TEN Framework vosk_asr_cpp 扩展深入解析:用 C++ 构建基于 Vosk 的本地实时语音识别
人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载本文以 TEN Framework 仓库中的vosk_asr_cpp示例扩展为主线系统讲解如何将开源语音识别引擎 Vosk 封装为一个标准的 TEN Framework C 扩展从 VOSK SDK 与识别模型的手工部署到扩展属性property.json配置、扩展生命周期回调on_init/on_audio_frame/on_deinit的源码走读再到基于 googletest 的独立测试与tman安装集成流程。读完本文你可以完整复现该扩展的部署与构建过程并理解 TEN Framework 音频扩展帧进、结果出的数据流设计。一、扩展定位TEN Framework 中的 C ASR 扩展vosk_asr_cpp是一个为 TEN Framework 用 C 编写的 Vosk 自动语音识别ASR扩展其定位是接收上游如音频文件播放器、麦克风采集模块送入的音频帧逐帧送入 Vosk 识别器进行解码并以data消息的形式输出识别文本——既包括说话过程中的部分结果partial result也包括语句结束时的最终结果final result从而天然适配实时转写场景。从 manifest.json 可以看到该扩展的元信息type为extension包名为vosk_asr_cpp当前版本0.11.73tags标注为cpp表明这是一个 C 实现的扩展依赖两个系统包ten_runtime扩展运行时版本0.11.73与googletest版本1.7.0-rc2用于独立测试。manifest 中还定义了两个常用脚本体现了该包的日常开发方式scripts: { test: bin/vosk_asr_cpp_test, build: sh -c cd .ten/app tgn gen linux x64 debug -- ten_enable_standalone_testtrue tgn build linux x64 debug }其中build脚本通过tgn gen生成构建文件并显式开启ten_enable_standalone_testtrue再执行tgn build这与第六节介绍的独立测试机制直接对应。二、环境准备手工部署 VOSK SDK为什么 SDK 不随扩展自带VOSK SDK包含头文件与动态库体积较大因此vosk_asr_cpp默认不内置SDK需要使用者自行下载并部署。官方文档README.en-US.md、README.ja-JP.md 等多语言版本给出的做法是从 vosk-api 的官方发行页alphacep/vosk-api 的 releases下载与当前平台匹配的预编译包然后按以下两个位置放置文件文件放置位置作用vosk_api.h扩展根目录下的include/目录编译期头文件src/main.cc中#include vosk_api.h直接依赖它libvosk.so扩展根目录下的lib_private/目录运行期动态库构建时链接、运行时通过 rpath 查找rpathlib_private/是如何被找到的这一目录约定并非随意规定BUILD_release.gn 中有明确的构建配置佐证ten_package(vosk_asr_cpp) { package_kind extension enable_build true sources [ src/main.cc ] include_dirs [ include, include/nlohmann_json, ] # Add rpath to find vosk library. if (is_mac) { ldflags [ -Wl,-rpath,loader_path/../lib_private ] } else if (is_linux) { ldflags [ -Wl,-rpath\$ORIGIN/../lib_private ] } lib_dirs [ lib_private ] libs [ vosk ] }可以看到include目录被加入头文件搜索路径vosk_api.h由此被找到lib_dirs指向lib_private链接期找到libvosk同时通过平台相关的-rpathLinux 下$ORIGIN/../lib_privatemacOS 下loader_path/../lib_private确保扩展编译出的动态库在运行期也能从相对自身路径的lib_private/目录加载libvosk.so而不依赖系统库搜索路径或LD_LIBRARY_PATH。这就是头文件放include/、动态库放lib_private/这一约定的底层原因。注意仓库中include/目录当前已内置了nlohmannJSON 库头文件说明该扩展在构建配置层面预留了第三方头文件扩展能力而 vosk 相关头文件仍需使用者按上述说明手工补充。三、安装 VOSK 识别模型SDK 只解决怎么跑识别引擎的问题真正的识别能力来自 Vosk 模型。文档要求从 Vosk 模型官网alphacephei.com/vosk/models下载所需模型解压后放到扩展根目录的models/目录下。模型加载逻辑在源码中非常直接。src/main.cc 的on_init回调中void on_init(ten::ten_env_t ten_env) override { auto model_name ten_env.get_property_string(model_name); // Open the specified model. vosk_model vosk_model_new((std::string(models/) model_name).c_str()); if (vosk_model nullptr) { TEN_LOGE(Failed to load model, check if exists in the folder); exit(EXIT_FAILURE); } auto sample_rate ten_env.get_property_float32(sample_rate); TEN_ENV_LOG_INFO(ten_env, (std::string(Specify sample rate: ) std::to_string(sample_rate)).c_str()); vosk_recognizer vosk_recognizer_new(vosk_model, sample_rate); if (vosk_recognizer nullptr) { TEN_LOGE(Failed to create recognizer); exit(EXIT_FAILURE); } ten_env.on_init_done(); }要点模型名不是硬编码的而是从扩展属性model_name读取再以models/ model_name拼接成相对路径调用vosk_model_new加载——这就是模型必须放在models/目录下的强制约定加载失败会打印Failed to load model, check if exists in the folder并直接exit(EXIT_FAILURE)排查部署问题时可优先检查日志中这条信息识别器vosk_recognizer_new的第二个参数是采样率来自属性sample_ratefloat32 类型识别器的解码行为会严格基于该采样率设计。四、属性配置property.json 的两个核心参数扩展根目录下的 property.json 定义了该扩展的全部可配置属性默认内容如下{ model_name: vosk-model-small-en-us-0.15, sample_rate: 16000.0 }属性类型默认值含义与约束model_namestringvosk-model-small-en-us-0.15models/目录下的模型子目录名对应从官网下载的英文小模型更换模型如中文模型时同步修改此项sample_ratefloat3216000.0送入识别器的音频采样率Vosk 官方小模型基于 16 kHz 设计修改该值时须与模型要求及上游音频流一致sample_rate在on_init中会以TEN_ENV_LOG_INFO打印日志形如Specify sample rate: 16000便于运行时核对配置是否生效。测试代码 tests/basic.cc 的注释也再次强调测试音频需为16 kHz 采样率的 PCM 格式。五、核心实现走读音频帧进、识别结果出数据流总览从源码结构看整个扩展的数据流是一个清晰的单向管线上游音频帧 (audio_frame) └─ on_audio_frame ├─ frame-lock_buf() 锁定 PCM 数据 ├─ vosk_recognizer_accept_waveform() 送入 Vosk 解码 ├─ 判断 is_final0仍在说话非0一句话结束 │ ├─ 非最终句vosk_recognizer_partial_result() │ └─ 最终句vosk_recognizer_result() └─ send_data(recognition_result) 输出 data 消息 ├─ property: result (string) └─ property: is_final (int)on_audio_frame逐帧解码与部分/最终结果关键实现在 src/main.ccvoid on_audio_frame(ten::ten_env_t ten_env, std::unique_ptrten::audio_frame_t frame) override { std::string frame_name frame-get_name(); TEN_ENV_LOG_INFO( ten_env, (std::string(Received audio frame ) frame_name ).c_str()); ten::buf_t locked_in_buf frame-lock_buf(); int is_final vosk_recognizer_accept_waveform( vosk_recognizer, reinterpret_castconst char *(locked_in_buf.data()), static_castint(locked_in_buf.size())); frame-unlock_buf(locked_in_buf); const char *result nullptr; if (is_final ! 0) { result vosk_recognizer_result(vosk_recognizer); } else { result vosk_recognizer_partial_result(vosk_recognizer); } auto recognition_result ten::data_t::create(recognition_result); recognition_result-set_property(result, result); recognition_result-set_property(is_final, is_final); bool rc ten_env.send_data(std::move(recognition_result)); TEN_ASSERT(rc, Should not happen.); }几个实现细节值得注意缓冲区生命周期管理lock_buf()/unlock_buf()是 TEN Framework 音频帧的加锁/解锁配对操作。Vosk 的accept_waveform是同步调用解码完成并取走结果后即可解锁保证帧内存可被框架复用is_final的双义性vosk_recognizer_accept_waveform的返回值0 或非 0本身表示这一帧是否触发了语句结束扩展原样把它透传给下游is_final属性下游节点如 TTS、日志节点可据此区分流式部分结果与完整句子结果消息命名输出的data消息固定命名为recognition_result携带result识别文本与is_final两个属性这与测试代码的读取方式完全对称。on_deinit 与扩展注册资源释放与注册分别见 src/main.ccon_deinit中先释放识别器、再释放模型vosk_recognizer_free→vosk_model_free并置空指针最后调用ten_env.on_deinit_done()通知框架文件末尾通过宏TEN_CPP_REGISTER_ADDON_AS_EXTENSION(vosk_asr_cpp, vosk_asr_cpp_t)将 C 类注册为 TEN 扩展扩展名与包名保持一致。六、独立测试用 test.wav 验证端到端识别该扩展自带一个基于 googletest 的独立standalone测试可在不启动完整 TEN 应用的情况下验证音频进、文本出的完整链路。前置条件安装 googletest 系统包BUILD_release.gn 中的注释给出了明确的命令tman install system googletest对应manifest.json中声明的googletest依赖。之后通过tgn gen ... -- ten_enable_standalone_testtrue生成构建时才会启用如下测试目标if (ten_enable_standalone_test) { ten_package_test(vosk_asr_cpp_test) { package_kind extension sources [ .ten/app/ten_packages/system/googletest/src/gtest-all.cc, .ten/app/ten_packages/system/googletest/src/gtest_main.cc, tests/basic.cc, ] ... } }测试流程解析tests/basic.cc 的实现思路是模拟一个真实音频源构造函数打开./tests/test.wav注释明确要求PCM 格式、16 kHz 采样率该样例音频随包提供tests/test.wavon_start中按 4096 字节为块循环fread每块数据封装成一个名为recognize的audio_frame_t通过lock_buf/memcpy/unlock_buf写入 PCM 数据后send_audio_frame送入扩展模拟持续灌入音频流on_data回调读取扩展输出的recognition_result消息打印result与is_final一旦收到is_final 0的最终结果即调用ten_env.stop_test()结束测试——这隐含了 test.wav 中应包含一段完整语句的假设TEST(Test, Basic)入口通过set_test_mode_single(vosk_asr_cpp)声明被测扩展随后run()执行整个生命周期。提醒独立测试要求models/目录中已按property.json的model_name配置好模型否则扩展会在on_init阶段直接失败退出。七、安装与集成到 TEN 应用官方文档说明安装方式为遵循 TEN Framework 的包安装指南。结合仓库快速上手文档 docs/getting-started/quick-start.md 中介绍 C 扩展的标准流程以webrtc_vad_cpp为例vosk_asr_cpp的集成路径为安装扩展在应用目录如示例应用transcriber_demo下执行tman install extension vosk_asr_cpp将扩展连同本文第二节、第三节要求手工放置的 SDK 与模型文件拉入应用的.ten包环境重新构建执行tman run build构建系统会依据BUILD_release.gn把src/main.cc编译成扩展动态库并链接libvosk在应用中编排按 TEN Framework 的应用规范将该扩展挂入音频处理链路让上游节点如音频文件播放器的音频帧发往vosk_asr_cpp下游节点消费recognition_result数据消息即可。此外C 扩展的编译要求宿主机具备 C 工具链gcc/g 或 clang快速上手文档中给出了各平台的安装示例manifest.json的build脚本则展示了在 Linux x64 debug 模式下手工驱动tgn gentgn build的等价做法。八、目录结构与许可证小结综合 BUILD.gn 的打包规则与仓库实际内容该扩展的目录职责如下路径内容说明src/main.cc扩展唯一源码生命周期回调与 Vosk 调用本文第五节include/头文件内置 nlohmann 头文件vosk 头文件需手工放入lib_private/私有动态库需手工放入libvosk.so由 rpath 定位models/识别模型需手工下载解压放置名称与model_name属性一致property.json属性默认值model_name与sample_ratetests/basic.cc、tests/test.wav独立测试与样例音频16 kHz PCMBUILD.gn/BUILD_release.gn构建定义开发态打包 / 发布态编译含 rpath 与链接配置docs/README.*.md多语言文档en-US、zh-CN、zh-TW、ja-JP、ko-KR 五个版本关于许可证官方文档声明该包是 TEN Framework 项目的一部分遵循仓库顶层 LICENSE 所约定的 Apache License 2.0 许可。九、小结vosk_asr_cpp虽然代码量很小但它是理解 TEN Framework C 扩展机制的一个理想样本手工部署第三方 SDKinclude/lib_private/ rpath、通过property.json声明可配置项、在on_init/on_audio_frame/on_deinit三个回调中完成资源初始化、流式解码与释放最后用 googletest 独立测试验证端到端行为。掌握这套模式后将其他本地推理引擎封装成 TEN Framework 音频扩展只需替换解码核心、保持音频帧进、data 消息出的边界约定即可。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐TEN Framework vosk_asr_cpp 扩展实战Vosk C 语音识别扩展的 SDK 部署、属性配置与源码解析TEN Framework vosk_asr_cpp 扩展实战Vosk C 语音识别扩展的 SDK 部署、属性配置与源码解析 本文以 TEN Framew人工智能AI Agent多模态语音AI 应用TEN Framework 集成指南基于 AWS Transcribe 的异步实时语音识别扩展 aws_asr_pythonTEN Framework 集成指南基于 AWS Transcribe 的异步实时语音识别扩展 aws_asr_python 导读 本文深入讲解 TEN Fr人工智能AI Agent多模态语音AI 应用TEN Framework 中的 Soniox 实时语音识别扩展soniox_asr_python使用与源码解析TEN Framework 中的 Soniox 实时语音识别扩展soniox_asr_python使用与源码解析 本指南以 TEN Framework 仓库人工智能AI Agent多模态语音AI 应用上一篇微信聊天记录永久保存完全指南如何让珍贵对话永不丢失下一篇如何永久保存微信聊天记录WeChatMsg导出工具完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

