Hey I would like to know if there is any way to choose codecs when creating the offer/answer in WebRTC. There are currently not many video codecs to choose from, but there are audio codecs like Opus, PCMU, PCMA etc.
3 Answers
In general, yes. Here is example of how to prefer Opus codec during establishing conneciton. You should call 'preferOpus' from a callback function for createAnswer or createOffer.
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;
};

- 24,085
- 15
- 50
- 61

- 3,410
- 25
- 37
-
1Thanks a lot for this great code. Could you please detail in plain English what exactly you're trying to achieve? – Adrian Ber Oct 14 '15 at 15:26
-
@AdrianBer the main idea is to take SDP packet and change the appropriate fields in that way so the codec you wish to use by default would appeared before each other in the list of available codecs. – fycth Oct 15 '15 at 12:31
-
So practically you find the payload of the opus codec and add it as the third element (which is the first codec in order of preference) in the line starting with "m=audio". Why do you also remove the lines with CN? Btw, is somewhere a documentation explaining the format of the sdp string? – Adrian Ber Oct 16 '15 at 17:38
-
@AdrianBer I have a short blog note with another example/case of working with SDP: https://www.webrtcexample.com/blog/?go=all/how-to-support-stereo-in-a-webrtc-application/ - and there is also RFC for SDP: https://tools.ietf.org/html/rfc4566 - hope this will be useful for you – fycth Oct 16 '15 at 18:36
-
2Meantime, I wrote a SDP parser to better deal with this kind of things: https://github.com/beradrian/sdpparser – Adrian Ber Oct 27 '15 at 09:28
Choosing Opus will only get you halfway there. Even with the codec it might default to mono and around 42 kb/s as it's primarily designed for voice.
If you are not using voice input, and want consistent music, you can disable the audio processing features using constraints:
navigator.mediaDevices.getUserMedia({
audio: {
autoGainControl: false,
channelCount: 2,
echoCancellation: false,
latency: 0,
noiseSuppression: false,
sampleRate: 48000,
sampleSize: 16,
volume: 1.0
}
});
Then set the SDP to be stereo
and increase the 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);
This should output a string which looks like this:
a=fmtp:111 minptime=10;useinbandfec=1; stereo=1; maxaveragebitrate=510000
This gives a potential maximum bitrate of 520kb/s for stereo, which is 260kps per channel. Actual bitrate depends on the speed of your network and strength of your signal.
You can read more about the other available attributes at: https://www.rfc-editor.org/rfc/rfc7587
As browsers start to support setCodecPreferences, you can check for the "audio/opus" mimetype and set your codec preferences to opus codecs:
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);
}
Code adapted from this Pericror blog post to fix audio/video codecs.

- 19,461
- 8
- 43
- 65