Kurento實戰之四:應用開發指南

語言: CN / TW / HK

歡迎訪問我的GitHub

https://github.com/zq2599/blog_demos

內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;

本篇概覽

  • 本文是《Kurento實戰》的第四篇,前面的文章中,咱們先部署KMS再啟動官方demo,還把Kurento的重要概念都分類學習過,接下來要開始應用開發了;
  • 本文的主要內容是分析官方的<font color="blue">kurento-hello-world</font>專案,瞭解Kurento應用開發的基本流程和知識點,本文使用的程式碼是官方釋出的6.15.0版本,地址:https://github.com/Kurento/kurento-tutorial-java/archive/6.15.0.zip
  • 閱讀程式碼時,如果能從整體上將劃分清楚功能模組,再有針對性的逐個攻破細節,將會更高效的學習和理解原始碼,接下來咱們就按照Kurento官方的標準套路去拆分並逐個攻破;

如何劃分功能模組

按照不同的職責劃分,整個程式碼被拆分為三部分:

  1. WebSocket相關:WebSocket相關的通用處理,例如連線建立、關閉、異常的回撥,業務邏輯的分發等;
  2. WebRTC信令相關:ICE、SDP相關的處理;
  3. 業務邏輯:如果說1和2代表的是WebRTC的通用處理,那麼剩下的就是如何使用Kurento來實現業務需求了,這部分的主要內容是業務應用使用Kurento官方client和KMS互動,控制KMS為端側提供服務,互動方式如下圖: 在這裡插入圖片描述
  • 按照上述方式將程式碼做好拆分,劃定邊界,不論是閱讀官方demo還是自己開發應用,都能條理清晰的應對,接下來一起學習官方的hello-world原始碼,看看一個完整的Kurento應用是如何開發出來的

WebSocket相關

最簡單的邏輯應該是通用的WebSocket處理了,咱們先看這部分,複雜的稍後再說,Handler類中和WebSockert相關的邏輯如下:

  1. 繼承自TextWebSocketHandler(只處理text型別的資料,對於二進位制資料直接關閉會話);
  2. 重寫afterConnectionEstablished:WebSocket連線建立的回撥,只打了一行日誌;
  3. 重寫handleTransportError:WebSocket發生異常時候的回撥,僅關閉WebSocketSession;
  4. 重寫afterConnectionClosed:不論WebSocket是正常關閉還是發生異常,此方法都會執行,邏輯也很簡單,就是呼叫stop方法,這個方法是用來釋放KMS資源的,有好幾處都會呼叫,我們留到稍後和其他處理KMS的地方一起講;
  5. WebSockert部分最重要的程式碼是handleTextMessage方法,裡面是收到前端資料時的處理邏輯:先把資料轉為JsonObject物件,此物件的messageId欄位有四種值,每一種id及其對應的處理方法如下表格所示:
messageId 處理方法 說明
PROCESS_SDP_OFFER handleProcessSdpOffer 收到前端SDPOffer資料後的處理邏輯
ADD_ICE_CANDIDATE handleAddIceCandidate 收到前端ICE資料後的處理邏輯
STOP handleStop HashMap刪除使用者資料,再遠端呼叫MediaPipeline.release
ERROR handleError HashMap刪除使用者資料,再遠端呼叫MediaPipeline.release
  1. 並不是所有的應用都需要重寫上訴全部程式碼,還是以實際需求出發決定是否要重寫,以<font color="blue">kurento-one2one-call</font>專案為例,只重寫了handleTextMessage和afterConnectionClosed,其他的使用父類的即可,如下圖:

在這裡插入圖片描述 7. 還有一個傳送訊息到瀏覽器側的sendMessage方法,以及傳送錯誤資訊的sendError方法;

