1 Amazon IVS ライブストリームの S3 への自動記録 2 Amazon IVS チャットログを使用した Web チャットメッセージのアーカイブ 3 チャット リプレイを使用した Amazon IVS ライブ ストリームの再生 過去数回の投稿で、Amazon Interactive Video Service (Amazon IVS) のライブ ストリームを Amazon S3 に自動記録する方法と、Amazon IVS チャット ルームに送信されたメッセージをログに記録する方法について説明しました (上記のリンクを参照)。この投稿では、これら 2 つの概念を組み合わせてユーザー エクスペリエンスを完成させ、完全なチャット リプレイを備えた過去のライブ ストリームのオンデマンド再生を作成します。 前回の投稿で見たように、ロギング先に記録されるチャット メッセージには、Amazon IVS チャット ルームによってイベントが投稿された日時を表す GMT ベースのタイムスタンプが含まれています。ライブ ストリームの真のオンデマンド リプレイとメッセージのインタラクティブ チャット リプレイを可能な限り最も近いタイミングで実現するには、記録されたストリームから GMT ベースのタイムスタンプの定期的なストリームを取得する必要があります。チャット メッセージは、ストリーム再生中の任意の時点で表示される必要があります。現在、この情報を提供する文書化されたソースはありませんが、Amazon IVS を調べて、このタスクに役立つものを見つけられるかどうか見てみましょう. プレーヤー SDK Amazon IVS ストリーム メタデータ この問題を解決しようとして、私が最初に考えたのは、ライブ ストリームに関連付けられたメタデータを調べて、その中に貴重な情報が隠されているかどうかを確認することでした。ありがたいことに、チャットの再生目的で使用できるメタデータの通常のストリームには価値があるようです.私のテストでは、各ストリームには、Amazon IVS トランスコーディング プロセスによって注入されたように見える ID3 メタデータが含まれています。これらの ID3 タグには、チャットのリプレイに役立つタイムスタンプが含まれています。これらのイベントをリッスンするために、 イベント タイプをリッスンするハンドラーをアタッチできます。このイベントの種類は文書化されて が、 それについて多くのことは書かれておらず、何が含まれているかも保証されていません。 IVSPlayer.MetadataEventType.ID3 います ドキュメントには ?文書化されていない機能を使用することに懸念がある場合は、新しいメッセージが Amazon IVS チャット ルームに投稿されたときに、適切なタイム できます。 API を介して イベントを があることに注意してください。 文書化されていない機能を避けたいですか スタンプを使用して独自の時間指定されたメタデータをライブ ストリームに挿入 PutMetadata 投稿するサイズと頻度には制限 メタデータ イベントのリッスン Player SDK を使用して、記録されたストリームを再生するように Amazon IVS プレーヤーをセットアップしましょう。まず、 タグを介して最新の Amazon IVS プレーヤー SDK を含めます。 <script> ブログ シリーズ ご覧ください。開始について質問がある場合は、そのシリーズ (または以下) のいずれかの投稿にコメントを投稿してください。 Amazon IVS は初めてですか? Amazon Interactive Video Service の使用開始 を <script src="https://player.live-video.net/1.16.0/amazon-ivs-player.min.js"></script> いつものように、再生に使用する HTML マークアップに 要素を含める必要があります。 <video> <video id="video-player" muted controls autoplay playsinline></video> これで、IVS プレーヤーのインスタンスを作成できます。以下の URL をハードコーディングしていますが、この投稿 [todo: リンク] で説明されている方法でこの URL を取得できます。 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(); 前述のように、この目的に役立つようにするには、タイムスタンプの定期的なストリームが必要です。 ID3 メタデータが受信される頻度を把握するために、タイミングを追加してみましょう。まず、ストリームの再生が開始されるとすぐにタイムスタンプを取得しましょう。 ivsPlayer.addEventListener(IVSPlayer.PlayerState.PLAYING, (evt) => { window.time = Date.now(); }); 次に、ID3 イベント リスナーを追加し、タイミングをログに記録し、タイマーをリセットします。 ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { const now = Date.now(); console.log(`${(now - window.time) / 1000} seconds since last event`); window.time = now; }); これで、再生を開始し、コンソールを観察して、イベントが発生する頻度を確認できます。 私のテストでは、イベントは 1 ~ 2 秒ごとに発生します。リアルタイムではありませんが、ほとんどのシナリオではおそらく十分です。では、イベントに含まれるデータを見てみましょう。 window.ivsPlayer.addEventListener(IVSPlayer.MetadataEventType.ID3, (evt) => { console.log(evt); }); 上記のリスナーをアタッチして再生を開始すると、ブラウザ コンソールに次の情報が記録されていることがわかります。 これは非常に興味深い情報ですが、少し不可解です。私のテストに基づいて、 私たちが求めているタイムスタンプのようです。そのタイムスタンプを取得してログに記録するようにイベント ハンドラーを変更しましょう。 transc_s 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)); }); これにより、テスト用に次の出力が生成されます。 ビデオのランダムな瞬間を探すと、適切なタイムスタンプは常に正しいものになります。これは、イベントがストリームでキャプチャされた時点の有効な GMT タイムスタンプが 1 ~ 2 秒ごとにわかっていることを意味します。これは、このタイムスタンプより前に送信されたすべてのチャット メッセージがチャットに投稿され、チャット コンテナーに表示されるはずであると想定できることを意味します。 チャット ログの取得 ページが読み込まれると、このシリーズの前回の投稿 [todo: リンク] で概説した方法を使用して、ストリームのチャット ログ全体を取得し、チャット コンテナー でレンダリングできます。ストリームの開始時にメッセージが表示されないようにする必要があるため、メッセージをユーザーから非表示にするクラスが含まれていることを確認し、適切なタイムスタンプを持つデータ属性を保存して、どのメッセージを表示する必要があるかを知ることができます。ストリーム内の任意のタイムスタンプが与えられます。 <div> window.chatLog = await getChatLogs(logGroupName, chatArn, startTime, endTime); renderChat(); 私の 関数は、各メッセージのチャット コンテナーへの投稿を処理します。 renderChat() 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); }); }; これで、ID3 リスナーを変更して 関数を呼び出し、現在のタイムスタンプを渡すことができます。 replayChat() 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); }); では、記録されたストリームから現在のタイムスタンプ以下のタイムスタンプを含むすべてのチャット ノードを検索し、そのタイムスタンプに基づいてチャット メッセージを表示/非表示にすることができます。 replayChat() 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; } この時点で、記録された Amazon IVS ライブ ストリームを完全なチャット リプレイで再生するという目標を達成しました。 まとめ この投稿では、記録された Amazon IVS ライブ ストリームを記録されたチャット メッセージと組み合わせて、適切なタイミングのチャット メッセージでストリームのオンデマンド リプレイを作成する方法について説明しました。