Intro
At least in my environment, "VP8" is used as the default video codec for WebRTC.
But according to the SDP what I read last time, other codecs should be available as well.
So in this time, I will try using specific video codec.
Because the video codec used by WebRTC is determined by the SDP of both the Offer and Answer, I will try server-side(Offer) and client-side(Answer)/
Sample
[Client-side] Remove other video codecs from Offer SDP
To force using specific video codec, I can remove other codecs from Offer SDP.
videoCodecRemover.ts
import { hasAnyTexts } from "../hasAnyTexts";
/** Remove video codecs from SDP except specified ones */
export function removeVideoCodec(orgsdp: string, leaveMimeType: string): string {
if(!hasAnyTexts(leaveMimeType)) {
return orgsdp;
}
const codecs = RTCRtpSender.getCapabilities("video")?.codecs;
if(codecs == null) {
return orgsdp;
}
let modsdp = orgsdp;
for(const c of codecs) {
if(c.mimeType === leaveMimeType) {
continue;
}
modsdp = internalRemoveVideoCodec(modsdp, c.mimeType);
}
return modsdp;
}
/** Remove target MIME Type from SDP */
function internalRemoveVideoCodec(sdp: string, removeMimeType: string): string {
const videoCodec = removeMimeType.replace("video/", "");
const codecre = new RegExp('(a=rtpmap:(\\d*) ' + videoCodec + '/90000\\r\\n)');
const rtpmaps = sdp.match(codecre);
if (rtpmaps == null || rtpmaps.length <= 2) {
return sdp;
}
const rtpmap = rtpmaps[2];
let modsdp = sdp.replace(codecre, "");
modsdp = modsdp.replace(new RegExp('(a=rtcp-fb:' + rtpmap + '.*\r\n)', 'g'), "");
modsdp = modsdp.replace(new RegExp('(a=fmtp:' + rtpmap + '.*\r\n)', 'g'), "");
const aptpre = new RegExp('(a=fmtp:(\\d*) apt=' + rtpmap + '\\r\\n)');
const aptmaps = modsdp.match(aptpre);
let fmtpmap = "";
if (aptmaps != null && aptmaps.length >= 3) {
fmtpmap = aptmaps[2] ?? "";
modsdp = modsdp.replace(aptpre, "");
// remove video codecs by the "fmtpmap" value.
modsdp = modsdp.replace(new RegExp('(a=rtpmap:' + fmtpmap + '.*\r\n)', 'g'), "");
modsdp = modsdp.replace(new RegExp('(a=rtcp-fb:' + fmtpmap + '.*\r\n)', 'g'), "");
}
const videore = /(m=video.*\r\n)/;
const videolines = modsdp.match(videore);
if (videolines != null) {
//If many m=video are found in SDP, this program doesn't work.
const videoline = videolines[0].substring(0, videolines[0].length - 2);
const videoelem = videoline.split(" ");
let modvideoline = videoelem[0] ?? "";
for (let i = 1; i < videoelem.length; i++) {
if (videoelem[i] == rtpmap || videoelem[i] == fmtpmap) {
continue;
}
modvideoline += " " + videoelem[i];
}
modvideoline += "\r\n";
modsdp = modsdp.replace(videore, modvideoline);
}
return internalRemoveVideoCodec(modsdp, removeMimeType);
}
main.page.ts
...
function handleReceivedMessage(value: string) {
const message = JSON.parse(value);
if(!checkIsClientMessage(message)) {
console.error(`Invalid message type ${value}`);
return;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let offerData: any;
let preferredMimeType: string|null = null;
switch(message.event) {
...
case "offer":
offerData = JSON.parse(message.data);
if(view.getForceVideoCodec()) {
// 1. SDP, 2. MIME Type
offerData.sdp = removeVideoCodec(offerData.sdp, view.getPreferredVideoCodec());
} else {
...
}
if(webrtc.handleOffer(offerData, preferredMimeType) !== true) {
close();
}
break;
...
}
}
...
Before
...
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 121 127 120 125 107 108 109 123 118 116
c=IN IP4 0.0.0.0
a=setup:actpass
a=mid:0
a=ice-ufrag:qTksQATCTrhvEAcY
a=ice-pwd:dGLtcbyrUNKsdYxHDEjVuYgwUWdMqqkN
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 transport-cc
a=rtpmap:98 VP9/90000
a=fmtp:98 profile-id=0
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 transport-cc
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 transport-cc
a=rtpmap:100 VP9/90000
a=fmtp:100 profile-id=1
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 transport-cc
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 transport-cc
a=rtpmap:102 H264/90000
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 transport-cc
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 transport-cc
a=rtpmap:127 H264/90000
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 transport-cc
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=127
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 transport-cc
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 transport-cc
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtcp-fb:107 nack
a=rtcp-fb:107 nack pli
a=rtcp-fb:107 transport-cc
a=rtpmap:108 H264/90000
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 transport-cc
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtcp-fb:109 nack
a=rtcp-fb:109 nack pli
a=rtcp-fb:109 transport-cc
a=rtpmap:123 H264/90000
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 transport-cc
a=rtpmap:118 rtx/90000
a=fmtp:118 apt=123
a=rtcp-fb:118 nack
a=rtcp-fb:118 nack pli
a=rtcp-fb:118 transport-cc
a=rtpmap:116 ulpfec/90000
a=rtcp-fb:116 nack
a=rtcp-fb:116 nack pli
a=rtcp-fb:116 transport-cc
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=recvonly
...
After
...
m=video 9 UDP/TLS/RTP/SAVPF 102 127 125 108 123
c=IN IP4 0.0.0.0
a=setup:actpass
a=mid:0
a=ice-ufrag:qTksQATCTrhvEAcY
a=ice-pwd:dGLtcbyrUNKsdYxHDEjVuYgwUWdMqqkN
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:102 H264/90000
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 transport-cc
a=rtpmap:127 H264/90000
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 transport-cc
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 transport-cc
a=rtpmap:108 H264/90000
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 transport-cc
a=rtpmap:123 H264/90000
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 transport-cc
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=recvonly
...
This method works, but has problems.
If another client is already connected with a different video codec, the connection will fail.
[Client-side] setCodecPreferences
Because ghe priority of the video codecs used matches the order of description in SDP, I sort them by "setCodePreferences"
preferVideoCodec.ts
import { hasAnyTexts } from "ts/hasAnyTexts";
/** Prefer Specified Video Codec */
export function preferVideoCodec(codecs: RTCRtpCodecCapability[], mimeType: string): RTCRtpCodecCapability[] {
// skip sorting video codecs if the mimeType is empty.
if(!hasAnyTexts(mimeType)) {
return codecs;
}
const otherCodecs: RTCRtpCodecCapability[] = [];
const sortedCodecs: RTCRtpCodecCapability[] = [];
codecs.forEach((codec) => {
if (codec.mimeType === mimeType) {
sortedCodecs.push(codec);
} else {
otherCodecs.push(codec);
}
});
return sortedCodecs.concat(otherCodecs);
}
webrtc.controller.ts
...
public handleOffer(data: RTCSessionDescription | null | undefined, preferredMimeType: string|null): boolean {
...
this.peerConnection.setRemoteDescription(data);
// prefer specific video codec before calling createAnswer
if(hasAnyTexts(preferredMimeType)) {
this.peerConnection.getTransceivers()
.forEach((transceiver) => {
const kind = transceiver.sender.track?.kind;
if(kind == null) {
return;
}
if (kind === "video") {
let codecs = RTCRtpSender.getCapabilities(kind)?.codecs;
if(codecs == null) {
return;
}
codecs = preferVideoCodec(codecs, preferredMimeType);
transceiver.setCodecPreferences([...codecs, ...codecs]);
}
});
}
this.peerConnection.createAnswer()
.then(answer => {
if (this.peerConnection != null) {
this.peerConnection.setLocalDescription(answer);
}
if (this.answerSentEvent != null) {
this.answerSentEvent(answer);
}
});
return true;
}
...
After(Answer SDP, I select H264)
...
m=video 60274 UDP/TLS/RTP/SAVPF 102 121 127 120 125 107 108 109 123 118 96 97 98 99 116
c=IN IP4 60.46.180.81
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:4106528496 1 udp 2122260223 192.168.86.22 60274 typ host generation 0 network-id 1 network-cost 10
a=candidate:801605297 1 udp 1686052607 60.46.180.81 60274 typ srflx raddr 192.168.86.22 rport 60274 generation 0 network-id 1 network-cost 10
a=candidate:2321187837 1 tcp 1518280447 192.168.86.22 9 typ host tcptype active generation 0 network-id 1 network-cost 10
a=ice-ufrag:1jxi
a=ice-pwd:6y/munHjivGnsDyd+lTRNimE
a=ice-options:trickle
a=fingerprint:sha-256 BB:4B:E6:D0:EE:59:B3:1D:1C:F1:50:59:C6:4E:C7:92:57:94:AF:46:D9:42:1E:6D:5C:EE:CB:69:3D:72:AE:02
a=setup:active
a=mid:0
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:67076c8b-0491-43fc-b940-66433c9e00bd c98ca17c-7198-495a-90e3-d122c57be656
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 transport-cc
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:121 rtx/90000
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 transport-cc
a=fmtp:121 apt=102
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 transport-cc
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:120 rtx/90000
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 transport-cc
a=fmtp:120 apt=127
a=rtpmap:125 H264/90000
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 transport-cc
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=rtcp-fb:107 nack
a=rtcp-fb:107 nack pli
a=rtcp-fb:107 transport-cc
a=fmtp:107 apt=125
a=rtpmap:108 H264/90000
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 transport-cc
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:109 rtx/90000
a=rtcp-fb:109 nack
a=rtcp-fb:109 nack pli
a=rtcp-fb:109 transport-cc
a=fmtp:109 apt=108
a=rtpmap:123 H264/90000
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 transport-cc
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:118 rtx/90000
a=rtcp-fb:118 nack
a=rtcp-fb:118 nack pli
a=rtcp-fb:118 transport-cc
a=fmtp:118 apt=123
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=rtpmap:97 rtx/90000
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 transport-cc
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 transport-cc
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 transport-cc
a=fmtp:99 apt=98
a=rtpmap:116 ulpfec/90000
a=rtcp-fb:116 nack
a=rtcp-fb:116 nack pli
a=rtcp-fb:116 transport-cc
a=ssrc-group:FID 1751253213 3231317468
a=ssrc:1751253213 cname:TI63w5WXK1xmxz8A
a=ssrc:1751253213 msid:67076c8b-0491-43fc-b940-66433c9e00bd c98ca17c-7198-495a-90e3-d122c57be656
a=ssrc:3231317468 cname:TI63w5WXK1xmxz8A
a=ssrc:3231317468 msid:67076c8b-0491-43fc-b940-66433c9e00bd c98ca17c-7198-495a-90e3-d122c57be656
...
[Server-side] setCodecPreferences
Pion/WebRTC also has "setCodecPreferences".
So I can sort video codecs for Offer SDP as same as the client-side.
peerConnectionState.go
...
func NewPeerConnection() (*webrtc.PeerConnection, error) {
peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{
"stun:stun.l.google.com:19302",
},
},
},
})
if err != nil {
return nil, err
}
for _, typ := range []webrtc.RTPCodecType{webrtc.RTPCodecTypeVideo, webrtc.RTPCodecTypeAudio} {
if _, err := peerConnection.AddTransceiverFromKind(typ, webrtc.RTPTransceiverInit{
Direction: webrtc.RTPTransceiverDirectionRecvonly,
}); err != nil {
return nil, err
}
}
for _, trn := range peerConnection.GetTransceivers() {
if trn.Kind() == webrtc.RTPCodecTypeVideo {
// prefer "H264" for example
preferVideoCodec(trn, "video/H264")
}
}
return peerConnection, nil
}
...
func preferVideoCodec(trn *webrtc.RTPTransceiver, mimeType string) {
originalCodecs := trn.Receiver().GetParameters().Codecs
sortedCodecs := make([]webrtc.RTPCodecParameters, len(originalCodecs))
index := 0
for _, codec := range originalCodecs {
if codec.MimeType == mimeType {
sortedCodecs[index] = codec
index += 1
}
}
for _, codec := range originalCodecs {
if codec.MimeType != mimeType {
sortedCodecs[index] = codec
index += 1
}
}
trn.SetCodecPreferences(sortedCodecs)
}
After(Offer SDP)
...
m=video 9 UDP/TLS/RTP/SAVPF 102 127 125 108 123 96 97 98 99 100 101 121 120 107 109 118 116
c=IN IP4 0.0.0.0
a=setup:actpass
a=mid:0
a=ice-ufrag:psvRzwNhTPFgjkEt
a=ice-pwd:VdywVCOKklKxZknlYRpLusBpjaTxOneN
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:102 H264/90000
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=rtcp-fb:102 transport-cc
a=rtpmap:127 H264/90000
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 transport-cc
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 transport-cc
a=rtpmap:108 H264/90000
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=rtcp-fb:108 transport-cc
a=rtpmap:123 H264/90000
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 transport-cc
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtcp-fb:97 nack
a=rtcp-fb:97 nack pli
a=rtcp-fb:97 transport-cc
a=rtpmap:98 VP9/90000
a=fmtp:98 profile-id=0
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 transport-cc
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 transport-cc
a=rtpmap:100 VP9/90000
a=fmtp:100 profile-id=1
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 transport-cc
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 transport-cc
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
a=rtcp-fb:121 nack
a=rtcp-fb:121 nack pli
a=rtcp-fb:121 transport-cc
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=127
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=rtcp-fb:120 transport-cc
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtcp-fb:107 nack
a=rtcp-fb:107 nack pli
a=rtcp-fb:107 transport-cc
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtcp-fb:109 nack
a=rtcp-fb:109 nack pli
a=rtcp-fb:109 transport-cc
a=rtpmap:118 rtx/90000
a=fmtp:118 apt=123
a=rtcp-fb:118 nack
a=rtcp-fb:118 nack pli
a=rtcp-fb:118 transport-cc
a=rtpmap:116 ulpfec/90000
a=rtcp-fb:116 nack
a=rtcp-fb:116 nack pli
a=rtcp-fb:116 transport-cc
a=extmap:1 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=recvonly
...
Top comments (0)