ステップ2:IVS Chatによるリアルタイムチャット機能の実装
今回のステップの概要とライブ配信アプリとの関連について
このステップでは、ステップ1で構築したライブ配信基盤にAmazon IVS Chatを使用したリアルタイムチャット機能を追加します。具体的には、IVS Chatルームの作成、Cognitoとの連携によるユーザー認証、Lambda関数を使用したチャットメッセージのモデレーション機能を実装します。
ライブ配信アプリケーションにとって、IVS Chatは「映画館で観客が映画について感想を共有できる専用の会話スペース」のような役割を果たします。映画を見ながら隣の人と感想を話すように、視聴者は配信を見ながらリアルタイムでコメントを投稿し、他の視聴者や配信者と交流できます。通常のチャットシステムと違い、IVS Chatは配信と完全に同期しているため、「今画面に映っているシーンについて」のコメントがリアルタイムで共有されます。
このステップで学ぶこと
- Amazon IVS Chatの基本設定とチャットルーム作成
- Amazon Cognitoを使用したチャット参加者の認証・識別
- AWS Lambdaを使用したチャットメッセージのモデレーション
- リアルタイム通信の実装とWebSocket接続の管理
リソースの関わりと構成説明
ステップ2で作成するリソースは、ライブ配信アプリケーションのインタラクティブ機能を構築するものです。それぞれのリソースがライブ配信アプリケーションにどのように関わるのかを説明します。
Amazon IVS Chatとライブ配信アプリの関わり
Amazon IVS Chat「チャットルーム」は、ライブ配信アプリケーションの「観客席での会話エリア」のような役割を果たします。視聴者がリアルタイムでメッセージを投稿すると、他の視聴者にも瞬時に表示されます。配信との同期機能により、配信者が「今ジャンプします!」と言った瞬間に投稿されたコメントが、適切なタイミングで他の視聴者に表示されます。
Amazon Cognitoとライブ配信アプリの関わり
Amazon Cognito「ユーザー認証システム」は、ライブ配信アプリケーションの「入場券チェック係」のような役割を果たします。チャットに参加するユーザーの身元を確認し、適切な権限を付与します。これにより、匿名コメントの制限、VIPユーザーの特別扱い、不適切なユーザーの排除などが可能になります。
AWS Lambdaとライブ配信アプリの関わり
AWS Lambda「メッセージモデレーション機能」は、ライブ配信アプリケーションの「会話の監視員」のような役割を果たします。投稿されたメッセージを自動的にチェックし、不適切な内容(スパム、誹謗中傷、不適切な言葉)を検知してフィルタリングします。これにより、健全なコミュニティ環境を維持できます。
実際の手順
実際の手順では、たくさんの設定値を入力することになります。 本文中に設定値が指定されていない場合は、デフォルト値のまま作業を進めてください。
1. Amazon Cognitoユーザープールの作成
チャット参加者の認証に使用するCognitoユーザープールを作成します。
1-1. Cognitoユーザープールの基本設定
- AWSマネジメントコンソールで「Amazon Cognito」サービスにアクセスします
- 「ユーザープールを作成」ボタンをクリックします
- 以下の設定を行います:
- プール名:
live-streaming-users - サインインオプション:
ユーザー名とEメール - パスワードポリシー: デフォルト設定を使用
- MFA設定:
無効(今回は簡単のため無効にします)
- プール名:

