録画機能

概要

Sora では、配信している映像や音声を録画して保存することが可能です。 配信されている映像をできるかぎりそのまま保存するため、CPU リソースを最小限に抑えることができます。 出力される録画ファイルは WebM 形式です。映像のみの録画、音声のみの録音にも対応しています。

録画時には一切トランスコードを行っておりません。配信された映像をそのままに記録します。

用語

単一録画ファイル

切断または録画停止 API の実行、または録画期限が切れた場合の間が一つとして出力される動画ファイル

分割録画ファイル

split_duration で指定した時間ごとに区切られ分割されて出力される動画ファイル

録画ファイルの出力

録画ファイルの出力には 3 パターンあります。

単一録画ファイルのみ出力

  • split_duration を指定していない

上記を満たした場合、1 接続で 1 つ録画ファイルが出力されます。

単一録画ファイルと分割録画ファイルの両方が出力

  • split_duration が指定されている

上記を満たした場合、 1 接続で 1 つの録画ファイルと分割された録画ファイルの両方が出力されます。

ウェブフックも両方のウェブフックが通知されます。

分割録画ファイルのみ出力

  • split_duration が指定されている

  • expire_time0 に指定されている

  • split_onlytrue に指定されている

上記を満たした場合、分割された録画ファイルのみが出力されます。

制限

コーデック

録画 (録音) は、映像コーデックに VP8 と VP9 と H.264 、また音声コーデックに Opus を選択した場合のみ可能です。

警告

AV1 と H.265 の録画には非対応です。

解像度

WebRTC では配信側の CPU リソースが不足した場合や、 回線の品質が悪化した場合に解像度を動的に変更します。 そのため録画したデータの途中で解像度が低くなる可能性があります。

音声や映像のクライアント側でのトラック削除

クライアント側でシグナリング接続時に音声や映像を有効にした状態で、 クライアント側で音声トラック、または映像トラックのどちらかを削除した場合でも録画は行われます。 さらに追加して戻した形であれば録画側も戻ります。

ただし、音声と映像両方のトラックを削除した場合は正常に録画が行われません。

マルチストリーム機能での録画

対応しています。

サイマルキャスト機能での録画

対応しています。

サイマルキャストを利用している際の録画は 一番優先度が低い ストリームを録画します。

詳細はサイマルキャストの 映像の優先度 をご確認下さい。

スポットライト機能での録画

対応しています。

サイマルキャストを利用している際の録画は 一番優先度が低い ストリームを録画します。

詳細はサイマルキャストの 映像の優先度 をご確認下さい。

スポットライトレガシーでの録画

対応していません。

無変換録画

WebRTC 経由で流れてきている映像や音声を変換せず、 そのまま録画するファイルの形式に組み立て直してファイルを保存します。 そのため、CPU リソースを最小限に抑えられます。 ブラウザでの録画など、通常の録画は変換が入るため CPU に多くの負荷がかかります。

変換を行わないため、録画を終了した数秒後には録画したファイルを取得することができます。

解像度は送られてきた映像の最大値を録画ファイルの解像度として使用します。

録画の開始と終了について

Sora の録画機能は 明示的にチャネルの録画を停止するか、 チャネルの録画開始から指定した期限が過ぎるまでは、 そのチャネルでの配信を自動で録画する といった機能になります。

録画関連イベントのウェブフックについて

archive.available イベントウェブフック

単一録画ファイルが出力されたタイミングで archive.available という通知が送られます。

詳しくは archive.available をご確認ください。

recording.report イベントウェブフック

録画終了 API が実行されたか、 録画の期限が切れたタイミングで recording.report という通知が送られます。

重要

split_only=true が有効な場合は通知されません。

詳しくは recording.report をご確認ください。

archive.split イベントウェブフック

録画ファイル分割出力機能を有効にした場合、 分割された録画ファイルが出力されたタイミングで archive.split という通知が送られます。

詳しくは archive.split をご確認ください。

archive.end イベントウェブフック

録画ファイル分割出力機能を有効にした場合、 分割された録画が終了したタイミングで archive.end という通知が送られます。

詳しくは archive.end をご確認ください。

archive.failed イベントウェブフック

録画ファイルの保存に失敗した場合、 archive.failed という通知が送られます。

詳しくは archive.failed をご確認ください。

単一録画ファイル出力

単一録画ファイル出力は sora.confarchive_dir に指定したフォルダに recording_id 名のフォルダ以下にファイルが出力されます。

recording_id は録画開始 API を実行したときに戻ってくる値で、 Base32 でエンコードされた UUIDv4 となります。

ディレクトリ構造:

