AWS でライブ配信システムを構築する（５）MediaLive の設定 その２

#1. この記事で扱う内容
この記事では、AWS の各種サービスを使用してライブ配信システムを構築する方法について紹介します。

今回は、MediaLive でアーカイブを出力する方法、 Railsアプリから Channel を操作する方法、ライブ配信の遅延軽減法について紹介します。

記載した内容は、私が開発中に試行錯誤した結果であって、使用する環境や目的によっては必ずしも最善ではないかもしれませんので、その点をご注意ください。

##1-1. システム構成
「[（１）概要](https://qiita.com/mas_yam/items/9d4f491b3a1e310476f0)」に掲載のシステム構成図を参照してください。

##1-2. 環境
- AWS Elemental MediaLive（東京リージョン）
- CentOS7
- Rails 5.2.3
- Ruby 2.4.1

##1-3. 前提
- AWS のアカウントを取得済みであること
- S3 にバケットを作成してアクセス権等の設定を行えること
- 前回までの記事を参考に、MediaLive を使用したライブ配信の基本的な設定が完了していること
- Rails アプリの基本的なコーディング方法を理解していること

#2. MediaLive でアーカイブを出力する方法
MediaLive では、リアルタイムのライブ配信だけでなく、ライブ配信した動画をアーカイブとして保存して、後でオンデマンド配信することができます。

アーカイブを作成する方法はいくつかありますが、ここでは以下の2つの方法について紹介します。

- Archive output group を使用する方法
- HLS output group を使用する方法

##2-1. Archive output group を使用する方法
Archive output group は S3 にアーカイブを保存するために用意されている出力タイプです。

アーカイブファイルを保存するための S3 のバケットを事前に用意しておいてください。

参照

- [Creating an Archive Output Group - AWS Elemental MediaLive](https://docs.aws.amazon.com/ja_jp/medialive/latest/ug/creating-archive-output-group.html)
- [AWS Elemental MediaLiveのアーカイブ出力機能でライブ配信と同時にファイルにも映像を書き出す ｜ DevelopersIO](https://dev.classmethod.jp/cloud/aws/aws-elemental-medialive-archive-output/)

**(1)**
MediaLive のダッシュボードを開き、すでに作成してある Channel を選択して、「Action」から「Edit」を選びます。

<img width="500" alt="fig48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/34f76fec-0e50-f8eb-4250-9072e93a8d57.png">

**(2)**
左側のメニューにある「Output groups」欄の「Add」ボタンを押して、表示された「Add output group」画面で、「Archive」を選択して「Confirm」ボタンを押します。

<img width="500" alt="fig42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/7319cfa3-4e7b-e82a-936e-ef6c513e054a.png">

**(3)**
Archive output group の設定画面が開くので、以下のように入力します。

**Archive group destination**
<img width="600" alt="fig43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/979070e0-4ece-b031-ea58-7d615745cb2e.png">

- URL : アーカイブファイルを保存する S3 のバケットを以下の形式で指定します。

```
s3ssl://[バケット名]/[パス/][プレフィックス]
```

- パス ： アーカイブファイルを保存するディレクトリのパス（上の例では「livetest/archive/」）
- プレフィックス ： アーカイブファイルの先頭につける共通名（上の例では「live_stream」）

**Archive settings**

<img width="600" alt="fig44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/6be93433-4497-bd32-1997-9a6ff1ae314c.png">

- Name : アーカイブの設定に名前を付けます。識別するための名前なので任意の名前で構いません。
- Rollover Interval : 出力されるアーカイブファイル（.ts）１つあたりに収録される動画の時間を秒で指定します。

**Archive outputs**

<img width="600" alt="fig45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/6dc7c3bb-565e-e084-fbe9-487c70f9be3c.png">

解像度、ビットレート毎にアウトプットを指定することができます。ここで指定した各アウトプットに応じたアーカイブファイルが出力されます。

今回はデフォルトの1種類のみにしています。

- Name modifier : ファイル名に含めたい文字列を指定します（上の例では日時を表す識別子「`$dt$`」を指定しています。プレフィックスと合わせて「live_stream_20190102T1314_xxxxx.ts」といったファイル名で出力されます）

※ 識別子については「[Reference: Identifiers for Variable Data - AWS Elemental MediaLive](https://docs.aws.amazon.com/ja_jp/medialive/latest/ug/variable-data-identifiers.html)」を参照してください。

**(4)**
今回は、その他の設定はデフォルトのままにしておきます。

必要な項目の入力が終わったら、「Update Channel」ボタンを押して保存します。

<img width="500" alt="fig49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/9abb3b45-f86d-f9cb-a4dd-94b1896f3ecd.png">

###ライブ配信後のバケット
アーカイブ設定をした後、ライブ配信を行うと、指定したバケットに以下のようにアーカイブファイルが出力されます。

<img width="600" alt="fig50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/b55f527f-c679-fa4c-b733-984104cbef86.png">

###Archive output group を使用する際の注意点
Archive output group で生成されるアーカイブファイルはセグメントファイル（.ts）のみで、マニフェストファイル（.m3u8）は生成されません。

マニフェストファイルも自動で生成させたい場合は、2-2 で紹介する HLS output group を使用してアーカイブを生成してください。

##2-2. HLS output group を使用する方法
HLS output group は HLS 形式で動画ファイルを出力するための出力タイプです。

**(1)**
MediaLive のダッシュボードを開き、すでに作成してある Channel を選択して、「Action」から「Edit」を選びます。

**(2)**
左側のメニューにある「Output groups」欄の「Add」ボタンを押して、表示された「Add output group」画面で、「HLS」を選択して「Confirm」ボタンを押します。

<img width="600" alt="fig51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/0e4c45e9-a8bf-001f-fbea-64db5813ebbe.png">

**(3)**
HLS output group の設定画面が開くので、以下のように入力します。

**HLS group destination**
2-1の手順と同様に S3 バケットの URL を指定します。

![fig52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/e781d0bb-6401-86c6-4d94-d11d51466476.png)

- URL : アーカイブファイルを保存する S3 のバケットを以下の形式で指定します。

```
s3ssl://[バケット名]/[パス/][プレフィックス]
```

**HLS settings**
<img width="600" alt="fig53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/0f147cb0-bf5b-7862-4482-28d0ef3ff45a.png">

- CDN settings : 「Hls basic put」を選択します（その他はデフォルトのままにしておきます）

**Manifest and Segments**
<img width="600" alt="fig54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/ebb9db9e-ed37-83dd-42bd-b8e919b395d6.png">

- Mode : 「VOD」を選択します（その他の設定はデフォルトのままにしておきます）

**(4)**
今回は、その他の設定はデフォルトのままにしておきます。

必要な項目の入力が終わったら、「Update Channel」ボタンを押して保存します。

###ライブ配信後のバケット
アーカイブ設定をした後、ライブ配信を行うと、指定したバケットに以下のようにアーカイブファイルが出力されます。

<img width="600" alt="fig55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/c80cc572-b055-5c10-1470-b8f9dd3b74c8.png">

セグメントファイルに加えてマニフェストファイル（.m3u8）も自動で生成されています。

#3. Rails アプリから MediaLive のチャンネルを操作する
##3-1. IAM ユーザーの作成
Rails アプリから MediaLive にアクセスするために、必要なアクセス権を持った IAM ユーザーを作成します。

**(1) ポリシーの作成**
以下の権限を有効にしてポリシーを作成します。

![fig56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/0584cd11-ba15-77e6-8c7d-fe84965606aa.png)

**(2) ユーザーを作成する**
アクセスの種類を「プログラムによるアクセス」としてユーザーを作成し、(1) で作成したポリシーをアタッチします。

作成したユーザーのアクセスキーとシークレットアクセスキーを以降の操作で使用しますので控えておいてください。

##3-2. Rails の設定
Railsアプリから MediaLive にアクセスするには、以下の gem を使用します（括弧内は私の開発環境で使用してるバージョンです）。

- aws-sdk-rails (2.1.0)
- aws-sdk-medialive (1.15.0)

API の詳細については以下を参照してください。
[Class: Aws::MediaLive::Client — AWS SDK for Ruby V3](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/MediaLive/Client.html)

**(1) 事前準備**
MediaLive の操作には Aws::MediaLive::Client クラスを使用します。　まずは、Client オブジェクトを生成するメソッドを定義しておきます。

```ruby
private
def getMediaLiveClient
  Aws::MediaLive::Client.new(
    region: 'ap-northeast-1',
    credentials: Aws::Credentials.new(
        ENV['AWS_AKID'],
        ENV['AWS_SCRT']
     )
  )
end
```

※ 3-1 で作成したユーザーのアクセスキーとシークレットアクセスキーをそれぞれ環境変数 AWS_AKID, AWS_SCRT として登録してあるものとします。

**(2) チェンネルの情報を取得する**
MediaLive のチャンネルの各種情報は以下のコードで取得できます。

```ruby
# Medialive::Client オブジェクト生成
client = getMediaLiveClient 

# チャンネル一覧を取得
#   戻り値 ： チャンネル情報を保持したオブジェクトの配列が返されます
resp = client.list_channels()

# チャンネルの各種情報を取得
state = resp.channels[i].state  # チャンネルのステータス（idle/running等）
channel_id = resp.channels[i].id  # チェンネルのID

# Input の各種情報を取得
inputs = resp.channels[i].input_attachments  # Input の情報を保持したオブジェクトの配列
input_id = inputs[j].input_id  # Input の ID
input = client.describe_input({input_id: input_id})  # Input の詳細情報を取得
input_url = input.destinations[0].url  # Input の Destination の URL

# Security Group の取得
security_groups = input.security_groups  # Input にアタッチされている Security Group の ID の配列
security_group_id = security_groups[k]
# Security Group の詳細情報の取得
input_security_group = client.describe_input_security_group({input_security_group_id: security_group_id})
# Security Group にアタッチされた Whitelist の取得
input_security_group_whitelist_rules = input_security_group.whitelist_rules
cidr = input_security_group_whitelist_rules[l].cidr  # Whitelist に登録されたCIDR情報
```

**(3) チャンネルの スタート/ストップ**

```ruby
# チャンネルのスタート
resp = client.start_channel({channel_id: channel_id}) # 当該チャンネルの情報が返されます

# チャンネルのストップ
resp = client.stop_channel({channel_id: channel_id}) # 当該チャンネルの情報が返されます
```

**(4) Security Group の Whitelist の編集**

```ruby
# ホストまたはネットワークのアドレスをCIDR形式の配列で定義します
cidrs = ['192.168.1.2/32', '172.16.10.0/24']

# update_input_security_group
#   第1引数 : Security Group の ID
#   第2引数 : 登録する CIDR の配列
#   戻り値 : 当該 Security Group の情報
resp = client.update_input_security_group({
  input_security_group_id: security_group_id,
  whitelist_rules: cidrs,
})
```

※ update_input_security_group メソッドは、アドレスの追加ではなく上書きになるので、既存のリストに追加したい場合は予め登録されているアドレスのリストを取得し、その配列に新しいアドレスを追加したものを第2引数に指定してください。

#4. ライブ配信の遅延軽減について
MediaLive のチャンネルをデフォルトの設定で使用すると、ライブ配信において 30 秒程度の遅延が発生する場合があります（つまり、視聴者の画面には30秒前に撮影した映像が表示されます）。

配信の遅延は使用しているシステムの構成に大きく依存するので、一概にどの部分に原因があるとは言えませんが、ここでは、MediaLive 側の設定でできる遅延の軽減方法について紹介します。

なお、遅延の要因と軽減の詳しい考察については以下の AWS の記事で紹介されています。
[【4回シリーズ／1回目】メディアサービス － ライブ動画ストリーミングの遅延（レイテンシー） | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/jp-blog-media-streaming-latency20190319/)

**(1)**
MediaLive のダッシュボードでチャンネル一覧を開き、該当のチャンネルを選択して、[Actions > Edit] を選択して編集画面を開きます。

**(2)**
左側のメニューの Output Gropus から目的の Output を選択し、編集画面が表示されたら、「Manifest and Segments」欄で以下の項目を設定します。

- Segment Length : 1（1セグメントファイルあたりに収録される動画の時間を 1 秒にします）
- Num Segments : 3（マニフェストファイルに含まれるセグメントファイルの数を 3 つにします）

<img width="500" alt="fig57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413038/1ce5d639-4382-6b41-4337-a9b56035a004.png">

**(3)**
ライブ配信のテストをして遅延が軽減されたか確認してください。

なお、私の開発環境では、デフォルト設定の場合の遅延は 25 秒程度でしたが、この設定に変えた後は 10 秒程度まで軽減できました。

<br/>
以上で、ライブ配信システム構築に関する手順の紹介は終わりです。

# 目次
（１）[概要](https://qiita.com/mas_yam/items/9d4f491b3a1e310476f0)
（２）[MediaStore の設定](https://qiita.com/mas_yam/items/20c8b524ebd87595e88e)
動画ファイルを保管する MediaStore の設定について紹介します。
（３）[MediaLive の設定](https://qiita.com/mas_yam/items/ed01102b8a996bfc5774)
カメラからのライブ動画を受信して、動画ファイルに変換する MediaLive の設定について紹介します。
（４）[CloudFront による配信](https://qiita.com/mas_yam/items/c3d1dde987afa50479d1)
MediaStore に保管された動画ファイルを CloudFront を経由して配信する方法について紹介します。
（５）[MediaLive の設定 その２](https://qiita.com/mas_yam/items/9bdfdb2091fb12ab4c77) : このページ