目次

Amazon Interactive Video Service (IVS) v2.0 完全ガイド 2026

概要

Amazon Interactive Video Service(IVS) は、低レイテンシのライブストリーミングサービスであり、Twitch の技術をベースに 300 ミリ秒以下の超低遅延ライブ配信を提供します。ゲームライブ配信・ライブショッピング・リアルタイムオークション・バーチャルイベント・ライブホーム販売などのインタラクティブなライブ体験を構築できます。2024-2026年間に IVS Chat・IVS Real-Time Streaming(WebRTC ベース)・360度コンテンツ対応を拡張。

解決する課題

超低遅延によるインタラクション実現

  • YouTube Live・Twitch は 5-30 秒の遅延がありチャット双方向性が成立しないが、IVS は 300ms 以下で配信者とリアルタイムチャットが可能

自動マルチビットレート配信

  • トランスコード・CDN・スケーリングを自動管理、5秒で数万視聴者対応可能

タイムドメタデータ同期

  • ライブ映像に同期したメタデータ(商品情報・投票・クイズ)を埋め込んでインタラクティブ体験

リアルタイムチャット統合

  • IVS Chat で最大 10,000 同時接続チャットルーム、Lambda でメッセージモデレーション

低コスト・マネージド

  • インフラ管理不要でスケーラビリティを自動提供、従量課金で無駄を排除

アーキテクチャ全体

配信者(ストリーマー)層:
    PC(OBS / FFmpeg)or スマートフォン
    ├─ RTMP/RTMPS(インジェスト)
    │  rtmps://a1bcdef34ghij.global-contribute.live-video.net:443/app/
    │  Stream Key: sk_xxxxx
    └─ Bitrate: 3-8 Mbps, Resolution: 1080p, FPS: 30-60

IVS インジェスト層:
    ┌────────────────────────────────────────────────────┐
    │  IVS Ingest(Twitch インフラベース)               │
    │  ├─ RTMP/RTMPS エンコーダー対応                   │
    │  ├─ SRT(Secure Reliable Transport)対応         │
    │  ├─ DASH/HLS への自動トランスコード              │
    │  ├─ マルチビットレート(ABR)生成                │
    │  └─ 冗長性・自動フェイルオーバー                 │
    └────────────────────────────────────────────────────┘

ライブ配信サービス層:
    ┌────────────────────────────────────────────────────┐
    │  IVS Service Plane                                 │
    │  ├─ Live-to-VOD 記録(S3 自動保存)              │
    │  ├─ Timed Metadata(タイムコード付きメタデータ)│
    │  ├─ Recording Configuration(品質設定)         │
    │  ├─ Playback Authorization(署名付き再生 URL)  │
    │  └─ Thumbnail Auto-Generation                    │
    └────────────────────────────────────────────────────┘

チャット層:
    ┌────────────────────────────────────────────────────┐
    │  IVS Chat (WebSocket)                              │
    │  ├─ リアルタイムメッセージ配信                    │
    │  ├─ Lambda メッセージレビューハンドラー          │
    │  ├─ Max 10,000 同時接続                          │
    │  └─ メッセージ履歴保存(CloudWatch Logs)       │
    └────────────────────────────────────────────────────┘

Real-Time Streaming 層(IVS Stages):
    ┌────────────────────────────────────────────────────┐
    │  IVS Real-Time Streaming (WebRTC)                  │
    │  ├─ Max 12 ホスト(カメラ・画面共有)           │
    │  ├─ Max 10,000 視聴者                            │
    │  ├─ Latency: <300ms                               │
    │  └─ Composition Engine(レイアウト自動生成)     │
    └────────────────────────────────────────────────────┘

視聴者(プレーヤー)層:
    Web / iOS / Android / Smart TV
    ├─ IVS Player SDK(HLS/DASH)
    │  ↓ CloudFront CDN(自動統合)
    ├─ 遅延: <5 秒(Low Latency)
    ├─ 解像度: 1080p, 720p, 480p, 360p(自動適応)
    └─ 同期メタデータ受信(Timed Metadata)