├── archive
│   ├── 1CS9QJ0XPN4C76HBGBN6MGMK5M
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC.webm
│   │   ├── archive-H2NDA2YCGH7S1E9CVMFMXMA34R.json
│   │   ├── archive-H2NDA2YCGH7S1E9CVMFMXMA34R.webm
│   │   ├── archive-PBVZQQN3JS3MQF8XHVFXDMCEEC.json
│   │   ├── archive-PBVZQQN3JS3MQF8XHVFXDMCEEC.webm
│   │   └── report-1CS9QJ0XPN4C76HBGBN6MGMK5M.json
│   └── CZZ8A8KZB16A1DF5PKERBHGFNR
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.json
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.webm
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.json
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.webm
│       └── report-CZZ8A8KZB16A1DF5PKERBHGFNR.json

注意

archive_dirarchive_tmp_dir は違うディレクトリを指定して下さい

archive-<connection_id>

単一録画ファイル

単一録画ファイルは <recording_id>/archvie-<connection_id>.webm に WebM 形式で出力されます。

単一録画メタデータファイル

単一録画メタデータファイルは <recording_id>/archive-<connection_id>.json に JSON 形式で出力されます。

メタデータファイルには WebM ファイルがいつ出力され、どんな形式なのか、開始時刻や終了時刻などの情報が含まれています。

  • start_timestamp

    • この録画が開始された時刻を UTC で表しています

  • stop_timestamp

    • この録画が終了した時刻を UTC で表しています

  • start_time

    • この録画が開始された時刻を UNIX 秒で表しています

  • stop_time

    • この録画が終了した時刻を UNIX 秒で表しています

stats は省略しています

{
  "audio": {
    "codec_type": "OPUS"
  },
  "channel_id": "sora",
  "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W",
  "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W",
  "created_at": 1615524156,
  "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm",
  "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm",
  "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json",
  "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json",
  "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR",
  "size": 0,
  "start_time": 1615524137,
  "start_timestamp": "2021-03-12T04:42:17.455668Z",
  "stats": {
    "extract_queue_trimmed": 0,
    "final_extract_limit": 0,
    "min_audio_level": 11,
    "min_audio_level_split": 11,
    "total_audio_discraded": 0,
    "total_audio_empty_payload": 0,
    "total_audio_filling": 1,
    "total_audio_lip_sync_mode_recv_time": 0,
    "total_audio_lip_sync_mode_rtcp_sr": 2,
    "total_audio_sender_report": 3,
    "total_h264_nri_zero_drop": 0,
    "total_pli_trigger": 0,
    "total_stored_audio_packet": 833,
    "total_stored_unknown_packet": 0,
    "total_stored_video_keyframe_head": 1,
    "total_stored_video_packet": 1977,
    "total_video_chunk_postponed_partial": 1,
    "total_video_chunk_postponed_queued": 0,
    "total_video_chunk_postponed_undefined": 0,
    "total_video_force_forward": 0,
    "total_video_frame": 489,
    "total_video_lip_sync_mode_recv_time": 0,
    "total_video_lip_sync_mode_rtcp_sr": 2,
    "total_video_reset_no_video_timeout": 0,
    "total_video_reset_other": 0,
    "total_video_reset_pli": 0,
    "total_video_sender_report": 46
  },
  "stop_time": 1615524154,
  "stop_timestamp": "2021-03-12T04:42:34.094375Z",
  "video": {
    "bit_rate": 1000,
    "codec_type": "VP9",
    "height": 480,
    "width": 640
  }
}

report-<recording_id>

StopRecording API を使用して指定したチャネルに対する録画を停止するか録画の期限が切れた場合、 それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。

このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。

ファイルは <recording_id>/report-<recording_id>.json に出力されます。

  • start_time_offset

    • StartRecording API を叩いてから何秒経過した後にこの録画が開始したかを表しています

  • stop_time_offset

    • StartRecording API を叩いてから何秒経過した後にこの録画が終了したかを表しています

{
  "archives": [
    {
      "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W",
      "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W",
      "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm",
      "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm",
      "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json",
      "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json",
      "size": 0,
      "start_time_offset": 0,
      "start_timestamp": "2021-03-12T04:42:17.455668Z",
      "stop_time_offset": 17,
      "stop_timestamp": "2021-03-12T04:42:34.094375Z"
    }
  ],
  "channel_id": "sora",
  "created_at": 1615524137,
  "expire_time": 3600,
  "expired_at": 1615527737,
  "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json",
  "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json",
  "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR",
  "split_only": false
}

録画ファイル分割出力機能について

Sora では録画開始 API 実行時に split_duration を指定することで、録画ファイルを指定した間隔で出力する機能を提供しています。

重要

分割の最小単位はキーフレームから次のキーフレームまでです。例えば split_duration を 1 秒に設定した場合は、1 秒経過後に次のキーフレームが来たタイミングで分割出力されます。

録画が完了したファイルは sora.confarchive_dir に指定したフォルダに recording_id 名のフォルダ以下にファイルが出力されます。

recording_id は録画開始 API を実行したときに戻ってくる値です。

ディレクトリ構造:

