WebRTC PeerConnection中有选择编解码器的方法吗?

5

嘿,我想知道在WebRTC中创建offer/answer时是否有选择编解码器的方式。目前可供选择的视频编解码器并不多,但有一些音频编解码器,如Opus、PCMU、PCMA等。

3个回答

10

一般来说是可以的。以下是如何在建立连接时优先选择Opus编解码器的示例。 您应该从createAnswer或createOffer的回调函数中调用“preferOpus”。

var preferOpus = function(sdp) {
  var sdpLines = sdp.split('\r\n');

  for (var i = 0; i < sdpLines.length; i++) {
    if (sdpLines[i].search('m=audio') !== -1) {
      var mLineIndex = i;
      break;
    }
  }

  if (mLineIndex === null) return sdp;

  for (i = 0; i < sdpLines.length; i++) {
    if (sdpLines[i].search('opus/48000') !== -1) {
      var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
      if (opusPayload) 
        sdpLines[mLineIndex] = setDefaultCodec(sdpLines[mLineIndex], opusPayload);
      break;
    }
  }

  sdpLines = removeCN(sdpLines, mLineIndex);

  sdp = sdpLines.join('\r\n');
  return sdp;
};

var extractSdp = function(sdpLine, pattern) {
  var result = sdpLine.match(pattern);
  return (result && result.length == 2)? result[1]: null;
};

var setDefaultCodec = function(mLine, payload) {
  var elements = mLine.split(' ');
  var newLine = new Array();
  var index = 0;
  for (var i = 0; i < elements.length; i++) {
    if (index === 3) newLine[index++] = payload;
    if (elements[i] !== payload) newLine[index++] = elements[i];
  }
  return newLine.join(' ');
};

var removeCN = function(sdpLines, mLineIndex) {
  var mLineElements = sdpLines[mLineIndex].split(' ');
  for (var i = sdpLines.length-1; i >= 0; i--) {
    var payload = extractSdp(sdpLines[i], /a=rtpmap:(\d+) CN\/\d+/i);
    if (payload) {
      var cnPos = mLineElements.indexOf(payload);
      if (cnPos !== -1) mLineElements.splice(cnPos, 1);
      sdpLines.splice(i, 1);
    }
  }
  sdpLines[mLineIndex] = mLineElements.join(' ');
  return sdpLines;
};

1
非常感谢您提供这个优秀的代码。您能否用简单易懂的英语详细说明您想要实现的目标? - Adrian Ber
@AdrianBer 的主要想法是获取 SDP 数据包并更改其中相应的字段,使您希望默认使用的编解码器出现在可用编解码器列表中的其他编解码器之前。 - fycth
实际上,您需要找到Opus编解码器的有效载荷,并将其作为第三个元素(首选项顺序中的第一个编解码器)添加到以“m = audio”开头的行中。为什么还要删除带有CN的行?顺便问一下,是否有文档说明sdp字符串的格式? - Adrian Ber
@AdrianBer 我有一篇简短的博客笔记,其中包含另一个使用SDP的示例/案例:https://www.webrtcexample.com/blog/?go=all/how-to-support-stereo-in-a-webrtc-application/ - 还有关于SDP的RFC:https://tools.ietf.org/html/rfc4566 - 希望这对你有用。 - fycth
2
同时,我编写了一个SDP解析器来更好地处理这种情况:https://github.com/beradrian/sdpparser - Adrian Ber

2
选择Opus只能让你完成一半。即使使用编解码器,它可能会默认为单声道和约42 kb/s,因为它主要设计用于语音。
如果您不使用语音输入,并希望获得一致的音乐体验,您可以使用约束禁用音频处理功能:
navigator.mediaDevices.getUserMedia({
  audio: {
    autoGainControl: false,
    channelCount: 2,
    echoCancellation: false,
    latency: 0,
    noiseSuppression: false,
    sampleRate: 48000,
    sampleSize: 16,
    volume: 1.0
  }
});

然后将SDP设置为 stereo 并增加 maxaveragebitrate

let answer = await peer.conn.createAnswer(offerOptions);
answer.sdp = answer.sdp.replace('useinbandfec=1', 'useinbandfec=1; stereo=1; maxaveragebitrate=510000');
await peer.conn.setLocalDescription(answer);

这应该输出一个类似于这样的字符串:
a=fmtp:111 minptime=10;useinbandfec=1; stereo=1; maxaveragebitrate=510000

这意味着立体声的潜在最大比特率为520kb/s,每个通道为260kps。实际比特率取决于您的网络速度和信号强度。

您可以在以下链接中了解更多其他可用属性:https://www.rfc-editor.org/rfc/rfc7587


0
随着浏览器开始支持setCodecPreferences,您可以检查“audio/opus” MIME类型并将编解码器首选项设置为opus编解码器:
let tcvr = pc.getTransceivers()[0];
let codecs = RTCRtpReceiver.getCapabilities('audio').codecs;
let opus_codecs = [];
// iterate over supported codecs and pull out the codecs we want
for(let i = 0; i < codecs.length; i++)
{
   if(codecs[i].mimeType == "audio/opus")
   {
      opus_codecs .push(codecs[i]);
   }
}
// currently not all browsers support setCodecPreferences
if(tcvr.setCodecPreferences != undefined)
{
   tcvr.setCodecPreferences(opus_codecs);
}

Pericror博客文章改编的代码,用于修复音频/视频编解码器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接