1 Enregistrement automatique des flux en direct d'Amazon IVS sur S3 |
---|
2 Archivage des messages de chat Web avec Amazon IVS Chat Logging |
3 Lecture de flux en direct Amazon IVS avec relecture de chat |
Lorsque j'ai essayé de résoudre ce problème, ma première pensée a été de jeter un coup d'œil aux métadonnées associées à un flux en direct pour voir s'il y avait des informations précieuses cachées à l'intérieur. Heureusement, il semble y avoir une valeur dans le flux régulier de métadonnées qui peuvent être utilisées à des fins de lecture de chat. Lors de mes tests, chaque flux contient des métadonnées ID3 qui semblent être injectées par le processus de transcodage Amazon IVS. Ces balises ID3 contiennent un horodatage utile que nous pouvons utiliser pour faciliter la relecture du chat. Pour écouter ces événements, nous pouvons attacher un gestionnaire qui écoute le type d'événement IVSPlayer.MetadataEventType.ID3
. Ce type d'événement est documenté, mais la n'en dit pas grand-chose et ne donne aucune garantie sur ce qu'il peut contenir.
Vous voulez éviter les fonctionnalités non documentées ? Si vous êtes préoccupé par l'utilisation d'une fonctionnalité non documentée, vous pouvez avec l'horodatage approprié lorsque de nouveaux messages sont publiés dans vos salles de discussion Amazon IVS. Gardez à l'esprit qu'il existe des événements
PutMetadata
via l'API.
Configurons un lecteur Amazon IVS pour lire un flux enregistré à l'aide du SDK du lecteur. Tout d'abord, nous allons inclure le dernier SDK du lecteur Amazon IVS via une balise <script>
.
Nouveau sur Amazon IVS ? Consultez la série de blogs . Si vous avez des questions sur le démarrage, postez un commentaire sur n'importe quel article de cette série (ou ci-dessous) !
<script src="//player.live-video.net/1.16.0/amazon-ivs-player.min.js"></script>
Comme d'habitude, nous devrons inclure un élément <video>
dans notre balisage HTML qui sera utilisé pour la lecture.
<video id="video-player" muted controls autoplay playsinline></video>
const streamUrl = '//[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();
ivsPlayer.addEventListener(IVSPlayer.PlayerState.PLAYING, (evt) => { window.time = Date.now(); });
ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { const now = Date.now(); console.log(`${(now - window.time) / 1000} seconds since last event`); window.time = now; });
window.ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { console.log(evt); });
C'est une information très intéressante, mais un peu énigmatique. D'après mes tests, transc_s
semble être l'horodatage que nous recherchons. Modifions le gestionnaire d'événements pour saisir cet horodatage et le consigner.
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)); });
Lorsque ma page se charge, je peux utiliser la méthode décrite dans le post précédent [todo: link] de cette série pour récupérer l'intégralité du journal de discussion pour le flux et le rendre dans le conteneur de discussion <div>
. Étant donné qu'aucun message ne doit être visible au tout début du flux, je m'assurerai qu'ils contiennent une classe qui les masque à l'utilisateur et stocke un attribut de données avec l'horodatage approprié afin que je puisse savoir quels messages doivent être visibles étant donné n'importe quel horodatage dans le flux.
window.chatLog = await getChatLogs(logGroupName, chatArn, startTime, endTime); renderChat();
Ma fonction renderChat()
gère la publication de chaque message dans le conteneur de discussion.
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); }); };
Maintenant, je peux modifier l'écouteur ID3 pour appeler une fonction replayChat()
et lui transmettre l'horodatage actuel.
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); });
Dans replayChat()
, je peux trouver tous les nœuds de chat qui contiennent un horodatage inférieur ou égal à l'horodatage actuel du flux enregistré et afficher/masquer tout message de chat basé sur cet horodatage.
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; }