# WebRTC(七)媒体协商

# 媒体协商

# 创建连接和信令

  • 创建连接,指的是创建 RTCPeerConnection,它负责端与端之间彼此建立 P2P 连接。在后面 RTCPeerConnection 一节中,我们还会对其做进一步的介绍。
  • 信令,指的是客户端通过信令服务器交换 SDP 信息。

# WebRTC 中媒体协商的作用

媒体协商的作用就是让双方找到共同支持的媒体能力,如双方都支持的编解码器,从而最终实现彼此之间的音视频通信。

  • 首先,通信双方将它们各自的媒体信息,如编解码器、媒体流的 SSRC、传输协议、IP 地址和端口等,按 SDP 格式整理好。
  • 然后,通信双方通过信令服务器交换 SDP 信息,并待彼此拿到对方的 SDP 信息后,找出它们共同支持的媒体能力。
  • 最后,双方按照协商好的媒体能力开始音视频通信

# RTCPeerConnection

RTCPeerConnection 类, 顾名思义,它表示的就是端与端之间建立的连接, 端到端之间的媒体协商,就是基于 RTCPeerConnection 对象实现的

var pcConfig = null;
var pc = new RTCPeerConnection(pcConfig);
1
2

在 JavaScript 下创建 RTCPeerConnection 对象非常简单,如上所述,只要通过 new 关键字创建即可。

在创建 RTCPeerConnection 对象时,还可以给它传一个参数 pcConfig,该参数的结构非常复杂,这里我们先将其设置为 null

# 媒体协商的过程

在通讯双方都创建好 RTCPeerConnection 对象后,它们就可以开始进行媒体协商了。不过在进行媒体协商之前,有两个重要的概念,即 OfferAnswer ,你必须要弄清楚。

OfferAnswer 是什么呢?对于 1 对 1 通信的双方来说,我们称首先发送媒体协商消息的一方为呼叫方,而另一方则为被呼叫方。

Offer,在双方通讯时,呼叫方发送的 SDP 消息称为 Offer。

Answer,在双方通讯时,被呼叫方发送的 SDP 消息称为 Answer。

  • 首先,呼叫方创建 Offer 类型的 SDP 消息。创建完成后,调用 setLocalDescriptoin 方法将该 Offer 保存到本地 Local 域,然后通过信令将 Offer 发送给被呼叫方。
  • 被呼叫方收到 Offer 类型的 SDP 消息后,调用 setRemoteDescription 方法将 Offer 保存到它的 Remote 域。作为应答,被呼叫方要创建 Answer 类型的 SDP 消息,Answer 消息创建成功后,再调用 setLocalDescription 方法将 Answer 类型的 SDP 消息保存到本地的 Local 域。最后,被呼叫方将 Answer 消息通过信令发送给呼叫方。至此,被呼叫方的工作就完部完成了。
  • 接下来是呼叫方的收尾工作,呼叫方收到 Answer 类型的消息后,调用 RTCPeerConnecton 对象的 setRemoteDescription 方法,将 Answer 保存到它的 Remote 域。
  • 至此,整个媒体协商过程处理完毕。

# 媒体协商的代码实现

了解了 WebRTC 的媒体协商过程之后,我们再看一下如何使用 JavaScript 代码来实现这一功能。浏览器提供了几个非常方便的 API,这些 API 是对底层 WebRTC API 的封装。如下所示:

createOffer ,创建 Offer;

createAnswer,创建 Answer;

setLocalDescription,设置本地 SDP 信息;

setRemoteDescription,设置远端的 SDP 信息。

# 1. 呼叫方创建 Offer

function doCall() {

console.log('Sending offer to peer');

pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);

}
1
2
3
4
5
6
7

如果 createOffer 函数调用成功的话,浏览器会回调我们设置的 setLocalAndSendMessage 方法,你可以在 setLocalAndSendMessage 方法里获取到 RTCSessionDescription 类型的 SDP 信息;如果出错则会回调 handleCreateOfferError 方法。

最终,在 setLocalAndSendMessage 回调方法中,通过 setLocalDescription() 方法将本地 SDP 描述信息设置到 WebRTC 的 Local 域。然后通过信令通道将此会话描述发送给被呼叫方。代码如下所示:

function setLocalAndSendMessage(sessionDescription) {

pc.setLocalDescription(sessionDescription);

sendMessage(sessionDescription);

}
1
2
3
4
5
6
7

# 2. 被呼叫方收到 Offer

被呼叫方收到 Offer 后,调用 setRemoteDescription 方法设置呼叫方发送给它的 Offer 作为远端描述。代码如下:

socket.on('message', function(message) {

...

} else if (message.type === 'offer') {

pc.setRemoteDescription(new RTCSessionDescription(message));

doAnswer();

} else if (...) {

...

}

....

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. 被呼叫方创建 Answer

然后,被呼叫方调用 RTCPeerConnection 对象的 createAnswer 方法,它会生成一个与远程会话兼容的本地会话,并最终将该会话描述发送给呼叫方。

function doAnswer() {

pc.createAnswer().then(

setLocalAndSendMessage,

onCreateSessionDescriptionError

);

}
1
2
3
4
5
6
7
8
9
10
11

# 4. 呼叫方收到 Answer

当呼叫方得到被呼叫方的会话描述,即 SDP 时,调用 setRemoteDescription 方法,将收到的会话描述设置为一个远程会话。代码如下:

socket.on('message', function(message) {

...

} else if (message.type === 'answer') {

pc.setRemoteDescription(new RTCSessionDescription(message));

} else if (...) {

...

}

....

});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

需要特别注意的是,通信双方链路的建立是在设置本地媒体能力,即调用 setLocalDescription 函数之后才进行的。

Last Updated: 2/13/2023, 9:16:34 PM