iOS SDK

iOS SDK

更新时间:

本文介绍如何使用阿里云智能语音服务提供的iOS NUI SDK,包括SDK下载安装、关键接口及代码示例。

前提条件

下载安装

  1. 下载SDK和示例代码

    说明

    请下载后在样例初始化代码中替换您的阿里云账号信息、Appkey和Token才可运行。为方便集成,2.5.14版本后iOS接口使用纯Object-C接口,不再使用C++混合接口。

    类别

    兼容范围

    系统

    最低支持iOS9。

    架构

    arm64,x86_64

    此SDK还包含如下功能,若未支持您想要的功能,请前往对应文档获取SDK。

    功能

    是否支持

    一句话识别

    实时语音识别

    语音合成

    实时长文本语音合成

    离线语音合成

    录音文件识别极速版

    唤醒及命令词

  2. 解压ZIP包,将zip包中的nuisdk.framework添加到您的工程中,并在工程Build Phases的Link Binary With Libraries中添加nuisdk.framework。

  3. 使用Xcode打开此工程,工程中提供了参考代码以及一些直接可使用的工具类,例如音频播放录制和文件操作,您可以直接复制源码到您的实际工程进行使用。其中一句话识别示例代码为SpeechRecognizerViewController。替换Appkey和Token后可直接运行。

