[置顶] Android移动开发-在Android项目里集成讯飞语音识别与合成的实现
2017-11-10 15:36
656 查看
“人工智能”是今年比较火的一个名词,甚至大多数人认为“人工智能”是继“IT互联网”之后一个新的浪潮,将会是本世纪最高科技的水准。个人觉得,目前国内语音识别做的比较好的是科大讯飞,图像识别(或人脸识别)做的比较好的是face++(旷视)。
那么,如何在Android项目里集成讯飞语音识别与合成呢?
首先在讯飞语音的开发平台网址:http://www.xfyun.cn/ ,然后在平台注册成为开发者后在点击“控制台”——左边导航栏的“创建新应用”,打开应用创建页面,如下图所示:
填写各项应用信息,并勾选“我已阅读并接受《讯飞用户协议》”,然后点击“提交”按钮,回到应用信息页面后接着点击“立即开通”开通相应的服务,选择开通“语音听写”和“在线语音合成”服务后并点击“确认”按钮开通语音听写和语音合成的服务,语音听写和语音合成的服务开通后回到应用信息页面,即可看到该测试应用的的已开通的服务列表,同时记下测试应用的Appid,后面会在程序代码里用到。如下图所示:
然后在平台单页点击“SDK下载”链接,在下载页面选择“语音听写”和“在线语音合成”服务,选择“Android”平台、选择应用是刚才创建的过应用,然后点击“下载SDK”按钮下载开发包。
注意:集成讯飞语音SDK需要注意以下几点:
1.将Msc.jar、Sunflower.jar导入libs目录下,将libmsc.so整个目录导入src/main/jniLibs目录下。以下这些文件必须来自对应的SDK,如果用别的SDK,运行就会报错“用户校检失败”。
2.自定义一个Application类,在onCreate函数中加入以下代码,注意appid值为创建测试应用时分配到的Appid:
3.在AndroidMainifest.xml中加入必要的权限和自定义的Application类。
语音识别
layout/activity_voice_recognize.xml界面布局代码如下:
VoiceRecognizeActivity.java逻辑代码如下:
Demo程序运行效果界面截图如下:
语音合成
layout/activity_voice_compose.xml界面布局代码如下:
VoiceComposeActivity.java逻辑代码如下:
Demo程序运行效果界面截图如下:
MainApplication.java逻辑代码如下:
Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)
那么,如何在Android项目里集成讯飞语音识别与合成呢?
首先在讯飞语音的开发平台网址:http://www.xfyun.cn/ ,然后在平台注册成为开发者后在点击“控制台”——左边导航栏的“创建新应用”,打开应用创建页面,如下图所示:
填写各项应用信息,并勾选“我已阅读并接受《讯飞用户协议》”,然后点击“提交”按钮,回到应用信息页面后接着点击“立即开通”开通相应的服务,选择开通“语音听写”和“在线语音合成”服务后并点击“确认”按钮开通语音听写和语音合成的服务,语音听写和语音合成的服务开通后回到应用信息页面,即可看到该测试应用的的已开通的服务列表,同时记下测试应用的Appid,后面会在程序代码里用到。如下图所示:
然后在平台单页点击“SDK下载”链接,在下载页面选择“语音听写”和“在线语音合成”服务,选择“Android”平台、选择应用是刚才创建的过应用,然后点击“下载SDK”按钮下载开发包。
注意:集成讯飞语音SDK需要注意以下几点:
1.将Msc.jar、Sunflower.jar导入libs目录下,将libmsc.so整个目录导入src/main/jniLibs目录下。以下这些文件必须来自对应的SDK,如果用别的SDK,运行就会报错“用户校检失败”。
2.自定义一个Application类,在onCreate函数中加入以下代码,注意appid值为创建测试应用时分配到的Appid:
SpeechUtility.createUtility(MainApplication.this, "appid=5a046888");
3.在AndroidMainifest.xml中加入必要的权限和自定义的Application类。
<!-- 读取手机设置 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 查看网络状态 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- WLAN --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 上网 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 定位 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 录像/录音 --> <uses-permission android:name="android.permission.RECORD_VIDEO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- SD卡 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <application android:name=".MainApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> ... </application>
语音识别
layout/activity_voice_recognize.xml界面布局代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical" android:padding="5dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="讯飞语音识别" android:textColor="@color/black" android:textSize="20sp" /> <Button android:id="@+id/xf_recognize_setting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:text="设置" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <EditText android:id="@+id/xf_recognize_text" android:layout_width="match_parent" android:layout_height="0dp" android:layout_margin="5dp" android:layout_weight="1" android:background="@drawable/editext_selector" android:gravity="top|left" android:padding="5dp" android:textColor="@color/black" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/xf_recognize_start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="开始" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/xf_recognize_stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="停止" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/xf_recognize_cancel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="取消" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> <Button android:id="@+id/xf_recognize_stream" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="音频流识别" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout>
VoiceRecognizeActivity.java逻辑代码如下:
package com.fukaimei.speechrecognizer; import java.util.HashMap; import java.util.LinkedHashMap; import org.json.JSONException; import org.json.JSONObject; import com.fukaimei.speechrecognizer.util.FucUtil; import com.fukaimei.speechrecognizer.util.JsonParser; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.ui.RecognizerDialog; import com.iflytek.cloud.ui.RecognizerDialogListener; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.Toast; public class VoiceRecognizeActivity extends AppCompatActivity implements OnClickListener { private final static String TAG = VoiceRecognizeActivity.class.getSimpleName(); // 语音听写对象 private SpeechRecognizer mRecognize; // 语音听写UI private RecognizerDialog mRecognizeDialog; // 用HashMap存储听写结果 private HashMap<String, String> mRecognizeResults = new LinkedHashMap<String, String>(); private EditText mResultText; private SharedPreferences mSharedPreferences; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_voice_recognize); // 定义获取录音的动态权限 soundPermissions(); mResultText = ((EditText) findViewById(R.id.xf_recognize_text)); findViewById(R.id.xf_recognize_start).setOnClickListener(this); findViewById(R.id.xf_recognize_stop).setOnClickListener(this); findViewById(R.id.xf_recognize_cancel).setOnClickListener(this); findViewById(R.id.xf_recognize_stream).setOnClickListener(this); findViewById(R.id.xf_recognize_setting).setOnClickListener(this); mSharedPreferences = getSharedPreferences(VoiceSettingsActivity.PREFER_NAME, Activity.MODE_PRIVATE); // 初始化识别无UI识别对象,使用SpeechRecognizer对象,可根据回调消息自定义界面; mRecognize = SpeechRecognizer.createRecognizer(this, mInitListener); // 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer // 使用UI听写功能,请将assets下文件拷贝到项目中 mRecognizeDialog = new RecognizerDialog(this, mInitListener); } @Override protected void onDestroy() { super.onDestroy(); // 退出时释放连接 mRecognize.cancel(); mRecognize.destroy(); } @Override public void onClick(View v) { int ret = 0; // 函数调用返回值 int resid = v.getId(); if (resid == R.id.xf_recognize_setting) { // 进入参数设置页面 Intent intent = new Intent(this, VoiceSettingsActivity.class); intent.putExtra("type", VoiceSettingsActivity.XF_RECOGNIZE); startActivity(intent); } else if (resid == R.id.xf_recognize_start) { // 开始听写。如何判断一次听写结束:OnResult isLast=true 或者 onError mResultText.setText(null);// 清空显示内容 mRecognizeResults.clear(); // 设置参数 resetParam(); boolean isShowDialog = mSharedPreferences.getBoolean("show_dialog", true); if (isShowDialog) { // 显示听写对话框 mRecognizeDialog.setListener(mRecognizeDialogListener); mRecognizeDialog.show(); showTip("请开始说话………"); } else { // 不显示听写对话框 ret = mRecognize.startListening(mRecognizeListener); if (ret != ErrorCode.SUCCESS) { showTip("听写失败,错误码:" + ret); } else { showTip("请开始说话…"); } } } else if (resid == R.id.xf_recognize_stop) { // 停止听写 mRecognize.stopListening(); showTip("停止听写"); } else if (resid == R.id.xf_recognize_cancel) { // 取消听写 mRecognize.cancel(); showTip("取消听写"); } else if (resid == R.id.xf_recognize_stream) { // 音频流识别 mResultText.setText(null);// 清空显示内容 mRecognizeResults.clear(); // 设置参数 resetParam(); // 设置音频来源为外部文件 mRecognize.setParameter(SpeechConstant.AUDIO_SOURCE, "-1"); // 也可以像以下这样直接设置音频文件路径识别(要求设置文件在sdcard上的全路径): // mRecognize.setParameter(SpeechConstant.AUDIO_SOURCE, "-2"); // mRecognize.setParameter(SpeechConstant.ASR_SOURCE_PATH, "sdcard/XXX/XXX.pcm"); ret = mRecognize.startListening(mRecognizeListener); if (ret != ErrorCode.SUCCESS) { showTip("识别失败,错误码:" + ret); } else { byte[] audioData = FucUtil.readAudioFile(this, "retcognize_est.wav"); if (null != audioData) { showTip("开始音频流识别"); // 一次(也可以分多次)写入音频文件数据,数据格式必须是采样率为8KHz或16KHz(本地识别只支持16K采样率,云端都支持),位长16bit,单声道的wav或者pcm // 写入8KHz采样的音频时,必须先调用setParameter(SpeechConstant.SAMPLE_RATE, "8000")设置正确的采样率 // 注:当音频过长,静音部分时长超过VAD_EOS将导致静音后面部分不能识别 mRecognize.writeAudio(audioData, 0, audioData.length); mRecognize.stopListening(); } else { mRecognize.cancel(); showTip("读取音频流失败"); } } } } //初始化监听器 private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code); } } }; //听写监听器 private RecognizerListener mRecognizeListener = new RecognizerListener() { @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { // 错误码:10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。 // 如果使用本地功能(语记)需要提示用户开启语记的录音权限。 showTip(error.getPlainDescription(true)); } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onResult(RecognizerResult results, boolean isLast) { Log.d(TAG, results.getResultString()); printResult(results); if (isLast) { // TODO 最后的结果 } } @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:"+data.length); } @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); // } } }; private void printResult(RecognizerResult results) { String text = JsonParser.parseIatResult(results.getResultString()); String sn = null; try { JSONObject resultJson = new JSONObject(results.getResultString()); sn = resultJson.optString("sn"); } catch (JSONException e) { e.printStackTrace(); return; } mRecognizeResults.put(sn, text); StringBuffer resultBuffer = new StringBuffer(); for (String key : mRecognizeResults.keySet()) { resultBuffer.append(mRecognizeResults.get(key)); } mResultText.setText(resultBuffer.toString()); mResultText.setSelection(mResultText.length()); } //听写UI监听器 private RecognizerDialogListener mRecognizeDialogListener = new RecognizerDialogListener() { public void onResult(RecognizerResult results, boolean isLast) { printResult(results); } //识别回调错误 public void onError(SpeechError error) { showTip(error.getPlainDescription(true)); } }; private void showTip(final String str) { Toast.makeText(this, str, Toast.LENGTH_LONG).show(); } //参数设置 public void resetParam() { // 清空参数 mRecognize.setParameter(SpeechConstant.PARAMS, null); // 设置听写引擎。TYPE_LOCAL表示本地,TYPE_CLOUD表示云端,TYPE_MIX 表示混合 mRecognize.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 设置返回结果格式 mRecognize.setParameter(SpeechConstant.RESULT_TYPE, "json"); String lag = mSharedPreferences.getString("recognize_language_preference", "mandarin"); if (lag.equals("en_us")) { // 设置语言 mRecognize.setParameter(SpeechConstant.LANGUAGE, "en_us"); } else { mRecognize.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); // 设置语言区域 mRecognize.setParameter(SpeechConstant.ACCENT, lag); } // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理 mRecognize.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("recognize_vadbos_preference", "4000")); // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音 mRecognize.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("recognize_vadeos_preference", "1000")); // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点 mRecognize.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("recognize_punc_preference", "1")); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mRecognize.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mRecognize.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/recognize.wav"); } // 定义录音的动态权限 private void soundPermissions() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{ android.Manifest.permission.RECORD_AUDIO}, 1); } } /** * 重写onRequestPermissionsResult方法 * 获取动态权限请求的结果,再开启录音 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { } else { Toast.makeText(this, "用户拒绝了权限", Toast.LENGTH_SHORT).show(); } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }
Demo程序运行效果界面截图如下:
语音合成
layout/activity_voice_compose.xml界面布局代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical" android:padding="5dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="讯飞语音合成" android:textColor="@color/black" android:textSize="20sp" /> <Button android:id="@+id/xf_compose_setting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:text="设置" android:textColor="@color/black" android:textSize="17sp" /> </RelativeLayout> <EditText android:id="@+id/xf_compose_text" android:layout_width="match_parent" android:layout_height="0dp" android:layout_margin="5dp" android:layout_weight="1" android:background="@drawable/editext_selector" android:gravity="top|left" android:padding="5dp" android:text="@string/compose_source" android:textColor="@color/black" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/xf_compose_person" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="发音人" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/xf_compose_play" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="开始合成" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/xf_compose_cancel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="取消" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/xf_compose_pause" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="暂停播放" android:textColor="@color/black" android:textSize="17sp" /> <Button android:id="@+id/xf_compose_resume" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="继续播放" android:textColor="@color/black" android:textSize="17sp" /> </LinearLayout> </LinearLayout>
VoiceComposeActivity.java逻辑代码如下:
package com.fukaimei.speechrecognizer; 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 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.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.EditText; import android.widget.Toast; public class VoiceComposeActivity extends AppCompatActivity implements OnClickListener { private static String TAG = VoiceComposeActivity.class.getSimpleName(); // 语音合成对象 private SpeechSynthesizer mCompose; // 默认发音人 private String voicer = "xiaoyan"; private String[] mCloudVoicersEntries; private String[] mCloudVoicersValue; // 缓冲进度 private int mPercentForBuffering = 0; // 播放进度 private int mPercentForPlaying = 0; private EditText mResourceText; private SharedPreferences mSharedPreferences; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_voice_compose); mResourceText = ((EditText) findViewById(R.id.xf_compose_text)); findViewById(R.id.xf_compose_play).setOnClickListener(this); findViewById(R.id.xf_compose_cancel).setOnClickListener(this); findViewById(R.id.xf_compose_pause).setOnClickListener(this); findViewById(R.id.xf_compose_resume).setOnClickListener(this); findViewById(R.id.xf_compose_setting).setOnClickListener(this); findViewById(R.id.xf_compose_person).setOnClickListener(this); mSharedPreferences = getSharedPreferences(VoiceSettingsActivity.PREFER_NAME, MODE_PRIVATE); // 初始化合成对象 mCompose = SpeechSynthesizer.createSynthesizer(this, mComposeInitListener); // 云端发音人名称列表 mCloudVoicersEntries = getResources().getStringArray(R.array.voicer_cloud_entries); mCloudVoicersValue = getResources().getStringArray(R.array.voicer_cloud_values); } @Override protected void onDestroy() { super.onDestroy(); // 退出时释放连接 mCompose.stopSpeaking(); mCompose.destroy(); } @Override public void onClick(View v) { int resid = v.getId(); if (resid == R.id.xf_compose_setting) { Intent intent = new Intent(this, VoiceSettingsActivity.class); intent.putExtra("type", VoiceSettingsActivity.XF_COMPOSE); startActivity(intent); } else if (resid == R.id.xf_compose_play) { // 开始合成 //收到onCompleted 回调时,合成结束、生成合成音频。合成的音频格式:只支持pcm格式 String text = mResourceText.getText().toString(); // 设置参数 setParam(); int code = mCompose.startSpeaking(text, mComposeListener); if (code != ErrorCode.SUCCESS) { showTip("语音合成失败,错误码: " + code); } // //只保存音频不进行播放接口,调用此接口请注释startSpeaking接口 // //text:要合成的文本,uri:需要保存的音频全路径,listener:回调接口 // String path = Environment.getExternalStorageDirectory()+"/compose.pcm"; // int code = mCompose.synthesizeToUri(text, path, mComposeListener); } else if (resid == R.id.xf_compose_cancel) { // 取消合成 mCompose.stopSpeaking(); } else if (resid == R.id.xf_compose_pause) { // 暂停播放 mCompose.pauseSpeaking(); } else if (resid == R.id.xf_compose_resume) { // 继续播放 mCompose.resumeSpeaking(); } else if (resid == R.id.xf_compose_person) { // 选择发音人 showPresonSelectDialog(); } } private int selectedNum = 0; //发音人选择 private void showPresonSelectDialog() { new AlertDialog.Builder(this).setTitle("在线合成发音人选项") .setSingleChoiceItems(mCloudVoicersEntries, // 单选框有几项,各是什么名字 selectedNum, // 默认的选项 new DialogInterface.OnClickListener() { // 点击单选框后的处理 public void onClick(DialogInterface dialog, int which) { // 点击了哪一项 voicer = mCloudVoicersValue[which]; if ("catherine".equals(voicer) || "henry".equals(voicer) || "vimary".equals(voicer) || "Mariane".equals(voicer) || "Allabent".equals(voicer) || "Gabriela".equals(voicer) || "Abha".equals(voicer) || "XiaoYun".equals(voicer)) { mResourceText.setText(R.string.compose_source_en); } else { mResourceText.setText(R.string.compose_source); } selectedNum = which; dialog.dismiss(); } }).show(); } //初始化监听 private InitListener mComposeInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "InitListener init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code); } else { // 初始化成功,之后可以调用startSpeaking方法 // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成, // 正确的做法是将onCreate中的startSpeaking调用移至这里 } } }; //合成回调监听 private SynthesizerListener mComposeListener = 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.compose_toast_format), // mPercentForBuffering, mPercentForPlaying)); } @Override public void onSpeakProgress(int percent, int beginPos, int endPos) { // 播放进度 mPercentForPlaying = percent; // showTip(String.format(getString(R.string.compose_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); // } } }; private void showTip(final String str) { Toast.makeText(this, str, Toast.LENGTH_LONG).show(); } //参数设置 private void setParam() { // 清空参数 mCompose.setParameter(SpeechConstant.PARAMS, null); // 根据合成引擎设置相应参数 mCompose.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 设置在线合成发音人 mCompose.setParameter(SpeechConstant.VOICE_NAME, voicer); //设置合成语速 mCompose.setParameter(SpeechConstant.SPEED, mSharedPreferences.getString("speed_preference", "50")); //设置合成音调 mCompose.setParameter(SpeechConstant.PITCH, mSharedPreferences.getString("pitch_preference", "50")); //设置合成音量 mCompose.setParameter(SpeechConstant.VOLUME, mSharedPreferences.getString("volume_preference", "50")); //设置播放器音频流类型 mCompose.setParameter(SpeechConstant.STREAM_TYPE, mSharedPreferences.getString("stream_preference", "3")); // 设置播放合成音频打断音乐播放,默认为true mCompose.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true"); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mCompose.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mCompose.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/compose.wav"); } }
Demo程序运行效果界面截图如下:
MainApplication.java逻辑代码如下:
package com.fukaimei.speechrecognizer; import android.app.Application; import com.iflytek.cloud.SpeechUtility; public class MainApplication extends Application { @Override public void onCreate() { // 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null // 如在Application中调用初始化,需要在Mainifest中注册该Applicaiton // 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true" // 参数间使用半角“,”分隔。 // 设置你申请的应用appid,请勿在'='与appid之间添加空格及空转义符 // 注意: appid 必须和下载的SDK保持一致,否则会出现10407错误 SpeechUtility.createUtility(MainApplication.this, "appid=5a046888"); // 以下语句用于设置日志开关(默认开启),设置成false时关闭语音云SDK日志打印 // Setting.setShowLog(false); super.onCreate(); } }
Demo程序源码下载地址一(GitHub)
Demo程序源码下载地址二(Gitee)
相关文章推荐
- [置顶] Android移动开发-在Android项目里集成face++人脸识别的实现
- [置顶] Android移动开发-在Android项目里集成调用微信支付开发的实现
- [置顶] Android移动开发-在Android项目里集成开源框架ZXing实现扫描二维码的功能
- [置顶] Android移动开发-在Android项目里调用基于百度地图API实现定位
- Android开发之通过蓝牙耳机实现讯飞语音识别的功能
- [置顶] android开发之集成zxing,二维码,以及扫描二维码的功能实现。带源代码下载
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(一)
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(三)
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(三)
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(一)
- Android移动开发-在Android应用里集成QQ分享的实现
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(一)
- Android移动开发-在Android项目里实现仿QQ界面的 Material Design 设计开发
- Android网络开发回顾之旅 ① 在Android手机集成使用MQTT协议 ,实现搞掂移动控制硬件端。(附带Demo)
- [置顶] Android项目快速开发集成框架
- [置顶] Android开发之清除缓存功能实现方法,可以集成在自己的app中,增加一个新功能。
- 【Android开发经验】移动设备的“声波通信/验证”的实现——SinVoice开源项目介绍(二)
- [置顶] Android下通过pocketsphinx实现离线语音识别的环境搭建和demo运行
- Android-图像识别项目OpenCV(4):开发思路以及问题
- Android高手进阶篇4-实现侧滑菜单框架,一分钟集成到项目中