ハイライト
Apple は iOS 17、macOS 14、tvOS 17 で音声処理 API に 2 つの機能を追加しました。他のオーディオのダッキング(Other Audio Ducking)の細かな制御と、ミュート中の話者検出(Muted Talker Detection)です。これにより VoIP App は FaceTime のように背景音量を賢く調整し、ユーザーにミュート解除を促せます。
主要内容
背景音のダッキング: 一律制御から細かな制御へ
音声通話 App を作る開発者なら、通話中にユーザーが音楽や他のオーディオを再生し、背景音が大きすぎて声が聞き取りにくくなる場面に出会ったことがあるはずです。Apple の音声処理 API は以前から他のオーディオ音量を自動的に下げていましたが、ダッキング量は固定で、App によっては下がりすぎたり足りなかったりしました。
(03:16)今年、Apple は AUVoiceIO と AVAudioEngine の両方にダッキング設定 API を追加しました。開発者は、ダッキングスタイル(高度な動的ダッキングを有効にするか)とダッキング強度(4 段階)の 2 つの軸を制御できます。
高度な動的ダッキングの効果は FaceTime SharePlay に似ています。誰かが話している間はメディア音量が自動的に下がり、誰も話していないときは元に戻ります。これにより、通話と背景オーディオを自然に共存させられます。
ミュート中の話者検出: 「話していたのにマイクがオフだった」をなくす
オンライン会議で最も気まずい場面の 1 つは、ユーザーが熱心に話し続けたあとで、マイクがずっとミュートだったと気づくことです。
(07:58)Apple は iOS 15 でミュート中の話者検出を導入し、今年は macOS 14 と tvOS 17 に拡張しました。ユーザーが音声処理 API のミュートインターフェイスでミュートしていれば、システムはミュート中に話しているかを検出して App に通知できます。App は通知を受け取ったあと、ユーザーにミュート解除を促せます。
Apple の音声処理 API にまだ対応していない macOS App 向けには、代替手段として Core Audio HAL レベルの音声アクティビティ検出プロパティも用意されています。
詳細
他のオーディオのダッキング設定
Apple は 2 つの対応方法を提供しています。低レベルの AUVoiceIO(Audio Unit)と、高レベルの AVAudioEngine です。
AUVoiceIO 方式
(05:50)AUVoiceIO では C 構造体でダッキングパラメータを設定します。
typedef CF_ENUM(UInt32, AUVoiceIOOtherAudioDuckingLevel) {
kAUVoiceIOOtherAudioDuckingLevelDefault = 0,
kAUVoiceIOOtherAudioDuckingLevelMin = 10,
kAUVoiceIOOtherAudioDuckingLevelMid = 20,
kAUVoiceIOOtherAudioDuckingLevelMax = 30
};
struct AUVoiceIOOtherAudioDuckingConfiguration {
Boolean mEnableAdvancedDucking;
AUVoiceIOOtherAudioDuckingLevel mDuckingLevel;
};
設定を作成して適用します。
const AUVoiceIOOtherAudioDuckingConfiguration duckingConfig = {
.mEnableAdvancedDucking = true,
.mDuckingLevel = AUVoiceIOOtherAudioDuckingLevel::kAUVoiceIOOtherAudioDuckingLevelMin
};
OSStatus err = AudioUnitSetProperty(
auVoiceIO,
kAUVoiceIOProperty_OtherAudioDuckingConfiguration,
kAudioUnitScope_Global,
0,
&duckingConfig,
sizeof(duckingConfig)
);
キーポイント:
mEnableAdvancedDuckingがtrueのとき、システムは双方の音声アクティビティに応じてダッキング量を動的に調整するmDuckingLevelには 4 段階がある:default(従来の動作と同じ)、min(最小ダッキングで背景音が最大)、mid、max(最大ダッキングで声が最も明瞭)- 2 つの制御軸は互いに独立しており、組み合わせることで多くの場面をカバーできる
AVAudioEngine 方式
(07:20)AVAudioEngine は対応する Swift API を提供します。
let engine = AVAudioEngine()
let inputNode = engine.inputNode
do {
try inputNode.setVoiceProcessingEnabled(true)
} catch {
print("Could not enable voice processing \(error)")
}
let duckingConfig = AVAudioVoiceProcessingOtherAudioDuckingConfiguration(
enableAdvancedDucking: false,
duckingLevel: .max
)
inputNode.voiceProcessingOtherAudioDuckingConfiguration = duckingConfig
キーポイント:
- まず
setVoiceProcessingEnabled(true)を呼び出して音声処理モードを有効にする AVAudioVoiceProcessingOtherAudioDuckingConfigurationは Swift の構造体で、引数名は C 版と少し異なるinputNode.voiceProcessingOtherAudioDuckingConfigurationに直接代入すれば有効になる
ミュート中の話者検出
AUVoiceIO 実装
(07:32)
AUVoiceIOMutedSpeechActivityEventListener listener = ^(AUVoiceIOMutedSpeechActivityEvent event) {
if (event == kAUVoiceIOSpeechActivityHasStarted) {
// ユーザーがミュート中に話し始めたため、ミュート解除を促す
} else if (event == kAUVoiceIOSpeechActivityHasEnded) {
// ユーザーが話すのをやめた
}
};
OSStatus err = AudioUnitSetProperty(
auVoiceIO,
kAUVoiceIOProperty_MutedSpeechActivityEventListener,
kAudioUnitScope_Global,
0,
&listener,
sizeof(AUVoiceIOMutedSpeechActivityEventListener)
);
// ユーザーがミュートをタップしたとき
UInt32 muteUplinkOutput = 1;
AudioUnitSetProperty(
auVoiceIO,
kAUVoiceIOProperty_MuteOutput,
kAudioUnitScope_Global,
0,
&muteUplinkOutput,
sizeof(muteUplinkOutput)
);
キーポイント:
- リスナーは音声アクティビティ状態が変化したときだけ発火し、連続して繰り返し呼ばれることはない
- システムが正しく検出できるよう、ミュートは必ず
kAUVoiceIOProperty_MuteOutputAPI で実装する - イベントは
kAUVoiceIOSpeechActivityHasStartedとkAUVoiceIOSpeechActivityHasEndedの 2 種類だけ
AVAudioEngine 実装
(11:08)
let listener = { (event: AVAudioVoiceProcessingSpeechActivityEvent) in
if event == .started {
// ユーザーがミュート中に話し始めたため、ミュート解除を促す
} else if event == .ended {
// ユーザーが話すのをやめた
}
}
inputNode.setMutedSpeechActivityEventListener(listener)
// ユーザーがミュートをタップしたとき
inputNode.isVoiceProcessingInputMuted = true
キーポイント:
setMutedSpeechActivityEventListenerでリスナーを登録する- ミュートには必ず
isVoiceProcessingInputMutedプロパティを使い、他の方法は使わない - Swift の列挙値は
.startedと.endedで、C 版より簡潔
Core Audio HAL の音声アクティビティ検出(macOS 専用)
(12:31)Apple の音声処理 API に対応していない macOS App では、HAL API を使用できます。
// 入力デバイスの音声アクティビティ検出を有効にする
const AudioObjectPropertyAddress kVoiceActivityDetectionEnable = {
kAudioDevicePropertyVoiceActivityDetectionEnable,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
UInt32 shouldEnable = 1;
AudioObjectSetPropertyData(deviceID, &kVoiceActivityDetectionEnable, 0, NULL, sizeof(UInt32), &shouldEnable);
// 状態リスナーを登録する
const AudioObjectPropertyAddress kVoiceActivityDetectionState = {
kAudioDevicePropertyVoiceActivityDetectionState,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
AudioObjectAddPropertyListener(deviceID, &kVoiceActivityDetectionState, listener_callback, NULL);
リスナーの実装:
OSStatus listener_callback(
AudioObjectID inObjectID,
UInt32 inNumberAddresses,
const AudioObjectPropertyAddress* inAddresses,
void* inClientData
) {
UInt32 voiceDetected = 0;
UInt32 propertySize = sizeof(UInt32);
OSStatus status = AudioObjectGetPropertyData(
inObjectID, &kVoiceActivityDetectionState, 0, NULL, &propertySize, &voiceDetected
);
if (status == kAudioHardwareNoError) {
if (voiceDetected == 1) {
// 音声アクティビティを検出
} else {
// 音声アクティビティは検出されていない
}
}
return status;
}
キーポイント:
- 検出対象はエコーキャンセル後のマイク入力で、音声通話の場面に適している
- 検出は App のミュート状態とは独立しているため、App 側でミュート状態と組み合わせて判断する必要がある
- HAL のプロセスミュート API の使用が推奨される。メニューバーの録音インジケータを消灯でき、ユーザーのプライバシーを守れる
重要ポイント
-
スマート音量調整付きの通話 App
- 何を作るか: 音声通話中に背景音楽や効果音の音量を自動調整し、話している間は下げ、話していないときは戻す
- なぜ価値があるか: 以前は開発者が音声解析と音量制御ロジックを書く必要があったが、今は
enableAdvancedDuckingの 1 行で FaceTime レベルのスマートダッキングを実現できる - 始め方: AVAudioEngine で音声処理を有効にし、
voiceProcessingOtherAudioDuckingConfigurationを設定し、通話以外のオーディオを別ノードにルーティングする
-
「ミュート中です」提示付きの会議 App
- 何を作るか: ユーザーがミュート中に話しているかを検出し、画面上に提示を表示する
- なぜ価値があるか: これは FaceTime で既に提供されている機能で、ユーザーはこの操作に慣れている。
setMutedSpeechActivityEventListenerを数行書くだけで実現できる - 始め方: リスナーを登録したあと、
.startedイベントで「ミュート中に話しています」というオーバーレイを表示し、ワンタップのミュート解除ボタンを添える
-
ポッドキャスト/ライブ配信用の音声トリガーツール
- 何を作るか: 音声アクティビティ検出を使って、配信者が話したらシーンを自動切り替えしたり字幕を表示したりする
- なぜ価値があるか: HAL API の音声アクティビティ検出はエコーキャンセル後のクリーンな音声に基づくため、単純な音量しきい値より正確
- 始め方: macOS で
kAudioDevicePropertyVoiceActivityDetectionEnableを使って検出を有効にし、リスナーを登録し、自分の業務ロジックと組み合わせてアクションを発火する
-
マルチプレイヤーゲームのボイスチャット
- 何を作るか: ゲーム内ボイスチャットで、ゲーム効果音とチームメイトの声を共存させ、システムが賢く音量を調整する
- なぜ価値があるか: tvOS 17 は初めて音声処理 API に対応し、Continuity Camera と組み合わせることで Apple TV 上のゲームでも高品質なボイスチャットを提供できる
- 始め方: tvOS で AUVoiceIO または AVAudioEngine の音声処理モードを有効にし、ゲームシーンに応じて
min(ゲームの雰囲気を残す)またはmax(指示の明瞭さを確保する)のダッキングレベルを選ぶ
関連セッション
- Discover Continuity Camera for tvOS — tvOS で Continuity Camera を使い、音声処理 API と組み合わせる方法
- Support voice input in your app — App で音声入力をサポートする方法
- Add SharePlay to your app — SharePlay と音声処理を組み合わせて共有メディア体験を実現する方法
コメント
GitHub Issues · utterances