Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codec renegotiation #620

Open
alexlapa opened this issue Feb 3, 2025 · 5 comments
Open

Codec renegotiation #620

alexlapa opened this issue Feb 3, 2025 · 5 comments

Comments

@alexlapa
Copy link
Collaborator

alexlapa commented Feb 3, 2025

So right now str0m cannot change negotiated codec for a media line. Meaning that in the following example final assert will panic cause str0m wont't change mline from VP9 to VP8.

// ... m=video 9 UDP/TLS/RTP/SAVPF 98 100 ... a=mid:0 ... a=rtpmap:98 VP9/90000 ...
let vp9_offer = "v=0\r\no=- 6493822680788534460 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=video 9 UDP/TLS/RTP/SAVPF 98 100\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:E4FP\r\na=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL\r\na=ice-options:trickle\r\na=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 urn:3gpp:video-orientation\r\na=extmap:4 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:9 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:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\na=rtcp-mux\r\na=rtcp-rsize\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: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=ssrc:2680304743 cname:V7daxyexo/O3/inf\r\na=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\n";

// ... m=video 51931 UDP/TLS/RTP/SAVPF 96 ... a=mid:0 ... a=rtpmap:96 VP8/90000 ...
let vp8_offer = "v=0\r\no=- 6493822680788534460 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=video 51931 UDP/TLS/RTP/SAVPF 96\r\nc=IN IP4 192.168.10.196\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:2509241872 1 udp 2122260223 192.168.10.196 51931 typ host generation 0 network-id 1\r\na=ice-ufrag:E4FP\r\na=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL\r\na=ice-options:trickle\r\na=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 urn:3gpp:video-orientation\r\na=extmap:4 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:9 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:- 892ae9b4-6545-4edf-9187-1fd342e71486\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=ssrc:2680304743 cname:V7daxyexo/O3/inf\r\na=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\n";

let vp9_answer = rtc
    .sdp_api()
    .accept_offer(SdpOffer::from_sdp_string(vp9_offer).unwrap())
    .unwrap();

let vp8_answer = rtc
    .sdp_api()
    .accept_offer(SdpOffer::from_sdp_string(vp8_offer).unwrap())
    .unwrap();

assert!(vp9_answer != vp8_answer);

Renegotiating used codecs is perfectly fine and works via web API, i.e. this js snippet:

let pc = new RTCPeerConnection();
await pc.setRemoteDescription({ type: "offer", sdp: "v=0\r\no=- 6493822680788534460 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=video 9 UDP/TLS/RTP/SAVPF 98 100\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:E4FP\r\na=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL\r\na=ice-options:trickle\r\na=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 urn:3gpp:video-orientation\r\na=extmap:4 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:9 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:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\na=rtcp-mux\r\na=rtcp-rsize\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: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=ssrc:2680304743 cname:V7daxyexo/O3/inf\r\na=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\n" });
let vp9_answer = (await pc.createAnswer()).sdp;

await pc.setRemoteDescription({ type: "offer", sdp: "v=0\r\no=- 6493822680788534460 3 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=video 51931 UDP/TLS/RTP/SAVPF 96\r\nc=IN IP4 192.168.10.196\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=candidate:2509241872 1 udp 2122260223 192.168.10.196 51931 typ host generation 0 network-id 1\r\na=ice-ufrag:E4FP\r\na=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL\r\na=ice-options:trickle\r\na=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 urn:3gpp:video-orientation\r\na=extmap:4 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:9 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:- 892ae9b4-6545-4edf-9187-1fd342e71486\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=ssrc:2680304743 cname:V7daxyexo/O3/inf\r\na=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486\r\n" });
let vp8_answer = (await pc.createAnswer()).sdp;
console.log(vp8_answer.includes("VP9")); // returns false
console.log(vp9_answer.includes("VP8")); // returns false
console.log(vp9_answer.includes("VP9")); // returns true
console.log(vp8_answer.includes("VP8")); // returns true

So is this a bug or working as intended? Do you want this changed? I need to be able to change used codecs, but Im not sure whether to implement this in str0m or just remove old media lines and add new ones.

@algesten
Copy link
Owner

algesten commented Feb 3, 2025

Formatting the offers to understand the problem:

v=0
o=- 6493822680788534460 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS
m=video 9 UDP/TLS/RTP/SAVPF 98 100
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:E4FP
a=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL
a=ice-options:trickle
a=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 urn:3gpp:video-orientation
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:- 892ae9b4-6545-4edf-9187-1fd342e71486
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=ssrc:2680304743 cname:V7daxyexo/O3/inf
a=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486
v=0
o=- 6493822680788534460 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS
m=video 51931 UDP/TLS/RTP/SAVPF 96
c=IN IP4 192.168.10.196
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:2509241872 1 udp 2122260223 192.168.10.196 51931 typ host generation 0 network-id 1
a=ice-ufrag:E4FP
a=ice-pwd:v329FXqQhBQmzlbnO8XeQhSL
a=ice-options:trickle
a=fingerprint:sha-256 D4:EA:D1:85:D2:AB:0F:25:08:AA:6D:65:0A:1D:E1:2A:22:2F:AD:9D:3E:B0:BA:25:20:83:40:E2:D9:F6:AC:94
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 urn:3gpp:video-orientation
a=extmap:4 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:- 892ae9b4-6545-4edf-9187-1fd342e71486
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=ssrc:2680304743 cname:V7daxyexo/O3/inf
a=ssrc:2680304743 msid:- 892ae9b4-6545-4edf-9187-1fd342e71486

@algesten
Copy link
Owner

algesten commented Feb 3, 2025

@alexlapa is this really "renegotiation"?

If I recall correctly, the SDP is not actually committed to the RTCPeerConnection until you set it via setLocalDescription. I believe if you do, this example might fail. AFAIK the number of values you can change after a complete negotiation are very limited, something like a=sendrecv and maybe something else.

let pc = new RTCPeerConnection();

await pc.setRemoteDescription({});
let vp9_answer = (await pc.createAnswer()).sdp;
pc.setLocalDescription(vp9_answer); // missing this?!

await pc.setRemoteDescription({ ... });
let vp8_answer = (await pc.createAnswer()).sdp;
pc.setLocalDescription(vp8_answer); // missing this?!

@alexlapa
Copy link
Collaborator Author

alexlapa commented Feb 3, 2025

@algesten ,

Well thats a simplified example. Here is full if you want to try it yourself:

let pc1 = new RTCPeerConnection();
let pc2 = new RTCPeerConnection();
let track = (await navigator.mediaDevices.getUserMedia({video:true})).getTracks()[0];

let tr = pc1.addTransceiver(track);

pc1.onicecandidate = event => {
	if (event.candidate) {
	    pc2.addIceCandidate(event.candidate);
	}
};
pc2.onicecandidate = event => {
	if (event.candidate) {
	    pc1.addIceCandidate(event.candidate);
	}
};

tr.setCodecPreferences(RTCRtpSender.getCapabilities("video").codecs.filter(codec => codec.mimeType === "video/VP9"));

await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);

await new Promise(resolve => setTimeout(resolve, 5000));

tr.setCodecPreferences(RTCRtpSender.getCapabilities("video").codecs.filter(codec => codec.mimeType === "video/VP8"));

await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);

Or this snippet right here https://webrtc.github.io/samples/src/content/peerconnection/pc1/:

pc1.getTransceivers()[1].setCodecPreferences(RTCRtpSender.getCapabilities("video").codecs.filter(codec => codec.mimeType === "video/H264"));

await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);

It will work like this:

Screencast.from.2025-02-03.15-42-34.webm

Notice codec changes in webrtc-internals after renegotiation.

@xnorpx
Copy link
Collaborator

xnorpx commented Feb 3, 2025

I am curious why you need to renegotiate codecs?

@algesten
Copy link
Owner

algesten commented Feb 3, 2025

@alexlapa interesting! ok. today i learn. thanks!

I'd like to think of the SDP/session state as something that is incrementally added to. It's like a delicate stack of cards, where we can't change around the foundations.

Inside str0m fixing this could be a bit messy. I'm not sure the upheaval would be worth it.

The most important renegotiation is to support changing send/recv/sendrecv/inactive – which I believe we handle correctly already.

I don't know whether this is a particularly important use case. Though, I'm happy to be convinced/proven otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants