Android开发之科大讯飞语音合成与播报

Android开发之科大讯飞语音合成与播报Android开发之科大讯飞语音合成与播报_科大讯飞语音播报


今天做一个稍微复杂点的,Android集成科大讯飞实现语音合成与播报功能。


老规矩,直接进入正题。

一、效果图

在这里插入图片描述

二、打开讯飞开放平台,注册登录后,找到我的应用,点击创建新应用。

在这里插入图片描述

三、填写相关信息,然后点击提交。

在这里插入图片描述

四、点击创建好的应用。

在这里插入图片描述

五、可以看到APPID信息。

在这里插入图片描述

六、往下滑可以下载SDK。

在这里插入图片描述

七、下载到本地后,解压。

在这里插入图片描述
这里重点就是这个libs文件夹中的内容了。

八、把刚才解压后的libs中的文件复制到项目中的libs下。

在这里插入图片描述

1.此时这个Msc.jar还是不可用的,下面鼠标右键点击它。

在这里插入图片描述

2.点击Add As Library…

在这里插入图片描述

3.点击OK,此时你可以看到它可以展开了,就说明你的app模块中已经添加了这个jar的依赖了。

在这里插入图片描述

九、复制assets文件夹到项目中。

在这里插入图片描述

十、粘贴到main下面,如下图所示。

在这里插入图片描述

十一、配置项目,打开build.gradle。

	//资源设置
    sourceSets { 
   
        main { 
   
            jniLibs.srcDirs = ['libs']
        }
    }

十二、AndroidManifest.xml中配置权限。

	<!--连接网络权限,用于执行云端语音能力 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <!--读取网络信息状态 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--获取当前wifi状态 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!--允许程序改变网络连接状态 -->
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <!--读取手机信息权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <!--外存储写权限,构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--外存储读权限,构建语法需要用到此权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

十三、新建一个MyApplication类。

在这里插入图片描述

package com.example;

import android.app.Application;

import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechUtility;
import org.xutils.x;
public class MyApplication extends Application { 
   

    @Override
    public void onCreate() { 
   
        SpeechUtility.createUtility(MyApplication.this, SpeechConstant.APPID +"=\n" +
                "7b6e5ba7");
        super.onCreate();
        x.Ext.init(this);
        x.Ext.setDebug(BuildConfig.DEBUG);  //这个会影响性能
    }
}


1.然后在AndroidManifest.xml中配置

在这里插入图片描述

十四、主布局文件(activity_yy)

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="750dp" android:orientation="vertical">
    <include layout="@layout/main_title_bar"/>
    <EditText android:id="@+id/et_text" android:gravity="top|left" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/Theme.TYLDApp"/>

    <Button android:id="@+id/btn_play" android:text="开始播放" android:layout_width="200dp" android:textSize="20dp" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:background="@drawable/register_selector" android:layout_marginLeft="100dp" android:textColor="@color/white"/>
    <Button android:id="@+id/btn_cancel" android:text="取消" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:textColor="@color/white" android:textSize="20dp" android:background="@drawable/register_selector" android:layout_marginLeft="100dp"/>

    <Button android:id="@+id/btn_pause" android:layout_width="200dp" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="20dp" android:background="@drawable/register_selector" android:layout_marginLeft="100dp" android:layout_marginTop="10dp" android:text="暂停播放" />

    <Button android:id="@+id/btn_resume" android:layout_width="200dp" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="20dp" android:background="@drawable/register_selector" android:layout_marginLeft="100dp" android:layout_marginTop="10dp" android:text="继续播放" />
    <LinearLayout android:gravity="center_vertical" android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:paddingStart="6dp" android:paddingEnd="6dp">

        <View android:layout_width="0dp" android:layout_height="0.5dp" android:layout_weight="1" android:background="#000" />

        <TextView android:layout_marginStart="6dp" android:layout_marginEnd="6dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置" android:textColor="#000" android:textSize="16sp" />

        <View android:layout_width="0dp" android:layout_height="0.5dp" android:layout_weight="1" android:background="#000" />
    </LinearLayout>

    <!--设置发音人-->
    <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" android:paddingStart="6dp" android:paddingEnd="6dp">

        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置发音人:" android:textColor="#000" android:textSize="16sp" />

        <Spinner android:id="@+id/spinner" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" />
    </LinearLayout>
    <!--设置语速-->
    <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:gravity="center_vertical" android:paddingStart="6dp" android:paddingEnd="6dp">

        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置语速:" android:textColor="#000" android:textSize="16sp" />

        <SeekBar android:id="@+id/sb_speed" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" android:progress="50" />
    </LinearLayout>

    <!--设置音调-->
    <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:gravity="center_vertical" android:paddingStart="6dp" android:paddingEnd="6dp">

        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置音调:" android:textColor="#000" android:textSize="16sp" />

        <SeekBar android:id="@+id/sb_pitch" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" android:progress="50" />
    </LinearLayout>

    <!--设置音量-->
    <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:gravity="center_vertical" android:paddingStart="6dp" android:paddingEnd="6dp">

        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="设置音量:" android:textColor="#000" android:textSize="16sp" />

        <SeekBar android:id="@+id/sb_volume" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" android:progress="50" />
    </LinearLayout>

