मैंने हाल ही में अमेज़ॅन इंटरएक्टिव वीडियो सर्विस (अमेज़ॅन आईवीएस) के साथ मल्टी-होस्ट लाइव स्ट्रीम के बारे में कुछ पोस्ट लिखी हैं। यह एक रोमांचक सुविधा है जो संभावनाओं की दुनिया खोलती है जो हाल तक उपलब्ध नहीं थी। हमने सबसे पहले देखा कि मल्टी-होस्ट लाइव चैट एप्लिकेशन कैसे बनाया जाए ।
इसके बाद, हमने देखा कि उस लाइव चैट सत्र को अमेज़ॅन आईवीएस चैनल पर कैसे प्रसारित किया जाए।
जब हमने उस आखिरी पोस्ट में प्रसारण क्लाइंट में चैट प्रतिभागियों को जोड़ने पर ध्यान दिया, तो आपने शायद देखा कि मैंने थोड़ा धोखा दिया और VideoComposition
मानों को हार्डकोड किया जो प्रसारण क्लाइंट को क्लाइंट पर प्रतिभागी के वीडियो का आकार और स्थिति बताता है।
खैर - धोखा एक मजबूत शब्द है - मान लीजिए कि मैंने लाइव चैट सत्र को प्रसारित करने की प्रक्रिया पर ध्यान केंद्रित करने के लिए जानबूझकर कोड को सरल बना दिया है।
मूल रूप से हम यहां जो खोज रहे हैं वह प्रसारण में प्रतिभागी के वीडियो के आकार और स्थिति को संशोधित करना है ताकि जब एक वीडियो हो, तो लेआउट कुछ इस तरह दिखे:
लेकिन जब दो वीडियो होंगे, तो लेआउट कुछ इस तरह बदल जाएगा:
और जब पाँच हों:
आपको यह विचार मिल गया है - एक गतिशील लेआउट जो प्रतिभागियों की संख्या के आधार पर बदलता है।
इस पोस्ट में, हम एक ऐसे तरीके पर नज़र डालेंगे जिसका उपयोग करके आप डायनामिक लेआउट बनाना थोड़ा आसान बना सकते हैं। हम पिछली पोस्ट में समाधान का निर्माण करेंगे, इसलिए यदि आपने अभी तक वह पोस्ट नहीं पढ़ी है, तो शायद अभी ऐसा करना एक अच्छा विचार है।
पिछली पोस्ट में, हमने STAGE_PARTICIPANT_STREAMS_ADDED
नामक एक इवेंट के बारे में सुना। उस इवेंट के इवेंट हैंडलर में, हमने अपने प्रतिभागियों को DOM में जोड़ा और ऑडियो और वीडियो को IVSBroadcastClient
उदाहरण में प्रस्तुत किया।
एक गतिशील लेआउट प्रस्तुत करने के लिए, हमें यह ट्रैक करना होगा कि वर्तमान में सत्र में कितने प्रतिभागी हैं, इसलिए हम एक वैश्विक चर के रूप में participantIds
नामक एक सरणी जोड़ देंगे। आइए वर्तमान प्रतिभागी आईडी को उस सरणी में धकेलने के लिए इवेंट हैंडलर को संशोधित करें।
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { //add participant id to array participantIds.push(participant.id); renderParticipant(participant, streams); renderVideosToClient(participant, streams.find(s => s.streamType === StreamType.VIDEO)); renderAudioToClient(participant, streams.find(s => s.streamType === StreamType.AUDIO)); updateVideoCompositions(); });
पिछली पोस्ट में, मैंने उल्लेख किया था कि updateVideoCompositions()
विधि नहीं दिखाई गई क्योंकि कार्यान्वयन अलग-अलग होगा। हम थोड़ी देर में एक संभावित कार्यान्वयन के बारे में बात करेंगे।
अभी के लिए, आइए देखें कि हम हार्डकोडिंग के बजाय डायनामिक लेआउट कॉन्फ़िगरेशन कैसे प्राप्त कर सकते हैं जैसा कि हमने पिछली पोस्ट में किया था।
गतिशील आकार और स्थिति प्राप्त करने का एक तरीका प्रतिभागी सरणी पर लूप करना और प्रतिभागियों की संख्या, <canvas>
के आकार और पंक्तियों, स्तंभों और पैडिंग की वांछित मात्रा के आधार पर उनकी गणना करना है। लेकिन, क्यों ?
जब आपको पता चलता है कि ये मान कभी नहीं बदलते हैं तो यह बहुत कठिन कोड और अनावश्यक काम लगता है। यदि आपके पास एक प्रतिभागी है, तो वीडियो एक निश्चित आकार का होगा और <canvas>
में केंद्रित होगा।
इससे कोई फर्क नहीं पड़ता कि कितने प्रतिभागी जुड़ते हैं - प्रत्येक वीडियो का लेआउट प्रतिभागियों की दी गई संख्या के लिए हमेशा समान रहेगा। तो जब हम इन मूल्यों की पूर्व-गणना कर सकते हैं और उन्हें सरणी की एक श्रृंखला में संग्रहीत कर सकते हैं तो समय और सीपीयू चक्र क्यों बर्बाद करें?
अपने डेमो के लिए, मैंने प्रत्येक संभावित लेआउट के लिए संरचना मान निर्धारित करने के लिए एक पेन, कागज और कैलकुलेटर के साथ गहन 30 मिनट के साथ सर्वोत्तम मान निर्धारित करने में कुछ समय बिताया। कृपया ध्यान दें: जैसा कि निम्नलिखित रेखाचित्र से पता चलता है, मैं गणित या कला का विषय नहीं था।
इस डेमो के लिए, मैंने अपनी लाइव स्ट्रीम को केवल पहले 6 प्रतिभागियों के लिए वीडियो दिखाने तक ही सीमित रखा। आपका उपयोग मामला कुछ अलग निर्देशित कर सकता है, लेकिन एक लाइव स्ट्रीम में 6 से अधिक प्रतिभागी वीडियो होना मेरे अनुभव में थोड़ा व्यस्त हो जाता है।
यहाँ मेरी गणना का परिणाम है:
const layouts = [ [{ height: 720, width: 1280, x: 320, y: 180 }], [{ height: 450, width: 800, x: 80, y: 315 }, { height: 450, width: 800, x: 1040, y: 315 }], [{ height: 450, width: 800, x: 80, y: 45 }, { height: 450, width: 800, x: 1040, y: 45 }, { height: 450, width: 800, x: 560, y: 585 }], [{ height: 450, width: 800, x: 80, y: 45 }, { height: 450, width: 800, x: 1040, y: 45 }, { height: 450, width: 800, x: 80, y: 585 }, { height: 450, width: 800, x: 1040, y: 585 }], [{ height: 337, width: 600, x: 20, y: 100 }, { height: 337, width: 600, x: 650, y: 100 }, { height: 337, width: 600, x: 1280, y: 100 }, { height: 337, width: 600, x: 340, y: 640 }, { height: 337, width: 600, x: 980, y: 640 }], [{ height: 337, width: 600, x: 20, y: 100 }, { height: 337, width: 600, x: 650, y: 100 }, { height: 337, width: 600, x: 1280, y: 100 }, { height: 337, width: 600, x: 20, y: 640 }, { height: 337, width: 600, x: 650, y: 640 }, { height: 337, width: 600, x: 1280, y: 640 }] ];
यह अत्याधिक लग सकता है, लेकिन विचार करें कि बाहरी सरणी तत्व के प्रत्येक तत्व में प्रत्येक वीडियो के लिए रचनाओं की एक श्रृंखला होती है।
यदि 3 प्रतिभागी हैं, तो हम बाहरी सरणी में तीसरे तत्व को संदर्भित कर सकते हैं, और participantIds
आईडी सरणी में प्रतिभागी आईडी की स्थिति यह निर्धारित करेगी कि कौन सी रचना उस वीडियो पर लागू होगी।
उचित संरचना प्राप्त करने के लिए हम अपने renderVideosToClient()
फ़ंक्शन को संशोधित कर सकते हैं और जब हम प्रसारण क्लाइंट में वीडियो जोड़ते हैं तो उन मानों का उपयोग कर सकते हैं।
const renderVideosToClient = async (participant, stream) => { const participantId = participant.id; const videoId = `video-${participantId}`; // get the index of this participantId const pIdx = participantIds.indexOf(participantId); let composition = layouts[participantIds.length - 1][pIdx]; config.index = 2; const mediaStream = new MediaStream(); mediaStream.addTrack(stream.mediaStreamTrack); broadcastClient.addVideoInputDevice(mediaStream, videoId, composition); };
लेकिन याद रखें - यदि हम ऐसा केवल तभी करते हैं जब किसी प्रतिभागी को जोड़ा जाता है, तो पिछली वीडियो रचनाएँ अभी भी उस रचना को प्रतिबिंबित करेंगी जो उन्हें जोड़े जाने पर लागू की गई थी। यहीं पर updateVideoCompositions()
फ़ंक्शन चित्र में आता है।
यहां हम participantIds
सरणी पर लूप करते हैं, layouts
से उचित संरचना लेते हैं, और updateVideoDeviceComposition()
का उपयोग करते हैं।broadcastClient
की विधि।
const updateVideoCompositions = async () => { let idx = 0; for (const p of participantIds) { const videoId = `video-${p}`; let config = layouts[filteredParticipantIds.length - 1][idx]; config.index = 2; broadcastClient.updateVideoDeviceComposition(videoId, config); idx = idx + 1; } };
हमें यह भी सुनिश्चित करना चाहिए कि जब कोई प्रतिभागी मंच छोड़ता है तो हम प्रतिभागी आईडी को सरणी से हटा दें और सभी वीडियो के लिए संरचना को फिर से अपडेट करें।
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => { const participantId = participant.id; // remove participant id from array const pIdx = participantIds.findIndex(id => id === participantId); participantIds.splice(pIdx, 1); const videoTrackId = `video-${participantId}`; const audioTrackId = `audio-${participantId}`; if (broadcastClient.getVideoInputDevice(videoTrackId)) broadcastClient.removeVideoInputDevice(videoTrackId); if (broadcastClient.getAudioInputDevice(audioTrackId)) broadcastClient.removeAudioInputDevice(audioTrackId); const videoId = `${participantId}-video`; document.getElementById(videoId).closest('.participant-col').remove(); updateVideoCompositions(); });
जैसा कि ऊपर उल्लेख किया गया है, आप संभवतः प्रसारण क्लाइंट के माध्यम से लाइव स्ट्रीम में जोड़े जाने वाले वीडियो की मात्रा को सीमित करना चाहेंगे। हो सकता है कि आप यह दिखाने के लिए अंतिम वीडियो के बजाय एक स्थिर छवि जोड़ना चाहें कि दिखाए गए प्रतिभागियों की तुलना में अधिक प्रतिभागी हैं:
इस पोस्ट में, हमने अमेज़ॅन आईवीएस के साथ मल्टी-होस्ट चरण को प्रसारित करते समय गतिशील लेआउट के लिए एक दृष्टिकोण सीखा। भविष्य की पोस्ट में, हम एकाधिक होस्ट के साथ प्रसारण के लिए अतिरिक्त विकल्पों पर गौर करेंगे। हमेशा की तरह, यदि आपका कोई प्रश्न या टिप्पणी है, तो कृपया उन्हें नीचे छोड़ें।
यहाँ भी प्रकाशित किया गया