Cloudflare StreamのSimulcastingで出力ごと個別に転送の開始・停止ができるようになりました

Cloudflare Streamに打ち上げた映像を他の動画配信プラットフォームに転送できるSimulcasting機能で、出力ごと個別に転送の制御ができるようになりました。ダッシュボードまたはAPIからコントロール可能です。
2022.09.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

清水です。Cloudflareの動画配信プラットフォームサービスCloudflare Streamについてのアップデート情報をお届けします。Cloudflare Streamに打ち上げた映像をそのまま他の動画配信プラットフォームに転送できるサイマル放送(Simulcasting/Stream Connect)機能で、出力ごと個別に転送の開始、停止ができるようになりました。

Cloudflare StreamドキュメントChangelogに2022/09/15付でアップデートされた機能として記載があります。

Changelog · Cloudflare Stream docs

本エントリでは、このSimulcastingでの個別出力制御機能について実際に試してみたのでまとめてみたいと思います。

Cloudflare StreamのSimulcasting機能と今回のアップデートについて

まずはCloudflare StreamのSimulcasting機能について簡単に振り返っておきましょう。Simulcasting機能を使うことで、打ち上げた映像をCloudflare Stream自体でライブストリーミングしつつ、YouTube LiveやFacebook Live、Twitchなど他の動画配信プラットフォームに転送できる機能です。Stream Connectやrestreamなどとも呼ばれ、日本語ではサイマル放送などと表記します。

このSimulcasting、下記のエントリで実際に試してみています。このときは2022年4月で、Cloudflare Streamでライブストリーミングをしつつ、Simulcasting用の出力を作成したらすぐに出力先の動画配信プラットフォームにも映像が出力されるというぐあいでした。Simulcastingの出力の制御はできず、Cloudflare Streamに打ち上げた映像はそのままSimulcastingの出力先にも転送される状態ですね。

Simulcasting機能を使うことで、動画配信プラットフォームごと個別にグラウンド側から打ち上げていた映像をCloudflare Streamの1本に集約できるメリット、ネットワーク帯域の節約や現場機材の減少、打ち上げ元により近いエンドポイントの利用、といった点はこれまでも享受できていました。しかしSimulcasting機能を使う上で、配信プラットフォームごと個別に出力する・出力しない時間帯を制御したい、というケースもあったかと思います。例えば映像が入力されたら即、ライブストリーミングを公開してしまうプラットフォームを使用する場合がこのケースに当てはまるかと思います。またSNS向けの動画配信プラットフォームでは一部の時間帯のみ公開して集客しつつ、本編は独自サイトに埋め込んだ視聴ページで公開したい、といった場合にも当てはまりますよね。今回のアップデート、Simulcastingの個別出力制御ではダッシュボードもしくはAPIからの操作でこれら、出力ごとの個別のストリーミング転送の開始・停止が可能になりました。

Simulcastingで出力をコントロールしてみた

それでは実際にSimulcastingの個別出力抑制機能を確認していきましょう。先ほど記載した、2022年4月時点のこの機能がない段階のSimulcastingと比較してみてもよいかもしれません。検証内容としても同様のケース、Cloudflare Streamingでライブストリーミングしつつ、YouTube LiveへのSimulcastingを行う場合を確認しました。

まずはCloudflare StreamでLive Inputを作成し、Streaming Softwareから映像を打ち上げてライブストリーミングを開始しておきます。

続いてSimulcasting先となるYouTube Liveの準備を行います。

ライブ配信を作成し、ストリームURLならびにストリームキーを確認します。この2つの情報をもとに、Cloudflare Stream側でSimulcastingの出力を作成します。ライブ入力の詳細画面の最下部、[出力を作成する]ボタンから進みます。

「出力を作成する」画面で、プロトコルはRTMP(S)を選択し、URLとキーに先ほどYouTube Liveの画面で確認したストリームURLとストリームキーを入力します。Enabledはデフォルトのonのまま、[出力を作成する]ボタンを押下します。

