WWDC Quick Look 💓 By SwiftGGTeam
Create a seamless speech experience in your apps

Create a seamless speech experience in your apps

观看原视频

Highlight

Apple 在 AVSpeechSynthesizer 中加入 prefersAssistiveTechnologySettings,让应用语音可以沿用当前 VoiceOver 等辅助技术的声音、语速和音高设置。

核心内容

很多应用想加语音,第一反应是直接创建一个 AVSpeechSynthesizer。这在地图播报方向、AAC(Augmentative Alternative Communication,增强和替代沟通)应用、低视力用户的环境描述工具里很合理,因为这些体验本身就围绕语音展开,应用需要决定何时说、说什么、用什么声音说。

同一套做法放到屏幕阅读场景里会出问题。用户已经在使用 VoiceOver 或其他辅助技术时,应用再用 AVSpeechSynthesizer 自己播报,可能绕过用户为辅助技术配置的声音和语速。Session 一开始先划清边界:如果只是给 VoiceOver 用户补充少量事件描述,应通过 UIAccessibility.post(notification: .announcement, ...) 把请求交给正在运行的辅助技术。

真正需要 AVSpeechSynthesizer 的场景,是应用语音体验本身有独立价值。iOS 14 的新点在这里:AVSpeechUtterance.prefersAssistiveTechnologySettings 可以请求使用当前辅助技术的语音设置。这样,Seeing AI 这类应用仍然能自己描述取景器里的对象,同时让播报听起来更接近用户正在使用的 VoiceOver。

Session 后半段继续处理两个实际问题。AAC 应用可能要让用户选择自己的声音、语速、音高和音量;通话中还要把合成语音送进电话或 FaceTime。音频较多的应用还要决定 speech 是否占用应用共享的 audio session,避免和音乐、视频、音效互相干扰。

详细内容

交给辅助技术播报临时事件

01:25)当应用只需要为 VoiceOver 用户补充一个偶发事件,例如状态变化或操作完成,不需要自己创建本地屏幕阅读器。把 announcement 交给 UIAccessibility,VoiceOver 会管理这次播报。

UIAccessibility.post(notification: .announcement, argument: "Hello World")

关键点:

  • notification: .announcement 表示这是一条要由当前辅助技术播出的公告。
  • argument 是要朗读的文本。
  • 这条路径适合少量补充语音,不适合构建以语音为中心的应用功能。

创建并保留 AVSpeechSynthesizer

02:55)以语音为中心的功能需要应用自己控制播报。最小流程是创建 synthesizer、创建 utterance、调用 speak(_:)。讲者特别提醒,AVSpeechSynthesizer 对象要保留到语音结束。

self.synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "Hello World")
self.synthesizer.speak(utterance)

关键点:

  • AVSpeechSynthesizer() 是负责调度语音的对象。
  • AVSpeechUtterance(string:) 包含要播报的文本。
  • speak(utterance) 把这次 utterance 交给 synthesizer 播出。
  • self.synthesizer 需要被实例保留,避免语音尚未结束对象就被释放。

沿用 VoiceOver 等辅助技术的语音设置

04:08)默认情况下,AVSpeechSynthesizer 使用设备的 Accessibility Spoken Content 设置。iOS 14 新增的 prefersAssistiveTechnologySettings 可以请求使用当前正在运行的辅助技术设置,包括声音、语速和音高。

self.synthesizer = AVSpeechSynthesizer()
let utterance = AVSpeechUtterance(string: "Hello World")
utterance.prefersAssistiveTechnologySettings = true
self.synthesizer.speak(utterance)

关键点:

  • prefersAssistiveTechnologySettings = true 写在 AVSpeechUtterance 上。
  • 当前有 VoiceOver 等辅助技术运行时,辅助技术的声音、语速和音高优先生效。
  • 没有辅助技术运行时,系统继续使用 Spoken Content 设置或 utterance 上显式设置的属性。
  • AAC 应用可能需要用户自定义声音,这类场景要按产品目标评估是否开启该属性。

为语音中心型应用定制声音

05:42)AAC 应用可能会让用户选择代表自己的声音。AVSpeechUtterance 支持按语言代码或 voice identifier 指定 voice,也可以读取系统已安装 voice 列表。讲者还说明,Siri voices 即使能在 Spoken Content 设置中选择,也不能通过 AVSpeechSynthesizer API 直接使用;系统会回退到语言代码匹配的 voice。

let utterance = AVSpeechUtterance(string: "Hello World")

// Choose a voice using a language code
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")

// Choose a voice using an identifier
utterance.voice = AVSpeechSynthesisVoice(identifier: AVSpeechSynthesisVoiceIdentifierAlex)

// Get a list of installed voices
let voices = AVSpeechSynthesisVoice.speechVoices()

