Оптимизируйте свои подборки
Сохраняйте и классифицируйте контент в соответствии со своими настройками.
API Google Meet Media позволяет вашему приложению присоединяться к конференции Google Meet и потреблять медиапотоки в режиме реального времени.
Клиенты используют WebRTC для взаимодействия с серверами Meet. Представленные справочные клиенты ( C++ , TypeScript ) демонстрируют рекомендуемые практики, и вам рекомендуется использовать их в своей работе.
Однако вы также можете создавать полностью индивидуальные клиенты WebRTC, соответствующие техническим требованиям API Meet Media.
На этой странице изложены основные концепции WebRTC, необходимые для успешного сеанса API Meet Media.
Сигнализация предложения-ответа
WebRTC — это одноранговая (P2P) платформа, в которой участники взаимодействуют друг с другом посредством обмена сигналами. Чтобы начать сеанс, инициирующий узел отправляет предложение SDP удалённому узлу. Это предложение включает в себя следующие важные данные:
Медиа-описания для аудио и видео
Описания медиаконтента отражают информацию, передаваемую во время сеансов P2P. Существует три типа описаний: аудио, видео и данные.
Чтобы обозначить n аудиопотоков, оферент включает в предложение n описаний аудионосителей. То же самое относится и к видео. Однако описание носителя данных будет максимум одним.
Направленность
Каждое аудио- или видеоописание описывает отдельные потоки протокола SRTP (Secure Real-time Transport Protocol ), регулируемые RFC 3711 Они являются двунаправленными, позволяя двум одноранговым устройствам отправлять и получать медиаданные по одному и тому же соединению.
По этой причине каждое описание носителя (как в предложении, так и в ответе) содержит один из трех атрибутов, описывающих, как следует использовать поток:
sendonly : отправляет медиа только с предлагающего узла. Удалённый узел не будет отправлять медиа в этом потоке.
recvonly : принимает медиа только от удалённого узла. Удалённый узел не будет отправлять медиа в этом потоке.
sendrecv : Оба узла могут отправлять и получать данные в этом потоке.
Кодеки
В каждом описании медиа также указаны кодеки, поддерживаемые пиром. В случае API Meet Media клиентские предложения отклоняются, если они не поддерживают (как минимум) кодеки, указанные в технических требованиях .
DTLS-рукопожатие
Потоки SRTP защищены первоначальным рукопожатием по протоколу Datagram Transport Layer Security (DTLS, RFC 9147 ) между одноранговыми узлами. DTLS традиционно является клиент-серверным протоколом; в процессе передачи сигнала один одноранговый узел соглашается выступать в качестве сервера, а другой — в качестве однорангового узла.
Поскольку каждый поток SRTP может иметь собственное выделенное соединение DTLS, каждое описание носителя указывает один из трех атрибутов, указывающих роль однорангового узла в рукопожатии DTLS:
a=setup:actpass : предлагающий одноранговый узел подчиняется выбору удаленного однорангового узла.
a=setup:active : этот одноранговый узел действует как клиент.
a=setup:passive : этот узел действует как сервер.
Описания медиа-приложений
Каналы данных ( RFC 8831 ) являются абстракцией протокола передачи управления потоком («SCTP», RFC 9260 ).
Для открытия каналов передачи данных на начальном этапе сигнализации предложение должно содержать описание медиа-приложения . В отличие от описаний аудио- и видеоданных, описания приложений не указывают направление или кодеки.
Кандидаты ICE
Кандидаты на установление интерактивного соединения (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 .
При использовании API Meet Media клиенты всегда отправляют предложение SDP для инициирования соединения. Meet никогда не является инициатором.
Это поведение управляется внутренне эталонными клиентами ( C++ , TypeScript ), но разработчики пользовательских клиентов могут использовать PeerConnectionInterface WebRTC для генерации предложения.
Для подключения к Meet Meet предложение должно соответствовать определенным требованиям :
Клиент всегда должен выступать в качестве клиента в рукопожатии DTLS, поэтому в каждом описании носителя в предложении должно быть указано либо a=setup:actpass , либо a=setup:active .
Каждая строка описания носителя должна поддерживать все требуемые кодеки для этого типа носителя:
Аудио:Opus
Видео:VP8 , VP9 , AV1
Для приема аудио в предложении должно быть ровно 3 описания аудионосителей, предназначенных только для приема. Это можно сделать, установив трансиверы на объекте соединения с одноранговым узлом.
С++
// ...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 описаний видеоносителей, предназначенных только для приема. Это можно сделать, установив приемопередатчики на объекте соединения с пиром.
С++
// ...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 .
С++
// ...// 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. Это предложение согласовывает сеанс API Meet Media с аудио- и одним видеопотоком.
Обратите внимание, что имеются три описания аудионосителей, одно описание видеоносителя и обязательное описание носителя приложения.