音声の送信と受信¶
Sora Unity SDK で音声を送信・受信する際に必要となる設定や API について説明します。
音声送信と受信の提供機能について¶
Sora Unity SDK では以下を提供しています。
デバイスマイクを音声送信に利用する
Unity 内で生成した音声を送信する
音声送信を一時停止する (ソフトミュート)
録音デバイスを利用しない (ハードミュート)
利用可能な録音・再生デバイス一覧を取得する
受信した音声を任意の方法で再生する
音声コーデックやビットレートを指定する
ハンズフリー切り替えなど再生経路を制御する
利用時の注意事項¶
Sora.OnHandleAudioは Unity スレッドとは別スレッドで呼び出されます。バッファ操作時はロックなどで同期を取ってくださいSora.DispatchEvents()を呼び出さなくてもSora.OnHandleAudioは発火しますSora.ProcessAudio()は 48000Hz Stereo のデータのみ受け取ることができますConfig.UnityAudioInputをtrueにしている場合、NoAudioDeviceをtrueにしても Unity 側の音声入力は継続します
音声関連の API リファレンス¶
Sora.Config¶
Sora.Config クラスは Sora インスタンスの接続設定を定義します。音声送信・受信に関する主なプロパティは以下の通りです。
Audio: 音声トラックを有効にするかどうか。falseにすると停止しますNoAudioDevice: 物理マイクデバイスを利用しない場合にtrueを設定しますUnityAudioInput: Unity で生成した音声をSora.ProcessAudio()から送信する場合にtrueを設定しますUnityAudioOutput: OS の再生デバイスではなくSora.OnHandleAudioコールバックで音声を受け取りたい場合にtrueを設定しますAudioRecordingDevice: 利用する録音デバイスのDeviceNameまたはUniqueName(空文字ならデフォルトデバイス)AudioPlayoutDevice: 利用する再生デバイスのDeviceNameまたはUniqueName(空文字ならデフォルトデバイス)AudioCodecType: 利用する音声コーデックを指定します (現状はSora.AudioCodecType.OPUSのみ)AudioBitRate: 音声のビットレート (kbps)。省略時は Sora のデフォルト値になりますAudioStreamingLanguageCode: 字幕用途などで利用する言語コードを指定します
Sora クラスの音声関連 API¶
Sora.Connect(Sora.Config config): 指定した設定で接続しますSora.ProcessAudio(float[] data, int offset, int samples):UnityAudioInput利用時に送信したいサンプルを渡しますSora.OnHandleAudio:UnityAudioOutput利用時に受信音声を取得するコールバックSora.AudioEnabled: ソフトミュートのためのトグルプロパティSora.GetAudioRecordingDevices()/Sora.GetAudioPlayoutDevices(): 利用可能な録音・再生デバイス一覧をSora.DeviceInfo[]で取得します (列挙に失敗した場合はnull)Sora.OnMediaStreamTrack: 受信したトラックを取得するコールバック。音声トラックの場合はAudioTrackとconnectionIdを取得できます。track.Kindで音声か映像かを判別できますSora.OnRemoveMediaStreamTrack: トラックの削除時に通知されますSora.DispatchEvents(): メインスレッドでイベントを処理しますOnHandleAudio以外のコールバックでは呼び出しが必要です
Sora.AudioTrack クラスの API¶
SetVolume(double volume): このトラックの再生音量を設定します (0.0〜10.0)
注釈
音声データを直接取得する機能は、音声データ取得機能 を参照してください。
利用方法¶
接続と送受信設定¶
以下は基本的な送受信設定の例です。例では既に初期化済みの Sora インスタンス (sora) を利用しています。
Sora sora; // 初期化済みの Sora インスタンス
var signalingUrl = "wss://example.com/signaling"; // シグナリング URL
var channelId = "sora"; // チャンネル ID
var unityAudioInput = false; // true なら Unity 内で生成した音声を送信
var unityAudioOutput = false; // true なら再生を Unity 側で処理
var disableDevice = false; // true なら NoAudioDevice を有効化
var recordingDevice = ""; // 空文字ならデフォルト録音デバイス
var playoutDevice = ""; // 空文字ならデフォルト再生デバイス
var config = new Sora.Config()
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
Role = Sora.Role.Sendrecv,
Audio = true, // 音声送信を有効化
NoAudioDevice = disableDevice, // 録音デバイスを利用しない場合は true
UnityAudioInput = unityAudioInput, // Unity 生成音声を送信する場合に true
UnityAudioOutput = unityAudioOutput, // Unity 側で再生する場合に true
AudioRecordingDevice = recordingDevice, // 利用する録音デバイス
AudioPlayoutDevice = playoutDevice, // 利用する再生デバイス
};
sora.Connect(config);
利用可能なオーディオデバイスの列挙¶
Sora.GetAudioRecordingDevices() と Sora.GetAudioPlayoutDevices() を使うと利用可能なデバイスを取得できます。取得結果をログに出力する例です。
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)
{
// デバイス情報をログに出力
Debug.Log($"{label}: DeviceName={device.DeviceName}, UniqueName={device.UniqueName}");
}
}
void Start()
{
DumpDeviceInfo("audio recording devices", Sora.GetAudioRecordingDevices());
DumpDeviceInfo("audio playout devices", Sora.GetAudioPlayoutDevices());
}
音声コーデックとビットレートの設定¶
音質に影響する主要な設定について説明します。
コーデックの指定¶
Sora.Config.AudioCodecType を使用して利用する音声コーデックを指定できます。省略した場合は Sora サーバーのデフォルト値が使用されます (現状 OPUS のみ)。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
AudioCodecType = Sora.AudioCodecType.OPUS, // コーデックを指定
};
sora.Connect(config);
ビットレートの設定¶
Sora.Config.AudioBitRate で送信ビットレート (kbps) を指定できます。省略した場合は Sora サーバーのデフォルト値が使用されます。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
AudioBitRate = 64, // 音声のビットレート (kbps) を指定
};
sora.Connect(config);
Unity 音声入力を送信する場合¶
Unity で生成した音声を送信する場合は UnityAudioInput を true にし、Sora.ProcessAudio() にフレームデータを渡します。
以下は AudioRenderer を利用して 1 フレーム分のサンプルを送る例です。
void Start()
{
StartCoroutine(RenderAudio());
}
IEnumerator RenderAudio()
{
// Unity 内で音を鳴らしておくとキャプチャ状況を確認しやすい
audioSourceInput.Play();
// オーディオレンダラーを開始
AudioRenderer.Start();
while (true)
{
// Sora インスタンスが存在し、Unity 音声入力が有効な場合のみ処理する
if (sora == null || !unityAudioInput) continue;
// 1 フレーム分のサンプル数を取得する
var samples = AudioRenderer.GetSampleCountForCaptureFrame();
// ステレオモードでない場合はスキップ
if (AudioSettings.speakerMode != AudioSpeakerMode.Stereo) continue;
// ステレオ (2 チャンネル) 分のバッファを確保
using (var buf = new Unity.Collections.NativeArray<float>(samples * 2, Unity.Collections.Allocator.Temp))
{
// オーディオデータをレンダリング
AudioRenderer.Render(buf);
// Sora 経由で音声データを送信
sora.ProcessAudio(buf.ToArray(), 0, samples);
}
}
}
ソフトミュートとハードミュート¶
音声ミュートにはデバイスを維持するソフトミュートと、デバイス自体を利用しないハードミュートの 2 種類があります。
ソフトミュートは Sora.AudioEnabled を切り替えて行います。この場合マイクデバイスは解放されません。
public void ToggleAudio()
{
if (sora == null) return;
sora.AudioEnabled = !sora.AudioEnabled;
}
ハードミュートは接続時に Sora.Config.NoAudioDevice を true に設定します。送信中に切り替えることはできないため、設定を変える場合は再接続が必要です。
var config = new Sora.Config
{
SignalingUrl = signalingUrl,
ChannelId = channelId,
NoAudioDevice = true, // 物理マイクデバイスを利用しない
};
sora.Connect(config);
警告
UnityAudioInput が true の場合、NoAudioDevice を true にしても Unity からの音声入力は継続します。
Unity 内で受信音声を再生する場合¶
Config.UnityAudioOutput を true にすると、受信音声が Sora.OnHandleAudio でコールバックされます。以下はキューを使って AudioClip に流し込む例です。
// 受信した音声データを保持するキュー
Queue<short[]> audioBuffer = new Queue<short[]>();
// キューに格納されているサンプル数の合計
int audioBufferSamples = 0;
// 現在読み取り中のチャンク内の位置
int audioBufferPosition = 0;
void SetupAudioOutput()
{
// 音声データ受信時のコールバックを設定
sora.OnHandleAudio = (buf, samples, channels) =>
{
lock (audioBuffer)
{
// 受信したバッファをキューに追加
audioBuffer.Enqueue(buf);
// サンプル数を加算
audioBufferSamples += samples;
}
};
// 複数の受信者がいる場合は、重複にならないよう "Remote_{connectionId}" などを使用してください
// 48000Hz Stereo のデータのみ受け取ることができます
var clip = AudioClip.Create("Remote", 480000, 1, 48000, true, data =>
{
lock (audioBuffer)
{
// バッファが空、またはデータ不足の場合は無音を返す
if (audioBuffer.Count == 0 || audioBufferSamples < data.Length)
{
Array.Fill(data, 0.0f);
return;
}
// キューの先頭チャンクを取得
var chunk = audioBuffer.Peek();
// 要求されたデータ長分のサンプルを取り出す
for (int i = 0; i < data.Length; ++i)
{
// 現在のチャンクを読み終えた場合、次のチャンクへ移動
while (audioBufferPosition >= chunk.Length)
{
audioBuffer.Dequeue();
chunk = audioBuffer.Peek();
audioBufferPosition = 0;
}
// short 型 (±32768) から float 型 (±1.0) に変換
data[i] = chunk[audioBufferPosition] / 32768.0f;
++audioBufferPosition;
}
// 処理したサンプル数を減算
audioBufferSamples -= data.Length;
}
});
// AudioClip を AudioSource にセットして再生開始
audioSourceOutput.clip = clip;
audioSourceOutput.Play();
}
ハンズフリー制御 (Sora.IAudioOutputHelper)¶
Sora.AudioOutputHelperFactory.Create() で IAudioOutputHelper を生成すると、ハンズフリー切り替えなどの再生経路制御が可能になります。詳細は ハンズフリー も参照してください。
Sora.IAudioOutputHelper audioOutputHelper;
void InitAudioOutputHelper()
{
// ルート変更時に呼ばれるコールバックを指定して生成
audioOutputHelper = Sora.AudioOutputHelperFactory.Create(OnChangeRoute);
}
void OnChangeRoute()
{
if (audioOutputHelper == null) return;
// ルート変更を検知して処理を行う
Debug.Log("音声ルートが変更されました: " +
(audioOutputHelper.IsHandsfree() ? "ハンズフリー ON" : "ハンズフリー OFF"));
}
public void OnClickHandsfree()
{
if (audioOutputHelper == null) return;
audioOutputHelper.SetHandsfree(!audioOutputHelper.IsHandsfree());
}