View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

返回 WWDC23

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 转写文稿
  • 代码
  • 语音处理的新功能

    了解如何使用 Apple 语音处理 API 在 IP 语音应用中实现最佳的音频体验。我们将向你展示如何检测某人在静音状态下说话、如何调整其他音频的抑制行为等等。

    章节

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

    资源

      • 高清视频
      • 标清视频

    相关视频

    WWDC23

    • 使用 AirPods 提升你的 App 音频体验
    • 探索 tvOS 连续互通相机
  • 搜索此视频…

    ♪ ♪

    Julian:大家好 欢迎收看 “语音处理的新功能” 我是 Core Audio 团队的 Julian VoIP App 已经变得 比以往任何时候都重要 它帮助人们与同事 朋友和家人保持联系 语音聊天的音频质量 在提供良好的用户体验方面 起着关键作用 要实现在任何情况下 都把音频处理地很清晰 非常重要 也非常具有挑战性 这就是 Apple 提供语音处理 API 的原因 这样 当任何人使用你的 App 聊天时 无论他们处于什么样的声环境 无论使用什么 Apple 产品 无论连接了什么音频配件 他们始终都可以享受到 绝佳的音频体验 Apple 的语音处理 API 被广泛应用在很多 App 中 包括我们自己的 FaceTime 通话和电话 App 它提供了一流的音频信号处理 包括回声消除 噪音抑制 自动增益控制 以增强语音聊天音频质量 它的表现是由声学工程师 针对每种 Apple 产品型号 结合每种类型的 音频设备进行调整的 以应对它们不同的声学特性 使用 Apple 的语音处理 API 还可以让用户完全控制 App 的麦克风模式设置 包括标准 语音突显和宽谱 我们强烈建议 你在 VoIP App 中 使用 Apple 的语音处理 API Apple 的语音处理 API 有两种选择 第一个选择是叫作 AUVoiceIO 的 I/O 音频单元 也叫作 AUVoiceProcessingIO 这个选择适用于 需要与 I/O 音频单元直接互动的 App

    第二个选择是 AVAudioEngine 更确切地说 是启用 AVAudioEngine 的“语音处理”模式

    AVAudioEngine 是更高级的 API 一般来说 它更容易使用 它会减少你在处理音频时 要写的代码量 两个选择都会 提供相同的语音处理能力 那有什么新功能呢? 我们将首次在 Apple tvOS 上 提供语音处理 API 想了解更多细节 请查看讲座 “了解 Apple tvOS 的连续互通相机” 我们还为 AUVoiceIO 和 AVAudioEngine 添加了几个新的 API 为你提供更多的语音处理控制 帮助你实现新的功能

    第一个 API 是帮助你 控制对其他音频的抑制行为 我等下为你解释这是什么意思 第二个 API 是帮助你为 App 实现 静音发音检测功能 在本次讲座中 我将重点介绍这两个新 API 的细节 我想谈的第一个 API 是 “抑制其它音频” 在我们深入讨论这个 API 之前 让我解释一下什么是其它音频 以及为什么抑制很重要 当你使用 Apple 的语音处理 API 时 我们看一下播放音频发生了什么 你的 App 提供了 一个经过 Apple 语音处理的 语音聊天音频流 并播放到输出设备上 不过 可能还有 其他音频流在同时播放 例如 你的 App 可能在播放 另一个没有经过 语音处理 API 渲染的音频流

    也可能有其它 App 和你的 App 同时在播放音频 所以来自你的 App 之外的音频流 都会被 Apple 语音处理 视为“其它音频” 你的语音音频 在被播放到输出设备之前 会与其它音频混合在一起 对于语音聊天 App 播放音频 通常会优先考虑语音聊天音频 因此我们要抑制其它音频的音量 以提高语音音频的清晰度 过去 我们对其它音频 应用了固定量的抑制 这对大多数 App 来说效果很好 如果你的 App 满意现有的抑制行为 那么你不需要做任何改动 不过 我们了解到一些 App 希望对抑制行为 拥有更多的控制 这个 API 将帮助你实现这一目标

    让我们先来看看 AUVoiceIO 中的这个 API 等下再看 AVAudioEngine 对 AUVoiceIO 来说 这是其它音频抑制配置的结构 它提供了对抑制的两个方面的控制: 抑制的模式 即 mEnableAdvancedDucking 和抑制的量 即 mDuckingLevel 对于 mEnableAdvancedDucking 默认情况下 它是禁用的 一旦启用 它将根据聊天参与者中 任何一方的语音活动 动态地调整抑制等级 换句话说 当任何一方用户说话时 它会应用更多的抑制 而当没有用户说话时 它就会降低抑制 这和 FaceTime 通话 同播共享中的抑制非常类似 FaceTime 通话双方都不说话时 媒体播放音量很高 一旦有人开始说话 媒体播放音量就会降低

    接下来是 mDuckingLevel 它有四个级别的控件: 默认 (Default)、最小 (Min)、 中等 (Mid) 和最大 (Max) 默认 (Default) 抑制等级的 抑制量和我们一直应用的相同 我们将继续使用它为默认设置 最小 (Min) 抑制等级 会最小化我们应用的抑制量 换句话说 如果你想 让其他音频的音量尽可能大 你就可以使用这一设置 相反 最大 (Max) 抑制等级 会最大化我们应用的抑制量 一般来说 选择较高的抑制等级 会帮助提升语音聊天的清晰度

    这两个控件可以单独使用 当结合使用时 你可以灵活地 控制抑制行为

    我们已经介绍了抑制配置的作用 现在你可以创建 适合你的 App 的配置了 例如 在这里我将启用高级抑制 选择抑制等级为最小

    然后我将通过 kAUVoiceIOProperty_OtherAudioDuckingConfiguration 把这个抑制配置设置为 AUVoiceIO

    对 AVAudioEngine 用户来说 API 看起来非常相似 这是其他音频抑制配置的结构定义 这是抑制等级的枚举定义

    要在 AVAudioEngine 中 使用这个 API 你首先要在引擎的输入节点上 启用语音处理

    然后设置抑制配置

    最后 在输入节点上设置配置 接下来 让我们谈谈另一个API 它可以帮助你 在你的 App 中 实现一个非常有用的功能 你是否在线上会议中 遇到过这种情况 你以为你在和同事或朋友聊天 但没过多久 你发现你在静音状态 没有人听到 你的精彩观点或有趣的故事? 是的 这很尴尬 在你的 App 中添加 静音发言检测功能是非常有用的 就像这里的 FaceTime 通话一样

    这就是为什么 我们要为你提供一个 API 来检测静音状态下是否有人说话 它最初是在 iOS 15 中引入的 现在我们要将它引入到 macOS 14 和 Apple tvOS 17 以下是如何 使用该 API 的高级概述 首先 你需要向 AUVoiceIO 或 AVAudioEngine 提供一个侦听代码块 以在检测到静音状态 有人说话时接收通知 你提供的侦听代码块会在 静音时有人开始说话或停止说话时 被调用 然后实现此类通知的处理代码 例如 如果通知 显示用户在静音状态下开始说话 你可能会想提示其取消静音 最后 需要通过 AUVoiceIO 或 AVAudioEngine 的静音 API 才能实现静音

    让我带你看看 AUVoiceIO 的一些代码示例 我们稍后会讲到 AVAudioEngine 的例子 首先 准备一个 处理通知的侦听代码块

    该块有一个 AUVoiceIOSpeechActivityEvent 类型的参数 它可以是以下两个值之一: SpeechActivityHasStarted 或 SpeechActivityHasEnded

    每当语音活动事件 在静音期间发生变化时 侦听代码块就会被调用

    该块中就是你实现 如何处理该事件的地方 例如 当收到 SpeechActivityHasStarted 事件时 你可能会想提示用户取消静音 一旦你准备好了该侦听代码块 通过 kAUVoiceIOProperty_MutedSpeechActivityEventListener 向 AUVoiceIO 注册这个块

    当用户要静音时 通过静音 API kAUVoiceIOProperty_MuteOutput 实现静音

    你的侦听代码块只有在以下情况 才会被调用 一:用户被静音 二:语音活动状态改变时

    语音活动的持续存在或持续不存在 都不会导致多余的通知

    对 AVAudioEngine 用户来说 实例非常相似 在引擎的输入节点上 启用语音处理后 准备一个用于处理通知的侦听代码块

    然后在输入节点上注册该侦听代码块

    当用户需要静音时 使用 AVAudioEngine 的语音处理 API 来静音

    现在 我们已经讨论了 用 AUVoiceIO 和 AVAudioEngine 实现检测静音状态下 是否有人说话的功能 对于那些还没有准备好 采用 Apple 的语音处理 API 的人来说 我们会提供一个替代方案 来帮助你实现这个功能

    这一替代方案 只能通过 CoreAudio HAL API 在 macOS 上使用 即 Hardware Abstraction Layer API 有两个新的 HAL 属性 你可以结合使用它们 以帮助你检测语音活动 首先 通过 kAudioDevicePropertyVoiceActivityDetectionEnable 在输入设备上启用语音活动检测 然后 在 kAudioDevicePropertyVoiceActivityDetectionState 上 注册一个 HAL 属性侦听器 只要语音活动状态有变化 这个 HAL 属性侦听器就会被调用 当你的 App 被属性侦听器通知时 查询该属性以获得其当前值

    现在 让我用一些代码例子 来带你了解这些

    要在输入设备上启用语音活动检测 首先要构建 HAL 属性地址

    然后在输入设备上 设置该属性以启用它

    接下来 若要在语音活动检测状态 属性上注册一个侦听器 就要构建 HAL 属性地址 然后提供你的属性侦听器

    这里的“listener_callback” 是你的侦听器函数的名称

    这是一个关于 如何实现属性侦听器的例子

    侦听器符合此函数签名

    在这个例子中 我们假设这个侦听器 只注册了一个 HAL 属性 这意味着当它被调用时 对于哪个 HAL 属性有变化 是没有歧义的

    如果你将同一个侦听器注册到了 有多个 HAL 属性的通知上 那么你必须首先 通过 inAddresses 数组来查看 到底是什么发生了变化

    在处理这个通知时 查询 VoiceActivityDetectionState 属性 以获得其当前值

    然后在处理该值时 实现你自己的逻辑

    关于这些语音活动检测 HAL API 有一些重要的细节 首先 它是从被回声消除的 麦克风输入中 检测语音活动的 所以它是 语音聊天 App 的理想选择

    其次 这种检测工作 不受进程的静音状态的影响 为了用它来实现静音检测功能 你的 App 需要实现额外的逻辑 将语音活动状态和静音状态结合起来 如果 HAL API 用户要实现静音 我们强烈建议 使用 HAL 的进程静音 API 它可以抑制菜单栏中的录音指示灯 让用户相信他们的隐私 在静音状态下得到了保护 让我们来回顾一下 今天所谈到的内容 我们谈到了 Apple 的 语音处理 API 以及我们推荐 将它用于 VoIP App 的原因 我们谈到了抑制其他音频 以及控制抑制行为的 API 并用代码举例说明了 如何通过 AUVoiceIO 和 AVAudioEngine 使用它 我们还用 AUVoiceIO 和 AVAudioEngine 的代码例子 讲了如何实现 检测静音状态下是否有人说话 对于还没有采用 Apple 的 语音处理 API 的用户 我们还展示了在 macOS 上 使用 Core Audio HAL API 的替代方案 我们期待你 利用 Apple 的语音处理 API 构建出色的 App 感谢观看! ♪ ♪

    • 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
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则