外部統合:
    Lambda → メッセージモデレーション・メトリクス集約
    EventBridge → セッション開始/終了イベント
    S3 → ライブ配信アーカイブ保存
    CloudWatch → 監視・ログ

チャンネルの作成と設定

# IVS チャンネル作成(基本)
aws ivs create-channel \
  --name my-livestream \
  --type STANDARD \              # BASIC / STANDARD / ADVANCED_HD
  --latency-mode ULTRA_LOW \     # NORMAL(6-12s) / LOW(3s) / ULTRA_LOW(300ms)
  --authorized true \            # PlaybackAuthorization 必須
  --tags Key=Environment,Value=Production Key=App,Value=LiveCommerce

# チャンネル確認
aws ivs get-channel \
  --arn arn:aws:ivs:us-east-1:123456789012:channel/AbCdEfGh

# ストリームキー作成(配信者用)
aws ivs create-stream-key \
  --channel-arn arn:aws:ivs:us-east-1:123456789012:channel/AbCdEfGh

# レコーディング設定(Live-to-VOD)
aws ivs create-recording-configuration \
  --destination-configuration '[
    {
      "S3": {
        "BucketName": "my-ivs-archive-bucket",
        "RecordingPathPrefix": "live-archive/2026/",
        "EncryptionKey": {
          "Arn": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
        }
      }
    }
  ]' \
  --thumbnail-configuration '{"RecordingMode": "INTERVAL", "TargetIntervalSeconds": 60}'

# チャンネルにレコーディング設定をアタッチ
aws ivs update-channel \
  --arn arn:aws:ivs:us-east-1:123456789012:channel/AbCdEfGh \
  --recording-configuration-arn arn:aws:ivs:us-east-1:123456789012:recording-configuration/xxxxx

# Playback Authorization キーペア(署名付き再生 URL)
aws ivs create-playback-key-pair \
  --name my-playback-key \
  --tags Key=Environment,Value=Production

Web での再生(IVS Player)

