1 Grabación automática de transmisiones en vivo de Amazon IVS en S3 |
---|
2 Archivado de mensajes de chat web con Amazon IVS Chat Logging |
3 Reproducción de transmisión en vivo de Amazon IVS con reproducción de chat |
En nuestras últimas publicaciones, analizamos cómo grabar automáticamente las transmisiones en vivo de Amazon Interactive Video Service (Amazon IVS) en Amazon S3 y cómo registrar los mensajes enviados a una sala de chat de Amazon IVS (consulte los enlaces anteriores). En esta publicación, uniremos estos dos conceptos para completar la experiencia del usuario y crear una reproducción a pedido de transmisiones en vivo pasadas con una reproducción completa del chat.
Como se vio en nuestra última publicación, los mensajes de chat que se registran en el destino de registro incluyen una marca de tiempo basada en GMT que representa la fecha y la hora en que la sala de chat de Amazon IVS publicó el evento. Para lograr una verdadera reproducción a pedido de una transmisión en vivo completa con una reproducción de chat interactiva de un mensaje en el momento más cercano posible, necesitamos obtener una transmisión regular de marcas de tiempo basadas en GMT de la transmisión grabada que podamos usar para determinar qué los mensajes de chat deben estar visibles en cualquier momento dado en la reproducción de la transmisión. Actualmente no hay una fuente documentada que proporcione esta información, pero analicemos el SDK del reproductor Amazon IVS y veamos si podemos encontrar algo que nos ayude con esta tarea.
Al tratar de resolver este problema, lo primero que pensé fue echar un vistazo a los metadatos asociados con una transmisión en vivo para ver si hay información valiosa oculta en ellos. Afortunadamente, parece haber un valor en el flujo regular de metadatos que se puede usar para nuestros propósitos de reproducción de chat. En mis pruebas, cada transmisión contiene metadatos ID3 que parecen haber sido inyectados por el proceso de transcodificación de Amazon IVS. Estas etiquetas ID3 contienen una marca de tiempo útil que podemos usar para ayudar con la reproducción del chat. Para escuchar estos eventos, podemos adjuntar un controlador que escuche el tipo de evento IVSPlayer.MetadataEventType.ID3
. Este tipo de evento está documentado, pero los documentos no dicen mucho al respecto ni garantizan lo que puede contener.
¿ Quiere evitar funciones no documentadas ? Si le preocupa usar una función no documentada, puede inyectar sus propios metadatos cronometrados en su transmisión en vivo con la marca de tiempo adecuada cuando se publiquen nuevos mensajes en sus salas de chat de Amazon IVS. Tenga en cuenta que existen límites para el tamaño y la frecuencia de publicación de eventos
PutMetadata
a través de la API.
Configuremos un reproductor de Amazon IVS para reproducir una transmisión grabada con Player SDK. En primer lugar, incluiremos el SDK de reproductor de Amazon IVS más reciente a través de una etiqueta <script>
.
¿Nuevo en Amazon IVS? Consulte la serie de blogs Introducción a Amazon Interactive Video Service . Si tiene preguntas sobre cómo comenzar, publique un comentario en cualquier publicación de esa serie (o debajo).
<script src="https://player.live-video.net/1.16.0/amazon-ivs-player.min.js"></script>
Como de costumbre, necesitaremos incluir un elemento <video>
en nuestro marcado HTML que se usará para la reproducción.
<video id="video-player" muted controls autoplay playsinline></video>
Ahora podemos crear una instancia del reproductor IVS. Estoy codificando la URL a continuación, pero puede obtener esta URL a través del método descrito en esta publicación [todo: enlace].
const streamUrl = 'https://[redacted].cloudfront.net/ivs/v1/[redacted]/[redacted]/2022/11/17/18/6/[redacted]/media/hls/master.m3u8'; const videoEl = document.getElementById('video-player'); const ivsPlayer = IVSPlayer.create(); ivsPlayer.attachHTMLVideoElement(videoEl); ivsPlayer.load(streamUrl); ivsPlayer.play();
Como se mencionó anteriormente, para que sea útil para este propósito, necesitamos un flujo regular de marcas de tiempo. Para averiguar con qué frecuencia se reciben los metadatos ID3, agreguemos un poco de tiempo. Primero, capturemos una marca de tiempo tan pronto como la transmisión comience a reproducirse.
ivsPlayer.addEventListener(IVSPlayer.PlayerState.PLAYING, (evt) => { window.time = Date.now(); });
A continuación, agregaremos el detector de eventos ID3, registraremos el tiempo y restableceremos el temporizador.
ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { const now = Date.now(); console.log(`${(now - window.time) / 1000} seconds since last event`); window.time = now; });
Ahora podemos iniciar la reproducción y observar la consola para ver con qué frecuencia se activan los eventos.
En mis pruebas, los eventos se activan cada 1 o 2 segundos. No es en tiempo real, pero probablemente sea lo suficientemente bueno para la mayoría de los escenarios. Ahora echemos un vistazo al evento para ver qué datos contiene.
window.ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { console.log(evt); });
Cuando comenzamos la reproducción con el oyente adjunto arriba, podemos ver la siguiente información registrada en la consola del navegador.
Esta es una información muy interesante, pero un poco críptica. Según mis pruebas, transc_s
parece ser la marca de tiempo que buscamos. Modifiquemos el controlador de eventos para tomar esa marca de tiempo y registrarla.
window.ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { const segmentMetadata = evt.find((tag) => tag.desc === 'segmentmetadata'); const segmentMetadataInfo = JSON.parse(segmentMetadata.info[0]); const timestamp = segmentMetadataInfo['transc_s']; const timestampWithMs = timestamp * 1000; console.log(timestampWithMs); console.log(new Date(timestamp)); });
Esto produce el siguiente resultado para mi prueba.
Si busco un momento aleatorio en el video, la marca de tiempo adecuada siempre es correcta. Esto significa que cada 1 o 2 segundos conocemos una marca de tiempo GMT válida del momento en el que se capturó el evento en la transmisión. Esto significa que podemos suponer que todos los mensajes de chat que se enviaron antes de esta marca de tiempo se publicaron en el chat y deberían estar visibles en el contenedor de chat.
Cuando se carga mi página, puedo utilizar el método descrito en la publicación anterior [todo: enlace] de esta serie para recuperar todo el registro de chat de la transmisión y representarlo en el contenedor de chat <div>
. Dado que ningún mensaje debe estar visible al comienzo de la transmisión, me aseguraré de que las llamadas contengan una clase que los oculte del usuario y almacene un atributo de datos con la marca de tiempo adecuada para poder saber qué mensajes deben estar visibles. dada cualquier marca de tiempo en la transmisión.
window.chatLog = await getChatLogs(logGroupName, chatArn, startTime, endTime); renderChat();
Mi función renderChat()
maneja la publicación de cada mensaje en el contenedor de chat.
const renderChat = () => { const chatContainer = document.getElementById('chat'); window.chatLog.forEach(msg => { const msgTemplate = document.getElementById('chatMsgTemplate'); const msgEl = msgTemplate.content.cloneNode(true); const ts = new Date(msg.event_timestamp).getTime() * 1000; msgEl.querySelector('.msg-container').setAttribute('data-timestamp', ts); msgEl.querySelector('.chat-username').innerHTML = msg.payload.Attributes.username; msgEl.querySelector('.msg').innerHTML = msg.payload.Content; chatContainer.appendChild(msgEl); }); };
Ahora puedo modificar el oyente ID3 para llamar a una función replayChat()
y pasarle la marca de tiempo actual.
window.ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { const segmentMetadata = evt.find((tag) => tag.desc === 'segmentmetadata'); const segmentMetadataInfo = JSON.parse(segmentMetadata.info[0]); const timestamp = segmentMetadataInfo['transc_s']; const timestampWithMs = timestamp * 1000; replayChat(timestampWithMs); });
En replayChat()
, puedo encontrar todos los nodos de chat que contienen una marca de tiempo menor o igual que la marca de tiempo actual de la transmisión grabada y mostrar/ocultar cualquier mensaje de chat basado en esa marca de tiempo.
const replayChat = (currentTimestamp) => { Array.from(document.querySelectorAll('[data-timestamp]')).forEach(node => { const chatMsgTs = Number(node.getAttribute('data-timestamp')); const isVisible = chatMsgTs <= currentTimestamp; if (isVisible) { node.classList.remove('d-none'); } else { node.classList.add('d-none'); } }); const chatContainer = document.getElementById('chat'); chatContainer.scrollTop = chatContainer.scrollHeight; }
En este punto, hemos logrado el objetivo de reproducir una transmisión en vivo de Amazon IVS grabada con una reproducción completa del chat.
En esta publicación, analizamos cómo combinar transmisiones en vivo de Amazon IVS grabadas con mensajes de chat registrados para crear una reproducción a pedido de una transmisión con mensajes de chat sincronizados correctamente.