帮你快速理解、总结文档立即下载

实时语音识别 V2

最近更新时间:2026-08-11 17:35:37
我的收藏
SDK 以插件的方式封装了 Android 和 iOS 实时语音识别 V2 功能,提供 Flutter 版本的实时语音识别。V2 通过 WebSocket 实时识别音频,并将服务端返回的原始 JSON 透传给开发者,由开发者自行解析语音识别结果。本文介绍 SDK 的安装方法及示例。

开发环境

Dart >= 2.18.4
Flutter >= 3.3.8
Android API Level >= 24
iOS >= 13.0

获取安装

请前往 控制台 下载 Flutter-V2,SDK 内 asr_plugin 目录即为 Flutter 插件,插件内 example 目录下为 Demo 示例。

接入指引

注意:
此插件仅支持 Android 和 iOS 两个平台且包含了平台相关的库,使用时请确保开发环境包含 Android Studio 及 XCode 否则可能会出现集成时的编译问题。
1. 将项目中 asr_plugin 目录复制到自己的 Flutter 工程下。
2. 在自己项目的配置文件 pubspec.yaml 下添加依赖。
asr_plugin:
# 该路径根据asr_plugin存放路径改变
path: ../asr_plugin
3. 在需要使用到的页面,导入 asr_plugin 的依赖。
import 'package:asr_plugin/asr_plugin.dart';

接口说明

接口示例代码为 demo 部分代码,完整代码请参考位于 example 里的 demo 示例。

ASRControllerConfig

配置相关参数用于生成 ASRController

参数
int appID = 0; // 腾讯云 appID
int projectID = 0; //腾讯云 projectID
String secretID = ""; //腾讯云 secretID
String secretKey = ""; // 腾讯云 secretKey
String? token = null; // 腾讯云 token(可选)

String engine_model_type = "16k_zh_en_speaker_2.0"; //设置引擎,不设置默认16k_zh_en_speaker_2.0(V2 引擎)
int filter_dirty = 0; //是否过滤脏词,具体的取值见API文档的filter_dirty参数
int filter_modal = 0; //过滤语气词具体的取值见API文档的filter_modal参数
int filter_punc = 0; //过滤句末的句号具体的取值见API文档的filter_punc参数
int convert_num_mode = 1; //是否进行阿拉伯数字智能转换。具体的取值见API文档的convert_num_mode参数
String hotword_id = ""; //热词id。具体的取值见API文档的hotword_id参数
String customization_id = ""; //自学习模型id,详情见API文档
int? vad_silence_time = 0; //语音断句检测阈值,详情见API文档
int needvad = 1; //人声切分,详情见API文档
int word_info = 0; //是否显示词级别时间戳,详情见API文档
int reinforce_hotword = 0; //热词增强功能,详情见API文档
double noise_threshold = 0; //噪音参数阈值,详情见API文档

bool is_compress = true; //是否开启音频压缩,开启后使用opus压缩传输数据
bool silence_detect = false; //静音检测功能,开启后检测到静音会停止识别
int silence_detect_duration = 5000; //静音检测时长,开启静音检测功能后生效
bool is_save_audio_file = false; //是否保存音频,仅对内置录音生效,格式为s16le,16000Hz,mono的pcm,开启后会通过NOTIFY类型的ASRData返回到上层,其中ASRData中info为以下的JSON格式{"type":"onAudioFile", "code": 0, "message": "audio file path"}
String audio_file_path = ""; //is_save_audio_file为true时,会将音频保存在指定位置

/// 自定义请求域名,仅替换 ws/wss 连接的域名部分;不传则使用默认内置国内域名 asr.cloud.tencent.com。
/// 仅传纯域名,无需带路径,例如境外用户可设置为 "asr.international.cloud.tencent.com"。
/// 注意:签名串始终使用默认内置国内域名计算,不受此参数影响。
String? host;

方法
Future<ASRController> build() async // 创建ASRController
void setCustomParam(String key, dynamic value) // 设置自定义参数(透传到native层)
void removeCustomParam(String key) // 移除自定义参数
ASRControllerConfig clone() // 克隆当前配置

示例
var _config = ASRControllerConfig();
_config.filter_dirty = 1;
_config.filter_modal = 0;
_config.filter_punc = 0;
var _controller = await _config.build();

ASRController

控制语音识别的流程及获取语音识别的结果

方法
Stream<ASRData> recognize() async* // 开始识别(内置录音)
Stream<ASRData> recognizeWithDataSource(Stream<Uint8List>? source) async* // 开始识别(自定义数据源)
stop() async // 停止识别
Future<void> cancel() // 取消识别并把 SDK 状态强制重置回 none(iOS/Android 均生效)
release() async // 释放资源
Future<void> writeContent(ContextPrompt contextPrompt) // 在识别过程中发送临时热词/上下文prompt

// 以下 3 个 SDK 状态查询接口 iOS/Android 均已支持(V2 底层原生提供)
Future<ASRRecognizeState> getAudioRecognizeState() // 查询 SDK 当前录音识别状态
Future<bool> canStartAudioRecognize() // 当前是否可以直接开启一次新的识别(等价 state == none)
Future<bool> needCancelToResetState() // 当前是否停留在 start/stop 中间态,需要先 cancel 重置

writeContent 说明
仅在识别进行中(onSliceSuccess 已开始下发)调用有效
对发送之后的音频识别生效
若识别未开始或已结束,会抛出 PlatformException(code=-104)
参数非法(prompt 为空等)会抛出 PlatformException(code=-105)
序列化或底层发送异常会抛出 PlatformException(code=-106)

