本文以 Web 平台为例,介绍如何在项目中,实现音视频发布流和订阅流功能。
参考示例项目。
一次简单的音视频通话的流程图如下:
实现一次简单的音视频通话主要包含以下步骤:
调用浏览器原生 getUserMedia
创建一个本地音视频流,并保存音视频轨道。
// See https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints. const stream:MediaStream= await navigator.mediaDevices.getUserMedia(options as MediaStreamConstraints) const videoTrack = mediaStream.getVideoTracks()[0]; const audioTrack = mediaStream.getAudioTracks()[0];
const peer = new RTCPeerConnection({}) const ms = new MediaStream() // 添加音视频轨道 if (audioTrack) ms.addTrack(audioTrack); if (videoTrack) ms.addTrack(videoTrack); peer.addTransceiver(audioTrack || "audio",{ streams:[ms], direction:"sendonly" }) peer.addTransceiver(videoTrack || "video",{ streams:[ms], direction:"sendonly" }) // 创建 P2P offer const offer = await peer.createOffer(); // 设置本地 offer // 参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription peer.setLocalDescription(offer);
const peer = new RTCPeerConnection({}) peer.addTransceiver("audio",{ direction:"recvonly" }) peer.addTransceiver("video",{ direction:"recvonly" }) // 创建 P2P offer const offer = await peer.createOffer(); // 设置本地 offer // 参考 https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription peer.setLocalDescription(offer);
// 通过 veWTN 服务交换 offer const res = await fetch(YOUR_PUSH_URL||YOUR_PULL_URL, { method: 'POST', body: offer.sdp, headers }); if (!res.ok) { return res; } // 可以在 headers 里获取到断开链接的请求地址 const resourceURL = new URL(res.headers.get('location') || '', url); const sdp = await res.text(); const answer = new RTCSessionDescription({ type: 'answer', sdp }); await peerConn.setRemoteDescription(answer);
发布订阅的双方交换 SDP 之后,peerConnection 就已经成功建联。此时订阅端 peerConnection 可在回调 ontrack 中接收到发布端的音视频流。
peer.ontrack = function (event) { if (event && event.streams) { if (event.track.kind === 'video') { const player = document.querySelector("#video"); player.onloadeddata = () =>{ player.play(); } // 设置播放器的 srcObject 属性为接收到的流 player.current.srcObject = event.streams[0]; } } };
断开 PeerConnection 后,音视频流的发布和接收也将停止。
peer.close(); peer = undefined; fetch(resourceURL.href, { method: 'DELETE' });
至此,我们实现了基础的音视频通话。