文档

Android SDK

更新时间:

本文介绍了如何使用阿里云离线语音合成服务提供的Android NUI SDK,包括下载安装SDK和语音包、SDK关键接口及代码示例。

前提条件

下载安装

  1. 下载SDK

    重要

    下载后在样例初始化代码中替换您的阿里云账号信息、Appkey才可运行。

    类别

    兼容范围

    系统

    支持Android 4.0 以上版本,API LEVEL 14

    架构

    armeabi-v7a,arm64-v8a,x86,x86_64

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

    功能

    是否支持

    一句话识别

    实时语音识别

    语音合成

    实时长文本语音合成

    离线语音合成

    录音文件识别极速版

    唤醒及命令词

  2. 下载语音包,详情请参见接口说明中的语音包列表。

    重要

    SDK和语音包是完全独立的,下载SDK后并不能直接使用,需要下载语音包,并设置语音包存放路径。

  3. 解压ZIP包,在app/libs目录下获取AAR格式的SDK包。

  4. 使用Android Studio打开此工程。其中语音合成示例代码为TtsLocalActivity.java文件。

SDK关键接口

  • tts_initialize:初始化SDK。

    /**
     * 初始化SDK,离线合成暂不支持多实例,请先释放后再次进行初始化。请勿在UI线程调用,可能会引起阻塞。
     * 初始化是耗时操作,不需要合成一个任务就进行该操作;在启动和退出时进行一次即可。
     * @param callback:事件监听回调,参见下文具体回调。
     * @param ticket:json string形式的初始化参数,参见下方说明或接口说明:https://help.aliyun.com/document_detail/204185.html。
     * @param level:log打印级别,值越小打印越多。
     * @param save_log:是否保存log为文件,存储目录为ticket中的debug_path字段值。
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int tts_initialize(INativeTtsCallback callback,
                                           String ticket,
                                           final Constants.LogLevel level,
                                           boolean save_log);

    INativeTtsCallback类型包含如下回调:

    • onTtsEventCallback:SDK事件回调。

      /**
       * 事件回调
       * @param event:回调事件,参见如下事件列表。
       * @param task_id:请求的任务ID。
       * @param ret_code:参见错误码,出现TTS_EVENT_ERROR事件时有效,可查阅https://help.aliyun.com/document_detail/459864.html。
       */
      void onTtsEventCallback(TtsEvent event, String task_id, int ret_code);

      事件列表:

      名称

      说明

      TTS_EVENT_START

      语音合成开始,准备播放。

      TTS_EVENT_END

      语音合成结束,合成数据已全部抛出,但并不表示播放结束。

      TTS_EVENT_CANCEL

      取消语音合成。

      TTS_EVENT_PAUSE

      语音合成暂停。

      TTS_EVENT_RESUME

      语音合成恢复。

      TTS_EVENT_ERROR

      语音合成发生错误。可通过getparamTts("error_msg")获得详细错误消息。

    • onTtsDataCallback:合成数据回调。

      /**
       * @param info:使用时间戳功能时,返回JSON格式的时间戳结果。
       * @param info_len:info字段的数据长度,暂不使用。
       * @param data:合成的音频数据,写入播放器。
       */
      void onTtsDataCallback(String info, int info_len, byte[] data);
  • setparamTts:设置参数。

    /**
     * 以键值对形式设置参数, 参见接口说明:https://help.aliyun.com/document_detail/204185.html
     * @param param:参数名,参见接口说明。
     * @param value:参数值,参见接口说明。
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int setparamTts(String param, String value);
  • getparamTts:获取参数。

    /**
     * 获取参数值
     * @param param:参数名,参考接口说明:https://help.aliyun.com/document_detail/204185.html。
     * @return:参数值。
     */
    public String getparamTts(String param);
  • startTts:开始合成。

    /**
     * 开始合成任务
     * @param priority:任务优先级,请使用"1"。
     * @param taskid:任务ID,可传入32个字节的uuid,或传入空内容由SDK自动生成。
     * @param text:播放的文本内容。
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int startTts(String priority, String taskid, String text);
  • cancelTts:取消合成。

    /**
     * 取消合成任务
     * @param taskid:传入想要停止的任务ID,如果为空则取消所有任务。
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int cancelTts(String taskid);
  • pauseTts:暂停合成。

    /**
     * 暂停合成任务
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int pauseTts();
  • resumeTts:恢复合成。

    /**
     * 恢复暂停的任务
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int resumeTts();
  • tts_release:释放SDK资源。

    /**
     * 释放SDK
     * @return:参见错误码:https://help.aliyun.com/document_detail/459864.html。
     */
    public synchronized int tts_release();

调用步骤

  1. 初始化SDK和播放组件。

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

  3. 调用startTts进行播放。

  4. 在合成数据回调中,将数据写入播放器进行播放,建议使用流式播放。

  5. 收到语音合成结束的回调。

