Skip to main content

Audio Engine API

音声キャプチャ・再生エンジンの内部API定義。


1. 概要

Audio Engineは以下の責務を持つ:

  • オーディオデバイスの列挙・選択
  • 音声キャプチャ(入力)
  • 音声再生(出力)
  • ローカルモニタリング
  • サンプルレート変換
  • デバイス切断時の自動フォールバック

1.1 自動開始仕様

アプリケーション起動時、オーディオエンジンは自動的に開始される:

  • 開始タイミング: Tauriアプリケーションのsetupフック内
  • 使用デバイス: システムのデフォルト入力/出力デバイス
  • Start/Stopボタン: UIに残すが、デバイス切り替えは即時反映
  • 失敗時: エラーログを出力し、ユーザーは手動でデバイスを選択して再試行

1.2 デバイス即時切り替え

デバイス選択UIでデバイスを変更した場合:

  • 入力デバイス: 即座にキャプチャストリームを再作成(10-50msの音切れ)
  • 出力デバイス: 即座に再生ストリームを再作成(10-50msの音切れ)
  • 停止→再開始の操作は不要

1.3 デバイス切断時の自動フォールバック

使用中のデバイスが切断された場合:

  • cpalのStreamError::DeviceNotAvailableを検知
  • システムのデフォルトデバイスに自動切り替え
  • フロントエンドにdevice-disconnectedイベントを送信
  • UIにトースト通知を表示

2. モジュール構成

audio/
├── codec.rs # コーデック(PCM, Opus)
├── device.rs # デバイス管理
├── engine.rs # オーディオエンジン(キャプチャ・再生)
├── error.rs # エラー型
├── plc.rs # Packet Loss Concealment
└── resampler.rs # サンプルレート変換(ADR-013)

3. デバイス管理 API

3.1 デバイス列挙

/// 利用可能な入力デバイス一覧を取得
///
/// スレッド: 任意
/// ブロッキング: No
fn list_input_devices() -> Result<Vec<AudioDevice>, AudioError>;

/// 利用可能な出力デバイス一覧を取得
///
/// スレッド: 任意
/// ブロッキング: No
fn list_output_devices() -> Result<Vec<AudioDevice>, AudioError>;

3.2 デバイス情報

struct AudioDevice {
/// デバイス識別子
id: DeviceId,
/// 表示名
name: String,
/// 対応サンプルレート
supported_sample_rates: Vec<u32>,
/// 対応チャンネル数
supported_channels: Vec<u16>,
/// デフォルトデバイスかどうか
is_default: bool,
/// ASIO対応(Windowsのみ)
is_asio: bool,
}

3.3 デバイス選択

/// 入力デバイスを設定
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: Yes(デバイスオープン完了まで)
///
/// # 注意
/// キャプチャ中に呼び出した場合、キャプチャは停止される
fn set_input_device(device_id: DeviceId) -> Result<(), AudioError>;

/// 出力デバイスを設定
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: Yes(デバイスオープン完了まで)
///
/// # 注意
/// 再生中に呼び出した場合、再生は停止される
fn set_output_device(device_id: DeviceId) -> Result<(), AudioError>;

4. キャプチャ API

4.1 設定

struct CaptureConfig {
/// サンプルレート(Hz)
sample_rate: u32,
/// チャンネル数
channels: u16,
/// フレームサイズ(サンプル数)
frame_size: u32,
/// ビット深度
bit_depth: BitDepth,
}

enum BitDepth {
I16,
I24,
F32,
}

4.2 キャプチャ開始・停止

/// 音声キャプチャを開始
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: No(即座にリターン、キャプチャは別スレッドで実行)
///
/// # コールバック
/// キャプチャされた音声データは `on_audio_captured` コールバックで通知される
fn start_capture(config: CaptureConfig) -> Result<(), AudioError>;

/// 音声キャプチャを停止
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: Yes(キャプチャスレッド終了まで)
fn stop_capture() -> Result<(), AudioError>;

4.3 コールバック

/// 音声キャプチャコールバック
///
/// スレッド: リアルタイムオーディオスレッドから呼び出される
///
/// # 制約
/// - メモリアロケーション禁止
/// - ブロッキングI/O禁止
/// - ミューテックスの長時間保持禁止
/// - 処理時間: frame_size / sample_rate 以内(例: 128/48000 = 2.67ms)
fn on_audio_captured(data: &AudioBuffer, timestamp: u64);