├── archive
│   ├── 1CS9QJ0XPN4C76HBGBN6MGMK5M
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0001.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0001.webm
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0002.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0002.webm
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0003.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0003.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC.json
│   │   ├── archive-A4756MXP914ZB265E92JE3ZMWC.webm
│   │   └── report-1CS9QJ0XPN4C76HBGBN6MGMK5M.json
│   └── CZZ8A8KZB16A1DF5PKERBHGFNR
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.json
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.webm
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.json
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.webm
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.json
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.webm
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.json
│       ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.webm
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.json
│       ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.webm
│       └── report-CZZ8A8KZB16A1DF5PKERBHGFNR.json

archive-<connection_id>_<split_index>

内容は archive.split イベントウェブフックと同等です

分割録画ファイル

分割録画ファイルは <recording_id>/archvie-<connection_id>_<split_index>.webm に WebM 形式で出力されます。

分割録画メタデータファイル

内容は archive.available イベントウェブフックと同等です

分割録画メタデータファイルは <recording_id>/archive-<connection_id>_<split_index>.json に JSON 形式で出力されます。

  • split_index

    • ファイル名につくインデックスです 0001 から始まり 9999 の後は 10000 となります

stats は省略しています

{
  "type": "archive.split",
  "channel_id": "sora",
  "connection_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C",
  "timestamp": "2020-11-06T09:52:44.498575Z",
  "client_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C",
  "data": {
    "audio": {
      "codec_type": "OPUS"
    },
    "recording_id": "CZZ8A8KZB16A1DF5PKERBHGFNR",
    "file_path": "/path/to/sora/archive/CZZ8A8KZB16A1DF5PKERBHGFNR/archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.webm",
    "filename": "CZZ8A8KZB16A1DF5PKERBHGFNR/archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.webm",
    "metadata_file_path": "/path/to/sora/archive/CZZ8A8KZB16A1DF5PKERBHGFNR/archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.json",
    "metadata_filename": "CZZ8A8KZB16A1DF5PKERBHGFNR/archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.json",
    "channel_id": "sora",
    "client_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C",
    "connection_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C",
    "split_index": "0001",
    "created_at": 1604656364,
    "size": 823263,
    "start_time": 1604656354,
    "start_timestamp": "2020-11-06T09:52:34.696758Z",
    "stats": {},
    "stop_time": 1604656364,
    "stop_timestamp": "2020-11-06T09:52:44.493179Z",
    "video": {
      "bit_rate": 1000,
      "codec_type": "VP9",
      "height": 480,
      "width": 640
    }
  },
  "id": "ZAHYYZPDAH2MFCAWRHSVMHPHRG",
  "label": "WebRTC SFU Sora",
  "version": "2020.3"
}

録画ファイル分割出力終了通知

重要

録画分割出力終了のファイルは生成されません。

録画が終了したタイミングで recording.report とは別にイベントウェブフック archive.end が通知されます。

詳細は archive.end をご確認ください。

録画ファイル分割出力のみを行う

重要

録画ファイル分割出力のみの場合は録画終了 API を実行しても recording.report ウェブフックは通知されません。

録画開始 API 実行時に split_durationsplit_only: trueexpire_time: 0 の 3 つを指定することで、録画ファイル分割出力 のみ を行うことが可能になります。

録画ファイル合成ツール

マルチストリームを録画した場合はそれぞれの接続に対して録画ファイルが出力されます。このそれぞれ分かれた録画ファイルを合成して一つにするツールをオープンソースとして公開しています。

詳細は WebRTC 録画合成ツール Hisui をご確認ください。

試してみる

Sora では録画機能を試すためのデモ機能を提供しています。 デモ機能 を参照の上、デモ機能を有効にしてください。

ここでは Sora が立っているサーバは example.com としています。

チャネルの録画開始

API を叩いて録画を開始してください。

httpie:

$ http POST example.com:3000/ \
    x-sora-target:Sora_20161101.StartRecording \
    channel_id=sora \
    expire_time:=3600 -vvv

curl:

$ curl -X POST example.com:3000/ \
    -H "x-sora-target: Sora_20161101.StartRecording" \
    -d '{"channel_id": "sora", "expire_time": 3600}' -vvv

その後 https://example.com/sendrecv.html を開き、 connect ボタンを押して配信を開始します。

切断またはチャネルの録画終了、もしくはチャネルの録画期限が来たタイミングでクライアントの録画は終了します。

チャネルの録画終了

チャネルの録画を終了するには API を叩く必要があります。

httpie:

$ http POST example.com:3000/ \
    x-sora-target:Sora_20161101.StopRecording \
    channel_id=sora -vvv

curl:

$ curl -X POST example.com:3000/ \
    -H "x-sora-target: Sora_20161101.StopRecording" \
    -d '{"channel_id": "sora"}' -vvv

その後 archive/ ディレクトリに webm 形式のファイルが出力されます。 Chrome または Firefox にドラッグアンドドロップして、動作を確認しましょう。