# FAQ

## 一般

### Sora Flutter SDK のライセンスはなんですか？

Sora Flutter SDK はオープンソースライセンス [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) で配布しています。

### Sora Flutter SDK は WebRTC SFU Sora 以外の SFU にも利用できますか？

WebRTC SFU Sora のシグナリング方式に対応している SFU であれば利用できます。

### Sora Flutter SDK はどのプラットフォームに対応していますか？

対応プラットフォームについては [プラットフォーム](overview.html#プラットフォーム) をご確認ください。

### サンプルコードはありますか？

サンプルコードはありませんが、 Sora に接続できる開発者ツール実装を用意しています。
 をご確認ください。

### ソースコードをダウンロードする際の注意点はありますか？

`git clone` などでソースコードをダウンロードする場合は、タグを指定するか `main` ブランチを選択してください。

### Dart 以外の言語で使えますか？

使えません。 Sora Flutter SDK は Dart 専用です。

## 設定

### Sora Flutter SDK が対応している音声コーデックを教えてください

Sora Flutter SDK は以下の音声コーデックに、すべてのプラットフォームで対応しています。

- Opus

### Sora Flutter SDK が対応している映像コーデックを教えてください

映像コーデックの実際の対応状況は、プラットフォームと端末 / OS バージョンに依存します。SDK は次の映像エンコーダー / デコーダーを利用します。

| バックエンド | 対応プラットフォーム | エンコード | デコード |
| --- | --- | --- | --- |
| ソフトウェア | 全プラットフォーム | `VP8` / `VP9` / `AV1` | `VP8` / `VP9` / `AV1` |
| `Apple VideoToolbox` | `iOS` / `macOS` | `H.264` / `H.265` | `H.264` / `H.265` |
| `Android MediaCodec` | `Android` | `H.264` / `H.265` / `VP8` / `VP9` / `AV1` | `H.264` / `H.265` / `VP8` / `VP9` / `AV1` |

> **注釈**
>
> ハードウェアエンコード / デコードの実際の対応状況は、端末と OS バージョンに依存します。上記の表にないプラットフォームで `H.264` / `H.265` を利用できるとは限りません。

`Sora.supportedVideoCodecTypes` で、実行中のプラットフォームのデコーダーが対応するコーデックを確認できます。

```dart
final codec = VideoCodecType.h264;
final supportedCodecs = Sora.supportedVideoCodecTypes;

if (!supportedCodecs.contains(codec)) {
  throw UnsupportedError('このプラットフォームのデコーダーは対応していません');
}
```

この API は実際にハードウェア / ソフトウェアデコードが可能なコーデックを返します。送信側のエンコーダー対応を保証する API ではないため、 `videoCodecType` に指定したコーデックで送信できることを確認する用途には使えません。

### `H.264` と `H.265` を利用する条件はありますか？

あります。 `H.264` / `H.265` のハードウェアエンコード / デコードを利用するには、 `iOS` / `macOS` デバイスが `Apple VideoToolbox` に、 `Android` デバイスが `Android MediaCodec` に対応している必要があります。端末や OS バージョンによって利用できない場合があります。

### ハードウェアアクセラレーターを利用するにはどうすればいいですか？

ハードウェアアクセラレーターを利用する際は以下の条件を全て満たしている必要があります。

- デバイスが利用したいコーデックのハードウェアアクセラレーターを搭載していること
- SDK が対象プラットフォームのハードウェアエンコーダー / デコーダーに対応していること

Sora Flutter SDK では、 `iOS` / `macOS` は `Apple VideoToolbox` 、 `Android` は `Android MediaCodec` を利用します。

`Windows` / `Linux` の `H.264` / `H.265` 対応は、このハードウェア対応表には含まれません。

### 受信したリモート映像の黒画面が相手の切断後も残り続けるのはなぜですか？

受信側が対応していないコーデックの映像を受信すると、画面が真っ黒のままで映像が表示されない状態になります。この黒画面が相手の切断後も残り続けることがあります。

非対応コーデックの映像の場合、answer で拒否するため映像フレームが届かず、映像が映らない状態が続きます。このとき、 `SoraTrackEvent` で映像トラックが通知されるため、 `textureId` を取得することはできます。

通常は相手が切断した際、 `SoraRemoveTrackEvent` が映像トラック削除時に通知され、 画面表示更新に利用することができます。しかし answer で拒否した映像トラックについては `libwebrtc` の挙動で通知されません。その結果、黒画面のままトラックが表示に残り続けます。

そのため、アプリケーション側で切断したコネクションのトラックが表示に残らないように対処してください。削除のタイミングと方法はアプリケーションの設計に合わせてください。例えば、相手の切断時に `connection.destroyed` 通知を受けて該当するコネクションのトラックを削除する方法があります。

また、自分側から切断した場合は、 SDK が全リモート映像トラックを破棄し、 `SoraRemoveTrackEvent` が通知されます。

Sora Flutter SDK の DevTools では、 `connection.destroyed` 通知で切断したコネクションのトラックを削除しています。実装は [devtools](https://github.com/shiguredo/sora-flutter-sdk/tree/develop/devtools) をご確認ください。

> **注釈**
>
> `SoraRemoveTrackEvent` を受けて映像トラックを取り除く実装は、 [削除されたリモートトラックの映像を取り除く](video_rendering.html#削除されたリモートトラックの映像を取り除く) をご確認ください。

> **注釈**
>
> シグナリング通知を無効にしている場合は `connection.destroyed` が通知されません。詳細は Sora のドキュメント [シグナリング通知](https://sora-doc.shiguredo.jp/SIGNALING_NOTIFY) をご確認ください。

### 特定の解像度が利用できません

`Android` / `iOS` / `macOS` デバイスのハードウェアアクセラレーターの問題で、指定した解像度を利用できないことがあります。

エンコーダー/デコーダーの初期化時に例外が発生したり、
エンコード/デコード処理が失敗して映像が正常に送受信されないケースがある場合があります。

> **ヒント**
>
> 160x120 など低めの解像度で問題が起きることが多いです。

> **注釈**
>
> 問題が発生した場合は Discord へフィードバックして頂けると助かります。

### 自分の接続のコネクション ID を取得することはできますか？

できます。 `SoraConnection` の `connectionId` プロパティで取得できます。 `connectionId` はサーバーから offer を受信したタイミングで更新されます。接続前や offer が未到達のときは `null` です。

```dart
conn.events.listen((event) {
  if (event case SoraConnectionStateChangedEvent(state: SoraConnectedState())) {
    // 接続後にコネクション ID を取得する
    print('connection_id: ${conn.connectionId}');
  }
});
```

### 受信したストリームと Sora のコネクション ID を紐づける方法はありますか？

`conn.events` の `SoraTrackEvent` から受信したトラック ( `RemoteMediaStreamTrack` ) が通知されます。
`RemoteMediaStreamTrack` の `connectionId` フィールドに、そのストリームを配信しているクライアントのコネクション ID が設定されています。

```dart
conn.events.listen((event) {
  if (event case SoraTrackEvent(:final track)) {
    // track.connectionId で配信元のコネクション ID を取得できる
    print('track: ${track.trackId}, connection_id: ${track.connectionId}');
  }
});
```

### 受信したストリーム毎に音量を変更する方法はありますか？

Sora Flutter SDK の公開 API では、リモート音声ごとの再生音量変更はできません。
受信音声は SDK とプラットフォームの標準経路で再生され、出力のルーティングは OS と `libwebrtc` の挙動に従います。

詳細は [音声の送受信](audio.html) をご確認ください。

### 音声のステレオ送受信に対応していますか？

音声の送信、受信ともに対応していません。ただし、Sora の実験的機能である Opus の詳細パラメータで `stereo` / `sprop_stereo` を指定することでステレオを利用できます。利用する場合は、事前に Sora のサポートへ連絡してください。詳細は [シグナリング設定](signaling.html) をご確認ください。

### Sora の TURN 機能を無効にして利用できますか？

できません。

Sora Flutter SDK は Sora を `turn = false` に設定して利用することはできません。

### 接続/切断処理を連続して実行しても安全ですか？

Sora Flutter SDK では `connect()` 呼び出し時に既存の接続を自動で切断し、 `disconnect()` も内部で直列化されています。
そのため、ユーザーが接続/切断ボタンを連続してタップした場合でも、SDK 側で処理の衝突は防がれます。

ただし、意図しないタイミングでの切断や再接続を避けるため、UI 側でのボタン連打抑止の実装を推奨します。

### Sora への切断後に同じ `SoraConnection` インスタンスで再接続できますか？

できます。 `disconnect()` を呼んだあと、同じインスタンスで再度 `connect()` を呼ぶことができます。
完全に使い終わった場合は、 `disconnect()` の後に `dispose()` を呼んでリソースを破棄してください。

### 接続に失敗した場合のタイムアウト時間を変更できますか？

できます。 `SoraConnectionConfig` の `timeoutOptions` で `SoraTimeoutOptions` を指定してください。

- `connectionTimeout`: WebSocket 接続から PeerConnection 接続完了まで (デフォルト: 30 秒)
- `disconnectWaitTimeout`: `disconnect()` のリソース解放待機 (デフォルト: 10 秒)
- `signalingCandidateTimeout`: WebSocket 接続確立時間 (デフォルト: 5 秒)

詳細は [タイムアウト機能](timeout.html) をご確認ください。

### 音声・映像の送信をミュートで無効化できますか？

`setAudioEnabled(false)` や `setVideoEnabled(false)` で音声・映像トラックの送信を無効化できます。
ただし、これらの API はトラックの `enabled` を切り替えるものであり、マイクやカメラのハードウェア自体を停止するわけではありません。
そのため、端末のプライバシーインジケーター (ランプ) の消灯は保証しません。

詳細は [メディアデバイス](media_device.html) をご確認ください。

### 受信した音声の音量が小さいです ( `iOS` / `iPadOS` )

`iOS` / `iPadOS` では `AVAudioSession` の category が `.playAndRecord` に設定されるため、受信音量が小さくなる場合があります。
これは `iOS` の仕様です。必要に応じて接続後に `AVAudioSession` の category を変更してください。

### 自己署名証明書は利用できますか？

できません。優先実装にて対応可能です。

### 音声の再生先 (スピーカー) を選択できますか？

Sora Flutter SDK の公開 API では、再生先スピーカーの明示的な切り替えはできません。
音声の再生先は、基本的に各プラットフォームの標準ルーティングに従います。

- `Android`: `Android` / `libwebrtc` の音声ルーティングに従います
- `iOS` / `iPadOS`: `AVAudioSession` の音声ルートに従います。 `AirPlay` や `Bluetooth` などの再生先をユーザーに選ばせる場合は、アプリケーション側で `AVRoutePickerView` を利用してください
- `macOS`: `OS` / `CoreAudio` の既定音声出力へ再生されます

現在利用可能な音声出力デバイスの一覧は `MediaDevices.enumerateAudioOutputDevices()` で取得できます。

詳細は [音声の送受信](audio.html) をご確認ください。

## リアルタイムメッセージング機能

### いつ sendDataChannelMessage() を呼べばよいですか？

`connect()` 呼び出し後、 `SoraDataChannelOpenEvent` で対象 label の open を確認してから送ってください。DataChannel が未確立のまま送ると、内部実装上は該当 channel が見つからず送信されません。

```dart
import 'dart:convert';
import 'dart:typed_data';

conn.events.listen((event) {
  if (event is SoraDataChannelOpenEvent &&
      event.event.label == '#messaging') {
    conn.sendDataChannelMessage(
      '#messaging',
      Uint8List.fromList(utf8.encode('ready')),
    );
  }
});
```

### `compress: true` のとき、アプリケーション側で圧縮や展開は必要ですか？

不要です。

送信時は SDK が `compress` 設定に従って `sendDataChannelMessage()` の payload を圧縮し、受信時は SDK が展開したうえで `SoraDataChannelMessageEvent` に渡します。

## サポート

### Sora Flutter SDK の有償サポートは提供していますか？

Sora Flutter SDK の有償サポートは提供しておりません。

### 質問やバグ報告はどこで行えますか？

Sora Flutter SDK についての質問やバグ報告は Discord の `#sora-sdk-faq` チャンネルにお願いします。



ただし、 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。

### 質問やバグ報告にあたり、どのような情報を記載すればよいですか？

次の開発環境のバージョンを「メジャーバージョン、マイナーバージョン、メンテナンスバージョン」まで含めて記載してください。

- 利用している Sora のバージョン
- 利用している Sora Flutter SDK のバージョン
- 利用している Flutter SDK のバージョン
- 利用している Dart のバージョン
- 動作させている OS とそのバージョン ( `iOS` / `Android` / `macOS` / `Windows` など)
- 動作させているデバイスのモデル名 ( `Android` や `iOS` 端末の場合)
- 開発環境のバージョン ( `Android Studio` / `Xcode` など)

## リリース

### リリースサイクルを教えてください

Sora のメジャーバージョンアップ後に、
Sora へ追従を目的としたバージョンアップを行います。

ただし、具体的なリリースサイクルはありません。
