Initiator 开始协商

接收到服务器中继的用户媒体消息后,发起者将再次激活 checkAndStart() 函数,由于边界条件现在已更改,因此这一次实际上已执行:通道已准备就绪,本地流已 由 getUserMedia() API 调用提供。

图5-11 中的 UML 快照和以下 JavaScript 代码指示发起方(1)创建了 PeerConnection 对象; (2)将频道标记为已开始; (3)激活 doCall() JavaScript 函数。

  1. // Channel negotiation trigger function
  2. function checkAndStart() {
  3. if (!isStarted && typeof localStream != 'undefined' && isChannelReady) {
  4. createPeerConnection();
  5. isStarted = true;
  6. if (isInitiator) {
  7. doCall();
  8. }
  9. }
  10. }

深入研究上述操作的详细信息,以下代码摘录显示,为正确管理 ICE 候选地址以及远程流的添加和删除,PeerConnection 对象附加了许多处理程序。 此外,PeerConnection 还配备了一个数据通道,该通道将用于以对等方式与 Joiner 交换文本数据:

  1. function createPeerConnection() {
  2. try {
  3. pc = new RTCPeerConnection(pc_config, pc_constraints);
  4. pc.addStream(localStream);
  5. pc.onicecandidate = handleIceCandidate;
  6. console.log('Created RTCPeerConnnection with:\n' + ' config: \'' + JSON.stringify(pc_config) + '\';\n' + ' constraints: \'' + JSON.stringify(pc_constraints) + '\'.');
  7. } catch (e) {
  8. console.log('Failed to create PeerConnection, exception: ' + e.message);
  9. alert('Cannot create RTCPeerConnection object.');
  10. return;
  11. }
  12. pc.onaddstream = handleRemoteStreamAdded;
  13. pc.onremovestream = handleRemoteStreamRemoved;
  14. if (isInitiator) {
  15. try {
  16. // Create a reliable data channel
  17. sendChannel = pc.createDataChannel("sendDataChannel",{reliable: true});
  18. trace('Created send data channel');
  19. } catch (e) {
  20. alert('Failed to create data channel. ');
  21. trace('createDataChannel() failed with exception: ' + e.message);
  22. }
  23. sendChannel.onopen = handleSendChannelStateChange;
  24. sendChannel.onmessage = handleMessage;
  25. sendChannel.onclose = handleSendChannelStateChange;
  26. } else {
  27. // Joiner
  28. pc.ondatachannel = gotReceiveChannel;
  29. }
  30. }

图5-11

图5-11 Initiator 开始协商

关于 doCall() 函数,它基本上在可用的 PeerConnection 上调用 createOffer() 方法,要求浏览器正确构建一个 SDP (会话描述协议)对象,该对象代表发起方的媒体和要传达给远程方的功能:

  1. function doCall() {
  2. console.log('Creating Offer...');
  3. pc.createOffer(setLocalAndSendMessage, onSignalingError, sdpConstraints);
  4. }

与此调用关联的成功处理程序负责将浏览器提供的 SDP 与 PeerConnection 相关联,并通过信令服务器将其传输到远程对等方:

  1. function setLocalAndSendMessage(sessionDescription) {
  2. pc.setLocalDescription(sessionDescription);
  3. sendMessage(sessionDescription);
  4. }