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 Videokonferenz in Google Meet teilnehmen und Media-Streams in Echtzeit empfangen.
Clients verwenden WebRTC, um mit Meet-Servern zu kommunizieren. Die bereitgestellten Referenzclients (C++, TypeScript) demonstrieren empfohlene Vorgehensweisen. Wir empfehlen, direkt auf ihnen aufzubauen.
Sie können aber auch vollständig benutzerdefinierte WebRTC-Clients erstellen, die den technischen Anforderungen der Meet Media API entsprechen.
Auf dieser Seite werden die wichtigsten WebRTC-Konzepte beschrieben, die für eine erfolgreiche Meet Media API-Sitzung erforderlich sind.
Signalisierung von Angebot und Antwort
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 umfasst die folgenden wichtigen Details:
Media-Beschreibungen für Audio und Video
Medienbeschreibungen 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-Medienbeschreibungen in das Angebot ein. Dasselbe gilt für Videos. Es gibt jedoch maximal eine Media-Beschreibung für data.
Verkehrsrichtung
Jede Audio- oder Videobeschreibung beschreibt einzelne Secure Real-time Transport Protocol-Streams (SRTP), die von RFC
3711 geregelt werden. Sie sind bidirektional, sodass zwei Peers über dieselbe Verbindung Medien senden und empfangen können.
Aus diesem Grund enthält jede Medienbeschreibung (sowohl im Angebot als auch in der Antwort) eines von drei Attributen, die beschreiben, wie der Stream verwendet werden soll:
sendonly: Sendet nur Medien vom anbietenden Peer. Der Remote-Peer sendet keine Medien über diesen Stream.
recvonly: Empfängt nur Medien vom Remote-Peer. Der anbietende Peer sendet keine Medien in diesem Stream.
sendrecv: Beide Peers können Daten über diesen Stream senden und empfangen.
Codecs
In jeder Medienbeschreibung werden auch die von einem Peer unterstützten Codecs angegeben. Im Fall der Meet Media API werden Clientangebote abgelehnt, wenn sie nicht (mindestens) die in den technischen Anforderungen angegebenen 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-zu-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 Medienbeschreibung eines von drei Attributen an, um die Rolle des Peers im DTLS-Handshake anzugeben:
a=setup:actpass: Der angebotene Peer überlässt die Auswahl dem Remote-Peer.
a=setup:active: Dieser Peer fungiert als Client.
a=setup:passive: Dieser Peer fungiert als Server.
Beschreibungen für Anwendungsmedien
Datenkanäle (RFC 8831) sind eine Abstraktion des Stream Control Transmission Protocol („SCTP“, RFC
9260).
Damit Datenchannels während der ersten Signalisierungsphase geöffnet werden können, muss das Angebot eine application media description enthalten. Im Gegensatz zu Audio- und Videobeschreibungen werden in App-Beschreibungen keine Richtung oder Codecs angegeben.
ICE-Kandidaten
Die Interactive Connectivity Establishment-Kandidaten („ICE“, RFC
8445) eines Peers sind eine Liste von Routen, die ein Remote-Peer zum Herstellen einer Verbindung verwenden kann.
Das kartesische Produkt der Listen der beiden Peers, auch Kandidatenpaare genannt, 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 Beschreibung von Audiomedia:
Abbildung 1: Beispiel für ein Angebot mit einer Beschreibung von Audiomedien.
Der Remote-Peer antwortet mit einer SDP-Antwort, die dieselbe Anzahl von Media-Beschreibungszeilen enthält. Jede Zeile gibt an, welche Medien der Remote-Peer über die SRTP-Streams an den anbietenden Client zurücksendet. Der Remote-Peer kann auch bestimmte Streams des Anbieters ablehnen, indem er den entsprechenden Media-Deskriptoreintrag 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. Entwickler benutzerdefinierter Clients können jedoch die PeerConnectionInterface-Funktion von WebRTC verwenden, um ein Angebot zu generieren.
Damit eine Verbindung zu Meet Meet hergestellt werden kann, muss das Angebot bestimmte Anforderungen erfüllen:
Der Client muss immer als Client im DTLS-Handshake fungieren. Daher muss in jeder Medienbeschreibung im Angebot entweder a=setup:actpass oder a=setup:active angegeben werden.
Jede Media-Textzeile muss alle erforderlichen Codecs für den jeweiligen Medientyp unterstützen:
Audio:Opus
Video:VP8, VP9, AV1
Damit Audio empfangen werden kann, muss das Angebot genau drei Audio-Media-Beschreibungen enthalten, die nur empfangen werden können. Dazu müssen 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'});
Damit Sie Videoinhalte erhalten können, muss das Angebot 1–3 Media-Beschreibungen für den reinen Videoempfang enthalten. Dazu müssen 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 Datenchannels 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 SDP-Angebot und ‑Antwort
Hier ist ein vollständiges Beispiel für ein gültiges SDP-Angebot und eine passende SDP-Antwort. Bei diesem Angebot wird eine Meet Media API-Sitzung mit Audio und einem einzelnen Videostream ausgehandelt.
Es gibt drei Audio-Media-Beschreibungen, eine Video-Media-Beschreibung und die erforderliche Anwendungs-Media-Beschreibung.