WebRTC本地选择codec(web本地模拟)
Posted dreamw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebRTC本地选择codec(web本地模拟)相关的知识,希望对你有一定的参考价值。
codec:编码译码器,编解码器。它是一个程序,也可以是算法,或者设备,用于编码(encode)和解码(decode)数据流。
WebRTC能让两个web或者app之间建立音视频通信。通信过程中,数据流的格式必须被两边的设备支持。
WebRTC提供了接口查询支持的codec,并且可以设置要使用的codec。本文演示选择视频codec的过程。
示例#
用户可以在发送视频流之前选择codec。把支持的codec类型列出来,用户自行选择。
开启视频后,建立连接前,我们可以选择设置codec。如上图蓝色区域所示。
html#
先来准备页面。2个video控件分别显示收发视频。
按钮分别控制开始,呼叫(发起连接)和挂断。
select
用来选择codec。获取支持的codec信息,放到下拉栏里让用户选择。
以下是index.html主要内容
<div id="container">
<h1><a href="https://an.rustfisher.com/webrtc/peerconnection/change-codec/" title="WebRTC示例,修改codec">WebRTC示例,修改codec</a>
</h1>
<video id="localVideo" playsinline autoplay muted></video>
<video id="remoteVideo" playsinline autoplay></video>
<div class="box">
<button id="startBtn">开始</button>
<button id="callBtn">呼叫</button>
<button id="hangupBtn">挂断</button>
</div>
<div class="box">
<span>选择Codec:</span>
<select id="codecPreferences" disabled>
<option selected value="">Default</option>
</select>
<div id="actualCodec"></div>
</div>
<p>可以在控制台观察 <code>MediaStream</code>, <code>localStream</code>, 和 <code>RTCPeerConnection</code></p>
</div>
<script src="../../src/js/adapter-2021.js"></script>
<script src="js/main.js" async></script>
adapter-2021.js是存放在本地的文件。要使用最新的adapter,按以下地址引入
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
js#
main.js控制主要逻辑。从开启摄像头开始。建立连接前可以选择codec。
建立连接的流程与「WebRTC模拟传输视频流,video通过本地节点peer传输视频流」类似。
获取可用codec#
先判断浏览器是否有RTCRtpTransceiver
,并且要能支持setCodecPreferences
方法
const supportsSetCodecPreferences = window.RTCRtpTransceiver &&
\'setCodecPreferences\' in window.RTCRtpTransceiver.prototype;
通过RTCRtpSender.getCapabilities(\'video\')
获取可支持的codec。
然后把它们放进列表codecPreferences
里
if (supportsSetCodecPreferences)
const codecs = RTCRtpSender.getCapabilities(\'video\');
codecs.forEach(codec =>
if ([\'video/red\', \'video/ulpfec\', \'video/rtx\'].includes(codec.mimeType))
return;
const option = document.createElement(\'option\');
option.value = (codec.mimeType + \' \' + (codec.sdpFmtpLine || \'\')).trim();
option.innerText = option.value;
codecPreferences.appendChild(option);
);
codecPreferences.disabled = false;
配置codec#
呼叫之前,找到用户选择的codec。
调用transceiver.setCodecPreferences(codecs)
,把选中的codec交给transceiver
。
if (supportsSetCodecPreferences)
// 获取选择的codec
const preferredCodec = codecPreferences.options[codecPreferences.selectedIndex];
if (preferredCodec.value !== \'\')
const [mimeType, sdpFmtpLine] = preferredCodec.value.split(\' \');
const codecs = RTCRtpSender.getCapabilities(\'video\');
const selectedCodecIndex = codecs.findIndex(c => c.mimeType === mimeType && c.sdpFmtpLine === sdpFmtpLine);
const selectedCodec = codecs[selectedCodecIndex];
codecs.splice(selectedCodecIndex, 1);
codecs.unshift(selectedCodec);
console.log(codecs);
const transceiver = pc1.getTransceivers().find(t => t.sender && t.sender.track === localStream.getVideoTracks()[0]);
transceiver.setCodecPreferences(codecs);
console.log(\'选择的codec\', selectedCodec);
main.js完整代码如下
\'use strict\';
console.log(\'WebRTC示例,选择codec\');
// --------- ui准备 ---------
const startBtn = document.getElementById(\'startBtn\');
const callBtn = document.getElementById(\'callBtn\');
const hangupBtn = document.getElementById(\'hangupBtn\');
const localVideo = document.getElementById(\'localVideo\');
const remoteVideo = document.getElementById(\'remoteVideo\');
callBtn.disabled = true;
hangupBtn.disabled = true;
startBtn.addEventListener(\'click\', start);
callBtn.addEventListener(\'click\', call);
hangupBtn.addEventListener(\'click\', hangup);
// ---------------------------
// -------- codec 的配置 --------
const codecPreferences = document.querySelector(\'#codecPreferences\');
const supportsSetCodecPreferences = window.RTCRtpTransceiver &&
\'setCodecPreferences\' in window.RTCRtpTransceiver.prototype;
// -----------------------------
let startTime;
remoteVideo.addEventListener(\'resize\', () =>
console.log(`Remote video size changed to $remoteVideo.videoWidthx$remoteVideo.videoHeight`);
if (startTime)
const elapsedTime = window.performance.now() - startTime;
console.log(\'视频流连接耗时: \' + elapsedTime.toFixed(3) + \'ms\');
startTime = null;
);
let localStream;
let pc1;
let pc2;
const offerOptions =
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
;
function getName(pc)
return (pc === pc1) ? \'pc1\' : \'pc2\';
function getOtherPc(pc)
return (pc === pc1) ? pc2 : pc1;
// 启动本地视频
async function start()
console.log(\'启动本地视频\');
startBtn.disabled = true;
try
const stream = await navigator.mediaDevices.getUserMedia( audio: true, video: true );
console.log(\'获取到本地视频\');
localVideo.srcObject = stream;
localStream = stream;
callBtn.disabled = false;
catch (e)
alert(`getUserMedia() error: $e.name`);
if (supportsSetCodecPreferences)
const codecs = RTCRtpSender.getCapabilities(\'video\');
console.log(\'RTCRtpSender.getCapabilities(video):\\n\', codecs);
codecs.forEach(codec =>
if ([\'video/red\', \'video/ulpfec\', \'video/rtx\'].includes(codec.mimeType))
return;
const option = document.createElement(\'option\');
option.value = (codec.mimeType + \' \' + (codec.sdpFmtpLine || \'\')).trim();
option.innerText = option.value;
codecPreferences.appendChild(option);
);
codecPreferences.disabled = false;
else
console.warn(\'当前不支持更换codec\');
// 呼叫并建立连接
async function call()
callBtn.disabled = true;
hangupBtn.disabled = false;
console.log(\'开始呼叫\');
startTime = window.performance.now();
const videoTracks = localStream.getVideoTracks();
const audioTracks = localStream.getAudioTracks();
if (videoTracks.length > 0)
console.log(`使用的摄像头: $videoTracks[0].label`);
if (audioTracks.length > 0)
console.log(`使用的麦克风: $audioTracks[0].label`);
const configuration = ;
pc1 = new RTCPeerConnection(configuration);
pc1.addEventListener(\'icecandidate\', e => onIceCandidate(pc1, e));
pc2 = new RTCPeerConnection(configuration);