Room demo tutorial - Kurento Room 6.1.1 documentation

Room demo tutorial

本教程是使用Room API SDK開發(fā)多協(xié)作應(yīng)用程序的指南蚊惯,共有三個基本結(jié)構(gòu),也就是三個文件夾仔引,三個工程——kurento-room-server, kurento-room-client-jskurento-room-demo鄙皇。
代碼

一、服務(wù)器端代碼(server side code)

主類是KurentoRoomServerApp.java其爵,同樣為一個springboot應(yīng)用類车吹,我們將會在這個類里用Spring bean的方式來實例化構(gòu)成服務(wù)器端的各個組件。

1.帶通知的房間管理(room management)

這里用了 Room SDK 來管理房間和用戶醋闭,我們選擇的API——NotificationRoomManager類是一個通知風格的API窄驹,把它定義為一個Spring bean,以便以后依賴的注入证逻。
但首先我們要給NotificationRoomManager的構(gòu)造器提供一個 UserNotificationService 的實例作為參數(shù)乐埠,代碼中為notificationService,它是一個 JsonRpcNotificationService 類型的對象囚企,用于存儲JSON-RPC會話丈咐,以支持向客戶按發(fā)送響應(yīng)和通知。另一個參數(shù)為kmsManager龙宏。下圖代碼先定義了兩個參數(shù)棵逊,再用兩個參數(shù)送到構(gòu)造器來定義 NotificationRoomManager

  @Bean
  @ConditionalOnMissingBean
  public KurentoClientProvider kmsManager() {

    JsonArray kmsUris = getPropertyJson(KMSS_URIS_PROPERTY, KMSS_URIS_DEFAULT, JsonArray.class);
    List<String> kmsWsUris = JsonUtils.toStringList(kmsUris);

    if (kmsWsUris.isEmpty()) {
      throw new IllegalArgumentException(KMSS_URIS_PROPERTY
          + " should contain at least one kms url");
    }

    String firstKmsWsUri = kmsWsUris.get(0);

    if (firstKmsWsUri.equals("autodiscovery")) {
      log.info("Using autodiscovery rules to locate KMS on every pipeline");
      return new AutodiscoveryKurentoClientProvider();
    } else {
      log.info("Configuring Kurento Room Server to use first of the following kmss: " + kmsWsUris);
      return new FixedOneKmsManager(firstKmsWsUri);
    }
  }

  @Bean
  @ConditionalOnMissingBean
  public JsonRpcNotificationService notificationService() {
    return new JsonRpcNotificationService();
  }

  @Bean
  @ConditionalOnMissingBean
  public NotificationRoomManager roomManager() {
    return new NotificationRoomManager(notificationService(), kmsManager());
  }

2.通信(signaling)

我們的demo用Kureto 提供的 JSON-RPC 服務(wù)器庫來實現(xiàn)與客戶端的交互。
我們?yōu)檫M來的信息注冊了一個handler RoomJsonRpcHandler(整個RoomJsonRpcHandler.java就定義了這一個類)以便之后可以根據(jù)方法名字來處理請求银酗。這個類 RoomJsonRpcHandler實現(xiàn)了之前提到的Websocket API辆影。
在向這個API的registerJsonRpcHandlers方法中(一看到register應(yīng)該反應(yīng)過來這個方法在主類中,即KurentoRoomServerApp.java)添加這個handler(RoomJsonRpcHandler類實例化而來的roomHandler)時黍特,要指定路徑蛙讥。

  @Bean
  @ConditionalOnMissingBean
  public RoomJsonRpcHandler roomHandler() {
    return new RoomJsonRpcHandler(userControl(), notificationService());
  }

  @Override
  public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) {
    registry.addHandler(roomHandler().withPingWatchdog(true), "/room");
  }

