- 语音
- 音频
- 人工智能
- 嵌入式
【免费下载链接】porcupine
On-device wake word detection powered by deep learning
本指南以开源仓库porcupine的 iOS 绑定(binding/ios)为对象,系统讲解如何在 iOS 16.0+ 应用中集成 Porcupine 唤醒词引擎:从 Swift Package Manager / CocoaPods 安装、AccessKey 获取、麦克风权限配置,到高层面PorcupineManager(自动录音 + 检测)与低层面Porcupine(自定义音频流水线)两套 API 的完整用法,并覆盖自定义唤醒词、多语言模型与 API 在线训练等进阶场景。读完本文,你可以直接在 Xcode 工程中落地一个始终监听的语音唤醒功能。
Porcupine 与 iOS 绑定的定位
Porcupine 是一个基于深度学习的唤醒词引擎,用于构建"始终监听"(always-listening)的语音应用。其核心特性包括:
- 私有与离线:推理完全在设备端完成,音频不出设备;
- 资源高效:轻量级模型甚至可以在微控制器上运行;
- 数据高效:唤醒词只需"输入短语"即可生成,无需成千上万小时的定制音频训练数据;
- 可扩展:支持同时监听多个唤醒词/常驻语音命令;
- 跨平台:官方提供 iOS、Android、Web、Node.js、Python 等多种绑定。
仓库中的 iOS 绑定位于 binding/ios,核心源码由三个 Swift 文件构成:Porcupine.swift(低层封装)、PorcupineManager.swift(高层封装)与 PorcupineErrors.swift(错误类型体系)。底层通过 lib/ios/PvPorcupine.xcframework 中预编译的原生框架与 C 接口对接(见 include/pv_porcupine.h)。
兼容性与安装
兼容性要求
官方 iOS 绑定要求iOS 16.0+。这一约束同时体现在 Package.swift 的platforms: [.iOS(.v16)]与 Porcupine-iOS.podspec 的s.ios.deployment_target = '16.0'中,两者保持一致。
通过 Swift Package Manager 集成
在 Xcode 中打开工程的Package Dependencies,添加:
https://github.com/Picovoice/porcupine.git从 Package.swift 可以看到,SPM 包会构建Porcupine库目标,将 14 个内置关键词文件(alexa_ios.ppn、picovoice_ios.ppn等)与默认英语模型porcupine_params.pv作为资源一并打包,并自动引入PvPorcupine二进制目标与ios-voice-processor(~> 1.2.0)依赖。
通过 CocoaPods 集成
在 Podfile 中添加:
pod 'Porcupine-iOS'执行pod install后,在 Swift 代码中import Porcupine即可。根据 Porcupine-iOS.podspec,该 Pod 的模块名为Porcupine,Swift 版本 5.7,内置关键词与默认模型通过PorcupineResourcesresource bundle 分发。
获取 AccessKey
Porcupine 在初始化时必须传入有效的 PicovoiceAccessKey,它相当于使用 SDK 时的凭证:
- 免费注册/登录 Picovoice Console 即可获取;
- 务必保密,不要提交到公开代码仓库;
- 源码层面同样有强制校验:在 Porcupine.swift 中,空字符串 AccessKey 会直接抛出
PorcupineInvalidArgumentError("AccessKey is required for Porcupine initialization")。
麦克风权限配置
高层面 APIPorcupineManager需要访问设备麦克风,必须在应用的Info.plist中添加权限描述:
<key>NSMicrophoneUsageDescription</key> <string>[Permission explanation]</string>其中[Permission explanation]替换为向用户说明为何需要麦克风权限的文案。若缺失该键,录音启动会失败。低层面 APIPorcupine本身不直接录音(由你自行提供音频帧),但若应用整体需要麦克风,同样需要该权限。
高层面 API:PorcupineManager
PorcupineManager.swift 提供高层面 API:它内部借助ios-voice-processor完成麦克风录音,并将每一帧音频实时送入 Porcupine 检测引擎,检测到唤醒词时回调你注册的函数。这是快速上手的最简路径。
使用内置唤醒词
import Porcupine let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai) do { let porcupineManager = try PorcupineManager( accessKey: accessKey, keyword: Porcupine.BuiltInKeyword.picovoice, onDetection: wakeWordCallback) } catch { }wakeWordCallback是检测到关键词时被调用的回调函数,接收一个整数参数,指明检测到的是第几个唤醒词:
let wakeWordCallback: ((Int32) -> Void) = { keywordIndex in if keywordIndex == 0 { // wake word 0 detected! } }内置唤醒词通过Porcupine.BuiltInKeyword枚举访问。从 Porcupine.swift 的源码可以看到完整枚举列表:
| 枚举值 | 唤醒词文本 |
|---|---|
alexa | Alexa |
americano | Americano |
blueberry | Blueberry |
bumblebee | Bumblebee |
computer | Computer |
grapefruit | Grapefruit |
grasshopper | Grasshopper |
heyGoogle | Hey Google |
heySiri | Hey Siri |
jarvis | Jarvis |
okGoogle | Ok Google |
picovoice | Picovoice |
porcupine | Porcupine |
terminator | Terminator |
内置关键词构造时,源码会从 resource bundle 中查找对应文件(命名规则为关键词文本小写 + "_ios",扩展名ppn),例如porcupine_ios.ppn、hey google_ios.ppn。
使用自定义唤醒词
若需检测自定义唤醒词,改用keywordPaths参数传入.ppn文件路径数组:
do { let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai) let paths = ["path/to/keyword/one.ppn", "path/to/keyword/two.ppn"] let porcupineManager = try PorcupineManager( accessKey: accessKey, keywordPaths: paths, onDetection: wakeWordCallback) } catch { }传入多个路径即可同时监听多个唤醒词,回调中的keywordIndex与路径数组顺序一一对应(0 起)。
灵敏度与模型文件
除自定义唤醒词外,你还可以覆盖默认的英语模型文件和每个关键词的灵敏度(sensitivity):
- sensitivity:在漏报率(miss rate)与误报率(false alarm rate)之间权衡的浮点参数,取值范围[0, 1]。灵敏度越高,漏报越少,但误报增加。默认值为
0.5(见 Porcupine.swift 与 PorcupineManager.swift)。若传入的灵敏度数组长度与关键词数量不匹配,或任一数值越界,源码会抛出PorcupineInvalidArgumentError。 - modelPath:唤醒词引擎的参数文件(
.pv)。切换模型文件即可改变 Porcupine 理解的语言。默认使用英语模型porcupine_params.pv,从资源包中自动加载(Porcupine.swift)。
可选参数用法:
do { let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai) let paths = ["path/to/keyword/one.ppn", "path/to/keyword/two.ppn"] let porcupineManager = try PorcupineManager( accessKey: accessKey, keywordPaths: paths, modelPath: "path/to/model/file.pv", sensitivities: [0.7, 0.35], onDetection: wakeWordCallback) } catch { }启动、停止与资源释放
实例化PorcupineManager后即可开始录音与唤醒词检测:
do { porcupineManager.start() } catch { }停止监听:
porcupineManager.stop()从源码看,start()会向VoiceProcessor注册 frame/error 监听器并以Porcupine.frameLength、Porcupine.sampleRate启动录音;stop()则移除监听器并在无其他监听者时停止录音(PorcupineManager.swift)。检测结果与错误都会通过DispatchQueue.main.async回抛到主线程,方便直接更新 UI。
当应用不再需要该实例时,建议主动释放原生资源,而非等待垃圾回收:
porcupineManager.delete()delete()会先停止监听(若正在监听),再释放底层 Porcupine 实例的原生句柄(PorcupineManager.swift)。
低层面 API:Porcupine
Porcupine.swift 提供低层访问接口,适合已有自建音频处理流水线、希望把唤醒词检测嵌入其中的场景。它不负责录音,只负责对传入的音频帧做推理。
构造实例
import Porcupine do { let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai) let porcupine = try Porcupine(accessKey: accessKey, keyword: Porcupine.BuiltInKeyword.picovoice) } catch { }构造器同样支持keywordPaths、modelPath、sensitivities等参数,并额外提供device参数控制推理设备。从 Porcupine.swift 的文档注释与 include/pv_porcupine.h 可以确认其取值规则:
best(默认):自动选择最合适的设备;gpu:使用第一块可用 GPU;gpu:${GPU_INDEX}:指定第 N 块 GPU;cpu:以默认线程数在 CPU 上运行;cpu:${NUM_THREADS}:指定 CPU 线程数。
此外,Porcupine.getAvailableDevices()可以列出所有可用于推理的设备(底层调用pv_porcupine_list_hardware_devices,Porcupine.swift)。
帧处理循环
调用process函数逐帧搜索关键词,返回值keywordIndex为-1表示未检测到,否则为检测到的关键词索引:
func getNextAudioFrame() -> [Int16] { // .. get audioFrame return audioFrame; } while true { do { let keywordIndex = try porcupine.process(getNextAudioFrame()) if keywordIndex >= 0 { // .. detection made! } } catch { } }音频格式要求
process正常工作必须满足 Picovoice 规定的音频格式:
- 通过
Porcupine.sampleRate获取所需采样率(静态属性,底层对应pv_sample_rate()); - 通过
Porcupine.frameLength获取每帧所需样本数(静态属性,底层对应pv_porcupine_frame_length()); - 音频必须是单声道、16-bit 线性编码(PCM)。
源码对帧长有严格校验:process收到的pcm.count不等于Porcupine.frameLength时会抛出PorcupineInvalidArgumentError(Porcupine.swift)。测试工程中 BaseTest.swift 的processFile展示了标准做法:从 WAV 数据中跳过 44 字节文件头后,按frameLength * 2字节(16-bit 双字节)切帧送入process。
资源释放
使用完毕后主动释放原生资源:
porcupine.delete();delete()内部调用pv_porcupine_delete并清空句柄(Porcupine.swift),实例析构(deinit)时也会自动兜底释放。
自定义唤醒词集成
将自定义唤醒词.ppn文件加入 iOS 应用的方式:在 Xcode 的Build Phases > Copy Bundle Resources中添加该资源,然后在代码中获取其路径:
// file is called keyword_ios.ppn let keywordPath = Bundle.main.path(forResource: "keyword_ios", ofType: "ppn")如果模型文件是通过其他方式部署到设备上的,也可以直接使用设备上的绝对路径。源码中 getResourcePath 的逻辑说明:初始化时若传入的路径在文件系统中不存在,会尝试从应用 bundle 中按相对路径查找资源。
非英语场景
检测非英语唤醒词需要使用对应的语言模型文件。仓库 lib/common 目录下随包提供了全部支持语言的可移植模型参数文件:
porcupine_params.pv # 英语(默认) porcupine_params_de.pv # 德语 porcupine_params_es.pv # 西班牙语 porcupine_params_fr.pv # 法语 porcupine_params_it.pv # 意大利语 porcupine_params_ja.pv # 日语 porcupine_params_ko.pv # 韩语 porcupine_params_pt.pv # 葡萄牙语 porcupine_params_zh.pv # 中文用法示例:将porcupine_params_es.pv传入modelPath,并搭配对应的西班牙语.ppn关键词文件。注意语言必须匹配——测试用例 PorcupineAppTestUITests.swift 中的testInitFailWithMismatchedLanguage验证了"德语关键词 + 英语模型"初始化会失败。多语言完整回归由 PorcupineLanguageTests.swift 中的testWrapper驱动,它会按test_data.json遍历各语言测试用例。
通过 API 在线训练唤醒词模型
无需打开 Console 页面,可以直接通过 API 训练模型:
try Porcupine.trainWakeWordFromPhrase( "${ACCESS_KEY}", // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/) "${OUTPUT_PATH}", // Absolute path to file where the trained model will be saved "${LANGUAGE}", // Two character language code for the model (e.g. "en", "fr") "${PHRASE}" // Phrase to create a wake word from )从 Porcupine.swift 的实现可以看到该方法的内部行为:
- 语言白名单校验:
language必须是["en", "fr", "de", "es", "it", "ja", "ko", "pt"]之一,否则抛出PorcupineInvalidArgumentError; - 短语校验:短语不能为空,且长度不能超过 64 个字符;
- 网络请求:向
https://rest.picovoice.ai/{language}/api/ppn发送 POST 请求,AccessKey 放在x-api-key请求头,请求体为{"platform": "ios", "phrase": "..."}; - 结果落盘:响应成功(HTTP 2xx)后把返回的模型二进制写入
outputPath。
训练完成后即可用返回的.ppn文件直接初始化Porcupine或PorcupineManager。测试用例 PorcupineTrainTests.swift 展示了"训练 → 初始化 → 释放"的完整闭环,并验证了非法短语会抛错。
运行单元测试
打开仓库中的 PorcupineAppTest.xcodeproj,在 Xcode 中执行Product > Test即可运行测试。测试覆盖了三类场景:
- 功能测试(PorcupineAppTestUITests.swift):单/多内置关键词初始化与检测、自定义关键词与灵敏度、无效模型路径/灵敏度/关键词数量/平台不符等异常分支、设备枚举、错误消息栈等;
- 多语言测试(PorcupineLanguageTests.swift):按语言加载对应模型与关键词,对照 ground truth 验证检测结果;
- 性能测试(PerformanceTest):对 WAV 文件逐帧调用
process计时,断言平均处理耗时低于阈值。
测试资源由 copy_test_resources.sh 从仓库lib、resources目录拷贝生成。
参考 Demo 应用
仓库 demo/ios 提供两个可直接运行的示例工程:
- ForegroundApp:应用处于前台时进行唤醒词检测,支持在多个语言 Scheme 与内置关键词之间切换,其 ViewModel.swift 展示了
PorcupineManager的完整接入(含麦克风权限申请、启动/停止、错误分类处理); - BackgroundService:应用退到后台仍持续监听唤醒词(iOS 16.0+)。
两个 Demo 的接入方式均为:打开对应.xcodeproj,将ViewModel.swift中的${YOUR_ACCESS_KEY_HERE}替换为你的 AccessKey,然后运行。
常见错误类型
初始化或处理失败时抛出的错误统一继承自PorcupineError(PorcupineErrors.swift),按底层状态码映射为具体子类,便于精细化捕获:
| 错误类型 | 触发场景(示例) |
|---|---|
PorcupineMemoryError | 底层内存分配失败 |
PorcupineIOError | 模型/关键词文件缺失或不可读 |
PorcupineInvalidArgumentError | AccessKey 为空、灵敏度越界或数量不匹配、帧长不符、短语非法 |
PorcupineKeyError | AccessKey 无效 |
PorcupineInvalidStateError | 在已 delete 后调用start/process等 |
PorcupineRuntimeError | 网络请求失败、训练 API 返回非 2xx |
PorcupineActivationError/ActivationLimitError/ActivationThrottledError/ActivationRefusedError | AccessKey 激活相关异常 |
错误对象附带原生 message stack,便于排查底层引擎的具体失败原因。
- 语音
- 音频
- 人工智能
- 嵌入式
【免费下载链接】porcupine
On-device wake word detection powered by deep learning
相关推荐
Android 端 Porcupine 唤醒词引擎接入指南:高层/低层 API、自定义唤醒词与多语言部署
Android 端 Porcupine 唤醒词引擎接入指南:高层/低层 API、自定义唤醒词与多语言部署 本篇技术指南以 binding/android/REA
语音音频人工智能嵌入式Porcupine 唤醒词引擎完全指南:多平台 Demo 实操、SDK 集成与 ANSI C 源码级原理解析
Porcupine 唤醒词引擎完全指南:多平台 Demo 实操、SDK 集成与 ANSI C 源码级原理解析 Porcupine 是 Picovoice 出品的
语音音频人工智能嵌入式Porcupine语音唤醒引擎指南
Porcupine语音唤醒引擎指南 1. 项目介绍 Porcupine是由Picovoice开发的一款高性能的开源语音唤醒引擎,它允许开发者在各种设备上实现自定
语音音频人工智能嵌入式
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考