Google Meet Media API की मदद से, आपका ऐप्लिकेशन Google Meet कॉन्फ़्रेंस में शामिल हो सकता है और रीयल-टाइम में मीडिया स्ट्रीम का इस्तेमाल कर सकता है.
क्लाइंट, Meet सर्वर से बातचीत करने के लिए WebRTC का इस्तेमाल करते हैं. दिए गए रेफ़रंस क्लाइंट (C++,
TypeScript), सुझाए गए तरीकों को दिखाते हैं. इसलिए, हमारा सुझाव है कि आप सीधे इन पर आधारित क्लाइंट बनाएं.
हालांकि, आपके पास पूरी तरह से कस्टम WebRTC क्लाइंट बनाने का विकल्प भी है. ये क्लाइंट, Meet Media API की तकनीकी ज़रूरी शर्तों के मुताबिक होने चाहिए.
इस पेज पर, Meet Media API सेशन को सही तरीके से चलाने के लिए ज़रूरी WebRTC के मुख्य कॉन्सेप्ट के बारे में बताया गया है.
ऑफ़र-जवाब सिग्नलिंग
WebRTC एक पीयर-टू-पीयर (पी2पी) फ़्रेमवर्क है, जहां पीयर एक-दूसरे को सिग्नल भेजकर कम्यूनिकेट करते हैं. सेशन शुरू करने के लिए, शुरू करने वाला पीयर, रिमोट पीयर को एसडीपी ऑफ़र भेजता है. इस ऑफ़र में ये ज़रूरी जानकारी शामिल है:
ऑडियो और वीडियो के लिए मीडिया की जानकारी
मीडिया की जानकारी से पता चलता है कि पी2पी सेशन के दौरान क्या जानकारी शेयर की गई है. जानकारी तीन तरह की होती है: ऑडियो, वीडियो, और डेटा.
n ऑडियो स्ट्रीम की जानकारी देने के लिए, ऑफ़र देने वाला व्यक्ति या कंपनी ऑफ़र में n ऑडियो मीडिया की जानकारी शामिल करती है. वीडियो के लिए भी यही बात लागू होती है. हालांकि, ज़्यादा से ज़्यादा एक डेटा मीडिया ब्यौरा होगा.
दिशा
हर ऑडियो या वीडियो की जानकारी में, RFC
3711 से कंट्रोल की जाने वाली अलग-अलग सिक्योर रीयल-टाइम ट्रांसपोर्ट प्रोटोकॉल (एसआरटीपी) स्ट्रीम के बारे में बताया जाता है. ये दोतरफ़ा होते हैं. इनकी मदद से, दो पीयर एक ही कनेक्शन पर मीडिया भेज और पा सकते हैं.
इस वजह से, ऑफ़र और जवाब, दोनों में मौजूद हर मीडिया ब्यौरे में, स्ट्रीम के इस्तेमाल के तरीके के बारे में बताने वाला तीन में से एक एट्रिब्यूट होता है:
sendonly: सिर्फ़ ऑफ़र करने वाले पीयर से मीडिया भेजता है. रिमोट पीयर, इस स्ट्रीम पर मीडिया नहीं भेजेगा.
recvonly: सिर्फ़ रिमोट पीयर से मीडिया पाता है. ऑफ़र करने वाला पीयर, इस स्ट्रीम पर मीडिया नहीं भेजेगा.
sendrecv: इस स्ट्रीम पर, दोनों पीयर डेटा भेज और पा सकते हैं.
कोडेक
हर मीडिया के ब्यौरे में, यह भी बताया जाता है कि पीयर पर कौनसे कोडेक काम करते हैं. Meet Media API के मामले में, क्लाइंट के ऑफ़र तब तक अस्वीकार कर दिए जाते हैं, जब तक वे तकनीकी ज़रूरी शर्तों में बताए गए कोडेक के साथ काम नहीं करते.
डीटीएलएस हैंडशेक
SRTP स्ट्रीम को सुरक्षित करने के लिए, पीयर के बीच डेटाग्राम ट्रांसपोर्ट लेयर सिक्योरिटी ("DTLS", RFC
9147) हैंडशेक का इस्तेमाल किया जाता है.
DTLS आम तौर पर क्लाइंट-टू-सर्वर प्रोटोकॉल होता है. सिग्नल भेजने की प्रोसेस के दौरान, एक पीयर सर्वर के तौर पर काम करने के लिए सहमत होता है, जबकि दूसरा पीयर पीयर के तौर पर काम करता है.
हर SRTP स्ट्रीम का अपना खास डीटीएलएस कनेक्शन हो सकता है. इसलिए, हर मीडिया ब्यौरे में तीन में से किसी एक एट्रिब्यूट की जानकारी दी जाती है, ताकि डीटीएलएस हैंडशेक में पीयर की भूमिका के बारे में पता चल सके:
a=setup:actpass: ऑफ़र देने वाला पीयर, रिमोट पीयर की पसंद के हिसाब से काम करता है.
a=setup:active: यह पीयर क्लाइंट के तौर पर काम करता है.
a=setup:passive: यह पीयर, सर्वर के तौर पर काम करता है.
ऐप्लिकेशन के मीडिया का ब्यौरा
डेटा चैनल (RFC 8831), स्ट्रीम कंट्रोल ट्रांसमिशन प्रोटोकॉल ("एससीटीपी", RFC
9260) का एक एब्स्ट्रैक्शन है.
शुरुआती सिग्नल भेजने के दौरान डेटा चैनल खोलने के लिए, ऑफ़र में ऐप्लिकेशन के मीडिया की जानकारी होनी चाहिए. ऑडियो और वीडियो के ब्यौरे के उलट, ऐप्लिकेशन के ब्यौरे में डायरेक्शन या कोडेक की जानकारी नहीं दी जाती.
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)
कनेक्शन फ़्लो का उदाहरण
यहां ऑडियो मीडिया की जानकारी वाला एक ऑफ़र दिया गया है:
पहली इमेज. ऑडियो मीडिया की जानकारी वाले ऑफ़र का उदाहरण.
रिमोट पीयर, एसडीपी के जवाब के साथ जवाब देता है. इसमें मीडिया के ब्यौरे की उतनी ही लाइनें होती हैं जितनी लाइनें होस्ट ने भेजी हैं. हर लाइन से पता चलता है कि रिमोट पार्टनर, SRTP स्ट्रीम के ज़रिए ऑफ़र करने वाले क्लाइंट को कौनसा मीडिया भेजता है. रिमोट पार्टनर, मीडिया ब्यौरे की एंट्री को recvonly पर सेट करके, ऑफ़र करने वाले की कुछ स्ट्रीम को भी अस्वीकार कर सकता है.
Meet Media API के लिए, क्लाइंट हमेशा कनेक्शन शुरू करने के लिए एसडीपी ऑफ़र भेजते हैं. Meet कभी भी मीटिंग शुरू नहीं करता.
इस व्यवहार को रेफ़रंस क्लाइंट (C++, TypeScript) के ज़रिए मैनेज किया जाता है. हालांकि, कस्टम क्लाइंट के डेवलपर, ऑफ़र जनरेट करने के लिए WebRTC के PeerConnectionInterface का इस्तेमाल कर सकते हैं.
Meet से कनेक्ट करने के लिए, ऑफ़र को कुछ खास शर्तों को पूरा करना होगा:
DTLS हैंडशेक में क्लाइंट को हमेशा क्लाइंट के तौर पर काम करना चाहिए. इसलिए, ऑफ़र में मौजूद हर मीडिया के ब्यौरे में a=setup:actpass या
a=setup:active में से किसी एक को बताना ज़रूरी है.
मीडिया के ब्यौरे की हर लाइन में, उस मीडिया टाइप के लिए सभी ज़रूरी कोडेक काम करने चाहिए:
ऑडियो:Opus
वीडियो:VP8, VP9, AV1
ऑडियो पाने के लिए, ऑफ़र में सिर्फ़ पाने के लिए उपलब्ध तीन ऑडियो मीडिया के ब्यौरे होने चाहिए. ऐसा करने के लिए, पीयर कनेक्शन ऑब्जेक्ट पर ट्रांसीवर सेट करें.
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'});
वीडियो पाने के लिए, ऑफ़र में एक से तीन वीडियो मीडिया के ब्यौरे शामिल होने चाहिए. ऐसा करने के लिए, पीयर कनेक्शन ऑब्जेक्ट पर ट्रांसीवर सेट करें.
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'});
ऑफ़र में हमेशा डेटा चैनल शामिल होने चाहिए. कम से कम, session-control और media-stats चैनल हमेशा खुले होने चाहिए. सभी डेटा चैनल 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);};
एसडीपी ऑफ़र और जवाब का उदाहरण
यहां मान्य एसडीपी ऑफ़र और उससे मैच करने वाले एसडीपी जवाब का पूरा उदाहरण दिया गया है. इस ऑफ़र में, ऑडियो और एक वीडियो स्ट्रीम के साथ Meet Media API सेशन के लिए बातचीत की जाती है.
ध्यान दें कि यहां तीन ऑडियो मीडिया के ब्यौरे, एक वीडियो मीडिया के ब्यौरे, और ऐप्लिकेशन के मीडिया के ज़रूरी ब्यौरे हैं.
एक उदाहरण दिखाएं
क्लाइंट एसडीपी ऑफ़र
Meet Media API के एसडीपी के जवाब में दी गई शर्तें पूरी करना