回到RoomJsonRpcHandler.java類中,RoomJsonRpcHandler類的主方法handleRequest()會在每次收到客戶端的請求時被觸發(fā)灭衷,再出發(fā)的時候所有Websocket交流會在一個會話內(nèi)完成次慢,并且JSON-RPC庫會給每個會話提供一個引用。一次請求-應(yīng)答交換稱為一次事務(wù)翔曲。
應(yīng)用會存儲每個用戶對應(yīng)的繪畫和事務(wù)迫像,從而notificationService(主類中定義的)在從 Room SDK 中被調(diào)用的時候就可以向客戶端發(fā)相應(yīng)或服務(wù)器事件了。

  public final void handleRequest(Transaction transaction, Request<JsonObject> request)
      throws Exception {

    String sessionId = null;
    try {
      sessionId = transaction.getSession().getSessionId();
    } catch (Throwable e) {
      log.warn("Error getting session id from transaction {}", transaction, e);
      throw e;
    }

    updateThreadName(HANDLER_THREAD_NAME + "_" + sessionId);

    log.debug("Session #{} - request: {}", sessionId, request);

    notificationService.addTransaction(transaction, request);

    ParticipantRequest participantRequest = new ParticipantRequest(sessionId,
        Integer.toString(request.getId()));

    transaction.startAsync();

    switch (request.getMethod()) {
      case ProtocolElements.JOINROOM_METHOD :
        userControl.joinRoom(transaction, request, participantRequest);
        break;
      case ProtocolElements.PUBLISHVIDEO_METHOD :
        userControl.publishVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.UNPUBLISHVIDEO_METHOD :
        userControl.unpublishVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.RECEIVEVIDEO_METHOD :
        userControl.receiveVideoFrom(transaction, request, participantRequest);
        break;
      case ProtocolElements.UNSUBSCRIBEFROMVIDEO_METHOD :
        userControl.unsubscribeFromVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.ONICECANDIDATE_METHOD :
        userControl.onIceCandidate(transaction, request, participantRequest);
        break;
      case ProtocolElements.LEAVEROOM_METHOD :
        userControl.leaveRoom(transaction, request, participantRequest);
        break;
      case ProtocolElements.SENDMESSAGE_ROOM_METHOD :
        userControl.sendMessage(transaction, request, participantRequest);
        break;
      case ProtocolElements.CUSTOMREQUEST_METHOD :
        userControl.customRequest(transaction, request, participantRequest);
        break;
      default :
        log.error("Unrecognized request {}", request);
        break;
    }

    updateThreadName(HANDLER_THREAD_NAME);
  }

3.管理用戶請求(Manage user requests)

handler把對用戶請求的處理委托給了另一個組件瞳遍,JsonRpcUserControl 類的一個實例闻妓,代碼中是userControl,在主類中有定義

  @Bean
  @ConditionalOnMissingBean
  public JsonRpcUserControl userControl() {
    return new JsonRpcUserControl(roomManager());
  }

這個對象(userControl)會從用戶請求中提取出所需的參數(shù)傅蹂,并且調(diào)用部分roomManager的必要部分纷闺。用的時候還是在handler里面用算凿,只是具體實現(xiàn)封裝到了userControl里面:

    switch (request.getMethod()) {
      case ProtocolElements.JOINROOM_METHOD :
        userControl.joinRoom(transaction, request, participantRequest);
        break;
      case ProtocolElements.PUBLISHVIDEO_METHOD :
        userControl.publishVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.UNPUBLISHVIDEO_METHOD :
        userControl.unpublishVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.RECEIVEVIDEO_METHOD :
        userControl.receiveVideoFrom(transaction, request, participantRequest);
        break;
      case ProtocolElements.UNSUBSCRIBEFROMVIDEO_METHOD :
        userControl.unsubscribeFromVideo(transaction, request, participantRequest);
        break;
      case ProtocolElements.ONICECANDIDATE_METHOD :
        userControl.onIceCandidate(transaction, request, participantRequest);
        break;
      case ProtocolElements.LEAVEROOM_METHOD :
        userControl.leaveRoom(transaction, request, participantRequest);
        break;
      case ProtocolElements.SENDMESSAGE_ROOM_METHOD :
        userControl.sendMessage(transaction, request, participantRequest);
        break;
      case ProtocolElements.CUSTOMREQUEST_METHOD :
        userControl.customRequest(transaction, request, participantRequest);
        break;
      default :
        log.error("Unrecognized request {}", request);
        break;
    }