<!DOCTYPE html>
<html>
<head>
    <title>IVS Low-Latency Live Stream</title>
    <style>
        body { margin: 0; background: #1a1a1a; color: #fff; font-family: Arial, sans-serif; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        video { width: 100%; height: auto; background: #000; border-radius: 8px; }
        .metadata-display { background: rgba(255, 255, 255, 0.1); padding: 15px; margin-top: 15px; border-radius: 8px; }
        .chat-container { margin-top: 20px; height: 400px; background: #2a2a2a; border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }
        .chat-messages { flex: 1; overflow-y: auto; padding: 10px; }
        .chat-message { margin: 5px 0; padding: 8px; background: rgba(255, 255, 255, 0.05); border-left: 3px solid #ff6b35; border-radius: 4px; font-size: 14px; }
        .chat-input { display: flex; gap: 10px; padding: 10px; border-top: 1px solid #444; }
        .chat-input input { flex: 1; padding: 10px; background: #3a3a3a; color: #fff; border: none; border-radius: 4px; }
        .chat-input button { padding: 10px 20px; background: #ff6b35; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
    </style>
</head>
<body>
    <div class="container">
        <h1>IVS Low-Latency Live Stream</h1>
        <video id="video-player" playsinline autoplay muted></video>

        <div class="metadata-display" id="metadata-display">
            <strong>Timed Metadata:</strong>
            <div id="metadata-content">Waiting for metadata...</div>
        </div>

        <div class="chat-container">
            <div class="chat-messages" id="chat-messages"></div>
            <div class="chat-input">
                <input 
                    type="text" 
                    id="chat-input" 
                    placeholder="Type your message..."
                    autocomplete="off"
                >
                <button onclick="sendChatMessage()">Send</button>
            </div>
        </div>
    </div>

    <!-- IVS Player SDK -->
    <script src="https://player.live-video.net/1.26.0/amazon-ivs-player.min.js"></script>

    <script>
        const IVSPlayer = window.IVSPlayer;
        const PlayerState = IVSPlayer.PlayerState;
        const PlayerEventType = IVSPlayer.PlayerEventType;

        // バックエンドからライブストリーム URL を取得
        async function initializePlayer() {
            try {
                // 署名付き再生 URL をバックエンドから取得
                const response = await fetch('/api/get-playback-url', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        channelArn: 'arn:aws:ivs:us-east-1:123456789012:channel/AbCdEfGh'
                    })
                });

                const data = await response.json();
                const playbackUrl = data.playback_url;

                // IVS Player インスタンス作成
                if (IVSPlayer.isPlayerSupported) {
                    const player = IVSPlayer.create();
                    player.attachHTMLVideoElement(document.getElementById('video-player'));

                    // ライブストリーム読み込み
                    player.load(playbackUrl);
                    player.play();

                    // プレイヤーイベント
                    player.addEventListener(PlayerEventType.STATE_CHANGE, (e) => {
                        console.log('Player state:', e.state);
                        if (e.state === PlayerState.PLAYING) {
                            console.log('✓ Live stream started');
                        } else if (e.state === PlayerState.BUFFERING) {
                            console.log('Buffering...');
                        }
                    });

                    // Timed Metadata(タイムコード付きメタデータ)
                    player.addEventListener(PlayerEventType.TEXT_METADATA_CUE, (cue) => {
                        try {
                            const metadata = JSON.parse(cue.text);
                            handleTimedMetadata(metadata);
                        } catch (err) {
                            console.error('Error parsing metadata:', err);
                        }
                    });

                    // エラーハンドリング
                    player.addEventListener(PlayerEventType.ERROR, (err) => {
                        console.error('Player error:', err);
                    });

                    // チャット接続
                    connectToChat(data.channel_arn);

                } else {
                    console.error('IVS Player not supported');
                }
            } catch (error) {
                console.error('Initialization error:', error);
            }
        }

        // Timed Metadata 処理(商品情報・投票・クイズ等)
        function handleTimedMetadata(metadata) {
            const display = document.getElementById('metadata-content');

            if (metadata.type === 'product') {
                // ライブショッピング: 商品情報表示
                display.innerHTML = `
                    <strong>🛍️ Featured Product</strong>
                    <p>
                        Name: ${metadata.productName}<br>
                        Price: $${metadata.price}<br>
                        Discount: ${metadata.discount}%
                    </p>
                    <button onclick="purchaseProduct('${metadata.productId}')">Buy Now</button>
                `;
            } else if (metadata.type === 'poll') {
                // 投票
                display.innerHTML = `
                    <strong>📊 Live Poll</strong>
                    <p>${metadata.question}</p>
                    ${metadata.options.map((opt, i) => `
                        <button onclick="votePoll(${i})">${opt} (${metadata.votes?.[i] || 0})</button>
                    `).join('')}
                `;
            } else if (metadata.type === 'announcement') {
                // アナウンスメント
                display.innerHTML = `
                    <strong>📢 Announcement</strong>
                    <p>${metadata.message}</p>
                `;
            }
        }

        // IVS Chat 接続
        async function connectToChat(channelArn) {
            try {
                // チャットルーム作成(バックエンド)
                const response = await fetch('/api/create-chat-session', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        channelArn: channelArn,
                        userId: 'viewer-' + Math.random().toString(36).substr(2, 9),
                        userName: 'Viewer'
                    })
                });

                const { token, roomArn } = await response.json();

                // WebSocket 接続
                const ws = new WebSocket(
                    `wss://${roomArn.split(':')[5]}.ivschat.live-video.net`
                );

                ws.onopen = () => {
                    console.log('✓ Chat connected');
                    // 認証メッセージ送信
                    ws.send(JSON.stringify({
                        type: 'CONNECT',
                        token: token
                    }));
                };

                ws.onmessage = (event) => {
                    const message = JSON.parse(event.data);
                    if (message.type === 'MESSAGE') {
                        addChatMessage(message.userDisplayName, message.content);
                    }
                };

                ws.onerror = (err) => console.error('Chat error:', err);
                ws.onclose = () => console.log('Chat disconnected');

                // グローバル WebSocket 参照(メッセージ送信用)
                window.chatWs = ws;

            } catch (error) {
                console.error('Chat connection error:', error);
            }
        }

        // チャットメッセージ送信
        function sendChatMessage() {
            const input = document.getElementById('chat-input');
            const message = input.value.trim();

            if (message && window.chatWs) {
                window.chatWs.send(JSON.stringify({
                    type: 'SEND_MESSAGE',
                    content: message
                }));
                input.value = '';
            }
        }

        // チャットメッセージ表示
        function addChatMessage(userName, content) {
            const messagesDiv = document.getElementById('chat-messages');
            const messageEl = document.createElement('div');
            messageEl.className = 'chat-message';
            messageEl.innerHTML = `<strong>${userName}:</strong> ${escapeHtml(content)}`;
            messagesDiv.appendChild(messageEl);
            messagesDiv.scrollTop = messagesDiv.scrollHeight;
        }

        function escapeHtml(text) {
            const map = {
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#039;'
            };
            return text.replace(/[&<>"']/g, m => map[m]);
        }

        function purchaseProduct(productId) {
            alert('Product ' + productId + ' added to cart!');
        }

        function votePoll(optionIndex) {
            console.log('Voted for option:', optionIndex);
        }

        // ページロード時に初期化
        document.addEventListener('DOMContentLoaded', initializePlayer);

        // Enter キーでメッセージ送信
        document.getElementById('chat-input')?.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') sendChatMessage();
        });
    </script>
