View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • 音声処理の新機能

    Appleの音声処理APIを使用して、VoIPアプリでベストなオーディオ体験を実現する方法を紹介します。ミュート中に誰かが話していることを検出する方法や、他のオーディオのダッキング動作を調整する方法などを説明します。

    関連する章

    • 0:00 - Introduction
    • 3:19 - Other audio ducking
    • 7:55 - Muted talker detection
    • 11:37 - Muted talker detection for macOS

    リソース

      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC23

    • AirPodsによるアプリケーションのオーディオ体験の向上
    • tvOS向けの連携カメラ機能
  • ダウンロード

    ♪ ♪

    こんにちは 「音声処理の新機能」へようこそ Core Audioチームの Julianです ボイスオーバーIPアプリケーションは 同僚や友人 家族との つながりを維持するために これまで以上に不可欠です 音声チャットの音質は優れたユーザー体験を 提供する上で 重要な役割を果たします どのような状況でも 素晴らしいサウンドが得られる― オーディオ処理の実装は重要ですが 難しいことでもあります だからこそAppleが 音声処理APIを提供します あなたのアプリでチャットする際に 音響環境や 使用するApple製品や 接続されるオーディオアクセサリに関わらず 誰もが常に最高のオーディオ体験を 楽しむことができます Appleの音声処理APIは FaceTimeや 電話アプリを含む 多くのアプリによって 広く使用されています また クラス最高のオーディオ 信号処理を提供します エコーキャンセレーションやノイズ抑制 自動ゲインコントロールなどにより ボイスチャットの音声を向上させるのです その性能は 音響エンジニアによって Apple製品の各モデルと 各種オーディオ機器との組み合わせで それぞれの固有の音響特性を 考慮して調整されています Appleの音声処理APIを選択すると 標準版 音声分離 ワイドスペクトルなど アプリのマイクモード設定を ユーザーがフルに管理できます Voice over IPアプリには Apple音声処理APIの使用を 強くお勧めします アップルの音声処理APIには 2つの選択肢があります まずAUVoiceProcessingIOと呼ばれる I/Oオーディオユニットがあります これはI/Oオーディオユニットと 直接やり取りするアプリ向けです

    2つ目はAVAudioEngineで 具体的にはAVAudioEngineの 「音声処理」モードを有効にします

    AVAudioEngineは上位APIです 一般的には使いやすく オーディオを扱う際に書くべきコード量を 軽減できます どちらのオプションも 同じ音声処理機能を提供します さて 新しい点は何かというと 音声処理APIを初めて tvOSで利用できるようになりました 詳細は「Discover Continuity Camera for tvOS」を ご覧ください また AUVoiceIOとAVAudioEngineに 新しいAPIをいくつか追加し 音声処理をより制御可能にし 新機能の実装をサポートします

    最初のAPIは他のオーディオの ダッキング動作をコントロールするものです 何を意味するかは後ほど説明します 2つ目のAPIはミュート通話者の 検出機能をアプリに 実装するサポートをします このセッションでは これら2つの 新しいAPIの詳細に焦点を当てます 最初にお話しするAPIは 「Other audio ducking」です このAPIに取り組む前に 他のオーディオとは何か および ダッキングが重要な理由を説明します Appleの音声処理APIを使用する場合 再生音声に何が起こっているのか 見てみましょう あなたのアプリは Appleの音声処理で処理され 出力デバイスに再生される ボイスチャットオーディオストリームを 提供しています しかし 同時に他のオーディオストリームが 再生されている可能性があります 例えば あなたのアプリは 音声処理APIを通して レンダリングされていない 別のオーディオストリームを再生できます

    同時に他のアプリでもオーディオを 再生している可能性もあります あなたのアプリからの 音声オーディオストリーム以外の すべてのオーディオストリームは Appleの音声処理によって 「他のオーディオ」とみなされ あなたの音声オーディオは 再生前に出力デバイスに 他のオーディオと混合されます ボイスチャットアプリの場合は 通常 再生オーディオの主な焦点は ボイスチャットオーディオです よって音声の明瞭度を向上させるために 他の音声の音量レベルを下げています 以前は 他のオーディオに 一定のダッキングを適用していました これはほとんどのアプリで うまく機能しており あなたのアプリの 現在のダッキング動作が 十分に満足できるものであれば 何もする必要はありません しかし アプリによっては ダッキングの動作を さらに制御したい場合もあるでしょう

    まずはAUVoiceIOのAPIを検証し AVAudioEngineについては あとで説明します AUVoiceIOの場合 他の オーディオダッキング設定の 構造は次の通りです これはダッキングの2つの独立した側面の コントロールを提供します ダッキングのスタイルである mEnableAdvancedDuckingと ダッキングの量であるmDuckingLevelです mEnableAdvancedDuckingについては デフォルトでは無効になっています 有効化されるとチャット参加者の どちらか一方からの 音声アクティビティの存在に基づいて ダッキングレベルが動的に調整されます つまり 一方のユーザーが話しているときは より多くのダッキングを適用し どちらも話していないときは ダッキングを減らします これはFaceTime SharePlayの ダッキングと似ており FaceTimeの両者が話していないときは メディア再生の音量が大きく 誰かが話し始めるとすぐに メディア再生の音量が小さくなります

    次にmDuckingLevelについて コントロールには4つのレベルがあります デフォルト(Default) 最小(Min) 中程度(Mid) 最大(Max)です デフォルト(Default)の ダッキングレベルはこれまでと同じ― ダッキング量を適用し これは今後も デフォルトの設定となります 最小(Min)レベルでは 適用する ダッキング量を最小限に抑えます つまり 他のオーディオの音量を できるだけ大きくしたい場合に 使用する設定です 逆に 最大(Max)ダッキングレベルは ダッキング量を最大にします 一般的に 高いダッキングレベルを 選択すると ボイスチャットの明瞭度が向上します

    2つのコントロールは独立して使用できます 併用することでダッキングの挙動を 自在にコントロールできます

    ダッキング設定について説明したので 次はあなたのアプリに適した 設定を作成します 例えば ここでは 高度なダッキングを有効にし ダッキングレベルを最小に選択します

    次に、kAUVoiceIOProperty_ OtherAudioDuckingConfigurationを介して ダッキング設定を AUVoiceIOに設定します

    AVAudioEngineクライアントの場合 APIは非常によく似ています 以下は その他のオーディオ ダッキング設定の構造体定義で これはダッキングレベルの列挙型定義です

    AVAudioEngineで このAPIを使用するには まずエンジンの入力ノードで 音声処理を有効にしてから

    ダッキング設定を行います

    そして最後に 入力ノードに設定を入力します アプリに非常に便利な機能を 実装する際に役立つ― もう一つのAPIについて説明します オンライン会議で 同僚や友人と チャットしているつもりが しばらくしてからミュートに気づき あなたの素晴らしい指摘や面白い話を 誰も聞いていないことに 気づいたという経験はありませんか? 気まずいですよね FaceTimeがここで行っているように ミュートされた話し手を検出する機能が アプリにあると非常に便利です

    そのため ミュートされた通話者の存在を 検出するためのAPIを提供しています iOS 15で初めて導入され 現在はmacOS 14およびtvOS 17で 利用可能です このAPIの使い方の概略をお伝えします まず AUVoiceIOまたは AVAudioEnginにリスナーブロックを 提供し ミュートされた通話者の検出時に 通知を受け取る必要があります ミュートされた通話者が話し始めたり 話をやめたりするたびに 提供されたリスナーブロックが 呼び出されます そのような通知に対する 処理コードを実装してください 例えば ミュート中にユーザーが 話し始めたことを通知した場合 ミュートを解除するよう促すことができます 最後に AUVoiceIOまたは AVAudioEngineの ミュートAPIを使ってミュートを実装する ことが要件になっています

    AUVoiceIOを使ったコード例を いくつか紹介します AVAudioEngineの例については 後ほど説明します まず 通知を処理する リスナーブロックを用意します

    このブロックにはAUVoiceIOSpeech ActivityEvent型のパラメータがあり SpeechActivityHasStartedまたは SpeechActivityHasEndedの 2つの値のうち いずれかを指定します

    このリスナーブロックはミュート中 スピーチアクティビティイベントが 変化するたびに呼び出されます

    ブロックの中ではこのイベントを どのように処理するかを実装します 例えば SpeechActivityHasStarted イベントを受信したとき ユーザーにミュートを解除するよう 促すことができます リスナーブロックの準備ができたら kAUVoiceIOProperty_MutedSpeech ActivityEventListenerを 介して AUVoiceIOにブロックを登録します

    ユーザーがミュートした場合 ミュートAPIの kAUVoiceIOProperty_MuteOutputを 使用してミュートを実装します

    リスナーブロックが呼び出されるのは A)ユーザーがミュートされた時 B)スピーチアクティビティの状態が 変化したときだけです

    発話があってもなくても 冗長な通知は発生しません

    AVAudioEngineクライアントの実装も これに非常に似ています エンジンの入力ノードで 音声処理を有効にしたら 通知を処理する リスナーブロックを用意します

    次に リスナーブロックを 入力ノードに登録します

    ミュートした場合は AVAudioEngineの 音声処理ミュートAPIでミュートにします

    AUVoiceIOと AVAudioEngineを使った ミュート通話者の検出機能の 実装についてお伝えしました Appleの音声処理APIを 採用する準備がまだの方のために この機能を実装するための 代替手段を提供します

    この代替オプションは CoreAudio HAL API つまりハードウェア抽象化レイヤーAPIを 介してのみmacOSで利用可能です 2つの新しいHALプロパティがあり 組み合わせて使用することで 音声アクティビティを 検出する際に役立ちます まず kAudioDevicePropertyVoice ActivityDetectionEnableによって 入力デバイスの 音声アクティビティ検出を有効にします 次に HALプロパティリスナーを kAudioDevicePropertyVoice ActivityDetectionStateに登録します このHALプロパティリスナーは 音声アクティビティの状態に 変更があるたびに呼び出されます アプリが プロパティリスナーから通知を受けたら プロパティにクエリを実行して 現在の値を取得します

    コードの例を挙げて説明しましょう

    入力デバイスで音声アクティビティ検出を 有効にするには まず HALプロパティアドレスを構築します

    次に このプロパティを 入力デバイスに設定して有効にします

    次に 音声アクティビティ検出状態 プロパティにリスナーを登録するには HALプロパティアドレスを作成し プロパティリスナーを指定します

    ここでの「listener_callback」は リスナー関数の名前です

    これがプロパティリスナーの 実装方法の例です

    リスナーはこの関数シグネチャに従います

    この例では リスナーが 1つのHALプロパティに対してのみ 登録されていると仮定します つまり このリスナーが呼び出されたとき どのHALプロパティが変更されたのか 曖昧になることはありません

    複数のHALプロパティの通知用に 同じリスナーを登録する場合 最初にinAddressesの配列を調べて 何が変更されたかを 正確に確認する必要があります

    この通知を処理するには VoiceActivityDetectionState プロパティに問い合わせて

    現在の値を取得し その値を処理する 独自のロジックを実装します

    音声アクティビティ検出HAL APIには 何点か重要な詳細があります まず エコーキャンセルされた マイク入力から 音声アクティビティを検出するので ボイスチャットアプリに最適です

    第二に この検出はプロセスの ミュート状態に関係なく機能します この機能を使ってミュート通話者の 検出機能を実装するには 音声アクティビティ状態と ミュート状態を組み合わせる― 追加ロジックをアプリに 実装する必要があります HAL APIクライアントが ミュートを実装するには HALのプロセスミュートAPIの使用を 強くお勧めします メニューバーの 録画インジケーターランプを抑制し ユーザーはミュート状態でのプライバシーが 保護されていることに安心できます 今日の話を振り返りましょう Appleの音声処理APIについて紹介し これをボイスオーバーIPアプリに おすすめする理由をお伝えしました AUVoiceIOと AVAudioEngineを使った― ダッキング動作のコード例を交えながら 他の音声のダッキングやダッキング動作を 制御するAPIについてお話しました また AUVoiceIOと AVAudioEngineのコード例を用いて ミュート通話者の検出の 実装方法についても説明しました またAppleの音声処理APIを 採用していないクライアントのために Core Audio HAL APIを使って macOS上で音声処理を行う 代替オプションも紹介しました Appleの音声処理APIを使用した― 素晴らしいアプリを皆さんが 制作されるのを楽しみにしています ご視聴ありがとうございました! ♪ ♪

    • 5:50 - Other audio ducking

      // Insert code snipp297struct AUVoiceIOOtherAudioDuckingConfiguration {
      	Boolean mEnableAdvancedDucking;
      	AUVoiceIOOtherAudioDuckingLevel  mDuckingLevel;
      };et.
      typedef CF_ENUM(UInt32, AUVoiceIOOtherAudioDuckingLevel) {
      	kAUVoiceIOOtherAudioDuckingLevelDefault = 0,
      	kAUVoiceIOOtherAudioDuckingLevelMin = 10,
      	kAUVoiceIOOtherAudioDuckingLevelMid = 20,
      	kAUVoiceIOOtherAudioDuckingLevelMax = 30
      };
    • 6:48 - Other audio ducking

      const AUVoiceIOOtherAudioDuckingConfiguration duckingConfig = {
      	.mEnableAdvancedDucking = true,
      	.mDuckingLevel = AUVoiceIOOtherAudioDuckingLevel::kAUVoiceIOOtherAudioDuckingLevelMin
      };
      // AUVoiceIO creation code omitted
      OSStatus err = AudioUnitSetProperty(auVoiceIO, kAUVoiceIOProperty_OtherAudioDuckingConfiguration, kAudioUnitScope_Global, 0, &duckingConfig, sizeof(duckingConfig));
    • 6:50 - Other audio ducking

      const AUVoiceIOOtherAudioDuckingConfiguration duckingConfig = {
      	.mEnableAdvancedDucking = true,
      	.mDuckingLevel = AUVoiceIOOtherAudioDuckingLevel::kAUVoiceIOOtherAudioDuckingLevelMin
      };
      // AUVoiceIO creation code omitted
      OSStatus err = AudioUnitSetProperty(auVoiceIO, kAUVoiceIOProperty_OtherAudioDuckingConfiguration, kAudioUnitScope_Global, 0, &duckingConfig, sizeof(duckingConfig));
    • 7:20 - Other audio ducking

      public struct AVAudioVoiceProcessingOtherAudioDuckingConfiguration {
      	public var enableAdvancedDucking: ObjCBool 
      	public var duckingLevel: AVAudioVoiceProcessingOtherAudioDuckingConfiguration.Level
      }
      extension AVAudioVoiceProcessingOtherAudioDuckingConfiguration {
      	public enum Level : Int, @unchecked Sendable {
      		case `default` = 0
      		case min = 10
      		case mid = 20
      		case max = 30
      	}
      }
    • 7:31 - Other audio ducking

      let engine = AVAudioEngine()
      let inputNode = engine.inputNode
      do {
      	try inputNode.setVoiceProcessingEnabled(true)
      } catch {
      	print("Could not enable voice processing \(error)")
      }
      let duckingConfig = AVAudioVoiceProcessingOtherAudioDuckingConfiguration(mEnableAdvancedDucking: false, mDuckingLevel: .max)
      inputNode.voiceProcessingOtherAudioDuckingConfiguration = duckingConfig
    • 7:32 - Muted talker detection AUVoiceIO

      AUVoiceIOMutedSpeechActivityEventListener listener = 