信令相關

  • <font color="blue">kurento-hello-world</font>應用的功能是和KMS實現實時音影片通訊,因此WebRTC標準的信令處理是必不可少的,可惜Kurento官方並沒有對信令處理做太多封裝(也可能是信令和不同的業務處理邏輯都不一樣,導致不好抽象),結果就是一堆信令處理的程式碼散落在業務程式碼中;
  • 就算業務和信令的處理程式碼同時出現在Handler類中,只要熟悉WebRTC的信令處理流程,也很容易讀懂程式碼,下圖結合了WebRTC標準的信令處理流程,對前端和服務端的程式碼串聯在一起就行分析,左邊是瀏覽器上執行的js程式碼,右邊是服務端,這些程式碼都用紅色箭頭標識了處於WebRTC信令處理流程的具體位置,至此,整個流程都清晰的展現出來:

在這裡插入圖片描述

  • 如果您在電腦或手機上看上圖覺得模糊,請下載原始檔案,用<font color="blue">draw.io</font>開啟,檔案所在目錄是:https://github.com/zq2599/blog_demos/tree/master/files ,檔名為<font color="red">helloworld-flow.drawio</font>
  • 上圖列出了信令相關的所有程式碼,等到看完這些,剩下的就是業務程式碼了,也就是圖中紫色部分的<font color="blue">handleProcessSdpOffer</font>方法;

業務相關

  • <font color="blue">kurento-hello-world</font>應用是把本地攝像頭和麥克風資料傳到KMS,再從KMS取得這些資料在頁面展示,先看看官方是如何描述KMS pipeline的:

在這裡插入圖片描述

  • 從上圖可見pipeline邏輯非常簡單:只有一個WebRtcEndpoint,把自己的Src和Sink接上就完成了,咱們來看看對應的程式碼,在方法handleProcessSdpOffer中:
    // 建立pipeline
    final MediaPipeline pipeline = kurento.createMediaPipeline();
    user.setMediaPipeline(pipeline);

    // 建立webRtcEndpoint
    final WebRtcEndpoint webRtcEp =
        new WebRtcEndpoint.Builder(pipeline).build();
    user.setWebRtcEndpoint(webRtcEp);

    // 自己的sink連線上自己的src
    webRtcEp.connect(webRtcEp);

    // ---- Endpoint configuration

    String sdpOffer = jsonMessage.get("sdpOffer").getAsString();
    
    // 註冊各類監聽,例如媒體資源狀態變化、ICE變化等
    // 通過websocket回覆SDP Offer
    initWebRtcEndpoint(session, webRtcEp, sdpOffer);

    log.info("[Handler::handleStart] New WebRtcEndpoint: {}",
        webRtcEp.getName());
    
    // ---- Endpoint startup
    // 取得ICE資訊
    startWebRtcEndpoint(webRtcEp);
  • 再來看看停止WebRtc的stop方法,其實就是向KMS傳送了release指令:
  private void stop(final WebSocketSession session) {
    // Remove the user session and release all resources
    final UserSession user = users.remove(session.getId());
    if (user != null) {
      MediaPipeline mediaPipeline = user.getMediaPipeline();
      if (mediaPipeline != null) {
        log.info("[Handler::stop] Release the Media Pipeline");
        mediaPipeline.release();
      }
    }
  }

小結

以上就是整個<font color="blue">kurento-hello-world</font>的原始碼分析,整個工程的程式碼在拆分後再分析時,變得異常清晰和簡單:

  1. WebSocket和常規的java開發無異,向標準靠攏即可;
  2. WebRTC相關程式碼佔了較大比重,但是嚴格遵循了標準的信令流程,只要熟悉WebRTC就很容易閱讀和理解;
  3. 業務邏輯其實是和業務需求相關聯的,這裡需要熟悉KMS提供的能力,才能充分發揮KMS的例項,而pipeline編排和各個element的使用,也會是咱們後面文章的重點,用好這些element,打磨出更強大靈活的服務;

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 資料庫+中介軟體系列
  6. DevOps系列

歡迎關注公眾號:程式設計師欣宸

微信搜尋「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界... https://github.com/zq2599/blog_demos