利用 RTP 实现“保持”功能
由于 RTCPeerConnection 的流是通过 RTP 和上述接口实现的,因此您可以利用这些接口对流的内部进行访问和调整。您可以做的最简单的事情之一就是实现“保持”功能,即通话参与者可以点击一个按钮,关闭他们的麦克风,而是向另一个对等方发送音乐,并停止接收传入的音频。
注意:本示例使用了现代 JavaScript 功能,包括 async 函数和 await 表达式。这极大地简化了处理 WebRTC 方法返回的 Promise 的代码,使其更具可读性。
在下面的示例中,我们将把启用和禁用“保持”模式的对等方称为本地对等方,而被保持的用户称为远程对等方。
激活保持模式
本地对等方
当本地用户决定启用保持模式时,将调用下面的 enableHold() 方法。它接受一个包含保持期间播放的音频的 MediaStream 作为输入。
jsasync function enableHold(audioStream) {
try {
await audioTransceiver.sender.replaceTrack(audioStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = false;
audioTransceiver.direction = "sendonly";
} catch (err) {
/* handle the error */
}
}
try 块中的三行代码执行以下步骤
用包含保持音乐的 MediaStreamTrack 替换其传出音频轨道。
禁用传入音频轨道。
将音频收发器切换到仅发送模式。
这会通过发送 negotiationneeded 事件来触发 RTCPeerConnection 的重新协商,您的代码会通过使用 RTCPeerConnection.createOffer 生成 SDP 提议并将其通过信令服务器发送到远程对等方来响应。
audioStream(包含要播放的音频,而不是本地对等方的麦克风音频)可以来自任何地方。一种可能性是有一个隐藏的
远程对等方
在远程对等方,当我们收到方向设置为 "sendonly" 的 SDP 提议时,我们使用 holdRequested() 方法来处理它,该方法接受 SDP 提议字符串作为输入。
jsasync function holdRequested(offer) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(null);
audioTransceiver.direction = "recvonly";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
这里执行的步骤是
通过调用 RTCPeerConnection.setRemoteDescription() 将远程描述设置为指定的 offer。
将音频收发器的 RTCRtpSender 的轨道替换为 null,表示没有轨道。这会停止在收发器上发送音频。
将音频收发器的 direction 属性设置为 "recvonly",指示收发器仅接收音频而不发送任何音频。
SDP 答案通过调用 sendAnswer() 方法生成并发送,该方法使用 createAnswer() 生成答案,然后通过信令服务将生成的 SDP 发送到另一个对等方。
停用保持模式
本地对等方
当本地用户点击界面控件禁用保持模式时,将调用 disableHold() 方法来开始恢复正常功能的流程。
jsasync function disableHold(micStream) {
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.receiver.track.enabled = true;
audioTransceiver.direction = "sendrecv";
}
这会按如下方式逆转 enableHold() 中执行的步骤
音频收发器的 RTCRtpSender 轨道被替换为指定流的第一个音频轨道。
收发器的传入音频轨道被重新启用。
音频收发器的方向设置为 "sendrecv",表示它应恢复发送和接收流式音频,而不是仅发送。
就像在启用保持时一样,这会再次触发协商,导致您的代码向远程对等方发送新的提议。
远程对等方
当远程对等方收到 "sendrecv" 提议时,它会调用其 holdEnded() 方法
jsasync function holdEnded(offer, micStream) {
try {
await peerConnection.setRemoteDescription(offer);
await audioTransceiver.sender.replaceTrack(micStream.getAudioTracks()[0]);
audioTransceiver.direction = "sendrecv";
await sendAnswer();
} catch (err) {
/* handle the error */
}
}
此处 try 块内执行的步骤是
通过调用 setRemoteDescription() 将收到的提议存储为远程描述。
音频收发器的 RTCRtpSender 的 replaceTrack() 方法用于将传出音频轨道设置为麦克风音频流的第一个轨道。
收发器的方向设置为 "sendrecv",表示它应恢复发送和接收音频。
从现在开始,麦克风重新激活,远程用户可以再次听到本地用户,并与他们交谈。