</body>
</html>

バックエンド API(Python FastAPI)

import boto3
import json
from datetime import datetime, timedelta
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
import hmac
import hashlib
import base64

app = FastAPI()
ivs_client = boto3.client('ivs', region_name='us-east-1')
ivs_chat_client = boto3.client('ivschat', region_name='us-east-1')
lambda_client = boto3.client('lambda')

# Playback Authorization キー(署名付き再生 URL 生成用)
PLAYBACK_KEY_ARN = 'arn:aws:ivs:us-east-1:123456789012:playback-key-pair/xxxxx'
PLAYBACK_KEY_PRIVATE = """-----BEGIN RSA PRIVATE KEY-----
... (秘密鍵の内容)
-----END RSA PRIVATE KEY-----"""

@app.post('/api/get-playback-url')
async def get_playback_url(channel_arn: str):
    """署名付き再生 URL を生成"""
    try:
        # チャンネル情報取得
        response = ivs_client.get_channel(arn=channel_arn)
        channel = response['channel']
        playback_url_base = channel['playbackUrl']

        # Playback Authorization が有効か確認
        if channel.get('authorized'):
            # JWT トークンを生成(署名付き再生 URL)
            expiration = int((datetime.now() + timedelta(hours=24)).timestamp())
            
            # Playback Authorization トークン生成
            payload = {
                'sub': 'user-demo',
                'exp': expiration,
                'iat': int(datetime.now().timestamp()),
                'aws:channel-arn': channel_arn
            }
            
            # 実際には AWS Lambda で署名生成することを推奨
            token = generate_playback_token(payload)
            playback_url = f"{playback_url_base}?token={token}"
        else:
            playback_url = playback_url_base

        return JSONResponse({
            'success': True,
            'playback_url': playback_url,
            'channel_arn': channel_arn,
            'playback_url_base': playback_url_base,
            'latency_mode': channel.get('latencyMode')
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/api/put-metadata')
async def put_metadata(channel_arn: str, metadata: dict):
    """Timed Metadata をライブストリームに埋め込む"""
    try:
        # メタデータが有効か検証
        metadata_json = json.dumps(metadata)
        
        # IVS へメタデータ送信
        ivs_client.put_metadata(
            ChannelArn=channel_arn,
            Metadata=metadata_json
        )

        return JSONResponse({
            'success': True,
            'metadata_type': metadata.get('type'),
            'timestamp': datetime.now().isoformat()
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/api/create-chat-session')
async def create_chat_session(channel_arn: str, user_id: str, user_name: str):
    """IVS Chat セッション作成"""
    try:
        # チャットルーム作成(存在しない場合)
        # 実装では Channel ARN から Chat Room ARN を導出
        room_arn = channel_arn.replace(':channel/', ':room/')

        # チャット認証トークン生成
        token_response = ivs_chat_client.create_chat_token(
            RoomIdentifier=room_arn,
            UserId=user_id,
            Capabilities=['SEND_MESSAGE', 'DELETE_MESSAGE'],
            SessionDurationInMinutes=480,  # 8 時間
            Attributes={
                'username': user_name,
                'user_type': 'viewer',
                'moderator': 'false'
            }
        )

        return JSONResponse({
            'success': True,
            'token': token_response['Token'],
            'roomArn': room_arn,
            'tokenExpiration': token_response['TokenExpiration']
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post('/api/moderate-message')
async def moderate_message(room_arn: str, message_id: str, action: str):
    """チャットメッセージモデレーション(削除)"""
    try:
        if action == 'DELETE':
            ivs_chat_client.delete_message(
                RoomIdentifier=room_arn,
                Id=message_id
            )
        
        return JSONResponse({'success': True})

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

def generate_playback_token(payload: dict) -> str:
    """Playback Authorization トークン生成(簡略版)"""
    # 本番環境では AWS Signature Version 4 で署名
    import jwt
    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.backends import default_backend

    key = serialization.load_pem_private_key(
        PLAYBACK_KEY_PRIVATE.encode(),
        password=None,
        backend=default_backend()
    )

    token = jwt.encode(payload, key, algorithm='RS256')
    return token

IVS Real-Time Streaming(WebRTC ベース)

# ホスト・視聴者が同時参加する低遅延ステージ

import boto3
from fastapi import FastAPI

app = FastAPI()
ivs_realtime = boto3.client('ivs-realtime', region_name='us-east-1')

@app.post('/api/create-stage')
async def create_stage(stage_name: str):
    """ステージ作成(最大 12 ホスト + 10,000 視聴者)"""
    try:
        response = ivs_realtime.create_stage(
            name=stage_name,
            participantTokenConfiguration={
                'Capabilities': ['PUBLISH', 'SUBSCRIBE'],
                'Duration': 14400  # 4 時間
            }
        )

        return {
            'success': True,
            'stage_arn': response['stage']['arn'],
            'stage_id': response['stage']['stageId']
        }

    except Exception as e:
        return {'success': False, 'error': str(e)}

@app.post('/api/create-participant-token')
async def create_participant_token(
    stage_arn: str,
    user_id: str,
    user_type: str  # 'host' or 'viewer'
):
    """参加者トークン生成"""
    try:
        capabilities = []
        if user_type == 'host':
            capabilities = ['PUBLISH', 'SUBSCRIBE']  # ホスト: 配信 + 受信
        else:
            capabilities = ['SUBSCRIBE']  # 視聴者: 受信のみ

        response = ivs_realtime.create_participant_token(
            stageArn=stage_arn,
            userId=user_id,
            Capabilities=capabilities,
            Duration=14400
        )

        return {
            'success': True,
            'token': response['participantToken']['token'],
            'expiration': response['participantToken']['expirationTime']
        }

    except Exception as e:
        return {'success': False, 'error': str(e)}

@app.get('/api/stage-events/{stage_arn}')
async def get_stage_events(stage_arn: str):
    """ステージイベント取得(参加者の出入り)"""
    try:
        response = ivs_realtime.list_stage_events(
            stageArn=stage_arn,
            maxResults=50
        )

        return {
            'events': response.get('events', []),
            'next_token': response.get('nextToken')
        }

    except Exception as e:
        return {'error': str(e)}

Lambda メッセージモデレーション

# IVS Chat のメッセージを自動検査(不適切な内容を削除)

def message_review_handler(event, context):
    """
    IVS Chat メッセージレビューハンドラー
    
    event:
    {
        "roomArn": "arn:aws:ivschat:...",
        "messageId": "msg-123456",
        "sender": {"userId": "user-001"},
        "message": {"content": "..."},
        "timestamp": 1234567890
    }
    """
    
    message_content = event['message']['content']
    
    # 1. 不適切な言葉フィルター(カスタム辞書)
    banned_words = [
        'badword1', 'badword2', 'spam_keyword'
    ]
    
    for word in banned_words:
        if word.lower() in message_content.lower():
            return {
                'result': 'DELETE'  # メッセージ削除
            }
    
    # 2. URL スパム検出
    import re
    url_pattern = r'https?://[^\s]+'
    urls = re.findall(url_pattern, message_content)
    if len(urls) > 2:
        return {'result': 'DELETE'}
    
    # 3. キャップスロック過多(大文字ばかり)
    uppercase_ratio = sum(1 for c in message_content if c.isupper()) / max(len(message_content), 1)
    if uppercase_ratio > 0.8:
        return {'result': 'DELETE'}
    
    # 4. 過度なリピート
    if len(set(message_content)) < len(message_content) * 0.1:
        return {'result': 'DELETE'}
    
    # OK
    return {
        'result': 'ALLOW'
    }

料金体系(2026年)

項目 料金 備考
ライブ配信(STANDARD) $0.20/時間/配信 インジェスト時間
視聴(HD 1080p) $0.0025/GB ダウンロード GB
視聴(SD 480p) $0.0015/GB 低帯域向け
Real-Time Streaming $0.0042/分/参加者 ホスト・視聴者含む
IVS Chat $0.20/千メッセージ メッセージ数ベース
Recording(Live-to-VOD) $0.005/分 S3 保存料金別途

比較: IVS vs 競合

観点 IVS Twitch YouTube Live Wowza Streaming Cloud
遅延 300ms 以下 2-30 秒 5-30 秒 2-15 秒
インタラクション ✓ タイムドメタデータ・Chat 限定 Chat のみ 限定
Real-Time Streaming ✓ WebRTC(<300ms) × × ×
価格 従量課金(低コスト) 収益シェア 収益シェア 月額 $15-199
カスタマイズ ✓ API 完全開放 × ×
独立配信 × 要 YouTube Partner
推奨用途 ライブショッピング・イベント ゲーム配信 大規模配信 放送品質

ベストプラクティス

1. インジェスト設定(OBS)

Server: rtmps://a1bcdef34ghij.global-contribute.live-video.net:443/app/
Stream Key: sk_xxxxx
Video Bitrate: 4000 kbps (1080p/30fps)
Audio Bitrate: 128 kbps
Encoder: H.264 (x264)

2. Timed Metadata 設計

{
  "type": "product",
  "productId": "SKU-12345",
  "productName": "Limited Edition Gaming Headset",
  "price": 199.99,
  "discount": 15,
  "link": "https://shop.example.com/product/SKU-12345"
}

3. チャット モデレーション

  • 自動フィルター: Lambda で不適切用語・スパム自動削除
  • 手動モデレーション: Dashboard で リアルタイム監視・メッセージ削除
  • ユーザーレート制限: 1秒 5 メッセージまで(デフォルト)

4. Real-Time 用ネットワーク

  • 上りネット: 最小 2.5 Mbps(ホスト)、0.5 Mbps(視聴者)
  • 下りネット: 最小 5 Mbps(ホスト・視聴者共通)
  • 遅延目標: <500ms LAN、<2s インターネット

設計チェックリスト

  • [ ] Channel 作成済み・latency mode = ULTRA_LOW(300ms)
  • [ ] Stream Key を安全に配布(環境変数・シークレットマネージャー)
  • [ ] Recording Configuration 設定済み(S3 버킷)
  • [ ] Playback Authorization キーペア生成済み(署名付き再生 URL)
  • [ ] IVS Player SDK で HLS 再生・Timed Metadata 受信実装済み
  • [ ] IVS Chat で WebSocket 接続・メッセージ送受信実装済み
  • [ ] Lambda メッセージレビューハンドラー デプロイ済み
  • [ ] CloudWatch でインジェストビットレート・視聴者数監視中
  • [ ] Real-Time Streaming(Stage)テスト完了(WebRTC <300ms)
  • [ ] DDoS: CloudFront WAF + Shield Standard 有効化
  • [ ] コスト: 月間推定出力 GB・メッセージ数から費用試算済み

実装パターン: ライブショッピング

要件: 1時間のライブ配信・商品メタデータ同期・リアルタイムチャット・1000 同時視聴者

# バックエンド: Flask + Celery

from flask import Flask, request, jsonify
from celery import Celery
import boto3

app = Flask(__name__)
ivs = boto3.client('ivs', region_name='us-east-1')
celery_app = Celery(app.name)

# ライブ配信セッション管理
live_sessions = {}

@app.post('/api/start-live-shopping')
def start_live_shopping():
    """ライブショッピング配信開始"""
    
    channel_arn = 'arn:aws:ivs:us-east-1:123456789012:channel/LiveShop'
    
    # 配信情報を DynamoDB に保存
    session_id = f"session-{int(time.time())}"
    live_sessions[session_id] = {
        'channel_arn': channel_arn,
        'start_time': datetime.now(),
        'status': 'LIVE',
        'products': []
    }
    
    return jsonify({'session_id': session_id, 'status': 'started'})

@app.post('/api/feature-product')
def feature_product():
    """商品をライブ配信に同期"""
    data = request.json
    session_id = data['session_id']
    product = {
        'id': data['product_id'],
        'name': data['product_name'],
        'price': data['price'],
        'discount': data.get('discount', 0),
        'image_url': data['image_url']
    }
    
    # Timed Metadata で配信に埋め込む
    send_metadata_task.delay(
        live_sessions[session_id]['channel_arn'],
        {
            'type': 'product',
            'productId': product['id'],
            'productName': product['name'],
            'price': product['price'],
            'discount': product['discount'],
            'imageUrl': product['image_url']
        }
    )
    
    return jsonify({'success': True})

@celery_app.task
def send_metadata_task(channel_arn, metadata):
    """メタデータ送信タスク"""
    try:
        ivs.put_metadata(
            ChannelArn=channel_arn,
            Metadata=json.dumps(metadata)
        )
        return {'success': True}
    except Exception as e:
        return {'error': str(e)}

@app.post('/api/end-live-shopping')
def end_live_shopping():
    """ライブ配信終了"""
    session_id = request.json['session_id']
    
    # セッション終了(S3 に自動記録)
    live_sessions[session_id]['status'] = 'ENDED'
    live_sessions[session_id]['end_time'] = datetime.now()
    
    return jsonify({'success': True})

@app.get('/api/live-metrics/{session_id}')
def get_live_metrics(session_id):
    """ライブ配信メトリクス取得"""
    channel_arn = live_sessions[session_id]['channel_arn']
    
    response = ivs.get_stream(
        ChannelArn=channel_arn
    )
    
    stream = response.get('stream')
    if stream:
        return jsonify({
            'viewers': stream.get('viewerCount', 0),
            'health': stream.get('health', {}),
            'ingest_bitrate': stream.get('health', {}).get('bitrate'),
            'encoding': stream.get('health', {}).get('encoding')
        })
    
    return jsonify({'error': 'No active stream'})

最新動向(2024-2026)

  • Real-Time Streaming 拡張: WebRTC ベースの <300ms ストリーミング実装完了(2024)
  • IVS Chat 統計: メッセージ分析・視聴者エンゲージメント追跡機能(2025)
  • AI モデレーション: 機械学習ベースの不適切コンテンツ自動検出(2026 予定)
  • Dolby Atmos: サラウンドサウンド配信対応(検討中)

まとめ

Amazon IVS は 「超低遅延(300ms)のインタラクティブライブストリーミングプラットフォーム」。Twitch 技術ベースの信頼性・タイムドメタデータによるライブショッピング・IVS Chat と Real-Time Streaming を統合し、リアルタイム双方向体験を実現。

ライブショッピング・ゲーム配信・バーチャルイベント・オークション等の B2C インタラクティブアプリケーションに最適。マネージドサービスで インフラ管理不要、従量課金で低コスト。