SDK 状态查询说明
ASRRecognizeState 与 iOS QCloudASRRealTimeRecognizeState 一一对应:
none :空闲,可安全调用 recognize / recognizeWithDataSource
start :已调用 start,正在建立 WebSocket 连接
stop :已调用 stop,录音已结束,正在等待服务端返回 final 结果
recognizing :WebSocket 已连接成功,录音线程正在运行并持续发送音频
推荐流程:开始新一轮识别前先看 canStartAudioRecognize();若为 false 且 needCancelToResetState() 为 true,则先 cancel() 再启动,避免 SDK 停留在 start/stop 中间态导致的重复启动问题

cancel 与 stop 的区别
stop:自然结束当前识别任务,等待服务端返回最终结果后再关闭连接
cancel:立即终止识别,不等待服务端返回任何结果,直接关闭 WebSocket 连接

示例
try {
if (_controller != null) {
await _controller?.release();
}
_controller = await _config.build();
setState(() {
_btn_onclick = stopRecognize;
});
await for (final val in _controller!.recognize()) {
switch (val.type) {
case ASRDataType.SLICE:
var id = val.id!;
var res = val.res!;
var speakerId = val.speakerId; // 说话人 ID:-1=未确定,0~9=对应说话人(V2 引擎下发)
var sentenceType = val.sentenceType; // 句子类型:0=中间态(非稳态),1=稳态(最终确定结果)
if (id >= _sentences.length) {
for (var i = _sentences.length; i <= id; i++) {
_sentences.add("");
}
}
_sentences[id] = res;
setState(() {
_result = _sentences.map((e) => e).join("");
});
break;
case ASRDataType.SUCCESS:
setState(() {
_btn_onclick = startRecognize;
_result = val.result!;
_sentences = [];
});
break;
}
}
} on ASRError catch (e) {
setState(() {
_btn_onclick = startRecognize;
_result = "错误码:${e.code} \\n错误信息: ${e.message} \\n详细信息: ${e.resp}";
});
} catch (e) {
log(e.toString());
setState(() {
_btn_onclick = startRecognize;
});
}
}

ASRData

识别过程中返回的数据

参数
ASRDataType type; //数据类型
int? id; //句子的sentence_id
String? res; //数据类型为SLICE时返回的识别结果,具体格式参考服务端返回
String? result; //数据类型为SUCCESS时返回的识别结果,具体格式参考服务端返回
String? info; //数据类型为NOTIFY时携带的信息,具体格式参考服务端返回
int? speakerId; //说话人 ID:-1=未确定,0~9=对应说话人。V2 引擎(如 16k_zh_en_speaker_2.0)下发
int? sentenceType; //句子类型:0=中间态(非稳态,可能被后续结果修正),1=稳态(最终确定结果)。V2 引擎下发

V2 原始 JSON 与 ASRData 字段的对应关系
V2 SDK 从服务端接收的原始 JSON 结构如下:
{
"code": 0,
"message": "",
"sentences": {
"voice_text_str": "完整识别文本",
"sentence_list": [
{
"sentence_id": 0,
"sentence_type": 1,
"speaker_id": 0,
"sentence": "今天天气真好"
},
{
"sentence_id": 1,
"sentence_type": 0,
"speaker_id": -1,
"sentence": "是的啊"
}
]
},
"speaker_context_id": "a1b2c3d4e5f6..."
}

原生层会遍历 sentences.sentence_list(兼容旧版 result.speaker_sentences),逐条以 SLICE 类型的 ASRData 上抛到 Flutter,字段映射:
ASRData 字段
服务端 JSON 字段
id
sentence_id
res
sentence
speakerId
speaker_id
sentenceType
sentence_type
说明:
speaker_context_id(声纹 ID,24h 有效)暂未透传到 Flutter 层;如有多轮对话保持说话人 ID 连续的需求,可在原生桥接层扩展后通过setCustomParam回传下次任务。

ASRDataType

ASRData数据类型
enum ASRDataType {
SLICE,
SUCCESS,
NOTIFY,
}


ContextPrompt 和 PromptItem

用于临时热词和上下文功能,通过 ASRController.writeContent() 在识别过程中发送。

ContextPrompt
class ContextPrompt {
String? contextType; // 顶层 contextType(可选)
List<PromptItem>? prompt; // 结构化 prompt 列表
String? hotwordList; // 临时热词,格式同 hotword_list:"词|权重,词|权重"
}

PromptItem
class PromptItem {
String contextType; // 上下文类型,由业务自定,如 "scene"、"domain" 等
List<String> texts; // 该类型下的提示词文本列表
}

示例
final prompt = ContextPrompt(
hotwordList: "订金|11,语音识别|5",
contextType: "context",
prompt: [
PromptItem(contextType: "scene", texts: ["订金的胶带", "胶带反应"]),
PromptItem(contextType: "domain", texts: ["订金"]),
],
);
await _controller!.writeContent(prompt);


ASRError

识别过程中的错误

参数
int code; //错误码 iOS参考QCloudRealTimeClientErrCode Android参考ClientException
String message; //错误消息
String? resp; //服务端返回的原始数据


自定义数据源

SDK 只负责对输入的语音进行识别,不会进行额外的处理。但调用者可以通过自定义数据源来实现对录音数据的处理(降噪、回声消除等)来满足相应的场景需求。

自定义数据源需要数据以Stream<Uint8List>的方式传入到 SDK 且需要满足以下的要求:
采样数据格式仅支持单通道16000hz、16bit、小端的 pcm 数据流。
采样数据需要每隔40ms向stream推入1280B的数据且数据格式需要满足条件1。