2019-08-07Android 集成科大飞讯的语音合成

在项目中新建Application,在Application中配置项目对应appid和模式,如下图所示。

具体实现逻辑如下图。
package com.lcj.kdf;

import android.annotation.SuppressLint;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.SharedPreferences;

import android.os.Bundle;

import android.os.Environment;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.Window;

import android.widget.EditText;

import android.widget.RadioGroup;

import android.widget.RadioGroup.OnCheckedChangeListener;

import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;

import com.iflytek.cloud.InitListener;

import com.iflytek.cloud.SpeechConstant;

import com.iflytek.cloud.SpeechError;

import com.iflytek.cloud.SpeechSynthesizer;

import com.iflytek.cloud.SynthesizerListener;

import com.iflytek.cloud.util.ResourceUtil;

import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE;

public class TtsDemoextends Activityimplements OnClickListener {

private static StringTAG = TtsDemo.class.getSimpleName();

// 语音合成对象

  private SpeechSynthesizermTts;

// 默认云端发音人

  public static StringvoicerCloud="xiaoyan";

// 默认本地发音人

  public static StringvoicerLocal="xiaoyan";

// 云端发音人列表

  private String[]cloudVoicersEntries;

private String[]cloudVoicersValue ;

// 本地发音人列表

  private String[]localVoicersEntries;

private String[]localVoicersValue ;

//缓冲进度

  private int mPercentForBuffering =0;

//播放进度

  private int mPercentForPlaying =0;

// 云端/本地选择按钮

  private RadioGroupmRadioGroup;

// 引擎类型

  private StringmEngineType = SpeechConstant.TYPE_CLOUD;

private ToastmToast;

private SharedPreferencesmSharedPreferences;

@SuppressLint("ShowToast")

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

this.requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.ttsdemo);

initLayout();

// 初始化合成对象

      mTts = SpeechSynthesizer.createSynthesizer(this,mTtsInitListener);

// 云端发音人名称列表

      cloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries);

cloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values);

// 本地发音人名称列表

      localVoicersEntries = getResources().getStringArray(R.array.voicer_local_entries);

localVoicersValue = getResources().getStringArray(R.array.voicer_local_values);

mSharedPreferences = getSharedPreferences(TtsSettings.PREFER_NAME, Activity.MODE_PRIVATE);

mToast = Toast.makeText(this,"", Toast.LENGTH_SHORT);

}

/**

* 初始化Layout。

*/

  private void initLayout() {

findViewById(R.id.tts_play).setOnClickListener(this);

findViewById(R.id.tts_cancel).setOnClickListener(this);

findViewById(R.id.tts_pause).setOnClickListener(this);

findViewById(R.id.tts_resume).setOnClickListener(this);

findViewById(R.id.image_tts_set).setOnClickListener(this);

findViewById(R.id.tts_btn_person_select).setOnClickListener(this);

mRadioGroup=((RadioGroup) findViewById(R.id.tts_rediogroup));

mRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override

        public void onCheckedChanged(RadioGroup group,int checkedId) {

switch (checkedId) {

case R.id.tts_radioCloud:

mEngineType = SpeechConstant.TYPE_CLOUD;

break;

case R.id.tts_radioLocal:

mEngineType =  SpeechConstant.TYPE_LOCAL;

break;

default:

break;

}

}

} );

}

@Override

  public void onClick(View view) {

if(null ==mTts ){

// 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688

        this.showTip("创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化" );

return;

}

switch(view.getId()) {

case R.id.image_tts_set:

Intent intent =new Intent(TtsDemo.this, TtsSettings.class);

startActivity(intent);

break;

// 开始合成

// 收到onCompleted 回调时,合成结束、生成合成音频

// 合成的音频格式:只支持pcm格式

      case R.id.tts_play:

String text = ((EditText) findViewById(R.id.tts_text)).getText().toString();

// 设置参数

        setParam();

int code =mTts.startSpeaking(text,mTtsListener);

if (code != ErrorCode.SUCCESS) {

showTip("语音合成失败,错误码: " + code+",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");

}

break;

// 取消合成

      case R.id.tts_cancel:

mTts.stopSpeaking();

break;

// 暂停播放

      case R.id.tts_pause:

mTts.pauseSpeaking();

break;

// 继续播放

      case R.id.tts_resume:

mTts.resumeSpeaking();

break;

// 选择发音人

      case R.id.tts_btn_person_select:

showPresonSelectDialog();

break;

}

}