</LinearLayout>


十五、主java文件(YybbActivity)

package com.example.activity;


import static com.iflytek.cloud.VerifierResult.TAG;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.MemoryFile;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.example.R;
import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechEvent;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SynthesizerListener;
import com.iflytek.cloud.msc.util.FileUtil;
import com.iflytek.cloud.msc.util.log.DebugLog;

import java.util.Vector;

public class YybbActivity extends AppCompatActivity implements View.OnClickListener,AdapterView.OnItemSelectedListener { 
   
    //语速
    private String speedValue = "50";
    //音调
    private String pitchValue = "50";
    //音量
    private String volumeValue = "50";
    //输入框
    private EditText etText;
    // 语音合成对象
    private SpeechSynthesizer mTts;
    // 默认发音人
    private String voicer = "xiaoyan";
    //发音人名称
    private static final String[] arrayName = { 
   "讯飞小燕", "讯飞许久", "讯飞小萍", "讯飞小婧", "讯飞许小宝"};

    //发音人值
    private static final String[] arrayValue = { 
   "xiaoyan", "aisjiuxu", "aisxping", "aisjinger", "aisbabyxu"};

    //数组适配器
    private ArrayAdapter<String> arrayAdapter;
    // 引擎类型
    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    //播放的文字
    String text = " 属性:昔刘涓子晋末于丹阳郊外照射,忽见一物,高二丈许,射而中之,如雷电声若风雨。其夜不敢前追,诘旦率门徒子弟数人,寻纵至山下,见一小儿提罐,问何往为。";
    private Vector<byte[]> container = new Vector<>();
    //内存文件
    MemoryFile memoryFile;
    //总大小
    public volatile long mTotalSize = 0;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_yy);
         //请求权限
        requestPermissions();
        initView();
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(this, mTtsInitListener);
    }
    /** * 初始化页面 */
    private void initView() { 
   
        etText = findViewById(R.id.et_text);
        findViewById(R.id.btn_play).setOnClickListener(this);
        findViewById(R.id.btn_cancel).setOnClickListener(this);
        findViewById(R.id.btn_pause).setOnClickListener(this);
        findViewById(R.id.btn_resume).setOnClickListener(this);
       SeekBar sbSpeed = findViewById(R.id.sb_speed);
        SeekBar sbPitch = findViewById(R.id.sb_pitch);
        SeekBar sbVolume = findViewById(R.id.sb_volume);
        Spinner spinner = findViewById(R.id.spinner);
         //将可选内容与ArrayAdapter连接起来
        arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, arrayName);
        //设置下拉列表的风格
        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        //将adapter 添加到spinner中
        spinner.setAdapter(arrayAdapter);
        //添加事件Spinner事件监听
        spinner.setOnItemSelectedListener(this);

        setSeekBar(sbSpeed, 1);
        setSeekBar(sbPitch, 2);
        setSeekBar(sbVolume, 3);
    }

    /** * 请求权限 */
    private void requestPermissions() { 
   
        try { 
   
            //Android6.0及以上版本
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
   
                int permission = ActivityCompat.checkSelfPermission(this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE);
                if (permission != PackageManager.PERMISSION_GRANTED) { 
   
                    ActivityCompat.requestPermissions(this, new String[]
                            { 
   Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                    Manifest.permission.WRITE_SETTINGS,
                                    Manifest.permission.READ_EXTERNAL_STORAGE}, 0x0010);
                }
            }
        } catch (Exception e) { 
   
            e.printStackTrace();
        }
    }
    /** * 权限请求返回结果 */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 
   
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
    /** * 页面点击事件 * @param v 控件 */
    @Override
    public void onClick(View v) { 
   
        if (mTts == null) { 
   
            this.showTip("创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化");
            return;
        }
        switch (v.getId()) { 
   
            case R.id.btn_play://开始合成
                //输入文本
                String etStr = etText.getText().toString().trim();
                if (!etStr.isEmpty()) { 
   
                    text = etStr;
                }
                //设置参数
                setParam();
                //开始合成播放
                int code = mTts.startSpeaking(text, mTtsListener);
                if (code != ErrorCode.SUCCESS) { 
   
                    showTip("语音合成失败,错误码: " + code);
                }
                break;

            case R.id.btn_cancel://取消合成
                mTts.stopSpeaking();
                break;
            case R.id.btn_pause://暂停播放
                mTts.pauseSpeaking();
                break;
            case R.id.btn_resume://继续播放
                mTts.resumeSpeaking();
                break;

            default:
                break;
        }
    }
    /** * 初始化监听。 */
    private InitListener mTtsInitListener = new InitListener() { 
   
        @Override
        public void onInit(int code) { 
   
            Log.i(TAG, "InitListener init() code = " + code);
            if (code != ErrorCode.SUCCESS) { 
   
                showTip("初始化失败,错误码:" + code);
            } else { 
   
                showTip("初始化成功");
            }
        }
    };
    /** * Toast提示 * @param msg */
    private void showTip(String msg) { 
   
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
    /** * 参数设置 * * @return */
    private void setParam() { 
   
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        // 根据合成引擎设置相应参数
        if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) { 
   
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
            //支持实时音频返回,仅在synthesizeToUri条件下支持
            mTts.setParameter(SpeechConstant.TTS_DATA_NOTIFY, "1");
            // 设置在线合成发音人
            mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
             //设置语速
            mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
            //设置音调
            mTts.setParameter(SpeechConstant.PITCH, pitchValue);
            //设置音量
            mTts.setParameter(SpeechConstant.VOLUME, volumeValue);
        } else { 
   
            mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
            mTts.setParameter(SpeechConstant.VOICE_NAME, "");
        }
        // 设置播放合成音频打断音乐播放,默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "false");
        // 设置音频保存路径,保存音频格式支持pcm、wav
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "pcm");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, getExternalFilesDir(null) + "/msc/tts.pcm");
    }
    /** * 合成回调监听。 */
    private SynthesizerListener mTtsListener = new SynthesizerListener() { 
   
        //开始播放
        @Override
        public void onSpeakBegin() { 
   
            Log.i(TAG, "开始播放");
        }

        //暂停播放
        @Override
        public void onSpeakPaused() { 
   
            Log.i(TAG, "暂停播放");
        }

        //继续播放
        @Override
        public void onSpeakResumed() { 
   
            Log.i(TAG, "继续播放");
        }

        //合成进度
        @Override
        public void onBufferProgress(int percent, int beginPos, int endPos, String info) { 
   
            Log.i(TAG, "合成进度:" + percent + "%");
        }

        //播放进度
        @Override
        public void onSpeakProgress(int percent, int beginPos, int endPos) { 
   
            // 播放进度
            Log.i(TAG, "播放进度:" + percent + "%");
            SpannableStringBuilder style = new SpannableStringBuilder(text);
            style.setSpan(new BackgroundColorSpan(Color.RED), beginPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            etText.setText(style);
        }

        //播放完成
        @Override
        public void onCompleted(SpeechError error) { 
   
            if (error == null) { 
   
                Log.i(TAG, "播放完成," + container.size());
                DebugLog.LogD("播放完成," + container.size());
                for (int i = 0; i < container.size(); i++) { 
   
                    //写入文件
                    writeToFile(container.get(i));
                }
                //保存文件
                FileUtil.saveFile(memoryFile, mTotalSize, getExternalFilesDir(null) + "/1.pcm");
            } else { 
   
                //异常信息
                showTip(error.getPlainDescription(true));
            }
        }
        /** * 写入文件 */
        private void writeToFile(byte[] data) { 
   
            if (data == null || data.length == 0) { 
   
                return;
            }
            try { 
   
                if (memoryFile == null) { 
   
                    Log.i(TAG, "memoryFile is null");
                    String mFilepath = getExternalFilesDir(null) + "/1.pcm";
                    memoryFile = new MemoryFile(mFilepath, 1920000);
                    memoryFile.allowPurging(false);
                }
                memoryFile.writeBytes(data, 0, (int) mTotalSize, data.length);
                mTotalSize += data.length;
            } catch (Exception e) { 
   
                e.printStackTrace();
            }
        }

        //事件
        @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.i(TAG, "session id =" + sid);
            }

            //当设置SpeechConstant.TTS_DATA_NOTIFY为1时,抛出buf数据
            if (SpeechEvent.EVENT_TTS_BUFFER == eventType) { 
   
                byte[] buf = obj.getByteArray(SpeechEvent.KEY_EVENT_TTS_BUFFER);
                Log.i(TAG, "bufis =" + buf.length);
                container.add(buf);
            }
        }

    };
/** * 选中 */
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 
   
        voicer = arrayValue[position];
    }
    @Override
    public void onNothingSelected(AdapterView<?> parent) { 
   
    }
    //设置SeekBar
    private void setSeekBar(SeekBar seekBar, final int type) { 
   

        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 
   
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 
   
                switch (type) { 
   
                    case 1://设置语速 范围 1~100
                        speedValue = Integer.toString(progress);
                        break;
                    case 2://设置音调  范围 1~100
                        pitchValue = Integer.toString(progress);
                        break;
                    case 3://设置音量  范围 1~100
                        volumeValue = Integer.toString(progress);
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) { 
    }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) { 
    }
        });
    }

}

到这里就结束了,你可以试试哦

今天的文章Android开发之科大讯飞语音合成与播报分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/65444.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注