如何为高质量 Opus 音频设置 SDP
How to set up SDP for High quality Opus audio
我一直在尝试通过 WebRTC 传输一些高质量的音频流。 Opus,主要宣传的编解码器似乎很完美,因为它可以支持高达 510kbit/s 的速度,远远超过需要。
问题是,设置 Webrtc SDP 并没有看起来那么明显。感谢 Muaz Khan 的出色工作,我已经能够将它强制到 128kbit/s。
代码基本上是这样的:
function setBandwidth(sdp) {
var sdpLines = sdp.split('\r\n');
// Find opus payload.
var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000');
var opusPayload;
if (opusIndex) {
opusPayload = '109';
}
sdpLines[opusIndex]='a=rtpmap:'+opusPayload+' opus/48000/2';
var mediaIndex = findLine(sdpLines, 'm=audio');
sdpLines[mediaIndex]=(sdpLines[mediaIndex].slice(0,(sdpLines[mediaIndex].indexOf("RTP/SAVPF")+10))).concat(opusPayload);
var abIndex = findLine(sdpLines, 'a=mid:');
sdpLines[abIndex]='a=mid:audio\r\nb=AS:300000';
// Find the payload in fmtp line.
var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString());
if (fmtpLineIndex == null) {
sdpLines[opusIndex] = sdpLines[opusIndex].concat('\r\n'+'a=fmtp:' + opusPayload.toString()+ ' minptime=10; useinbandfec=1; maxaveragebitrate='+128*1024+'; stereo=1; sprop-stereo=1 ; cbr=1');
sdp = sdpLines.join('\r\n');
return sdp;
}
// Append stereo=1 to fmtp line.
// added maxaveragebitrate here; about 50 kbits/s
// added stereo=1 here for stereo audio
// x-google-min-bitrate=50; x-google-max-bitrate=50
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; maxaveragebitrate='+128*1024+'; stereo=1; sprop-stereo=1 ; cbr=1');
sdp = sdpLines.join('\r\n');
return sdp;
}
现在一切就绪,firefox 和 chrome 都显示发送方和接收方的正确值,通信打开,音乐播放!
adding answer-sdp v=0
o=mozilla...THIS_IS_SDPARTA-42.0 502631676322875352 0 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256.....
a=ice-options:trickle
a=msid-semantic:WMS *
m=audio 9 RTP/SAVPF 109
c=IN IP4 0.0.0.0
a=recvonly
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=ice-pwd:c56d106030599efe08cfa2a4f9b3ad5a
a=ice-ufrag:93982a76
a=mid:audio
b=AS:300000
a=rtcp-mux
a=rtpmap:109 opus/48000/2
a=fmtp:109 minptime=10; useinbandfec=1; maxaveragebitrate=131072; stereo=1; sprop-stereo=1 ; cbr=1
a=setup:active
a=ssrc:1948755120 cname:{208483df-13c9-e347-ba4a-c71604df3ad9}
但是质量太差了。 Chrome 在 chrome://webrtc-internals/ 上显示大约 30kbit/s 并且声音严重失真且音量可变...
关于这个问题的任何线索?
我创建了一个 SDP parser。您提供 SDP 描述,获得一个 JSON 对象,然后再次将其序列化。
通过这种方式,将 SDP 作为对象进行处理比作为批量文本处理要容易得多。
质量差的主要原因是浏览器的音频处理。
您需要将音频约束传递给 GetUserMedia 对象:
{ 'channelCount':{'exact': 2}, 'echoCancellation':false, 'autoGainControl':false, 'noiseSuppression':false }
您需要在 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。您获得的实际比特率将根据您的网络速度和信号强度而有所不同。
在以下位置记录了更多 SDP 属性:https://www.rfc-editor.org/rfc/rfc7587
我一直在尝试通过 WebRTC 传输一些高质量的音频流。 Opus,主要宣传的编解码器似乎很完美,因为它可以支持高达 510kbit/s 的速度,远远超过需要。 问题是,设置 Webrtc SDP 并没有看起来那么明显。感谢 Muaz Khan 的出色工作,我已经能够将它强制到 128kbit/s。 代码基本上是这样的:
function setBandwidth(sdp) {
var sdpLines = sdp.split('\r\n');
// Find opus payload.
var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000');
var opusPayload;
if (opusIndex) {
opusPayload = '109';
}
sdpLines[opusIndex]='a=rtpmap:'+opusPayload+' opus/48000/2';
var mediaIndex = findLine(sdpLines, 'm=audio');
sdpLines[mediaIndex]=(sdpLines[mediaIndex].slice(0,(sdpLines[mediaIndex].indexOf("RTP/SAVPF")+10))).concat(opusPayload);
var abIndex = findLine(sdpLines, 'a=mid:');
sdpLines[abIndex]='a=mid:audio\r\nb=AS:300000';
// Find the payload in fmtp line.
var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString());
if (fmtpLineIndex == null) {
sdpLines[opusIndex] = sdpLines[opusIndex].concat('\r\n'+'a=fmtp:' + opusPayload.toString()+ ' minptime=10; useinbandfec=1; maxaveragebitrate='+128*1024+'; stereo=1; sprop-stereo=1 ; cbr=1');
sdp = sdpLines.join('\r\n');
return sdp;
}
// Append stereo=1 to fmtp line.
// added maxaveragebitrate here; about 50 kbits/s
// added stereo=1 here for stereo audio
// x-google-min-bitrate=50; x-google-max-bitrate=50
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; maxaveragebitrate='+128*1024+'; stereo=1; sprop-stereo=1 ; cbr=1');
sdp = sdpLines.join('\r\n');
return sdp;
}
现在一切就绪,firefox 和 chrome 都显示发送方和接收方的正确值,通信打开,音乐播放!
adding answer-sdp v=0
o=mozilla...THIS_IS_SDPARTA-42.0 502631676322875352 0 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256.....
a=ice-options:trickle
a=msid-semantic:WMS *
m=audio 9 RTP/SAVPF 109
c=IN IP4 0.0.0.0
a=recvonly
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=ice-pwd:c56d106030599efe08cfa2a4f9b3ad5a
a=ice-ufrag:93982a76
a=mid:audio
b=AS:300000
a=rtcp-mux
a=rtpmap:109 opus/48000/2
a=fmtp:109 minptime=10; useinbandfec=1; maxaveragebitrate=131072; stereo=1; sprop-stereo=1 ; cbr=1
a=setup:active
a=ssrc:1948755120 cname:{208483df-13c9-e347-ba4a-c71604df3ad9}
但是质量太差了。 Chrome 在 chrome://webrtc-internals/ 上显示大约 30kbit/s 并且声音严重失真且音量可变... 关于这个问题的任何线索?
我创建了一个 SDP parser。您提供 SDP 描述,获得一个 JSON 对象,然后再次将其序列化。
通过这种方式,将 SDP 作为对象进行处理比作为批量文本处理要容易得多。
质量差的主要原因是浏览器的音频处理。 您需要将音频约束传递给 GetUserMedia 对象:
{ 'channelCount':{'exact': 2}, 'echoCancellation':false, 'autoGainControl':false, 'noiseSuppression':false }
您需要在 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。您获得的实际比特率将根据您的网络速度和信号强度而有所不同。
在以下位置记录了更多 SDP 属性:https://www.rfc-editor.org/rfc/rfc7587