From a817a4504d14d73ed21fe8791417e2753173bdd7 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Fri, 7 Mar 2025 22:18:54 -0300 Subject: [PATCH 01/37] added maxOpusPlaybackRate param --- packages/webrtc/src/RTCPeer.ts | 13 +-- packages/webrtc/src/utils/helpers.test.ts | 79 +++++++++++++--- packages/webrtc/src/utils/helpers.ts | 48 ++++++++-- packages/webrtc/src/utils/interfaces.ts | 3 + packages/webrtc/src/utils/sdpHelpers.test.ts | 53 ++++++++--- packages/webrtc/src/utils/sdpHelpers.ts | 94 +++++++++++--------- 6 files changed, 211 insertions(+), 79 deletions(-) diff --git a/packages/webrtc/src/RTCPeer.ts b/packages/webrtc/src/RTCPeer.ts index c2faab702..94926f9ea 100644 --- a/packages/webrtc/src/RTCPeer.ts +++ b/packages/webrtc/src/RTCPeer.ts @@ -3,12 +3,13 @@ import { getUserMedia, getMediaConstraints, filterIceServers, + getSenderAudioMaxBitrate, } from './utils/helpers' import { - sdpStereoHack, sdpBitrateHack, sdpMediaOrderHack, sdpHasValidCandidates, + opusConfigsHack, } from './utils/sdpHelpers' import { BaseConnection } from './BaseConnection' import { @@ -571,6 +572,7 @@ export default class RTCPeer { const audioTransceiverParams: RTCRtpTransceiverInit = { direction: this.options.negotiateAudio ? 'sendrecv' : 'sendonly', streams: [this._localStream], + sendEncodings: [{maxBitrate: getSenderAudioMaxBitrate(this.options)}] } this.logger.debug( 'Applying audioTransceiverParams', @@ -801,13 +803,12 @@ export default class RTCPeer { private _setLocalDescription(localDescription: RTCSessionDescriptionInit) { const { - useStereo, googleMaxBitrate, googleMinBitrate, googleStartBitrate, } = this.options - if (localDescription.sdp && useStereo) { - localDescription.sdp = sdpStereoHack(localDescription.sdp) + if (localDescription.sdp) { + localDescription.sdp = opusConfigsHack(localDescription.sdp, this.options) } if ( localDescription.sdp && @@ -832,8 +833,8 @@ export default class RTCPeer { } private _setRemoteDescription(remoteDescription: RTCSessionDescriptionInit) { - if (remoteDescription.sdp && this.options.useStereo) { - remoteDescription.sdp = sdpStereoHack(remoteDescription.sdp) + if (remoteDescription.sdp) { + remoteDescription.sdp = opusConfigsHack(remoteDescription.sdp, this.options) } if (remoteDescription.sdp && this.instance.localDescription) { remoteDescription.sdp = sdpMediaOrderHack( diff --git a/packages/webrtc/src/utils/helpers.test.ts b/packages/webrtc/src/utils/helpers.test.ts index 70534fe9f..37b5a2883 100644 --- a/packages/webrtc/src/utils/helpers.test.ts +++ b/packages/webrtc/src/utils/helpers.test.ts @@ -1,4 +1,4 @@ -import { getMediaConstraints } from '../utils/helpers' +import { getMediaConstraints, getSenderAudioMaxBitrate } from '../utils/helpers' jest.mock('../utils/deviceHelpers', () => ({ assureDeviceId: jest.fn().mockImplementation(async(p:any)=> Promise.resolve(p)) @@ -17,25 +17,49 @@ describe('Helpers functions', () => { it('should return audio === true & video === false', async () => { const mediaConstraints = await getMediaConstraints({}) - expect(mediaConstraints.audio).toStrictEqual(true) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) expect(mediaConstraints.video).toStrictEqual(false) }) it('should return audio === true & video === false', async () => { const mediaConstraints = await getMediaConstraints({audio: true, video: true}) - expect(mediaConstraints.audio).toStrictEqual(true) - expect(mediaConstraints.video).toStrictEqual(true) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) + expect(mediaConstraints.video).toEqual({}) }) it('should return audio === {}', async () => { const mediaConstraints = await getMediaConstraints({audio: {}}) - expect(mediaConstraints.audio).toEqual({}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) expect(mediaConstraints.video).toStrictEqual(false) }) it('should return audio === {}', async () => { const mediaConstraints = await getMediaConstraints({audio: {}, video: {}}) - expect(mediaConstraints.audio).toEqual({}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) + expect(mediaConstraints.video).toEqual({}) + }) + + it('should return compatible audio constrains, mono - audio only', async () => { + const mediaConstraints = await getMediaConstraints({audio: true, video: false, maxOpusPlaybackRate: 8000, useStereo: false}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1, "sampleRate": 8000}) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return compatible audio constrains, stereo - audio only', async () => { + const mediaConstraints = await getMediaConstraints({audio: true, video: false, maxOpusPlaybackRate: 8000, useStereo: true}) + expect(mediaConstraints.audio).toEqual({"channelCount": 2, "sampleRate": 8000}) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return compatible audio constrains, mono - with video', async () => { + const mediaConstraints = await getMediaConstraints({audio: true, video: true, maxOpusPlaybackRate: 8000, useStereo: false}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1, "sampleRate": 8000}) + expect(mediaConstraints.video).toEqual({}) + }) + + it('should return compatible audio constrains, stereo - with video', async () => { + const mediaConstraints = await getMediaConstraints({audio: true, video: true, maxOpusPlaybackRate: 8000, useStereo: true}) + expect(mediaConstraints.audio).toEqual({"channelCount": 2, "sampleRate": 8000}) expect(mediaConstraints.video).toEqual({}) }) @@ -47,17 +71,17 @@ describe('Helpers functions', () => { it('should return audio === true', async () => { const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(true) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) }) it('should return audio === {}', async () => { const mediaConstraints = await getMediaConstraints({audio: {}, remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) }) it('should return audio === {deviceId: { exact: "abcd" }}', async () => { const mediaConstraints = await getMediaConstraints({micId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }}) + expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }, channelCount: 1}) }) }) @@ -107,27 +131,54 @@ describe('Helpers functions', () => { it('should return audio === true & video === false', async () => { const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(true) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) expect(mediaConstraints.video).toStrictEqual(false) }) it('should return audio === true & video === true', async () => { const mediaConstraints = await getMediaConstraints({video: true, remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(true) - expect(mediaConstraints.video).toStrictEqual(true) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) + expect(mediaConstraints.video).toEqual({}) }) it('should return audio === {} & video === {}', async () => { const mediaConstraints = await getMediaConstraints({audio: {}, video: {}, remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({}) + expect(mediaConstraints.audio).toEqual({"channelCount": 1}) expect(mediaConstraints.video).toEqual({}) }) it('should return audio === {deviceId: { exact: "abcd" }} & video === {deviceId: { exact: "abcd" }}' , async () => { const mediaConstraints = await getMediaConstraints({micId: 'abcd', camId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }}) + expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }, channelCount: 1}) expect(mediaConstraints.video).toEqual({deviceId: { exact: "abcd" }}) }) }) }) + + describe('getSenderAudioMaxBitrate', () => { + it('should return 20000', () => { + expect(getSenderAudioMaxBitrate({useStereo: false, maxOpusPlaybackRate: 8000})) + }) + it('should return 40000', () => { + expect(getSenderAudioMaxBitrate({useStereo: true, maxOpusPlaybackRate: 8000})) + }) + it('should return 320000', () => { + expect(getSenderAudioMaxBitrate({useStereo: false, maxOpusPlaybackRate: 16000})) + }) + it('should return 640000', () => { + expect(getSenderAudioMaxBitrate({useStereo: true, maxOpusPlaybackRate: 16000})) + }) + it('should return 320000', () => { + expect(getSenderAudioMaxBitrate({useStereo: false, maxOpusPlaybackRate: 32000})) + }) + it('should return 640000', () => { + expect(getSenderAudioMaxBitrate({useStereo: true, maxOpusPlaybackRate: 32000})) + }) + it('should return 640000', () => { + expect(getSenderAudioMaxBitrate({useStereo: false, maxOpusPlaybackRate: 48000})) + }) + it('should return 1280000', () => { + expect(getSenderAudioMaxBitrate({useStereo: true, maxOpusPlaybackRate: 48000})) + }) + }) }) \ No newline at end of file diff --git a/packages/webrtc/src/utils/helpers.ts b/packages/webrtc/src/utils/helpers.ts index cbf0b38cc..e04e3c054 100644 --- a/packages/webrtc/src/utils/helpers.ts +++ b/packages/webrtc/src/utils/helpers.ts @@ -4,6 +4,8 @@ import { assureDeviceId } from './deviceHelpers' import { ConnectionOptions } from './interfaces' import { sdpHasAudio, sdpHasVideo } from './sdpHelpers' +const DEFAULT_MAX_BITRATE = 64000 + // FIXME: Remove and use getUserMedia directly export const getUserMedia = (constraints: MediaStreamConstraints) => { getLogger().info('RTCService.getUserMedia', constraints) @@ -43,31 +45,39 @@ export const getMediaConstraints = async ( options: ConnectionOptions ): Promise => { let audio = _getAudioConstraints(options) - const { micLabel = '', micId } = options + let video = _getVideoConstraints(options) + + const { micLabel = '', micId, camLabel = '', camId, maxOpusPlaybackRate, useStereo } = options + + const channelCount = useStereo ? 2 : 1 + if (typeof audio === 'boolean' && audio) { + audio = { channelCount } + } else if (typeof audio === 'object') { + audio.channelCount = channelCount + } + + if (typeof video === 'boolean' && video) { + video = {} + } if (micId && audio) { const newMicId = await assureDeviceId(micId, micLabel, 'microphone').catch( (_error) => null ) if (newMicId) { - if (typeof audio === 'boolean') { - audio = {} - } audio.deviceId = { exact: newMicId } } } - let video = _getVideoConstraints(options) - const { camLabel = '', camId } = options + if(maxOpusPlaybackRate && audio) { + audio.sampleRate = maxOpusPlaybackRate + } if (camId && video) { const newCamId = await assureDeviceId(camId, camLabel, 'camera').catch( (_error) => null ) if (newCamId) { - if (typeof video === 'boolean') { - video = {} - } video.deviceId = { exact: newCamId } } } @@ -75,6 +85,26 @@ export const getMediaConstraints = async ( return { audio, video } } +export const getSenderAudioMaxBitrate = (options: ConnectionOptions) => { + if(!options.maxOpusPlaybackRate && !options.useStereo) { + return + } + + let maxBitrate = DEFAULT_MAX_BITRATE + + if(options.maxOpusPlaybackRate && (options.maxOpusPlaybackRate <= 8000)) { + maxBitrate = options.useStereo ? 20000 : 40000 + } else if(options.maxOpusPlaybackRate && (options.maxOpusPlaybackRate <= 16000)) { + maxBitrate = options.useStereo ? 32000 : 64000 + } else if(options.maxOpusPlaybackRate && (options.maxOpusPlaybackRate <= 24000)) { + maxBitrate = options.useStereo ? 40000 : 80000 + } else if (options.useStereo) { + maxBitrate = 128000 + } + + return maxBitrate +} + interface FilterIceServersOptions { disableUdpIceServers?: boolean } diff --git a/packages/webrtc/src/utils/interfaces.ts b/packages/webrtc/src/utils/interfaces.ts index bda64f22d..1e7c3a1d4 100644 --- a/packages/webrtc/src/utils/interfaces.ts +++ b/packages/webrtc/src/utils/interfaces.ts @@ -86,6 +86,8 @@ export interface ConnectionOptions { maxIceGatheringTimeout?: number /** @internal */ maxConnectionStateTimeout?: number + /** OPUS audio codec max playback rate in Hz */ + maxOpusPlaybackRate?: number /** @internal */ watchMediaPackets?: boolean /** @internal */ @@ -99,6 +101,7 @@ export interface ConnectionOptions { nodeId?: string layout?: string + positions?: VideoPositions } diff --git a/packages/webrtc/src/utils/sdpHelpers.test.ts b/packages/webrtc/src/utils/sdpHelpers.test.ts index 9f243bdc8..58ffd65d0 100644 --- a/packages/webrtc/src/utils/sdpHelpers.test.ts +++ b/packages/webrtc/src/utils/sdpHelpers.test.ts @@ -1,5 +1,5 @@ import { - sdpStereoHack, + opusConfigsHack, sdpMediaOrderHack, sdpBitrateHack, sdpRemoveLocalCandidates, @@ -17,21 +17,54 @@ describe('SDP utility functions', () => { const AUDIO_VIDEO_SDP = `v=0\r\no=- 8094323291162995063 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 51609 UDP/TLS/RTP/SAVPF 111\r\na=sendrecv\r\nm=video 52560 UDP/TLS/RTP/SAVPF 96\r\na=recvonly\r\n` - describe('sdpStereoHack', () => { + describe('opusConfigsHack', () => { const SDP_OPUS_STEREO = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1; stereo=1; sprop-stereo=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' - const SDP_OPUS_NO_STEREO = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + const SDP_OPUS_STEREO_MAXPLAYBACKRATE = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;stereo=1;sprop-stereo=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + const SDP_OPUS_MAXPLAYBACKRATE = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + const SDP_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_NO_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_NO_OPUS_STEREO = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 stereo=1; sprop-stereo=1\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' - it('set stereo=1 if a=fmtp is present', () => { - expect(sdpStereoHack(SDP_OPUS_NO_STEREO)).toEqual(SDP_OPUS_STEREO) + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 stereo=1;sprop-stereo=1\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + const SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 maxplaybackrate=8000;useinbandfec=1;minptime=10;stereo=1;sprop-stereo=1\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + const SDP_NO_OPUS_MAXPLAYBACKRATE = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 maxplaybackrate=8000;useinbandfec=1;minptime=10\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' + + it('set stereo=1 if a=fmtp is present', () => { + expect(opusConfigsHack(SDP_OPUS_NO_STEREO, {useStereo: true})).toEqual(SDP_OPUS_STEREO) }) it('set stereo=1 if a=fmtp is NOT present', () => { - expect(sdpStereoHack(SDP_NO_OPUS_NO_STEREO)).toEqual(SDP_NO_OPUS_STEREO) + const result = opusConfigsHack(SDP_NO_OPUS_NO_STEREO, {useStereo: true}) + console.log(result) + expect(result).toEqual(SDP_NO_OPUS_STEREO) + }) + + it('set stereo=1 and maxplaybackrate=8000 if a=fmtp is present', () => { + + expect(opusConfigsHack(SDP_OPUS_NO_STEREO, {useStereo: true, maxOpusPlaybackRate: 8000})).toEqual(SDP_OPUS_STEREO_MAXPLAYBACKRATE) + }) + + it('set stereo=1 and maxplaybackrate=8000 if a=fmtp is NOT present', () => { + const result = opusConfigsHack(SDP_NO_OPUS_NO_STEREO, {useStereo: true, maxOpusPlaybackRate: 8000}) + console.log(result) + expect(result).toEqual(SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE) + }) + + it('set maxplaybackrate=8000 if a=fmtp is present', () => { + + expect(opusConfigsHack(SDP_OPUS_NO_STEREO, {maxOpusPlaybackRate: 8000})).toEqual(SDP_OPUS_MAXPLAYBACKRATE) + }) + + it('set maxplaybackrate=8000 if a=fmtp is NOT present', () => { + const result = opusConfigsHack(SDP_NO_OPUS_NO_STEREO, {maxOpusPlaybackRate: 8000}) + console.log(result) + expect(result).toEqual(SDP_NO_OPUS_MAXPLAYBACKRATE) }) }) @@ -41,9 +74,9 @@ describe('SDP utility functions', () => { const OFFER_KO = 'v=0\r\no=mozilla...THIS_IS_SDPARTA-65.0 4664580510618001282 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 37:18:D1:6A:F4:B6:DB:00:A0:48:4B:EC:CC:F3:E1:AF:DC:DB:DA:2C:E2:C0:6B:36:92:02:84:04:60:B5:EB:70\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=video 55993 UDP/TLS/RTP/SAVPF 120 121 126 97\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 55993 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 54949 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:5 urn:ietf:params:rtp-hdrext:toffset\r\na=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1\r\na=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=fmtp:121 max-fs=12288;max-fr=60\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:1\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {77747bff-84dd-124b-8f35-3d84e89cd9fe}\r\na=rtcp:54949 IN IP4 192.168.1.4\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 goog-remb\r\na=rtcp-fb:121 nack\r\na=rtcp-fb:121 nack pli\r\na=rtcp-fb:121 ccm fir\r\na=rtcp-fb:121 goog-remb\r\na=rtcp-fb:126 nack\r\na=rtcp-fb:126 nack pli\r\na=rtcp-fb:126 ccm fir\r\na=rtcp-fb:126 goog-remb\r\na=rtcp-fb:97 nack\r\na=rtcp-fb:97 nack pli\r\na=rtcp-fb:97 ccm fir\r\na=rtcp-fb:97 goog-remb\r\na=rtcp-mux\r\na=rtpmap:120 VP8/90000\r\na=rtpmap:121 VP9/90000\r\na=rtpmap:126 H264/90000\r\na=rtpmap:97 H264/90000\r\na=setup:actpass\r\na=ssrc:3672465901 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\nm=audio 60578 UDP/TLS/RTP/SAVPF 109 9 0 8 101\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 60578 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 56425 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:0\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {d3bf3e75-0c87-f849-a967-6ec743afd59b}\r\na=rtcp:56425 IN IP4 192.168.1.4\r\na=rtcp-mux\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:9 G722/8000/1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\na=setup:actpass\r\na=ssrc:3703202793 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\n' const ANSWER = - 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=fmtp:109 useinbandfec=0; stereo=1\r\na=rtpmap:101 telephone-event/8000\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\n' + 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=fmtp:109 useinbandfec=0;stereo=1\r\na=rtpmap:101 telephone-event/8000\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\n' const ANSWER_REVERTED = - 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=fmtp:109 useinbandfec=0; stereo=1\r\na=rtpmap:101 telephone-event/8000\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\n' + 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=fmtp:109 useinbandfec=0;stereo=1\r\na=rtpmap:101 telephone-event/8000\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\n' it('reorder sdp media lines for audio to come first', () => { expect(sdpMediaOrderHack(ANSWER, OFFER_KO)).toEqual(ANSWER_REVERTED) }) diff --git a/packages/webrtc/src/utils/sdpHelpers.ts b/packages/webrtc/src/utils/sdpHelpers.ts index 35baacac1..cba0e9208 100644 --- a/packages/webrtc/src/utils/sdpHelpers.ts +++ b/packages/webrtc/src/utils/sdpHelpers.ts @@ -1,6 +1,9 @@ import { getLogger } from '@signalwire/core' +import { ConnectionOptions } from '@signalwire/js' import SDPUtils from 'sdp' +const endOfLine = '\r\n' + const _isAudioLine = (line: string) => /^m=audio/.test(line) const _isVideoLine = (line: string) => /^m=video/.test(line) const _getCodecPayloadType = (line: string) => { @@ -45,7 +48,6 @@ export const sdpHasAudio = (sdp: string) => { * @return the SDP modified */ export const sdpStereoHack = (sdp: string) => { - const endOfLine = '\r\n' const sdpLines = sdp.split(endOfLine) const opusIndex = sdpLines.findIndex( @@ -79,7 +81,6 @@ export const sdpMediaOrderHack = ( answer: string, localOffer: string ): string => { - const endOfLine = '\r\n' const offerLines = localOffer.split(endOfLine) const offerAudioIndex = offerLines.findIndex(_isAudioLine) const offerVideoIndex = offerLines.findIndex(_isVideoLine) @@ -110,7 +111,6 @@ export const sdpBitrateHack = ( min: number, start: number ) => { - const endOfLine = '\r\n' const lines = sdp.split(endOfLine) lines.forEach((line, i) => { if (/^a=fmtp:\d*/.test(line)) { @@ -124,42 +124,6 @@ export const sdpBitrateHack = ( return lines.join(endOfLine) } -// const sdpAudioRemoveRTPExtensions = (sdp: string, extensionsToFilter: string[]): string => { -// const endOfLine = '\r\n' - -// let beginLines: string[] = [] -// let audioLines: string[] = [] -// let videoLines: string[] = [] -// const newLines = sdp.split(endOfLine) - -// const offerAudioIndex = newLines.findIndex(_isAudioLine) -// const offerVideoIndex = newLines.findIndex(_isVideoLine) - -// if (offerAudioIndex < offerVideoIndex) { -// beginLines = newLines.slice(0, offerAudioIndex) -// audioLines = newLines.slice(offerAudioIndex, offerVideoIndex) -// videoLines = newLines.slice(offerVideoIndex, (newLines.length - 1)) -// } else { -// beginLines = newLines.slice(0, offerVideoIndex) -// audioLines = newLines.slice(offerAudioIndex, (newLines.length - 1)) -// videoLines = newLines.slice(offerVideoIndex, offerAudioIndex) -// } - -// const newAudioLines = audioLines.filter((line: string) => { -// return !(line.includes(extensionsToFilter[0]) || line.includes(extensionsToFilter[1]) || line.includes(extensionsToFilter[2])) -// }) - -// return [...beginLines, ...newAudioLines, ...videoLines, ''].join(endOfLine) -// } - -// const sdpAudioRemoveRidMidExtHack = (sdp: string): string => { -// const extensionsToFilter = [ -// 'urn:ietf:params:rtp-hdrext:sdes:mid', -// 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id', -// 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id', -// ] -// return sdpAudioRemoveRTPExtensions(sdp, extensionsToFilter) -// } /** * Check for srflx, prflx or relay candidates @@ -189,13 +153,63 @@ export const sdpHasValidCandidates = (sdp: string) => { } } +export const opusConfigsHack = (sdp: SDPUtils.SDPBlob, options: ConnectionOptions) => { + const sdpLines = SDPUtils.splitLines(sdp) + const opusIndex = sdpLines.findIndex( + (s) => /^a=rtpmap:(\d+)\s+opus\/(\d+)(?:\/(\d+))?$/i.test(s) + ) + + if (opusIndex < 0) { + // nothing todo + return sdp + } + + const opusRtpMap = SDPUtils.parseRtpMap(sdpLines[opusIndex]) + + const pattern = new RegExp(`^a=fmtp:${opusRtpMap.payloadType}`) + const opusFmtpLineIndex = sdpLines.findIndex(s => pattern.test(s)) + + const opusParameters = + opusFmtpLineIndex >= 0 + ? SDPUtils.parseFmtp(sdpLines[opusFmtpLineIndex]) + : {} + + if (options.maxOpusPlaybackRate) { + opusParameters.maxplaybackrate = `${options.maxOpusPlaybackRate}` + opusParameters.useinbandfec = '1' + opusParameters.minptime = '10' + } + + if (options.useStereo) { + opusParameters.stereo = '1' + opusParameters['sprop-stereo'] = '1' + } + + const opusFmtpLine = SDPUtils.writeFmtp({ + channels: opusRtpMap.channels, + name: opusRtpMap.name, + payloadType: opusRtpMap.payloadType, + parameters: opusParameters, + clockRate: opusRtpMap.clockRate, + }) + + if (opusFmtpLineIndex >= 0) { + sdpLines[opusFmtpLineIndex] = opusFmtpLine.trim() + } else { + sdpLines[opusIndex] += `${endOfLine}${opusFmtpLine.trim()}` + console.log(sdpLines[opusIndex]) + } + + return `${sdpLines.join(endOfLine)}${endOfLine}` +} + /** * Remove "a=candidate" lines with local candidates * https://bloggeek.me/psa-mdns-and-local-ice-candidates-are-coming/ */ export const sdpRemoveLocalCandidates = (sdp: string) => { const pattern = /^a=candidate.*.local\ .*/ - const endOfLine = '\r\n' + return sdp .split(endOfLine) .filter((line) => !pattern.test(line)) From ff9f6157a4270172ad9d75a924b3da44600b49bb Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Tue, 11 Mar 2025 15:49:38 -0300 Subject: [PATCH 02/37] testing --- internal/playground-js/src/fabric/index.html | 10 ++++++++++ internal/playground-js/src/fabric/index.js | 3 +++ packages/js/src/fabric/WSClient.ts | 1 + packages/js/src/fabric/interfaces/wsClient.ts | 2 ++ packages/webrtc/src/utils/sdpHelpers.ts | 3 +-- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 592b9781d..362217dc4 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -93,6 +93,16 @@
Connect
Include Video +
+ + +
- - - -
- -
- Status: Not Connected -
- -
-
-
Controls
-
- - -
- -
- - -
+
+ + + + +
-
- - -
+
+ Status: Not Connected +
+
+
-
- - -
+
+
+
Controls
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
Layouts
-
- - -
-
- - -
+
+ + +
-
ScreenShare
-
- - -
-
- - -
-
- - -
+
+ +
-
- +
+ +
-
-
-
-
+
Layouts
-
+ + +
+
+ +
-
-
-
- - +
ScreenShare
+
+ +
-
- - +
+ +
-
- - +
+ +
-
-
- - -
-
- - -
-
- - -
+
+
+
+
-
-
Recording (unknown)
-
-
- - - - -
+
+
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
Recording (unknown)
+
+
+ + + +
+
-
-
Playback URL
-
- +
+
Playback URL
+
+ +
+
+
+ + + +
-
-
- - - - -
-
-
Playback Seek
-
-
- -
-
- -
-
- - -
+
+
Playback Seek
+
+
+ +
+
+ +
+
+ +
-
-
- -
+
+ + +
-
- - - +
+
+ + + + \ No newline at end of file diff --git a/internal/playground-js/src/fabric/index.js b/internal/playground-js/src/fabric/index.js index 39a1cc550..5b7de1cd9 100644 --- a/internal/playground-js/src/fabric/index.js +++ b/internal/playground-js/src/fabric/index.js @@ -307,14 +307,28 @@ window.dial = async ({ reattach = false } = {}) => { const dialer = reattach ? client.reattach : client.dial - const call = await dialer({ + const dialOptions = { nodeId: steeringId, to: document.getElementById('destination').value, rootElement: document.getElementById('rootElement'), video: document.getElementById('video').checked, audio: document.getElementById('audio').checked, - opusMaxPlaybackRate: parseInt(document.getElementById('opusConfig').value) - }) + } + + if (document.getElementById('targetCodec').value.trim().length) { + const codecPrefix = document.getElementById('targetCodec').value + if (document.getElementById('maxPlaybackRate').value.trim().length) { + dialOptions[`${codecPrefix}MaxPlaybackRate`] = parseInt( + document.getElementById('maxPlaybackRate').value + ) + } + if (document.getElementById('maxAverageBitrate').value.trim().length) { + dialOptions[`${codecPrefix}maxAverageBitrate`] = parseInt( + document.getElementById('maxAverageBitrate').value + ) + } + } + const call = await dialer(dialOptions) window.__call = call roomObj = call @@ -889,8 +903,12 @@ window.ready(async function () { document.getElementById('audio').checked = true document.getElementById('video').checked = localStorage.getItem('fabric.ws.video') === 'true' - document.getElementById('opusConfig').value = - localStorage.getItem('fabric.ws.opusConfig') || '' + document.getElementById('targetCodec').value = + localStorage.getItem('fabric.ws.targetCodec') || '' + document.getElementById('maxPlaybackRate').value = + localStorage.getItem('fabric.ws.maxPlaybackRate') || '' + document.getElementById('maxAverageBitrate').value = + localStorage.getItem('fabric.ws.maxAverageBitrate') || '' const urlParams = new URLSearchParams(window.location.search) const room = urlParams.get('room') From 07c55d28da595fdebfdad70f3f625ada7071ab60 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Mon, 24 Mar 2025 23:28:53 -0300 Subject: [PATCH 09/37] Fix build --- packages/core/src/index.ts | 4 +--- packages/core/src/types/index.ts | 8 -------- packages/core/src/types/utils.ts | 12 ++++++++++++ packages/core/src/utils/index.ts | 4 ---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 224d51421..969803e75 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,7 +24,6 @@ import { increasingDelay, decreasingDelay, constDelay, - isPlaybackRate } from './utils' import { WEBRTC_EVENT_TYPES, isWebrtcEventType } from './utils/common' import { BaseSession } from './BaseSession' @@ -77,13 +76,12 @@ export { isSATAuth, isJSONRPCRequest, isJSONRPCResponse, - isPlaybackRate, LOCAL_EVENT_PREFIX, stripNamespacePrefix, asyncRetry, increasingDelay, decreasingDelay, - constDelay + constDelay, } export * from './redux/features/component/componentSlice' diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index 07edbce4d..ba24dd71b 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -326,14 +326,6 @@ export type PubSubChannelEvents = | InternalVideoEventNames | SessionEvents -export enum PlaybackRate { - hz_8000 = 8000, - hz_12000 = 12000, - hz_16000 = 16000, - hz_24000 = 24000, - hz_48000 = 48000, -} - export * from './video' export * from './utils' export * from './cantina' diff --git a/packages/core/src/types/utils.ts b/packages/core/src/types/utils.ts index 925312e64..11973a2b5 100644 --- a/packages/core/src/types/utils.ts +++ b/packages/core/src/types/utils.ts @@ -147,3 +147,15 @@ export type Promisify = { export type Prettify = NonNullable & { [K in keyof T]: Prettify } & {} + +export enum PlaybackRate { + hz_8000 = 8000, + hz_12000 = 12000, + hz_16000 = 16000, + hz_24000 = 24000, + hz_48000 = 48000, +} + +export const isPlaybackRate = (value: unknown): value is PlaybackRate => { + return Object.values(PlaybackRate).includes(value as PlaybackRate) +} diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 4c1f964dc..9d652a5e8 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,4 +1,3 @@ -import { PlaybackRate } from '../types' import { Authorization, JSONRPCRequest, @@ -229,6 +228,3 @@ export const isSATAuth = (e?: Authorization): e is SATAuthorization => { return typeof e !== 'undefined' && 'jti' in e } -export const isPlaybackRate = (value: unknown): value is PlaybackRate => { - return Object.values(PlaybackRate).includes(value as PlaybackRate) -} From db832826be2ca87283d50f36e5818a410772fe6a Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Tue, 8 Apr 2025 15:06:14 -0300 Subject: [PATCH 10/37] cleanup --- internal/playground-js/src/fabric/index.html | 1 - packages/webrtc/src/utils/helpers.ts | 6 +----- packages/webrtc/src/utils/sdpHelpers.test.ts | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index cc0f24ffd..d73fbb4fe 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -60,7 +60,6 @@
Connect
-
-
-
- - -
-
- - -
-
-
Call Options:
-
- - +
+
+
+
+
+
Connect
+
+ +
-
- - +
+ +
-
-
-
-
- - - - - - +
+ + +
+
+
Call Options:
+
+ + +
+
+ + +
+
+
+
+
+ + + + + + +
-
-
- - - - -
+
+ + + + +
-
- Status: Not Connected +
+ Status: Not Connected +
-
-
-
-
Controls
-
- - -
+
+
+
Controls
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
Layouts
-
- - -
-
- - -
+
Layouts
+
+ + +
+
+ + +
-
ScreenShare
-
- - -
-
- - -
-
- - +
ScreenShare
+
+ + +
+
+ + +
+
+ + +
-
-
- +
+ +
-
-
-
-
-
+
+
+
+
+
-
-
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ + +
-
-
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ + +
-
-
-
Recording (unknown)
-
-
- - - - +
+
Recording (unknown)
+
+
+ + + + +
-
-
-
Playback URL
-
- -
-
-
- - - - +
+
Playback URL
+
+
-
-
Playback Seek
-
-
- -
-
- -
-
- - +
+
+ + + + +
+
+
Playback Seek
+
+
+ +
+
+ +
+
+ + +
-
-
- - +
+ + +
+
-
-
- - - - \ No newline at end of file + + + From 78a1f785ac8edf65251a00d706bcc8835b42505a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Tue, 15 Apr 2025 07:07:50 -0300 Subject: [PATCH 12/37] Update internal/playground-js/src/fabric/index.js Co-authored-by: Ammar Ansari --- internal/playground-js/src/fabric/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/playground-js/src/fabric/index.js b/internal/playground-js/src/fabric/index.js index 5b7de1cd9..a2c575576 100644 --- a/internal/playground-js/src/fabric/index.js +++ b/internal/playground-js/src/fabric/index.js @@ -323,7 +323,7 @@ window.dial = async ({ reattach = false } = {}) => { ) } if (document.getElementById('maxAverageBitrate').value.trim().length) { - dialOptions[`${codecPrefix}maxAverageBitrate`] = parseInt( + dialOptions[`${codecPrefix}MaxAverageBitrate`] = parseInt( document.getElementById('maxAverageBitrate').value ) } From 81a1b4c6a0bb599f9137ce2ef3332e58b11b7799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Tue, 15 Apr 2025 08:21:19 -0300 Subject: [PATCH 13/37] Update packages/js/src/fabric/WSClient.ts Co-authored-by: Ammar Ansari --- packages/js/src/fabric/WSClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/src/fabric/WSClient.ts b/packages/js/src/fabric/WSClient.ts index 83f94f963..cf15684be 100644 --- a/packages/js/src/fabric/WSClient.ts +++ b/packages/js/src/fabric/WSClient.ts @@ -179,7 +179,7 @@ export class WSClient extends BaseClient<{}> implements WSClientContract { } if (params.opusMaxAverageBitrate && params.opusMaxAverageBitrate <= 0) { - throw new Error('Invalid opusMaxPlaybackRate') + throw new Error('Invalid opusMaxPlaybackRate. It can only be a positive number.') } } From 8e924e0b65995bfe05d2a00546ae1f2c5ce8a6ac Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Tue, 6 May 2025 17:13:12 -0300 Subject: [PATCH 14/37] flexible audio codec params --- internal/playground-js/src/fabric/index.html | 2 + internal/playground-js/src/fabric/index.js | 21 +-- packages/core/src/types/utils.ts | 18 +-- packages/js/src/fabric/WSClient.ts | 25 +--- packages/js/src/fabric/interfaces/wsClient.ts | 8 +- packages/webrtc/src/RTCPeer.ts | 33 +++-- packages/webrtc/src/utils/helpers.test.ts | 24 ---- packages/webrtc/src/utils/helpers.ts | 5 - packages/webrtc/src/utils/interfaces.ts | 8 +- packages/webrtc/src/utils/sdpHelpers.test.ts | 110 +++++---------- packages/webrtc/src/utils/sdpHelpers.ts | 127 +++++++++--------- 11 files changed, 146 insertions(+), 235 deletions(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 2f74f21e2..2035a1fe6 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -106,6 +106,8 @@
Connect
> + + { if (document.getElementById('targetCodec').value.trim().length) { const codecPrefix = document.getElementById('targetCodec').value - if (document.getElementById('maxPlaybackRate').value.trim().length) { - dialOptions[`${codecPrefix}MaxPlaybackRate`] = parseInt( - document.getElementById('maxPlaybackRate').value - ) - } - if (document.getElementById('maxAverageBitrate').value.trim().length) { - dialOptions[`${codecPrefix}MaxAverageBitrate`] = parseInt( - document.getElementById('maxAverageBitrate').value - ) - } + dialOptions.audioCodecs = [ + `${codecPrefix}:${ + document.getElementById('maxPlaybackRate').value.trim().length + ? 'maxplaybackrate=' + : '' + }${document.getElementById('maxPlaybackRate').value.trim()}${ + document.getElementById('maxAverageBitrate').value.trim().length + ? ';maxaveragebitrate=' + : '' + }${document.getElementById('maxAverageBitrate').value.trim()}`, + ] } const call = await dialer(dialOptions) diff --git a/packages/core/src/types/utils.ts b/packages/core/src/types/utils.ts index 11973a2b5..5662d7bbb 100644 --- a/packages/core/src/types/utils.ts +++ b/packages/core/src/types/utils.ts @@ -148,14 +148,10 @@ export type Prettify = NonNullable & { [K in keyof T]: Prettify } & {} -export enum PlaybackRate { - hz_8000 = 8000, - hz_12000 = 12000, - hz_16000 = 16000, - hz_24000 = 24000, - hz_48000 = 48000, -} - -export const isPlaybackRate = (value: unknown): value is PlaybackRate => { - return Object.values(PlaybackRate).includes(value as PlaybackRate) -} +export type AudioCodecParams = + | `opus:${string}` + | `red:${string}` + | `G722:${string}` + | `PCMU:${string}` + | `PCMA:${string}` + | `telephone-event:${string}` diff --git a/packages/js/src/fabric/WSClient.ts b/packages/js/src/fabric/WSClient.ts index cf15684be..4cd9411fb 100644 --- a/packages/js/src/fabric/WSClient.ts +++ b/packages/js/src/fabric/WSClient.ts @@ -5,7 +5,6 @@ import { VertoBye, VertoSubscribe, VideoRoomSubscribedEventParams, - isPlaybackRate } from '@signalwire/core' import { MakeRoomOptions } from '../video' import { createFabricRoomSessionObject } from './FabricRoomSession' @@ -161,26 +160,6 @@ export class WSClient extends BaseClient<{}> implements WSClientContract { if (!pathname) { throw new Error('Invalid destination address') } - - if (params.opusMaxPlaybackRate) { - if (!isPlaybackRate(params.opusMaxPlaybackRate)) { - throw new Error('Invalid opusMaxPlaybackRate') - } - if (typeof params.audio === 'object') { - if ( - params.audio?.sampleRate && - params.audio?.sampleRate !== params.opusMaxPlaybackRate - ) { - throw new Error( - 'Mismatching parameters: opusMaxPlaybackRate, audio.sampleRate' - ) - } - } - } - - if (params.opusMaxAverageBitrate && params.opusMaxAverageBitrate <= 0) { - throw new Error('Invalid opusMaxPlaybackRate. It can only be a positive number.') - } } private buildOutboundCall(params: DialParams & { attach?: boolean }) { @@ -214,8 +193,7 @@ export class WSClient extends BaseClient<{}> implements WSClientContract { attach: params.attach ?? false, disableUdpIceServers: params.disableUdpIceServers || false, userVariables: params.userVariables || this.wsClientOptions.userVariables, - opusMaxPlaybackRate: params.opusMaxPlaybackRate, - opusMaxAverageBitrate: params.opusMaxAverageBitrate, + audioCodecs: params.audioCodecs, }) // WebRTC connection left the room. @@ -253,6 +231,7 @@ export class WSClient extends BaseClient<{}> implements WSClientContract { prevCallId: payload.callID, disableUdpIceServers: params.disableUdpIceServers || false, userVariables: params.userVariables || this.wsClientOptions.userVariables, + audioCodecs: params.audioCodecs }) // WebRTC connection left the room. diff --git a/packages/js/src/fabric/interfaces/wsClient.ts b/packages/js/src/fabric/interfaces/wsClient.ts index 848d7cd6f..8030a928e 100644 --- a/packages/js/src/fabric/interfaces/wsClient.ts +++ b/packages/js/src/fabric/interfaces/wsClient.ts @@ -1,4 +1,4 @@ -import { PlaybackRate, UserOptions } from '@signalwire/core' +import { AudioCodecParams, UserOptions } from '@signalwire/core' import { IncomingCallHandlers } from './incomingCallManager' import { FabricRoomSession } from '../FabricRoomSession' import { ApiRequestRetriesOptions } from '../SATSession' @@ -94,10 +94,8 @@ export interface CallParams { negotiateVideo?: boolean /** User & UserAgent metadata */ userVariables?: WSClientOptions['userVariables'] - /** OPUS audio codec max playback rate in Hz */ - opusMaxPlaybackRate?: PlaybackRate - /** OPUS audio codec max average bitrate in Hz */ - opusMaxAverageBitrate?: number + /** audio codec with fmtp params */ + audioCodecs?: AudioCodecParams[] } export interface DialParams extends CallParams { diff --git a/packages/webrtc/src/RTCPeer.ts b/packages/webrtc/src/RTCPeer.ts index baab9bf79..6b88a4713 100644 --- a/packages/webrtc/src/RTCPeer.ts +++ b/packages/webrtc/src/RTCPeer.ts @@ -8,7 +8,8 @@ import { sdpBitrateHack, sdpMediaOrderHack, sdpHasValidCandidates, - updateSDPForOpus, + useAudioCodecs, + sdpStereoHack, } from './utils/sdpHelpers' import { BaseConnection } from './BaseConnection' import { @@ -812,13 +813,15 @@ export default class RTCPeer { } private _setLocalDescription(localDescription: RTCSessionDescriptionInit) { - const { googleMaxBitrate, googleMinBitrate, googleStartBitrate } = - this.options - if (localDescription.sdp) { - localDescription.sdp = updateSDPForOpus( - localDescription.sdp, - this.options - ) + const { + useStereo, + googleMaxBitrate, + googleMinBitrate, + googleStartBitrate, + audioCodecs, + } = this.options + if (localDescription.sdp && useStereo) { + localDescription.sdp = sdpStereoHack(localDescription.sdp) } if ( localDescription.sdp && @@ -833,6 +836,9 @@ export default class RTCPeer { googleStartBitrate ) } + if (localDescription.sdp && audioCodecs) { + localDescription.sdp = useAudioCodecs(localDescription.sdp, audioCodecs) + } // this.logger.debug( // 'LOCAL SDP \n', // `Type: ${localDescription.type}`, @@ -843,11 +849,12 @@ export default class RTCPeer { } private _setRemoteDescription(remoteDescription: RTCSessionDescriptionInit) { - if (remoteDescription.sdp) { - remoteDescription.sdp = updateSDPForOpus( - remoteDescription.sdp, - this.options - ) + const { useStereo, audioCodecs } = this.options + if (remoteDescription.sdp && useStereo) { + remoteDescription.sdp = sdpStereoHack(remoteDescription.sdp) + } + if (remoteDescription.sdp && audioCodecs) { + remoteDescription.sdp = useAudioCodecs(remoteDescription.sdp, audioCodecs) } if (remoteDescription.sdp && this.instance.localDescription) { remoteDescription.sdp = sdpMediaOrderHack( diff --git a/packages/webrtc/src/utils/helpers.test.ts b/packages/webrtc/src/utils/helpers.test.ts index 6d9871626..67f1c826f 100644 --- a/packages/webrtc/src/utils/helpers.test.ts +++ b/packages/webrtc/src/utils/helpers.test.ts @@ -39,30 +39,6 @@ describe('Helpers functions', () => { expect(mediaConstraints.video).toEqual({}) }) - it('should return compatible audio constrains, mono - audio only', async () => { - const mediaConstraints = await getMediaConstraints({audio: true, video: false, opusMaxPlaybackRate: 8000, useStereo: false}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1, "sampleRate": 8000}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return compatible audio constrains, stereo - audio only', async () => { - const mediaConstraints = await getMediaConstraints({audio: true, video: false, opusMaxPlaybackRate: 8000, useStereo: true}) - expect(mediaConstraints.audio).toEqual({"channelCount": 2, "sampleRate": 8000}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return compatible audio constrains, mono - with video', async () => { - const mediaConstraints = await getMediaConstraints({audio: true, video: true, opusMaxPlaybackRate: 8000, useStereo: false}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1, "sampleRate": 8000}) - expect(mediaConstraints.video).toEqual({}) - }) - - it('should return compatible audio constrains, stereo - with video', async () => { - const mediaConstraints = await getMediaConstraints({audio: true, video: true, opusMaxPlaybackRate: 8000, useStereo: true}) - expect(mediaConstraints.audio).toEqual({"channelCount": 2, "sampleRate": 8000}) - expect(mediaConstraints.video).toEqual({}) - }) - }); describe('SDP support audio', () => { diff --git a/packages/webrtc/src/utils/helpers.ts b/packages/webrtc/src/utils/helpers.ts index e3883c86a..94ee17234 100644 --- a/packages/webrtc/src/utils/helpers.ts +++ b/packages/webrtc/src/utils/helpers.ts @@ -50,7 +50,6 @@ export const getMediaConstraints = async ( micId, camLabel = '', camId, - opusMaxPlaybackRate, useStereo, } = options @@ -74,10 +73,6 @@ export const getMediaConstraints = async ( } } - if (opusMaxPlaybackRate && audio) { - audio.sampleRate = opusMaxPlaybackRate - } - if (camId && video) { const newCamId = await assureDeviceId(camId, camLabel, 'camera').catch( (_error) => null diff --git a/packages/webrtc/src/utils/interfaces.ts b/packages/webrtc/src/utils/interfaces.ts index 9d75afeaf..1bd4ff219 100644 --- a/packages/webrtc/src/utils/interfaces.ts +++ b/packages/webrtc/src/utils/interfaces.ts @@ -1,4 +1,4 @@ -import type { PlaybackRate, VideoPositions } from '@signalwire/core' +import type { AudioCodecParams, VideoPositions } from '@signalwire/core' import { BaseConnectionState, VideoRoomDeviceEventParams, @@ -30,6 +30,8 @@ export interface ConnectionOptions { disableUdpIceServers?: boolean /** Audio constraints to use when joining the room. Default: `true`. */ audio?: MediaStreamConstraints['audio'] + /** audio codec with fmtp params */ + audioCodecs?: AudioCodecParams[] /** Video constraints to use when joining the room. Default: `true`. */ video?: MediaStreamConstraints['video'] /** @internal */ @@ -86,10 +88,6 @@ export interface ConnectionOptions { maxIceGatheringTimeout?: number /** @internal */ maxConnectionStateTimeout?: number - /** OPUS audio codec max playback rate in Hz */ - opusMaxPlaybackRate?: PlaybackRate - /** OPUS audio codec max average bitrate in Hz */ - opusMaxAverageBitrate?: number /** @internal */ watchMediaPackets?: boolean /** @internal */ diff --git a/packages/webrtc/src/utils/sdpHelpers.test.ts b/packages/webrtc/src/utils/sdpHelpers.test.ts index 10a010721..06b4d443a 100644 --- a/packages/webrtc/src/utils/sdpHelpers.test.ts +++ b/packages/webrtc/src/utils/sdpHelpers.test.ts @@ -1,5 +1,4 @@ import { - updateSDPForOpus, sdpMediaOrderHack, sdpBitrateHack, sdpRemoveLocalCandidates, @@ -8,7 +7,8 @@ import { getOppositeSdpDirection, sdpHasAudio, sdpHasVideo, - getMaxBitrate, + sdpStereoHack, + useAudioCodecs, } from './sdpHelpers' describe('SDP utility functions', () => { @@ -21,60 +21,49 @@ describe('SDP utility functions', () => { describe('opusConfigsHack', () => { const SDP_OPUS_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=fmtp:111 minptime=10;useinbandfec=1;stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - const SDP_OPUS_STEREO_MAXPLAYBACKRATE = + const SDP_OPUS_STEREO_MAXPLAYBACKRATE = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=4000;stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - const SDP_OPUS_MONO_MAXPLAYBACKRATE = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - - const SDP_OPUS_MAXPLAYBACKRATE = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - const SDP_OPUS_NO_STEREO = + const SDP_G711 = + 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' + + // const SDP_OPUS_MONO_MAXPLAYBACKRATE = + // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' + + // const SDP_OPUS_MAXPLAYBACKRATE = + // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' + const SDP_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_NO_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_INSERTED_OPUS_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=fmtp:111 stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - const SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=4000;stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - const SDP_NO_OPUS_MAXPLAYBACKRATE = - 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - - it('set stereo=1 if a=fmtp is present', () => { - //@ts-expect-error partial options - expect(updateSDPForOpus(SDP_OPUS_NO_STEREO, {useStereo: true})).toEqual(SDP_OPUS_STEREO) + // const SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE = + // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=4000;stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' + // const SDP_NO_OPUS_MAXPLAYBACKRATE = + // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' + + it('set stereo=1 if a=fmtp is present', () => { + expect(sdpStereoHack(SDP_OPUS_NO_STEREO)).toEqual(SDP_OPUS_STEREO) }) it('set stereo=1 if a=fmtp is NOT present', () => { - //@ts-expect-error partial options - const result = updateSDPForOpus(SDP_NO_OPUS_NO_STEREO, {useStereo: true}) + const result = sdpStereoHack(SDP_NO_OPUS_NO_STEREO) expect(result).toEqual(SDP_INSERTED_OPUS_STEREO) }) it('set stereo=1 and maxplaybackrate=8000 maxbitrate=4000 if a=fmtp is present', () => { - //@ts-expect-error partial options - expect(updateSDPForOpus(SDP_OPUS_NO_STEREO, {useStereo: true, opusMaxPlaybackRate: 8000})).toEqual(SDP_OPUS_STEREO_MAXPLAYBACKRATE) - }) - - it('set stereo=1 and maxplaybackrate=8000 maxbitrate=2000 if a=fmtp is present', () => { - //@ts-expect-error partial options - expect(updateSDPForOpus(SDP_OPUS_NO_STEREO, {useStereo: false, opusMaxPlaybackRate: 8000})).toEqual(SDP_OPUS_MONO_MAXPLAYBACKRATE) + let sdp = useAudioCodecs(SDP_OPUS_NO_STEREO, [ + 'opus:maxplaybackrate=8000;maxaveragebitrate=4000', + 'telephone-event:', + ]) + sdp = sdpStereoHack(sdp) + expect(sdp).toEqual(SDP_OPUS_STEREO_MAXPLAYBACKRATE) }) - it('set stereo=1 and maxplaybackrate=8000 if a=fmtp is NOT present', () => { - //@ts-expect-error partial options - const result = updateSDPForOpus(SDP_NO_OPUS_NO_STEREO, {useStereo: true, opusMaxPlaybackRate: 8000}) - expect(result).toEqual(SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE) - }) - - it('set maxplaybackrate=8000 if a=fmtp is present', () => { - //@ts-expect-error partial options - expect(updateSDPForOpus(SDP_OPUS_NO_STEREO, {opusMaxPlaybackRate: 8000})).toEqual(SDP_OPUS_MAXPLAYBACKRATE) - }) - - it('set maxplaybackrate=8000 if a=fmtp is NOT present', () => { - //@ts-expect-error partial options - const result = updateSDPForOpus(SDP_NO_OPUS_NO_STEREO, {opusMaxPlaybackRate: 8000}) - expect(result).toEqual(SDP_NO_OPUS_MAXPLAYBACKRATE) + it('only G711 codec', () => { + let sdp = sdpStereoHack(SDP_OPUS_NO_STEREO) + sdp = useAudioCodecs(sdp, ['PCMU:', 'PCMA:']) + expect(sdp).toEqual(SDP_G711) }) }) @@ -88,7 +77,9 @@ describe('SDP utility functions', () => { const ANSWER_PARSED_REVERTED = 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=setup:active\r\na=sendrecv\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=rtcp-mux\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:109 useinbandfec=0;stereo=1\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=setup:active\r\na=ptime:20\r\na=sendrecv\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\na=rtcp-mux\r\na=silenceSupp:off - - - -\r\n' it('reorder sdp media lines for audio to come first', () => { - expect(sdpMediaOrderHack(ANSWER, OFFER_KO)).toEqual(ANSWER_PARSED_REVERTED) + expect(sdpMediaOrderHack(ANSWER, OFFER_KO)).toEqual( + ANSWER_PARSED_REVERTED + ) }) it('if audio already comes first, do nothing', () => { @@ -199,39 +190,4 @@ describe('SDP utility functions', () => { expect(getOppositeSdpDirection('inactive')).toBe('inactive') }) }) - - describe('getMaxBitrate', () => { - it('should return 2000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: false, opusMaxPlaybackRate: 8000})).toBe(2000) - }) - it('should return 4000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: true, opusMaxPlaybackRate: 8000})).toBe(4000) - }) - it('should return 320000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: false, opusMaxPlaybackRate: 16000})).toBe(32000) - }) - it('should return 640000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: true, opusMaxPlaybackRate: 16000})).toBe(64000) - }) - it('should return 400000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: false, opusMaxPlaybackRate: 24000})).toBe(40000) - }) - it('should return 800000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: true, opusMaxPlaybackRate: 24000})).toBe(80000) - }) - it('should return 640000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: false, opusMaxPlaybackRate: 48000})).toBe(64000) - }) - it('should return 1280000', () => { - //@ts-expect-error partial options - expect(getMaxBitrate({useStereo: true, opusMaxPlaybackRate: 48000})).toBe(128000) - }) -}) }) diff --git a/packages/webrtc/src/utils/sdpHelpers.ts b/packages/webrtc/src/utils/sdpHelpers.ts index 82f77d495..3eee5148b 100644 --- a/packages/webrtc/src/utils/sdpHelpers.ts +++ b/packages/webrtc/src/utils/sdpHelpers.ts @@ -1,20 +1,14 @@ -import { getLogger } from '@signalwire/core' -import { BaseConnectionOptions } from '../BaseConnection' +import { AudioCodecParams, getLogger } from '@signalwire/core' import sdpTransform from 'sdp-transform' -const DEFAULT_MAX_BITRATE = 64000 - const endOfLine = '\r\n' type MediaSectionType = 'audio' | 'video' -const opusPayload = 111 -const dtmfPayload = 110 - const _getMediaSection = ( mutableParsedSDP: sdpTransform.SessionDescription, - type: 'audio' | 'video' -) => mutableParsedSDP.media.find((medisSection) => medisSection.type == type) + type: MediaSectionType +) => mutableParsedSDP.media.find((mediaSection) => mediaSection.type == type) const _stringifyParamMap = (paramMap: sdpTransform.ParamMap) => Object.entries(paramMap) @@ -142,6 +136,26 @@ export const filterAudioCodes = ( }) } +const _mapToCodecPayload = ( + parsedSDP: sdpTransform.SessionDescription, + mediaType: MediaSectionType, + codecs: string[] +) => { + const codecPayloads = codecs.map((codec) => { + const mediaSection = _getMediaSection(parsedSDP, mediaType) + return mediaSection?.rtp.find((rtp) => rtp.codec === codec)?.payload + }) + + const filteredPayloads: number[] = codecPayloads.filter( + (payload) => typeof payload === 'number' + ) + if (filteredPayloads.length !== codecs.length) { + throw new Error('Enable to map all codecs to payload numbers') + } + + return filteredPayloads +} + const _getOrCreatePayloadFmtp = ( mediaSection: sdpTransform.MediaDescription, codecPayload: number @@ -159,7 +173,7 @@ const _getOrCreatePayloadFmtp = ( return codecFmtp } -export const upsertCodecParams = ( +const upsertCodecParams = ( mutableParsedSDP: sdpTransform.SessionDescription, media: MediaSectionType, codecPayload: number, @@ -183,41 +197,56 @@ export const upsertCodecParams = ( fmtp.config = _stringifyParamMap(updatedParams) } -/** - * @returns True if the opus parameters are specified - */ -const shouldOfferOpusOnly = (options: BaseConnectionOptions) => - !!options.opusMaxAverageBitrate || !!options.opusMaxPlaybackRate +export const sdpStereoHack = (sdp: string) => { + const parsedSDP = sdpTransform.parse(sdp) + try { + const opusPayload = _mapToCodecPayload(parsedSDP, 'audio', ['opus'])[0] + upsertCodecParams(parsedSDP, 'audio', opusPayload, { + stereo: '1', + 'sprop-stereo': '1', + }) + + const result = sdpTransform.write(parsedSDP) + + return result + } catch (e) { + console.warn(e) + return sdp + } +} -export const updateSDPForOpus = ( +export const useAudioCodecs = ( sdp: string, - options: BaseConnectionOptions + audioCodecs: AudioCodecParams[] ) => { const parsedSDP = sdpTransform.parse(sdp) - const opusFmtpConfig: sdpTransform.ParamMap = {} + const audioCodecSplitted = audioCodecs.map((audioCodecParam) => + audioCodecParam.split(':') + ) + const audioCodecNames = audioCodecSplitted.map( + (audioCodecParams) => audioCodecParams[0] + ) + const audioCodecPayloads = _mapToCodecPayload( + parsedSDP, + 'audio', + audioCodecNames + ) + const audioCodecParams = audioCodecSplitted.map( + (audioCodecParams) => audioCodecParams[1] + ) - if (shouldOfferOpusOnly(options)) { - filterAudioCodes(parsedSDP, [opusPayload, dtmfPayload]) - if (options.opusMaxPlaybackRate) { - opusFmtpConfig['maxplaybackrate'] = `${options.opusMaxPlaybackRate}` - opusFmtpConfig['maxaveragebitrate'] = `${getMaxBitrate(options)}` - } + filterAudioCodes(parsedSDP, audioCodecPayloads) - if (options.opusMaxAverageBitrate) { - opusFmtpConfig['maxaveragebitrate'] = `${options.opusMaxAverageBitrate}` + audioCodecParams.forEach((params, idx) => { + if (params.length) { + const paramsMap = sdpTransform.parseParams(params) + upsertCodecParams(parsedSDP, 'audio', audioCodecPayloads[idx], paramsMap) } - } - - if (options.useStereo) { - opusFmtpConfig.stereo = '1' - opusFmtpConfig['sprop-stereo'] = '1' - } + }) - if(Object.keys(opusFmtpConfig).length) { - upsertCodecParams(parsedSDP, 'audio', opusPayload, opusFmtpConfig) - } + const result = sdpTransform.write(parsedSDP) - return sdpTransform.write(parsedSDP) + return result } /** @@ -295,29 +324,3 @@ export const hasMatchingSdpDirection = ({ const remoteDirection = getSdpDirection(remoteSdp, media) return remoteDirection === expectedRemoteDirection } - -export const getMaxBitrate = (options: BaseConnectionOptions) => { - if (!options.opusMaxPlaybackRate && !options.useStereo) { - return - } - - let maxBitrate = DEFAULT_MAX_BITRATE - - if (options.opusMaxPlaybackRate && options.opusMaxPlaybackRate <= 8000) { - maxBitrate = !options.useStereo ? 2000 : 4000 - } else if ( - options.opusMaxPlaybackRate && - options.opusMaxPlaybackRate <= 16000 - ) { - maxBitrate = !options.useStereo ? 32000 : 64000 - } else if ( - options.opusMaxPlaybackRate && - options.opusMaxPlaybackRate <= 24000 - ) { - maxBitrate = !options.useStereo ? 40000 : 80000 - } else if (options.useStereo) { - maxBitrate = 128000 - } - - return maxBitrate -} From 035d424a11fc401d609e8132719c93f337bec463 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Tue, 6 May 2025 17:26:26 -0300 Subject: [PATCH 15/37] changeset --- .changeset/cute-zebras-grin.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .changeset/cute-zebras-grin.md diff --git a/.changeset/cute-zebras-grin.md b/.changeset/cute-zebras-grin.md new file mode 100644 index 000000000..7b2c03dec --- /dev/null +++ b/.changeset/cute-zebras-grin.md @@ -0,0 +1,10 @@ +--- +'@signalwire/webrtc': minor +'@signalwire/js': minor +--- + +Added dial params: + +- audioCodecs + +The new parameter allows developers to select the audio codec to use with the desired configuration From dc0c11f2ca91a483a37fc545e487f9e66dc21eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Wed, 7 May 2025 08:44:31 -0300 Subject: [PATCH 16/37] Atualizar o index.html Co-authored-by: Ammar Ansari --- internal/playground-js/src/fabric/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 896312cf3..ff56c5dfd 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -110,7 +110,7 @@
Connect
Maximum Playback Rate Maximum Average Bitrate Date: Wed, 7 May 2025 08:45:38 -0300 Subject: [PATCH 18/37] Atualizar o index.html Co-authored-by: Ammar Ansari --- internal/playground-js/src/fabric/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 0d7af924c..839820606 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -130,6 +130,7 @@
Connect
From 00b65d98b21dde9c5db7178d0918cafbe0433c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Wed, 7 May 2025 08:59:22 -0300 Subject: [PATCH 19/37] Update internal/playground-js/src/fabric/index.html Co-authored-by: Ammar Ansari --- internal/playground-js/src/fabric/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 839820606..eb3bc8aac 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -98,7 +98,7 @@
Connect
- + -
-
- - +
+
+
+
+
+
+
Connect
+
+ + +
+
+ + +
+
+ + +
+
+
Call Options:
+
+ +
-
- - +
+ +
-
-
Call Options:
-
- - +
+
+
+
+ +
-
- - +
+ +
-
-
-
-
- - - - - - -
+
+ +
+
-
- - - - -
+
+ + + + +
-
- Status: Not Connected -
+
+ Status: Not Connected
+
-
-
-
Controls
-
- - -
- -
- - -
- -
- - -
- -
- - -
+
+
+
Controls
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
Layouts
-
- - -
-
- - -
+
+ + +
-
ScreenShare
-
- - -
-
- - -
-
- - -
+
+ +
-
- +
+ +
-
-
-
-
+
Layouts
-
+ + +
+
+ +
-
-
-
- - +
ScreenShare
+
+ +
-
- - +
+ +
-
- - +
+ +
-
-
- - -
-
- - -
-
- - -
+
+
+
+
-
-
Recording (unknown)
-
-
- - - - -
+
+
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
Recording (unknown)
+
+
+ + + +
+
-
-
Playback URL
-
- +
+
Playback URL
+
+ +
+
+
+ + + +
-
-
- - - - -
-
-
Playback Seek
-
-
- -
-
- -
-
- - -
+
+
Playback Seek
+
+
+ +
+
+ +
+
+ +
-
-
- -
+
+ + +
-
- - - +
+
+ + + + \ No newline at end of file From 41817e3aef5f8acddbb4facaaa1c2e4a8fd46447 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 09:22:56 -0300 Subject: [PATCH 21/37] dependencies fix --- package-lock.json | 8 -------- package.json | 1 - 2 files changed, 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9198362a..defd79923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ }, "devDependencies": { "@types/node": "^20.3.2", - "@types/sdp-transform": "^2.4.9", "dotenv": "^16.3.1", "jest-websocket-mock": "^2.5.0", "mock-socket": "^9.3.1", @@ -6548,13 +6547,6 @@ "@types/node": "*" } }, - "node_modules/@types/sdp-transform": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@types/sdp-transform/-/sdp-transform-2.4.9.tgz", - "integrity": "sha512-bVr+/OoZZy7wrHlNcEAAa6PAgKA4BoXPYVN2EijMC5WnGgQ4ZEuixmKnVs2roiAvr7RhIFVH17QD27cojgIZCg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", diff --git a/package.json b/package.json index 076d55d2d..9dd347f16 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ }, "devDependencies": { "@types/node": "^20.3.2", - "@types/sdp-transform": "^2.4.9", "dotenv": "^16.3.1", "jest-websocket-mock": "^2.5.0", "mock-socket": "^9.3.1", From b8704ad1337efab4f8f4812d366ba9cbb2cf25e1 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 11:31:41 -0300 Subject: [PATCH 22/37] build fix --- package-lock.json | 10 ++++++++++ packages/webrtc/package.json | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index defd79923..e2529e34f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6547,6 +6547,13 @@ "@types/node": "*" } }, + "node_modules/@types/sdp-transform": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/sdp-transform/-/sdp-transform-2.4.9.tgz", + "integrity": "sha512-bVr+/OoZZy7wrHlNcEAAa6PAgKA4BoXPYVN2EijMC5WnGgQ4ZEuixmKnVs2roiAvr7RhIFVH17QD27cojgIZCg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -16650,6 +16657,9 @@ "@signalwire/core": "4.2.1", "sdp-transform": "2.15.0" }, + "devDependencies": { + "@types/sdp-transform": "^2.4.9" + }, "engines": { "node": ">=14" } diff --git a/packages/webrtc/package.json b/packages/webrtc/package.json index 8f01d0878..b8dd3ec15 100644 --- a/packages/webrtc/package.json +++ b/packages/webrtc/package.json @@ -40,5 +40,8 @@ "@signalwire/core": "4.2.1", "sdp-transform": "2.15.0" }, - "types": "dist/cjs/webrtc/src/index.d.ts" + "types": "dist/cjs/webrtc/src/index.d.ts", + "devDependencies": { + "@types/sdp-transform": "^2.4.9" + } } From 255f0cfbbdc724547ba1253caba03a9602c57436 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 11:57:56 -0300 Subject: [PATCH 23/37] formating --- internal/playground-js/src/fabric/index.html | 852 ++++++++++++------- 1 file changed, 556 insertions(+), 296 deletions(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 2e4de0895..3fd3e6ec3 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -1,343 +1,603 @@ + + Signalwire Call Demo + + - - Signalwire Call Demo - - + + - - + + + + - - - - - - -
-
-
-

Call Fabric Demo

+ +
+
+
+

Call Fabric Demo

+
-
-
-
-
-
-
-
Connect
-
- - -
-
- - -
-
- - -
-
-
Call Options:
-
- - +
+
+
+
+
+
Connect
+
+ +
-
- - +
+ +
-
-
-
-
- - +
+ + +
+
+
Call Options:
+
+ +
-
- - +
+ +
-
- - +
+
+
+
+ + +
+
+ + +
+
+ + +
-
-
- - - - -
+
+ + + + +
-
- Status: Not Connected +
+ Status: Not Connected +
-
-
-
-
Controls
-
- - -
+
+
+
Controls
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
Layouts
-
- - -
-
- - -
+
Layouts
+
+ + +
+
+ + +
-
ScreenShare
-
- - -
-
- - -
-
- - +
ScreenShare
+
+ + +
+
+ + +
+
+ + +
-
-
- +
+ +
-
-
-
-
-
+
+
+
+
+
-
-
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ + +
-
-
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ + +
-
-
-
Recording (unknown)
-
-
- - - - +
+
Recording (unknown)
+
+
+ + + + +
-
-
-
Playback URL
-
- -
-
-
- - - - +
+
Playback URL
+
+
-
-
Playback Seek
-
-
- -
-
- -
-
- - +
+
+ + + + +
+
+
Playback Seek
+
+
+ +
+
+ +
+
+ + +
-
-
- - +
+ + +
+
-
-
- - - - \ No newline at end of file + + + From 37e545de2255ec02e25e816b2598600a1a9e919e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Wed, 7 May 2025 11:59:42 -0300 Subject: [PATCH 24/37] Update packages/webrtc/src/RTCPeer.ts Co-authored-by: Ammar Ansari --- packages/webrtc/src/RTCPeer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webrtc/src/RTCPeer.ts b/packages/webrtc/src/RTCPeer.ts index 6b6fc575e..bd47f79b5 100644 --- a/packages/webrtc/src/RTCPeer.ts +++ b/packages/webrtc/src/RTCPeer.ts @@ -93,7 +93,7 @@ export default class RTCPeer { if ( this.options.useStereo === true && typeof this.options.audio === 'object' && - (this.options.audio.channelCount ?? 2) != 2 + (this.options.audio.channelCount ?? 2) !== 2 ) { throw new Error('Mismatch params: useStereo, audio.channelCount') } From a514e783bf471036d17bdbea863cb1a1c0b738dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Barbosa=20Marques=20dos=20Santos?= Date: Wed, 7 May 2025 11:59:58 -0300 Subject: [PATCH 25/37] Update packages/js/src/fabric/interfaces/wsClient.ts Co-authored-by: Ammar Ansari --- packages/js/src/fabric/interfaces/wsClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js/src/fabric/interfaces/wsClient.ts b/packages/js/src/fabric/interfaces/wsClient.ts index 5f536fa71..a26479dde 100644 --- a/packages/js/src/fabric/interfaces/wsClient.ts +++ b/packages/js/src/fabric/interfaces/wsClient.ts @@ -110,7 +110,7 @@ export interface CallParams extends DefaultCallParams { stopCameraWhileMuted?: boolean /** Whether to stop the microphone when the member is muted. Default: `true`. */ stopMicrophoneWhileMuted?: boolean - /** audio codec with fmtp params */ + /** Audio codec with fmtp params */ audioCodecs?: AudioCodecParams[] } From 5f99076bb366bf989e32a691a5ff709e733c9572 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 12:19:04 -0300 Subject: [PATCH 26/37] fixes --- packages/core/src/types/utils.ts | 2 +- packages/js/src/fabric/interfaces/wsClient.ts | 8 ++++++-- packages/webrtc/src/utils/helpers.ts | 16 +++++++--------- packages/webrtc/src/utils/interfaces.ts | 4 ++-- packages/webrtc/src/utils/sdpHelpers.ts | 4 ++-- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/core/src/types/utils.ts b/packages/core/src/types/utils.ts index 5662d7bbb..df7c7cb58 100644 --- a/packages/core/src/types/utils.ts +++ b/packages/core/src/types/utils.ts @@ -148,7 +148,7 @@ export type Prettify = NonNullable & { [K in keyof T]: Prettify } & {} -export type AudioCodecParams = +export type AudioCodecOptions = | `opus:${string}` | `red:${string}` | `G722:${string}` diff --git a/packages/js/src/fabric/interfaces/wsClient.ts b/packages/js/src/fabric/interfaces/wsClient.ts index a26479dde..6c9de155f 100644 --- a/packages/js/src/fabric/interfaces/wsClient.ts +++ b/packages/js/src/fabric/interfaces/wsClient.ts @@ -1,4 +1,8 @@ -import { AudioCodecParams, SessionOptions, UserOptions } from '@signalwire/core' +import { + AudioCodecOptions, + SessionOptions, + UserOptions, +} from '@signalwire/core' import { IncomingCallHandlers } from './incomingCallManager' import { FabricRoomSession } from '../FabricRoomSession' @@ -111,7 +115,7 @@ export interface CallParams extends DefaultCallParams { /** Whether to stop the microphone when the member is muted. Default: `true`. */ stopMicrophoneWhileMuted?: boolean /** Audio codec with fmtp params */ - audioCodecs?: AudioCodecParams[] + audioCodecs?: AudioCodecOptions[] } export interface DialParams extends CallParams { diff --git a/packages/webrtc/src/utils/helpers.ts b/packages/webrtc/src/utils/helpers.ts index 1a1ecb8aa..69816ae61 100644 --- a/packages/webrtc/src/utils/helpers.ts +++ b/packages/webrtc/src/utils/helpers.ts @@ -47,18 +47,16 @@ export const getMediaConstraints = async ( let audio = _getAudioConstraints(options) let video = _getVideoConstraints(options) - const { - micLabel = '', - micId, - camLabel = '', - camId, - useStereo, - } = options + const { micLabel = '', micId, camLabel = '', camId, useStereo } = options const channelCount = useStereo ? 2 : 1 - if (typeof audio === 'boolean' && audio) { + if (typeof audio === 'boolean' && audio && useStereo !== undefined) { audio = { channelCount } - } else if (typeof audio === 'object') { + } else if ( + typeof audio === 'object' && + useStereo !== undefined && + !audio.channelCount + ) { audio.channelCount = channelCount } diff --git a/packages/webrtc/src/utils/interfaces.ts b/packages/webrtc/src/utils/interfaces.ts index 1bd4ff219..fc0257cc7 100644 --- a/packages/webrtc/src/utils/interfaces.ts +++ b/packages/webrtc/src/utils/interfaces.ts @@ -1,4 +1,4 @@ -import type { AudioCodecParams, VideoPositions } from '@signalwire/core' +import type { AudioCodecOptions, VideoPositions } from '@signalwire/core' import { BaseConnectionState, VideoRoomDeviceEventParams, @@ -31,7 +31,7 @@ export interface ConnectionOptions { /** Audio constraints to use when joining the room. Default: `true`. */ audio?: MediaStreamConstraints['audio'] /** audio codec with fmtp params */ - audioCodecs?: AudioCodecParams[] + audioCodecs?: AudioCodecOptions[] /** Video constraints to use when joining the room. Default: `true`. */ video?: MediaStreamConstraints['video'] /** @internal */ diff --git a/packages/webrtc/src/utils/sdpHelpers.ts b/packages/webrtc/src/utils/sdpHelpers.ts index 3eee5148b..3e16eb2e2 100644 --- a/packages/webrtc/src/utils/sdpHelpers.ts +++ b/packages/webrtc/src/utils/sdpHelpers.ts @@ -1,4 +1,4 @@ -import { AudioCodecParams, getLogger } from '@signalwire/core' +import { AudioCodecOptions, getLogger } from '@signalwire/core' import sdpTransform from 'sdp-transform' const endOfLine = '\r\n' @@ -217,7 +217,7 @@ export const sdpStereoHack = (sdp: string) => { export const useAudioCodecs = ( sdp: string, - audioCodecs: AudioCodecParams[] + audioCodecs: AudioCodecOptions[] ) => { const parsedSDP = sdpTransform.parse(sdp) const audioCodecSplitted = audioCodecs.map((audioCodecParam) => From 5d5b474c6e4175ce26a68783cfd910e9e64f1c17 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 12:35:17 -0300 Subject: [PATCH 27/37] fix --- packages/webrtc/src/utils/helpers.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/webrtc/src/utils/helpers.ts b/packages/webrtc/src/utils/helpers.ts index 69816ae61..190391c0d 100644 --- a/packages/webrtc/src/utils/helpers.ts +++ b/packages/webrtc/src/utils/helpers.ts @@ -49,10 +49,12 @@ export const getMediaConstraints = async ( const { micLabel = '', micId, camLabel = '', camId, useStereo } = options + if (typeof audio === 'boolean' && audio) { + audio = {} + } + const channelCount = useStereo ? 2 : 1 - if (typeof audio === 'boolean' && audio && useStereo !== undefined) { - audio = { channelCount } - } else if ( + if ( typeof audio === 'object' && useStereo !== undefined && !audio.channelCount From 43d5abe9c0e297f116de42590a35bad1f21afcb3 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 12:38:36 -0300 Subject: [PATCH 28/37] fix test --- packages/webrtc/src/utils/helpers.test.ts | 275 ++++++++++++---------- 1 file changed, 157 insertions(+), 118 deletions(-) diff --git a/packages/webrtc/src/utils/helpers.test.ts b/packages/webrtc/src/utils/helpers.test.ts index 67f1c826f..ba6dea4ad 100644 --- a/packages/webrtc/src/utils/helpers.test.ts +++ b/packages/webrtc/src/utils/helpers.test.ts @@ -1,134 +1,173 @@ import { getMediaConstraints } from '../utils/helpers' jest.mock('../utils/deviceHelpers', () => ({ - assureDeviceId: jest.fn().mockImplementation(async(p:any)=> Promise.resolve(p)) + assureDeviceId: jest + .fn() + .mockImplementation(async (p: any) => Promise.resolve(p)), })) - describe('Helpers functions', () => { - describe('getMediaConstraints', () => { - - describe('No remote SDP', () => { - it('should return audio === false & video === false', async () => { - const mediaConstraints = await getMediaConstraints({audio: false, video: false}) - expect(mediaConstraints.audio).toStrictEqual(false) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return audio === true & video === false', async () => { - const mediaConstraints = await getMediaConstraints({}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return audio === true & video === false', async () => { - const mediaConstraints = await getMediaConstraints({audio: true, video: true}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toEqual({}) - }) - - it('should return audio === {}', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return audio === {}', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}, video: {}}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toEqual({}) - }) - - }); - - describe('SDP support audio', () => { - const SDP = - 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=audio 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' - - it('should return audio === true', async () => { - const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - }) - - it('should return audio === {}', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}, remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - }) - - it('should return audio === {deviceId: { exact: "abcd" }}', async () => { - const mediaConstraints = await getMediaConstraints({micId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }, channelCount: 1}) - }) + describe('getMediaConstraints', () => { + describe('No remote SDP', () => { + it('should return audio === false & video === false', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: false, + video: false, + }) + expect(mediaConstraints.audio).toStrictEqual(false) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return audio === true & video === false', async () => { + const mediaConstraints = await getMediaConstraints({}) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return audio === true & video === false', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: true, + video: true, + }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toEqual({}) + }) + + it('should return audio === {}', async () => { + const mediaConstraints = await getMediaConstraints({ audio: {} }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return audio === {}', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: {}, + video: {}, + }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toEqual({}) + }) + }) + + describe('SDP support audio', () => { + const SDP = + 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=audio 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' + + it('should return audio === true', async () => { + const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + }) + + it('should return audio === {}', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: {}, + remoteSdp: SDP, + }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + }) + + it('should return audio === {deviceId: { exact: "abcd" }}', async () => { + const mediaConstraints = await getMediaConstraints({ + micId: 'abcd', + remoteSdp: SDP, + }) + expect(mediaConstraints.audio).toEqual({ + deviceId: { exact: 'abcd' }, + channelCount: 1, }) + }) + }) - describe('SDP dont support audio', () => { - const SDP = - 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=video 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' - - it('should return audio === true', async () => { - const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(false) - }) - - it('should return audio === {}', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}, remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(false) - }) - - it('should return audio === {deviceId: { exact: "abcd" }}', async () => { - const mediaConstraints = await getMediaConstraints({micId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.audio).toStrictEqual(false) - }) + describe('SDP dont support audio', () => { + const SDP = + 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=video 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' + + it('should return audio === true', async () => { + const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) + expect(mediaConstraints.audio).toStrictEqual(false) + }) + + it('should return audio === {}', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: {}, + remoteSdp: SDP, }) + expect(mediaConstraints.audio).toStrictEqual(false) + }) - describe('SDP dont support video', () => { - const SDP = - 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=audio 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' - - it('should return video === false, case 1', async () => { - const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return video === false , case 2', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}, remoteSdp: SDP}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return audio === video === false , case 3', async () => { - const mediaConstraints = await getMediaConstraints({camId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.video).toStrictEqual(false) + it('should return audio === {deviceId: { exact: "abcd" }}', async () => { + const mediaConstraints = await getMediaConstraints({ + micId: 'abcd', + remoteSdp: SDP, }) + expect(mediaConstraints.audio).toStrictEqual(false) + }) + }) + + describe('SDP dont support video', () => { + const SDP = + 'v=0\r\no=FreeSWITCH 1707233696 1707233697 IN IP4 190.102.98.211\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.211\r\nt=0 0\r\na=msid-semantic: WMS xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\nm=audio 19828 RTP/SAVPF 0 8 102\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:102 opus/48000/2\r\na=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40\r\na=fingerprint:sha-256 0F:F7:47:2D:19:38:46:88:E7:42:2A:4B:53:53:F5:19:1B:DC:EF:8E:14:F7:44:79:ED:94:A7:1B:97:92:7F:C5\r\na=setup:actpass\r\na=rtcp-mux\r\na=rtcp:19828 IN IP4 190.102.98.211\r\na=ssrc:4043346828 cname:rhPWOFid3mVMmndP\r\na=ssrc:4043346828 msid:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo a0\r\na=ssrc:4043346828 mslabel:xXtAEH0vyxeST9BACBkvRkF55amZ0EYo\r\na=ssrc:4043346828 label:xXtAEH0vyxeST9BACBkvRkF55amZ0EYoa0\r\na=ice-ufrag:OnbwxGrtGEix86Mq\r\na=ice-pwd:drdSXmVQzHtLVwrAKsW8Yerv\r\na=candidate:1409144412 1 udp 2130706431 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 1 udp 2130706431 172.17.0.2 19828 typ host generation 0\r\na=candidate:1409144412 2 udp 2130706430 190.102.98.211 19828 typ srflx raddr 172.17.0.2 rport 19828 generation 0\r\na=candidate:7363643456 2 udp 2130706430 172.17.0.2 19828 typ host generation 0\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\n' + + it('should return video === false, case 1', async () => { + const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return video === false , case 2', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: {}, + remoteSdp: SDP, }) + expect(mediaConstraints.video).toStrictEqual(false) + }) - describe('SDP support audio & videos', () => { - const SDP = - 'v=0\r\no=- 8094323291162995063 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS 45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU\r\nm=audio 51609 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 110 112 113 126\r\nc=IN IP4 172.17.0.5\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:528442011 1 udp 2122260223 192.168.1.12 52783 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:3788879375 1 tcp 1518280447 192.168.1.12 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:511643837 1 udp 1686052607 37.118.148.114 52783 typ srflx raddr 192.168.1.12 rport 52783 generation 0 network-id 1 network-cost 10\r\na=candidate:427329035 1 udp 25108479 172.17.0.5 51609 typ relay raddr 172.17.0.6 rport 49152 generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:Yoii\r\na=ice-pwd:uMmennPss4DGhOvNYiKxQT7w\r\na=ice-options:trickle\r\na=fingerprint:sha-256 C4:62:01:34:2C:20:32:37:00:BE:DD:40:E7:03:DA:0E:57:A0:EB:30:DD:BD:98:20:11:3B:1C:00:FD:A6:3D:37\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 29e5d7e5-de01-4058-b202-929b7e454469\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red/48000/2\r\na=fmtp:63 111/111\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:335962309 cname:7wjKGH97nM78eMmS\r\na=ssrc:335962309 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 29e5d7e5-de01-4058-b202-929b7e454469\r\nm=video 52560 UDP/TLS/RTP/SAVPF 96 97 102 122 127 121 125 107 108 109 124 120 39 40 45 46 98 99 100 101 123 119 114 115 116\r\nc=IN IP4 172.17.0.5\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:528442011 1 udp 2122260223 192.168.1.12 52673 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:3788879375 1 tcp 1518280447 192.168.1.12 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:511643837 1 udp 1686052607 37.118.148.114 52673 typ srflx raddr 192.168.1.12 rport 52673 generation 0 network-id 1 network-cost 10\r\na=candidate:427329035 1 udp 25108479 172.17.0.5 52560 typ relay raddr 172.17.0.6 rport 49154 generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:Yoii\r\na=ice-pwd:uMmennPss4DGhOvNYiKxQT7w\r\na=ice-options:trickle\r\na=fingerprint:sha-256 C4:62:01:34:2C:20:32:37:00:BE:DD:40:E7:03:DA:0E:57:A0:EB:30:DD:BD:98:20:11:3B:1C:00:FD:A6:3D:37\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:39 H264/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=rtpmap:46 rtx/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:123 H264/90000\r\na=rtcp-fb:123 goog-remb\r\na=rtcp-fb:123 transport-cc\r\na=rtcp-fb:123 ccm fir\r\na=rtcp-fb:123 nack\r\na=rtcp-fb:123 nack pli\r\na=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 red/90000\r\na=rtpmap:115 rtx/90000\r\na=fmtp:115 apt=114\r\na=rtpmap:116 ulpfec/90000\r\na=ssrc-group:FID 3973975883 3471156669\r\na=ssrc:3973975883 cname:7wjKGH97nM78eMmS\r\na=ssrc:3973975883 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\na=ssrc:3471156669 cname:7wjKGH97nM78eMmS\r\na=ssrc:3471156669 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\n' - - it('should return audio === true & video === false', async () => { - const mediaConstraints = await getMediaConstraints({remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toStrictEqual(false) - }) - - it('should return audio === true & video === true', async () => { - const mediaConstraints = await getMediaConstraints({video: true, remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toEqual({}) - }) - - it('should return audio === {} & video === {}', async () => { - const mediaConstraints = await getMediaConstraints({audio: {}, video: {}, remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({"channelCount": 1}) - expect(mediaConstraints.video).toEqual({}) - }) - - it('should return audio === {deviceId: { exact: "abcd" }} & video === {deviceId: { exact: "abcd" }}' , async () => { - const mediaConstraints = await getMediaConstraints({micId: 'abcd', camId: 'abcd', remoteSdp: SDP}) - expect(mediaConstraints.audio).toEqual({deviceId: { exact: "abcd" }, channelCount: 1}) - expect(mediaConstraints.video).toEqual({deviceId: { exact: "abcd" }}) - }) + it('should return audio === video === false , case 3', async () => { + const mediaConstraints = await getMediaConstraints({ + camId: 'abcd', + remoteSdp: SDP, }) + expect(mediaConstraints.video).toStrictEqual(false) + }) }) -}) \ No newline at end of file + describe('SDP support audio & videos', () => { + const SDP = + 'v=0\r\no=- 8094323291162995063 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS 45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU\r\nm=audio 51609 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 110 112 113 126\r\nc=IN IP4 172.17.0.5\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:528442011 1 udp 2122260223 192.168.1.12 52783 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:3788879375 1 tcp 1518280447 192.168.1.12 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:511643837 1 udp 1686052607 37.118.148.114 52783 typ srflx raddr 192.168.1.12 rport 52783 generation 0 network-id 1 network-cost 10\r\na=candidate:427329035 1 udp 25108479 172.17.0.5 51609 typ relay raddr 172.17.0.6 rport 49152 generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:Yoii\r\na=ice-pwd:uMmennPss4DGhOvNYiKxQT7w\r\na=ice-options:trickle\r\na=fingerprint:sha-256 C4:62:01:34:2C:20:32:37:00:BE:DD:40:E7:03:DA:0E:57:A0:EB:30:DD:BD:98:20:11:3B:1C:00:FD:A6:3D:37\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 29e5d7e5-de01-4058-b202-929b7e454469\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red/48000/2\r\na=fmtp:63 111/111\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:335962309 cname:7wjKGH97nM78eMmS\r\na=ssrc:335962309 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 29e5d7e5-de01-4058-b202-929b7e454469\r\nm=video 52560 UDP/TLS/RTP/SAVPF 96 97 102 122 127 121 125 107 108 109 124 120 39 40 45 46 98 99 100 101 123 119 114 115 116\r\nc=IN IP4 172.17.0.5\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:528442011 1 udp 2122260223 192.168.1.12 52673 typ host generation 0 network-id 1 network-cost 10\r\na=candidate:3788879375 1 tcp 1518280447 192.168.1.12 9 typ host tcptype active generation 0 network-id 1 network-cost 10\r\na=candidate:511643837 1 udp 1686052607 37.118.148.114 52673 typ srflx raddr 192.168.1.12 rport 52673 generation 0 network-id 1 network-cost 10\r\na=candidate:427329035 1 udp 25108479 172.17.0.5 52560 typ relay raddr 172.17.0.6 rport 49154 generation 0 network-id 1 network-cost 10\r\na=ice-ufrag:Yoii\r\na=ice-pwd:uMmennPss4DGhOvNYiKxQT7w\r\na=ice-options:trickle\r\na=fingerprint:sha-256 C4:62:01:34:2C:20:32:37:00:BE:DD:40:E7:03:DA:0E:57:A0:EB:30:DD:BD:98:20:11:3B:1C:00:FD:A6:3D:37\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:39 H264/90000\r\na=rtcp-fb:39 goog-remb\r\na=rtcp-fb:39 transport-cc\r\na=rtcp-fb:39 ccm fir\r\na=rtcp-fb:39 nack\r\na=rtcp-fb:39 nack pli\r\na=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:40 rtx/90000\r\na=fmtp:40 apt=39\r\na=rtpmap:45 AV1/90000\r\na=rtcp-fb:45 goog-remb\r\na=rtcp-fb:45 transport-cc\r\na=rtcp-fb:45 ccm fir\r\na=rtcp-fb:45 nack\r\na=rtcp-fb:45 nack pli\r\na=rtpmap:46 rtx/90000\r\na=fmtp:46 apt=45\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:123 H264/90000\r\na=rtcp-fb:123 goog-remb\r\na=rtcp-fb:123 transport-cc\r\na=rtcp-fb:123 ccm fir\r\na=rtcp-fb:123 nack\r\na=rtcp-fb:123 nack pli\r\na=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 red/90000\r\na=rtpmap:115 rtx/90000\r\na=fmtp:115 apt=114\r\na=rtpmap:116 ulpfec/90000\r\na=ssrc-group:FID 3973975883 3471156669\r\na=ssrc:3973975883 cname:7wjKGH97nM78eMmS\r\na=ssrc:3973975883 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\na=ssrc:3471156669 cname:7wjKGH97nM78eMmS\r\na=ssrc:3471156669 msid:45Xh7kvyxccAi1fP6gpacCd2XY5IPfmp9zkU 95f5bd7e-f301-4349-aa8d-c493812cd7b0\r\n' + + it('should return audio === true & video === false', async () => { + const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toStrictEqual(false) + }) + + it('should return audio === true & video === true', async () => { + const mediaConstraints = await getMediaConstraints({ + video: true, + remoteSdp: SDP, + }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toEqual({}) + }) + + it('should return audio === {} & video === {}', async () => { + const mediaConstraints = await getMediaConstraints({ + audio: {}, + video: {}, + remoteSdp: SDP, + }) + expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.video).toEqual({}) + }) + + it('should return audio === {deviceId: { exact: "abcd" }} & video === {deviceId: { exact: "abcd" }}', async () => { + const mediaConstraints = await getMediaConstraints({ + micId: 'abcd', + camId: 'abcd', + remoteSdp: SDP, + }) + expect(mediaConstraints.audio).toEqual({ deviceId: { exact: 'abcd' } }) + expect(mediaConstraints.video).toEqual({ deviceId: { exact: 'abcd' } }) + }) + }) + }) +}) From eb67f3388d592197d7ba2b7eed468b7603564adc Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 12:46:45 -0300 Subject: [PATCH 29/37] test fix --- packages/webrtc/src/utils/helpers.test.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/webrtc/src/utils/helpers.test.ts b/packages/webrtc/src/utils/helpers.test.ts index ba6dea4ad..0a17d8a64 100644 --- a/packages/webrtc/src/utils/helpers.test.ts +++ b/packages/webrtc/src/utils/helpers.test.ts @@ -20,7 +20,7 @@ describe('Helpers functions', () => { it('should return audio === true & video === false', async () => { const mediaConstraints = await getMediaConstraints({}) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toStrictEqual(false) }) @@ -29,13 +29,13 @@ describe('Helpers functions', () => { audio: true, video: true, }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toEqual({}) }) it('should return audio === {}', async () => { const mediaConstraints = await getMediaConstraints({ audio: {} }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toStrictEqual(false) }) @@ -44,7 +44,7 @@ describe('Helpers functions', () => { audio: {}, video: {}, }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toEqual({}) }) }) @@ -55,7 +55,7 @@ describe('Helpers functions', () => { it('should return audio === true', async () => { const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) }) it('should return audio === {}', async () => { @@ -63,7 +63,7 @@ describe('Helpers functions', () => { audio: {}, remoteSdp: SDP, }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) }) it('should return audio === {deviceId: { exact: "abcd" }}', async () => { @@ -72,8 +72,7 @@ describe('Helpers functions', () => { remoteSdp: SDP, }) expect(mediaConstraints.audio).toEqual({ - deviceId: { exact: 'abcd' }, - channelCount: 1, + deviceId: { exact: 'abcd' } }) }) }) @@ -136,7 +135,7 @@ describe('Helpers functions', () => { it('should return audio === true & video === false', async () => { const mediaConstraints = await getMediaConstraints({ remoteSdp: SDP }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toStrictEqual(false) }) @@ -145,7 +144,7 @@ describe('Helpers functions', () => { video: true, remoteSdp: SDP, }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toEqual({}) }) @@ -155,7 +154,7 @@ describe('Helpers functions', () => { video: {}, remoteSdp: SDP, }) - expect(mediaConstraints.audio).toEqual({ channelCount: 1 }) + expect(mediaConstraints.audio).toEqual({}) expect(mediaConstraints.video).toEqual({}) }) From b54aa5aff5385d5d86bf4ccc51cb988b0cbabf2b Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Wed, 7 May 2025 15:07:23 -0300 Subject: [PATCH 30/37] fix sdpMediaOrderHack --- packages/webrtc/src/utils/sdpHelpers.test.ts | 38 +++++++++++++++----- packages/webrtc/src/utils/sdpHelpers.ts | 17 +++++++-- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/packages/webrtc/src/utils/sdpHelpers.test.ts b/packages/webrtc/src/utils/sdpHelpers.test.ts index 06b4d443a..c02817726 100644 --- a/packages/webrtc/src/utils/sdpHelpers.test.ts +++ b/packages/webrtc/src/utils/sdpHelpers.test.ts @@ -26,21 +26,12 @@ describe('SDP utility functions', () => { const SDP_G711 = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - // const SDP_OPUS_MONO_MAXPLAYBACKRATE = - // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - - // const SDP_OPUS_MAXPLAYBACKRATE = - // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 minptime=10;useinbandfec=1;maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' const SDP_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_NO_OPUS_NO_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=ice-options:trickle\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:102 H264/90000\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:122 rtx/90000\r\na=fmtp:122 apt=102\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:114 ulpfec/90000\r\na=ssrc-group:FID 1714381393 967654061\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\n' const SDP_INSERTED_OPUS_STEREO = 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=fmtp:111 stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - // const SDP_NO_OPUS_STEREO_MAXPLAYBACKRATE = - // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=4000;stereo=1;sprop-stereo=1\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' - // const SDP_NO_OPUS_MAXPLAYBACKRATE = - // 'v=0\r\no=- 135160591336882782 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS 381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=group:BUNDLE audio video\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 110\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:111 opus/48000/2\r\na=rtpmap:110 telephone-event/48000\r\na=fmtp:111 maxplaybackrate=8000;maxaveragebitrate=2000\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:111 transport-cc\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=setup:actpass\r\na=mid:audio\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:3652058873 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:3652058873 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 8841cbb1-90ba-4655-8784-60a185846706\r\na=ssrc:3652058873 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:3652058873 label:8841cbb1-90ba-4655-8784-60a185846706\r\na=rtcp-mux\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114\r\nc=IN IP4 0.0.0.0\r\na=rtpmap:96 VP8/90000\r\na=rtpmap:97 rtx/90000\r\na=rtpmap:98 VP9/90000\r\na=rtpmap:99 rtx/90000\r\na=rtpmap:100 H264/90000\r\na=rtpmap:101 rtx/90000\r\na=rtpmap:102 H264/90000\r\na=rtpmap:122 rtx/90000\r\na=rtpmap:127 H264/90000\r\na=rtpmap:121 rtx/90000\r\na=rtpmap:125 H264/90000\r\na=rtpmap:107 rtx/90000\r\na=rtpmap:108 H264/90000\r\na=rtpmap:109 rtx/90000\r\na=rtpmap:124 H264/90000\r\na=rtpmap:120 rtx/90000\r\na=rtpmap:123 red/90000\r\na=rtpmap:119 rtx/90000\r\na=rtpmap:114 ulpfec/90000\r\na=fmtp:97 apt=96\r\na=fmtp:98 profile-id=0\r\na=fmtp:99 apt=98\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=fmtp:101 apt=100\r\na=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=fmtp:122 apt=102\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=fmtp:121 apt=127\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=fmtp:107 apt=125\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032\r\na=fmtp:109 apt=108\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032\r\na=fmtp:120 apt=124\r\na=fmtp:119 apt=123\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:102 goog-remb\r\na=rtcp-fb:102 transport-cc\r\na=rtcp-fb:102 ccm fir\r\na=rtcp-fb:102 nack\r\na=rtcp-fb:102 nack pli\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\na=setup:actpass\r\na=mid:video\r\na=sendrecv\r\na=ice-ufrag:Y5Zy\r\na=ice-pwd:yQLVrXgG+irP0tgLLr4ZjQb5\r\na=fingerprint:sha-256 45:ED:86:FB:EB:FE:21:20:62:C4:07:81:AA:B8:BC:87:60:CC:2B:54:CE:D5:F0:16:93:C4:61:23:28:59:DF:8B\r\na=ice-options:trickle\r\na=ssrc:1714381393 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:1714381393 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:1714381393 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:1714381393 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 cname:kufSZ8JnlRUuQVc2\r\na=ssrc:967654061 msid:381b9efc-7cf5-45bb-8f39-c06558b288de 99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc:967654061 mslabel:381b9efc-7cf5-45bb-8f39-c06558b288de\r\na=ssrc:967654061 label:99d2faa8-950d-40f7-ad80-16789c9b4faa\r\na=ssrc-group:FID 1714381393 967654061\r\na=rtcp-mux\r\na=rtcp-rsize\r\n' it('set stereo=1 if a=fmtp is present', () => { expect(sdpStereoHack(SDP_OPUS_NO_STEREO)).toEqual(SDP_OPUS_STEREO) @@ -72,8 +63,17 @@ describe('SDP utility functions', () => { 'v=0\r\no=mozilla...THIS_IS_SDPARTA-65.0 4664580510618001282 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 37:18:D1:6A:F4:B6:DB:00:A0:48:4B:EC:CC:F3:E1:AF:DC:DB:DA:2C:E2:C0:6B:36:92:02:84:04:60:B5:EB:70\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=audio 60578 UDP/TLS/RTP/SAVPF 109 9 0 8 101\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 60578 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 56425 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:0\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {d3bf3e75-0c87-f849-a967-6ec743afd59b}\r\na=rtcp:56425 IN IP4 192.168.1.4\r\na=rtcp-mux\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:9 G722/8000/1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\na=setup:actpass\r\na=ssrc:3703202793 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\nm=video 55993 UDP/TLS/RTP/SAVPF 120 121 126 97\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 55993 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 54949 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:5 urn:ietf:params:rtp-hdrext:toffset\r\na=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1\r\na=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=fmtp:121 max-fs=12288;max-fr=60\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:1\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {77747bff-84dd-124b-8f35-3d84e89cd9fe}\r\na=rtcp:54949 IN IP4 192.168.1.4\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 goog-remb\r\na=rtcp-fb:121 nack\r\na=rtcp-fb:121 nack pli\r\na=rtcp-fb:121 ccm fir\r\na=rtcp-fb:121 goog-remb\r\na=rtcp-fb:126 nack\r\na=rtcp-fb:126 nack pli\r\na=rtcp-fb:126 ccm fir\r\na=rtcp-fb:126 goog-remb\r\na=rtcp-fb:97 nack\r\na=rtcp-fb:97 nack pli\r\na=rtcp-fb:97 ccm fir\r\na=rtcp-fb:97 goog-remb\r\na=rtcp-mux\r\na=rtpmap:120 VP8/90000\r\na=rtpmap:121 VP9/90000\r\na=rtpmap:126 H264/90000\r\na=rtpmap:97 H264/90000\r\na=setup:actpass\r\na=ssrc:3672465901 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\n' const OFFER_KO = 'v=0\r\no=mozilla...THIS_IS_SDPARTA-65.0 4664580510618001282 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 37:18:D1:6A:F4:B6:DB:00:A0:48:4B:EC:CC:F3:E1:AF:DC:DB:DA:2C:E2:C0:6B:36:92:02:84:04:60:B5:EB:70\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=video 55993 UDP/TLS/RTP/SAVPF 120 121 126 97\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 55993 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 54949 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:4 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:5 urn:ietf:params:rtp-hdrext:toffset\r\na=fmtp:126 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1\r\na=fmtp:97 profile-level-id=42e01f;level-asymmetry-allowed=1\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=fmtp:121 max-fs=12288;max-fr=60\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:1\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {77747bff-84dd-124b-8f35-3d84e89cd9fe}\r\na=rtcp:54949 IN IP4 192.168.1.4\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 goog-remb\r\na=rtcp-fb:121 nack\r\na=rtcp-fb:121 nack pli\r\na=rtcp-fb:121 ccm fir\r\na=rtcp-fb:121 goog-remb\r\na=rtcp-fb:126 nack\r\na=rtcp-fb:126 nack pli\r\na=rtcp-fb:126 ccm fir\r\na=rtcp-fb:126 goog-remb\r\na=rtcp-fb:97 nack\r\na=rtcp-fb:97 nack pli\r\na=rtcp-fb:97 ccm fir\r\na=rtcp-fb:97 goog-remb\r\na=rtcp-mux\r\na=rtpmap:120 VP8/90000\r\na=rtpmap:121 VP9/90000\r\na=rtpmap:126 H264/90000\r\na=rtpmap:97 H264/90000\r\na=setup:actpass\r\na=ssrc:3672465901 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\nm=audio 60578 UDP/TLS/RTP/SAVPF 109 9 0 8 101\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 60578 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 56425 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:0\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {d3bf3e75-0c87-f849-a967-6ec743afd59b}\r\na=rtcp:56425 IN IP4 192.168.1.4\r\na=rtcp-mux\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:9 G722/8000/1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\na=setup:actpass\r\na=ssrc:3703202793 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\n' + const OFFER_NO_VIDEO = + 'v=0\r\no=mozilla...THIS_IS_SDPARTA-65.0 4664580510618001282 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 37:18:D1:6A:F4:B6:DB:00:A0:48:4B:EC:CC:F3:E1:AF:DC:DB:DA:2C:E2:C0:6B:36:92:02:84:04:60:B5:EB:70\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\nm=audio 60578 UDP/TLS/RTP/SAVPF 109 9 0 8 101\r\nc=IN IP4 192.168.1.4\r\na=candidate:0 1 UDP 2122252543 192.168.1.4 60578 typ host\r\na=candidate:1 1 TCP 2105524479 192.168.1.4 9 typ host tcptype active\r\na=candidate:0 2 UDP 2122252542 192.168.1.4 56425 typ host\r\na=candidate:1 2 TCP 2105524478 192.168.1.4 9 typ host tcptype active\r\na=sendrecv\r\na=end-of-candidates\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level\r\na=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1\r\na=fmtp:101 0-15\r\na=ice-pwd:37573269874225f2b9ee22d8fc483281\r\na=ice-ufrag:e762c9de\r\na=mid:0\r\na=msid:{8de043d7-7ff5-5c46-8822-e0d9ffd96e73} {d3bf3e75-0c87-f849-a967-6ec743afd59b}\r\na=rtcp:56425 IN IP4 192.168.1.4\r\na=rtcp-mux\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:9 G722/8000/1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:101 telephone-event/8000\r\na=setup:actpass\r\na=ssrc:3703202793 cname:{05f7b618-2088-4048-9d8a-37e95f7fd8b6}\r\n' + + const OFFER_NO_MEDIA = + 'v=0\r\no=mozilla...THIS_IS_SDPARTA-65.0 4664580510618001282 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=sendrecv\r\na=fingerprint:sha-256 37:18:D1:6A:F4:B6:DB:00:A0:48:4B:EC:CC:F3:E1:AF:DC:DB:DA:2C:E2:C0:6B:36:92:02:84:04:60:B5:EB:70\r\na=group:BUNDLE 0 1\r\na=ice-options:trickle\r\na=msid-semantic:WMS *\r\n' + const ANSWER = 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=fmtp:109 useinbandfec=0;stereo=1\r\na=rtpmap:101 telephone-event/8000\r\na=silenceSupp:off - - - -\r\na=ptime:20\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=sendrecv\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=setup:active\r\na=rtcp-mux\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\n' + const ANSWER_NO_MEDIA = + 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\n' + const ANSWER_PARSED_REVERTED = 'v=0\r\no=FreeSWITCH 1548927489 1548927490 IN IP4 190.102.98.65\r\ns=FreeSWITCH\r\nc=IN IP4 190.102.98.65\r\nt=0 0\r\na=msid-semantic: WMS 2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\nm=video 32174 UDP/TLS/RTP/SAVPF 120\r\nb=AS:5120\r\na=rtpmap:120 VP8/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\na=rtcp:32174 IN IP4 190.102.98.65\r\na=rtcp-fb:120 ccm fir\r\na=rtcp-fb:120 nack\r\na=rtcp-fb:120 nack pli\r\na=setup:active\r\na=sendrecv\r\na=ice-ufrag:a18QY1pFCOxw1p3M\r\na=ice-pwd:jbKGpwsMOR8bsqKsiI96zoB2\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=candidate:4637747447 1 udp 659136 190.102.98.65 32174 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:2587074312 cname:3rydmInNWVddlW4C\r\na=ssrc:2587074312 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 v0\r\na=ssrc:2587074312 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:2587074312 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6v0\r\na=rtcp-mux\r\nm=audio 21632 UDP/TLS/RTP/SAVPF 109 101\r\na=rtpmap:109 opus/48000/2\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:109 useinbandfec=0;stereo=1\r\na=rtcp:21632 IN IP4 190.102.98.65\r\na=setup:active\r\na=ptime:20\r\na=sendrecv\r\na=ice-ufrag:1NDpJtrAbZCfeHb7\r\na=ice-pwd:Zzab7nPT9SXkERNvvhK5B2wC\r\na=fingerprint:sha-256 2D:89:4F:82:44:AC:3C:CB:B3:63:AC:17:11:49:4E:11:1A:7D:70:2D:18:51:00:76:03:E1:82:72:92:3F:20:5B\r\na=candidate:7330097990 1 udp 659136 190.102.98.65 21632 typ host generation 0\r\na=end-of-candidates\r\na=ssrc:3361527577 cname:3rydmInNWVddlW4C\r\na=ssrc:3361527577 msid:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6 a0\r\na=ssrc:3361527577 mslabel:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6\r\na=ssrc:3361527577 label:2OlCk4kjBnIzrzS1reSby6Zc0RIbdof6a0\r\na=rtcp-mux\r\na=silenceSupp:off - - - -\r\n' it('reorder sdp media lines for audio to come first', () => { @@ -85,6 +85,26 @@ describe('SDP utility functions', () => { it('if audio already comes first, do nothing', () => { expect(sdpMediaOrderHack(ANSWER, OFFER_OK)).toEqual(ANSWER) }) + + it('if offer has no video section, do nothing', () => { + expect(sdpMediaOrderHack(ANSWER, OFFER_NO_VIDEO)).toEqual(ANSWER) + }) + + it('if offer has no media section, do nothing', () => { + expect(sdpMediaOrderHack(ANSWER, OFFER_NO_MEDIA)).toEqual(ANSWER) + }) + + it('if answer has no media section, do nothing', () => { + expect(sdpMediaOrderHack(ANSWER_NO_MEDIA, OFFER_OK)).toEqual( + ANSWER_NO_MEDIA + ) + }) + + it('if both have no media section, do nothing', () => { + expect(sdpMediaOrderHack(ANSWER_NO_MEDIA, OFFER_NO_MEDIA)).toEqual( + ANSWER_NO_MEDIA + ) + }) }) describe('sdpBitrateHack', () => { diff --git a/packages/webrtc/src/utils/sdpHelpers.ts b/packages/webrtc/src/utils/sdpHelpers.ts index 3e16eb2e2..8826b26ba 100644 --- a/packages/webrtc/src/utils/sdpHelpers.ts +++ b/packages/webrtc/src/utils/sdpHelpers.ts @@ -44,11 +44,24 @@ export const sdpMediaOrderHack = ( const parsedOffer = sdpTransform.parse(localOffer) const parsedAnswer = sdpTransform.parse(answer) - if (parsedOffer.media[0].type === parsedAnswer.media[0].type) { + if ( + parsedOffer.media.length == 1 || + parsedOffer.media?.[0]?.type === parsedAnswer.media?.[0]?.type || + parsedOffer.media?.[0]?.type === 'audio' || + !(Boolean(parsedOffer.media?.length) && Boolean(parsedAnswer.media?.length)) + ) { return answer } - parsedAnswer.media.reverse() + const answerMediaIndex = parsedAnswer.media.findIndex( + (mediaSession) => mediaSession.type === parsedOffer.media[0].type + ) + if (answerMediaIndex !== -1) { + ;[parsedAnswer.media[0], parsedAnswer.media[answerMediaIndex]] = [ + parsedAnswer.media[answerMediaIndex], + parsedAnswer.media[0], + ] + } return sdpTransform.write(parsedAnswer) } From 4d4945223398d331db2728d86af158bd173fcce8 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Thu, 8 May 2025 12:20:58 -0300 Subject: [PATCH 31/37] don't change the remote description --- packages/webrtc/src/RTCPeer.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/webrtc/src/RTCPeer.ts b/packages/webrtc/src/RTCPeer.ts index bd47f79b5..01b0be1ec 100644 --- a/packages/webrtc/src/RTCPeer.ts +++ b/packages/webrtc/src/RTCPeer.ts @@ -868,9 +868,6 @@ export default class RTCPeer { if (remoteDescription.sdp && useStereo) { remoteDescription.sdp = sdpStereoHack(remoteDescription.sdp) } - if (remoteDescription.sdp && audioCodecs) { - remoteDescription.sdp = useAudioCodecs(remoteDescription.sdp, audioCodecs) - } if (remoteDescription.sdp && this.instance.localDescription) { remoteDescription.sdp = sdpMediaOrderHack( remoteDescription.sdp, From 7e5704c8e2566c2674533e6296d1ce726e722c3f Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Mon, 26 May 2025 10:43:00 -0300 Subject: [PATCH 32/37] cleanup --- packages/webrtc/src/RTCPeer.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/webrtc/src/RTCPeer.ts b/packages/webrtc/src/RTCPeer.ts index 01b0be1ec..5444e5f83 100644 --- a/packages/webrtc/src/RTCPeer.ts +++ b/packages/webrtc/src/RTCPeer.ts @@ -854,17 +854,11 @@ export default class RTCPeer { if (localDescription.sdp && audioCodecs) { localDescription.sdp = useAudioCodecs(localDescription.sdp, audioCodecs) } - // this.logger.debug( - // 'LOCAL SDP \n', - // `Type: ${localDescription.type}`, - // '\n\n', - // localDescription.sdp - // ) return this.instance.setLocalDescription(localDescription) } private _setRemoteDescription(remoteDescription: RTCSessionDescriptionInit) { - const { useStereo, audioCodecs } = this.options + const { useStereo } = this.options if (remoteDescription.sdp && useStereo) { remoteDescription.sdp = sdpStereoHack(remoteDescription.sdp) } From 9e7335b245eeae9a41e542b01eafcfa85d323792 Mon Sep 17 00:00:00 2001 From: Joao Santos Date: Mon, 26 May 2025 11:20:36 -0300 Subject: [PATCH 33/37] Update audio codec selection and input handling in the demo --- internal/playground-js/src/fabric/index.html | 44 ++++---------------- internal/playground-js/src/fabric/index.js | 16 ++----- 2 files changed, 10 insertions(+), 50 deletions(-) diff --git a/internal/playground-js/src/fabric/index.html b/internal/playground-js/src/fabric/index.html index 3fd3e6ec3..fef8793d9 100644 --- a/internal/playground-js/src/fabric/index.html +++ b/internal/playground-js/src/fabric/index.html @@ -98,44 +98,14 @@
Connect
- - -
-
- - -
-
- - Audio Codec Override +