SDK关键接口

  • nui_initialize :初始化SDK。

    /**
     * 初始化SDK,SDK为单例,请先释放后再次进行初始化。请勿在UI线程调用,可能引起阻塞。
     * @param parameters: 初始化参数,参见接口说明文档
     * @param level: log打印级别,值越小打印越多
     * @param save_log: 是否保存log为文件,存储目录为parameter中的debug_path字段值
     * @return 参见错误码
    -(NuiResultCode) nui_initialize:(const char *)parameters
                           logLevel:(NuiSdkLogLevel)level
                            saveLog:(BOOL)save_log;
  • nui_set_params :以JSON格式设置SDK参数。

    /**
     * 以JSON格式设置参数
     * @param params: 参数信息请参见接口说明文档
     * @return 参见错误码
    -(NuiResultCode) nui_set_params:(const char *)params;
  • nui_dialog_start :开始识别。

    /**
     * 开始识别
     * @param vad_mode: 多种模式,对于识别场景,请使用P2T
     * @param dialog_params: 设置识别参数,可不设置
     * @return 参见错误码
    -(NuiResultCode) nui_dialog_start:(NuiVadMode)vad_mode
                          dialogParam:(const char *)dialog_params;
  • nui_dialog_cancel :结束识别。

    /**
     * 结束识别,调用该接口后,服务端将返回最终识别结果并结束任务
     * @param force: 是否强制结束而忽略最终结果,false或NO表示停止但是等待完整结果返回
     * @return 参见错误码
    -(NuiResultCode) nui_dialog_cancel:(BOOL)force;
  • nui_release :释放SDK。

    /**
     * 释放SDK资源
     * @return 参见错误码
    -(NuiResultCode) nui_release;

  • NeoNuiSdkDelegate: 事件代理

    onNuiEventCallback:SDK事件回调。

    /**
     * SDK主要事件回调
     * @param event: 回调事件,参见如下事件列表
     * @param dialog: 会话编号,暂不使用
     * @param wuw: 语音唤醒功能使用(暂不支持)
     * @param asr_result: 语音识别结果
     * @param finish: 本轮识别是否结束标志
     * @param resultCode: 参见错误码,在出现EVENT_ASR_ERROR事件时有效
    -(void) onNuiEventCallback:(NuiCallbackEvent)nuiEvent
                        dialog:(long)dialog
                     kwsResult:(const char *)wuw
                     asrResult:(const char *)asr_result
                      ifFinish:(BOOL)finish
                       retCode:(int)code;

    NuiCallbackEvent事件列表:

    名称

    说明

    EVENT_VAD_START

    检测到人声起点。

    EVENT_VAD_END

    检测到人声尾点。

    EVENT_ASR_PARTIAL_RESULT

    语音识别中间结果。

    EVENT_ASR_RESULT

    语音识别最终结果。

    EVENT_ASR_ERROR

    根据错误码信息判断出错原因。

    EVENT_MIC_EEROR

    录音错误,表示SDK连续2秒未收到任何音频,可检查录音系统是否正常。

    onNuiNeedAudioData:获取音频

    /**
     * 开始识别时,此回调被连续调用,App需要在回调中进行语音数据填充
     * @param audioData:  填充语音的存储区
     * @param len: 需要填充语音的字节数
     * @return 实际填充的字节数
    -(int) onNuiNeedAudioData:(char *)audioData length:(int)len;

    onNuiAudioStateChanged:根据音频状态进行录音功能的开关。

    /**
     * 当start/stop/cancel等接口调用时,SDK通过此回调通知App进行录音的开关操作
     * @param state:录音需要的状态(打开/关闭)
    -(void) onNuiAudioStateChanged:(NuiAudioState)state;

    onNuiRmsChanged:音频能量事件。

    /**
     * SDK主要事件回调
     * @param rms: 语音能量值,范围为-160至0
    -(void) onNuiRmsChanged:(float) rms;

调用步骤

  1. 初始化SDK、录音实例。

  2. 根据业务需求配置参数。

  3. 调用nui_dialog_start开始识别。

  4. 根据音频状态回调onNuiAudioStateChanged,打开录音机。

  5. 在onNuiNeedAudioData回调中提供录音数据。

  6. 在EVENT_ASR_PARTIAL_RESULT事件回调中获取识别结果。

  7. 调用nui_dialog_cancel结束识别。

  8. 结束调用,使用release接口释放SDK资源。

代码示例

说明

接口默认采用get_instance方式获得单例,您如果有多例需求,也可以直接alloc对象进行使用。

NUI SDK初始化

NSString * initParam = [self genInitParams];
[_nui nui_initialize:[initParam UTF8String] logLevel:LOG_LEVEL_VERBOSE saveLog:save_log];

其中,genInitParams生成为String JSON字符串,包含资源目录和用户信息。其中用户信息包含如下字段,获取方式请参见 接口说明

//账号和项目创建
//  ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
[dictM setObject:@"<您申请创建的app_key>" forKey:@"app_key"]; // 必填
//获取token方式:
//方法1:
//  首先ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
//  然后请看 https://help.aliyun.com/document_detail/466615.html 使用其中方案一获取临时凭证
//  此方案简介: 远端服务器使用以下方法获得有效时限的临时凭证, 下发给移动端进行使用, 保证账号信息ak_id和ak_secret不被泄露
//  获得Token方法(运行在APP服务端): https://help.aliyun.com/document_detail/450255.html?spm=a2c4g.72153.0.0.79176297EyBj4k
[dictM setObject:@"<服务器生成的具有时效性的临时凭证>" forKey:@"token"]; // 必填
//方法2:
//  STS获取临时凭证方法暂不支持
// 推荐填入具有唯一性的id, 方便定位问题
[dictM setObject:id_string forKey:@"device_id"]; // 必填

参数设置

以JSON字符串形式进行设置。

-(NSString*) genParams {
    NSMutableDictionary *nls_config = [NSMutableDictionary dictionary];
    [nls_config setValue:@YES forKey:@"enable_intermediate_result"];
    //参数可根据实际业务进行配置 https://help.aliyun.com/document_detail/173298.html?spm=a2c4g.173528.0.0.47f05398HEpSxW
    //  若要使用VAD模式,则需要设置nls_config参数启动在线VAD模式
    //[nls_config setValue:@YES forKey:@"enable_voice_detection"];
    //[nls_config setValue:@10000 forKey:@"max_start_silence"];
    //[nls_config setValue:@800 forKey:@"max_end_silence"];
    NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
    [dictM setObject:nls_config forKey:@"nls_config"];
    [dictM setValue:@(SERVICE_TYPE_ASR) forKey:@"service_type"]; // 必填
    NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
    NSString * jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    return jsonStr;
NSString * parameters = [self genParams];
[_nui nui_set_params:[parameters UTF8String]];

开始识别

通过nui_dialog_start接口开启监听。

//若要使用VAD模式,则需要设置nls_config参数启动在线VAD模式(见genParams())
[_nui nui_dialog_start:MODE_P2T dialogParam:[param_string UTF8String]];

回调处理

  • onNuiAudioStateChanged :录音状态回调,SDK内部维护录音状态,调用时根据该状态的回调进行录音机的开关操作。

    -(void)onNuiAudioStateChanged:(NuiAudioState)state{
        TLog(@"onNuiAudioStateChanged state=%u", state);
        if (state == STATE_CLOSE || state == STATE_PAUSE) {
            [_voiceRecorder stop:YES];
        } else if (state == STATE_OPEN){
            self.recordedVoiceData = [NSMutableData data];
            [_voiceRecorder start];
    }
  • onNuiNeedAudioData :录音数据回调,在该回调中填充录音数据。

    -(int)onNuiNeedAudioData:(char *)audioData length:(int)len {
        static int emptyCount = 0;
        @autoreleasepool {
            @synchronized(_recordedVoiceData){
                if (_recordedVoiceData.length > 0) {
                    int recorder_len = 0;
                    if (_recordedVoiceData.length > len)
                        recorder_len = len;
                        recorder_len = _recordedVoiceData.length;
                    NSData *tempData = [_recordedVoiceData subdataWithRange:NSMakeRange(0, recorder_len)];
                    [tempData getBytes:audioData length:recorder_len];
                    tempData = nil;
                    NSInteger remainLength = _recordedVoiceData.length - recorder_len;
                    NSRange range = NSMakeRange(recorder_len, remainLength);
                    [_recordedVoiceData setData:[_recordedVoiceData subdataWithRange:range]];
                    emptyCount = 0;
                    return recorder_len;
                } else {
                    if (emptyCount++ >= 50) {
                        TLog(@"_recordedVoiceData length = %lu! empty 50times.", (unsigned long)_recordedVoiceData.length);
                        emptyCount = 0;
                    return 0;
        return 0;
    }
  • onNuiEventCallback :NUI SDK事件回调,请勿在事件回调中调用SDK的接口,可能引起死锁。

    -(void)onNuiEventCallback:(NuiCallbackEvent)nuiEvent
                       dialog:(long)dialog
                    kwsResult:(const char *)wuw
                    asrResult:(const char *)asr_result
                     ifFinish:(bool)finish
                      retCode:(int)code {
        TLog(@"onNuiEventCallback event %d finish %d", nuiEvent, finish);
        if (nuiEvent == EVENT_ASR_PARTIAL_RESULT || nuiEvent == EVENT_ASR_RESULT) {
            TLog(@"ASR RESULT %s finish %d", asr_result, finish);
            NSString *result = [NSString stringWithUTF8String:asr_result];
            [myself showAsrResult:result];
        } else if (nuiEvent == EVENT_ASR_ERROR) {
            TLog(@"EVENT_ASR_ERROR error[%d]", code);
        } else if (nuiEvent == EVENT_MIC_ERROR) {
            TLog(@"MIC ERROR");
            [_voiceRecorder stop:YES];
            [_voiceRecorder start];
        if (finish) {
            [myself showStart];
        return;
    }

结束识别

[_nui nui_dialog_cancel:NO];

常见问题

iOS SDK使用一句话识别功能,集成nuisdk.framework,按照文档在工程Build Phases的Link Binary With Libraries中添加nuisdk.framework,在编译配置的General > Frameworks, Libraries, and Embedded Content中配置nuisdk.framework为Embed & Sign,但.m中仍提示找不到 nuisdk.framework/Headers/NeoNui.h如何解决?

请检查头文件#import <nuisdk/NeoNui.h>是否按照文档正常导入。

是否有Android和iOS的SDK,能否用在专有云环境下?

有SDK,在专有云安装包里默认不提供,可以通过阿里云帮助中心对应的服务文档中下载,如实时语音识别的 Android SDK iOS SDK 。移动端SDK可以调用公共云ASR、TTS服务,也可以用在专有云环境下。

iOS是否支持后台处理?

SDK本身不限制前后台,iOS SDK的样例工程默认仅支持前台处理,如果您需要支持后台处理,可以做如下修改:

  1. 在工程Info.list中添加 Required background modes 配置,并在该配置下添加 Item ,Value设置为 App plays audio or streams audio/video using AirPlay 配置1

  2. 在录音模块中进入后台时,不停止录音。亦即NLSVoiceRecorder.m中_appResignActive接口中不做停止录音调用。 配置2

下载语音交互iOS SDK至本地静态库,运行Demo程序测试代码时,模拟器可以正常运行,真机无法运行,报错“Reason: no suitable image found. Did find:xxx”如何解决?

建议您删除手机上对应的APP后,执行 xcode clean ,并重新尝试运行。除此以外,还需检查签名的正确性,如果签名不正确,需撤销原来的inHouse证书,重新制作新的证书和provisioning profile,并将代码重新签名,再次打包。

iOS端集成nuisdk运行报mic错误如何处理?

请检查当前录音设备是否被占用。

使用智能语音服务集成iOS SDK,接入nuisdk.framework后,导入头文件#import "nuisdk.framework/Headers/NeoNui.h"后项目报错如何解决?

一般情况下是SDK导入有问题导致,请您确认下图参数是否已勾选,如果已勾选,建议您将头文件导入方式换为 #import <nuisdk/NeoNui.h> ios导入头部文件失败

按照文档使用SDK接入后报错“/Users/admin/FlashTranscription_iOS/Fc_ASR.xcodeproj Building for iOS, but the linked and embedded framework 'nuisdk.framework' was built for iOS + iOS Simulator."”如何解决?

可能因为版本过高导致,建议您修改项目配置 Validate Workspace Yes 后,重新编译。 按照文档使用SDK接入后报错

使用集成语音服务iOS SDK,集成flutter_plugin时报错“Undefined symbols for architecture arm64: "std::__1::mutex::~mutex()", referenced from: ___cxx_global_var_init in libflutter_tts.a(ringBuf.o)”如何解决?

您可以打开iOS工程下的Podfile文件,修改 post_install do |installer| 部分的代码,再次执行构建即可成功。

集成语音服务报错

TRTC实时音视频和语音识别结合,当同时调用麦克风时可能会发生冲突,导致有一方没有声音如何解决?

建议尝试TRTC的音视频流,使用 localStream.getAudioTrack 获取 MediaStreamTrack 对象,并转换为符合ASR标准的音频流,然后通过语音识别SDK发起请求。

使用App集成iOS SDK,提交到App store失败,提示“Unsupported Architectures. The executable for AliYunSmart.app/Frameworks/nuisdk.framework contains unsupported architectures '[x86_ _64, i386]'. With error code”如何解决?

可能是模拟器架构影响,您可以参考如下方法查看framework版本并移除framework模拟器架构。

  1. 进入framework目录。

  2. 输入命令 lipo -info xxxFramework ,查看framework的架构版本,如果含有模拟器打包需要把模拟器架构移除。

使用集成语音服务iOS SDK,接入nuisdk.framework后报错,要修改Legacy Build system才可以运行,如何解决?

建议您修改项目配置 Validate Workspace Yes 后,重新编译。 按照文档使用SDK接入后报错