^(AUVoiceIOMutedSpeechActivityEvent event) {		
          if (event == kAUVoiceIOSpeechActivityHasStarted) {
      		// User has started talking while muted. Prompt the user to un-mute
      	} else if (event == kAUVoiceIOSpeechActivityHasEnded) {
      		// User has stopped talking while muted
      	}
      };
      OSStatus err = AudioUnitSetProperty(auVoiceIO, kAUVoiceIOProperty_MutedSpeechActivityEventListener, kAudioUnitScope_Global, 0, &listener,  sizeof(AUVoiceIOMutedSpeechActivityEventListener));
      // When user mutes
      UInt32 muteUplinkOutput = 1;
      result = AudioUnitSetProperty(auVoiceIO, kAUVoiceIOProperty_MuteOutput, kAudioUnitScope_Global, 0, &muteUplinkOutput, sizeof(muteUplinkOutput));
    • 11:08 - Muted talker detection AVAudioEngine

      let listener =  { (event : AVAudioVoiceProcessingSpeechActivityEvent) in
      	if (event == AVAudioVoiceProcessingSpeechActivityEvent.started) {
      		// User has started talking while muted. Prompt the user to un-mute
      	} else if (event == AVAudioVoiceProcessingSpeechActivityEvent.ended) {
      		// User has stopped talking while muted
      	}
      }
      inputNode.setMutedSpeechActivityEventListener(listener)
      // When user mutes
      inputNode.isVoiceProcessingInputMuted = true
    • 12:31 - Voice activity detection - implementation with HAL APIs

      // Enable Voice Activity Detection on the input device
      const AudioObjectPropertyAddress kVoiceActivityDetectionEnable{
              kAudioDevicePropertyVoiceActivityDetectionEnable,
              kAudioDevicePropertyScopeInput,
              kAudioObjectPropertyElementMain };
      OSStatus status = kAudioHardwareNoError;
      UInt32 shouldEnable = 1;
      status = AudioObjectSetPropertyData(deviceID, &kVoiceActivityDetectionEnable, 0, NULL, sizeof(UInt32), &shouldEnable);
      // Register a listener on the Voice Activity Detection State property
      const AudioObjectPropertyAddress kVoiceActivityDetectionState{
              kAudioDevicePropertyVoiceActivityDetectionState,
              kAudioDevicePropertyScopeInput,
              kAudioObjectPropertyElementMain };
      status = AudioObjectAddPropertyListener(deviceID, &kVoiceActivityDetectionState, (AudioObjectPropertyListenerProc)listener_callback, NULL); // “listener_callback” is the name of your listener function
    • 13:13 - Voice activity detection - listener_callback implementation

      OSStatus listener_callback(
          AudioObjectID                 inObjectID,
          UInt32                        inNumberAddresses,
          const AudioObjectPropertyAddress*   __nullable inAddresses,
          void* __nullable              inClientData)
      {
        // Assuming this is the only property we are listening for, therefore no need to go through inAddresses
             UInt32 voiceDetected = 0;
           UInt32 propertySize = sizeof(UInt32);
           OSStatus status = AudioObjectGetPropertyData(inObjectID, &kVoiceActivityState, 0, NULL, &propertySize, &voiceDetected);
        
             if (kAudioHardwareNoError == status) {
       if (voiceDetected == 1) {
          // voice activity detected
      	} else if (voiceDetected == 0) {
      		    // voice activity not detected
      	}
       }
       return status;
      };
  • 特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。

    クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。

Developer Footer

  • ビデオ
  • WWDC23
  • 音声処理の新機能
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン