[Pion/WebRTC][TypeScript] Use specific video codec

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.

[Pion/WebRTC] Try reading Offer messages

So in this time, I …


This content originally appeared on DEV Community and was authored by Masui Masanori

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
...


This content originally appeared on DEV Community and was authored by Masui Masanori


Print Share Comment Cite Upload Translate Updates
APA

Masui Masanori | Sciencx (2023-05-17T16:46:57+00:00) [Pion/WebRTC][TypeScript] Use specific video codec. Retrieved from https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/

MLA
" » [Pion/WebRTC][TypeScript] Use specific video codec." Masui Masanori | Sciencx - Wednesday May 17, 2023, https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/
HARVARD
Masui Masanori | Sciencx Wednesday May 17, 2023 » [Pion/WebRTC][TypeScript] Use specific video codec., viewed ,<https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/>
VANCOUVER
Masui Masanori | Sciencx - » [Pion/WebRTC][TypeScript] Use specific video codec. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/
CHICAGO
" » [Pion/WebRTC][TypeScript] Use specific video codec." Masui Masanori | Sciencx - Accessed . https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/
IEEE
" » [Pion/WebRTC][TypeScript] Use specific video codec." Masui Masanori | Sciencx [Online]. Available: https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/. [Accessed: ]
rf:citation
» [Pion/WebRTC][TypeScript] Use specific video codec | Masui Masanori | Sciencx | https://www.scien.cx/2023/05/17/pion-webrtctypescript-use-specific-video-codec/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.