1-2. アプリクライアントの設定
- 作成したユーザープールの詳細画面で「アプリの統合」タブを選択します
- 「アプリクライアントを作成」をクリックします
- 以下の設定を行います:
- アプリタイプ:
パブリッククライアント - アプリクライアント名:
live-streaming-client - クライアントシークレット:
クライアントシークレットを生成しない(Webアプリケーションのため) - 認証フロー:
ALLOW_USER_PASSWORD_AUTH(ユーザー名パスワード認証を許可)ALLOW_REFRESH_TOKEN_AUTH(リフレッシュトークン認証を許可)
- アプリタイプ:
【解説】認証フローの選択について
Cognitoでは複数の認証フローが提供されています。今回選択したALLOW_USER_PASSWORD_AUTHは、ユーザー名とパスワードによる直接認証を可能にします。
ALLOW_REFRESH_TOKEN_AUTHは、アクセストークンの期限が切れた際に、リフレッシュトークンを使用して新しいトークンを取得するために必要です。
Webアプリケーションではクライアントシークレットを安全に保管できないため、パブリッククライアントとして設定します。
2. Amazon IVS Chatルームの作成
配信チャンネルと連携するチャットルームを作成します。
2-1. IVS Chatルームの基本設定
- AWSマネジメントコンソールで「Amazon IVS」サービスにアクセスします
- 左側メニューから「Chat」を選択します
- 「ルームを作成」ボタンをクリックします
- 以下の設定を行います:
- ルーム名:
live-streaming-chat - 最大メッセージ長:
500文字 - 最大メッセージレート:
10メッセージ/秒 - ログ設定: 有効(CloudWatch Logsに送信)
- ルーム名:
2-2. チャットトークンの生成設定
- 作成したチャットルームの詳細画面で「ARN」をコピーして保存します
- IAMロールでIVS Chatへのアクセス権限を設定します:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ivschat:CreateChatToken",
"ivschat:SendMessage",
"ivschat:DisconnectUser"
],
"Resource": "arn:aws:ivschat:REGION:ACCOUNT:room/ROOM-ID"
}
]
}3. Lambda関数によるメッセージモデレーション
投稿されたメッセージを自動的にチェックするLambda関数を作成します。
3-1. Lambda関数の作成
- AWSマネジメントコンソールで「AWS Lambda」サービスにアクセスします
- 「関数の作成」ボタンをクリックします
- 以下の設定を行います:
- 関数名:
chat-message-moderator - ランタイム:
Python 3.9 - アーキテクチャ:
x86_64
- 関数名:
3-2. モデレーション機能の実装
Lambda関数のコードを以下のように実装します:
import json
import re
import boto3
def lambda_handler(event, context):
"""
チャットメッセージのモデレーション機能
不適切な内容を検知してフィルタリング
"""
# 禁止ワードリスト(実際の運用では外部設定ファイルから読み込み)
banned_words = [
'スパム', '広告', '宣伝', '詐欺',
'暴言', '誹謗', '中傷', '差別'
]
try:
# イベントからメッセージ内容を取得
message_content = event.get('messageContent', '')
user_id = event.get('userId', '')
# メッセージ長のチェック
if len(message_content) > 500:
return {
'statusCode': 400,
'body': json.dumps({
'action': 'reject',
'reason': 'メッセージが長すぎます'
})
}
# 禁止ワードのチェック
for word in banned_words:
if word in message_content:
return {
'statusCode': 400,
'body': json.dumps({
'action': 'reject',
'reason': f'不適切な内容が含まれています: {word}'
})
}
# URLスパムのチェック
url_pattern = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
if re.search(url_pattern, message_content):
return {
'statusCode': 400,
'body': json.dumps({
'action': 'reject',
'reason': 'URLの投稿は禁止されています'
})
}
# 連続投稿のチェック(簡易実装)
# 実際の運用では、DynamoDBなどでユーザーの投稿履歴を管理
# メッセージが適切な場合は承認
return {
'statusCode': 200,
'body': json.dumps({
'action': 'approve',
'message': message_content
})
}
except Exception as e:
print(f"Error in message moderation: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({
'action': 'reject',
'reason': 'システムエラーが発生しました'
})
}4. チャット機能付き視聴画面の実装
ステップ1で作成した視聴画面にチャット機能を追加します。
4-1. HTML構造の更新
既存のviewer.htmlを以下のように更新します:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ライブ配信視聴画面(チャット機能付き)</title>
<script src="https://player.live-video.net/1.46.0/amazon-ivs-player.min.js"></script>
<script src="https://unpkg.com/@amazon-ivs/chat-messaging@1.0.2/dist/amazon-ivs-chat-messaging.min.js"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1000.0.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}
.container {
max-width: 1200px;
margin: 0 auto;
display: flex;
gap: 20px;
}
.video-section {
flex: 2;
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.chat-section {
flex: 1;
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
display: flex;
flex-direction: column;
height: 600px;
}
#video-player {
width: 100%;
height: 450px;
background-color: #000;
border-radius: 8px;
}
.status {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
font-weight: bold;
}
.live { background-color: #d4edda; color: #155724; }
.offline { background-color: #f8d7da; color: #721c24; }
.login-form {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
}
.login-form input {
width: 100%;
padding: 8px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
.login-form button {
width: 100%;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.chat-messages {
flex: 1;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
margin-bottom: 10px;
background-color: #f9f9f9;
}
.chat-input {
display: flex;
gap: 10px;
}
.chat-input input {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.chat-input button {
padding: 8px 15px;
background-color: #28a745;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.message {
margin-bottom: 10px;
padding: 8px;
border-radius: 4px;
background-color: white;
}
.message .username {
font-weight: bold;
color: #007bff;
}
.message .timestamp {
font-size: 0.8em;
color: #666;
margin-left: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="video-section">
<h1>ライブ配信視聴画面</h1>
<div id="video-player"></div>
<div id="status" class="status offline">配信は開始されていません</div>
</div>
<div class="chat-section">
<h3>チャット</h3>
<!-- ログインフォーム -->
<div id="login-form" class="login-form">
<input type="text" id="username" placeholder="ユーザー名">
<input type="password" id="password" placeholder="パスワード">
<button onclick="login()">ログイン</button>
<button onclick="register()">新規登録</button>
</div>
<!-- チャット画面(ログイン後に表示) -->
<div id="chat-area" style="display: none; flex: 1; display: flex; flex-direction: column;">
<div id="chat-messages" class="chat-messages"></div>
<div class="chat-input">
<input type="text" id="message-input" placeholder="メッセージを入力..." maxlength="500">
<button onclick="sendMessage()">送信</button>
</div>
</div>
</div>
</div>
<script>
// AWS SDK設定
AWS.config.region = 'us-east-1'; // 適切なリージョンに変更
// IVSプレイヤーの初期化
const player = IVSPlayer.create();
player.attachHTMLVideoElement(document.getElementById('video-player'));
// 再生URL(ステップ1で取得したものに置き換え)
const playbackUrl = 'YOUR_PLAYBACK_URL_HERE';
// チャット関連の変数
let chatClient;
let currentUser = null;
const chatRoomArn = 'YOUR_CHAT_ROOM_ARN_HERE';
// 配信状態の監視
player.addEventListener(IVSPlayer.PlayerEventType.STATE_CHANGED, function(event) {
const statusElement = document.getElementById('status');
if (event.state === IVSPlayer.PlayerState.PLAYING) {
statusElement.textContent = '🔴 ライブ配信中';
statusElement.className = 'status live';
} else if (event.state === IVSPlayer.PlayerState.IDLE) {
statusElement.textContent = '配信は開始されていません';
statusElement.className = 'status offline';
}
});
// Cognitoユーザープール設定
const userPool = new AmazonCognitoIdentity.CognitoUserPool({
UserPoolId: 'YOUR_USER_POOL_ID',
ClientId: 'YOUR_CLIENT_ID'
});
// ログイン機能
async function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
if (!username || !password) {
alert('ユーザー名とパスワードを入力してください');
return;
}
const authenticationData = {
Username: username,
Password: password,
};
const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
const userData = {
Username: username,
Pool: userPool,
};
const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('ログイン成功');
currentUser = username;
initializeChat(result.getAccessToken().getJwtToken());
// ログインフォームを非表示、チャット画面を表示
document.getElementById('login-form').style.display = 'none';
document.getElementById('chat-area').style.display = 'flex';
},
onFailure: function(err) {
console.error('ログイン失敗:', err);
alert('ログインに失敗しました: ' + err.message);
},
});
}
// 新規登録機能
async function register() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
if (!username || !password) {
alert('ユーザー名とパスワードを入力してください');
return;
}
const attributeList = [];
userPool.signUp(username, password, attributeList, null, function(err, result) {
if (err) {
console.error('登録失敗:', err);
alert('登録に失敗しました: ' + err.message);
return;
}
alert('登録が完了しました。ログインしてください。');
console.log('ユーザー登録成功:', result.user);
});
}
// チャット機能の初期化
async function initializeChat(accessToken) {
try {
// チャットトークンの取得(実際の実装では、Lambda関数経由で取得)
const chatToken = await getChatToken(accessToken);
// チャットクライアントの初期化
const ChatRoom = window.IVSChatMessaging.ChatRoom;
chatClient = new ChatRoom({
regionOrUrl: 'us-east-1', // 適切なリージョンに変更
tokenProvider: () => Promise.resolve(chatToken)
});
// メッセージ受信イベントの設定
chatClient.addListener('message', (message) => {
displayMessage(message);
});
// チャットルームに接続
await chatClient.connect();
console.log('チャットに接続しました');
} catch (error) {
console.error('チャット初期化エラー:', error);
alert('チャットの初期化に失敗しました');
}
}
// チャットトークンの取得(実際の実装では、Lambda関数から取得)
async function getChatToken(accessToken) {
// この部分は実際の実装では、Lambda関数を呼び出してトークンを取得
// 今回はサンプル用の固定値
return 'SAMPLE_CHAT_TOKEN';
}
// メッセージ送信機能
async function sendMessage() {
const messageInput = document.getElementById('message-input');
const messageContent = messageInput.value.trim();
if (!messageContent) {
return;
}
try {
await chatClient.sendMessage(messageContent);
messageInput.value = '';
} catch (error) {
console.error('メッセージ送信エラー:', error);
alert('メッセージの送信に失敗しました');
}
}
// メッセージ表示機能
function displayMessage(message) {
const messagesContainer = document.getElementById('chat-messages');
const messageElement = document.createElement('div');
messageElement.className = 'message';
const timestamp = new Date().toLocaleTimeString();
messageElement.innerHTML = `
<span class="username">${message.sender.userId}</span>
<span class="timestamp">${timestamp}</span>
<div>${message.content}</div>
`;
messagesContainer.appendChild(messageElement);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// Enterキーでメッセージ送信
document.getElementById('message-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
// 配信の読み込み
player.load(playbackUrl);
</script>
</body>
</html>【解説】IVS ChatとWebSocketの活用
IVS Chatは内部的にWebSocket接続を使用してリアルタイム通信を実現しています。従来のHTTPポーリング方式と比較して、レイテンシが大幅に改善され、サーバー負荷も軽減されます。
チャットメッセージは配信と同期して表示されるため、視聴者は配信者の行動に対してリアルタイムで反応できます。これにより、従来の一方向配信から双方向のインタラクティブな配信に進化します。
メッセージのモデレーション機能により、健全なコミュニティ環境を維持しながら、活発な交流を促進できます。
このステップで何をしたのか
このステップでは、Amazon IVS Chatを使用してライブ配信アプリケーションにリアルタイムチャット機能を追加しました。具体的には、Cognitoユーザープールによるチャット参加者の認証システム、IVS Chatルームの作成と設定、Lambda関数によるメッセージモデレーション機能を実装しました。また、視聴画面にチャット機能を統合し、配信を見ながらリアルタイムでコメント交換ができる環境を構築しました。
ライブ配信アプリでどのような影響があるのか
この構成により、ライブ配信アプリケーションは単なる一方向配信から、視聴者との双方向コミュニケーションが可能なインタラクティブな配信プラットフォームに進化しました。視聴者は配信を見ながらリアルタイムでコメントを投稿でき、他の視聴者や配信者と交流できます。メッセージモデレーション機能により、健全なコミュニティ環境が維持され、スパムや不適切な投稿から配信を守ることができます。これは、テレビ番組に視聴者参加機能を追加したような効果で、エンゲージメントの大幅な向上が期待できます。
技術比較まとめ表
| 技術領域 | AWS | オンプレミス |
|---|---|---|
| リアルタイム通信 | IVS Chat + WebSocket 配信特化の低遅延チャット | WebSocket + Socket.io 汎用リアルタイム通信の実装 |
| ユーザー認証 | Amazon Cognito マネージド認証サービス | 独自認証システム データベース + セッション管理 |
| メッセージ処理 | Lambda + IVS Chat サーバーレスでスケーラブル | Node.js/PHP サーバー 常時稼働サーバーが必要 |
学習において重要な技術的違い
1. チャットと配信の同期
- AWS:IVS ChatがIVS配信と自動同期、配信遅延に合わせてチャット表示
- オンプレミス:手動でタイムスタンプ管理、配信とチャットの同期実装が複雑
2. スケーラビリティの対応
- AWS:IVS Chatが自動スケーリング、同時チャット参加者数の制限なし
- オンプレミス:WebSocketサーバーの負荷分散とスケーリング設計が必要
3. メッセージモデレーション
- AWS:Lambdaによるサーバーレス処理、Amazon Comprehendとの連携可能
- オンプレミス:専用サーバーでのフィルタリング処理、機械学習APIとの連携が複雑
4. 運用・監視
- AWS:CloudWatchによる自動監視、チャット品質メトリクスを自動収集
- オンプレミス:独自監視システムの構築、ログ解析とアラート設定が必要
実践チェック:画面キャプチャで証明しよう
下記のチェック項目について、実際にAWSマネジメントコンソールで設定ができていることを確認し、各項目ごとに該当画面のスクリーンショットを撮影して提出してください。
-
Amazon Cognitoユーザープールが作成され、適切な設定(サインインオプション、パスワードポリシー)が行われている
-
Cognitoアプリクライアントが作成され、適切な認証フロー(ALLOW_USER_PASSWORD_AUTH、ALLOW_REFRESH_TOKEN_AUTH)が設定されている
-
Amazon IVS Chatルームが作成され、適切な設定(メッセージ長、メッセージレート、ログ設定)が行われている
-
Lambda関数(chat-message-moderator)が作成され、メッセージモデレーション機能が実装されている
-
チャット機能付き視聴画面でユーザー登録・ログイン機能が正常に動作している
-
チャット画面でメッセージの送信・受信がリアルタイムで動作している
提出方法: 各項目ごとにスクリーンショットを撮影し、まとめて提出してください。 ファイル名やコメントで「どの項目か」が分かるようにしてください。
構成図による理解度チェック
ステップ1の構成図に、このステップで作成したリソースを追記して、現在のインフラ構成を完成させましょう。
なぜ構成図を更新するのか?
ライブ配信システムにチャット機能が追加されることで、データフローが複雑になります。配信データの流れに加えて、チャットメッセージの流れ、ユーザー認証の流れを理解することが重要です。構成図を更新することで、各コンポーネントがどのように連携してリアルタイムコミュニケーションを実現しているかを視覚的に把握できます。
- 認証フローの理解: Cognitoによるユーザー認証からチャット参加までの流れ
- メッセージフローの理解: チャット投稿からモデレーション、配信との同期表示まで
- リアルタイム通信の理解: WebSocket接続によるリアルタイムメッセージ交換
構成図の書き方
ステップ1で作成した構成図をベースに、以下のリソースを追記してみましょう。
- Amazon Cognito: ユーザー認証・管理、配信者と視聴者のアクセス制御
- Amazon IVS Chat: チャットルーム、リアルタイムメッセージ交換
- AWS Lambda: メッセージモデレーション、不適切投稿のフィルタリング
- WebSocket接続: 視聴者とチャットルーム間のリアルタイム通信経路
💡 ヒント: 配信データフロー(一方向)とチャットメッセージフロー(双方向)を異なる色や線種で表現し、リアルタイム性の違いを明確にしましょう。
理解度チェック:なぜ?を考えてみよう
AWSの各リソースや設計には、必ず”理由”や”目的”があります。 下記の「なぜ?」という問いに自分なりの言葉で答えてみてください。 仕組みや設計意図を自分で説明できることが、真の理解につながります。 ぜひ、単なる暗記ではなく「なぜそうなっているのか?」を意識して考えてみてください。
Q. なぜIVS Chatでは配信との同期機能が重要なのでしょうか?通常のWebチャットシステムとの違いを含めて説明してください。
Q. なぜチャットメッセージのモデレーション機能をLambda関数で実装するのでしょうか?常時稼働するサーバーではなくサーバーレスアーキテクチャを選択する理由を説明してください。
Q. なぜCognitoでクライアントシークレットを無効にするのでしょうか?Webアプリケーションにおけるセキュリティの観点から説明してください。
今回のステップで利用したAWSサービス名一覧
- Amazon IVS Chat:ライブ配信に特化したリアルタイムチャット、配信との同期機能を提供
- Amazon Cognito:ユーザー認証・管理、チャット参加者の身元確認とアクセス制御
- AWS Lambda:メッセージモデレーション、サーバーレスでのチャット品質管理
- WebSocket:リアルタイム双方向通信、チャットメッセージの即座な配信