天天看點

無線端的彈幕實作方案

無線端的彈幕實作方案

前段時間做了遊戲的相關業務,其中彈幕相關的内容自成一塊。彈幕已經不隻是最初的視訊彈幕了,戰火已經燒到了評論區,燒到了手機淘寶的首頁搜尋結果。作為一種近幾年迅速燃起的内容呈現形式,有必要适時引入,對于休閑化、娛樂化的業務更是如此。那麼,要做出一個較為完整的彈幕效果來,需要哪幾個部分呢?尤其是,在集團内部,怎麼快速地搭建起一個可用的彈幕架構來?本文分3塊來闡述。

<a href="http://taobaofed.org/blog/2016/05/13/barrage-in-mobile/#client_rendering_module">彈幕渲染層</a>

<a href="http://taobaofed.org/blog/2016/05/13/barrage-in-mobile/#data_pipeline_module">彈幕資料通道</a>

<a href="http://taobaofed.org/blog/2016/05/13/barrage-in-mobile/#server_business_module">彈幕服務邏輯</a>

目前彈幕的呈現載體主要是web、無線用戶端。因為我們的工作主要針對無線端,是以本文主要以無線端為例——包括ios,android兩類系統。

彈幕無非是動畫,是分布在時間軸上圖像的連續運動。自然可以用native的動畫來實作。不過彈幕動畫有一個重要的特征,即保持動畫元素(sprites)盡可能少地碰撞,以使彈幕承載的資訊能夠清晰地傳達,執行碰撞檢測是必須的。但彈幕裡的碰撞檢測相對簡單,因為彈幕的運動軌迹相對簡單并且容易預測,是以隻需要在一條彈幕将要顯示之前,根據已經顯示的彈幕(位置、速度、活躍的時間等)來确定他的運動軌迹。以盡最大可能地在其生命周期内不與已有彈幕沖突。

無線端的彈幕實作方案

彈幕不是超然而獨立的,往往相伴業務場景而生,目前可見最多的場景是視訊,直播或者錄播皆有。到此時則涉及到一個時間同步的問題。比如,一位使用者在看一段時間第314s的時候突然有感而發,發出了一條彈幕,自然希望其他觀衆能夠在看到視訊此刻看到他的彈幕。是以一條彈幕上屏的時間是需要明确的,想想那些年文不對題的字幕君吧。那麼,如何實作呢?一般,可以為一條彈幕提供一個時間點delay,當到了這個時刻,由控制器把這條彈幕播放出去。但僅僅這些是不夠的,因為視訊還存在暫停,存在快進快退,是以你必須也為彈幕元件提供類似的接口,以期能和視訊内容同步。其他的應用場景也是類似的。比如下面的樣子(彈幕在向左運動):

彈幕的運動樣式主要有兩種,一種是橫向的過場彈幕,一種是縱向的浮動彈幕。彈幕的内容形式不外乎一段文字或者圖檔,其中以文字為主。對于文字,則有文字的顔色、背景、字型、邊框等屬性,這一切必須是靈活可配的。當然實際應用中一個app需要的是風格統一的、優雅美觀的彈幕動畫。是以彈幕的方向不要太混亂,不要有太多不一樣的主題配置。你可以定義幾類色調協調但樣式不同的彈幕,然後由業務代碼決定使用哪一種風格的彈幕。

性能直接關系到使用者體驗。在絕大多數場景中,錦上添花的彈幕往往伴随着具體的業務邏輯,業務邏輯會占用cpu——甚至很高的cpu,比如視訊解碼———是以彈幕動畫應該盡可能地使用gpu渲染。為應對線上可能的大規模彈幕的情況,本地最好也能測試到大量彈幕的情況。可以使用一個定時器,模拟用戶端頻繁接受渲染彈幕的情況,看看實際中彈幕的性能究竟如何。

彈幕稀稀疏疏地鋪滿半屏視窗,朦胧中猶抱琵琶半遮面的感覺,自然是最好的。但萬一遇到彈幕決堤,内容瘋狂湧來,那當如何應對?渲染内容層層堆疊,既看不清,又降低了系統應用性能,為此可以在業務或者元件中選擇限流。

若不考慮彈幕在使用者間共享,隻需下圖左側的子產品即可;若需引入彈幕共享、存儲功能,則如下圖右側所示。

無線端的彈幕實作方案

但實際情況往往比這複雜。彈幕很多時候是實時的,最好使用長連接配接來傳輸資料。業務導向的項目,很少從零開始開發專門的彈幕服務通道,而是盡可能地應用已有的服務元件。淘寶在長連通道上有多個選擇,但其功能又是不盡相同的。這種不同也會帶來彈幕實作方案的不同。比如通道a支援訂閱功能,消息會根據訂閱關系分發;而通道b是單純的通道,訂閱關系由業務方維護,凡是發送到用戶端的消息都會接收,是以流量需要業務服務端來控制。

僅僅使用長連接配接通道是不夠的,還需引入業務伺服器,其原因如下:

如果長連通道不支援用戶端發送消息,那麼彈幕的發送要走其它的接口

因業務原因,需要統一多個長連接配接通道,以便更好地做 多端同步,故引入中間伺服器做協調

一些業務相關的需求,不适合在長連接配接伺服器上做,比如内容過濾、彈幕存儲、服務端限流等

整體的資料流如下圖所示:

無線端的彈幕實作方案

通過長連接配接傳輸的彈幕消息會有一些附加資料需要考慮,比如彈幕的樣式、出現的時間,随着業務的擴充,可能需要更多的輔助字段。是以彈幕消息必須能夠向後相容,一般可設定為message,version兩個字段,message為純粹的json字元串,version表示消息的版本号。先解析version,根據判斷得到的version選擇響應的解析樣式。太多的附加資訊會降低資料的使用率,此是需要權衡的地方。當然,如果針對的是線上視訊業務,彈幕的流量相比于視訊流而言,就顯得不那麼重要了。

主要有兩種:

使用者發送了彈幕消息後,通過網絡發送消息的同時直接将彈幕資料上屏,以提升使用者所見即所得的體驗;當收到相同的彈幕消息後,将消息抛棄。

使用者發送了彈幕消息後,通過正常的網絡接收消息然後渲染呈現,這樣會因延時損失一定的使用者體驗,但邏輯簡單,并且可以控制所有彈幕資料。

主題代表彈幕消息圍繞的中心。在不同的業務場景中,主題的呈現方式可能是不同的。在視訊直播業務中,主題代表了一個個直播房間,彈幕圍繞着視訊展開;在新聞咨詢業務中,主題代表了一則則新聞,彈幕圍繞着新聞展開。用戶端與主題存在多對一的關系,如下圖所示:

無線端的彈幕實作方案

使用者u1、u2訂閱了主題t1,使用者u3、u4訂閱了主題t2。由于處于不同的語境中,u1、u2發送的彈幕u3、u4應該是不能接收到的,反之亦然。很自然服務端需要維護一個使用者到主題的映射表簡單的實作是,用戶端監測到使用者進入特定主題之後,發送一條網絡請求登記這樣一條訂閱;使用者離開特定主題時發送網絡請求登出登記。但由于實際用戶端運作場景複雜,離開特定主題不一定來得及發送網絡請求。補充方案是,由用戶端每隔特定時間心跳一次,用以告知服務端維護映射表。一旦服務端一段時間沒有監聽到心跳資訊,就取消映射表中的一條訂閱。這裡需要注意的是,服務端需要防止心跳的僞造,否則可能映射表可能會因攻擊而混亂掉。一旦映射表正确建立,使用者發送的彈幕消息就可以準确傳達到相同主題的使用者用戶端了。

對于直播等即時性業務,彈幕資料一般沒有重播的必要;但是對于錄播,則需要持久化彈幕,如是方能在其他使用者看視訊的時候看到其他人發出過的彈幕消息。持久化這類彈幕資料,必須在存儲彈幕的時候帶上彈幕對應的時間點。在使用者進入了某一主題之後,批量傳回給用戶端對應的彈幕資料,由用戶端将彈幕資料對應到視訊業務響應的時間點上;如果此主題對應的彈幕資料很多,服務端可能實作做一定的篩選;對于錄播同時新發送的彈幕,則由服務端記錄并添加到對應的彈幕資料清單中。

轉載自:http://taobaofed.org/blog/2016/05/13/barrage-in-mobile/

作者:拂銘