PaddleSpeech VITS 单调对齐模块解析:monotonic_align 的 maximum_path 实现与双后端加速机制

PaddleSpeech VITS 单调对齐模块解析:monotonic_align 的 maximum_path 实现与双后端加速机制

人工智能语音音频NLP媒体生成 【免费下载链接】PaddleSpeech Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation …

2026/9/26 13:23:24 阅读更多 →
Windows关机不彻底?一文看懂快速启动与真正关机的方法

Windows关机不彻底?一文看懂快速启动与真正关机的方法

你有没有注意过,Windows电脑点“关机”之后,如果再开机,速度往往快得不像话,有的机器甚至5秒内就回到了桌面。先别高兴,这个“关机”很可能只是半关机:系统内核根本没有完全退出,它被保存到了磁…

2026/9/26 8:08:24 阅读更多 →
AI原生软件开发:Anthropic手册的工程落地指南

AI原生软件开发:Anthropic手册的工程落地指南

先声明一下,这篇不是把手册原文翻译一遍,那没意思。我更想把Anthropic公开的内部AI原生软件开发手册当成一份“工程路线图”,结合我自己这一年多在真实项目里折腾AI编程工具的经历,把它拆成能直接落地的思路、步骤和坑。毕竟工具谁…

2026/9/25 7:49:08 阅读更多 →

