官术网_书友最值得收藏!

5.6 信令狀態機

在開始介紹端到端通信之前,必須先實現客戶端的信令系統,讓客戶端與信令服務器可以互通,從而為端到端交換信息做好準備。那么客戶端的信令系統該如何實現呢?

最簡單的辦法是通過狀態機實現,其基本原理如下:每次發送/接收一個信令后,客戶端都根據狀態機當前的狀態做相應的邏輯處理。比如當客戶端剛啟動時,其處于Init狀態,在此狀態下,用戶只能向服務端發送join消息,待服務端返回joined消息后,客戶端的狀態機發生了變化,變成了joined狀態后,才能開展后續工作。客戶端的狀態機如圖5.1所示。

圖5.1 信令狀態機

從圖中可以發現,客戶端的狀態機共有4種狀態,分別是Init、joined、joined_unbind以及joined_conn。下面詳述一下各種狀態之間是如何變化的。

·客戶端剛啟動時,其初始狀態為Init。

·在Init狀態下,用戶只能向服務器發送join消息;服務端收到join消息后,會返回joined消息;如果客戶端能收到joined消息,則說明用戶已經成功加入房間中,此時客戶端狀態更新為joined。

·在joined狀態下,客戶端有多種選擇,根據不同的選擇可以切換到不同的狀態:

 –如果用戶離開房間,客戶端又回到了初始狀態,即Init狀態。

 –如果客戶端收到第二個用戶加入的消息(即other_joined消息),則切換到join_conn狀態。在這種狀態下,兩個用戶就可以進行通信了。

 –如果客戶端收到第二個用戶離開的消息(即bye消息),則需要將其狀態切換到join_unbind。實際上,join_unbind狀態與joined狀態基本是一致的,不過可以通過這兩種不同的狀態值判斷出用戶之前的狀態。

·如果客戶端處于join_conn狀態,當它收到bye消息時,會變成joined_unbind狀態。

·如果客戶端是joined_unbind狀態,當它收到other_join消息時,會變成join_conn狀態。

接下來看一下客戶端狀態機是如何實現的,參見代碼5.9。

代碼5.9 客戶端狀態機


1 var state = init;
2
3 // 連接信令服務器并根據信令更新狀態機
4 function conn(){
5
6    // 建立socket.io 連接
7    socket = io.connect ();
8
9    // 收到joined 消息
10   socket.on('joined ', (roomid , id) =>
11      state = 'joined '; // 變更狀態
12      …
13      // 創建連接
14      createPeerConnection ();
15      bindTracks ();
16      …
17   });
18
19   // 收到otherjoin 消息
20   socket.on('otherjoin ', (roomid) => {
21     …
22     state = 'joined_conn ';  // 更改狀態
23     call();
24     …
25   });
26
27   // 收到full 消息
28   socket.on('full', (roomid , id) => {
29     …
30     hangup ();
31     socket.disconnect (); // 關閉連接
32     state = 'init'; // 回到初始化狀態
33     …
34   });
35
36 // 收到用戶離開的消息
37 socket.on('left', (roomid , id) => {
38     …
39     hangup ();
40     socket.disconnect ();
41     state='init' // 回到初始化狀態
42     …
43   });
44
45 socket.on('bye', (room , id) => {
46     …
47     state = 'joined_unbind ';
48     hangup ();
49     …
50   });
51
52   …
53   // 向服務端發送join 消息
54   roomid = getQueryVariable('room');
55   socket.emit('join', roomid);
56
57  }
58
59   …
60   conn(); // 與信令服務器建立連接
61 …

在代碼5.9中,首先執行第一行代碼,將狀態機的狀態初始化為init;之后調用conn()函數,讓客戶端與信令服務器建立連接。而在conn()內部做了三件事:一是調用socket.io的connect()方法與信令服務器建立連接;二是向socket.io注冊5個回調函數,分別對應5個信令消息,即joined、otherjoin、full、left以及bye消息,以便收到不同的消息時做不同的邏輯處理;三是向信令服務器發送join消息。至此客戶端的運轉就由信令驅動起來了。

當客戶端收到服務端返回的joined消息后,會在回調之前注冊到socket.io中的回調函數,因此上面代碼的第10~17行會被執行。在這段代碼中,客戶端首先變更自己當前的狀態為joined,然后創建RTCPeerConnection(關于RTCPeerConnection的內容將會在5.7.1節詳細介紹)對象,最后將采集到的音視頻流綁定到之前創建好的RTCPeerConnection對象上。

當第二個用戶上線后,第一個用戶會收到服務端發來的otherjoin消息。上面代碼中的第20~25行會被執行。在這幾行代碼中,也是先變更客戶端狀態為joined_conn,然后調用call()函數。call()函數實現的是媒體協商,有關媒體協商相關的內容會在5.7.3節再做介紹,相關的代碼也在5.7.3節中給出。

其他幾種情況與前面介紹的兩種情況是類似的,都是收到服務端的信令后回調對應的函數,在函數中變更狀態,然后做相應的邏輯處理,這里就不再贅述了。

主站蜘蛛池模板: 滦南县| 基隆市| 中超| 乐东| 岳阳市| 绍兴县| 旬邑县| 浦城县| 杂多县| 二连浩特市| 木里| 卓资县| 安吉县| 定结县| 东乌| 昌平区| 五寨县| 常熟市| 大余县| 周宁县| 玉环县| 桐城市| 东台市| 寿阳县| 成都市| 昌乐县| 宁安市| 东乌| 德保县| 枞阳县| 金昌市| 保靖县| 北安市| 福贡县| 宁津县| 北宁市| 竹北市| 凌源市| 修文县| 盈江县| 陆川县|