近日因项目需要,查阅多方文档最终选择集成了一个百度的语音合成模块。在此为什么要选百度语音合成呢,因为百度重点声明此业务永久免费。这里我只集成了在线语音播放功能,该项目是在百度案例项目基础上二次开发,所以代码还是比较简洁规范的,有需要的朋友可以直接下载该项目集成到自己的项目中。至于离线语音合成就得需要的朋友自己上百度官方查阅相关文档了。
通过学习本文章还可以重点掌握如何自定义一个preferences.xml
4、主页面
/**
* TTS播放类
*
* @author 康驻关
*/
public class demo_activity extends Activity implements OnClickListener, SpeechSynthesizerListener {
private ImageButton moresetting, startOrPauseSpeech, stopSpeech;
/** 输入合成文本 **/
private EditText mInput;
/** 显示合成状态 **/
private TextView mShowText;
/** 定义TTS **/
private SpeechSynthesizer mSpeechSynthesizer;
/** MESSAGE消息标识 **/
private static final int PRINT = 0;
private static final String TAG = "MainActivity";
/** 判断当前播放状态,0表示停止播放,1表示播放中,2表示暂停播放 **/
private static int flag = 0;
private String description;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_main);
// 初始化控件
initialView();
// 初始化TTS;
initialTts();
Intent intent = getIntent();
description = intent.getStringExtra("description");
}
/**
* 初始化各个控件
*/
private void initialView() {
this.moresetting = (ImageButton) this.findViewById(R.id.moresetting);
this.moresetting.setOnClickListener(this);
this.startOrPauseSpeech = (ImageButton) this.findViewById(R.id.startOrPauseSpeech);
this.startOrPauseSpeech.setOnClickListener(this);
this.stopSpeech = (ImageButton) this.findViewById(R.id.stopSpeech);
this.stopSpeech.setOnClickListener(this);
this.mInput = (EditText) this.findViewById(R.id.inputTextView);
this.mShowText = (TextView) this.findViewById(R.id.logView);
this.mShowText.setMovementMethod(new ScrollingMovementMethod());
}
/**
* 初始化TTS
*/
private void initialTts() {
// 获取tts实例
this.mSpeechSynthesizer = SpeechSynthesizer.getInstance();
// 设置app上下文(必需参数)
this.mSpeechSynthesizer.setContext(this);
// 设置tts监听器
this.mSpeechSynthesizer.setSpeechSynthesizerListener(this);
// 请替换为语音开发者平台注册应用得到的apikey和secretkey (在线授权)
this.mSpeechSynthesizer.setApiKey("XQ4QTvPpdw0dhutVUSBzxAn5iQtZwcHw", "a0QcGOC4MW1DIqZWn7h0xgSY3pnRqmR8");
// 初始化tts各参数
initTTSParam(this.mSpeechSynthesizer);
// 授权检测接口(可以不使用,只是验证授权是否成功)
AuthInfo authInfo = this.mSpeechSynthesizer.auth(TtsMode.MIX);
if (authInfo.isSuccess()) {
toPrint("auth success");
} else {
String errorMsg = authInfo.getTtsError().getDetailMessage();
toPrint("auth failed errorMsg=" + errorMsg);
}
/**
* 初始化 tts引擎,可以指定使用online在线,或者 mix离在线混合引擎 .
* mix离在线混合引擎会在online在线不能用的情况下自动使在线offline离线引擎 具体参数清查看文档
*/
mSpeechSynthesizer.initTts(TtsMode.MIX);
}
/**
* 在调用 在调用 speak 方法开始合成 并朗读之前,可以对参数进行配置(未设置的参数将使用默认值)
*
* @param SpeechSynthesizer
*/
private void initTTSParam(SpeechSynthesizer speechSynthesizer) {
// 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增加,各值含义参考文档,以文档说明为准。0--普通女声,1--普通男声,2--特别男声,3--情感男声。。。)默认0
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
// 调整音量 ,范围 [0-9],默认为5
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5");
// 调整语速 ,范围 [0-9],默认为5
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");
// 调整语调,范围 [0-9],默认为5
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");
// 设置Mix模式的合成策略,默认MIX_MODE_DEFAULT, 其它参数请参考文档
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_HIGH_SPEED_NETWORK);
// 设置音频格式,默认AUDIO_ENCODE_AMR
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_ENCODE, SpeechSynthesizer.AUDIO_ENCODE_AMR);
// 设置比特率,默认AUDIO_BITRATE_AMR_15K
speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUDIO_RATE, SpeechSynthesizer.AUDIO_BITRATE_AMR_12K65);
}
/*
* 当退出时销毁TTS
*/
@Override
protected void onDestroy() {
this.mSpeechSynthesizer.release();
super.onDestroy();
}
/**
* 获取EditView上的文字合成语音
*/
private void speak() {
String text = this.mInput.getText().toString(); // 获取EditView上的文字
// 该接口比较耗时,采用排队策略调后将自动加入合成列并按顺序进行和播放 该接口比较耗时,采用排队策略调后将自动加入合成列并按顺序进行合成和播放
int result = this.mSpeechSynthesizer.speak(text);
/**
* speak(String text,String utteranceId); utteranceId参数用来指定此次文本合成标识
* 该接口和sprak(String Text)接口功能相同 详细使用请参照开发文档
*/
// int result = this.mSpeechSynthesizer.speak("你好","1");
// this.mSpeechSynthesizer.speak("我好","2");
// this.mSpeechSynthesizer.speak("大家好","3");
// 判断是否合成成功
if (result < 0) {
toPrint("error,please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
}
}
/**
* 暂停播放
*/
private void pause() {
this.mSpeechSynthesizer.pause();
flag = 2; // 将播放状态改为暂停播放
}
/**
* 恢复播放
*/
private void resume() {
this.mSpeechSynthesizer.resume();
flag = 1; // 将播放状态改为播放中
}
/**
* 停止播放,清除合成缓存
*/
private void stop() {
this.mSpeechSynthesizer.stop();
flag = 0; // 将播放状态改为停止播放
}
/**
* 此接口实现只合成不播放,可用于网络较差时的缓存策略
*/
private void synthesize() {
String text = this.mInput.getText().toString();
int result = this.mSpeechSynthesizer.synthesize(text);
if (result < 0) {
toPrint("error,please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
}
}
/**
* 批量合成播放接口
*/
private void batchSpeak() {
List bags = new ArrayList();
bags.add(getSpeechSynthesizeBag("123456", "0"));
bags.add(getSpeechSynthesizeBag("你好", "1"));
bags.add(getSpeechSynthesizeBag("使用百度语音合成SDK", "2"));
bags.add(getSpeechSynthesizeBag("hello", "3"));
bags.add(getSpeechSynthesizeBag("这是一个demo工程", "4"));
int result = this.mSpeechSynthesizer.batchSpeak(bags);
if (result < 0) {
toPrint("error,please look up error code in doc or URL:http://yuyin.baidu.com/docs/tts/122 ");
}
}
/**
* @param text
* 合成文本
* @param utteranceId
* 标识ID
* @return
*/
private SpeechSynthesizeBag getSpeechSynthesizeBag(String text, String utteranceId) {
SpeechSynthesizeBag speechSynthesizeBag = new SpeechSynthesizeBag();
speechSynthesizeBag.setText(text);
speechSynthesizeBag.setUtteranceId(utteranceId);
return speechSynthesizeBag;
}
/**
* 开始合成
*
* @param arg0
* arg0对应 speak中的utteranceId参数
*/
@Override
public void onSynthesizeStart(String utteranceId) {
toPrint("onSynthesizeStart utteranceId=" + utteranceId);
}
/**
* @param arg0
* @param arg1
* @param arg2
*/
@Override
public void onSynthesizeDataArrived(String utteranceId, byte[] data, int progress) {
// toPrint("onSynthesizeDataArrived");
}
/**
* 完成合成
*
* @param arg0
* arg0对应 speak中的utteranceId参数
*/
@Override
public void onSynthesizeFinish(String utteranceId) {
toPrint("onSynthesizeFinish utteranceId=" + utteranceId);
}
/**
* 播放开始
*
* @param arg0
* arg0对应 speak中的utteranceId参数
*/
@Override
public void onSpeechStart(String utteranceId) {
toPrint("onSpeechStart utteranceId=" + utteranceId);
}
/*
* @param arg0
*
* @param arg1
*/
@Override
public void onSpeechProgressChanged(String utteranceId, int progress) {
// toPrint("onSpeechProgressChanged");
}
/**
* 播放完成
*
* @param arg0
* arg0对应 speak中的utteranceId参数
*/
@Override
public void onSpeechFinish(String utteranceId) {
toPrint("onSpeechFinish utteranceId=" + utteranceId);
flag = 0; // 将播放状态改为停止播放
setImageButtonBG(this.startOrPauseSpeech, 1);
}
/**
* 合成出错
*
* @param arg0
* @param arg1
*/
@Override
public void onError(String utteranceId, SpeechError error) {
toPrint("onError error=" + "(" + error.code + ")" + error.description + "--utteranceId=" + utteranceId);
}
/**
* 用于处理UI
*/
private Handler mHandler = new Handler() {
/*
* @param msg
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int what = msg.what;
switch (what) {
case PRINT:
print(msg); // 将合成信息写入TextView
break;
default:
break;
}
}
};
/**
* 将信息封装到Message中发送个handler
*
* @param str
*/
private void toPrint(String str) {
Message msg = Message.obtain();
msg.obj = str;
this.mHandler.sendMessage(msg);
}
/**
* 将封装到Message中的信息解析成字符串
*
* @param msg
*/
private void print(Message msg) {
String message = (String) msg.obj;
if (message != null) {
Log.w(TAG, message);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
scrollLog(message);
}
}
/**
* 对消息进行处理显示在TextView中
*
* @param message
*/
private void scrollLog(String message) {
Spannable colorMessage = new SpannableString(message + "\n");
// 设置字符串颜色
colorMessage.setSpan(new ForegroundColorSpan(0xff0000ff), 0, message.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mShowText.append(colorMessage);
Layout layout = mShowText.getLayout();
if (layout != null) {
int scrollAmount = layout.getLineTop(mShowText.getLineCount()) - mShowText.getHeight();
if (scrollAmount > 0) {
mShowText.scrollTo(0, scrollAmount + mShowText.getCompoundPaddingBottom());
} else {
mShowText.scrollTo(0, 0);
}
}
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.moresetting: {
Intent intent = new Intent(demo_activity.this, SettingsActivity.class);
startActivity(intent);
break;
}
case R.id.startOrPauseSpeech: {
if (flag == 0) {
// 开始播放
speak();
flag = 1; // 将播放状态改为播放中
setImageButtonBG(this.startOrPauseSpeech, 0);
} else if (flag == 1) {
// 暂停播放
pause();
flag = 2; // 将播放状态改为暂停播放
setImageButtonBG(this.startOrPauseSpeech, 1);
} else if (flag == 2) {
// 恢复播放
resume();
flag = 1; // 将播放状态改为播放中
setImageButtonBG(this.startOrPauseSpeech, 0);
}
break;
}
case R.id.stopSpeech:
stop();
break;
default:
break;
}
}
/**
* 给imageButton设置背景图,0表示设置暂停背景,1表示设置播放背景,
*
* @param imageButton
* @param flag
*/
private void setImageButtonBG(ImageButton imageButton, int flag) {
if (flag == 0)
imageButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_pause));
else if (flag == 1)
imageButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_play));
}
}
5、设置页面
/**
* TTS设置类
* @author 康驻关
*/
public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String KEY_PREF_AUDIO_ENCODE = "pref_audio_encode";
public static final String KEY_PREF_AUDIO_RATE = "pref_audio_rate";
public static final String KEY_PREF_SPEAKER = "pref_speaker";
public static final String KEY_PREF_SPEECH_PITCH = "pref_speech_pitch";
public static final String KEY_PREF_SPEECH_SPEED = "pref_speech_speed";
public static final String KEY_PREF_SPEECH_VOLUME = "pref_speech_volume";
private void changeRateSet() {
ListPreference localListPreference1 = (ListPreference) findPreference("pref_audio_encode");
ListPreference localListPreference2 = (ListPreference) findPreference("pref_audio_rate");
String str = localListPreference1.getValue();
int i = localListPreference2.findIndexOfValue(localListPreference2.getValue());
if (str.equals("0")) {
localListPreference2.setEntries(R.array.pref_bv_rate_entries);
int n = getResources().getStringArray(R.array.pref_bv_rate_entries).length;
if (i > n - 1)
localListPreference2.setValueIndex(n - 1);
} else if (str.equals("1")) {
localListPreference2.setEntries(R.array.pref_amr_rate_entries);
int m = getResources().getStringArray(R.array.pref_amr_rate_entries).length;
if (i > m - 1)
localListPreference2.setValueIndex(m - 1);
} else if (str.equals("2")) {
localListPreference2.setEntries(R.array.pref_opus_rate_entries);
int m = getResources().getStringArray(R.array.pref_opus_rate_entries).length;
if (i > m - 1)
localListPreference2.setValueIndex(m - 1);
} else if (str.equals("3")) {
localListPreference2.setEntries(R.array.pref_mp3_rate_entries);
int m = getResources().getStringArray(R.array.pref_mp3_rate_entries).length;
if (i > m - 1)
localListPreference2.setValueIndex(m - 1);
}
}
private void setSummaryForListPref(SharedPreferences paramSharedPreferences, String paramString) {
ListPreference localListPreference = (ListPreference) findPreference(paramString);
int i = localListPreference.findIndexOfValue(paramSharedPreferences.getString(paramString, "0"));
String str = localListPreference.getEntries()[i].toString();
localListPreference.setSummary("当前设置为:" + str);
}
private void setSummaryForNumPickerPref(SharedPreferences paramSharedPreferences, String paramString) {
Preference localPreference = findPreference(paramString);
if (Build.VERSION.SDK_INT >= 11) {
String str = paramSharedPreferences.getString(paramString, "5");
localPreference.setSummary("当前设置为:" + str);
return;
}
String str = paramSharedPreferences.getString(paramString, "5");
localPreference.setSummary("当前设置为:" + str);
}
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
addPreferencesFromResource(R.xml.preferences);
}
public void onPause() {
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
public void onResume() {
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
super.onResume();
SharedPreferences localSharedPreferences = getPreferenceScreen().getSharedPreferences();
setSummaryForNumPickerPref(localSharedPreferences, "pref_speech_volume");
setSummaryForNumPickerPref(localSharedPreferences, "pref_speech_speed");
setSummaryForNumPickerPref(localSharedPreferences, "pref_speech_pitch");
setSummaryForListPref(localSharedPreferences, "pref_speaker");
setSummaryForListPref(localSharedPreferences, "pref_audio_encode");
changeRateSet();
setSummaryForListPref(localSharedPreferences, "pref_audio_rate");
}
public void onSharedPreferenceChanged(SharedPreferences paramSharedPreferences, String paramString) {
if ((paramString.equals("pref_speech_speed")) || (paramString.equals("pref_speech_pitch"))
|| (paramString.equals("pref_speech_volume")))
setSummaryForNumPickerPref(paramSharedPreferences, paramString);
if ((paramString.equals("pref_audio_encode")) || (paramString.equals("pref_speaker"))
|| (paramString.equals("pref_audio_rate")))
setSummaryForListPref(paramSharedPreferences, paramString);
if (paramString.equals("pref_audio_encode")) {
changeRateSet();
setSummaryForListPref(paramSharedPreferences, "pref_audio_rate");
}
}
@Override
protected void onStop() {
super.onStop();
this.finish();
}
}
6、自定义preferences
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto" >
"pref_common_settings"
android:title="@string/pref_common_settings_title" >
"@string/pref_speaker_default"
android:dialogTitle="@string/pref_speaker"
android:entries="@array/pref_speaker_entries"
android:entryValues="@array/pref_speaker_values"
android:key="pref_speaker"
android:title="@string/pref_speaker" />
"@string/pref_speech_volume_default"
android:dialogTitle="@string/pref_speech_volume"
android:entries="@array/pref_speech_volume_entries"
android:entryValues="@array/pref_speech_volume_values"
android:key="pref_speech_volume"
android:title="@string/pref_speech_volume" />
"@string/pref_speech_speed_default"
android:dialogTitle="@string/pref_speech_speed"
android:entries="@array/pref_speech_speed_entries"
android:entryValues="@array/pref_speech_speed_values"
android:key="pref_speech_speed"
android:title="@string/pref_speech_speed" />
"@string/pref_speech_pitch_default"
android:dialogTitle="@string/pref_speech_pitch"
android:entries="@array/pref_speech_pitch_entries"
android:entryValues="@array/pref_speech_pitch_values"
android:key="pref_speech_pitch"
android:title="@string/pref_speech_pitch" />
</PreferenceCategory>
" >
@string /pref_audio_encode_default"
android:dialogTitle="@string/pref_audio_encode"
android:entries="@array/pref_audioEncode_entries"
android:entryValues="@array/pref_audioEncode_values"
android:key="pref_audio_encode"
android:title="@string/pref_audio_encode" />
@string /pref_amr_rate_default"
android:dialogTitle="@string/pref_audio_rate"
android:entries="@array/pref_amr_rate_entries"
android:entryValues="@array/pref_amr_rate_values"
android:key="pref_audio_rate"
android:title="@string/pref_audio_rate" />
7、主界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:focusable="true"
android:focusableInTouchMode="true"
>
<TextView
android:id="@+id/logView"
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="2.0"
android:background="@+drawable/back_border"
android:freezesText="true"
android:hint="@string/logViewHint"
android:padding="12.0dip"
android:scrollbars="vertical" />
<EditText
android:id="@+id/inputTextView"
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="2.0"
android:gravity="center|left|top"
android:hint="@string/inputHint" />
<LinearLayout
android:id="@+id/controlBar"
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="1.0" >
<ImageButton
android:id="@+id/moresetting"
android:layout_width="0.0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/start"
android:src="@+drawable/ic_action_settings" />
<ImageButton
android:id="@+id/startOrPauseSpeech"
android:layout_width="0.0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/start"
android:src="@+drawable/ic_action_play" />
<ImageButton
android:id="@+id/stopSpeech"
android:layout_width="0.0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/start"
android:src="@+drawable/ic_action_stop" />
LinearLayout>
LinearLayout>
其他资源文件就不一一列出了,需要的朋友直接下载完整项目,本人还是比较喜欢百度提供的开发平台,毕竟免费就是坑比较多需要自己慢慢研究
项目下载地址 http://download.csdn.net/detail/kzg_ip/9584611