5. 再生 API

5.1 設定

struct PlaybackConfig {
/// サンプルレート(Hz)
sample_rate: u32,
/// チャンネル数
channels: u16,
/// フレームサイズ(サンプル数)
frame_size: u32,
/// ビット深度
bit_depth: BitDepth,
}

5.2 再生開始・停止

/// 音声再生を開始
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: No
fn start_playback(config: PlaybackConfig) -> Result<(), AudioError>;

/// 音声再生を停止
///
/// スレッド: 非リアルタイムスレッドから呼び出すこと
/// ブロッキング: Yes
fn stop_playback() -> Result<(), AudioError>;

5.3 音声データ供給

/// 再生用音声データをキューに追加
///
/// スレッド: 任意(ロックフリーキュー使用)
/// ブロッキング: No
///
/// # 戻り値
/// キューに追加できた場合は Ok、キューが満杯の場合は Err
fn enqueue_audio(data: AudioBuffer, timestamp: u64) -> Result<(), AudioError>;

6. ローカルモニタリング API

/// ローカルモニタリングを有効化
///
/// スレッド: 任意
/// ブロッキング: No
///
/// # 動作
/// キャプチャした音声を遅延なしで出力にミックスする
fn enable_local_monitoring() -> Result<(), AudioError>;

/// ローカルモニタリングを無効化
fn disable_local_monitoring() -> Result<(), AudioError>;

/// ローカルモニタリングの音量を設定
///
/// # 引数
/// - volume: 0.0(無音)〜 1.0(最大)
fn set_local_monitoring_volume(volume: f32) -> Result<(), AudioError>;

7. ミキサー API

/// 参加者の音量を設定
///
/// スレッド: 任意(アトミック操作)
/// ブロッキング: No
///
/// # 引数
/// - participant_id: 参加者ID
/// - volume: 0.0(無音)〜 1.0(最大)
fn set_participant_volume(participant_id: ParticipantId, volume: f32);

/// 参加者をミュート
fn mute_participant(participant_id: ParticipantId);

/// 参加者のミュートを解除
fn unmute_participant(participant_id: ParticipantId);

/// マスター音量を設定
fn set_master_volume(volume: f32);

8. バッファ

8.1 AudioBuffer

struct AudioBuffer {
/// サンプルデータ(インターリーブ形式)
data: Vec<f32>,
/// チャンネル数
channels: u16,
/// サンプル数(チャンネルあたり)
samples: u32,
}

8.2 リングバッファ

/// ロックフリーリングバッファ
///
/// 単一プロデューサー・単一コンシューマー(SPSC)
struct RingBuffer<T> {
// ...
}

impl<T> RingBuffer<T> {
/// バッファを作成
fn new(capacity: usize) -> Self;

/// データをプッシュ(プロデューサー側)
/// ブロッキング: No
fn push(&self, item: T) -> Result<(), T>;

/// データをポップ(コンシューマー側)
/// ブロッキング: No
fn pop(&self) -> Option<T>;

/// 現在のアイテム数
fn len(&self) -> usize;
}

9. エラー

pub enum AudioError {
/// デバイスが見つからない
DeviceNotFound(String),
/// デバイスオープン失敗
DeviceOpenFailed(String),
/// サポートされていない設定
UnsupportedConfig(String),
/// ストリームエラー
StreamError(String),
/// バッファオーバーフロー
BufferOverflow,
/// バッファアンダーラン
BufferUnderrun,
/// リサンプリングエラー(ADR-013)
ResamplerError(String),
}

10. リサンプラー API(ADR-013)

ADR-013で決定された受信側リサンプリング戦略を実装するモジュール。

10.1 概要

  • 送信側: サンプルレート変換なし(ネイティブレートで送信)
  • 受信側: ピアのサンプルレートがローカルと異なる場合のみリサンプリング
  • 目的: 低遅延優先、必要な場合のみ変換

10.2 AudioResampler トレイト

