Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Google Meet Media API cho phép ứng dụng của bạn tham gia một hội nghị trên Google Meet và sử dụng các luồng nội dung nghe nhìn theo thời gian thực.
Các ứng dụng sử dụng WebRTC để giao tiếp với máy chủ Meet. Các ứng dụng tham chiếu được cung cấp (C++, TypeScript) minh hoạ các phương pháp hay và bạn nên tạo trực tiếp trên các ứng dụng này.
Tuy nhiên, bạn cũng có thể tạo các ứng dụng WebRTC hoàn toàn tuỳ chỉnh tuân thủ các yêu cầu kỹ thuật của Meet Media API.
Trang này trình bày các khái niệm chính về WebRTC cần thiết cho một phiên Meet Media API thành công.
Truyền tín hiệu đề nghị-trả lời
WebRTC là một khung ngang hàng (P2P), trong đó các thành phần ngang hàng giao tiếp bằng cách báo hiệu cho nhau. Để bắt đầu một phiên, máy ngang khởi tạo sẽ gửi một đề nghị SDP đến một máy ngang từ xa. Ưu đãi này bao gồm những thông tin quan trọng sau:
Nội dung mô tả về nội dung nghe nhìn cho âm thanh và video
Nội dung mô tả về nội dung nghe nhìn cho biết những gì được truyền đạt trong các phiên P2P. Có 3 loại nội dung mô tả: âm thanh, video và dữ liệu.
Để cho biết luồng âm thanh n, bên cung cấp sẽ thêm nội dung mô tả phương tiện âm thanh n vào đề nghị. Điều này cũng đúng với video. Tuy nhiên, sẽ chỉ có tối đa một nội dung mô tả dữ liệu đa phương tiện.
Hướng đi
Mỗi nội dung mô tả bằng âm thanh hoặc video đều mô tả các luồng Giao thức truyền tải bảo mật theo thời gian thực (SRTP) riêng lẻ, chịu sự điều chỉnh của RFC
3711. Đây là các kết nối hai chiều, cho phép hai thiết bị ngang hàng gửi và nhận nội dung nghe nhìn thông qua cùng một kết nối.
Do đó, mỗi nội dung mô tả về nội dung nghe nhìn (trong cả đề nghị và câu trả lời) đều chứa một trong ba thuộc tính mô tả cách sử dụng luồng:
sendonly: Chỉ gửi nội dung nghe nhìn từ thiết bị ngang hàng cung cấp. Thiết bị ngang hàng từ xa sẽ không gửi nội dung nghe nhìn trên luồng này.
recvonly: Chỉ nhận nội dung nghe nhìn từ thiết bị ngang hàng từ xa. Bên ngang cung cấp sẽ không gửi nội dung nghe nhìn trên luồng này.
sendrecv: Cả hai thiết bị ngang hàng đều có thể gửi và nhận trên luồng này.
Bộ mã hoá và giải mã
Mỗi nội dung mô tả về nội dung nghe nhìn cũng chỉ định các bộ mã hoá và giải mã mà một thiết bị ngang hàng hỗ trợ. Trong trường hợp Meet Media API, các đề nghị của ứng dụng khách sẽ bị từ chối trừ phi chúng hỗ trợ (ít nhất) các bộ mã hoá và giải mã được chỉ định trong yêu cầu kỹ thuật.
Bắt tay DTLS
Các luồng SRTP được bảo mật bằng một quy trình bắt tay Bảo mật tầng truyền tải Datagram ("DTLS", RFC
9147) ban đầu giữa các thiết bị ngang hàng.
DTLS theo truyền thống là một giao thức từ máy khách đến máy chủ; trong quá trình báo hiệu, một thiết bị ngang hàng đồng ý đóng vai trò là máy chủ trong khi thiết bị còn lại đóng vai trò là thiết bị ngang hàng.
Vì mỗi luồng SRTP có thể có kết nối DTLS riêng, nên mỗi nội dung mô tả về nội dung nghe nhìn sẽ chỉ định một trong ba thuộc tính để cho biết vai trò của thiết bị ngang hàng trong quá trình bắt tay DTLS:
a=setup:actpass: Đối tượng ngang hàng đề nghị sẽ tuân theo lựa chọn của đối tượng ngang hàng từ xa.
a=setup:active: Đối tượng ngang hàng này đóng vai trò là ứng dụng khách.
a=setup:passive: Thiết bị ngang hàng này đóng vai trò là máy chủ.
Nội dung mô tả về nội dung nghe nhìn trong ứng dụng
Kênh dữ liệu (RFC 8831) là một bản tóm tắt của Giao thức truyền tải điều khiển luồng ("SCTP", RFC
9260).
Để mở các kênh dữ liệu trong giai đoạn báo hiệu ban đầu, đề nghị phải chứa một nội dung mô tả phương tiện ứng dụng. Không giống như nội dung mô tả bằng âm thanh và video, nội dung mô tả ứng dụng không chỉ định hướng hoặc codec.
Ứng cử viên ICE
Các đề xuất Thiết lập kết nối tương tác ("ICE", RFC
8445) của một thiết bị ngang hàng là danh sách các tuyến đường mà một thiết bị ngang hàng từ xa có thể sử dụng để thiết lập kết nối.
Tích Đề-các của danh sách hai thành phần ngang hàng, được gọi là các cặp đề xuất, biểu thị các tuyến đường tiềm năng giữa hai thành phần ngang hàng. Các cặp này được kiểm tra để xác định tuyến đường tối ưu.
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)
Ví dụ về quy trình kết nối
Dưới đây là một sản phẩm có nội dung mô tả bằng âm thanh:
Hình 1. Ví dụ về ưu đãi có nội dung mô tả bằng âm thanh về nội dung nghe nhìn.
Đối tượng ngang hàng từ xa phản hồi bằng một câu trả lời SDP chứa cùng số lượng dòng mô tả nội dung nghe nhìn. Mỗi dòng cho biết nội dung nghe nhìn (nếu có) mà thiết bị ngang hàng từ xa gửi lại cho ứng dụng khách cung cấp trên các luồng SRTP. Đối tượng ngang hàng từ xa cũng có thể từ chối các luồng cụ thể từ bên đề nghị bằng cách đặt mục nhập nội dung mô tả nội dung nghe nhìn đó thành recvonly.
Đối với Meet Media API, các ứng dụng luôn gửi đề nghị SDP để bắt đầu kết nối. Meet không bao giờ là người bắt đầu.
Hành vi này được các ứng dụng tham chiếu quản lý nội bộ (C++, TypeScript), nhưng nhà phát triển ứng dụng tuỳ chỉnh có thể dùng PeerConnectionInterface của WebRTC để tạo đề nghị.
Để kết nối với Meet, ưu đãi phải tuân thủ một số yêu cầu cụ thể:
Ứng dụng phải luôn đóng vai trò là ứng dụng trong quá trình bắt tay DTLS, vì vậy, mọi nội dung mô tả về nội dung nghe nhìn trong đề nghị đều phải chỉ định a=setup:actpass hoặc a=setup:active.
Mỗi dòng nội dung mô tả về nội dung nghe nhìn phải hỗ trợ tất cả codec bắt buộc cho loại nội dung nghe nhìn đó:
Âm thanh:Opus
Video:VP8, VP9, AV1
Để nhận âm thanh, đề nghị phải có chính xác 3 phần mô tả nội dung nghe nhìn chỉ nhận âm thanh. Bạn có thể thực hiện việc này bằng cách thiết lập các bộ thu phát trên đối tượng kết nối ngang hàng.
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'});
Để nhận video, mặt hàng phải có từ 1 đến 3 nội dung mô tả về phương tiện video chỉ nhận. Bạn có thể thực hiện việc này bằng cách thiết lập các bộ thu phát trên đối tượng kết nối ngang hàng.
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'});
Ưu đãi phải luôn có các kênh dữ liệu. Ít nhất, các kênh session-control và media-stats phải luôn mở. Tất cả các kênh dữ liệu đều phải là 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);};
Ví dụ về đề nghị và câu trả lời SDP
Sau đây là ví dụ đầy đủ về một đề nghị SDP hợp lệ và câu trả lời SDP phù hợp. Đề nghị này thương lượng một phiên Meet Media API có âm thanh và một luồng video duy nhất.
Quan sát thấy có 3 nội dung mô tả nội dung nghe nhìn bằng âm thanh, 1 nội dung mô tả nội dung nghe nhìn bằng video và nội dung mô tả nội dung nghe nhìn bắt buộc của ứng dụng.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-07-16 UTC."],[],[]]