ライブ入力からYouTube Liveへの出力(Simalcasting)が作成できました。作成時のオプションの通り、Enableにチェックが入っている状態です。すぐにYouTube Live側へストリームが転送され、ライブ配信の準備ができた状態となります。[ライブ配信を開始]ボタンでYouTube Liveのライブ配信を開始します。

以下のようにCloudflare Streamに打ち上げた映像が、Cloudflare StreamならびにYouTube Liveの双方でライブストリーミング視聴できる状態となります。(時間が少し飛んでしまっているのは、検証が一時中断してしまったためです。)

さて、ここからが本題のSimulcastingの個別出力抑制機能の確認です。Cloudflare Stream側、Simulcasting出力のEnableのチェックをoffにしてみましょう。

YouTube Liveへのストリーミングの転送が停止します。ストリームの状態の箇所で「データなし」となっていますね。

YouTubeの視聴用URL側でもライブストリーミングが停止します。(プレイヤー中央に「ぐるぐるマーク」が表示されていますね。)このとき、Cloudflare Stream側のライブストリーミングは続行したままとなります。

ライブ入力の出力の設定で、YouTube LiveへのSimulcastingを再度Enabledにする(チェックを入れる)と、YouTube Liveへの転送が再開されます。

YouTube LiveへのSimulcastingのEnabled項目のon/offでストリーミングが中断・再開(開始・停止)することが確認できました。

この検証では、YouTube Liveへのライブストリーミングが中断する、というかたちで確認を行いました。本来であればYouTube Live側で[ライブ配信を終了]の操作をしたあと、Cloudflare Stream側のSimulcastingをDisabledにする、という流れになるかと思います。もちろん、YouTube Live側で[ライブ配信を終了]していれば公開されているライブストリーミング自体も終了するわけですが、映像の打ち上げ側とYouTube Live側で管理者が異なる場合などに、YouTube Liveへの映像を明示的に停止することで[ライブ配信の終了]の操作を忘れてしまっていてうっかり配信すべきでない箇所が配信されてしまった、といったことが防げるようになりますね。

Simlcastingの出力コントロールをAPIでもやってみた

Simulcastingの出力制御について、ダッシュボードからの操作で確認をしてみました。このSimulcastingの個別出力制御機能、ほかのCloudflare Streamの操作と同様、APIからでも使うことができます。さきほど作成したライブ入力をそのまま使い、Amazon Interactive Video Service (Amazon IVS)へのSimulcastingを追加するかたちで試してみましょう。

以下のAPIドキュメントを参照しながら進めます。

またAPIトークンの取得などは以下ブログエントリの方法で実施済みとします。

APIトークン、アカウントID、そして使用しているLive InputのUIDをシェル変数に格納しておきます。

% TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
% ACCOUNT=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
% LIVE_INPUT_UID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

まずはAmazon IVS側でSimulcasting先となるChannelを作成して、ストリームURL(Ingest Server)ならびにストリームキー(Stream Key)を確認しておきます。

Cloudflare StreamのLive InputのSimulcasting設定については、/live_inputs/${LIVE_INPUT_UID}/outputsエンドポイントへのGETリクエストで情報を取得できます。(Live Input自体の設定情報は/live_inputs/${LIVE_INPUT_UID}エンドポイントへのGETリクエストとなりますが、今回は省略します。)さきほど設定したYouTube Liveへの設定がresultにまとめられていますね。historyには接続履歴がまとまっています。

 % curl -X GET \
     -H "Authorization: Bearer ${TOKEN}" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs"
{
  "result": [
    {
      "uid": "745cxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "url": "rtmp://a.rtmp.youtube.com/live2",
      "streamKey": "xxxxxxxxxxxxxxxxxxxxxxxx",
      "enabled": true,
      "status": {
        "current": {
          "reason": "client_disconnect",
          "state": "disconnected",
          "statusEnteredAt": "2022-09-16T12:12:46.485Z",
          "statusLastSeen": "2022-09-16T12:12:46.485Z"
        },
        "history": [
          {
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T11:57:40.217Z"
          },
          {
            "reason": "connected",
            "state": "connected",
            "statusEnteredAt": "2022-09-16T11:57:40.553Z"
          },
          {
            "reason": "client_disconnect",
            "state": "disconnected",
            "statusEnteredAt": "2022-09-16T12:10:34.039Z"
          },
          {
            "reason": "new_configuration_accepted",
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T12:11:26.889Z"
          },
          {
            "reason": "connected",
            "state": "connected",
            "statusEnteredAt": "2022-09-16T12:11:27.235Z"
          }
        ]
      }
    }
  ],
  "success": true,
  "errors": [],
  "messages": []
}

Simulcastingの出力設定の追加はエンドポイント/live_inputs/${LIVE_INPUT_UID}/outputsヘデータをPOSTします。この際、送信するデータのurlstreamKeyに先ほど確認したAmazon IVSのストリームURL(Ingest Server)ならびにストリームキー(Stream Key)を指定します。またこのurlstreamKeyのほかにオプションとしてenabledパラメータを追加することができます。今回はfalseで指定してみます。

curl -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     --data '{"url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app", "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "enabled": false}' \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs"

送信データのJSONを整形すると以下となります。

{
  "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
  "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "enabled": false
}

以下が実行結果です。

 % curl -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     --data '{"url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app", "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "enabled": false}' \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs"
{
  "result": {
    "uid": "b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
    "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "enabled": false,
    "status": null
  },
  "success": true,
  "errors": [],
  "messages": []
}

/live_inputs/${LIVE_INPUT_UID}/outputsヘデータをPOSTしたあと、ダッシュボードでも出力が追加されたことを確認してみます。転送を制御するEnabledoffの状態で新たな出力が追加されていますね。

続いて、このSimulcastingの出力ごとの転送のコントロールを行ってみます。出力の制御には/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}エンドポイントにPOSTを行います。OUTPUT_UIDはさきほどの出力追加の際のレスポンス内容からシェル変数に格納しておきます。

% OUTPUT_UID="b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}エンドポイントへのPOSTは以下の形式となります。

 % curl -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     --data '{"enabled": true}' \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}"

送信データのJSONは以下になります。シンプルに1つのメンバーのみデータですね。

{
  "enabled": true
}

以下が実行結果です。

% curl -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     --data '{"enabled": true}' \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}"
{
  "result": {
    "uid": "b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
    "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "enabled": true,
    "status": null
  },
  "success": true,
  "errors": [],
  "messages": []
}

実行後、ダッシュボードでも確認してみましょう。Enalbedの項目がonになりました。

これでCloudflare Stream、YouTube Liveでのライブストリーミングに加えて、Amazon IVSでのライブストリーミングも行えている状態となりました。

続いて、Amazon IVSへのSimulcasting出力をAPIから停止してみます。開始したときと同様、/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}エンドポイントへのPOSTを行いますが、送信データのenabledの値をfalseとします。

{
  "enabled": false
}

以下、実行結果となります。/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}エンドポイントへのPOSTの前後で/stream/live_inputs/${LIVE_INPUT_UID}/outputsエンドポイントへGETを行い、状態の変化を確認しながら進めてみました。

まずは/stream/live_inputs/${LIVE_INPUT_UID}/outputsエンドポイントへのGETです。Amazon IVSへのSimulcasting出力で"enabled": trueとなっています。

% curl -X GET \
     -H "Authorization: Bearer ${TOKEN}" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs"
{
  "result": [
    {
      "uid": "745cxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "url": "rtmp://a.rtmp.youtube.com/live2",
      "streamKey": "xxxxxxxxxxxxxxxxxxxxxxxx",
      "enabled": true,
      "status": {
        "current": {
          "reason": "connected",
          "state": "connected",
          "statusEnteredAt": "2022-09-16T12:52:11.186Z",
          "statusLastSeen": "2022-09-16T13:02:41.136Z"
        },
        "history": [
          {
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T12:52:10.826Z"
          }
        ]
      }
    },
    {
      "uid": "b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
      "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "enabled": true,
      "status": {
        "current": {
          "reason": "connected",
          "state": "connected",
          "statusEnteredAt": "2022-09-16T12:58:46.376Z",
          "statusLastSeen": "2022-09-16T13:02:41.136Z"
        },
        "history": [
          {
            "reason": "new_configuration_accepted",
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T12:58:45.042Z"
          }
        ]
      }
    }
  ],
  "success": true,
  "errors": [],
  "messages": []
}

/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}エンドポイントへ{"enabled": false}なデータをPOSTします。

% curl -X POST \
     -H "Authorization: Bearer ${TOKEN}" \
     --data '{"enabled": false}' \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs/${OUTPUT_UID}"
{
  "result": {
    "uid": "b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
    "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "enabled": false,
    "status": {
      "current": {
        "reason": "connected",
        "state": "connected",
        "statusEnteredAt": "2022-09-16T12:58:46.376Z",
        "statusLastSeen": "2022-09-16T13:02:56.101Z"
      },
      "history": [
        {
          "reason": "new_configuration_accepted",
          "state": "connecting",
          "statusEnteredAt": "2022-09-16T12:58:45.042Z"
        }
      ]
    }
  },
  "success": true,
  "errors": [],
  "messages": []
}

確認のため、もう一度/stream/live_inputs/${LIVE_INPUT_UID}/outputsエンドポイントへGETを行います。Amazon IVSへのSimulcasting出力が"enabled": falseとなっていますね。

% curl -X GET \
     -H "Authorization: Bearer ${TOKEN}" \
     "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT}/stream/live_inputs/${LIVE_INPUT_UID}/outputs"
{
  "result": [
    {
      "uid": "745cxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "url": "rtmp://a.rtmp.youtube.com/live2",
      "streamKey": "xxxxxxxxxxxxxxxxxxxxxxxx",
      "enabled": true,
      "status": {
        "current": {
          "reason": "connected",
          "state": "connected",
          "statusEnteredAt": "2022-09-16T12:52:11.186Z",
          "statusLastSeen": "2022-09-16T13:03:26.042Z"
        },
        "history": [
          {
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T12:52:10.826Z"
          }
        ]
      }
    },
    {
      "uid": "b6b3xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "url": "rtmps://622exxxxxxxx.global-contribute.live-video.net:443/app",
      "streamKey": "sk_ap-northeast-1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "enabled": false,
      "status": {
        "current": {
          "reason": "client_disconnect",
          "state": "disconnected",
          "statusEnteredAt": "2022-09-16T13:03:05.078Z",
          "statusLastSeen": "2022-09-16T13:03:26.042Z"
        },
        "history": [
          {
            "reason": "new_configuration_accepted",
            "state": "connecting",
            "statusEnteredAt": "2022-09-16T12:58:45.042Z"
          },
          {
            "reason": "connected",
            "state": "connected",
            "statusEnteredAt": "2022-09-16T12:58:46.376Z"
          }
        ]
      }
    }
  ],
  "success": true,
  "errors": [],
  "messages": []
}

APIを実行してAmazon IVSへのSimulcasting出力を停止したあと、ダッシュボードならびにAmazon IVSのライブストリーミング画面を確認してみます。ダッシュボード上でEnalbedoffになっており、またAmaozn IVSへのライブストリーミングも停止された状態となりました。

まとめ

Cloudflare Streamに新たに追加されたSimulcastingの個別出力制御機能について、ダッシュボードならびにAPIから動作を確認してみました。Simulcasting機能のメリットを感じつつも、プラットフォームごとに配信の時間帯などが異なっている、設定後すぐにライブストリーミングの転送が開始されることが許容できない、などで導入を見送っていた場合にドンピシャにハマるアップデートかなと思います。