# 録画

## 概要

Sora Cloud では Sora の録画機能を利用することができます。録画機能を利用するにあたり、追加料金などは不要です。

録画ファイルはご用意いただいた AWS S3 または S3 互換オブジェクトストレージ (以降オブジェクトストレージ) にアップロードします。

## 録画機能を利用する前に

> **重要**
>
> 録画機能を利用するにはプロジェクトにオブジェクトストレージが設定されている必要があります。

オブジェクトストレージの設定がされていない場合は Sora の録画開始 API を呼び出しても実行されません。

### オブジェクトストレージの設定について

Sora Cloud では管理コンソールからプロジェクトの設定画面でオブジェクトストレージの設定を行います。
その際、設定の接続確認でファイルのアップロードと削除を行います。
そのため Sora Cloud 側に設定するアクセスキーパーミッションは Put と Delete が必要です。
また、Hisui Cloud を利用する際には Get の権限も必要になります。

また Google Cloud Storage に関しては、Access Key ID および Secret Access Key は名称が他のオブジェクトストレージと異なります。
そのため、後述する [S3 または S3 互換オブジェクトストレージのエンドポイント](recording.html#a41384) および [Sora Cloud での Google Cloud Storage の利用方法](recording.html#2c7f03) を確認の上、設定を行ってください。


## 制限

Sora Cloud の録画機能を利用するには以下の制限があります。

これらの制限に該当する場合、API による録画開始を行った場合は API 実行エラーとなります。ウェブフックの戻り値による録画開始をした場合は録画が開始されません。

### 一括録画と分割録画の制限

Sora Cloud の録画方式は、一括録画または分割録画のどちらかしか選択できません。

### 一括録画の有効期限の制限

Sora Cloud では一括録画は最大で 3 時間 (10800 秒) までしか録画できません。
有効期限の指定は必須です。 1 以上、10800 以下の値を指定してください。

この値を超える場合は [録画ファイル分割出力のみ](https://sora-doc.shiguredo.jp/RECORDING#3f7b27) を利用してください。

### 分割録画の分割時間の制限

Sora Cloud では分割録画を行う際に指定する分割時間は最大で 3 時間 (10800 秒) までしか指定できません。

## 録画機能の設定例

一括録画または分割録画を行う際の設定例は以下の通りです。

### 一括録画

#### API による録画開始の設定例

`Sora_20231220.StartRecording` のパラメーターで `expire_time` に 1 以上、10800 以下の値を指定します。

```console
$ curl -sS \
    -X POST \
    https://api.sora-cloud.shiguredo.app/sora-api \
    -H "Authorization: Bearer <API-KEY>" \
    -H "x-sora-target: Sora_20231220.StartRecording" \
    --json '{"channel_id":"sora-cloud@SJW1TPPMQ3JGXM6XD0DTEH77RZDWX0N1","expire_time":3600}' \
    | jq .
```

#### ウェブフックによる録画開始の設定例

セッションウェブフック `session.created` または認証ウェブフックの戻り値で `recording_expire_time` に 1 以上、10800 以下の値を指定します。

```javascript
// session.created の戻り値で指定する例
{
  "recording": true,
  "recording_expire_time": 3600
}
```

### 分割録画

#### API による録画開始の設定例

`Sora_20231220.StartRecording` のパラメーターで `split_duration` に 1 以上、10800 以下の値を指定します。

```console
$ curl -sS \
    -X POST \
    https://api.sora-cloud.shiguredo.app/sora-api \
    -H "Authorization: Bearer <API-KEY>" \
    -H "x-sora-target: Sora_20231220.StartRecording" \
    --json '{"channel_id":"sora-cloud@SJW1TPPMQ3JGXM6XD0DTEH77RZDWX0N1","split_only":true,"split_duration":3600}' \
    | jq .
```

#### ウェブフック による録画開始の設定例

セッションウェブフック `session.created` または認証ウェブフックの戻り値で `recording_split_duration` に 1 以上、10800 以下の値を指定します。

```javascript
// session.created の戻り値の例
{
  "recording": true,
  "recording_split_only": true,
  "recording_split_duration": 3600
}
```

## オブジェクトストレージへのアップロード

プロジェクト設定画面で指定したオブジェクトストレージに録画関連ファイルをアップロードします。

録画関連ファイルは recording_id のディレクトリ配下にアップロードされます。ファイル名はパッケージ版の Sora と同様です。

ファイル名の詳細につきましては、Sora の録画機能のドキュメントをご確認ください。

- [Sora ドキュメント 一括録画ファイルの命名規則について](https://sora-doc.shiguredo.jp/RECORDING#84f89f)
- [Sora ドキュメント 分割録画ファイルの命名規則について](https://sora-doc.shiguredo.jp/RECORDING#d4fb46)

それぞれのファイルのアップロードが終わり次第、アップロード完了のウェブフックリクエストを送信します。

### 対応オブジェクトストレージ

- AWS S3
- MinIO
- GCP GCS
- Vultr Object Storage
- Linode Object Storage
- DigitalOcean Spaces
- Cloudflare R2

### 未検証オブジェクトストレージ

- Wasabi


## ウェブフック通知

Sora Cloud では録画ファイルのアップロードが完了するとウェブフックで通知を行います。

### Sora Cloud ウェブフック recording-report.uploaded

**sora-cloud-webhook-type**: recording-report.uploaded

- s3_uri- s3://<bucket-name>/<file-path>

```json
{
  "id": "<Base32-UUIDv4>",
  "type": "recording-report.uploaded",
  "timestamp": "<RFC3339>",
  "org_id": "<UUID>",
  "project_id": "<String>",
  "recording_id": "<Base32-UUIDv4>",
  "channel_id": "<String>",
  "filename": "<Recording-ID>/report-<Connection-ID>.json",
  "s3_uri": "s3://<Bucket-Name>/<File-Path>"
}
```

### Sora Cloud ウェブフック archive.uploaded

**sora-cloud-webhook-type**: archive.uploaded

- s3_uri- s3://<bucket-name>/<file-path>
- metadata_s3_uri- s3://<bucket-name>/<file-path>

```json
{
  "id": "<Base32-UUIDv4>",
  "type": "archive.uploaded",
  "timestamp": "<RFC3339>",
  "recording_id": "<Base32-UUIDv4>",
  "org_id": "<UUID>",
  "project_id": "<String>",
  "channel_id": "<String>",
  "session_id": "<Base32-UUIDv4>",
  "client_id": "<String | Base32-UUIDv4>",
  "connection_id": "<Base32-UUIDv4>",
  "s3_uri": "s3://<Bucket-Name>/<File-Path>",
  "metadata_s3_uri": "s3://<Bucket-Name>/<File-Path>"
}
```

### Sora Cloud ウェブフック split-archive.uploaded

**sora-cloud-webhook-type**: split-archive.uploaded

```json
{
  "id": "<Base32-UUIDv4>",
  "type": "split-archive.uploaded",
  "timestamp": "<RFC3339>",
  "recording_id": "<Base32-UUIDv4>",
  "org_id": "<UUID>",
  "project_id": "<String>",
  "channel_id": "<String>",
  "session_id": "<Base32-UUIDv4>",
  "client_id": "<String | Base32-UUIDv4>",
  "connection_id": "<Base32-UUIDv4>",
  "s3_uri": "s3://<Bucket-Name>/<File-Path>",
  "metadata_s3_uri": "s3://<Bucket-Name>/<File-Path>"
}
```

### Sora Cloud ウェブフック split-archive-end.uploaded

**sora-cloud-webhook-type**: split-archive-end.uploaded

```json
{
  "id": "<Base32-UUIDv4>",
  "type": "split-archive-end.uploaded",
  "timestamp": "<RFC3339>",
  "recording_id": "<Base32-UUIDv4>",
  "org_id": "<UUID>",
  "project_id": "<String>",
  "channel_id": "<String>",
  "session_id": "<Base32-UUIDv4>",
  "client_id": "<String | Base32-UUIDv4>",
  "connection_id": "<Base32-UUIDv4>",
  "s3_uri": "s3://<Bucket-Name>/<File-Path>"
}
```

## 録画関連ファイルの Sora との差分

- `*_path` 系の値がすべて `"REDACTED"` という文字列に置き換わります
- `event_metadata` の値がすべて `"REDACTED"` という文字列に置き換わります

## イベントウェブフックの Sora との差分

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

Sora Cloud の録画ウェブフック `recording.report` は Sora と仕様が一部が異なります。

Sora では録画終了時のウェブフックにレポートと録画とメタデータのファイルローカルパスを通知しますが、
Sora Cloud ではローカルパスは `REDACTED` という文字列に置き換わって通知されます。

- `"file_path": "REDACTED"`
- `"metadata_file_path": "REDACTED"`

```json
{
    "type": "recording.report",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "log_written": "<Boolean>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "metadata": "<JSON-Object>",
        "split_only": "<Boolean>",
        "file_written": "<Boolean>",
        "created_at": "<UNIX-Time>",
        "expire_time": "<Integer>",
        "expired_at": "<UNIX-Time>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
        "file_path": "REDACTED",
        "filename": "<String>",
        "failed_archives": [],
        "archives": [
            {
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "label": "<String>",
                "node_name": "<String>",
                "filename": "<String>",
                "file_path": "REDACTED",
                "metadata_file_path": "REDACTED",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            },
            {
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "label": "<String>",
                "node_name": "<String>",
                "filename": "<String>",
                "file_path": "REDACTED",
                "metadata_file_path": "REDACTED",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            }
        ]
    }
}
```

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

Sora Cloud の録画ウェブフック `archive.available` は Sora と仕様の一部が異なります。

Sora では録画ファイルが利用可能になった際のウェブフックに、録画ファイルとメタデータのローカルパスを通知しますが、
Sora Cloud ではローカルパスは `REDACTED` という文字列に置き換わって通知されます。

- `"file_path": "REDACTED"`
- `"metadata_file_path": "REDACTED"`

```json
{
    "type": "archive.available",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "group_id": "<Base32-UUIDv4>",
    "session_id": "<Base32-UUIDv4>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "log_written": "<Boolean>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "group_id": "<String or Base32-UUIDv4>",
        "session_id": "<String or Base32-UUIDv4>",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "created_at": "<UNIX-Time>",
        "filename": "<String>",
        "file_path": "REDACTED",
        "metadata_filename": "<String>",
        "metadata_file_path": "REDACTED",
        "size": "<Integer>",
        "audio": "<Boolean>",
        "audio_codec_type": "<String>",
        "video": "<Boolean>",
        "video_codec_type": "<String>",
        "video_bit_rate": "<Integer>",
        "video_height": "<Integer>",
        "video_width": "<Integer>",
        "stats": {},
        "start_time": "<UNIX-Time>",
        "start_time_offset": "<Integer>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<UNIX-Time>",
        "stop_time_offset": "<Integer>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>"
    }
}
```

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

Sora Cloud の録画ウェブフック `split-archive.available` は Sora と仕様の一部が異なります。

Sora では録画ファイルが利用可能になった際のウェブフックに、録画ファイルとメタデータのローカルパスを通知しますが、
Sora Cloud ではローカルパスは `REDACTED` という文字列に置き換わって通知されます。

- `"file_path": "REDACTED"`
- `"metadata_file_path": "REDACTED"`

```json
{
    "type": "split-archive.available",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "group_id": "<Base32-UUIDv4>",
    "session_id": "<Base32-UUIDv4>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "log_written": "<Boolean>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "split_index": "<String>",
        "group_id": "<String or Base32-UUIDv4>",
        "session_id": "<String or Base32-UUIDv4>",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "created_at": "<UNIX-Time>",
        "filename": "<String>",
        "file_path": "REDACTED",
        "metadata_filename": "<String>",
        "metadata_file_path": "REDACTED",
        "size": "<Integer>",
        "audio": "<Boolean>",
        "audio_codec_type": "<String>",
        "video": "<Boolean>",
        "video_codec_type": "<String>",
        "video_bit_rate": "<Integer>",
        "video_height": "<Integer>",
        "video_width": "<Integer>",
        "stats": {},
        "start_time": "<UNIX-Time>",
        "start_time_offset": "<Integer>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<UNIX-Time>",
        "stop_time_offset": "<Integer>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>"
    }
}
```

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

Sora Cloud の録画ウェブフック `split-archive.end` は Sora と仕様の一部が異なります。

Sora では録画ファイルが利用可能になった際のウェブフックに、録画ファイルとメタデータのローカルパスを通知しますが、
Sora Cloud ではローカルパスは `REDACTED` という文字列に置き換わって通知されます。

- `"file_path": "REDACTED"`
- `"metadata_file_path": "REDACTED"`

```json
{
    "type": "split-archive.end",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "group_id": "<Base32-UUIDv4>",
    "session_id": "<Base32-UUIDv4>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "log_written": "<Boolean>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "split_last_index": "<String>",
        "group_id": "<String or Base32-UUIDv4>",
        "session_id": "<String or Base32-UUIDv4>",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "filename": "<String>",
        "file_path": "REDACTED",
        "audio": "<Boolean>",
        "audio_codec_type": "<String>",
        "video": "<Boolean>",
        "video_codec_type": "<String>",
        "video_bit_rate": "<Integer>",
        "stats": {},
        "start_time": "<UNIX-Time>",
        "start_time_offset": "<Integer>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<UNIX-Time>",
        "stop_time_offset": "<Integer>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>"
    }
}
```

## セッションウェブフックの Sora との差分

### セッションウェブフック recording.report

Sora Cloud のセッションウェブフック `recording.report` は Sora と仕様の一部が異なります。

Sora では録画終了時のウェブフックにレポートと録画とメタデータのファイルローカルパスを通知しますが、
Sora Cloud ではローカルパスは `REDACTED` という文字列に置き換わって通知されます。

- `"file_path": "REDACTED"`
- `"metadata_file_path": "REDACTED"`

```json
{
    "type": "recording.report",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "group_id": "<String>",
    "session_id": "<String>",
    "session_metadata": "<JSON>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "data": {
        "channel_id": "<String>",
        "group_id": "<String>",
        "session_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "recording_metadata": "<JSON-Object>",
        "split_only": "<Boolean>",
        "split_duration": "<Integer>",
        "created_at": "<UNIX-Time>",
        "expire_time": "<Integer>",
        "expired_at": "<UNIX-Time>",
        "file_path": "<String>",
        "filename": "<String>",
        "file_written": "<Boolean>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
        "archives": [
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String | Base32-UUIDv4>",
                "bundle_id": "<String | Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "file_path": "REDACTED",
                "filename": "<String>",
                "metadata_file_path": "REDACTED",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            },
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String | Base32-UUIDv4>",
                "bundle_id": "<String | Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "file_path": "REDACTED",
                "filename": "<String>",
                "metadata_file_path": "REDACTED",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            }
        ],
        "failed_archives": [
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String | Base32-UUIDv4>",
                "bundle_id": "<String | Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>"
            },
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String | Base32-UUIDv4>",
                "bundle_id": "<String | Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>"
            }
        ]
    }
}
```


## S3 または S3 互換オブジェクトストレージのエンドポイント

### Google Cloud Storage

**endpoint**: storage.googleapis.com

### Akamai Connected Cloud (Linode Object Storage)

**endpoint**: <region>.linodeobjects.com

### Vultr Object Storage

**endpoint**: <region>.vultrobjects.com

### Cloudflare R2

**endpoint**: <account-id>.r2.cloudflarestorage.com

account-id は以下を参考にしてください。




## Sora Cloud での Google Cloud Storage の利用方法

Google Cloud Storage を録画機能で利用する際の設定例です。

- Google Cloud の IAM から Sora Cloud から使用するサービスアカウントを作成します- Sora Cloud から Google Cloud Storage の接続検証時には `Storage オブジェクトユーザー (roles/storage.objectUser)` のロールを使用しています
  - ファイル書き込みと削除、録画ファイルを保存する際に録画 ID でフォルダを作成するための権限が最低限必要になります
  - Hisui Cloud を利用する場合はファイル取得の権限も必要になります
- 録画ファイル保存先のバケットを作成します- バケット名は S3 互換の命名規則に従い設定を行います- 3-63 文字の範囲
    - 英字小文字、数字、ハイフンのみ
    - その他の規則は [S3 互換の命名規則](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/bucketnamingrules.html) を参照してください
- Google Cloud Storage の設定から相互運用性のタブを開きます- サービスアカウント HMAC から `サービスアカウント用にキーを作成` をクリックし、作成したサービスアカウントを選択します
  - アクセスキーとシークレットが表示されます
  - それぞれ Sora Cloud 管理コンソール上の Object Storage Access Key ID と Object Storage Secret Access Key として使用するため控えておきます
- Sora Cloud のプロジェクト設定画面でオブジェクトストレージの設定を行います- Object Storage Endpoint: storage.googleapis.com
  - Object Storage Access Key ID: 作成した HMAC アクセスキー
  - Object Storage Secret Access Key: 作成した HMAC シークレット
  - Object Storage Bucket Name: 作成したバケット名