最新新闻

UWB不止定位:用SR1120构建低功耗高速短距数据链路

UWB不止定位:用SR1120构建低功耗高速短距数据链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 13:55:32 阅读更多 →
Claude Code模板实战:从提示词工程到AI编程规范化

Claude Code模板实战:从提示词工程到AI编程规范化

第一次看到 claude-code-templates 这个项目名,我的第一反应是:模板?代码生成不是现场发挥吗?等自己实际搭过一遍才发现,模板这套东西不是“把提示词存起来”这么简单。它解决的是我长期以来的一个真实痛点&#xff…

2026/9/26 13:55:32 阅读更多 →
xAI发布Grok Build后,AI终端展深圳开幕:用TaoToken统一Key打通Claude Code与Agent终端链路

xAI发布Grok Build后,AI终端展深圳开幕:用TaoToken统一Key打通Claude Code与Agent终端链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 13:55:32 阅读更多 →
ESP32 NVS数据隔离四层防线:防串门、防覆盖、防崩溃

ESP32 NVS数据隔离四层防线:防串门、防覆盖、防崩溃

1. 为什么“多个小应用共用一块 Flash”会出事?——从 NVS 的物理本质讲起你手头有块 ESP32,上面跑着温控模块、OTA 升级服务、蓝牙配网 UI、还有个本地日志缓存器——四个独立功能模块,各自都要存点东西:温控的校准系数、OTA 的固…

2026/9/26 13:55:32 阅读更多 →
宏翔上位机3.5实战:从CAN调试到ECU刷写完整指南

宏翔上位机3.5实战:从CAN调试到ECU刷写完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 13:55:32 阅读更多 →
Java后端对象分层:PO、VO、BO、DTO、DAO全解析

Java后端对象分层:PO、VO、BO、DTO、DAO全解析

1. 这几个缩写到底在说什么先讲个我面试时的真实经历。有次候选人简历写得挺漂亮,我随口问了句"你们项目里的VO和DTO是一回事吗",对方愣了几秒,回了一句"反正都是用来传数据的,感觉差不多"。这回答不算错&…

2026/9/26 13:54:31 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →