معاينة مطوّري البرامج:
تتوفّر هذه الميزة كجزء من برنامج برنامج الاستخدام المبكر في Google Workspace لمطوّري البرامج ، الذي يمنح إمكانية الوصول المبكر إلى ميزات معيّنة.
لاستخدام Meet Media API للوصول إلى الوسائط في الوقت الفعلي من مؤتمر، يجب تسجيل مشروع Google Cloud والكيان الأساسي لبروتوكول OAuth وجميع المشاركين في المؤتمر في برنامج الاستخدام المبكر لمطوّري البرامج.
تسمح واجهة برمجة التطبيقات Google Meet Media API لتطبيقك بالانضمام إلى مؤتمر على Google Meet
واستخدام بث الوسائط في الوقت الفعلي.
تستخدم البرامج WebRTC للتواصل مع خوادم Meet. تعرض البرامج المرجعية المقدَّمة (C++ وTypeScript ) أفضل الممارسات، ونشجّعك على الاستفادة منها مباشرةً.
ومع ذلك، يمكنك أيضًا إنشاء برامج WebRTC مخصّصة بالكامل تتوافق مع
المتطلبات الفنية
لواجهة برمجة التطبيقات Meet Media API .
توضّح هذه الصفحة مفاهيم WebRTC الرئيسية المطلوبة لإجراء جلسة ناجحة باستخدام Meet Media API.
إشارات العرض والردّ
WebRTC هو إطار عمل من نظير إلى نظير (P2P)، حيث يتواصل النظراء من خلال إرسال إشارات إلى بعضهم البعض. لبدء جلسة، يرسل النظير الذي يبدأ الجلسة عرض SDP
offer إلى نظير بعيد. يتضمّن هذا العرض التفاصيل المهمة التالية:
توضّح أوصاف الوسائط ما يتم إرساله خلال جلسات P2P. هناك ثلاثة أنواع من الأوصاف: الصوت والفيديو والبيانات.
للإشارة إلى n من بث الصوت، يدرج مقدّم العرض n من أوصاف الوسائط الصوتية في العرض. وينطبق الأمر نفسه على الفيديو. ومع ذلك، لن يكون هناك سوى وصف واحد للوسائط البيانية على الأكثر.
اتجاهات الطريق
يصف كل وصف صوتي أو فيديو بث بروتوكول النقل الآمن في الوقت الفعلي (SRTP) فردي، محكوم بـ RFC
3711 . هذه البث ثنائية الاتجاه، ما يسمح لنظيرين بإرسال الوسائط وتلقّيها عبر الاتصال نفسه.
لهذا السبب، يحتوي كل وصف للوسائط (في كلّ من العرض والردّ) على إحدى السمات الثلاث التي تصف كيفية استخدام البث:
sendonly : لا يتم إرسال الوسائط إلا من النظير الذي يقدّم العرض. لن يرسل النظير البعيد الوسائط على هذا البث.
recvonly : لا يتم تلقّي الوسائط إلا من النظير البعيد. لن يرسل النظير الذي يقدّم العرض الوسائط على هذا البث.
sendrecv : يمكن لكلا النظيرين إرسال الوسائط وتلقّيها على هذا البث.
برامج الترميز
يحدّد كل وصف للوسائط أيضًا برامج الترميز التي يتيحها النظير. في حالة
Meet Media API، يتم رفض عروض البرامج ما لم تكن تتيح
(على الأقل) برامج الترميز المحدّدة في المتطلبات
الفنية .
المصافحة باستخدام بروتوكول أمان طبقة النقل لمخطّطات البيانات (DTLS)
يتم تأمين بث SRTP من خلال مصافحة أولية بين النظيرين باستخدام
بروتوكول أمان طبقة النقل لمخطّطات البيانات ("DTLS", RFC
9147 ).
عادةً ما يكون DTLS بروتوكولاً من العميل إلى الخادم، وخلال عملية الإشارة، يوافق أحد النظيرين على العمل كخادم بينما يعمل الآخر كنظير.
بما أنّ كل بث SRTP قد يكون له اتصال DTLS مخصّص، يحدّد كل وصف للوسائط إحدى السمات الثلاث للإشارة إلى دور النظير في المصافحة باستخدام DTLS:
a=setup:actpass : يترك النظير الذي يقدّم العرض الخيار للنظير البعيد.
a=setup:active : يعمل هذا النظير كعميل.
a=setup:passive : يعمل هذا النظير كخادم.
قنوات البيانات (RFC 8831 ) هي
تجريد لـ بروتوكول نقل التحكّم في البث ("SCTP"، RFC
9260 ).
لفتح قنوات البيانات خلال مرحلة الإشارة الأولية، يجب أن يحتوي العرض على وصف لوسائط التطبيق . على عكس أوصاف الصوت والفيديو، لا تحدّد أوصاف التطبيق الاتجاه أو برامج الترميز.
مرشّحو ICE
مرشّحو بروتوكول إنشاء الاتصال التفاعلي ("ICE", RFC
8445 ) لنظير ما هم قائمة بالمسارات التي يمكن أن يستخدمها نظير بعيد لإنشاء اتصال.
يمثّل ناتج الضرب الديكارتي لقائمتَي النظيرين، المعروف باسم أزواج المرشّحين ،
المسارات المحتمَلة بين نظيرين. يتم اختبار هذه الأزواج لتحديد المسار الأمثل.
الإشارة من خلال Meet REST API
استخدِم Meet REST API لإجراء إشارات
العرض والردّ هذه. يقدّم تطبيقك عرض
SDP إلى طريقة
connectActiveConference()
ويتلقّى رد
SDP في المقابل.
تعرض عيّنات التعليمات البرمجية التالية كيفية استدعاء الطريقة:
مثال على تدفق الاتصال
في ما يلي عرض يتضمّن وصفًا لوسائط الصوت:
الشكل 1. مثال على عرض يتضمّن وصفًا لوسائط الصوت
يردّ النظير البعيد بعرض SDP answer يحتوي على العدد نفسه من أسطر وصف الوسائط. يشير كل سطر إلى الوسائط التي يرسلها النظير البعيد إلى العميل الذي يقدّم العرض عبر بث SRTP، إن وُجدت. قد يرفض النظير البعيد أيضًا بثًا معيّنًا من مقدّم العرض من خلال ضبط إدخال وصف الوسائط هذا على recvonly.
بالنسبة إلى Meet Media API، يرسل العملاء دائمًا عرض SDP لبدء اتصال. لا يبدأ Meet الاتصال أبدًا.
تتم إدارة هذا السلوك داخليًا من قِبل البرامج المرجعية
(C++ وTypeScript )،
ولكن يمكن لمطوّري البرامج المخصّصة استخدام PeerConnectionInterface في WebRTC لـ
إنشاء عرض.
للاتصال بـ Meet، يجب أن يتوافق العرض مع متطلبات معيّنة
:
يجب أن يعمل العميل دائمًا كعميل في المصافحة باستخدام DTLS، لذا يجب أن يحدّد كل وصف للوسائط في العرض إما a=setup:actpass أو a=setup:active.
يجب أن يتيح كل سطر وصف للوسائط جميع برامج الترميز المطلوبة لنوع الوسائط
هذا:
الصوت: Opus
الفيديو: VP8 وVP9 وAV1
لتلقّي الصوت، يجب أن يتضمّن العرض 3 أوصاف لوسائط الصوت التي لا يمكن إلا تلقّيها. يمكنك إجراء ذلك من خلال ضبط أجهزة الإرسال والاستقبال على عنصر اتصال النظير.
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' });
لتلقّي الفيديو، يجب أن يتضمّن العرض وصفًا واحدًا إلى ثلاثة أوصاف لوسائط الفيديو التي لا يمكن إلا تلقّيها. يمكنك إجراء ذلك من خلال ضبط أجهزة الإرسال والاستقبال على عنصر اتصال النظير.
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' });
يجب أن يتضمّن العرض دائمًا قنوات البيانات. في الحد الأدنى، يجب أن تكون قناتا session-control وmedia-stats مفتوحتَين دائمًا. يجب أن تكون جميع قنوات البيانات 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 );
};
مثال على عرض SDP والردّ
في ما يلي مثال كامل على عرض SDP صالح وردّ SDP مطابق. يتفاوض هذا العرض على جلسة Meet Media API تتضمّن الصوت وبث فيديو واحدًا.
لاحظ أنّ هناك ثلاثة أوصاف لوسائط الصوت ووصفًا واحدًا لوسائط الفيديو ووصف وسائط التطبيق المطلوب.
ملاحظة: يتم فصل الأقسام إلى صفوف لتسهيل العرض.
عرض SDP للعميل
ردّ 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