paint-brush
Como criar um layout dinâmico para transmissões de vários hosts com o Amazon IVSpor@amazonivs
2,313 leituras
2,313 leituras

Como criar um layout dinâmico para transmissões de vários hosts com o Amazon IVS

Muito longo; Para ler

Na última postagem, vimos como criar um aplicativo de bate-papo ao vivo com vários hosts com o Amazon Interactive Video Service (Amazon IVS). vídeo no cliente. Vamos dar uma olhada em uma abordagem que você pode utilizar para tornar a criação de um layout dinâmico um pouco mais fácil.
featured image - Como criar um layout dinâmico para transmissões de vários hosts com o Amazon IVS
Amazon Interactive Video Service (IVS)  HackerNoon profile picture

Escrevi algumas postagens recentemente sobre transmissões ao vivo multi-host com o Amazon Interactive Video Service (Amazon IVS). É um recurso empolgante que abre mundos de possibilidades que simplesmente não estavam disponíveis até recentemente. Primeiro, vimos como criar um aplicativo de bate-papo ao vivo com vários hosts .


Em seguida, vimos como transmitir essa sessão de bate-papo ao vivo para um canal do Amazon IVS.


Quando analisamos a adição de participantes de bate-papo ao cliente de transmissão naquele último post, você provavelmente notou que trapaceei um pouco e codifiquei os valores de VideoComposition que informam ao cliente de transmissão o tamanho e a posição do vídeo do participante no cliente.


Bem - enganado é uma palavra forte - digamos que simplifiquei intencionalmente o código para focar no processo de transmissão de uma sessão de bate-papo ao vivo.


Basicamente, o que procuramos aqui é modificar o tamanho e a posição do vídeo do participante na transmissão para que, quando houver um vídeo, o layout fique mais ou menos assim:



Mas quando houver dois vídeos, o layout mudará para algo assim:



E quando são cinco:



Você entendeu - um layout dinâmico que muda com base na quantidade de participantes.


Nesta postagem, veremos uma abordagem que você pode utilizar para tornar a criação de um layout dinâmico um pouco mais fácil. Desenvolveremos a solução na última postagem, portanto, se você ainda não leu essa postagem, provavelmente é uma boa ideia fazê-lo agora.


Na última postagem, ouvimos um evento chamado STAGE_PARTICIPANT_STREAMS_ADDED . No manipulador de eventos desse evento, adicionamos nossos participantes ao DOM e renderizamos o áudio e o vídeo para a instância IVSBroadcastClient .


Para renderizar um layout dinâmico, precisaremos rastrear quantos participantes estão atualmente na sessão, então adicionaremos um array participantIds como uma variável global. Vamos modificar o manipulador de eventos para enviar o ID do participante atual para esse array.


 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(); });


No último post, mencionei que o método updateVideoCompositions() não foi mostrado porque a implementação poderia variar. Falaremos sobre uma implementação possível daqui a pouco.


Por enquanto, vamos dar uma olhada em como podemos obter uma configuração de layout dinâmico em vez de codificá-la como fizemos no último post.


Uma maneira de obter um tamanho e uma posição dinâmicos é percorrer o array de participantes e calculá-los com base no número de participantes, no tamanho do <canvas> e na quantidade desejada de linhas, colunas e preenchimento. Mas, por quê ?


Isso soa como um monte de código difícil e trabalho desnecessário quando você percebe que esses valores nunca mudam. Se você tiver um participante, o vídeo terá um tamanho fixo e centralizado na <canvas> .


Não importa quantos participantes são adicionados - o layout de cada vídeo sempre será o mesmo para um determinado número de participantes. Então, por que desperdiçar tempo e ciclos de CPU quando poderíamos pré-calcular esses valores e armazená-los em uma matriz de matrizes?


Para minha demonstração, passei algum tempo determinando os melhores valores com 30 minutos intensivos com caneta, papel e calculadora para determinar os valores de composição para cada layout possível. Observação: eu não era formado em matemática ou arte, conforme evidenciado pelo esboço a seguir.



Para esta demonstração, limitei minha transmissão ao vivo para mostrar apenas vídeos para os primeiros 6 participantes. Seu caso de uso pode ditar algo diferente, mas ter mais de 6 vídeos de participantes em uma transmissão ao vivo torna-se um pouco complicado na minha experiência.


Aqui está o resultado dos meus cálculos:


 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 }] ];


Isso pode parecer complicado, mas considere que cada elemento no elemento externo da matriz contém uma matriz de composições para cada vídeo.


Se houver 3 participantes, podemos referenciar o terceiro elemento no array externo, e a posição do ID do participante no participantIds determinará qual composição será aplicada a esse vídeo.


Podemos modificar nossa função renderVideosToClient() para obter a composição adequada e usar esses valores quando adicionamos o vídeo ao cliente de transmissão.


 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); };


Mas lembre-se - se fizermos isso apenas quando um participante for adicionado, as composições de vídeo anteriores ainda refletirão a composição que foi aplicada quando foram adicionadas. É aí que a função updateVideoCompositions() entra em cena.


Aqui, fazemos um loop sobre o participantIds , pegamos a composição adequada de layouts e usamos o updateVideoDeviceComposition() ( documentos ) do método 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; } };


Também devemos garantir que, quando um participante sair do palco, removamos o ID do participante da matriz e atualizemos novamente a composição de todos os vídeos.


 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(); });


Conforme mencionado acima, você provavelmente desejará limitar a quantidade de vídeos adicionados à transmissão ao vivo por meio do cliente de transmissão. Você pode querer adicionar uma imagem estática em vez do vídeo final para mostrar que há mais participantes do que o mostrado:


Resumo

Nesta postagem, aprendemos uma abordagem para layouts dinâmicos ao transmitir um estágio de vários hosts com o Amazon IVS. Em uma postagem futura, veremos opções adicionais para transmissão com vários hosts. Como sempre, se você tiver dúvidas ou comentários, deixe-os abaixo.


Também publicado aqui