Mantieni tutto organizzato con le raccolte
Salva e classifica i contenuti in base alle tue preferenze.
L'API Google Meet Media consente alla tua app di partecipare a una conferenza Google Meet e utilizzare flussi multimediali in tempo reale.
I client utilizzano WebRTC per comunicare con i server Meet. I client di riferimento forniti (C++, TypeScript) mostrano le pratiche consigliate e ti invitiamo a utilizzarli come base per la tua implementazione.
Tuttavia, puoi anche creare client WebRTC completamente personalizzati che rispettino i requisiti tecnici dell'API Meet Media.
Questa pagina descrive i concetti chiave di WebRTC necessari per una sessione
dell'API Meet Media riuscita.
Segnalazione di offerta/risposta
WebRTC è un framework peer-to-peer (P2P) in cui i peer comunicano segnalandosi
a vicenda. Per iniziare una sessione, il peer che la avvia invia un'offerta SDP a un peer remoto. Questa offerta
include i seguenti dettagli importanti:
Descrizioni dei contenuti multimediali per audio e video
Le descrizioni dei contenuti multimediali indicano cosa viene comunicato durante le sessioni P2P. Esistono tre tipi di descrizioni: audio, video e dati.
Per indicare i flussi audio n, l'offerente include le descrizioni dei contenuti multimediali audio n nell'offerta. Lo stesso vale per i video. Tuttavia, ci sarà al massimo una descrizione dei contenuti multimediali dati.
Senso di marcia
Ogni descrizione audio o video descrive singoli stream Secure Real-time Transport
Protocol (SRTP), regolati da RFC
3711. Sono bidirezionali,
consentendo a due peer di inviare e ricevere contenuti multimediali tramite la stessa connessione.
Per questo motivo, ogni descrizione dei contenuti multimediali (sia nell'offerta che nella risposta) contiene
uno dei tre attributi che descrivono come deve essere utilizzato lo stream:
sendonly: invia solo i contenuti multimediali del peer che offre. Il peer remoto
non invierà contenuti multimediali su questo stream.
recvonly: riceve solo i contenuti multimediali dal peer remoto. Il peer che ha effettuato l'offerta
non invierà contenuti multimediali su questo stream.
sendrecv: entrambi i peer possono inviare e ricevere su questo stream.
Codec
Ogni descrizione multimediale specifica anche i codec supportati da un peer. Nel caso dell'API Meet Media, le offerte dei client vengono rifiutate a meno che non supportino (almeno) i codec specificati nei requisiti tecnici.
Handshake DTLS
I flussi SRTP sono protetti da un handshake iniziale Datagram Transport Layer Security ("DTLS", RFC
9147) tra i peer.
DTLS è tradizionalmente un protocollo client-server; durante la procedura di segnalazione,
un peer accetta di fungere da server, mentre l'altro da peer.
Poiché ogni flusso SRTP potrebbe avere la propria connessione DTLS dedicata, ogni
descrizione multimediale specifica uno dei tre attributi per indicare il ruolo del peer
nell'handshake DTLS:
a=setup:actpass: il peer che offre si adegua alla scelta del peer remoto.
a=setup:active: questo peer funge da client.
a=setup:passive: questo peer funge da server.
Descrizioni dei contenuti multimediali dell'applicazione
I canali di dati (RFC 8831) sono
un'astrazione del Stream Control Transmission Protocol ("SCTP", RFC
9260).
Per aprire i canali di dati durante la fase di segnalazione iniziale, l'offerta deve contenere
una descrizione dei media dell'applicazione. A differenza delle descrizioni audio e video,
le descrizioni delle app non specificano la direzione o i codec.
Candidati ICE
I candidati Interactive Connectivity Establishment ("ICE", RFC
8445) di un peer sono un elenco di
percorsi che un peer remoto può utilizzare per stabilire una connessione.
Il prodotto cartesiano degli elenchi dei due peer, noto come coppie candidate,
rappresenta i potenziali percorsi tra due peer. Queste coppie vengono testate per
determinare il percorso ottimale.
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)
Flusso di connessione di esempio
Ecco un'offerta con una descrizione audio del media:
Figura 1. Esempio di offerta con una descrizione audio.
Il peer remoto risponde con una risposta
SDP contenente lo stesso numero
di righe di descrizione dei media. Ogni riga indica i contenuti multimediali, se presenti, che il peer remoto
invia al client che offre la sessione tramite i flussi SRTP. Il peer remoto
potrebbe anche rifiutare flussi specifici dell'offerente impostando la voce della descrizione
multimediale su recvonly.
Per l'API Meet Media, i client inviano sempre l'offerta SDP per avviare
una connessione. Meet non è mai l'iniziatore.
Questo comportamento è gestito internamente dai client di riferimento
(C++, TypeScript),
ma gli sviluppatori di client personalizzati possono utilizzare PeerConnectionInterface di WebRTC per
generare un'offerta.
Per connettersi a Meet Meet, l'offerta deve rispettare requisiti specifici:
Il client deve sempre fungere da client nell'handshake DTLS, quindi ogni
descrizione dei contenuti multimediali nell'offerta deve specificare a=setup:actpass o
a=setup:active.
Ogni riga di descrizione dei contenuti multimediali deve supportare tutti i codec
obbligatori per quel tipo di
contenuti multimediali:
Audio:Opus
Video:VP8, VP9, AV1
Per ricevere l'audio, l'offerta deve includere esattamente tre descrizioni di contenuti multimediali audio di sola ricezione. Puoi farlo impostando i transceiver sull'oggetto connessione peer.
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'});
Per ricevere video, l'offerta deve includere 1-3 descrizioni di media video di sola ricezione. Puoi farlo impostando i transceiver sull'oggetto connessione peer.
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'});
L'offerta deve sempre includere i canali di dati. Come minimo, i canali
session-control e media-stats devono essere sempre aperti. Tutti i canali
di dati devono essere 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);};
Esempio di offerta e risposta SDP
Ecco un esempio completo di un'offerta SDP valida e della risposta SDP corrispondente. Questa offerta
negozia una sessione dell'API Meet Media con audio e un singolo stream
video.
Osserva che sono presenti tre descrizioni di contenuti multimediali audio, una descrizione di contenuti multimediali video e la descrizione di contenuti multimediali dell'applicazione richiesta.