移動端直播開發(四)播放與彈幕評論

寫在前面的話

上一篇已經介紹了關于RTMP推流相關的知識,那么推完流后視頻服務器就會對推流進行轉發,那么這一篇主要就是介紹下,關于移動端播放與彈幕評論相關的知識。

一.播放

關于播放其實一般情況我們都是使用第三方的播放庫,因為這些庫相對來說支持各種不同的協議比如RTMP,HLS或者其他的視頻協議,那我們這里就使用Bilibili開發并開源的IJKPlayer播放器,關于這方面更多的講解可以參考之前寫的文章IJKPlayer初識-編譯與使用

我們只需要把視頻轉發的地址設置進去就好了

如下

圖1 直播播放

由于錄制視頻再轉GIF不太方便,所以就單獨上一張圖了,明白是什么意思就好。

其實很多直播平臺也是用的IJKPlayer做的播放器,比如斗魚呀等等

對于現在的直播來說,彈幕評論也是直播平臺中很重要的一部分,所以接下來我們來探究下關于移動端關于彈幕評論的實現

二.彈幕評論

對于彈幕評論,其實客戶端我們可以想到的方法就是輪詢來不斷的獲取最新的評論數據,但是可想而知不停的網絡請求訪問,會對整個客戶端的性能帶來一定的問題,而且也會導致對于手機電量的消耗增大,所以我們得想出另外的方案來解決這個問題,自然就是參考現在比較成熟的PC網站是如何實現這部分的需求的,其實現在有部分的網站已經在使用WebSocket來實現實時彈幕的效果了,當然在我們移動端也是可以使用WebScoket的,所以我們就用WebScoket方案來實現彈幕評論

工欲善其事必先利其器,所以我們先了解下什么是WebScoket

WebScoket

WebSocket協議是一種建立在TCP連接基礎上的全雙工通信的協議,同http一樣通過TCP來傳輸數據,但是它和http最大的不同有兩點:1.WebSocket是一種雙向通信協議,在建立連接后,WebSocket服務器和Browser/UA都能主動的向對方發送或接收數據,就像Socket一樣,不同的是WebSocket是一種建立在Web基礎上的一種簡單模擬Socket的協議;2.WebSocket需要通過握手連接,類似于TCP它也需要客戶端和服務器端進行握手連接,連接成功后才能相互通信。

協議內容組成如下

圖2 WebScoket協議內容

WebSocket按上面圖中協議規則進行傳輸,上圖稱為一個數據幀。

  • FIN,共1位,標記消息是否是最后1幀,1個消息由1個或多個數據幀構成,若消息由1幀構成,起始幀就是結束幀。

  • RSV1,RSV2,RSV3,各1位,預留位,用于自定義擴展。如果沒有擴展,各位值為0;如果定義了擴展,即為非0值。如果接收的幀中此處為非0,但是擴展中卻沒有該值的定義,那么關閉連接。

  • OPCODE,共4位,幀類型,分為控制幀和非控制幀。如果接收到未知幀,接收端必須關閉連接。

    WebSocket的控制幀有3種,關閉幀、Ping幀、Pong幀,關閉幀很好理解,客戶端如果收到關閉幀直接關閉連接即可,當然客戶端也可以發送關閉幀給服務器端。而Ping幀和Pong幀則是WebSocket的心跳檢測,用于保證客戶端是在線的,一般來說,只有服務端給客戶端發送Ping幀,然后客戶端發送Pong幀進行回應,表示自己還在線,可以進行后續通信。

  • MASK,共1位,掩碼位,表示幀中的數據是否經過加密,客戶端發出的數據幀需要經過掩碼處理,這個值都是1。如果值是1,那么Masking-key域的數據就是掩碼秘鑰,用于解碼PayloadData,否則Masking-key長度為0

  • Payload len,7位或者7+16位或者7+64位,表示數據幀中數據大小,這里有好幾種情況。

    如果值為0-125,那么該值就是payload data的真實長度。
    如果值為126,那么該7位后面緊跟著的2個字節就是payload data的真實長度。
    如果值為127,那么該7位后面緊跟著的8個字節就是payload data的真實長度。
    長度遵循一個原則,就是用最少的字節表示長度,舉個例子,當payload data的真實長度是124時,在0-125之間,必須用7位表示;不允許將這7位表示成126或者127,然后后面用2個字節或者8個字節表示124,這樣做就違反了原則。

  • Masking-key ,0或者4個字節,當MASK位為1時,4個字節,否則0個字節。如果MASK值為1,則發出去的數據需要經過加密處理

  • Payload data,其大小是(x+y)個字節,x是Extension data,即擴展數據,y是Application data,即程序數據,擴展數據可能為0。 如果擴展數據不為0,必須提前進行協商,規定其長度,否則是不合法的數據幀。

以上是WebSocket數據傳輸的幀內容,大致了解即可。

對于WebSocket和前面說的RTMP一樣也是有握手協議的過程,接下來我們就看一下WebSocket握手協議

客戶端發送get請求協議升級

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat,superchat
Sec-WebSocket-Version: 13

該請求會在請求頭上帶上WebSocket的版本號,這里是13,以及客戶端隨機生成的Sec-WebSocket-Key,服務器端收到后根據這個key進行一些處理,返回一個Sec-WebSocket-Accept的值給客戶端。

服務端返回同意升級到WebSocket協議

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

收到響應后,響應頭中包含Sec-WebSocket-Accept值,該值表示服務器端同意握手,值的計算方式如下:

$(Sec-WebSocket-Accept)=BASE64(SHA1($(Sec-WebSocket-Key)+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))

客戶端得到該值后,對本地的Sec-WebSocket-Key進行同樣的編碼,然后對比,如果相同則可以進行后續處理。

關于WebSocket協議,一般來說,如果是通過https協議開始升級而來的,那么一般是wss://開頭,如果是http協議開始升級而來的,那么一般是ws://開頭

WebScoket實現彈幕效果

前面說了相關協議的東西,那么接下來就是實現具體的效果了,對于Android平臺,我們可以Java-WebSocket庫來實現WebSocket通信,當然除了這個還可以選擇其他的庫,我這里選擇Java-WebSocket來實現我們的功能了。

WebScoket服務器搭建

對于WebScoket服務器搭建,可以使用Java API javax.websocket包中的WebSocket相關類(注意Java API只實現了標準的RFC 6455(JSR256),如果你非要選擇其它早期草案則需要用Java-WebSocket來實現,在Java-WebSocket中連接協議“Draft_17”就是標準的RFC 6455(JSR256),另外要使用Java API javax.websocket包中的WebSocket相關類要求JDK7及以上,Tomcat 7.0.49及以上):

代碼如下

@ServerEndpoint(value = "/websocket/{user}")
public class ChatServerEndpoint {

    private static Set<Session> sessions = new HashSet<Session>();
    private Session session;

    @OnOpen
    public void open(Session session, @PathParam(value = "user") String user) {

        this.session = session;
        sessions.add(this.session);

        sendToAll(session.getRequestURI() + "進入房間");

        System.out.println(session.getRequestURI() + " 進入房間");
    }

    @OnClose
    public void close() {

        sessions.remove(session);

        sendToAll(session.getRequestURI() + " 離開房間");

        System.out.println(session.getRequestURI() + " 離開房間");
    }

    @OnMessage
    public void message(String message) {

        sendToAll("[" + session.getRequestURI() + "]" + message);

        System.out.println("[" + session.getRequestURI() + "]" + message);
    }

    private void sendToAll(String text) {

        for (Session client : sessions) {
            synchronized (client) {
                client.getAsyncRemote().sendText(text);
            }
        }
    }

}

這里服務器端的代碼主要是消息轉發功能,進入,離開,以及用戶發送信息都會轉發給連接的客戶端。

啟動tomcat就可以用Android客戶端來連接進行聊天、接收推送了。

Android端創建

首先添加Java-WebSocket的依賴如下

compile 'org.java-websocket:Java-WebSocket:1.3.0'

接下來就可以創建一個WebSockeClient

WebSocketClient client = new WebSocketClient(new URI(""), new Draft_17()) {
    @Override
    public void onOpen(ServerHandshake handshakedata) {
        Log.e("hxy", "已經連接到服務器【" + getURI() + "】");
    }

    @Override
    public void onMessage(String message) {
        Log.e("hxy", "獲取到服務器信息【" + message + "】");
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        Log.e("hxy", "斷開服務器連接【" + getURI() + ",狀態碼: " + code + ",斷開原因:" + reason + "】");
    }

    @Override
    public void onError(Exception ex) {
        Log.e("hxy", "連接發生了異常【異常原因:" + ex + "】");
    }
};  
client.connect();

這里我們只有設置前面搭建的服務器端的地址即可,然后就可以監聽到連接,斷開,異常等信息,同時也可以監聽到服務器發出的信息。

同樣我們也可以向服務器發送信息,代碼如下

client.send("message from client");

通過這樣就可以實現服務器與客戶端的雙向通信了

運行如下:

圖3 webSocket通訊

可以看到這里客戶端A連接服務器端,并發生消息,服務器端轉發連接信息與來自客戶端A的信息,客戶端A接收后將信息顯示出來,然后用另外的客戶端B進行連接發送信息,客戶端A同樣可以接收到后將信息顯示出來。

所以這里就實現了WebSocket相關的雙向通信了,

至于怎么彈幕,有了數據,彈幕只是表現形式咯,這個實現比較簡單就不做說明了,其實可以使用同樣Bilibili開發并開源的DanmakuFlameMaster

寫在后面的話

那么到這里就完成了移動直播相關的基本的問題了,我這邊更加著重于對于原理的講解,而不是把代碼貼出來簡單的概述而過,跟著這些原理一步一步研究出來顯然會對自己提升更大,至于視頻直播的濾鏡問題,可以參考我寫的濾鏡系列文章,當然我這里僅僅是實現了直播的整套流程,但是對于直播其實還有很多的問題,這里就不做過多的研究了,有興趣的朋友可以進行進一步的研究,peace~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 國家電網公司企業標準(Q/GDW)- 面向對象的用電信息數據交換協議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 11,052評論 6 13
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,660評論 25 708
  • 在老表朋友圈看到這樣一段話: 當孩子不麻煩你的時候 可能已經長大成人了 當父母不再麻煩你的時候 可能只愿來世再見了...
    阿木先森閱讀 251評論 2 2
  • 當你愛上一個人的時候,那就大膽的去愛,去把你心里的一切想法都化為愛的力量。但如果不愛了又或某種原因要舍棄這段感情,...
    迷路的貓耳朵閱讀 506評論 0 0
  • 前年的時候, 你的夢在紙上。 去年的時候, 你的夢在嘴上。 今年的時候, 你的夢在路上……
    小劇在成長閱讀 103評論 2 4