Em nosso último post, aprendemos como criar um "palco" virtual para criar uma experiência de bate-papo por vídeo em tempo real para até 12 participantes com o Amazon Interactive Video Service (Amazon IVS). Como um recurso independente, é muito poderoso e nos permite adicionar colaboração em tempo real aos nossos aplicativos. No entanto, esse recurso foi criado para capacitar os desenvolvedores a criar facilmente experiências colaborativas de transmissão ao vivo semelhantes ao recurso "Guest Star" no Twitch. Nesta postagem, desenvolveremos a demonstração anterior para combinar os feeds de áudio e vídeo de todos os participantes em um único feed e transmitir esse feed para um canal do Amazon IVS.
Se você ainda não leu o post anterior, faça isso antes de prosseguir com este post. Para recapitular, nesse post aprendemos como:
Crie um recurso de estágio com o AWS SDK for JavaScript (v3)
Crie tokens de participantes do estágio com o AWS SDK for JavaScript (v3)
Use o Web Broadcast SDK para se conectar ao palco virtual para chat de vídeo em tempo real entre os participantes
A próxima etapa para criar uma experiência de transmissão ao vivo colaborativa é combinar (ou "compor") os participantes locais e remotos em um único fluxo que pode ser publicado em um canal do Amazon IVS. Para isso também podemos usar o Web Broadcast SDK, então vamos ver como isso é feito.
Se você se lembra, na última postagem tivemos várias funções chamadas dentro de um manipulador DOMContentLoaded
que habilitou permissões, obteve dispositivos, configurou a instância Stage
e gerenciou o ingresso no stage. Adicionaremos mais um método a este fluxo chamado initBroadcastClient()
que podemos usar para criar uma instância do IVSBroadcastClient
. Vamos precisar de um elemento <canvas>
em nossa marcação para o fluxo combinado para que nossos participantes possam visualizar o que será transmitido para o canal Amazon IVS.
const initBroadcastClient = async () => { broadcastClient = IVSBroadcastClient.create({ streamConfig: IVSBroadcastClient.STANDARD_LANDSCAPE, ingestEndpoint: '[YOUR INGEST ENDPOINT]', }); const previewEl = document.getElementById('broadcast-preview'); broadcastClient.attachPreview(previewEl); const bgImage = new Image(); bgImage.src = '/images/stage_bg.png'; broadcastClient.addImageSource(bgImage, 'bg-image', { index: 0 }); };
Para tornar as coisas um pouco mais atraentes visualmente, usei addImageSource()
para adicionar uma imagem de plano de fundo ao fluxo. O método addImageSource()
recebe três argumentos: a imagem, um nome exclusivo para a fonte e um objeto VideoComposition
que é usado para definir o index
(ou 'camada') da fonte. Se você verificar oVideoComposition
, você também notará que ele pode conter valores para as posições height
, width
, x
e y
da fonte. Aproveitaremos essas propriedades daqui a pouco quando adicionarmos nossas camadas de vídeo para cada participante.
Em seguida, adicionaremos o áudio e o vídeo de cada participante ao cliente de transmissão. Faremos isso dentro do manipulador StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED
que definimos no post anterior. Modifique essa função para adicionar chamadas a duas novas funções.
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { renderParticipant(participant, streams); renderVideosToClient(participant, streams.find(s => s.streamType === StreamType.VIDEO)); renderAudioToClient(participant, streams.find(s => s.streamType === StreamType.AUDIO)); });
Agora vamos criar a função renderVideosToClient()
. Aqui, estou codificando a VideoComposition
para valores apropriados para um único participante. Em seu aplicativo, você desejará calcular dinamicamente os valores height
, width
, x
e y
dependendo da quantidade de usuários que estão participando da conversa no momento.
const renderVideosToClient = async (participant, stream) => { const participantId = participant.id; const videoId = `video-${participantId}`; const composition = { index: 1, height: 984, width: 1750, x: 85, y: 48 }; const mediaStream = new MediaStream(); mediaStream.addTrack(stream.mediaStreamTrack); broadcastClient.addVideoInputDevice(mediaStream, videoId, composition); };
A função renderAudioToClient()
é semelhante, mas usa o método addAudioInputDevice()
do SDK para adicionar a faixa de áudio.
const renderAudioToClient = async (participant, stream) => { const participantId = participant.id; const audioTrackId = `audio-${participantId}`; const mediaStream = new MediaStream(); mediaStream.addTrack(stream.mediaStreamTrack); broadcastClient.addAudioInputDevice(mediaStream, audioTrackId) };
Neste ponto, o palco está pronto para ser transmitido para um canal chamando broadcastClient.startBroadcast('[YOUR STREAM KEY]')
. Também precisaremos lidar com a remoção de participantes do broadcastClient
quando eles saírem de um palco. Para isso, atualize o manipulador para StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED
.
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => { const videoTrackId = `video-${participant.id}`; const audioTrackId = `audio-${participant.id}`; if (broadcastClient.getVideoInputDevice(videoTrackId)) broadcastClient.removeVideoInputDevice(videoTrackId); if (broadcastClient.getAudioInputDevice(audioTrackId)) broadcastClient.removeAudioInputDevice(audioTrackId); const videoId = `${participant.id}-video` document.getElementById(videoId).closest('.participant-col').remove(); updateVideoCompositions(); // function not defined in demo, implementation will vary });
Veja como uma implementação pode parecer com um único participante. Observe que cada participante do estágio seria mostrado na tela inferior e a visualização composta a ser transmitida é mostrada acima.
E quando vários participantes entram no palco virtual, o aplicativo ajusta o layout para acomodar cada participante.
Quando o participante 'host' clicar no botão 'Broadcast', a conversa combinada será transmitida para o canal Amazon IVS como uma visualização composta com todos os áudios e vídeos dos participantes combinados em um único stream.
Nesta postagem, aprendemos como criar uma transmissão ao vivo com áudio e vídeo de vários participantes remotos. Em uma postagem futura, examinaremos opções alternativas para criar o stream composto e transmiti-lo para um canal Amazon IVS.