映像の送信と受信¶
Sora Unity SDK で映像を送信・受信する際に必要となる設定や API について説明します。
デバイスカメラ・Unity カメラの切り替え、ミュート操作、受信映像の描画までを確認できるようになっています。
映像送信と受信の提供機能について¶
Sora Unity SDK では以下を提供しています。
デバイスカメラを映像送信に利用する
Unity カメラを映像送信に利用する
任意の
Textureを映像送信に利用する映像送信を一時停止する (ソフトミュート)
カメラデバイスを利用しない (ハードミュート)
利用可能なカメラデバイス一覧を取得する
受信した映像を任意のテクスチャに描画する
映像コーデックの指定をする
ハードウェアアクセラレーションの利用を指定する
プラットフォームと制限¶
Sora.OnCapturerFrameは Android では利用できませんiOS や macOS ではカメラアクセス権限が無い場合、デバイス列挙や接続処理が失敗するため権限を付与したうえで利用してください
Unity カメラ送信や任意のテクスチャを送信する場合は
RenderTextureFormat.BGRA32が必要となるため、プロジェクト設定で BGRA32 を有効にしてください
映像関連の API リファレンス¶
Sora.Config¶
Sora.Config クラスは Sora インスタンスの接続設定を定義します。映像送信に関する主なプロパティは以下の通りです。
Video: 映像トラックの送信を有効にするかどうか。falseにすると映像送信を停止しますNoVideoDevice: 物理カメラデバイスを利用しない場合にtrueを設定しますVideoBitRate: 映像送信のビットレート (kbps)。省略時は接続する Sora のデフォルト値になりますCameraConfig: 使用するカメラソースをまとめたSora.CameraConfigのインスタンスVideoCodecType: 利用する映像コーデックを指定します。省略時は Sora のデフォルト値になりますVideoCodecImplementation: 利用する映像エンコーダー / デコーダーを指定します。省略時は Internal (libwebrtc 標準) になりますVideoVp9Params: VP9 コーデックのパラメーターを JSON 文字列で指定します。空文字や不正な値の場合はINVALID-MESSAGEエラーになります。VideoAv1Params: AV1 コーデックのパラメーターを JSON 文字列で指定します。空文字や不正な値の場合はINVALID-MESSAGEエラーになります。VideoH264Params: H.264 コーデックのパラメーターを JSON 文字列で指定します。空文字や不正な値の場合はINVALID-MESSAGEエラーになります。
Sora.CameraConfig¶
Sora.CameraConfig クラスはカメラソースを定義します。プロパティは以下の通りです。
CapturerType: カメラの種類を指定します (DeviceCamera/UnityCamera/TextureのいずれかでデフォルトはDeviceCamera)UnityCamera: Unity カメラを送信する場合に指定しますUnityCameraRenderTargetDepthBuffer: Unity カメラのレンダーターゲットに確保する深度バッファビット数を指定します (デフォルトは16)VideoCapturerDevice: 利用する物理カメラのDeviceNameもしくはUniqueNameを指定します(空文字の場合はデフォルトデバイスを利用します)VideoWidth: 映像の幅を指定します(デフォルトは640)VideoHeight: 映像の高さを指定します(デフォルトは480)VideoFps: 映像のフレームレートを指定します(デフォルトは30)Texture:RenderTextureを送信する場合に指定します
Sora.CameraConfig のヘルパーメソッド¶
Sora.CameraConfig には設定生成を簡単にするヘルパーメソッドが用意されています。
各プロパティを個別に設定する代わりに、これらのメソッドを使うことで適切な設定のインスタンスを簡単に作成できます。
物理カメラを使用する場合:
Sora.CameraConfig.FromDeviceCamera(string videoCapturerDevice, int videoWidth, int videoHeight, int videoFps)
端末の内蔵カメラ、外付け Web カメラなどの物理カメラを送信ソースとして設定します。
videoCapturerDevice:Sora.GetVideoCapturerDevices()で取得したデバイスのDeviceNameまたはUniqueNameを指定videoWidth,videoHeight: 送信する映像の解像度(例:1280 x 720)videoFps: 送信するフレームレート(例:30 fps)
Unity カメラを使用する場合:
Sora.CameraConfig.FromUnityCamera(UnityEngine.Camera unityCamera, int unityCameraRenderTargetDepthBuffer, int videoWidth, int videoHeight, int videoFps)
Unityシーン内のカメラが映している内容を送信ソースとして設定します。ゲーム画面やCG映像を配信したい場合に使用します。
unityCamera: 送信したい Unity の Camera コンポーネント(例:Camera.main)unityCameraRenderTargetDepthBuffer: RenderTexture 深度バッファビット数(通常は16または24)videoWidth,videoHeight: 送信する映像の解像度videoFps: 送信するフレームレート
Texture を使用する場合:
Sora.CameraConfig.FromTexture(UnityEngine.Texture texture, int videoFps)
Unity で生成・管理している任意の Texture を送信ソースとして指定します。
texture: 送信したいTexture(RenderTexture推奨)videoFps: 送信するフレームレート
ヘルパーメソッドを利用すると CapturerType に応じた必要な設定を利用することができます。
Sora クラスの映像関連 API¶
Sora.Connect(Sora.Config config): 指定した設定で接続しますSora.VideoEnabled: ソフトミュートのためのトグルプロパティSora.SwitchCamera(Sora.CameraConfig cameraConfig): 接続中に送信カメラを切り替えます。NoVideoDeviceの設定に依存せず呼び出しますSora.OnRender(): Unity カメラを利用する場合にWaitForEndOfFrame後に呼び出してフレームを送信しますSora.OnCapturerFrame: キャプチャ直後のフレームを受け取るコールバック。別スレッドで実行されますSora.GetVideoCapturerDevices(): 利用可能なカメラデバイス一覧をSora.DeviceInfo[]で取得します (列挙に失敗した場合はnullが返ります)Sora.OnAddTrack/Sora.OnRemoveTrack: 受信映像トラックの追加・削除時に通知されますSora.GetVideoTrackFromVideoSinkId(uint videoSinkId):videoSinkIdから対応するVideoTrackを取得します。指定したvideoSinkIdに対応するVideoTrackが見つからない場合は例外をスローしますSora.VideoTrack: 映像トラックを表します。Sora.GetVideoTrackFromVideoSinkId()やSora.OnMediaStreamTrackで取得できますVideoTrack.GetVideoSinkId(Sora sora): このVideoTrackに対応するvideoSinkIdを取得します
Sora.RenderTrackToTexture(uint videoSinkId, Texture texture):videoSinkIdで受信した映像をtextureにレンダリングします。送信中の場合、自身のvideoSinkIdを指定すれば送信映像もレンダリングできますSora.DispatchEvents(): メインスレッドでイベントを処理するためにUpdate()などから呼び出します
利用方法¶
接続と送信設定¶
以下は基本的な送信設定の例です。例では既に初期化済みの Sora インスタンス (sora) を利用しています。
// Inspector などで取得した設定値をもとに送信設定を組み立てる例
Sora sora; // 初期化済みの Sora インスタンス
var signalingUrl = "wss://example.com/signaling"; // シグナリング URL
var channelId = "sora"; // チャンネル ID
var selectedDevice = "camera_unique_name"; // 利用するデバイスカメラ名
Camera capturedCamera = Camera.main; // Unity カメラ送信時に利用するカメラ
var renderTargetDepth = 16; // RenderTexture の深度バッファビット数
int videoWidth = 1280; // 映像の幅
int videoHeight = 720; // 映像の高さ
int videoFps = 30; // 映像のフレームレート
int videoBitRate = 1500; // 映像のビットレート (kbps)
var useUnityCamera = false; // true なら Unity カメラを送信
var disableDevice = false; // true なら NoVideoDevice を有効化
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
Role = Sora.Role.Sendrecv,
Video = true, // 映像送信を有効化
NoVideoDevice = disableDevice, // 物理カメラデバイスを利用しない場合は true
VideoBitRate = videoBitRate, // 送信ビットレート (kbps)
};
// 物理カメラか Unity カメラかを判定してカメラソースを設定
// 使用するカメラに応じて、ヘルパーメソッドで CameraConfig を生成します
// useUnityCamera が true かつ capturedCamera が null でない場合は Unity カメラを使用します
// それ以外の場合、物理カメラデバイスを使用 (Web カメラなどの実カメラを送信)します
config.CameraConfig = useUnityCamera && capturedCamera != null
? Sora.CameraConfig.FromUnityCamera(capturedCamera, renderTargetDepth, videoWidth, videoHeight, videoFps)
: Sora.CameraConfig.FromDeviceCamera(selectedDevice, videoWidth, videoHeight, videoFps);
sora.Connect(config);
利用可能なカメラデバイスの列挙¶
Sora.GetVideoCapturerDevices() を使うと利用可能なカメラデバイスを取得できます。
戻り値は Sora.DeviceInfo[] で、列挙が失敗した場合は null が返ります。
取得したデバイス名、UniqueName を使って Sora.CameraConfig.VideoCapturerDevice に設定できます。
ここでは取得結果をログに出力する例を示します。
void DumpDeviceInfo(string label, Sora.DeviceInfo[] devices)
{
if (devices == null || devices.Length == 0)
{
// デバイスが見つからない場合の処理
Debug.LogWarning($"{label}: device not found");
return;
}
foreach (var device in devices)
{
// DeviceName と UniqueName をログに出力
Debug.Log($"{label}: DeviceName={device.DeviceName}, UniqueName={device.UniqueName}");
}
}
void Start()
{
// 例として起動時にデバイス一覧を出力
DumpDeviceInfo("video capturer devices", Sora.GetVideoCapturerDevices());
}
映像コーデックとビットレートの設定¶
映像品質に影響する主要な設定について説明します。
コーデックの指定¶
Sora.Config.VideoCodecType を使用して利用する映像コーデックを指定できます。省略した場合は Sora サーバーのデフォルト値が使用されます。
利用可能なコーデック:
Sora.VideoCodecType.VP9Sora.VideoCodecType.VP8Sora.VideoCodecType.H264Sora.VideoCodecType.AV1Sora.VideoCodecType.H265
コーデックを利用する前に、クライアントがそのエンコーダ/デコーダを利用可能か Sora.GetVideoCodecCapability() で確認してください。
Encoder / Decoder が true でないコーデックを指定すると、接続処理や切断処理でクラッシュする恐れがあります。
コーデックパラメーターの指定¶
各コーデックには詳細なパラメーターを設定できます。
VP9 のパラメーター¶
Sora.Config.VideoVp9Params で VP9 コーデックのプロファイル ID を JSON 文字列として指定できます。
// SoraSample.cs を参考にした VP9 のパラメーターを設定するサンプルコード
// enableVideoVp9Params が true の場合に VP9 パラメーターを設定します
// VP9 パラメーターを設定する場合有効にする
public bool enableVideoVp9Params = false;
// VP9 パラメーターを設定 0, 1, 2, 3 が利用可能
public int videoVp9ParamsProfileId;
// VP9 パラメーターを設定する場合は JSON 文字列を設定する
string videoVp9ParamsJson = "";
if (enableVideoVp9Params)
{
var vp9Params = new VideoVp9Params()
{
profile_id = videoVp9ParamsProfileId
};
videoVp9ParamsJson = JsonUtility.ToJson(vp9Params);
}
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
VideoCodecType = Sora.VideoCodecType.VP9,
VideoVp9Params = videoVp9ParamsJson,
};
AV1 のパラメーター¶
Sora.Config.VideoAv1Params で AV1 コーデックのプロファイルを JSON 文字列として指定できます。
// SoraSample.cs を参考にした AV1 のパラメーターを設定するサンプルコード
// enableVideoAv1Params が true の場合に AV1 パラメーターを設定します
// AV1 パラメーターを設定する場合有効にする
public bool enableVideoAv1Params = false;
// AV1 パラメーターを設定 0, 1, 2 が利用可能
public int videoAv1ParamsProfile;
// AV1 パラメーターを設定する場合は JSON 文字列を設定する
string videoAv1ParamsJson = "";
if (enableVideoAv1Params)
{
var av1Params = new VideoAv1Params()
{
profile = videoAv1ParamsProfile
};
videoAv1ParamsJson = JsonUtility.ToJson(av1Params);
}
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
VideoCodecType = Sora.VideoCodecType.AV1,
VideoAv1Params = videoAv1ParamsJson,
};
H.264 のパラメーター¶
Sora.Config.VideoH264Params で H.264 コーデックのプロファイルレベル ID を JSON 文字列として指定できます。
// SoraSample.cs を参考にした H.264 のパラメーターを設定するサンプルコード
// enableVideoH264Params が true の場合に H.264 パラメーターを設定します
// H.264 パラメーターを設定する場合有効にする
public bool enableVideoH264Params = false;
// H.264 パラメーターを設定
// 例: "42e01f" はレベル 3.1
public string videoH264ParamsProfileLevelId = "";
// H.264 パラメーターを設定する場合は JSON 文字列を設定する
string videoH264ParamsJson = "";
if (enableVideoH264Params)
{
var h264Params = new VideoH264Params()
{
profile_level_id = videoH264ParamsProfileLevelId
};
videoH264ParamsJson = JsonUtility.ToJson(h264Params);
}
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
VideoCodecType = Sora.VideoCodecType.H264,
VideoH264Params = videoH264ParamsJson,
};
ビットレートの設定¶
Sora.Config.VideoBitRate で送信ビットレート(kbps)を指定できます。省略した場合は Sora サーバーのデフォルト値が使用されます。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
VideoCodecType = Sora.VideoCodecType.H264, // コーデックを指定
VideoBitRate = 1500, // ビットレート(kbps)を指定
};
sora.Connect(config);
VideoCodecImplementation を使用してエンコーダー/デコーダーの実装を指定することも可能です。
詳細は エンコーダー / デコーダーの指定 を参照してください。
Unity カメラを送信する場合¶
Unity カメラを映像送信に利用する場合の設定と実装方法を説明します。
設定方法¶
Unity カメラを使用する場合は CameraConfig で CapturerType.UnityCamera を指定し、送信したいカメラを設定します。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
CameraConfig = new Sora.CameraConfig()
{
CapturerType = Sora.CapturerType.UnityCamera,
UnityCamera = capturedCamera, // 送信したいCamera
VideoFps = 30,
VideoWidth = 1280,
VideoHeight = 720,
},
};
または、ヘルパーメソッドを使用することもできます:
config.CameraConfig = Sora.CameraConfig.FromUnityCamera(capturedCamera, 16, 1280, 720, 30);
フレーム送信の実装¶
Unity カメラを送信する際は WaitForEndOfFrame の最後で Sora.OnRender() を呼び出します。
この処理はコルーチンとして実装し、Start() などで開始してください。
void Start()
{
StartCoroutine(Render());
}
IEnumerator Render()
{
while (true)
{
yield return new WaitForEndOfFrame(); // Unity の描画完了を待機
if (sora != null)
{
// OnRender() は必ず WaitForEndOfFrame の後に呼び出すこと
sora.OnRender(); // Unity カメラの映像フレームを Sora に転送
}
}
}
Texture を送信する場合¶
CapturerType.Texture を使うと、任意の Texture を映像トラックとして送信できます。ポストプロセス済みのゲーム画面やコンピュートシェーダーの結果などを配信したい場合に有効です。
注釈
Texture2D なども指定できますが、ピクセルを書き換えるたびに Unity が内部テクスチャを作り直し、以前に取得した GetNativeTexturePtr() が無効になります。
Sora に渡したポインタが切れてしまうため、動的に更新する場合は RenderTexture を Sora に渡し、Graphics.Blit(Texture2D, RenderTexture) などで内容を反映させる運用を推奨します。
設定例¶
// 生成した RenderTexture を Sora に送信し、かつ画面に表示するサンプル
// 事前に RenderTexture を用意していない場合でも自動で生成します
Sora sora;
// RenderTexture を送る(Inspector で割り当て可。未設定なら生成)
public RenderTexture captureTargetTexture;
// captureTargetTexture の内容を画面表示する Texture
public Texture2D stagingTexture;
InitSora();
GetVideoSize(videoSize, out var videoWidth, out var videoHeight);
// RenderTexture 未割り当てなら生成
if (captureTargetTexture == null)
{
captureTargetTexture = new RenderTexture(videoWidth, videoHeight, 16, RenderTextureFormat.BGRA32);
captureTargetTexture.Create();
}
else if (!captureTargetTexture.IsCreated())
{
captureTargetTexture.Create();
}
// stagingTexture もサイズを揃える
if (stagingTexture == null ||
stagingTexture.width != captureTargetTexture.width ||
stagingTexture.height != captureTargetTexture.height)
{
stagingTexture = new Texture2D(captureTargetTexture.width, captureTargetTexture.height, TextureFormat.BGRA32, false);
}
// stagingTexture を更新して RenderTexture に反映(内容を書き換えた直後に呼ぶ)
stagingTexture.Apply(false, false);
Graphics.Blit(stagingTexture, captureTargetTexture);
// RenderTexture を送る設定
var cameraConfig = Sora.CameraConfig.FromTexture(captureTargetTexture, videoFps);
var config = new Sora.Config()
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
CameraConfig = cameraConfig,
};
sora.Connect(config);
// 毎フレーム更新したい場合は Update() で
void Update()
{
if (stagingTexture != null && captureTargetTexture != null)
{
stagingTexture.Apply(false, false);
Graphics.Blit(stagingTexture, captureTargetTexture);
}
}
カメラの切り替え¶
接続中にデバイスカメラとUnityカメラを切り替える場合は SwitchCamera() を使用します。
// クラスのフィールドとして定義
Sora sora;
public Camera capturedCamera;
public string videoCapturerDevice = "";
public void SwitchToUnityCamera()
{
if (sora == null) return;
sora.SwitchCamera(Sora.CameraConfig.FromUnityCamera(capturedCamera, 16, 1280, 720, 30));
}
public void SwitchToDeviceCamera()
{
if (sora == null) return;
sora.SwitchCamera(Sora.CameraConfig.FromDeviceCamera(videoCapturerDevice, 1280, 720, 30));
}
ソフトミュートとハードミュート¶
ミュートにはデバイスを維持するソフトミュートと、デバイス自体を利用しないハードミュートの 2 種類があります。
ソフトミュートは Sora.VideoEnabled を切り替えて行います。この場合カメラデバイスは解放されません。
public void ToggleVideo()
{
if (sora == null) return;
sora.VideoEnabled = !sora.VideoEnabled;
}
カメラデバイスを利用しないハードミュートは接続時に Sora.Config.NoVideoDevice を true に設定することで行います。
警告
送信中ハードウェアミュートに切り替えることはできず、再接続をする必要があります。
Sora.SwitchCamera() を呼び出すとカメラを取得しに行くため、ハードミュート中は呼び出さないでください。
意図せずカメラを取得してミュートが解除されることがあります。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
NoVideoDevice = true, // 物理カメラデバイスを利用しない
};
sora.Connect(config);
映像受信の処理¶
受信した映像トラックは OnAddTrack / OnRemoveTrack で管理し、RenderTrackToTexture で描画します。
connectionId が空文字の場合は自身の映像です。
この例は SoraUnitySdkExamples の SoraSample.cs にもありますのでそちらも参考にしてください。
// 受信映像トラックを管理するためのDictionary
Dictionary<string, GameObject> tracks = new Dictionary<string, GameObject>();
// 映像トラックが追加された時のコールバック
sora.OnAddTrack = (videoSinkId, connectionId) =>
{
// UI要素を生成(baseContentはプリファブとして事前に用意)
// Hierarchy に Canvas を作成して RawImage を対象にすると簡単です
var obj = Instantiate(baseContent);
obj.name = $"track {videoSinkId}";
obj.transform.SetParent(scrollViewContent.transform);
obj.SetActive(true);
// 映像を描画するためのテクスチャを生成
var image = obj.GetComponent<UnityEngine.UI.RawImage>();
image.texture = new Texture2D(320, 240, TextureFormat.RGBA32, false);
// トラック管理用のDictionaryに追加
tracks[videoSinkId] = obj;
};
// 映像トラックが削除された時のコールバック
sora.OnRemoveTrack = (videoSinkId, connectionId) =>
{
if (!tracks.TryGetValue(videoSinkId, out var obj)) return;
// テクスチャとGameObjectを適切に破棄
var image = obj.GetComponent<UnityEngine.UI.RawImage>();
Destroy(image.texture);
Destroy(obj);
tracks.Remove(videoSinkId);
};
void Update()
{
if (sora == null) return;
// 受信イベントをメインスレッドで処理(必須)
sora.DispatchEvents();
// 各トラックの映像をテクスチャに描画
foreach (var pair in tracks)
{
var image = pair.Value.GetComponent<UnityEngine.UI.RawImage>();
// 受信映像をテクスチャに描画(毎フレーム呼び出す)
sora.RenderTrackToTexture(pair.Key, image.texture);
}
}