比如在joinRoom()請求中,它要干的事如下:

public void joinRoom(Transaction transaction, Request<JsonObject> request,
      ParticipantRequest participantRequest) throws IOException, InterruptedException,
      ExecutionException {
    String roomName = getStringParam(request, ProtocolElements.JOINROOM_ROOM_PARAM);
    String userName = getStringParam(request, ProtocolElements.JOINROOM_USER_PARAM);

    boolean dataChannels = false;
    if (request.getParams().has(ProtocolElements.JOINROOM_DATACHANNELS_PARAM)) {
      dataChannels = request.getParams().get(ProtocolElements.JOINROOM_DATACHANNELS_PARAM)
          .getAsBoolean();
    }

    ParticipantSession participantSession = getParticipantSession(transaction);
    participantSession.setParticipantName(userName);
    participantSession.setRoomName(roomName);
    participantSession.setDataChannels(dataChannels);

    roomManager.joinRoom(userName, roomName, dataChannels, true, participantRequest);
  }

4.用戶響應(yīng)與事件

現(xiàn)在來到了notificationService犁功,由上文知氓轰,他是一個JsonRpcNotificationService類型的對象,為RoomJsonRpcHandler類的私有成員浸卦。
這個類將所有用戶會話存儲為映射署鸡,從中可以獲取向一個房間請求做出響應(yīng)所需的事務(wù)對象。發(fā)送通知用了session對象的功能限嫌。
響應(yīng)一個特定請求時靴庆,對應(yīng)的事務(wù)對象被用完后會被移出內(nèi)存(getAndRemoveTransaction()),再來相應(yīng)就是新的事務(wù)了怒医。發(fā)出錯誤指示回應(yīng)也是一樣炉抒。

  @Override
  public void sendResponse(ParticipantRequest participantRequest, Object result) {
    Transaction t = getAndRemoveTransaction(participantRequest);
    if (t == null) {
      log.error("No transaction found for {}, unable to send result {}", participantRequest, result);
      return;
    }
    try {
      t.sendResponse(result);
    } catch (Exception e) {
      log.error("Exception responding to user ({})", participantRequest, e);
    }
  }

發(fā)服務(wù)器響應(yīng)或者服務(wù)器事件時,我們需要用到session對象稚叹。session對象需要一直保留焰薄,直到close session()方法被調(diào)用。close session()被調(diào)用可以有兩種來源扒袖,可以是因為用戶的離開被roomhandler調(diào)用塞茅,也可以是因為網(wǎng)絡(luò)錯誤被websocket調(diào)用。

二季率、demo對服務(wù)器端的定制

這個demo替換和修改了一些服務(wù)器端代碼的spring bean來進行了一些特殊訂制野瘦。全部在KurentoRoomDemoApp中完成,它先導入了原始server類然后做了修改:

import org.kurento.room.KurentoRoomServerApp;
...
public class KurentoRoomDemoApp {
   ...
   public static void main(String[] args) throws Exception {
      SpringApplication.run(KurentoRoomDemoApp.class, args);
   }
}

1.自定義KurentoClientProvider

我們自定義了FixedNKmsManager作為默認的provider接口飒泻,得以管理一系列由在配置文件中指定的URI創(chuàng)建的KurentoClient鞭光。

2.自定義用戶控制(user control)

