1. 接入准备
1.1 SDK 获取
1.2 接入须知
开发者在调用前请先查看实时语音识别的 接口说明,了解接口的使用要求和使用步骤。
该接口需要手机能够连接网络(GPRS、3G 或 Wi-Fi 网络等),且系统为 iOS 9.0 及以上版本。
运行 Demo 必须设置 AppID、SecretID、SecretKey,可在 API 密钥管理 中获取。
1.3 SDK 导入
1. 下载并解压 iOS SDK 压缩包,压缩包中包含 Demo 和 SDK, 其中QCloudRealTime.xcframework为实时语音识别framework包;VoiceCommon.framework为语音SDK公共组件framework包
2. XcodeFile > Add Files to "Your Project",在弹出 Panel 选中所下载SDK包QCloudRealTime.xcframework和VoiceCommon.framework > Add(选中"Copy items if needed")。
1.4 工程配置
在工程的 info.plist 中申请系统麦克风权限,添加如下内容:
<key>NSMicrophoneUsageDescription</key><string>需要使用您的麦克风采集音频</string>
在工程中添加依赖库,在 Build Phases Link Binary With Libraries 中添加以下库:
QCloudRealTime.xcframework
libc++.tbd
AVFoundation.framework
AudioToolbox.framework
VoiceCommon.framework
2. 快速接入
2.1 开发流程及接入示例
话者分离版 SDK 通过 WebSocket 实时识别音频,并将服务端返回的原始 JSON 透传给开发者,由开发者自行解析话者分离结果。
2.1.1 使用内置录音器采集语音识别示例
1. 引入SDK 的头文件
#import <QCloudRealTime/QCloudRealTimeRecognizer.h>#import <QCloudRealTime/QCloudConfig.h>#import <QCloudRealTime/QCloudRealTimeResult.h>#import <QCloudRealTime/QCloudAudioDataSource.h>
2. 创建 QCloudConfig 实例
//1.创建 QCloudConfig 实例QCloudConfig *config = [[QCloudConfig alloc] initWithAppId:kQDAppIdsecretId:kQDSecretIdsecretKey:kQDSecretKeyprojectId:0];// 以下为可选配置参数config.requestTimeout = 10; // 请求超时时间(秒)// config.sliceTime = 40; // 语音分片时长默认40ms(无特殊需求不建议更改)config.enableDetectVolume = YES; // 是否检测音量config.endRecognizeWhenDetectSilence = YES; // 是否检测到静音停止识别config.shouldSaveAsFile = YES; // 仅限使用SDK内置录音器有效,是否保存录音文件到本地 默认关闭config.saveFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"recordaudio.wav"]; // 开启shouldSaveAsFile后音频保存的路径,仅限使用SDK内置录音器有效,默认路径为[NSTemporaryDirectory() stringByAppendingPathComponent:@"recordaudio.wav"]// 以下为API参数配置,参数描述见API文档:https://cloud.tencent.com/document/product/1093/48982config.engineType = @"16k_zh_en_speaker"; // 话者分离版必须使用此引擎config.filterDirty = 0; // 是否过滤脏词,具体的取值见API文档的filter_dirty参数config.filterModal = 0; // 过滤语气词,具体的取值见API文档的filter_modal参数config.filterPunc = 0; // 过滤句末的句号,具体的取值见API文档的filter_punc参数config.convertNumMode = 1; // 是否进行阿拉伯数字智能转换。具体的取值见API文档的convert_num_mode参数// config.hotwordId = @""; // 热词id。具体的取值见API文档的hotword_id参数// config.customizationId = @""; // 自学习模型id,详情见API文档// config.vadSilenceTime = -1; // 语音断句检测阈值,详情见API文档config.needvad = 1; // 默认1 0:关闭 vad,1:开启 vad。如果语音分片长度超过60秒,用户需开启 vad。config.wordInfo = 0; // 是否显示词级别时间戳。详情见API文档config.reinforceHotword = 0; // 热词增强功能 0:关闭,1:开启 默认0config.noiseThreshold = 0; // 噪音参数阈值,默认为0,取值范围:[-1,1]
3. 创建 QCloudRealTimeRecognizer 实例
QCloudRealTimeRecognizer *recognizer = [[QCloudRealTimeRecognizer alloc] initWithConfig:config];
4. 设置 delegate,实现 QCloudRealTimeRecognizerDelegate 方法
recognizer.delegate = self;
5. 开始识别
//使用内置录音器前需要先设置AVAudioSession状态为可录音的模式NSError *error = nil;[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:&error];if (error) {//错误处理}[[AVAudioSession sharedInstance] setActive:YES error:nil];//启动识别[recognizer start];
6. 结束识别
[recognizer stop];
2.1.2 调用者提供语音数据示例
1. 引入 SDK 的头文件
#import <QCloudRealTime/QCloudRealTimeRecognizer.h>#import <QCloudRealTime/QCloudConfig.h>#import <QCloudRealTime/QCloudRealTimeResult.h>#import <QCloudRealTime/QCloudAudioDataSource.h>
2. 创建 QCloudConfig 实例
//1.创建 QCloudConfig 实例QCloudConfig *config = [[QCloudConfig alloc] initWithAppId:kQDAppIdsecretId:kQDSecretIdsecretKey:kQDSecretKeyprojectId:0];// 以下为可选配置参数config.requestTimeout = 10; // 请求超时时间(秒)// config.sliceTime = 40; // 语音分片时长默认40ms(无特殊需求不建议更改)config.enableDetectVolume = YES; // 是否检测音量config.endRecognizeWhenDetectSilence = YES; // 是否检测静音,默认YESconfig.silenceDetectDuration = 3.0; // 最大静音时间阈值,单位:秒config.endRecognizeWhenDetectSilenceAutoStop = YES; // 是否检测到静音停止识别,默认YES// 以下为API参数配置,参数描述见API文档:https://cloud.tencent.com/document/product/1093/131127config.engineType = @"16k_zh_en_speaker"; // 话者分离版兜底使用此引擎,详情见API文档config.filterDirty = 0; // 是否过滤脏词,具体的取值见API文档的filter_dirty参数config.filterModal = 0; // 过滤语气词,具体的取值见API文档的filter_modal参数config.filterPunc = 0; // 过滤句末的句号,具体的取值见API文档的filter_punc参数config.convertNumMode = 1; // 是否进行阿拉伯数字智能转换。具体的取值见API文档的convert_num_mode参数// config.hotwordId = @""; // 热词id。具体的取值见API文档的hotword_id参数// config.customizationId = @""; // 自学习模型id,详情见API文档// config.vadSilenceTime = -1; // 语音断句检测阈值,详情见API文档config.needvad = 1; // 默认1 0:关闭 vad,1:开启 vad。如果语音分片长度超过60秒,用户需开启 vad。config.wordInfo = 0; // 是否显示词级别时间戳,详情见API文档config.noiseThreshold = 0; // 噪音参数阈值,默认为0,取值范围:[-1,1],详情见API文档// [config setApiParam:@"custom_param" value:@"value"]; // 设置自定义请求参数,用于在请求中添加SDK尚未支持的参数
3. 自定义 QCloudDemoAudioDataSource,QCloudDemoAudioDataSource 实现 QCloudAudioDataSource 协议
// QCloudDemoAudioDataSource 具体源代码详见 SDK demo 目录QCloudDemoAudioDataSource *dataSource = [[QCloudDemoAudioDataSource alloc] init];
4. 创建 QCloudRealTimeRecognizer 实例
QCloudRealTimeRecognizer *recognizer = [[QCloudRealTimeRecognizer alloc] initWithConfig:config dataSource:dataSource];
5. 设置 delegate,实现 QCloudRealTimeRecognizerDelegate 方法
recognizer.delegate = self;
6. 开始识别
[recognizer start];
7. 结束识别
[recognizer stop];
2.2 主要接口类说明
2.2.1 QCloudRealTimeRecognizer 初始化说明
QCloudRealTimeRecognizer 是实时语音识别类,提供两种初始化方法。
/*** 初始化方法,调用者使用内置录音器采集音频* @param config 配置参数,详见QCloudConfig定义*/- (instancetype)initWithConfig:(QCloudConfig *)config;/*** 初始化方法,调用者传递语音数据调用此初始化方法* @param config 配置参数,详见QCloudConfig定义* @param dataSource 语音数据数据源,必须实现QCloudAudioDataSource协议*/- (instancetype)initWithConfig:(QCloudConfig *)config dataSource:(id<QCloudAudioDataSource>)dataSource;
2.2.2 QCloudConfig 初始化方法说明
/*** 初始化方法-直接鉴权* @param appid 腾讯云 appId* @param secretId 腾讯云 secretId* @param secretKey 腾讯云 secretKey* @param projectId 腾讯云 projectId*/- (instancetype)initWithAppId:(NSString *)appidsecretId:(NSString *)secretIdsecretKey:(NSString *)secretKeyprojectId:(NSString *)projectId;/*** 初始化方法-通过STS临时证书鉴权,详见https://cloud.tencent.com/document/product/598/33416* @param appid 腾讯云appId* @param secretId 腾讯云临时secretId* @param secretKey 腾讯云临时secretKey* @param token 对应的token*/- (instancetype)initWithAppId:(NSString *)appidsecretId:(NSString *)secretIdsecretKey:(NSString *)secretKeytoken:(NSString *)token;
2.2.3 获取SDK版本号接口说明
/*** 获取SDK版本号*/+ (NSString*) getVersion;
2.2.4 话者分离 JSON 响应格式
话者分离版 SDK 的核心差异:服务端返回的 JSON 数据通过
realTimeRecognizerOnRawResult:jsonData: 回调原始透传,开发者自行解析。{"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..."}
字段说明:
字段 | 类型 | 说明 |
sentence_id | int | 句子 ID,从 0 开始递增 |
sentence_type | int | 0=中间态(非稳态),1=稳态(最终确定结果) |
speaker_id | int | 说话人 ID:**-1**=未确定,0~9=对应说话人 |
sentence | string | 当前句子的识别文本 |
voice_text_str | string | 完整语音流的识别文本汇总 |
speaker_context_id | string | 声纹 ID,24h 有效。下次识别传入可保持说话人 ID 连续性 |
说明:
兼容旧版
result.speaker_sentences 格式,建议优先使用新版 sentences.sentence_list。2.2.5 QCloudRealTimeRecognizerDelegate 方法说明
@protocol QCloudRealTimeRecognizerDelegate <NSObject>@required/*** 原始 JSON 数据回调* 话者分离版 SDK 通过此回调透传服务端返回的原始 JSON,开发者自行解析话者分离结果* @param recognizer 实时语音识别实例* @param jsonData 服务端返回的 JSON 字符串*/- (void)realTimeRecognizerOnRawResult:(QCloudRealTimeRecognizer *)recognizer jsonData:(NSString *)jsonData;@optional/*** 一次识别成功回调@param recognizer 实时语音识别实例@param result 一次识别出的总文本, 实际是由SDK本地处理,将本次识别的realTimeRecognizerOnSegmentSuccessRecognize 识别结果拼接后一次性返回*/- (void)realTimeRecognizerDidFinish:(QCloudRealTimeRecognizer *)recognizer result:(NSString *)result;/*** 一次识别失败回调* @param recognizer 实时语音识别实例* @param result 识别结果信息,错误信息详情看QCloudRealTimeResponse内错误码*/- (void)realTimeRecognizerDidError:(QCloudRealTimeRecognizer *)recognizer result:(QCloudRealTimeResult *)result;/*** 开始录音回调* @param recognizer 实时语音识别实例* @param error 开启录音失败,错误信息*/- (void)realTimeRecognizerDidStartRecord:(QCloudRealTimeRecognizer *)recognizer error:(NSError *)error;/*** 结束录音回调* @param recognizer 实时语音识别实例*/- (void)realTimeRecognizerDidStopRecord:(QCloudRealTimeRecognizer *)recognizer;/*** 录音音量实时回调用* @param recognizer 实时语音识别实例* @param volume 声音音量,取值范围(-40-0)*/- (void)realTimeRecognizerDidUpdateVolume:(QCloudRealTimeRecognizer *)recognizer volume:(float)volume;/*** 录音音量实时回调用* @param recognizer 实时语音识别实例* @param volume 声音音量,计算方式如下$A_{i}$为采集音频振幅值* $$A_{mean} = \\frac{1}{n} \\sum_{i=1}^{n} A_{i}^{2}$$* $$volume=\\max (10*\\log_{10}(A_{mean}), 0)$$*/- (void)realTimeRecognizerDidUpdateVolumeDB:(QCloudRealTimeRecognizer *)recognizer volume:(float)volume;/*** 语音流的开始识别* @param recognizer 实时语音识别实例* @param voiceId 语音流对应的voiceId,唯一标识* @param seq flow的序列号*/- (void)realTimeRecognizerOnFlowRecognizeStart:(QCloudRealTimeRecognizer *)recognizer voiceId:(NSString *)voiceId seq:(NSInteger)seq;/*** 语音流的结束识别* @param recognizer 实时语音识别实例* @param voiceId 语音流对应的voiceId,唯一标识* @param seq flow的序列号*/- (void)realTimeRecognizerOnFlowRecognizeEnd:(QCloudRealTimeRecognizer *)recognizer voiceId:(NSString *)voiceId seq:(NSInteger)seq;/*** 触发静音事件时回调*/-(void)realTimeRecognizerOnSliceDetectTimeOut;/*** 录音停止后回调一次,再次开始录音会清空上一次保存的文件* @param recognizer 实时语音识别实例* @param audioFilePath 音频文件路径*/- (void)realTimeRecognizerDidSaveAudioDataAsFile:(QCloudRealTimeRecognizer *)recognizeraudioFilePath:(NSString *)audioFilePath;@end
2.2.6 QCloudAudioDataSource 协议说明
调用者不使用 SDK 内置录音器进行语音数据采集,自己提供语音数据需要实现此协议所有方法,可见 Demo 工程中的 QDAudioDataSource 实现。
/*** 语音数据数据源,如果调用者需要自己提供语音数据需要, 调用者实现此协议中所有方法* 提供符合以下要求的语音数据:* 采样率:16k* 音频格式:pcm* 编码:16bit位深的单声道*/@protocol QCloudAudioDataSource <NSObject>@required/*** 标识data source是否开始工作,执行完start后需要设置成YES, 执行完stop后需要设置成NO*/@property (nonatomic, assign) BOOL running;@property (nonatomic, copy, readonly) NSString *audioFilePath;/*** 标识QCloudAudioRecorder是否正在录音*/@property (nonatomic, assign, readonly) BOOL recording;/*** SDK会调用start方法,实现此协议的类需要初始化数据源。didStart 是否开始 YES 往下执行,NO不会往下执行*/- (void)start:(void(^)(BOOL didStart, NSError *error))completion;/*** SDK会调用stop方法,实现此协议的类需要停止提供数据*/- (void)stop;/*** SDK会调用实现此协议的对象的此方法读取语音数据, 如果语音数据不足expectLength,read线程进入休眠。* @param expectLength 期望读取的字节数,如果返回的NSData不足expectLength个字节,SDK会抛出异常。*/- (nullable NSData *)readData:(NSInteger)expectLength;@end
2.2.7 QCloudVoiceLogger 日志设置说明
// 设置log等级为DEBUG级,上生产环境可选择VOICE_SDK_ERROR_LEVEL级别的log[QCloudVoiceLogger setLoggerLevel:VOICE_SDK_DEBUG_LEVEL];// 将log写入本地磁盘,demo工程默认打开,宿主层接入上生产环境需要关闭。[QCloudVoiceLogger needLogFile:YES];// (可选)注册log回调[QCloudVoiceLogger registerLoggerListener:^(VoiceLoggerLevel loggerLevel, NSString * _Nonnull logInfo) {NSLog(@"[ASR]-%@",logInfo);} withNativeLog:NO];
3. 常见问题指引
3.1 回音消除指引
本小节主要介绍如何通过 iOS 原生 API 实现回音消除,下面将介绍实现方案(完整代码参考 Demo工程中的 QCloudAECDataSource 类的实现方法)。
3.1.1 回声消除方案介绍
1. 设置AVAudioSession支持边播放边录音的模式
AVAudioSession* session = [AVAudioSession sharedInstance];[session setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
2. 通过AVAudioEngine添加播放节点构建音频处理图
self.engine = [[AVAudioEngine alloc] init];self.play_node = [[AVAudioPlayerNode alloc] init];[self.engine attachNode:self.play_node];[self.engine connect:self.play_node to:self.engine.outputNode format:nil];
3. 通过调用输入节点的setVoiceProcessingEnabled开启回声消除
[self.engine.inputNode setVoiceProcessingEnabled:YES error:&error];
4. 启动音频处理图
[self.engine startAndReturnError:&error];
3.1.2 回声消除方案适配的机型列表
1. 回声消除要求系统版本不低于iOS 13.0
2. 回声消除适配还会受到机型及系统的影响,以下列举已测试机型和系统的适配情况
机型 | 系统 | 适配 | 备注 |
iPhone 11 Pro | 13.4 | 否 | 回声消除导致播放音量变化 |
iPhone 11 Pro Max | 14.4.2 | 否 | 回声消除导致播放音量变化 |
iPhone 12 | 14.1 | 否 | 回声消除导致播放音量变化 |
iPhone 12 Pro | 14.1 | 否 | 回声消除导致播放音量变化 |
iPhone 6s Plus | 15.1 | 否 | 回声消除导致播放音量变化 |
iPhone 8 Plus | 14.0.1 | 否 | 回声消除导致播放音量变化 |
iPhone SE2 | 17.0(beta5) | 否 | 回声消除导致播放音量变化 |
iPhone X | 15 | 否 | 回声消除导致播放音量变化 |
iPhone XR | 16.6 | 否 | 回声消除导致播放音量变化 |
iPhone XS Max | 14.2 | 否 | 回声消除导致播放音量变化 |
iPhone 12 mini | 14.1 | 否 | 回声消除不生效 |
iPhone 13 mini | 15 | 否 | 回声消除不生效 |
iPhone 14 | 16 | 否 | 回声消除不生效 |
iPhone 14 Plus | 16.0.2 | 否 | 回声消除不生效 |
iPhone 14 Pro | 16 | 否 | 回声消除不生效 |
iPhone 14 Pro Max | 16 | 否 | 回声消除不生效 |
iPhone 11 | 16.1.1 | 是 | - |
iPhone 12 Pro Max | 16.3.1 | 是 | - |
iPhone 13 | 15.0.1 | 是 | - |
iPhone 13 Pro | 15.0.2 | 是 | - |
iPhone 13 Pro Max | 15.0.2 | 是 | - |
iPhone SE3 | 15.4 | 是 | - |
iPhone XS | 14.4 | 是 | - |
3.2 话者分离版常见问题
3.2.1 speaker_context_id 的作用?
speaker_context_id 是服务端返回的声纹 ID(24h 内有效)。将上次返回的 ID 通过 setApiParam:value: 传入下次识别任务,可使同一说话人的 ID 保持连续,适用于多轮对话场景。3.2.2 sentence_type=0 和 sentence_type=1 的区别?
sentence_type=0:中间态(非稳态),可能被后续结果修正,建议实时显示时使用灰色样式。sentence_type=1:确定态(稳态),不会再改变,适合最终展示。3.2.3 cancel 与 stop 的区别?
stop:自然结束当前识别任务,等待服务端返回最终结果后再关闭连接。cancel:立即终止识别,不等待服务端返回任何结果,直接关闭 WebSocket 连接。