/// Trait for audio resampling
pub trait AudioResampler: Send {
/// Process input samples and return resampled output
fn process(&mut self, input: &[f32]) -> Result<Vec<f32>, ResamplerError>;

/// Get the latency introduced by resampling in samples (at output rate)
fn latency_samples(&self) -> usize;

/// Get the latency introduced by resampling in milliseconds
fn latency_ms(&self, output_rate: u32) -> f32;
}

10.3 リサンプラー実装

/// Passthrough resampler for same sample rate (no conversion)
pub struct PassthroughResampler;

/// Fast resampler using rubato for real-time audio
pub struct FastResampler {
input_rate: u32,
output_rate: u32,
chunk_size: usize,
}

impl FastResampler {
/// Create a new fast resampler
///
/// # Arguments
/// * `input_rate` - Input sample rate in Hz
/// * `output_rate` - Output sample rate in Hz
/// * `chunk_size` - Expected input chunk size (frame size)
pub fn new(input_rate: u32, output_rate: u32, chunk_size: usize)
-> Result<Self, ResamplerError>;
}

10.4 ファクトリ関数

/// Create a resampler for the given sample rates
///
/// Returns a PassthroughResampler if input and output rates are the same,
/// otherwise returns a FastResampler.
pub fn create_resampler(
input_rate: u32,
output_rate: u32,
chunk_size: usize,
) -> Result<Box<dyn AudioResampler>, ResamplerError>;

10.5 ResamplerError

pub enum ResamplerError {
/// Resampler creation failed
CreationFailed(String),
/// Resampling failed
ProcessFailed(String),
/// Invalid sample rate
InvalidSampleRate(u32),
}

10.6 サポートされるサンプルレート

サンプルレート説明
44100 HzCD品質
48000 Hz推奨(標準)
96000 Hz高品質

11. デバイスイベント

11.1 AudioEvent

オーディオストリームで発生するイベント。デバイス切断検知に使用。

/// Events that can occur during audio streaming
#[derive(Debug, Clone)]
pub enum AudioEvent {
/// Input device was disconnected
InputDeviceDisconnected,
/// Output device was disconnected
OutputDeviceDisconnected,
/// Stream error occurred
StreamError(String),
}

11.2 イベント送信の設定

impl AudioEngine {
/// Set event sender for device change notifications
///
/// Thread: Non-realtime thread
/// Must be called before starting capture/playback
pub fn set_event_sender(&mut self, tx: Sender<AudioEvent>);
}

11.3 DeviceEvent(サービスレイヤー)

AudioServiceからフロントエンドへ送信されるイベント。

/// Events sent from the audio thread to notify about device changes
#[derive(Debug, Clone)]
pub enum DeviceEvent {
/// Input device was disconnected and fallback occurred
InputDeviceDisconnected {
/// Device name if fallback succeeded, None if failed
fallback_device: Option<String>,
},
/// Output device was disconnected and fallback occurred
OutputDeviceDisconnected {
/// Device name if fallback succeeded, None if failed
fallback_device: Option<String>,
},
}

11.4 Tauri イベント

フロントエンドへはdevice-disconnectedイベントとしてemitされる:

{
"type": "input" | "output",
"fallback": "default" | null
}

12. スレッドモデル

┌─────────────────────────────────────────────────────────┐
│ Main Thread │
│ (デバイス設定、開始/停止) │
└─────────────────────────────────────────────────────────┘

┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Capture Thread │ │ Playback Thread │ │ Monitor Thread │
│ (リアルタイム) │ │ (リアルタイム) │ │ (リアルタイム) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ ▲ │
│ │ │
▼ │ │
┌─────────────────────────┴───────────────┘
│ Lock-free Ring Buffer
└─────────────────────────────────────────┘

13. 使用例

// デバイス列挙
let inputs = list_input_devices()?;
let outputs = list_output_devices()?;

// デバイス選択
set_input_device(inputs[0].id)?;
set_output_device(outputs[0].id)?;

// キャプチャ設定
let config = CaptureConfig {
sample_rate: 48000,
channels: 1,
frame_size: 128,
bit_depth: BitDepth::F32,
};

// コールバック設定
set_capture_callback(|data, timestamp| {
// ネットワーク送信キューに追加
network.send_audio(data, timestamp);
});

// 開始
start_capture(config)?;
start_playback(playback_config)?;
enable_local_monitoring()?;

// ... セッション中 ...

// 停止
stop_capture()?;
stop_playback()?;