Organiza tus páginas con colecciones
Guarda y categoriza el contenido según tus preferencias.
La API de Google Meet Media permite que tu app se una a una conferencia de Google Meet y consuma transmisiones de medios en tiempo real.
Los clientes usan WebRTC para comunicarse con los servidores de Meet. Los clientes de referencia proporcionados (C++, TypeScript) demuestran las prácticas recomendadas, y te sugerimos que los uses como base para tu desarrollo.
Sin embargo, también puedes compilar clientes de WebRTC completamente personalizados que cumplan con los requisitos técnicos de la API de Meet Media.
En esta página, se describen los conceptos clave de WebRTC necesarios para una sesión exitosa de la API de Meet Media.
Señalización de oferta y respuesta
WebRTC es un framework de igual a igual (P2P) en el que los pares se comunican a través de la señalización. Para iniciar una sesión, el peer que la inicia envía una oferta de SDP a un peer remoto. Esta oferta incluye los siguientes detalles importantes:
Descripciones de contenido multimedia para audio y video
Las descripciones de medios indican lo que se comunica durante las sesiones P2P. Existen tres tipos de descripciones: audio, video y datos.
Para indicar transmisiones de audio n, el oferente incluye descripciones de medios de audio n en la oferta. Lo mismo sucede con los videos. Sin embargo, solo habrá una descripción de medios de datos como máximo.
Direccionalidad
Cada descripción de audio o video describe transmisiones individuales del Protocolo seguro de transporte en tiempo real (SRTP), regidas por RFC
3711. Son bidireccionales, lo que permite que dos pares envíen y reciban contenido multimedia a través de la misma conexión.
Por este motivo, cada descripción de medios (tanto en la oferta como en la respuesta) contiene uno de los tres atributos que describen cómo se debe usar el flujo:
sendonly: Solo envía contenido multimedia del par de la oferta. El par remoto no enviará contenido multimedia en esta transmisión.
recvonly: Solo recibe contenido multimedia del par remoto. El par de la oferta no enviará contenido multimedia en esta transmisión.
sendrecv: Ambos pares pueden enviar y recibir en esta transmisión.
Códecs
Cada descripción de medios también especifica los códecs que admite un par. En el caso de la API de Meet Media, se rechazan las ofertas del cliente, a menos que admitan (al menos) los códecs especificados en los requisitos técnicos.
Protocolo de enlace DTLS
Los flujos de SRTP están protegidos por un protocolo de enlace inicial de seguridad de la capa de transporte de datagramas (“DTLS”, RFC
9147) entre los pares.
Tradicionalmente, DTLS es un protocolo de cliente a servidor. Durante el proceso de señalización, un par acepta actuar como servidor, mientras que el otro actúa como par.
Dado que cada transmisión de SRTP puede tener su propia conexión DTLS dedicada, cada descripción de medios especifica uno de los tres atributos para indicar el rol del par en el handshake de DTLS:
a=setup:actpass: El par de oferta se somete a la elección del par remoto.
a=setup:active: Este par actúa como cliente.
a=setup:passive: Este par actúa como servidor.
Descripciones de contenido multimedia de la aplicación
Los canales de datos (RFC 8831) son una abstracción del protocolo de transmisión de control de flujo (“SCTP”, RFC
9260).
Para abrir canales de datos durante la fase de señalización inicial, la oferta debe contener una descripción de medios de la aplicación. A diferencia de las descripciones de audio y video, las descripciones de la aplicación no especifican la dirección ni los códecs.
Candidatos de ICE
Los candidatos de Interactive Connectivity Establishment (ICE, RFC
8445) de un par son una lista de rutas que un par remoto puede usar para establecer una conexión.
El producto cartesiano de las listas de los dos pares, conocido como pares candidatos, representa las rutas potenciales entre dos pares. Estos pares se prueban para determinar la ruta óptima.
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)
Ejemplo de flujo de conexión
Esta es una oferta con una descripción de medios de audio:
Figura 1. Ejemplo de oferta con una descripción de contenido multimedia de audio.
El par remoto responde con una respuesta SDP que contiene la misma cantidad de líneas de descripción de medios. Cada línea indica qué medios, si los hay, el par remoto envía de vuelta al cliente que ofrece a través de las transmisiones de SRTP. El par remoto también puede rechazar transmisiones específicas del oferente configurando esa entrada de descripción de medios en recvonly.
En el caso de la API de Meet Media, los clientes siempre envían la oferta de SDP para iniciar una conexión. Meet nunca es el iniciador.
Este comportamiento se administra internamente con los clientes de referencia (C++, TypeScript), pero los desarrolladores de clientes personalizados pueden usar PeerConnectionInterface de WebRTC para generar una oferta.
Para conectarse a Meet Meet, la oferta debe cumplir con requisitos específicos:
El cliente siempre debe actuar como cliente en el protocolo de enlace de DTLS, por lo que cada descripción de medios en la oferta debe especificar a=setup:actpass o a=setup:active.
Cada línea de descripción de medios debe admitir todos los códex requeridos para ese tipo de medio:
Audio:Opus
Video:VP8, VP9, AV1
Para recibir audio, la oferta debe incluir exactamente 3 descripciones de medios de audio de solo recepción. Puedes hacerlo configurando transceptores en el objeto de conexión entre pares.
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'});
Para recibir video, la oferta debe incluir de 1 a 3 descripciones de medios de video de solo recepción. Puedes hacerlo configurando transceptores en el objeto de conexión entre pares.
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'});
La oferta siempre debe incluir canales de datos. Como mínimo, los canales session-control y media-stats siempre deben estar abiertos. Todos los canales de datos deben ser 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);};
Ejemplo de oferta y respuesta de SDP
Este es un ejemplo completo de una oferta de SDP válida y una respuesta de SDP coincidente. Esta oferta negocia una sesión de la API de Meet Media con audio y una sola transmisión de video.
Observa que hay tres descripciones de medios de audio, una descripción de medios de video y la descripción de medios de aplicación requerida.
[[["Fácil de comprender","easyToUnderstand","thumb-up"],["Resolvió mi problema","solvedMyProblem","thumb-up"],["Otro","otherUp","thumb-up"]],[["Falta la información que necesito","missingTheInformationINeed","thumb-down"],["Muy complicado o demasiados pasos","tooComplicatedTooManySteps","thumb-down"],["Desactualizado","outOfDate","thumb-down"],["Problema de traducción","translationIssue","thumb-down"],["Problema con las muestras o los códigos","samplesCodeIssue","thumb-down"],["Otro","otherDown","thumb-down"]],["Última actualización: 2025-07-16 (UTC)"],[],[]]