<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 1.概要? ? ? 在Janus的眾多插件中,有一個房間插件videoRoom,由于它實現視頻會議sfu功能,通過改造能適合我們很多業務場景。而且在Janus眾多的業務插件中`VideoRoom`應該也是最復雜的一個,如果你們撐握了它,就輕而易舉了解其他插件。 ? ? ?janus 提供了很多管理房間的api接口,包括房間的創建,修改,刪除,轉推等操作。學習這些api有助于了解janus房間管理,同時也可以學習房間管理需要提供哪些標準的api接口。 ## 1.VideoRoom插件 `? ?VideoRoom`是Janus的一個插件,實現了一個SFU(Selective Forwarding Unit)型的音視頻會議。如果你從數據轉發的角度看,也可以把它認為是一個音視頻`路由器`。 `? ?VideoRoom`實現的音視頻會議是基于`發布/訂閱`模式。每個`參與方`都可以發布自己的實時音視頻流,因此它可以實現幾種不同的場景,比如泛娛樂化直播或多人的實時互動產品(如音視頻會議、在線教育小班課等)。m/n? ? ? ? ? 76 ? ? ? ? ?主handle是發布handle。考慮到此插件允許一個`參與方`可以打開多個WebRTC?`PeerConnection`(如每個`參與方`可以有1個用于推流的`PeerConnection`和N個拉流的`PeerConnection`),所以每個`參與方`需要為訂閱不同的流`attach`到`VideoRoom`插件幾次(每`attach`一次就會生成一個`Handle`,每個`Handle`就是一個上下文)。因此,對于每個`參與方`至少要有一個`Handle`用于管理與插件的關系(如加入一個房間,離開一個房間,靜音/取消靜音,發布,接收事件)。 ? ? ? ? 每當`參與方`需要訂閱另一個參與方發布的音視頻流時,它需要創建一個新的`Handle`。新創建的`Handle`在邏輯上屬于**“slave”**`Handle`,它不能像**“master”**`Handle`一樣可以做取消房間靜音這樣的操作。因此,**從**`Handle`唯一目的是提供一個上下文,在該上下文中創建一個`recvonly`類型的`PeerConnection`來訂閱發布者的音視頻流。 通過上面的描述我們可以知道,主Handle用于管理,而從Handle用于訂閱音視頻流。 > 注意,現在`WebRTC`已經實現了SSRC復用(Unified Plan),這意味著你可以使用相同的`Janus Handle`?和`PeerConnection`同時接收多路音視頻流。 ## 2.房間參數? ? ? ? ?VideoRoom插件功能非常強大,也很靈活,它有很多的配置項,你可以通過`conf/janus.plugin.videoroom.jcfg`來修改它們。當然Janus也支持動態API修改配置,如通過API創建房間等。 ### 2.1 創建房間 要增加更多房間或修改現有房間信息,你可以向Janus發送下面格式的請求: ~~~ room- <唯一的房間ID>:{ description = 房間的描述信息 is_private = true | false(是否是私有房間? 如果創建的是私有房間,則無法通過list指令進行查看) secret = <可選項,操作房間所需的密碼,如果設置了,則像做銷毀房間這樣的操作時你要帶上它才行> PIN = <可選項,加入會議房間的密碼> require_pvtid = true | false(是否訂閱音視頻流時,需要提供一個與發布者相關的有效private_id, 默認為false) publishers = <房間內發布者的最大數>(例如,一個視頻會議可以有6個發布者,而廣播只有一個,默認= 3) bitrate = <房間里發布者發送數據的最大比特率>(例如128000) fir_freq = <向發布者發送FIR指令的頻率>(0 =禁用) audiocodec = opus | g722 | pcmu | pcma | isac32 | isac16(發布者可以使用的音頻編解碼器列表,默認為opus。編碼器按優先順序以逗號分隔) videocodec = vp8 | vp9 | h264 | av1 | h265(發布者可以使用的視頻編解碼器列表,默認為vp8。可以按優先級順序用逗號分隔,例如,vp9,vp8,h264) vp9_profile = VP9首選的profile("2" 表示 "profile-id = 2" ) h264_profile = H.264首選的profile("42e01f" 表示 "profile-level-id = 42e01f" ) opus_fec = true | false(是否使用帶內FEC;僅適用于Opus,默認為false) video_svc = true | false(是否啟用SVC支持;僅適用于VP9,默認為false) audiolevel_ext = true | false(對于發布者是否使用RTP擴展ssrc-audio-level?默認為 true) audiolevel_event = true | false(是否將audiolevel事件發送給其他用戶) audio_active_packets = 100(音頻保活包個數,默認值= 100,2秒) audio_level_average = 25(音頻音量級別的平均值,127 =靜音,0 ='太大聲',默認= 25) videoorient_ext = true | false(發布者是否使用RTP擴展video-orientation? 默認= true) playoutdelay_ext = true | false(發布者是否使用RTP擴展playout-delay? 默認= true) transport_wide_cc_ext = true | false(發布者是否使用RTP擴展 transport-wide-cc? 默認= true) record = true | false(該房間是否啟錄制?默認= false) rec_dir = <啟用錄制后,錄制文件存放的目錄> lock_record = true | false(是否鎖定錄制狀態? 默認= false) notify_joining = true | false(可選,當有新的參與方加入房音后,是否通知房間里的所有參與者? Videoroom插件默認僅通知發布者,啟用此功能可能會導致額外的通知傳輸。 該功能與require_pvtid一起啟用時,對管理員管理僅收聽的參與者特別有用。默認= false) require_e2ee = true | false(是否啟用端到端加密? 默認= false)} ~~~ ## 3\. Video Room API接口 `? VideoRoom`?插件支持很多API操作。這些API中,一些是同步請求,一些則是異步請求。但無論是同步還是異步請求,當遇到無效的JSON格式或無效的請求時,都使用同步進行錯誤響應。 ? ? ?接下來,我們首先看看都有那些同步請求API。`create`,`destroy`,`edit`,`exists`,`list`,`allowed`,`kick`和`listparticipants`是同步請求API。`create`允許您動態創建一個新的音視頻房間;`edit`允許您動態編輯房間的屬性(例如 修改PIN碼);`destroy`首先釋放視頻資源,然后踢除房間里的所有用戶,最后銷毀音視頻房間;`exists`檢查指定的音視頻房間是否存在;`list`列出所有有效的音視頻房間;?`listparticipants`列出指定房間中所有激活的參與者及其詳細信息。 ? ? ?異步請求API有:`join`,`joinandconfigure`,`configure`,`publish`,`unpublish`,`start`,`pause`,`switch`和`leave`。`join`允許你加入指定的音視頻房間;`configure`可用于修改某些屬性(例如,比特率范圍);`joinandconfigure`的含義是將前兩個請求合并為一個請求(該請求僅適用于發布者);`publish`發布媒體流給所有訂閱者;?`unpublish`正好與`publish`相反;`start`允許你開始接收訂閱的媒體流;`pause`暫停發送媒體流;`switch`更改指定`PeerConnection`的媒體源(例如,你正在看A,現在改為看B),但無需為此創建新的Handle;`leave`離開視頻房間。 下面咱們對上面提到的API做一下詳細分析,首先看一下`create`API,它用于創建新的音視頻房間,其格式如下: ~~~ { "request":"create", "room":<可選,房間ID。如果不填,則由插件隨機生成>, "permanent":<true | false,是否創建永久房間,默認= false>, "description":"<可選,房間的名稱>", "secret":"<可選,編輯/銷毀房間時用的密碼>", "pin":"<可選,加入房間的密碼>", "is_private":<true | false,是否是私有房間?如果是私有房間則不會出現在房間列表中>, "allowed":[可選,用戶加入房間的token數組], ...} ~~~ 上面的說明已經非常清楚了,這里我就不做簡贅述了。 如果`create`成功,則會返回`created`響應,格式如下: ~~~ { "videoroom":“created", "room":<房間ID>, "permanent":<是否是創建的永久房間?是則為true,否則為false>} ~~~ > 注意,如果你請求創建一個永久房間,但`permanet`返回的是false,很可能是因為權限的問題導致的。 如果`create`請求失敗,則返回錯誤信息,格式如下: ~~~ { "videoroom":"event", "error_code":<錯誤碼,每個錯誤碼的含義需要看插件實現代碼中的宏定義>, "error":"<錯誤描述字符串>"} ~~~ > 這里需要注意的是,所有請求的錯誤響應格式都與上面一樣。 默認情況下,所有用戶都可以創建房間,但你可以通過在`VideoRoom`插件的配置文件中增加`admin_key`項來限制此功能。此時,只有帶了正確的`admin_key`值的`create`請求才能成功創建房間。你也可以選擇將此功能擴展到RTP轉發,只轉發受信任的客戶端的RTP包。 房間創建好后,您可以用`edit`API編輯其中的部分(但不是全部)屬性。`edit`允許你修改房間描述,密碼,PIN碼以及是否為私有。但你將無法修改他的靜態屬性,例如房間ID,采樣率,與擴展相關的內容等。如果你有興趣更改ACL,還需要查看`allowed`是否允許。 一個`edit`請求格式如下: ~~~ { "request":"edit", "room":<房間ID>, "secret":"<房間密碼>", "new_description":"<房間的新名稱,可選>", "new_secret":"<房間的新密碼,可選>", "new_pin":"<新PIN碼,可選>", "new_is_private":<true | false,房間是否為私有房間?>, "new_require_pvtid":<true | false,房間是否要求訂閱者提供private_id>, "new_bitrate":<比特率>, "new_fir_freq":<發送PLI請求關鍵幀的時間間隔>, "new_publishers":<房間里發布者的最大數>, "new_lock_record":<true | false,如否可以改變錄制狀態>, "permanent":<true | false,該房間是否是永久房間?默認= false>} ~~~ `edit`請求成功,剛收到`edited`響應: ~~~ { "videoroom":"edited", "room":<房間ID>} ~~~ 接下來我們來看看`destroy`API,無論你是通過動態創建的還是靜態創建的房間,均可使用`destroy`銷毀它,其格式如下: ~~~ { "request":"destroy", "room":<房間ID>, "secret":"<房間密碼>", "permanent":<true | false,是否是永久房間,默認= false>} ~~~ 成功銷毀房間后將收到`destroyed`響應,其格式如下: ~~~ { "videoroom":"destroyed", "room":<房間ID>} ~~~ 銷毀房間后,在房間內的所有參與者都會收到`destroyed`事件,如下所示: ~~~ { "videoroom":"destroyed", "room":<房間ID>} ~~~ Janus中還提供了`exists`API,來檢查房間是否存在,該請求的格式如下: ~~~ { "request":"exists", "room":<房間ID>} ~~~ 請求成功將收到success響應: ~~~ { "videoroom":“success", "room":<房間ID>, “exists":<true | false 房間是否存在>} ~~~ `allowed`API可以打開/關閉對令牌的檢測,它還可以增加/刪除允許的用戶,其請求格式如下: ~~~ { "request":"allowed", "secret":"<房間密碼,如果已配置,則是必需的>", "action":"enable | disable | add | remove", "room":<房間ID>, "allowed":[ //字符串數組 ]} ~~~ 成功請求將返回success響應: ~~~ { "videoroom":“success", "room":<房間ID>, “allowed":[ //更新后完整的令牌列表 ]} ~~~ 如果你是房間管理員(即你創建了該房間并可以加密訪問),則你可以使用`kick`API踢除房間內的用戶。 > 注意,這只會將用戶踢出房間,但并不能阻止他們重新加入。要禁止他們加入,你需要先從授權用戶列表中刪除他們(請參閱allowed請求),然后再將其踢掉。`kick`請求的格式如下: ~~~ { "request":"kick", "secret":"<房間密碼>", "room":<房間ID>, "id":<被踢用戶ID>} ~~~ 請求成功將收到success響應: ~~~ { "videoroom":"success",} ~~~ 你還可以通過`list`API獲取可用房間的列表(不包括配置或創建為私有的房間),其格式如下: ~~~ { "request":“list"} ~~~ 請求成功將返回success響應,響應中會帶有有效的房間列表: ~~~ { "videoroom":“成功", "rooms":[//房間對象數組 {// 第一個房間 "room":<房間ID>, "description":"<房間名稱>", "pin_required":<true | false,是否需要輸入PIN嗎才能加入此房間>, "max_publishers":<房間內發布者最大數量,> "bitrate":<發布者使用的(通過REMB)比特率上限>, "bitrate_cap":<true | false,上述上限是否可以動態更改?>, "fir_freq":<發送PLI/FIR請求關鍵幀的時間間隔>, "audiocodec":"<音頻編解碼器列表,每個編碼器以逗號分隔>", "videocodec":"<視頻編解碼器列表,每個編碼器以逗號分隔>", "record":<true | false,是否打開了錄制功能>, "record_dir":"<如果開啟了錄掉,.mjr文件保存的路徑>", "lock_record":<true | false,是否只能通過密碼才能更改房間記錄狀態>, "num_participants":<房間內參與人的個數> }, //其他房間 ]} ~~~ 當然,你要獲取特定房間中的參與者列表,可以使用`listparticipants`請求,其格式如下: ~~~ { "request":"listparticipants", "room":<房間ID>} ~~~ 請求成功將返回一個`participants`響應: ~~~ { "videoroom":"participants", "room":<房間ID>, “participants":[//參與者對象的數組 {//參與者#1 "id":<用戶ID>, "display":"<用戶名;可選>", "publisher":"<true | false,用戶是否是房間的發布者>", "talking":<true | false,用戶是否可以說話(僅當使用音頻級別時)> }, //其他參與者 ]} ~~~ 上面是Janus中的同步API。異步API都是與`參與者`有關,即`參與者`如何發布,訂閱或管理他們正在發送或接收的媒體流。 ## 4\. VideoRoom 發布者 在VideoRoom中,`發布者`是指那些能夠在房間中發布`媒體流`的參與者。 當你以`發布者`的身份加入到房間里時,您應該發送`join`請求,并且將ptype設置為`publisher`。請求的具體格式如下: ~~~ { "request":"join", "ptype":"pbulisher", "room":<房間ID>, "id":<發布者ID;可選,如果缺少,將由插件選擇>, "display":"<發布者名稱;可選>", "token":"<邀請令牌,如果房間有ACL時需要該字段;可選>"} ~~~ `joid`請求成功將收到`joined`事件,其中包含當前激活的`發布者`列表,以及任選的`參加者`列表。`joined`事件格式如下: ~~~ { "videoroom":"joined", "room":<房間ID>, "description":<房間名,如果有的話>, "id":<用戶ID>, "private_id":<與參與者相關聯的不同唯一ID;打算是私人的>, “publishers":[ { "id":<活動發布者#1的唯一ID>, "display":"<發布者#1的名稱,如果有的話>", "audio_codec":"<發布者#1使用的音頻編解碼器,如果有的話>", "video_codec":"<發布者#1使用的視頻編解碼器,如果有的話>", "simulcast":"<如果發布者使用simulcast,則為true(僅VP8和H.264)>", "talking":<true | false,發布者開啟語音聊天(僅在使用音頻級別的情況下)>, }, //其他活躍的發布者 ], "attendees":[//僅當房間的notify_joining設置為TRUE時存在 { "id":<與會者#1的唯一ID>, "display":"<與會者#1的名稱,如果有的話>" }, //其他參加者 ]} ~~~ > 注意,如果房間中當前沒有人,則`發布者`列表為空。上面格式中的`private_id`屬性只有在用戶訂閱時才起作用。 對于房間里的訂閱者來說,會收到`event`通知。 ~~~ { "videoroom":"event", "room":<房間ID>, “joining":{ "id":<參與者ID>, "display":"<參與者名稱>" }} ~~~ 如果你想成為`發布者`,則發送`publish`請求。該請求必須跟著一個`JSEP SDP Offer`,用于協商新的`PeerConnection`。插件會將其與房間配置進行匹配(例如,確保房間中使用協商的編解碼器),并使用`JSEP SDP answer`進行答復從而完成`PeerConnection`的設置。建立`PeerConnection`后,發布者立即處于活動狀態,其他參與者就可以訂閱它發布的流啦。 `publish`請求格式如下: ~~~ { "request":"publish", "audio":<true | false,是否應該轉發音頻;默認為true>, "video":<true | false,是否應該轉發視頻;默認為true>, "data":<true | false,是否應該轉發數據;默認為true>, "audiocodec":"<在協商協議中首選的音頻編解碼器;可選>", "videocodec":"<在協商協議中首選的視頻編解碼器;可選>", "bitrate":<通過REMB返回的比特率上限;可選,如果存在則覆蓋全局房間值>, "record":<true | false,是否應該記錄此發布者;可選> "filename":"<錄制文件名;可選>", "display":"<用戶名稱;可選>", "audio_level_average":"<音頻音量平均值,此設置覆蓋房間的audio_level_average;可選>", "audio_active_packets":"<音頻保活包數,此設置覆蓋房間audio_active_packets;可選>} ~~~ 此請求應該與發布者的`JSEP SDP Offer`一起提供,插件收到此消息后,將協商與之匹配的`JSEP SDP Answer`。如果成功,`configured`事件將被返回,其格式如下: ~~~ { "videoroom":"event", "configured":“ok"} ~~~ 該事件將與準備好的`JSEP SDP Answer`一起發送給客戶端。 你也可以用`configure`請求代替`publish`。兩者的功能在`發布`上是等效的,但從語義的角度來看,`publish`是發布時要發送的正確消息。`configure`請求也可以用于更新發布者會話的某些屬性,在這種情況下,就不能用`publish`請求了。 > 需要注意的是,如果用戶已經發送過`publish`了,再發送`publish`將導致失敗。 其實,您可以將`join`和`publish`兩個API合并為一個API請求。比如你一開始以`參與者`的身份加入,隨后變為`發布者`,這時你就可以將他們合并。你可以使用`joinandconfigure`請求來做到這一點,該請求將這兩個請求(join與publish)結合在一起。如果成功,則響應一個`joined`事件,并且將`JSEP SDP Answer`一起發送出去。 一旦`PeerConnection`設置成功,且發布者處于激活狀態,`event`就會被發向房間中的所有`參與者`。其格式如下所示: ~~~ { "videoroom":"event", "room":<房間ID>, “publishes":[ { "id":<新發布者的唯一ID>, "display":"<新發布者的名稱,如果有的話>", "audio_codec":"<新布者使用的音頻編解碼器,如果有的話>", "video_codec":"<新發布使用的視頻編解碼器,如果有的話>", "simulcast":"<如果發布者使用simucast,則為true(僅VP8和H.264)>", "talking":<true | false,發布者是否在講話(僅在使用音頻級別的情況下)>, } ]} ~~~ 要停止發布并刪除相關的`PeerConnection`,可以使用該`unpublish`請求: ~~~ { "request":“unpublish"} ~~~ 當插件收到這條請求后,它會刪除對應的`PeerConnection`,并將發布者從活動列表中刪除。如果成功,響應如下所示: ~~~ { "videoroom":"event", “unpublish":“ok"} ~~~ 當`PeerConnection`刪除后,插件還將向所有其他`參與者`通知該流不再可用的消息: ~~~ { "videoroom":"event", "room":<房間ID>, "unpublished":<發布者的ID>} ~~~ > 注意,不光收到`unpublish`消息會觸發上面的事件通知,其實無論什么情況下,只要`發布者`提供的流消失了(例如,句柄已關閉或用戶失去連接),都會發同樣的`事件`。此外,你可以使用同一句柄的上下文多次執行`發布`或`取消發布`操作。 正如我們上面講過的,你可以使用`configure`請求調整發布者會話的某些屬性。該請求的格式如下: ~~~ { "request":"configure", "audio":<true | false,取決于是否應該轉發音頻;默認為true>, "video":<true | false,取決于是否應該轉發視頻;默認為true>, "data":<true | false,取決于是否應該轉發數據;默認為true>, "bitrate":<比特率上限;可選,如果存在則覆蓋全局房間值(除非設置了bitrate_cap)>, "keyframe":<true | false,是否向發布者發送關鍵幀請求>, "record":<true | false,是否開啟錄制;可選> "filename":"<如果開啟了錄制,指明錄制路徑/文件;可選>", "display":"<用戶名稱;可選>", "audio_active_packets":"<音頻保活包個數,audio_active_packets;可選>", "audio_level_average":"<音頻音量平均值,audio_level_average;可選>",} ~~~ `configure`基本上與`publish`的屬性相同。這就是為什么兩個請求都可以用來開始發布的原因。如果`configure`成功,則返回`configured`事件,格式如下: ~~~ { "videoroom":"event", "configured":“ok"} ~~~ 當發送`configure`請求RTP擴展`ssrc-audio-level`時,如果`audiolevel_event`設置為true ,則可能會向所有發布者發送一些臨時事件。這些事件將具有以下格式: ~~~ { "videoroom":<"talking"|"stopped-talking",是否發布者開始或停止發言>, "room":<房間的唯一ID>, "id":<發布者的唯一ID>, "audio-level-dBov-avg":<音平音量的平均值,127 =靜音,0 ='太大聲'>} ~~~ ## 5\. VideoRoom 級聯 `? VideoRoom`插件的主要目的是從WebRTC源(發布者)獲取媒體,并將其轉發到WebRTC目的地(訂閱者),但實際上存在幾種方案,可以將媒體轉發給外部(不一定與WebRTC兼容)組件。例如,用于媒體處理,外部錄制,轉碼,級聯等等。`rtp_forward`顧名思義,就是將發布者發送的RTP包(普通或加密)實時轉發到遠程后端。 您可以使用`rtp_forward`請求為現有發布者添加新的RTP轉發器,其格式如下: ~~~ { "request":"rtp_forward", "room":<房間ID>, "publisher_id":<發布者ID>, "host":"<將RTP和數據包轉發到的host主機IP地址>", "host_family":"<ipv4 | ipv6,使用IPv4還是IPv6;默認情況下,無論我們得到什么>", "audio_port":<音頻RTP數據包轉發到的端口>, "audio_ssrc":<音頻SSRC,用于流式傳輸;可選> "audio_pt":<音頻有效負載類型;可選> "audio_rtcp_port":<接收方接收音頻RTCP反饋端口;可選,當前未用于音頻>, "video_port":<將視頻RTP數據包轉發到的端口>, "video_ssrc":<視頻 SSRC;可選> "video_pt":<視頻有效載荷類型;可選> "video_rtcp_port":<接收方接收視頻RTCP反饋端口;可選> "video_port_2":<如果simulcast,則視頻第二個的RTP數據端口>, "video_ssrc_2":<如果simulcast,則視頻第二個的SSRC;可選> "video_pt_2":<如果simulcast,則視頻第二個的有效載荷類型;可選> "video_port_3":<如果simulcast,則視頻第三個RTP數據包端口>, "video_ssrc_3":<如果simulcast,則視頻第三個SSRC;可選> "video_pt_3":<如果simulcast,則視頻第三個的有效載荷類型;可選> "data_port":<數據通道消息端口>, "srtp_suite":<身份驗證標簽的長度(32或80);可選> "srtp_crypto":"<用作加密的密鑰(如SDES中的base64編碼的密鑰;可選>"} ~~~ > 注意,如上所述,如果您配置了admin\_key屬性,則在請求中也需要提供它,否則未授權的請求將被拒絕。默認情況下,沒有對rtp\_forward進行限制。 如果請求成功則返回`rtp_forward`響應,其中格式如下: ~~~ { "videoroom":"rtp_forward", "room":<房間ID>, "publisher_id":<發布者ID> "rtp_stream":{ "host":"<接收流的主機IP,如果未解析,則與請求相同>", "audio":<音頻RTP端口,與請求相同(如果已配置)>, "audio_rtcp":<音頻RTCP端口,與請求相同(如果已配置)>, "audio_stream_id":<分配給音頻RTP轉發器的唯一數字ID,如果有的話,> "video":<視頻RTP端口,與請求相同(如果已配置)>, "video_rtcp":<視頻RTCP端口,如果配置,則與請求相同,> "video_stream_id":<分配給主視頻RTP轉發器的唯一數字ID,如果有的話,> "video_2":<第二個視頻端口,與請求相同(如果已配置)>, "video_stream_id_2":<分配給第二層視頻RTP轉發器的唯一數字ID,如果有的話,> "video_3":<第三個視頻端口,與請求相同(如果已配置)>, "video_stream_id_3":<分配給第三個視頻RTP轉發器的唯一數字ID,如果有,> "data":<數據端口,與請求相同(如果已配置)>, "data_stream_id":<分配給數據通道消息轉發器的唯一數字ID(如果有)> }} ~~~ 要停止以前創建的RTP轉發器,可以使用`stop_rtp_forward`請求,其格式如下: ~~~ { "request":"stop_rtp_forward", "room":<房間ID>, "publisher_id":<發布者ID>, "stream_id":<RTP轉發器ID>} ~~~ 請求成功,則返回`stop_rtp_forward`響應: ~~~ { "videoroom":"stop_rtp_forward", "room":<房間ID>, "publisher_id":<發布者ID,與請求相同,> "stream_id":<流ID,與請求相同>} ~~~ 如果要獲取特定房間中所有轉發器的列表,可以使用`listforwarders`請求,其格式如下: ~~~ { "request":"listforwarders", "room":<房間的唯一數字ID>, "secret":"<房間密碼;如果已配置,則是必需的>"} ~~~ 請求成功,則返回forwarders響應,其中包括RTP轉發器列表: ~~~ { "videoroom":"forwarders", "room":<房間的唯一ID>, "rtp_forwarders":[//具有RTP轉發器的發布者數組 {//發布者#1 "publisher_id":<發布者#1的唯一數字ID>, "rtp_forwarders":[// RTP轉發器數組 {// RTP轉發器#1 "audio_stream_id":<音頻RTP轉發器的唯一ID,如果有的話>, "video_stream_id":<視頻RTP轉發器的唯一ID,如果有的話>, "data_stream_id":<數據通道消息轉發器的唯一ID(如果有)>, "ip":"<接收端IP>", "port":<接收端端口>, "rtcp_port":<接收端RTCP端口,如果有的話>, "ssrc":<轉發器正在使用的SSRC,如果有的話>, "pt":<轉發器正在使用的有效負載類型>, "substream":<視頻子流,如果有>, "srtp":<true | false,RTP流是否已加密> }, //此發布者的其他轉發器 ], }, //其他發布者 ] ~~~ 在會議進行期間啟用或禁用錄制,您可以使用`enable_recording`請求,該請求的格式如下: ~~~ { "request":"enable_recording", "room":<房間ID>, "secret":"<房間密碼;如果已配置,則是必需的>" "record":<true | false,是否自動記錄此會議室中的參與者>,} ~~~ > 注意,參與者通常也可以通過configure請求來更改自己的錄制狀態:這樣做是為了獲得最大的靈活性,您可能希望單獨記錄一些流,而不是全局或自動記錄一些內容,到特定文件。就是說,如果你希望確保在啟用全局錄制后參與者不能停止其錄制,或者在不應該錄制該會議室的情況下啟動它,那么您應該確保在創建會議室時使用lock\_record屬性,將其設置為true。這樣,只有在提供了房間密碼的情況下,才能更改錄制狀態,從而確保只有管理員才能執行此操作。 最后,您可以使用`leave`請求離開會議室。如果您是會議室中的活動發布者,這也將隱式取消你的發布。該leave請求如下所示: ~~~ { "request":"leave"} ~~~ 如果成功,響應將如下所示: ~~~ { "videoroom":"event", "leave":"ok"} ~~~ 其他參與者將收到”leave”事件,格式如下: ~~~ { "videoroom":"event", "room":<房間ID>, "leave:<離開的參與者的唯一ID>} ~~~ 如果您是活躍的發布者,則其他用戶也將收到相應的`unpublish`事件,以通知他們該流不再可用。如果您只是潛伏而不是發布者,則其他參與者將僅收到”leave”事件。 ## VideoRoom 訂閱者 訂閱者在加入房間時,join請求的ptype屬性應該設置為`subscriber`,并指定要訂閱的確切的媒體流。該請求的確切語法如下: ~~~ { "request":"join", "ptype":"subscriber", "room":<房間ID>, "feed":<發布者ID;強制性>, "private_id":<發起此請求的用戶ID;可選的,除非房間配置要求> "close_pc":<true | false,發布者離開時是否應自動關閉PeerConnection;默認為true>, "audio":<true | false,是否轉發音頻;默認為true>, "video":<true | false,是否轉發視頻;默認為true>, "data":<true | false,是否轉發數據;默認為true>, "offer_audio":<true | false; 是否應該協商音頻;如果發布者的音頻>,默認為true "offer_video":<true | false; 是否應該協商視頻;如果發布者的視頻>,默認為true "offer_data":<true | false; 是否應該協商數據通道;如果發布者的datachannels>為默認值,則為true "substream":<啟用了simulcast情況下,要接收的子流(0-2);可選> "temporal":<啟用simulcast情況下,要接收的時間層(0-2);可選> "fallback":<多少時間(在我們這里,默認為250000)沒有接收到數據包將使我們下降到下面的子流>, "spatial_layer":<啟用VP9-SVC時要接收的空間層(0-2);可選> "temporal_layer":<啟用VP9-SVC時要接收的時間層(0-2);可選> } ~~~ 如您所見,只要指定好要訂閱的發布者ID,并在需要時指定好`private_id`(訂閱者ID),其它的都可以不設置。不過請求中的`offer_audio`,`offer_video`和`offer_data`特別有意思,你可以通過它們訂閱媒體的一個子集(音頻\\視頻\\數據)。 默認情況下,發送`join`請求時會導致插件層創建`SDP Offer`,用以協商發布者提供那些媒體。此外,如果發布者發布的是`simulcast`或`VP9 SVC`,那么你還可以訂閱你感興趣的子流,例如,獲得最佳質量的中間質量。更有意思的是,你可以使用`configure`請求隨時動態更改這些設置。 上面的請求如果成功,將生成一個新的`JSEP SDP Offer`,并伴隨一個attached事件: ~~~ { "videoroom":"attached", "room":<房間ID>, "feed":<發布者ID>, "display":"<發布者的名稱,如果有的話>"} ~~~ 在此階段,為了完成`PeerConnection`的設置,訂閱者應將`JSEP SDP Answer`發送回插件。此操作是通過`start`請求來完成的,在這種情況下,請求必須與`JSEP SDP Answer`相關聯,但是不需要任何參數: ~~~ { "request":“start"} ~~~ 如果成功,此請求將返回一個started事件: ~~~ { "videoroom":"event", "started":"ok"} ~~~ 完成此操作后,所需要做的就是等待WebRTC?`PeerConnection`建立成功。一旦`PeerConnection`建立成功,Streaming插件就可以開始向訂閱的觀眾轉發媒體了。 > 注意,在需要重新協商(例如出于ICE重啟目的)的情況下,您也可以使用我們剛經歷的相同步驟(watch請求,然后插件創建`JSEP Offer`,最后客戶端發送`start`請求和`JSEP Answer`)。 作為`訂閱者`,您可以發送`pause`臨時暫停或發送`start`恢復整個媒體的傳送(在這種情況下,不附帶任何JSEP SDP Answer)。因為上下文中已經有了相關信息,所以不需要重新進行協商。 ~~~ { "request":"pause"} { "request":"start"} ~~~ 當然,它們會分別導致paused和started事件: ~~~ { "videoroom":"event", "paused":"ok"} { "videoroom":"event", "started":"ok"} ~~~ `configure`請求可以對`訂閱`做更多深入操作。該請求允許`訂閱者`動態更改與媒體訂閱有關的某些屬性,`configure`請求的格式如下: ~~~ { "request":"configure", "audio":<true | false,是否應該轉發音頻;可選> "video":<true | false,是否應該轉發視頻;可選> "data":<true | false,是否轉發數據;可選> "substream":<啟用simulcast情況下,要接收的子流(0-2);可選> "temporal":<啟用simulcast,要接收的時間層(0-2);可選> "fallback":<多少時間(在我們這里,默認為250000)沒有接收到數據包將使我們下降到下面的子流>, "spatial_layer":<啟用VP9-SVC時要接收的空間層(0-2);可選> "temporal_layer":<啟用VP9-SVC時要接收的時間層(0-2);可選> "audio_level_average":"<如果提供,將覆蓋此用戶的房間audio_level_average;可選>", "audio_active_packets":"<如果提供,將覆蓋此用戶的房間audio_active_packets;可選> } ~~~ 正如你所看到的audio,video和data屬性可以用作媒體級的暫停/恢復功能,而pause與start只是簡單地暫停/恢復所有數據流。 下面來說說`switch`,switch 請求格式如下: ~~~ { "request":"switch", "feed":<要切換到的新發布者的唯一ID;強制性>, "audio":<true | false,取決于是否應該中繼音頻;可選> "video":<true | false,取決于是否應該中繼視頻;可選> "data":<true | false,取決于是否應該中繼數據通道消息;可選>} ~~~ 如果成功,您將退訂之前的發布者,然后訂閱新的發布者。確認切換成功的事件如下所示: ~~~ { "videoroom":"event", "switched":"ok", "room":<房間ID>, "id":<新發布者的唯一ID> } ~~~ 最后,要停止訂閱并刪除相關的PeerConnection,可以使用該leave請求。由于上下文是隱式的,因此不需要其他參數: ~~~ { "request":"leave" } ~~~ 如果成功,該插件將嘗試拆除PeerConnection,并發送回一個left事件: ~~~ { "videoroom":"event", "left":"ok", } ~~~ ## 小結 `VideoRoom`插件是Janus的一個特別重要的插件,對于該插件的理解對于我們理解整個Janus有至關重要的意義。本文說細分析了`VideoRoom`插件中所有的信令,大體上我們可以將它們人成兩在類,一類是房間管理信令,另一類是用戶信令。 這些信令設計的非常巧妙,對我們研發自己的SFU會議系統是一個很好的借鑒。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看