ایجاد یک چیدمان پویا برای پخش چند میزبان با آمازون IVS
من اخیراً چند پست در مورد پخش زنده چند میزبان با سرویس ویدیوی تعاملی آمازون (Amazon IVS) نوشته ام. این یک ویژگی هیجانانگیز است که دنیایی از امکانات را به شما میگشاید که تا همین اواخر در دسترس نبودند. ما ابتدا نحوه ایجاد یک برنامه چت زنده چند میزبان را بررسی کردیم. بعد، دیدیم که چگونه آن جلسه چت زنده را در یک کانال IVS آمازون پخش کنیم.
وقتی در آخرین پست به اضافه کردن شرکت کنندگان در چت به سرویس گیرنده پخش نگاه کردیم، احتمالاً متوجه شده اید که من کمی تقلب کردم و کدهای سخت افزاری را وارد کردم. 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>
. مهم نیست که چند شرکت کننده اضافه می شوند – طرح بندی هر ویدیو همیشه برای تعداد معینی از شرکت کنندگان یکسان خواهد بود. پس چرا زمان و چرخههای CPU را تلف کنیم، وقتی میتوانیم این مقادیر را از قبل محاسبه کرده و در آرایهای از آرایهها ذخیره کنیم.
برای نسخه نمایشی خود، مدتی را صرف تعیین بهترین مقادیر با 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();
});
همانطور که در بالا ذکر شد، به احتمال زیاد می خواهید تعداد ویدیوهایی را که از طریق سرویس گیرنده پخش به پخش زنده اضافه می شوند، محدود کنید. ممکن است بخواهید به جای ویدیوی نهایی یک تصویر ثابت اضافه کنید تا نشان دهید تعداد شرکت کنندگان بیشتر از آنچه نشان داده شده است:
خلاصه
در این پست، یک رویکرد برای طرحبندیهای پویا هنگام پخش یک مرحله میزبان چندگانه با آمازون IVS آموختیم. در پست آینده، گزینه های اضافی برای پخش با میزبان های متعدد را بررسی خواهیم کرد. مثل همیشه، اگر سوال یا نظری دارید، لطفاً آن را در زیر مطرح کنید.