קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
באמצעות Google Meet Media API, האפליקציה שלכם יכולה להצטרף לועידה ב-Google Meet ולצרוך שידורי מדיה בזמן אמת.
לקוחות משתמשים ב-WebRTC כדי לתקשר עם שרתי Meet. בלקוחות העזרה שסופקו (C++, TypeScript) מוצגות שיטות מומלצות, מומלץ להסתמך עליהן ישירות.
עם זאת, אפשר גם ליצור לקוחות WebRTC מותאמים אישית לחלוטין שתואמים לדרישות הטכניות של Meet Media API.
בדף הזה מפורטים מושגים מרכזיים של WebRTC שנדרשים כדי לנהל סשן Meet Media API.
איתות של הצעה-תשובה
WebRTC היא מסגרת של תקשורת peer-to-peer (P2P), שבה משתמשים מתקשרים באמצעות איתותים זה לזה. כדי להתחיל סשן, הצומת המבצע את ההתחלה שולח הצעה של SDP לצומת מרוחק. המבצע הזה כולל את הפרטים החשובים הבאים:
תיאורי מדיה לאודיו ולווידאו
תיאורי המדיה מציינים מה מועבר במהלך סשנים של P2P. יש שלושה סוגים של תיאורים: אודיו, וידאו ונתונים.
כדי לציין n שידורי אודיו, המפרסם צריך לכלול בתוכן המבצע n תיאורי מדיה של אודיו. אותו עיקרון נכון גם לגבי סרטונים. עם זאת, יהיה רק תיאור אחד של מדיה מסוג data.
כיוון
כל תיאור של אודיו או וידאו מתאר סטרימינג ספציפי של פרוטוקול להעברה בטוחה בזמן אמת (SRTP), שמנוהל על ידי RFC
3711. הם דו-כיווניים, ומאפשרים לשני מכשירים לשלוח ולקבל מדיה באותו חיבור.
לכן, כל תיאור מדיה (גם בהצעה וגם בתשובה) מכיל אחד משלושת המאפיינים שמתארים את אופן השימוש בסטרימינג:
sendonly: שליחת מדיה רק מהציוד המקביל שמציע את השירות. המשתמש המרוחק לא ישלח מדיה בשידור הזה.
recvonly: מקבלת מדיה רק מהצינור הרחוק. הצומת של המבצע לא ישלח מדיה בשידור הזה.
sendrecv: שני השותפים יכולים לשלוח ולקבל בזרם הזה.
רכיבי קודק
כל תיאור מדיה מציין גם את הקודקים שנתמכים על ידי השותף. במקרה של Meet Media API, הצעות של לקוחות נדחות אם הן לא תומכות (לפחות) בקודקים שצוינו בדרישות הטכניות.
לחיצת יד בפרוטוקול DTLS
מקור הנתונים של SRTP מאובטח באמצעות לחיצת יד ראשונית של Datagram Transport Layer Security (DTLS, RFC
9147) בין השותפים.
DTLS הוא בדרך כלל פרוטוקול לקוח-שרת. במהלך תהליך האות, אחד מהמכשירים מסכים לפעול בתור השרת והשני פועל בתור מכשיר עמית.
מכיוון שלכל שידור SRTP יכול להיות חיבור DTLS ייעודי משלו, כל תיאור מדיה מציין אחד משלושת המאפיינים הבאים כדי לציין את התפקיד של השותף לחיצת היד ב-DTLS:
a=setup:actpass: הצוות בהתוכנית מקבל את הבחירה של הצוות המרוחק.
a=setup:active: הצומת הזה פועל בתור הלקוח.
a=setup:passive: הצומת הזה משמש כשרת.
תיאורים של מדיה באפליקציה
ערוצי נתונים (RFC 8831) הם הפשטה של Stream Control Transmission Protocol (SCTP, RFC
9260).
כדי לפתוח ערוצי נתונים במהלך שלב האותת הראשוני, ההצעה צריכה לכלול תיאור של מדיה באפליקציה. בניגוד לתיאורים של אודיו וסרטונים, בתיאורים של אפליקציות לא מצוינים כיוון או קודיקים.
מועמדים ל-ICE
המועמדים ל-Interactive Connectivity Establishment (ICE, RFC
8445) של עמית הם רשימה של מסלולים שיכולים לשמש עמית מרוחק כדי ליצור חיבור.
המוצר הקרטזי של שתי רשימות השכנים, שנקרא הצמדים המועמדים, מייצג את המסלולים הפוטנציאליים בין שני השכנים. המערכת בודקת את הצמדים האלה כדי לקבוע את המסלול האופטימלי.
importcom.google.api.core.ApiFuture;importcom.google.apps.meet.v2beta.ConnectActiveConferenceRequest;importcom.google.apps.meet.v2beta.ConnectActiveConferenceResponse;importcom.google.apps.meet.v2beta.SpaceName;importcom.google.apps.meet.v2beta.SpacesServiceClient;publicclassAsyncConnectActiveConference{publicstaticvoidmain(String[]args)throwsException{asyncConnectActiveConference();}publicstaticvoidasyncConnectActiveConference()throwsException{// This snippet has been automatically generated and should be regarded as a code template only.// It will require modifications to work:// - It may require correct/in-range values for request initialization.// - It may require specifying regional endpoints when creating the service client as shown in// https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_librarytry(SpacesServiceClientspacesServiceClient=SpacesServiceClient.create()){ConnectActiveConferenceRequestrequest=ConnectActiveConferenceRequest.newBuilder().setName(SpaceName.of("[SPACE]").toString()).setOffer("offer105650780").build();ApiFuture<ConnectActiveConferenceResponse>future=spacesServiceClient.connectActiveConferenceCallable().futureCall(request);// Do something.ConnectActiveConferenceResponseresponse=future.get();}}}
usingGoogle.Apps.Meet.V2Beta;usingSystem.Threading.Tasks;publicsealedpartialclassGeneratedSpacesServiceClientSnippets{/// <summary>Snippet for ConnectActiveConferenceAsync</summary>/// <remarks>/// This snippet has been automatically generated and should be regarded as a code template only./// It will require modifications to work:/// - It may require correct/in-range values for request initialization./// - It may require specifying regional endpoints when creating the service client as shown in/// https://cloud.google.com/dotnet/docs/reference/help/client-configuration#endpoint./// </remarks>publicasyncTaskConnectActiveConferenceAsync(){// Create clientSpacesServiceClientspacesServiceClient=awaitSpacesServiceClient.CreateAsync();// Initialize request argument(s)stringname="spaces/[SPACE]";// Make the requestConnectActiveConferenceResponseresponse=awaitspacesServiceClient.ConnectActiveConferenceAsync(name);}}
/** * This snippet has been automatically generated and should be regarded as a code template only. * It will require modifications to work. * It may require correct/in-range values for request initialization. * TODO(developer): Uncomment these variables before running the sample. *//** * Required. Resource name of the space. * Format: spaces/{spaceId} */// const name = 'abc123'/** * Required. WebRTC SDP (Session Description Protocol) offer from the client. * The format is defined by RFC * 8866 (https://www.rfc-editor.org/rfc/rfc8866) with mandatory keys defined * by RFC 8829 (https://www.rfc-editor.org/rfc/rfc8829). This is the standard * SDP format generated by a peer connection's createOffer() and * createAnswer() methods. */// const offer = 'abc123'// Imports the Meet libraryconst{SpacesServiceClient}=require('@google-apps/meet').v2beta;// Instantiates a clientconstmeetClient=newSpacesServiceClient();asyncfunctioncallConnectActiveConference(){// Construct requestconstrequest={name,offer,};// Run requestconstresponse=awaitmeetClient.connectActiveConference(request);console.log(response);}callConnectActiveConference();
# This snippet has been automatically generated and should be regarded as a# code template only.# It will require modifications to work:# - It may require correct/in-range values for request initialization.# - It may require specifying regional endpoints when creating the service# client as shown in:# https://googleapis.dev/python/google-api-core/latest/client_options.htmlfromgoogle.appsimportmeet_v2betaasyncdefsample_connect_active_conference():# Create a clientclient=meet_v2beta.SpacesServiceAsyncClient()# Initialize request argument(s)request=meet_v2beta.ConnectActiveConferenceRequest(name="name_value",offer="offer_value",)# Make the requestresponse=awaitclient.connect_active_conference(request=request)# Handle the responseprint(response)
דוגמה לתהליך חיבור
הנה מבצע עם תיאור של מדיה אודיו:
איור 1. דוגמה למבצע עם תיאור של מדיה אודיו.
השותף המרוחק משיב בתשובה SDP שמכילה את אותו מספר שורות של תיאור המדיה. כל שורה מציינת את סוגי המדיה, אם יש כאלה, שהצינור הרחוק שולח בחזרה ללקוח המציע דרך מקורות הנתונים של 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(inti=0;i < 3;++i){webrtc::RtpTransceiverInitaudio_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()){returnabsl::InternalError(absl::StrCat("Failed to add audio transceiver: ",audio_result.error().message()));}}
JavaScript
pc=newRTCPeerConnection();// Configure client to receive audio from Meet servers.pc.addTransceiver('audio',{'direction':'recvonly'});pc.addTransceiver('audio',{'direction':'recvonly'});pc.addTransceiver('audio',{'direction':'recvonly'});
כדי לקבל סרטון, המבצע צריך לכלול 1-3 תיאורי מדיה של וידאו לקבלה בלבד. כדי לעשות זאת, מגדירים משדרים-מקבלים באובייקט החיבור של השותף.
C++
// ...rtc::scoped_refptr<webrtc::PeerConnectionInterface>peer_connection;for(uint32_ti=0;i < configurations.receiving_video_stream_count;++i){webrtc::RtpTransceiverInitvideo_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()){returnabsl::InternalError(absl::StrCat("Failed to add video transceiver: ",video_result.error().message()));}}
JavaScript
pc=newRTCPeerConnection();// 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.constexprwebrtc::DataChannelInitkDataChannelConfig={.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()){returnabsl::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()){returnabsl::InternalError(absl::StrCat("Failed to create data channel ",data_channel_label,": ",stats_create_result.error().message()));}
JavaScript
// ...pc=newRTCPeerConnection();// All data channels must be ordered.constdataChannelConfig={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 עם אודיו ושידור וידאו יחיד.
שימו לב שיש שלושה תיאורים של מדיה אודיו, תיאור אחד של מדיה וידאו ותיאור הנדרש של מדיה באפליקציה.
[[["התוכן קל להבנה","easyToUnderstand","thumb-up"],["התוכן עזר לי לפתור בעיה","solvedMyProblem","thumb-up"],["סיבה אחרת","otherUp","thumb-up"]],[["חסרים לי מידע או פרטים","missingTheInformationINeed","thumb-down"],["התוכן מורכב מדי או עם יותר מדי שלבים","tooComplicatedTooManySteps","thumb-down"],["התוכן לא עדכני","outOfDate","thumb-down"],["בעיה בתרגום","translationIssue","thumb-down"],["בעיה בדוגמאות/בקוד","samplesCodeIssue","thumb-down"],["סיבה אחרת","otherDown","thumb-down"]],["עדכון אחרון: 2025-03-06 (שעון UTC)."],[[["The Google Meet Media API enables applications to join Google Meet conferences and receive real-time media streams, relying on WebRTC for peer-to-peer communication."],["Offer-answer signaling, facilitated by the Meet REST API, is crucial for establishing WebRTC sessions, with the initiating peer sending an SDP offer and receiving an SDP answer from the remote peer."],["Clients connecting to Google Meet must support specific codecs (Opus for audio, VP8, VP9, AV1 for video), act as the DTLS client, include at least three `recvonly` audio descriptions, and always include data channels."],["Media descriptions specify the type of media (audio, video, data), with directionality (sendonly, recvonly, sendrecv) determining stream usage and direction, governed by SRTP."],["SDP media descriptions include the type of media (audio, video, or application/data), which IP and port it uses, the ICE credential, the DTLS fingerprint and the header extensions it supports, like the time offset, the content type, the mid and the rtp-stream-id, among others."]]],[]]