Meet Media API-Konzepte
Mit Sammlungen den Überblick behalten
Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.
Mit der Google Meet Media API kann Ihre App an einer Google Meet
Konferenz teilnehmen und Echtzeit-
Media-Streams nutzen.
Clients verwenden WebRTC, um mit Meet-Servern zu kommunizieren. Die bereitgestellten
Referenzclients (C++,
TypeScript) zeigen empfohlene Vorgehensweisen.
Wir empfehlen, direkt darauf aufzubauen.
Auf dieser Seite werden die wichtigsten WebRTC-Konzepte beschrieben, die für eine erfolgreiche Meet Media API-Sitzung erforderlich sind.
Angebot-Antwort-Signalisierung
WebRTC ist ein Peer-to-Peer-Framework (P2P), bei dem Peers miteinander kommunizieren, indem sie sich gegenseitig signalisieren. Um eine Sitzung zu starten, sendet der initiierende Peer ein SDP
Angebot an einen Remote-Peer. Dieses Angebot enthält die folgenden wichtigen Details:
Mediabeschreibungen für Audio und Video
Mediabeschreibungen geben an, was während P2P-Sitzungen kommuniziert wird. Es gibt drei Arten von Beschreibungen: Audio, Video und Daten.
Um n Audiostreams anzugeben, fügt der Anbieter n Audio-Mediabeschreibungen in das Angebot ein. Dasselbe gilt für Video. Es gibt jedoch höchstens eine Daten -Mediabeschreibung.
Verkehrsrichtung
Jede Audio- oder Videobeschreibung beschreibt einzelne Secure Real-time Transport
Protocol (SRTP)-Streams, die durch RFC
3711 geregelt werden. Diese sind bidirektional, sodass zwei Peers Medien über dieselbe Verbindung senden und empfangen können.
Aus diesem Grund enthält jede Mediabeschreibung (sowohl im Angebot als auch in der Antwort) eines von drei Attributen, das beschreibt, wie der Stream verwendet werden soll:
sendonly: Sendet nur Medien vom anbietenden Peer. Der Remote-Peer sendet keine Medien in diesem Stream.
recvonly: Empfängt nur Medien vom Remote-Peer. Der anbietende Peer sendet keine Medien in diesem Stream.
sendrecv: Beide Peers können in diesem Stream senden und empfangen.
Codecs
Jede Mediabeschreibung gibt auch die Codecs an, die ein Peer unterstützt. Bei der
Meet Media API werden Clientangebote abgelehnt, wenn sie nicht mindestens die in den technischen
Anforderungenangegebenen Codecs unterstützen.
DTLS-Handshake
SRTP-Streams werden durch einen anfänglichen
Datagram Transport Layer Security -Handshake („DTLS“, RFC
9147) zwischen den Peers gesichert.
DTLS ist traditionell ein Client-Server-Protokoll. Während des Signalisierungsprozesses stimmt ein Peer zu, als Server zu fungieren, während der andere als Peer fungiert.
Da jeder SRTP-Stream eine eigene DTLS-Verbindung haben kann, gibt jede Mediabeschreibung eines von drei Attributen an, um die Rolle des Peers beim DTLS-Handshake anzugeben:
a=setup:actpass: Der anbietende Peer richtet sich nach der Wahl des Remote-Peers.
a=setup:active: Dieser Peer fungiert als Client.
a=setup:passive: Dieser Peer fungiert als Server.
Mediabeschreibungen für Anwendungen
Datenkanäle (RFC 8831) sind
eine Abstraktion des Stream Control Transmission Protocol ("SCTP", RFC
9260).
Um während der anfänglichen Signalisierungsphase Datenkanäle zu öffnen, muss das Angebot eine Mediabeschreibung für Anwendungen enthalten. Im Gegensatz zu Audio- und Videobeschreibungen geben Anwendungsbeschreibungen keine Richtung oder Codecs an.
ICE-Kandidaten
Die Interactive Connectivity Establishment-Kandidaten („ICE“, RFC
8445) eines Peers sind eine Liste von
Routen, die ein Remote-Peer verwenden kann, um eine Verbindung herzustellen.
Das kartesische Produkt der Listen der beiden Peers, die sogenannten Kandidatenpaare,
stellt die potenziellen Routen zwischen zwei Peers dar. Diese Paare werden getestet, um die optimale Route zu ermitteln.
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)
Beispiel für einen Verbindungsablauf
Hier ist ein Angebot mit einer Audio-Mediabeschreibung:
Abbildung 1 Beispielangebot mit einer Audio-Mediabeschreibung.
Der Remote-Peer antwortet mit einer SDP
Antwort, die dieselbe Anzahl
von Mediabeschreibungszeilen enthält. Jede Zeile gibt an, welche Medien der Remote-Peer gegebenenfalls über die SRTP-Streams an den anbietenden Client zurücksendet. Der Remote-Peer kann auch bestimmte Streams vom Anbieter ablehnen, indem er den entsprechenden Eintrag in der Mediabeschreibung auf recvonly setzt.
Bei der Meet Media API senden Clients immer das SDP-Angebot, um eine Verbindung herzustellen. Meet ist nie der Initiator.
Dieses Verhalten wird intern von den Referenzclients
(C++, TypeScript) verwaltet,
aber Entwickler benutzerdefinierter Clients können WebRTCs PeerConnectionInterface verwenden,
um ein Angebot zu erstellen.
Um eine Verbindung zu Meet herzustellen, muss das Angebot bestimmte
Anforderungen erfüllen:
Der Client muss beim DTLS-Handshake immer als Client fungieren. Daher muss jede Mediabeschreibung im Angebot entweder a=setup:actpass oder a=setup:active angeben.
Jede Mediabeschreibungszeile muss alle erforderlichen
Codecs für diesen Medien
typ unterstützen:
Audio:Opus
Video:VP8, VP9, AV1
Um Audio zu empfangen, muss das Angebot genau drei Audio-Mediabeschreibungen enthalten, die nur zum Empfangen verwendet werden. Dazu können Sie Transceiver für das Peer-Verbindungsobjekt festlegen.
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'});
Um Video zu empfangen, muss das Angebot 1 bis 3 Video-Mediabeschreibungen enthalten, die nur zum Empfangen verwendet werden. Dazu können Sie Transceiver für das Peer-Verbindungsobjekt festlegen.
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'});
Das Angebot muss immer Datenkanäle enthalten. Mindestens die Kanäle session-control und media-stats sollten immer geöffnet sein. Alle Datenkanäle müssen ordered sein.
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);};
Beispiel für ein SDP-Angebot und eine SDP-Antwort
Hier ist ein vollständiges Beispiel für ein gültiges SDP-Angebot und eine passende SDP-Antwort. Dieses Angebot verhandelt eine Meet Media API-Sitzung mit Audio und einem einzelnen Videostream.
Es gibt drei Audio-Mediabeschreibungen, eine Video-Mediabeschreibung und die erforderliche Mediabeschreibung für Anwendungen.