关键点:

  • AVSpeechSynthesisVoice(language:) 适合按语言选择系统 voice。
  • AVSpeechSynthesisVoice(identifier:) 适合指定某个已知 voice。
  • AVSpeechSynthesisVoice.speechVoices() 返回系统当前可用 voice,用户下载新 voice 后列表会更新。
  • Siri voices 不属于这个 API 可直接选择的范围。

调整语速、音高和音量

06:16)如果应用决定自己控制语音风格,可以设置 utterance 的 rate、pitch multiplier 和 volume。Transcript 给出的范围分别是 rate 0 到 1、pitch multiplier 0.5 到 2、volume 0 到 1。

let utterance = AVSpeechUtterance(string: "Hello World")

// Choose a rate between 0 and 1, 0.5 is the default rate
utterance.rate = 0.75

// Choose a pitch multiplier between 0.5 and 2, 1 is the default multiplier
utterance.pitchMultiplier = 1.5

// Choose a volume between 0 and 1, 1 is the default value
utterance.volume = 0.5

关键点:

  • rate 控制朗读速度,示例把默认 0.5 提高到 0.75。
  • pitchMultiplier 控制音高倍率,默认是 1。
  • volume 控制这次 utterance 的音量,默认是 1。
  • 如果同时开启 prefersAssistiveTechnologySettings 且辅助技术正在运行,辅助技术设置会优先生效。

把合成语音送入正在进行的通话

06:34)AAC 应用的一个关键场景是让非语言用户通过电话或 FaceTime 沟通。mixToTelephonyUplink 为这个场景设计:有活动中的 outgoing call 时,speech 会路由到通话;没有活动通话时,speech 走默认 audio route。

self.synthesizer = AVSpeechSynthesizer()
self.synthesizer.mixToTelephonyUplink = true

关键点:

  • mixToTelephonyUplink 设置在 AVSpeechSynthesizer 上。
  • 活动通话可以是 phone call 或 FaceTime call。
  • 没有通话时,系统不会强行改变默认播报路径。

让系统管理 speech audio session

07:02)默认情况下,speech audio 使用应用共享的 audio session。把 usesApplicationAudioSession 设为 false 后,系统会接管 speech audio 的管理,处理 audio interruptions、设置 session active/inactive,并让 speech 与应用其他音频 duck and mix。

self.synthesizer = AVSpeechSynthesizer()
self.synthesizer.usesApplicationAudioSession = false

关键点:

  • usesApplicationAudioSession 默认是 true
  • 设为 false 后,speech audio 不再使用应用共享 audio session。
  • 系统会管理中断处理和 session 激活状态。
  • 对同时播放音乐、视频、音效的应用,这能减少 speech 与其他音频互相干扰。

核心启发

  1. 为取景器类工具加入可控对象播报

做什么:在识物、导览或扫描类 App 中,用 AVSpeechSynthesizer 朗读取景器识别到的对象或环境变化。

为什么值得做:Session 用 Seeing AI 说明,面向盲人或低视力用户的应用可以保持 VoiceOver 可访问,同时用 synthesizer 控制对象描述的时机。

怎么开始:先保证 UI 元素有正确的 accessibility label;对象识别结果进入稳定状态后创建 AVSpeechUtterance;如果 VoiceOver 正在运行,将 prefersAssistiveTechnologySettings 设为 true

  1. 给 AAC 应用增加电话沟通模式

做什么:让用户点选短语后,把合成语音送入正在进行的电话或 FaceTime。

为什么值得做:Transcript 明确指出 mixToTelephonyUplink 可以把 speech route 到 active outgoing call,这对非语言用户很关键。

怎么开始:复用现有短语构建 UI;初始化 AVSpeechSynthesizer;进入通话模式时设置 mixToTelephonyUplink = true;没有通话时保留普通外放路径。

  1. 为 VoiceOver 用户提供一致的应用内播报

做什么:在需要应用自己播报的功能里,让 speech 采用当前辅助技术的声音、语速和音高。

为什么值得做:Session 演示了默认 speech 与 VoiceOver 设置不一致时的割裂感;prefersAssistiveTechnologySettings 能让第二段播报贴近 VoiceOver。

怎么开始:检查每个 AVSpeechUtterance 创建点;对面向辅助技术用户的 utterance 设置 prefersAssistiveTechnologySettings = true;对用户明确自定义 voice 的 AAC 场景保留单独设置。

  1. 把应用内语音从主 audio session 中拆出去

做什么:在音乐、视频或音效较多的 App 中,让 speech audio 交给系统管理,减少音频焦点冲突。

为什么值得做usesApplicationAudioSession = false 后,系统会处理 speech audio 的中断、active 状态,并让 speech 与其他应用音频 duck and mix。

怎么开始:梳理 App 里所有 speech 出口;先在非录音场景试点设置 usesApplicationAudioSession = false;用音乐播放、视频播放、来电中断等路径做回归测试。

关联 Session

评论

GitHub Issues · utterances