android studio集成百度语音合成

离开老师的指导有一段时间了,天天都会给本身找点事情作,或则简单的安排计划一下,收货很少很多刚恰好。 
 这是2017年的第一篇比较正式的博客,也算是我在CSDN上的第一次吧!哈哈。今天记录的是最近在集成百度语音上的一些步骤和小部分总结。最开始准备使用讯飞语音的,然而在下载集成后屡次测试都没有反应,感受是哪儿出现了问题,而且讯飞语音在语音唤醒上面也有限制,最后无心间发现了百度语音,就尝试着试试,固然目前只完成了语音合成部分,接下来固然会去玩玩语音识别和唤醒咯。java

步骤以下:

  1. Android Studio新建一个Mudule,好比个人:MyTest_AutoAnswer,你能够随意叫啥名。
  2. 登陆网址百度语音开发者平台注册帐号并建立应用。http://yuyin.baidu.com/ 。
  3. 进入离线下载资源,先开通服务,再下载。我这里仅仅下载的为语音合成部分的离在线融合SDK–安卓版本。
  4. 进入应用管理在该项目的右边点开管理包名,并在应用包名处输入android Studio中建立的应用包名,好比个人为:com.bk120.mytest_autoanswer。保存修改。此处能够不用下载什么临时受权文件,我就没下载由于你已经把包名都填上了。
  5. 同理点击查看Key,查看当前应用的所需的主要三个参数 AppId APIKey SecretKey,后面会用获得。
  6. 将咱们前面几步中下载的SDk解压,为以下目录结构: 
     BaiduTtsSample:为一个模板代码,eclipse版本的,我就是借鉴里面稍微修改了一下。 
     data:为百度语音资源,声音文件,它为一个必须文件,中英文资源。最后使用是放在手机物理存储下的。 
     doc:为一个pdf的简介使用方法以及网络的使用Api文档说明。咱们用不到,能够下去读一读的。 
     libs:为资源jar包和语音引擎文件.so库。也是咱们集成必须使用到的。 
    7.接下来的步骤是,咱们家语音资源和libs下的资源方法android studio咱们的项目里面。将data里面的文件所有复制到Asserts文件夹下。将libs下的两个jar文件复制到项目的libs中,并添加Add As library关联。在项目中的main路径下新建一个jnilibs文件夹,用于放置剩余的libs下的文件。因此后的文件目录为: 
     libs下面多余的两个okhttp和okio是个人网络访问的库,此处没有影响,不用添加的。 
    8.最后在AndroidManifest文件中申明以下权限,我申请的比较多,由于作了一个网络判断的事件处理,没事所有Ctrl+C就好没影响的。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到此,集成就结束了,接下来就是如何使用。固然能够参照BaiduTtsSample文件夹下的src里面的一个MainActvity的写法。也能够按照我下面的总结的工具类来直接使用,方便快捷省事。android

工具类以下


package com.bk120.mytest_autoanswer;

import android.content.Context;
import android.os.Environment;
import com.baidu.tts.client.SpeechError;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.baidu.tts.client.SynthesizerTool;
import com.baidu.tts.client.TtsMode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/*** Created by bk120 on 2017/1/3.
 * 语音合成工具类
 */

public class VoiceUtils {
//////////////////需配置部分////////////////////////
//AppId
private String APPID="9156383";
//ApiKey
private String APIKEY="BZQ1owOxjYzf0ADT1agq8SxU";
//SecretKey
private String SECRETKEY="43b8a384182f2af0b935cf4ee9dce03f";
////////////////////配置结束////////////////////////////////////

private SpeechSynthesizer mSpeechSynthesizer;
private String mSampleDirPath;
private static final String SAMPLE_DIR_NAME = "baiduTTS";
private static final String SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female.dat";
private static final String SPEECH_MALE_MODEL_NAME = "bd_etts_speech_male.dat";
private static final String TEXT_MODEL_NAME = "bd_etts_text.dat";
private static final String LICENSE_FILE_NAME = "temp_license.txt";
private static final String ENGLISH_SPEECH_FEMALE_MODEL_NAME = "bd_etts_speech_female_en.dat";
private static final String ENGLISH_SPEECH_MALE_MODEL_NAME = "bd_etts_speech_male_en.dat";
private static final String ENGLISH_TEXT_MODEL_NAME = "bd_etts_text_en.dat";
//初始化
public  void init(Context context,int speaker){
    initialEnv(context);
    initialTts(context,speaker);
}
//获取解析器
public SpeechSynthesizer getSyntheszer(){
    return mSpeechSynthesizer;
}
//初始化配置文件
private void initialEnv(Context context) {
    if (mSampleDirPath == null) {
        String sdcardPath = Environment.getExternalStorageDirectory().toString();
        mSampleDirPath = sdcardPath + "/" + SAMPLE_DIR_NAME;
    }
    makeDir(mSampleDirPath);
    copyFromAssetsToSdcard(context,false, SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_FEMALE_MODEL_NAME);
    copyFromAssetsToSdcard(context,false, SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/" + SPEECH_MALE_MODEL_NAME);
    copyFromAssetsToSdcard(context,false, TEXT_MODEL_NAME, mSampleDirPath + "/" + TEXT_MODEL_NAME);
    copyFromAssetsToSdcard(context,false, LICENSE_FILE_NAME, mSampleDirPath + "/" + LICENSE_FILE_NAME);
    copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME, mSampleDirPath + "/"
            + ENGLISH_SPEECH_FEMALE_MODEL_NAME);
    copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_SPEECH_MALE_MODEL_NAME, mSampleDirPath + "/"
            + ENGLISH_SPEECH_MALE_MODEL_NAME);
    copyFromAssetsToSdcard(context,false, "english/" + ENGLISH_TEXT_MODEL_NAME, mSampleDirPath + "/"
            + ENGLISH_TEXT_MODEL_NAME);
}

private void makeDir(String dirPath) {
    File file = new File(dirPath);
    if (!file.exists()) {
        file.mkdirs();
    }
}
/**
 * 将资源语音文件复制到手机SD卡中
 * @param isCover 是否覆盖已存在的目标文件
 * @param source
 * @param dest
 */
private void copyFromAssetsToSdcard(Context context,boolean isCover, String source, String dest) {
    File file = new File(dest);
    if (isCover || (!isCover && !file.exists())) {
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            is = context.getResources().getAssets().open(source);
            String path = dest;
            fos = new FileOutputStream(path);
            byte[] buffer = new byte[1024];
            int size = 0;
            while ((size = is.read(buffer, 0, 1024)) >= 0) {
                fos.write(buffer, 0, size);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
//初始化解析器
private void initialTts(Context context,int speaker) {
    this.mSpeechSynthesizer = SpeechSynthesizer.getInstance();
    this.mSpeechSynthesizer.setContext(context);
    this.mSpeechSynthesizer.setSpeechSynthesizerListener(new MyListnener());
    // 文本模型文件路径 (离线引擎使用)
    this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, mSampleDirPath + "/"
            + TEXT_MODEL_NAME);
    // 声学模型文件路径 (离线引擎使用)
    this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, mSampleDirPath + "/"
            + SPEECH_FEMALE_MODEL_NAME);
    // 请替换为语音开发者平台上注册应用获得的App ID (离线受权)
    this.mSpeechSynthesizer.setAppId(APPID);
    // 请替换为语音开发者平台注册应用获得的apikey和secretkey (在线受权)
    this.mSpeechSynthesizer.setApiKey(APIKEY,
            SECRETKEY);
    // 发音人(在线引擎),可用参数为0,1,2,3。。。(服务器端会动态增长,各值含义参考文档,以文档说明为准。0--普通女声,4--情感女声,3--普通男声,6--特殊男声。。。)
    this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, speaker+"");
    // 设置Mix模式的合成策略
    this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);
    // 受权检测接口(只是经过AuthInfo进行检验受权是否成功。)
    // 初始化tts
    mSpeechSynthesizer.initTts(TtsMode.MIX);
    // 加载离线英文资源(提供离线英文合成功能)
    mSpeechSynthesizer.loadEnglishModel(mSampleDirPath + "/" + ENGLISH_TEXT_MODEL_NAME, mSampleDirPath
                    + "/" + ENGLISH_SPEECH_FEMALE_MODEL_NAME);

}
//合成监听器
class MyListnener implements SpeechSynthesizerListener{
    @Override
    public void onSynthesizeStart(String s) {
        //合成准备工做
    }
    @Override
    public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
        //合成数据和进度的回调接口,分屡次回调
    }
    @Override
    public void onSynthesizeFinish(String s) {
        //合成正常结束,每句合成正常结束都会回调,若是过程当中出错,则回调onError,再也不回调此接口
    }
    @Override
    public void onSpeechStart(String s) {
        //播放开始,每句播放开始都会回调
    }
    @Override
    public void onSpeechProgressChanged(String s, int i) {
        //播放进度回调接口,分屡次回调
    }
    @Override
    public void onSpeechFinish(String s) {
        // 播放正常结束,每句播放正常结束都会回调,若是过程当中出错,则回调onError,再也不回调此接口
    }
    @Override
    public void onError(String s, SpeechError speechError) {
        //当合成或者播放过程当中出错时回调此接口
    }
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175

 该工具类我就很少解释了,惟一须要配置的地方在前面获取到的AppId,ApiKey和SecretKey直接替换成你本身的就能够了。该工具类作的事就是第一步将因为资源文件及Asserts下面的文件复制到SD卡上,而后初始化一个语音合成器SpeechSynthesizer。并提供放回的方法getSyntheszer供外部使用。合成监听器SpeechSynthesizerListener能处理各个阶段的事件。固然这个工具类很差,存在构造器还须要传入参数,有待改进,int speaker 为发声人,从0到7均可以使用,男声,女声,本身能够试着玩玩。api

在MainActivity使用:

  1. 布局文件咱们用一个输入框EditText和四个按钮来测试不一样的发声。 
    布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
android:background="#7EBF4B"
tools:context="com.bk120.mytest_autoanswer.MainActivity">
<EditText
    android:layout_height="120dp"
    android:layout_width="match_parent"
    android:hint="输入:"
    android:layout_marginTop="10dp"
    android:id="@+id/mainactivity_et"
    android:paddingLeft="10dp"
    android:background="@drawable/et_shape"
    />

<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_marginTop="10dp"
    >
    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:onClick="puTongWoman"
        android:layout_weight="1"
        android:text="普通女声"
        android:textSize="15sp"
        android:textColor="#71A7C7"
        android:background="@drawable/btn_shape"
        />
    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:onClick="qingGanWoman"
        android:layout_weight="1"
        android:text="情感女声"
        android:textSize="15sp"
        android:textColor="#71A7C7"
        android:background="@drawable/btn_shape"
        />
    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:onClick="puTongMan"
        android:layout_weight="1"
        android:textSize="15sp"
        android:textColor="#71A7C7"
        android:text="普通男声"
        android:background="@drawable/btn_shape"
        />
    <Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:onClick="qingGanMan"
        android:layout_weight="1"
        android:textSize="15sp"
        android:textColor="#71A7C7"
        android:text="情感男声"
        android:background="@drawable/btn_shape"
        />
</LinearLayout>
</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

2.Activity中直接获取EditText对象并处理点击事件,以下: 
MainActivity中:缓存

– 
package com.bk120.mytest_autoanswer;服务器

import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.baidu.tts.client.SpeechSynthesizer;

public class MainActivity extends Activity {
    private EditText mInput;
    private SpeechSynthesizer mSpeechSynthesizer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mInput= (EditText) this.findViewById(R.id.mainactivity_et);
}
//普通女声
public void puTongWoman(View view){
    speak(0);
}
//特殊女声
public void qingGanWoman(View view){
    speak(4);
}
//普通男声
public void puTongMan(View view){
    speak(3);
}
//特殊男声
public void qingGanMan(View view){
    speak(6);
}
private void speak(int speaker) {
    //如果每次都这样是否是会有内存问题呢?须要思考改进
    VoiceUtils utils=new VoiceUtils();
    utils.init(this,speaker);
    mSpeechSynthesizer=utils.getSyntheszer();
    String text = this.mInput.getText().toString();
    //须要合成的文本text的长度不能超过1024个GBK字节。
    if (TextUtils.isEmpty(mInput.getText())) {
        text = "你好!";
        mInput.setText(text);
    }
   this.mSpeechSynthesizer.speak(text);
}
//释放缓存
@Override
protected void onDestroy() {
    this.mSpeechSynthesizer.release();
    super.onDestroy();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

经过上面的步骤语音合成就算完事了,在没有网络链接的状况下默认speaker为0–普通女声,即点击全部按钮都是普通女声朗读出文本框中的文字,英文中文均可以,网络状态下其余按钮才能发出不一样的声音。 
网络

 结果就是这样,点击按钮就能听见朗读声音咯。图中的按钮和输入框shape文件以下,文件名分别为btn_shape和et_shape,都放在res下的drawable文件夹中,适可参考Ctrl+C吧! 
btn_shape:app

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:color="#8BE5E8" android:width="1dp"/>
<corners android:radius="5dp"/>
<solid android:color="#C46F5F"/>
</shape>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

et_shape:eclipse

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:color="#facd89" android:width="5dp"/>
<corners android:radius="8dp"/>
</shape>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

 第一次写这个东东,是否是太详细了居然写了老久了,这打字速度有点坑啊,还要多锻炼!ide