Initiator 加入频道

图5-4 显示了启动上一节中描述的示例 WebRTC 应用程序时,Initiator 采取的动作序列。

图5-4

图5-4 发起者加入频道

如图所示,将网页加载到浏览器中后,首先会提示用户输入频道名称。 然后,对等方连接到信令服务器,并向其发送创建或加入消息。 这在下面的 JavaScript 代码段中进行了报告,并在 图5-5 的快照中也进行了显示:

  1. // Let's get started: prompt user for input (room name)
  2. var room = prompt('Enter room name:');
  3. // Connect to signalling server
  4. var socket = io.connect("http://localhost:8181");
  5. // Send 'create' or 'join' message to singnalling server
  6. if (room !== '') {
  7. console.log('Create or join room', room);
  8. socket.emit('create or join', room);
  9. }

图5-5

图5-5 发起者在 Chrome 浏览器中加入

当服务器收到创建或加入消息时,它将对等方识别为发起方,并创建与所需通道关联的服务器端房间。 最终它将创建的消息发送回客户端:

  1. // Handle 'create or join' messages
  2. socket.on('create or join', function (room) {
  3. var numClients = io.sockets.clients(room).length;
  4. log('S --> Room ' + room + ' has ' + numClients + ' client(s)');
  5. log('S --> Request to create or join room', room);
  6. // First client joining...
  7. if (numClients == 0){socket.join(room);
  8. socket.emit('created', room);
  9. } else if (numClients == 1) {
  10. ...

图5-6 显示了此阶段的服务器控制台。

图5-6

图5-6 信令服务器创建信令通道

现在我们到达了客户端从服务器获取一条创建的消息并意识到它将扮演通道发起者的角色:

  1. // Handle 'created' message coming back from server:
  2. // this peer is the initiator
  3. socket.on('created', function (room) {
  4. console.log('Created room ' + room);
  5. isInitiator = true;
  6. ...

客户端执行的下一个动作是通过 getUserMedia() API调用来访问用户的媒体:

图5-7 显示了在获得用户同意之前浏览器的窗口。

图5-7

图5-7 Initiator 征求用户同意

以下快照报告了 handleUserMedia() 成功处理程序执行的操作:

  1. 检索到的视频流附加到 HTML 页面的本地 <video> 元素
  2. 获取到的用户媒体消息发送给服务器
  1. // Call getUserMedia()
  2. navigator.getUserMedia(constraints, handleUserMedia, handleUserMediaError);
  3. console.log('Getting user media with constraints', constraints);

这些操作中的第一个操作的效果如 图5-8 所示。

图5-8

图5-8 用户同意后的发起者

下面是用于向服务器发送消息的 JavaScript 代码:

  1. // Send message to the other peer via the signaling server
  2. function sendMessage(message){
  3. console.log('Sending message: ', message);
  4. socket.emit('message', message);
  5. }

以下摘录中显示了与接收通用消息相关的服务器端行为。 服务器首先将一条日志消息(在 图5-8 下部的浏览器控制台中也可见)发送回客户端,然后将接收到的消息广播到远程方(如果存在)(不是这种情况) 在呼叫流程的这一点):

  1. // Handle 'message' messages
  2. socket.on('message', function (message) {
  3. log('S --> got message: ', message);
  4. // channel-only broadcast...
  5. socket.broadcast.to(message.channel).emit('message', message);
  6. });

通道启动程序执行的最后一个操作是 checkAndStart() 函数的执行,由于通道尚未准备好,在整个调用流程的此阶段,该函数实际上不执行任何操作:

  1. function checkAndStart() {
  2. // Do nothing if channel not ready...
  3. if (!isStarted && typeof localStream != 'undefined' && isChannelReady) {
  4. ...