private static int selectedNumCloud=0;

private static int selectedNumLocal=0;

/**

* 发音人选择。

*/

  private void showPresonSelectDialog() {

switch (mRadioGroup.getCheckedRadioButtonId()) {

// 选择在线合成

      case R.id.tts_radioCloud:

new AlertDialog.Builder(this).setTitle("在线合成发音人选项")

.setSingleChoiceItems(cloudVoicersEntries,// 单选框有几项,各是什么名字

              selectedNumCloud,// 默认的选项

              new DialogInterface.OnClickListener() {// 点击单选框后的处理

            public void onClick(DialogInterface dialog,

int which) {// 点击了哪一项

              voicerCloud =cloudVoicersValue[which];

if ("catherine".equals(voicerCloud) ||"henry".equals(voicerCloud) ||"vimary".equals(voicerCloud)) {

((EditText) findViewById(R.id.tts_text)).setText(R.string.text_tts_source_en);

}else {

((EditText) findViewById(R.id.tts_text)).setText(R.string.text_tts_source);

}

selectedNumCloud = which;

dialog.dismiss();

}

}).show();

break;

// 选择本地合成

      case R.id.tts_radioLocal:

new AlertDialog.Builder(this).setTitle("本地合成发音人选项")

.setSingleChoiceItems(localVoicersEntries,// 单选框有几项,各是什么名字

              selectedNumLocal,// 默认的选项

              new DialogInterface.OnClickListener() {// 点击单选框后的处理

            public void onClick(DialogInterface dialog,

int which) {// 点击了哪一项

              voicerLocal =localVoicersValue[which];

if ("catherine".equals(voicerLocal) ||"henry".equals(voicerLocal) ||"vimary".equals(voicerLocal)) {

((EditText) findViewById(R.id.tts_text)).setText(R.string.text_tts_source_en);

}else {

((EditText) findViewById(R.id.tts_text)).setText(R.string.text_tts_source);

}

selectedNumLocal = which;

dialog.dismiss();

}

}).show();

break;

default:

break;

}

}

/**

* 初始化监听。

*/

  private InitListenermTtsInitListener =new InitListener() {

@Override

      public void onInit(int code) {

Log.d(TAG,"InitListener init() code = " + code);

if (code != ErrorCode.SUCCESS) {

showTip("初始化失败,错误码:"+code+",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");

}else {

// 初始化成功,之后可以调用startSpeaking方法

// 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成,

// 正确的做法是将onCreate中的startSpeaking调用移至这里

        }

}

};

/**

* 合成回调监听。

*/

  private SynthesizerListenermTtsListener =new SynthesizerListener() {

@Override

      public void onSpeakBegin() {

showTip("开始播放");

}

@Override

      public void onSpeakPaused() {

showTip("暂停播放");

}

@Override

      public void onSpeakResumed() {

showTip("继续播放");

}

@Override

      public void onBufferProgress(int percent,int beginPos,int endPos,

String info) {

// 合成进度

        mPercentForBuffering = percent;

showTip(String.format(getString(R.string.tts_toast_format),

mPercentForBuffering,mPercentForPlaying));

}

@Override

      public void onSpeakProgress(int percent,int beginPos,int endPos) {

// 播放进度

        mPercentForPlaying = percent;

showTip(String.format(getString(R.string.tts_toast_format),

mPercentForBuffering,mPercentForPlaying));

}

@Override

      public void onCompleted(SpeechError error) {

if (error ==null) {

showTip("播放完成");

}else if (error !=null) {

showTip(error.getPlainDescription(true));

}

}

@Override

      public void onEvent(int eventType,int arg1,int arg2, Bundle obj) {

// 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因

// 若使用本地能力,会话id为null

// if (SpeechEvent.EVENT_SESSION_ID == eventType) {

//    String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);

//    Log.d(TAG, "session id =" + sid);

// }

//实时音频流输出参考

/*if (SpeechEvent.EVENT_TTS_BUFFER == eventType) {

byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER);

Log.e("MscSpeechLog", "buf is =" + buf);

}*/

      }

};

private void showTip(final String str){

runOnUiThread(new Runnable() {

@Override

        public void run() {

mToast.setText(str);

mToast.show();

}

});

}

/**

* "engine_type = local, text_encoding = UTF8, tts_res_path = fo|res/tts/xiaoyan.jet;fo|res/tts/common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2"

* 参数设置

* 无效的参数值  参数值错误,离线资源没有正确导入  "按照文档说明,输入正确的参数值、导入资源到相应位置等.

* 检查参数值是否超过范围或不符合要求." "http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=14142&highlight=10107

* http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=15920&highlight=10107"

*/

  private void setParam(){

// 清空参数

      mTts.setParameter(SpeechConstant.PARAMS,null);

//设置合成

      if(mEngineType.equals(SpeechConstant.TYPE_CLOUD))

{

//设置使用云端引擎

        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);

//设置发音人

        mTts.setParameter(SpeechConstant.VOICE_NAME,voicerCloud);

}else {

//设置使用本地引擎

        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);

//设置发音人资源路径

        mTts.setParameter(ResourceUtil.TTS_RES_PATH,getResourcePath());

//设置发音人

        mTts.setParameter(SpeechConstant.VOICE_NAME,voicerLocal);

}

//mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY,"1");//支持实时音频流抛出,仅在synthesizeToUri条件下支持

//设置合成语速

      mTts.setParameter(SpeechConstant.SPEED,mSharedPreferences.getString("speed_preference","50"));

//设置合成音调

      mTts.setParameter(SpeechConstant.PITCH,mSharedPreferences.getString("pitch_preference","50"));

//设置合成音量

      mTts.setParameter(SpeechConstant.VOLUME,mSharedPreferences.getString("volume_preference","50"));

//设置播放器音频流类型

      mTts.setParameter(SpeechConstant.STREAM_TYPE,mSharedPreferences.getString("stream_preference","3"));

// 设置播放合成音频打断音乐播放,默认为true

      mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS,"true");

// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限

  mTts.setParameter(SpeechConstant.AUDIO_FORMAT,"wav");

mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/tts.wav");

}

//获取发音人资源路径

// private String getResourcePath(){

//    StringBuffer tempBuffer = new StringBuffer();

//    //合成通用资源

//    tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "tts/common.jet"));

//    tempBuffer.append(";");

//    //发音人资源

//    tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "tts/"+TtsDemo.voicerLocal+".jet"));

//    return tempBuffer.toString();

// }

  private String getResourcePath(){

StringBuffer tempBuffer =new StringBuffer();

//合成通用资源

      tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets,"tts/common.jet"));

tempBuffer.append(";");

//发音人资源

      tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets,"tts/"+TtsDemo.voicerLocal+".jet"));

return tempBuffer.toString();

}

@Override

  protected void onDestroy() {

super.onDestroy();

if(null !=mTts ){

mTts.stopSpeaking();

// 退出时释放连接

        mTts.destroy();

}

}

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,322评论 5 465
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,288评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,227评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,015评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,936评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,534评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,995评论 3 389
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,616评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,907评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,923评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,741评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,525评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,016评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,141评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,453评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,054评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,249评论 2 339

推荐阅读更多精彩内容