# 音声データ取得機能

Sora Unity SDK では音声トラックから非圧縮の音声データを取得する仕組みを提供しています。

音声トラックを表す `AudioTrack` に `IAudioTrackSink` を関連付けると、音声データを音声トラックごとにコールバックで受け取ることができます。

ここでは、音声データ取得機能と利用方法について説明します。基本的な音声送受信については [音声の送信と受信](functions_audio.html) を参照してください。

## 音声データの形式

コールバックで取得できる音声データは非圧縮の `16 bit PCM (Pulse Code Modulation)` 形式です。

`IAudioTrackSink` インターフェースは以下のように定義されています。

```csharp
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` を実装したクラスを設定すると、送信中の音声データを取得できます。

```csharp
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` を関連付けることは可能で、各シンクは独立して同一のトラックから音声データを受け取ります

### 実装例

以下は受信音声トラックごとに音声データを取得する例です。

```csharp
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);
        }
    };
}
```