代码示例

  1. 语音合成初始化。

    //设置默认目的地路径最下级目录名字
    //  比如设置当前 /data/user/0/mit.alibaba.nuidemo/files/asr_my
    //  未调用此接口, 则默认为 /data/user/0/mit.alibaba.nuidemo/files/asr_my
    CommonUtils.setTargetDataDir("asr_my");
    
    //这里获得资源路径, 即工作路径
    //  内部通过context.getApplicationContext().getFilesDir().toString() + "/asr_my" 创建工作路径,
    //  例如 /data/user/0/mit.alibaba.nuidemo/files/asr_my
    String workspace = CommonUtils.getModelPath(this);
    
    //从nuisdk.aar中assets资源拷贝到workspace中
    CommonUtils.copyTtsAssetsData(this);
    
    //SDK初始化
    NativeNui nui_tts_instance = new NativeNui(Constants.ModeType.MODE_TTS);
    int ret = nui_tts_instance.tts_initialize(new INativeTtsCallback() {}, genInitParams(workspace), Constants.LogLevel.LOG_LEVEL_VERBOSE, true);
    if (Constants.NuiResultCode.SUCCESS == ret) {
        // 初始化成功
    } else {
        // 初始化失败,通过“error_msg”查看详细错误信息,离线语音合成FAQ文档中已列出常见错误
        String errmsg =  nui_tts_instance.getparamTts("error_msg");
        Log.e(TAG, "init failed.errmsg:" + errmsg);
        // 初始化失败时直接返回,不用再调用合成或者参数设置接口
        return ret;
    }

    其中,genInitParams生成为String JSON字符串,包含资源目录和用户信息。其中用户信息包含如下字段。

    说明
    • 精品版sdk_code为software_nls_tts_offline

    • 普通版sdk_code为software_nls_tts_offline_standard

    private String genInitParams(String workpath) {
        File folder = new File(workpath);
        if (!folder.exists() && !folder.isDirectory()) {
            Log.e(TAG, "工作目录:" + workpath + " , 不存在, 会导致无法初始化");
            return null;
        }
    
        String str = "";
        try {
            // 需要特别注意:ak_id/ak_secret/app_key/sdk_code/device_id等参数必须传入SDK
            // 离线语音合成sdk_code取值:精品版为software_nls_tts_offline, 标准版为software_nls_tts_offline_standard
            // 鉴权信息获取参:https://help.aliyun.com/document_detail/69835.htm?spm=a2c4g.11186623.2.28.10b33069T2ydLk#topic-1917889
            JSONObject initObject = Auth.getTicket(); // 必填, 按照getTicket()说明进行设置
        
            initObject.put("workspace", workpath); // 必填
            // 设置为离线合成
            initObject.put("mode_type", "0"); // 必填
            str = initObject.toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return str;
    }
    
    public static JSONObject getTicket() {
        JSONObject object = new JSONObject();
    
        //郑重提示:
        //  您的账号信息ak_id和ak_secret一定不可存储在app代码中和移动端侧, 以防账号信息泄露。
        //  若使用离线功能(离线语音合成), 则必须ak_id、ak_secret、app_key
        //  若使用在线功能(语音合成、实时转写、一句话识别、录音文件转写), 则只需app_key和token(或sts_token)
    
        //账号和项目创建
        //  ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
        object.put("app_key", "<您申请创建的app_key>"); // 必填
    
        //请使用您的阿里云账号与appkey进行访问, 以下介绍两种方案(不限于两种)
        //方案一(强烈推荐):
        //  首先ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
        //  然后请看 https://help.aliyun.com/document_detail/466615.html 使用其中方案二使用STS获取临时账号
        //  此方案简介: 远端服务器运行STS生成具有有效时限的临时凭证, 下发给移动端进行使用, 保证账号信息ak_id和ak_secret不被泄露
        object.put("ak_id", "STS.<服务器生成的具有时效性的临时凭证>"); // 必填
        object.put("ak_secret", "<服务器生成的具有时效性的临时凭证>"); // 必填
        object.put("sts_token", "<服务器生成的具有时效性的临时凭证>"); // 必填,STS临时账户在离线功能时必须填写sts_token
    
        //方案二(泄露风险, 不推荐):
        //  首先ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
        //  此方案简介: 远端服务器存储账号信息, 加密下发给移动端进行使用, 但是仍然存在泄露风险。
        // object.put("ak_id", "<一定不可代码中存储和本地明文存储>"); // 必填
        // object.put("ak_secret", "<一定不可代码中存储和本地明文存储>"); // 必填
    
        // 特别说明: 鉴权所用的id是由以下device_id,与手机内部的一些唯一码进行组合加密生成的。
        //   更换手机或者更换device_id都会导致重新鉴权计费。
        //   此外, 以下device_id请设置有意义且具有唯一性的id, 比如用户账号(手机号、IMEI等),
        //   传入相同或随机变换的device_id会导致鉴权失败或重复收费。
        //   Utils.getDeviceId() 并不能保证生成不变的device_id,请不要使用
        object.put("device_id", "empty_device_id"); // 必填
    
        // 离线语音合成sdk_code取值:精品版为software_nls_tts_offline, 标准版为software_nls_tts_offline_standard
        // 离线语音合成账户和sdk_code可用于唤醒
        object.put("sdk_code", "software_nls_tts_offline_standard"); // 必填
    
        return object;
    }
  2. 根据需求设置参数。

    //设置本地发音人,如下载的aicheng语音包放在目录/sdcard/idst/目录下,那么命令为”/sdcard/idst/aicheng“
    //  语音包和SDK是隔离的,需要先设置语音包
    //  如果切换发音人:SDK可使用语音包与鉴权账号相关,由购买时获得的语音包使用权限决定
    //  如已经购买aijia,按下边方式调用后,发音人将切为aijia
    //  语音包下载地址:https://help.aliyun.com/document_detail/204185.html?spm=a2c4g.11186623.6.628.3cde73409gZCmA
    //  语音包试听:https://www.aliyun.com/activity/intelligent/offline_tts?spm=5176.12061040.J_5715429470.2.42c33871uFGa5s
    //  特别说明:离线语音合成的发音人, 并不一定也存在于在线语音合成;同理, 在线语音合成的发音人, 并不一定也存在于离线语音合成
    
    //aar中的资源目录中自带了一个发音人aijia, /data/user/0/mit.alibaba.nuidemo/files/asr_my/tts/voices/aijia
    String fullName = workspace + "/tts/voices/" + mFontName;
    
    //切换发音人:一定要输入全路径名称
    Log.i(TAG, "use extend_font_name:" + fullName);
    ret = nui_tts_instance.setparamTts("extend_font_name", fullName);
    if (ret != Constants.NuiResultCode.SUCCESS) {
        Log.e(TAG, "setparamTts extend_font_name " + fullName + " failed, ret:" + ret);
        String errmsg =  nui_tts_instance.getparamTts("error_msg");
        return ret;
    }
  3. 启动语音合成。

    nui_tts_instance.startTts("1", "", ttsText);
  4. 回调处理。

    • onTtsEventCallback:语音合成事件回调,根据语音合成状态控制播放器。

      public void onTtsEventCallback(INativeTtsCallback.TtsEvent event) {
          Log.i(TAG, "tts event:" + event);
          if (event == INativeTtsCallback.TtsEvent.TTS_EVENT_START) {
              Log.i(TAG, "eventStart");
              // 打开播放器
              mAudioTrack.play();
          } else if (event == INativeTtsCallback.TtsEvent.TTS_EVENT_END || event == TtsEvent.TTS_EVENT_CANCEL || event == TtsEvent.TTS_EVENT_ERROR) {
              // 提示: TTS_EVENT_END事件表示TTS已经合成完并通过回调传回了所有音频数据, 而不是表示播放器已经播放完了所有音频数据。
              Log.i(TAG, "eventEnd");
      
              // 表示推送完数据, 当播放器播放结束则会有playOver回调
              mAudioTrack.isFinishSend(true);
      
              if (event == TtsEvent.TTS_EVENT_ERROR) {
                  // 通过此接口获得详细的错误信息
                  String error_msg = nui_tts_instance.getparamTts("error_msg");
                  Log.e(TAG, "TTS_EVENT_ERROR error_code:" + ret_code + " errmsg:" + error_msg);
              }
          } else if (event == TtsEvent.TTS_EVENT_PAUSE) {
              // 暂停播放器
              mAudioTrack.pause();
              Log.i(TAG, "eventPause");
          } else if (event == TtsEvent.TTS_EVENT_RESUME) {
              // 重启播放器
              mAudioTrack.play();
          }
      }
    • onTtsDataCallback:语音合成数据回调,将回调中的合成数据写入播放器进行播放。

      public void onTtsDataCallback(String info, int info_len, byte[] data) {
          if (info.length() > 0) {
              Log.i(TAG, "info: " + info);
          }
          if (data.length > 0) {
              mAudioTrack.setAudioData(data);
              Log.i(TAG, "write:" + data.length);
          }
      }
  5. 取消语音合成。

    nui_tts_instance.cancelTts("");
  6. 退出语音合成。

    nui_tts_instance.tts_release();

常见问题

使用离线语音合成Android SDK,语音播报时出现不合理断句,该如何处理?

您可以通过SSML标记语言尝试解决。

调用Android SDK时,手机报错提示“audio recoder not init”。

您可以通过以下方式排查:

  • 检查AudioRecord是否初始化正常。

  • 检查语音播放器是否有问题。

  • 编写AudioRecord录音代码,测试是否正常。

在模拟器上运行下载的Android程序,程序出现闪退现象,是什么原因?

模拟器可能会出现未知问题,建议您使用真机测试。

int ret = nui_instance.initialize(this, genInitParams(assets_path,debug_path), Constants.LogLevel.LOG_LEVEL_VERBOSE, true)。在该段代码中,录音权限是打开的,但代码仍然报错240021。

表示FILE_ACCESS_FAIL文件访问错误。你需要检查:

  • 是否有文件读写权限。

  • 是否完成SDK配置文件的拷贝,检查是否拷贝完成的代码示例如下:

if (CommonUtils.copyAssetsData(this)) {
Log.i(TAG, "copy assets data done");
} else {
Log.i(TAG, "copy assets failed");
return;
}

  • 本页导读 (1)
文档反馈