音声データ取得機能¶
Sora Unity SDK では音声トラックから非圧縮の音声データを取得する仕組みを提供しています。
音声トラックを表す AudioTrack に IAudioTrackSink を関連付けると、音声データを音声トラックごとにコールバックで受け取ることができます。
ここでは、音声データ取得機能と利用方法について説明します。基本的な音声送受信については 音声の送信と受信 を参照してください。
音声データの形式¶
コールバックで取得できる音声データは非圧縮の 16 bit PCM (Pulse Code Modulation) 形式です。
IAudioTrackSink インターフェースは以下のように定義されています。
public interface IAudioTrackSink
{
void OnData(short[] data, int bitsPerSample, int sampleRate,
int numberOfChannels, int numberOfFrames,
long? absoluteCaptureTimestampMs);
}
OnData() コールバックのパラメータ:
data: PCM 形式の音声データ (short 配列)bitsPerSample: 1 サンプル当たりのビット数 (libwebrtc では常に 16)sampleRate: サンプルレート (単位: Hz)numberOfChannels: 音声データのチャンネル数 (モノラルなら 1、ステレオなら 2)numberOfFrames: data に含まれるフレーム数absoluteCaptureTimestampMs: キャプチャ時刻 (ミリ秒)
送信音声データを取得する¶
Sora.SenderAudioTrackSink に IAudioTrackSink を実装したクラスを設定すると、送信中の音声データを取得できます。
class AudioDataSink : Sora.IAudioTrackSink
{
public void OnData(short[] data, int bitsPerSample, int sampleRate,
int numberOfChannels, int numberOfFrames,
long? absoluteCaptureTimestampMs)
{
// PCM 音声データを処理
Debug.Log($"送信音声データ: sampleRate={sampleRate}, channels={numberOfChannels}, frames={numberOfFrames}");
}
}
void Start()
{
sora.SenderAudioTrackSink = new AudioDataSink();
}
受信音声データを取得する¶
Sora.OnMediaStreamTrack コールバックで受信した AudioTrack に IAudioTrackSink を追加すると、各トラックの音声データを個別に取得できます。
AudioTrack の識別方法¶
IAudioTrackSink.OnData() で受け取る音声データがどのトラックのものか判断するには、OnMediaStreamTrack コールバックで渡される AudioTrack や connectionId を使用してください。
connectionId は Sora サーバーが払い出すコネクション ID です。
AudioTrackSink と AudioTrack の関連付けについて¶
IAudioTrackSinkとAudioTrackの関連付けは 1:1 を前提に設計されています1 つの
IAudioTrackSinkを複数のAudioTrackに同時に関連付ける 1:N の利用は想定していません一方で、1 本の
AudioTrackに対して複数のIAudioTrackSinkを関連付けることは可能で、各シンクは独立して同一のトラックから音声データを受け取ります
実装例¶
以下は受信音声トラックごとに音声データを取得する例です。
class AudioTrackSink : Sora.IAudioTrackSink
{
public void OnData(short[] data, int bitsPerSample, int sampleRate,
int numberOfChannels, int numberOfFrames,
long? absoluteCaptureTimestampMs)
{
// PCM 音声データを処理
Debug.Log($"受信音声データ: sampleRate={sampleRate}, channels={numberOfChannels}, frames={numberOfFrames}");
}
}
Dictionary<string, AudioTrackSink> audioSinks = new Dictionary<string, AudioTrackSink>();
void Start()
{
sora.OnMediaStreamTrack = (transceiver, track, connectionId) =>
{
if (track.Kind == Sora.MediaStreamTrack.AudioKind)
{
var audioTrack = track as Sora.AudioTrack;
var sink = new AudioTrackSink();
audioTrack.AddSink(sora, sink);
audioSinks[connectionId] = sink;
}
};
sora.OnRemoveMediaStreamTrack = (receiver, track, connectionId) =>
{
if (track.Kind == Sora.MediaStreamTrack.AudioKind && audioSinks.ContainsKey(connectionId))
{
var audioTrack = track as Sora.AudioTrack;
audioTrack.RemoveSink(sora, audioSinks[connectionId]);
audioSinks.Remove(connectionId);
}
};
}