Pratinjau Developer:
Tersedia sebagai bagian dari Program Pratinjau Developer Google Workspace , yang memberikan akses awal ke fitur tertentu.
Untuk menggunakan Meet Media API guna mengakses media real-time dari konferensi, project Google Cloud, akun utama OAuth, dan semua peserta dalam konferensi harus terdaftar dalam Program Pratinjau Developer.
Google Meet Media API memungkinkan aplikasi Anda bergabung ke
konferensi Google Meet dan menggunakan streaming media real-time.
Klien menggunakan WebRTC untuk berkomunikasi dengan server Meet. Klien referensi yang disediakan (C++ ,
TypeScript ) menunjukkan praktik yang direkomendasikan dan
Anda dianjurkan untuk membuat aplikasi langsung berdasarkan klien tersebut.
Namun, Anda juga dapat membuat klien WebRTC yang sepenuhnya kustom dan mematuhi
persyaratan teknis
Meet Media API .
Halaman ini menguraikan konsep WebRTC utama yang diperlukan untuk sesi Meet Media API yang berhasil.
Sinyal penawaran-jawaban
WebRTC adalah framework peer-to-peer (P2P), tempat peer berkomunikasi dengan saling memberi sinyal. Untuk memulai sesi, peer yang memulai mengirimkan penawaran
SDP ke peer jarak jauh. Penawaran ini mencakup detail penting berikut:
Deskripsi media menunjukkan apa yang dikomunikasikan selama sesi P2P. Ada tiga jenis deskripsi: audio, video, dan data.
Untuk menunjukkan n streaming audio, penawar menyertakan n deskripsi media audio dalam penawaran. Hal yang sama berlaku untuk video. Namun, hanya akan ada satu deskripsi media data .
Arah
Setiap deskripsi audio atau video menjelaskan streaming Secure Real-time Transport
Protocol (SRTP) individual, yang diatur oleh RFC
3711 . Deskripsi ini bersifat dua arah, sehingga memungkinkan dua peer mengirim dan menerima media melalui koneksi yang sama.
Oleh karena itu, setiap deskripsi media (dalam penawaran dan jawaban) berisi salah satu dari tiga atribut yang menjelaskan cara streaming harus digunakan:
sendonly : Hanya mengirim media dari peer penawaran. Peer jarak jauh tidak akan mengirim media di streaming ini.
recvonly : Hanya menerima media dari peer jarak jauh. Peer penawaran tidak akan mengirim media di streaming ini.
sendrecv : Kedua peer dapat mengirim dan menerima di streaming ini.
Codec
Setiap deskripsi media juga menentukan codec yang didukung peer. Dalam kasus
Meet Media API, penawaran klien akan ditolak kecuali jika mendukung
(setidaknya) codec yang ditentukan dalam persyaratan
teknis .
Handshake DTLS
Streaming SRTP diamankan oleh handshake awal
Datagram Transport Layer Security ("DTLS", RFC
9147 ) antara peer.
DTLS secara tradisional adalah protokol klien-ke-server; selama proses sinyal, satu peer setuju untuk bertindak sebagai server, sedangkan peer lainnya bertindak sebagai peer.
Karena setiap streaming SRTP mungkin memiliki koneksi DTLS khusus, setiap deskripsi media menentukan salah satu dari tiga atribut untuk menunjukkan peran peer dalam handshake DTLS:
a=setup:actpass : Peer penawaran akan mengikuti pilihan peer jarak jauh.
a=setup:active : Peer ini bertindak sebagai klien.
a=setup:passive : Peer ini bertindak sebagai server.
Channel data (RFC 8831 ) adalah
abstraksi dari Stream Control Transmission Protocol ("SCTP", RFC
9260 ).
Untuk membuka channel data selama fase sinyal awal, penawaran harus berisi deskripsi media aplikasi . Tidak seperti deskripsi audio dan video, deskripsi aplikasi tidak menentukan arah atau codec.
Kandidat ICE
Kandidat Interactive Connectivity Establishment ("ICE", RFC
8445 ) peer adalah daftar
rute yang dapat digunakan peer jarak jauh untuk membuat koneksi.
Produk kartesius dari daftar dua peer, yang dikenal sebagai pasangan kandidat ,
mewakili rute potensial antara dua peer. Pasangan ini diuji untuk menentukan rute yang optimal.
Sinyal melalui Meet REST API
Gunakan Meet REST API untuk melakukan sinyal
penawaran-jawaban ini. Aplikasi Anda memberikan penawaran
SDP ke metode
connectActiveConference()
dan menerima jawaban
SDP sebagai balasannya.
Contoh kode berikut menunjukkan cara memanggil metode:
Contoh alur koneksi
Berikut adalah penawaran dengan deskripsi media audio:
Gambar 1. Contoh penawaran dengan deskripsi media audio.
Peer jarak jauh merespons dengan jawaban
SDP yang berisi jumlah
baris deskripsi media yang sama. Setiap baris menunjukkan media apa, jika ada, yang dikirim kembali oleh peer jarak jauh ke klien penawaran di seluruh streaming SRTP. Peer jarak jauh juga dapat menolak streaming tertentu dari penawar dengan menetapkan entri deskripsi media tersebut ke recvonly.
Untuk Meet Media API, klien selalu mengirim penawaran SDP untuk memulai koneksi. Meet tidak pernah menjadi inisiator.
Perilaku ini dikelola secara internal oleh klien referensi
(C++ , TypeScript ),
tetapi developer klien kustom dapat menggunakan PeerConnectionInterface WebRTC untuk
membuat penawaran.
Untuk terhubung ke Meet, penawaran harus mematuhi persyaratan tertentu
requirements :
Klien harus selalu bertindak sebagai klien dalam handshake DTLS, sehingga setiap deskripsi media dalam penawaran harus menentukan a=setup:actpass atau a=setup:active.
Setiap baris deskripsi media harus mendukung semua codec
yang diperlukan untuk jenis media
tersebut:
Audio: Opus
Video: VP8, VP9, AV1
Untuk menerima audio, penawaran harus menyertakan tepat 3 deskripsi media audio hanya terima. Anda dapat melakukannya dengan menetapkan transceiver pada objek koneksi peer.
C++
// ...
rtc :: scoped_refptr<webrtc :: PeerConnectionInterface > peer_connection ;
for ( int i = 0 ; i < 3 ; ++ i ) {
webrtc :: RtpTransceiverInit audio_init ;
audio_init . direction = webrtc :: RtpTransceiverDirection :: kRecvOnly ;
audio_init . stream_ids = { absl :: StrCat ( "audio_stream_" , i )};
webrtc :: RTCErrorOr<rtc :: scoped_refptr<webrtc :: RtpTransceiverInterface >>
audio_result = peer_connection - >AddTransceiver (
cricket :: MediaType :: MEDIA_TYPE_AUDIO , audio_init );
if ( ! audio_result . ok ()) {
return absl :: InternalError ( absl :: StrCat ( "Failed to add audio transceiver: " ,
audio_result . error (). message ()));
}
}
JavaScript
pc = new RTCPeerConnection ();
// Configure client to receive audio from Meet servers.
pc . addTransceiver ( 'audio' , { 'direction' : 'recvonly' });
pc . addTransceiver ( 'audio' , { 'direction' : 'recvonly' });
pc . addTransceiver ( 'audio' , { 'direction' : 'recvonly' });
Untuk menerima video, penawaran harus menyertakan 1–3 deskripsi media video hanya terima. Anda dapat melakukannya dengan menetapkan transceiver pada objek koneksi peer.
C++
// ...
rtc :: scoped_refptr<webrtc :: PeerConnectionInterface > peer_connection ;
for ( uint32_t i = 0 ; i < configurations . receiving_video_stream_count ; ++ i ) {
webrtc :: RtpTransceiverInit video_init ;
video_init . direction = webrtc :: RtpTransceiverDirection :: kRecvOnly ;
video_init . stream_ids = { absl :: StrCat ( "video_stream_" , i )};
webrtc :: RTCErrorOr<rtc :: scoped_refptr<webrtc :: RtpTransceiverInterface >>
video_result = peer_connection - >AddTransceiver (
cricket :: MediaType :: MEDIA_TYPE_VIDEO , video_init );
if ( ! video_result . ok ()) {
return absl :: InternalError ( absl :: StrCat ( "Failed to add video transceiver: " ,
video_result . error (). message ()));
}
}
JavaScript
pc = new RTCPeerConnection ();
// Configure client to receive video from Meet servers.
pc . addTransceiver ( 'video' , { 'direction' : 'recvonly' });
pc . addTransceiver ( 'video' , { 'direction' : 'recvonly' });
pc . addTransceiver ( 'video' , { 'direction' : 'recvonly' });
Penawaran harus selalu menyertakan channel data. Minimal, channel session-control dan media-stats harus selalu terbuka. Semua channel data harus ordered.
C++
// ...
// All data channels must be ordered.
constexpr webrtc :: DataChannelInit kDataChannelConfig = {. ordered = true };
rtc :: scoped_refptr<webrtc :: PeerConnectionInterface > peer_connection ;
// Signal session-control data channel.
webrtc :: RTCErrorOr<rtc :: scoped_refptr<webrtc :: DataChannelInterface >>
session_create_result = peer_connection - >CreateDataChannelOrError (
"session-control" , &kDataChannelConfig );
if ( ! session_create_result . ok ()) {
return absl :: InternalError ( absl :: StrCat ( "Failed to create data channel " ,
data_channel_label , ": " ,
session_create_result . error (). message ()));
}
// Signal media-stats data channel.
webrtc :: RTCErrorOr<rtc :: scoped_refptr<webrtc :: DataChannelInterface >>
stats_create_result = peer_connection - >CreateDataChannelOrError (
"media-stats" , &kDataChannelConfig );
if ( ! stats_create_result . ok ()) {
return absl :: InternalError ( absl :: StrCat ( "Failed to create data channel " ,
data_channel_label , ": " ,
stats_create_result . error (). message ()));
}
JavaScript
// ...
pc = new RTCPeerConnection ();
// All data channels must be ordered.
const dataChannelConfig = {
ordered : true ,
};
// Signal session-control data channel.
sessionControlChannel = pc . createDataChannel ( 'session-control' , dataChannelConfig );
sessionControlChannel . onopen = () = > console . log ( "data channel is now open" );
sessionControlChannel . onclose = () = > console . log ( "data channel is now closed" );
sessionControlChannel . onmessage = async ( e ) = > {
console . log ( "data channel message" , e . data );
};
// Signal media-stats data channel.
mediaStatsChannel = pc . createDataChannel ( 'media-stats' , dataChannelConfig );
mediaStatsChannel . onopen = () = > console . log ( "data channel is now open" );
mediaStatsChannel . onclose = () = > console . log ( "data channel is now closed" );
mediaStatsChannel . onmessage = async ( e ) = > {
console . log ( "data channel message" , e . data );
};
Contoh penawaran dan jawaban SDP
Berikut adalah contoh lengkap penawaran SDP yang valid dan jawaban SDP yang cocok. Penawaran ini menegosiasikan sesi Meet Media API dengan audio dan satu streaming video.
Perhatikan bahwa ada tiga deskripsi media audio, satu deskripsi media video, dan deskripsi media aplikasi yang diperlukan.
Catatan: Bagian dipisahkan ke dalam baris agar lebih mudah dilihat.
Penawaran SDP klien
Jawaban SDP Meet Media API
v=0
o=- 1479484780199836840 3 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1 2 3 4
a=extmap-allow-mixed
a=msid-semantic: WMS
v=0
o=- 0 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1 2 3 4
a=msid-semantic: WMS virtual-6666 virtual-video-7777/7777
a=ice-lite
m=audio 59905 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
c=IN IP4 136.55.18.35
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:3490152339 1 udp 2113937151 46ae665f-23fd-49df-a002-6d12bc897a54.local 59905 typ host generation 0 network-cost 999
a=candidate:1937170525 1 udp 2113939711 aa575ae6-68fc-4155-83c1-007a1f5e8e55.local 58304 typ host generation 0 network-cost 999
a=candidate:2999458021 1 udp 1677732095 2605:a601:55ab:b000:615a:2317:bf6b:7a30 58304 typ srflx raddr :: rport 0 generation 0 network-cost 999
a=candidate:2517543359 1 udp 1677729535 136.55.18.35 59905 typ srflx raddr 0.0.0.0 rport 0 generation 0 network-cost 999
a=ice-ufrag:0HPF
a=ice-pwd:GcBv48eO/q64iPxb7MHKS87y
a=ice-options:trickle
a=fingerprint:sha-256 71:0A:DD:DF:D1:63:8E:D5:CB:E6:2B:6D:41:1D:D4:EE:79:B2:95:97:8A:F0:64:FF:10:37:8D:41:ED:DB:EC:C4
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
m=audio 19306 UDP/TLS/RTP/SAVPF 111
c=IN IP4 142.250.82.213
a=rtcp:9 IN IP4 0.0.0.0
a=candidate: 1 udp 2113932031 142.250.82.213 19306 typ host generation 0
a=candidate: 1 tcp 2113932030 142.250.82.253 19306 typ host tcptype passive generation 0
a=candidate: 1 ssltcp 2113932029 142.250.82.253 19313 typ host generation 0
a=candidate: 1 udp 2113939711 2001:4860:4864:6:4000::19 19306 typ host generation 0
a=candidate: 1 tcp 2113939710 2001:4860:4864:6:8000::5 19306 typ host tcptype passive generation 0
a=candidate: 1 ssltcp 2113939709 2001:4860:4864:6:8000::5 19313 typ host generation 0
a=ice-ufrag:K8mRD3UolM6pjwoKAhgCCIoBnCgCIAEQ
a=ice-pwd:+7DfqMEDEFB6dLAKfGjT41l7ygg=
a=fingerprint:sha-256 32:C0:9D:17:AD:99:E2:B8:2D:FD:5D:87:D4:36:44:4A:5B:3E:EE:EA:F2:BE:BE:72:3B:66:4C:F2:57:3C:0D:FF
a=setup:passive
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:virtual-6666 virtual-6666
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:6666 cname:6666
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:0HPF
a=ice-pwd:GcBv48eO/q64iPxb7MHKS87y
a=ice-options:trickle
a=fingerprint:sha-256 71:0A:DD:DF:D1:63:8E:D5:CB:E6:2B:6D:41:1D:D4:EE:79:B2:95:97:8A:F0:64:FF:10:37:8D:41:ED:DB:EC:C4
a=setup:actpass
a=mid:1
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:K8mRD3UolM6pjwoKAhgCCIoBnCgCIAEQ
a=ice-pwd:+7DfqMEDEFB6dLAKfGjT41l7ygg=
a=fingerprint:sha-256 32:C0:9D:17:AD:99:E2:B8:2D:FD:5D:87:D4:36:44:4A:5B:3E:EE:EA:F2:BE:BE:72:3B:66:4C:F2:57:3C:0D:FF
a=setup:passive
a=mid:1
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:virtual-6667 virtual-6667
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:6667 cname:6667
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 13 110 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:0HPF
a=ice-pwd:GcBv48eO/q64iPxb7MHKS87y
a=ice-options:trickle
a=fingerprint:sha-256 71:0A:DD:DF:D1:63:8E:D5:CB:E6:2B:6D:41:1D:D4:EE:79:B2:95:97:8A:F0:64:FF:10:37:8D:41:ED:DB:EC:C4
a=setup:actpass
a=mid:2
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:K8mRD3UolM6pjwoKAhgCCIoBnCgCIAEQ
a=ice-pwd:+7DfqMEDEFB6dLAKfGjT41l7ygg=
a=fingerprint:sha-256 32:C0:9D:17:AD:99:E2:B8:2D:FD:5D:87:D4:36:44:4A:5B:3E:EE:EA:F2:BE:BE:72:3B:66:4C:F2:57:3C:0D:FF
a=setup:passive
a=mid:2
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:virtual-6668 virtual-6668
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10;useinbandfec=1
a=ssrc:6668 cname:6668
m=application 9 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 0.0.0.0
a=ice-ufrag:0HPF
a=ice-pwd:GcBv48eO/q64iPxb7MHKS87y
a=ice-options:trickle
a=fingerprint:sha-256 71:0A:DD:DF:D1:63:8E:D5:CB:E6:2B:6D:41:1D:D4:EE:79:B2:95:97:8A:F0:64:FF:10:37:8D:41:ED:DB:EC:C4
a=setup:actpass
a=mid:3
a=sctp-port:5000
a=max-message-size:262144
m=application 9 DTLS/SCTP 5000
c=IN IP4 0.0.0.0
a=ice-ufrag:K8mRD3UolM6pjwoKAhgCCIoBnCgCIAEQ
a=ice-pwd:+7DfqMEDEFB6dLAKfGjT41l7ygg=
a=fingerprint:sha-256 32:C0:9D:17:AD:99:E2:B8:2D:FD:5D:87:D4:36:44:4A:5B:3E:EE:EA:F2:BE:BE:72:3B:66:4C:F2:57:3C:0D:FF
a=setup:passive
a=mid:3
a=sctpmap:5000 webrtc-datachannel 1024
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 35 36 37 38 102 103 104 105 106 107 108 109 127 125 39 40 41 42 43 44 45 46 47 48 112 113 114 115 116 117 118 49
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:0HPF
a=ice-pwd:GcBv48eO/q64iPxb7MHKS87y
a=ice-options:trickle
a=fingerprint:sha-256 71:0A:DD:DF:D1:63:8E:D5:CB:E6:2B:6D:41:1D:D4:EE:79:B2:95:97:8A:F0:64:FF:10:37:8D:41:ED:DB:EC:C4
a=setup:actpass
a=mid:4
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 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:4 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=recvonly
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=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
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:99 rtx/90000
a=fmtp:99 apt=98
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=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:35 VP9/90000
a=rtcp-fb:35 goog-remb
a=rtcp-fb:35 transport-cc
a=rtcp-fb:35 ccm fir
a=rtcp-fb:35 nack
a=rtcp-fb:35 nack pli
a=fmtp:35 profile-id=1
a=rtpmap:36 rtx/90000
a=fmtp:36 apt=35
a=rtpmap:37 VP9/90000
a=rtcp-fb:37 goog-remb
a=rtcp-fb:37 transport-cc
a=rtcp-fb:37 ccm fir
a=rtcp-fb:37 nack
a=rtcp-fb:37 nack pli
a=fmtp:37 profile-id=3
a=rtpmap:38 rtx/90000
a=fmtp:38 apt=37
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:103 rtx/90000
a=fmtp:103 apt=102
a=rtpmap:104 H264/90000
a=rtcp-fb:104 goog-remb
a=rtcp-fb:104 transport-cc
a=rtcp-fb:104 ccm fir
a=rtcp-fb:104 nack
a=rtcp-fb:104 nack pli
a=fmtp:104 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:105 rtx/90000
a=fmtp:105 apt=104
a=rtpmap:106 H264/90000
a=rtcp-fb:106 goog-remb
a=rtcp-fb:106 transport-cc
a=rtcp-fb:106 ccm fir
a=rtcp-fb:106 nack
a=rtcp-fb:106 nack pli
a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=106
a=rtpmap:108 H264/90000
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 transport-cc
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f
a=rtpmap:125 rtx/90000
a=fmtp:125 apt=127
a=rtpmap:39 H264/90000
a=rtcp-fb:39 goog-remb
a=rtcp-fb:39 transport-cc
a=rtcp-fb:39 ccm fir
a=rtcp-fb:39 nack
a=rtcp-fb:39 nack pli
a=fmtp:39 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f
a=rtpmap:40 rtx/90000
a=fmtp:40 apt=39
a=rtpmap:41 H264/90000
a=rtcp-fb:41 goog-remb
a=rtcp-fb:41 transport-cc
a=rtcp-fb:41 ccm fir
a=rtcp-fb:41 nack
a=rtcp-fb:41 nack pli
a=fmtp:41 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=f4001f
a=rtpmap:42 rtx/90000
a=fmtp:42 apt=41
a=rtpmap:43 H264/90000
a=rtcp-fb:43 goog-remb
a=rtcp-fb:43 transport-cc
a=rtcp-fb:43 ccm fir
a=rtcp-fb:43 nack
a=rtcp-fb:43 nack pli
a=fmtp:43 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=f4001f
a=rtpmap:44 rtx/90000
a=fmtp:44 apt=43
a=rtpmap:45 AV1/90000
a=rtcp-fb:45 goog-remb
a=rtcp-fb:45 transport-cc
a=rtcp-fb:45 ccm fir
a=rtcp-fb:45 nack
a=rtcp-fb:45 nack pli
a=fmtp:45 level-idx=5;profile=0;tier=0
a=rtpmap:46 rtx/90000
a=fmtp:46 apt=45
a=rtpmap:47 AV1/90000
a=rtcp-fb:47 goog-remb
a=rtcp-fb:47 transport-cc
a=rtcp-fb:47 ccm fir
a=rtcp-fb:47 nack
a=rtcp-fb:47 nack pli
a=fmtp:47 level-idx=5;profile=1;tier=0
a=rtpmap:48 rtx/90000
a=fmtp:48 apt=47
a=rtpmap:112 H264/90000
a=rtcp-fb:112 goog-remb
a=rtcp-fb:112 transport-cc
a=rtcp-fb:112 ccm fir
a=rtcp-fb:112 nack
a=rtcp-fb:112 nack pli
a=fmtp:112 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f
a=rtpmap:113 rtx/90000
a=fmtp:113 apt=112
a=rtpmap:114 H264/90000
a=rtcp-fb:114 goog-remb
a=rtcp-fb:114 transport-cc
a=rtcp-fb:114 ccm fir
a=rtcp-fb:114 nack
a=rtcp-fb:114 nack pli
a=fmtp:114 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=64001f
a=rtpmap:115 rtx/90000
a=fmtp:115 apt=114
a=rtpmap:116 red/90000
a=rtpmap:117 rtx/90000
a=fmtp:117 apt=116
a=rtpmap:118 ulpfec/90000
a=rtpmap:49 flexfec-03/90000
a=rtcp-fb:49 goog-remb
a=rtcp-fb:49 transport-cc
a=fmtp:49 repair-window=10000000
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:K8mRD3UolM6pjwoKAhgCCIoBnCgCIAEQ
a=ice-pwd:+7DfqMEDEFB6dLAKfGjT41l7ygg=
a=fingerprint:sha-256 32:C0:9D:17:AD:99:E2:B8:2D:FD:5D:87:D4:36:44:4A:5B:3E:EE:EA:F2:BE:BE:72:3B:66:4C:F2:57:3C:0D:FF
a=setup:passive
a=mid:4
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendonly
a=msid:virtual-video-7777/7777 virtual-video-7777/7777
a=rtcp-mux
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtcp-fb:98 goog-remb
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=ssrc-group:FID 7777 7778
a=ssrc:7777 cname:7777
a=ssrc:7778 cname:7777