百度语音合成(Android简单实现)

本文详细介绍如何使用百度语音合成SDK实现离线和在线语音合成,包括注册账号、创建应用、下载并配置SDK及模型文件的步骤。文章还提供了完整的Java源代码示例,展示如何在Android应用中集成语音合成功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 简介

百度开发文档

https://ai.baidu.com/docs#/TTS-Android-SDK/top

本文实现了1种离线语言合成和多种在线语音合成。

百度语音合成需要经过以下几个步骤,先注册百度账号,再创建百度语音应用,然后下载百度语音的SDK(jar文件)、语音模型(dat文件)、NDK so库文件,接着将jar文件放在Project->app->libs目录下、dat文件放在Project->src->main->assets目录下、NDK so库文件放在Project->src->main->jniLibs目录下(如果目录不存在,手动建立即可),最后调用相应的方法即可。

注意:(1)要实现离线语音合成Android工程的包名必须与在创建的百度语音应用时输入的包名相同;

(2)需要实现将assets下的语音模型复制到SD卡上。

2 源代码

工程目录

2.1 java源代码

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.baidu.tts.auth.AuthInfo;
import com.baidu.tts.client.SpeechSynthesizer;
import com.baidu.tts.client.TtsMode;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    Button buttonSpeak = null;
    Button buttonStop = null;

    // 语言模型文件路径
    private String dirFile = Environment.getExternalStorageDirectory() + File.separator +"my_voice"+ File.separator ;
    private String textFilename = "bd_etts_text.dat";
    private String modelFilename ="bd_etts_speech_f7.dat";

    // 百度语言的账号
    private String appId = "17246190";
    private String appKey = "UfrBeadhzS2UhuDiGuPa8TlD";
    private String secretKey = "G73dYXjcEgZflVgWURVhAuVUM25nAuAT";

    // TtsMode.MIX; 离在线融合,在线优先; TtsMode.ONLINE 纯在线;
    private TtsMode ttsMode = TtsMode.MIX;

    // 设置语言合成器
    protected SpeechSynthesizer mSpeechSynthesizer = null;

    // 设置TAG
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化权限
        initPermission();

        // 初始化语言合成
        initTTS();

        // 初始化控件
        this.initView();
    }

    /**
     * 初始化控件
     */
    private void initView(){
        this.buttonSpeak = findViewById(R.id.speak);
        this.buttonSpeak.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSpeechSynthesizer.speak("Hello world !");
            }
        });

        this.buttonStop = findViewById(R.id.stop);
        this.buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stop();
            }
        });
    }

    /**
     * 初始化语言合成
     */
    private void initTTS() {

        // 1. 获取实例
        this.mSpeechSynthesizer = SpeechSynthesizer.getInstance();
        this.mSpeechSynthesizer.setContext(MainActivity.this);

        // 2. 设置appId,appKey.secretKey
        int result = this.mSpeechSynthesizer.setAppId(appId);
        result = this.mSpeechSynthesizer.setApiKey(appKey, secretKey);
        System.out.println("https://ai.baidu.com/docs#/TTS-Android-SDK/top-错误码:" + result);

        // 3. 支持离线的话,需要设置离线模型
        boolean isMix = this.ttsMode.equals(TtsMode.MIX);
        if (isMix) {
            if(isDirExist(dirFile)){
                copyAssetsToSdcard(MainActivity.this, dirFile+textFilename, textFilename);
                copyAssetsToSdcard(MainActivity.this, dirFile+modelFilename, modelFilename);
            }
            // 设置语言模型
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, dirFile+textFilename);
            // 设置使用的语言模型
            mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, dirFile+modelFilename);

            // 检查离线授权文件是否下载成功
            AuthInfo authInfo = mSpeechSynthesizer.auth(this.ttsMode);
            // 文本模型文件路径 (离线引擎使用)
            if(authInfo.isSuccess()){
                print("授权成功!");
            }else {
                print("授权失败!");
            }
        }

        // 4. 以下setParam 参数选填。不填写则默认值生效
        // 设置在线发声音人: 0 普通女声(默认),本文仅仅设置了1种离线语言,其他的3中离线语言可以自己下载
        this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEAKER, "0");
        // 设置合成的音量,0-15 ,默认 5
        this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_VOLUME, "5");
        // 设置合成的语速,0-15 ,默认 5
        this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_SPEED, "5");
        // 设置合成的语调,0-15 ,默认 5
        this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_PITCH, "5");

        // 该参数设置为TtsMode.MIX生效。即纯在线模式不生效。
        // MIX_MODE_DEFAULT 默认 ,wifi状态下使用在线,非wifi离线。在线状态下,请求超时6s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线,非wifi离线。在线状态下, 请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_NETWORK , 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线
        this.mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_DEFAULT);

        // 5. 初始化
        result = this.mSpeechSynthesizer.initTts(ttsMode);
        System.out.println("https://ai.baidu.com/docs#/TTS-Android-SDK/top-错误码:" + result);
    }

    private void stop() {
        print("停止合成引擎 按钮已经点击");
        int result = this.mSpeechSynthesizer.stop();
        System.out.println("https://ai.baidu.com/docs#/TTS-Android-SDK/top-错误码:" + result);
    }

    private void print(String message) {
        Log.i(TAG, message);
    }

    @Override
    protected void onDestroy() {
        if (this.mSpeechSynthesizer != null) {
            this.mSpeechSynthesizer.stop();
            this.mSpeechSynthesizer.release();
            this.mSpeechSynthesizer = null;
            print("释放资源成功");
        }
        super.onDestroy();
    }


    /**
     * 下面是android 6.0以上的动态授权
     * android 6.0 以上需要动态申请权限
     */
    private void initPermission() {
        String[] permissions = {
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.MODIFY_AUDIO_SETTINGS,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_SETTINGS,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.ACCESS_WIFI_STATE,
                Manifest.permission.CHANGE_WIFI_STATE
        };

        ArrayList<String> toApplyList = new ArrayList<String>();

        for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
                // 进入到这里代表没有权限.
            }
        }
        String[] tmpList = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }

    }

    /**
     * 检查目录是否存在
     * @param dirPath 目录的路径
     * @return true代表目录存在
     */
    private boolean isDirExist(String dirPath){
        File dirFile = new File(dirPath);
        if(dirFile.exists()){
            return true;
        }else {
            return dirFile.mkdirs();
        }
    }

    /**
     * 复制Assets目录下的文件到SD卡
     * @param context 代表Activity.this
     * @param filePath 文件路径
     * @param fileName 文件名
     */
    private void copyAssetsToSdcard(Context context, String filePath, String fileName){
        File file = new File(filePath);

        // Determine if the file exists
        if (!file.exists()) {

            // Initial the stream
            InputStream inputStream = null;
            FileOutputStream fileOutputStream = null;

            try {
                inputStream = context.getResources().getAssets().open(fileName);
                fileOutputStream = new FileOutputStream(filePath);
                byte[] buffer = new byte[1024];
                int bufferSize = 0;
                // Copy the data
                while ((bufferSize = inputStream.read(buffer, 0, 1024)) >= 0) {
                    fileOutputStream.write(buffer, 0, bufferSize);
                }

                // Close the stream
                inputStream.close();
                fileOutputStream.close();

            } catch (IOException e) {
                Log.d("Baidu-TTS","Baidu-TTS write dat error!");
                e.printStackTrace();
            }
        }
    }
}
 

2.2 xml布局源代码

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:orientation="horizontal"
        android:weightSum="3">

        <Button
            android:id="@+id/speak"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:lines="2"
            android:text="合成并播放"
            android:textSize="12dp" />

        <Button
            android:id="@+id/stop"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="2"
            android:lines="2"
            android:text="停止合成引擎"
            android:textSize="12dp" />

    </LinearLayout>

</LinearLayout>

2.3 xml的manifests文件的权限

<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <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.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值