自定義了DemoJsonRpcUserControl來實現(xiàn)對于customRequest這一附加的websocket請求類型的支持。
在這個類中我們重寫了customRequest()方法蠢络,以實現(xiàn)切換FaceOverlayFilter衰猛,它可以在發(fā)布者的頭上加一個帽子或者移除。他把濾鏡對象當作websocket session的一個屬性來存儲刹孔,方便了濾鏡的刪除:

  @Override
  public void customRequest(Transaction transaction, Request<JsonObject> request,
      ParticipantRequest participantRequest) {
    try {
      if (request.getParams() == null
          || request.getParams().get(filterType.getCustomRequestParam()) == null) {
        throw new RuntimeException(
            "Request element '" + filterType.getCustomRequestParam() + "' is missing");
      }
      switch (filterType) {
        case MARKER:
          handleMarkerRequest(transaction, request, participantRequest);
          break;
        case HAT:
        default:
          handleHatRequest(transaction, request, participantRequest);
      }
    } catch (Exception e) {
      log.error("Unable to handle custom request", e);
      try {
        transaction.sendError(e);
      } catch (IOException e1) {
        log.warn("Unable to send error response", e1);
      }
    }
  }

3.依賴

手動刪除了一些會造成沖突的依賴。

三娜睛、客戶端代碼

這部分描述一下kurento-room-demo中包含的AngularJS應(yīng)用髓霞。

1.庫

  • 在這個時候,我突然腦子一抽覺得畦戒,我應(yīng)該線跑一下demo再來看代碼啊方库。所以我去跑demo,沒想到障斋,很慘纵潦,又是一堆別人從來沒遇到過的錯徐鹤。改了,兩天半吧邀层,改了兩天半的bug返敬。你能想象官方demo還有bug嗎!A仍骸>⒃!而且秸谢,最主要的是凛澎,我也說了,這bug都是別人沒遇到過的估蹄,所以我去搜解決方案就很少塑煎,僅有的比較契合的也都是英文,剩下的那些臭蚁,中文的什么什么鬼的轧叽,完全看不下去。so刊棕,到這了炭晒,兩天半,我終于找到了一個看似可以采用的解決方案甥角,然后自定義得改了改网严,現(xiàn)在把電腦放著讓它自己慢慢解決maven依賴吧,也不知道是不是有效嗤无。等之后回來再看吧震束。雖然還不能確定是否有效,但起碼能做點什么了当犯,也不枉我搜了這么多網(wǎng)頁垢村,看了那么多英文文檔啊。哦嚎卫,對嘉栓,在這里表揚一下stack overflow。甚是得朕心






































最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拓诸,一起剝皮案震驚了整個濱河市侵佃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奠支,老刑警劉巖馋辈,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異倍谜,居然都是意外死亡迈螟,警方通過查閱死者的電腦和手機叉抡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來答毫,“玉大人褥民,你說我怎么就攤上這事±映#” “怎么了轴捎?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蚕脏。 經(jīng)常有香客問我侦副,道長,這世上最難降的妖魔是什么驼鞭? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任秦驯,我火速辦了婚禮,結(jié)果婚禮上挣棕,老公的妹妹穿的比我還像新娘译隘。我一直安慰自己,他們只是感情好洛心,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布固耘。 她就那樣靜靜地躺著,像睡著了一般词身。 火紅的嫁衣襯著肌膚如雪厅目。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天法严,我揣著相機與錄音损敷,去河邊找鬼。 笑死深啤,一個胖子當著我的面吹牛拗馒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溯街,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诱桂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了苫幢?” 一聲冷哼從身側(cè)響起访诱,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎韩肝,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體九榔,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡哀峻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年涡相,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剩蟀。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡催蝗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出育特,到底是詐尸還是另有隱情丙号,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布缰冤,位于F島的核電站犬缨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏棉浸。R本人自食惡果不足惜怀薛,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迷郑。 院中可真熱鬧枝恋,春花似錦、人聲如沸嗡害。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霸妹。三九已至十电,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抑堡,已是汗流浹背摆出。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留首妖,地道東北人偎漫。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像有缆,于是被迫代替她去往敵國和親象踊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354