2015-12-05 19:16:43 yangzhaomuma 阅读数 5521
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5925 人正在学习 去看看 杨波

Android语音识别,简单的理解就是把语音转化为文字。

在日常中,语音识别,车载导航、语音输入等,虽然不一定准确,但用途广泛。

这里就介绍下谷歌原生的语音识别与百度的语音识别

谷歌语音识别

谷歌语音识别做法很简单

1、首先检测本地是否有语音识别工具,比如谷歌语音搜索,如果没有就结束;

2、用intent意图表示语音识别;

3、发送这个intent,并等待返回;

4、显示返回的内容;

具体的代码如下:

package com.example.speak_csdn;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;

public class MainActivity extends Activity {

	final int RESPONCERESULT=99;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button btnButton=(Button)findViewById(R.id.mybtn);
		btnButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				speak();
			}
		});
	}

	public void speak()
	{
            try{  
             //通过Intent传递语音识别的模式,开启语音  
             Intent intent=new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);  
             //语言模式和自由模式的语音识别  
             intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);  
             //提示语音开始  
             intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "开始语音");  
             
             //开始语音识别  
             startActivityForResult(intent, RESPONCERESULT);  
             }catch (Exception e) {  
                 // TODO: handle exception  
                 e.printStackTrace();  
                 Toast.makeText(getApplicationContext(), "找不到语音设备", 1).show();  
             }  
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		
		//回调获取从谷歌得到的数据   
        if(requestCode==RESPONCERESULT && resultCode==RESULT_OK){  
            //取得语音的字符  
            ArrayList<String> results=data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);  
            //谷歌可能有许多语音类似的返回,越往上优先级越高,这里列出所有的返回并拼接成字符串   
            String resultString="";  
            for(int i=0;i<results.size();i++){  
                resultString+=results.get(i);  
            }  
            Toast.makeText(this, resultString, 1).show();  
        }  
		super.onActivityResult(requestCode, resultCode, data);
	}
	
	

}

代码完成了,注意要加上网络访问权限,因为这个是在线语音识读,代码关键的语句在以下几句:

 //通过Intent传递语音识别的模式,开启语音  
             Intent intent=new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);  
             //语言模式和自由模式的语音识别  
             intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);  
             //提示语音开始  
             intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "开始语音");  
             
             //开始语音识别  
             startActivityForResult(intent, RESPONCERESULT);  


对应这个的布局语句很简单,只有一个button按钮。给这个按钮绑定事件,点击运行...


这和我们预料的不同啊,网络没有问题,测试了WIFI和GPRS都是同样的结果。最终这只能归结为谷歌后台服务无法连接,你或者可以通过翻墙来看到效果。

悲伤。

那现在我们看看中国本地的语音识别,百度语音。

百度语音识别

百度语音识别,应用的是百度提供的SDK来实现。这个在百度的开放平台上可以看到很详细的说明。
应用它的步骤如下:
1、下载jar包;
2、添加权限;
3、在代码中,用给定的API来做语音识别;
4、显示返回内容;

jar包、so文件下载

以下是从百度开放平台上下载的jar包以及so文件,用于后续的开发使用

权限添加

AndroidManifest.xml中添加需要的权限,如下:
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <!-- 蓝牙录音 -->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <!-- 某些手机启动SCO音频连接需要此权限 -->
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <!-- 蓝牙录音检测耳机状态 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />

代码中使用API

这个就是使用API的过程,如下代码:
package com.example.baiduspeak_csdn;

import java.util.ArrayList;

import com.baidu.voicerecognition.android.ui.BaiduASRDigitalDialog;
import com.baidu.voicerecognition.android.ui.DialogRecognitionListener;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;

public class MainActivity extends Activity {

	//百度自定义对话框
	 private BaiduASRDigitalDialog mDialog = null;
	 //对话框监听
	 private DialogRecognitionListener mRecognitionListener;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Button btnButton=(Button)findViewById(R.id.mybtn);
		btnButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				speak_Baidu();
			}
		});
		
		mRecognitionListener = new DialogRecognitionListener() {

            @Override
            public void onResults(Bundle results) {
                ArrayList<String> rs = results != null ? results.getStringArrayList(RESULTS_RECOGNITION) : null;
                if (rs != null && rs.size() > 0) {
                	Toast.makeText(MainActivity.this, rs.get(0), 1).show();
                }

            }
        };
	}
    //百度语音识别
	public void speak_Baidu()
	{
		if (mDialog != null) {
            mDialog.dismiss();
        }
        Bundle params = new Bundle();
        //设置注册百度开放平台得到的值 API_KEY,SECRET_KEY
        params.putString(BaiduASRDigitalDialog.PARAM_API_KEY, Constants.API_KEY);
        params.putString(BaiduASRDigitalDialog.PARAM_SECRET_KEY, Constants.SECRET_KEY);
        //设置对话框模式
        params.putInt(BaiduASRDigitalDialog.PARAM_DIALOG_THEME, Config.DIALOG_THEME);
        //根据设置新建对话框
        mDialog = new BaiduASRDigitalDialog(this, params);
        //设置对话框的监听
        mDialog.setDialogRecognitionListener(mRecognitionListener);
        //对话框设置
	    mDialog.getParams().putInt(BaiduASRDigitalDialog.PARAM_PROP, Config.CURRENT_PROP);
	    mDialog.getParams().putString(BaiduASRDigitalDialog.PARAM_LANGUAGE, Config.getCurrentLanguage());
	    mDialog.getParams().putBoolean(BaiduASRDigitalDialog.PARAM_START_TONE_ENABLE, Config.PLAY_START_SOUND);
	    mDialog.getParams().putBoolean(BaiduASRDigitalDialog.PARAM_END_TONE_ENABLE, Config.PLAY_END_SOUND);
	    mDialog.getParams().putBoolean(BaiduASRDigitalDialog.PARAM_TIPS_TONE_ENABLE, Config.DIALOG_TIPS_SOUND);
	    mDialog.show();
	}
	 @Override
	    protected void onDestroy() {
	        if (mDialog != null) {
	            mDialog.dismiss();
	        }
	        super.onDestroy();
	    }

}
代码也只是简单的定义一个按钮,按钮绑定一个事件。
事件发起时,我们设定了挺多参数,重要的有平台分配的APP_KEY,SECRET_KEY,PROP,语言的选择等。
根据这些,百度对我们发出的声音,在服务端,得到匹配的内容并返回前端。
效果如下:


这个效果我们是能看到的。简单的用法就是这样的。类似谷歌语音,一个请求即可。

源码

源码包括以上的谷歌和百度语音识别,可供下载:

2018-04-15 16:27:23 yzy565280261 阅读数 752
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5925 人正在学习 去看看 杨波

在我们的项目里,我负责的功能是实现在场景中通过麦克风输入语音命令进行交互,这首先就要求工程链接一个语音识别库。

常用的比较好的语音识别库有讯飞平台、百度云、腾讯云等等。

其中,亲加通讯和百度的SDK主要是面对移动端,TTS主要面对Windows,科大讯飞移动端桌面端都有。

这里我们选择百度云,因为我发现百度云除了使用SDK以外,它可以选择一种不用下载配置SDK的方式,即REST API:

链接:http://ai.baidu.com/docs#/ASR-API/top


下面我们直接上代码
在unity中新建一个脚本

private string token;                           //access_token
    private string cuid = ";        //用户标识
    private string format = "wav";                  //语音格式
    private int rate = 8000;                        //采样率
    private int channel = 1;                        //声道数
    private string speech;                          //语音数据,进行base64编码
    private int len;                                //原始语音长度
    private string lan = "zh";                      //语种
 
    private string grant_Type = "client_credentials";  
    private string client_ID = ";                       //百度appkey
    private string client_Secret = ";                   //百度Secret Key
 
    private string baiduAPI = "http://vop.baidu.com/server_api";
    private string getTokenAPIPath = "https://openapi.baidu.com/oauth/2.0/token";
 
    private Byte[] clipByte;
 
    /// <summary>
    /// 转换出来的TEXT
    /// </summary>
    public static string audioToString;
 
    private AudioSource aud;
    private int audioLength;//录音的长度
以上是需要声明的变量。其中AppKey和SecretKey需要你注册成为百度的开发者,然后再应用管理中去看
下图:

继续代码:

/// <summary>
    /// 获取百度用户令牌
    /// </summary>
    /// <param name="url">获取的url</param>
    /// <returns></returns>
    private IEnumerator GetToken(string url)
    {
        WWWForm getTForm = new WWWForm();
        getTForm.AddField("grant_type", grant_Type);
        getTForm.AddField("client_id", client_ID);
        getTForm.AddField("client_secret", client_Secret);
 
        WWW getTW = new WWW(url, getTForm);
        yield return getTW;
        if (getTW.isDone)
        {
            if (getTW.error == null)
            {
                token = JsonMapper.ToObject(getTW.text)["access_token"].ToString();
                StartCoroutine(GetAudioString(baiduAPI));
            }
            else
                Debug.LogError(getTW.error);
        }
    }
上面这段代码用于获取百度的Token,有了Token才有权使用API。

然后是发送转换请求的方法:
/// <summary>
    /// 把语音转换为文字
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private IEnumerator GetAudioString(string url)
    {
        JsonWriter jw = new JsonWriter();
        jw.WriteObjectStart();
        jw.WritePropertyName("format");
        jw.Write(format);
        jw.WritePropertyName("rate");
        jw.Write(rate);
        jw.WritePropertyName("channel");
        jw.Write(channel);
        jw.WritePropertyName("token");
        jw.Write(token);
        jw.WritePropertyName("cuid");
        jw.Write(cuid);
        jw.WritePropertyName("len");
        jw.Write(len);
        jw.WritePropertyName("speech");
        jw.Write(speech);
        jw.WriteObjectEnd();
        WWWForm w = new WWWForm();
 
 
        WWW getASW = new WWW(url, Encoding.Default.GetBytes(jw.ToString()));
        yield return getASW;
        if (getASW.isDone)
        {
            if (getASW.error == null)
            {
                JsonData getASWJson = JsonMapper.ToObject(getASW.text);
                if (getASWJson["err_msg"].ToString() == "success.")
                {
                    audioToString = getASWJson["result"][0].ToString();
                    if (audioToString.Substring(audioToString.Length - 1) == ",")
                        audioToString = audioToString.Substring(0, audioToString.Length - 1);
                    Debug.Log(audioToString);
                }
            }
            else
            {
                Debug.LogError(getASW.error);
            }
        }
    }
到目前为止,链接百度云语音就完成了,之后我们再继续实现unity麦克风录入音源以及具体的识别过程。
2014-06-17 09:38:00 zpf8861 阅读数 3902
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5925 人正在学习 去看看 杨波

百度语义理解开放平台面向互联网开发者提供自然语言文本的解析服务,也就是可以根据文本的意图解析成相应的表示。

为了易于人阅读,同时也方便机器解析和生成,意图表示协议采用 json 语言进行描述,采用 gb18030 编码。 

json 语言的基本概念: 
1、属性名/属性值 
即键值对(key-value) 
2、数组 
在 json 中是“[]”括起来的内容,数据结构为 ["value1","value2",...],取值方式和所有语言中一样,使用索引获取,属性值的类型可以是数字、字符串、数组、对象。 
3、对象 
在 json 中表示为“{}”括起来的内容,数据结构为 {key1:value1,key2:value2,...}的键值对的结构。在面向对象的语言中,key 为对象的属性,value 为对应的属性值,所以很容易理解,取值方法为对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象几种。 

自然语言文本(以下简称 query)。query 的意图表示由如下键值对和数组构成: 
1、raw_text:用户的原始输入文本 
2、parsed_text:经过分词,纠错,改写处理后的文本 
3、version:协议版本号 
4、results:意图表示数组 

从服务器中得到的json数据就是按照这样的几个部分组成的,例如 “北京天气”对应的json结构如下

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. query:北京明天天气   
  2. {   
  3.  "raw_text":"北京明天天气",   
  4.  "parsed_text":"北京 明天 天气",   
  5.  "results":[   
  6.  {   
  7.  "domain":"weather",   
  8.  "intent":"query",   
  9.  "score":1,    
  10.  "object":{   
  11.  "date": "2013-09-25,2013-09-25",   
  12. "region":"北京"   
  13.  }   
  14.  }   
  15.  ]   
  16. }  
在“百度语义理解开放平台 意图表示协议”文档中有详细的介绍,这篇文章主要介绍如何通过代码对这样的语义模型结果进行解析,并对解析的结果进行相应的操作。

下面的代码就是对服务器返回的json数据结构进行解析的过程,开发者首先需要了解json数据是怎么的键值对,然后一层一层解析就可以,根据不同的语义,分发到不同的操作中。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void handleResult(String result) {  
  2.         try {  
  3.             JSONObject r = new JSONObject(result);  
  4.             result = r.optString("json_res");  
  5.             r = new JSONObject(result);  
  6.             String query = r.optString("raw_text");  
  7.             if (!TextUtils.isEmpty(query)) {  
  8.                 mAdapter.add(new ChatItem(query));  
  9.                 mAdapter.notifyDataSetChanged();  
  10.             }  
  11.             JSONArray commands = r.optJSONArray("results");  
  12.             JSONObject command = null;  
  13.             String type = null;  
  14.             if (commands != null && commands.length() > 0) {  
  15.                 command = commands.optJSONObject(0);  
  16.                 type = command.optString("domain");  
  17.             } else {  
  18.                 commands = r.optJSONArray("commandlist");  
  19.                 if (commands != null && commands.length() > 0) {  
  20.                     command = commands.optJSONObject(0);  
  21.                     type = command.optString("commandtype");  
  22.   
  23.                 }  
  24.             }  
  25.             if (!TextUtils.isEmpty(type)) {  
  26.                 Log.i("TYPE", type);  
  27.                 new CommandProcessorTask().execute(mProcessors.getProcessor(type), command);  
  28.             }  
  29.         } catch (JSONException e) {  
  30.   
  31.             e.printStackTrace();  
  32.         }  
  33.     }  

结果是以String格式返回的,所以首先,将该字符串转为JSONObject,然后解析"json_res"对应的字符串,再生产JSONObject,之后解析"raw_text"对应的文本,然后一步步的把每个键值对应的数据提取出来,其中“domain”对应的是语义的领域,可以作为区分语意的type类型分发到不同操作。
2018-12-26 22:45:35 qq_36973838 阅读数 6400
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5925 人正在学习 去看看 杨波

我是一名2016级电子信息工程的学生,这是第一次发博客,因为经常在这里查资料 ,自己也应该贡献一点经验吧,也可以当是记录自己学习的过程吧。

最近在自学python,然后18年9月份正好python加入计算机二级,再然后我趁这个机会就混过了。

百度了一下语音识别,有很许多厂商提供语音识别服务,比如:阿里云、百度AI平台、腾讯云、讯飞AI…

大家可以尝试一下其他的免费平台,我这里选择的是百度语音识别,当然需要注册一个百度云平台的账号,附上网址点击直达

支持的语音格式

原始 PCM 的录音参数必须符合 8k/16k 采样率、16bit 位深、单声道,支持的格式有:pcm(不压缩)、wav(不压缩,pcm编码)、amr(压缩格式)。
我这里采用的是采样率为16KHz、单声道、wav格式的录音参数。

附上录音的源代码
这里需要pyaudio和wave库
LuYin(5, ‘test.wav’)表示录音5秒,文件名为test.wav

import pyaudio
import wave
def LuYin(Time,filename):
    CHUNK = 1024              #wav文件是由若干个CHUNK组成的,CHUNK我们就理解成数据包或者数据片段。
    FORMAT = pyaudio.paInt16  #这个参数后面写的pyaudio.paInt16表示我们使用量化位数 16位来进行录音。
    CHANNELS = 1              #代表的是声道,这里使用的单声道。
    RATE = 16000              # 采样率16k
    RECORD_SECONDS = Time     #采样时间
    WAVE_OUTPUT_FILENAME = filename   #输出文件名

    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)

    print("* 录音开始")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)

    print("* 录音结束")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

注意事项

如果需要使用实时识别、长语音、唤醒词、语义解析等其它语音功能,请使用Android或者iOS SDK 或 Linux C++ SDK 等。

请严格按照文档里描述的参数进行开发,特别请关注原始录音参数以及语音压缩格式的建议,否则会影响识别率,进而影响到产品的用户体验。

目前系统支持的语音时长上限为60s,请不要超过这个长度,否则会返回错误。(摘自官方文档)

获取tokent

tokent(鉴权认证机制)相当于是自己的身份,有个这个合格的身份平台才会给你提供服务。
可以把tokent获取出来直接使用,不用每一次都获取,但是这个tokent隔一段时间会失效,我感觉是一个月左右/笑哭

import requests
import json
def Gettokent():
    baidu_server = "https://openapi.baidu.com/oauth/2.0/token?"
    grant_type = "client_credentials"
    #API Key
    client_id = "你的API Key"
    #Secret Key
    client_secret = "你的Secret Key"

    #拼url
    url = 'https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(client_id, client_secret)
    #print(url)
    #获取token
    res = requests.post(url)
    #print(res.text)
    token = json.loads(res.text)["access_token"]
    print(token)

上传识别

后两项参数为非必须(摘自官方文档)
主要参数

dev_pid 参数列表(摘自官方文档)
dev_pid 参数列表

语音识别 返回数据参数详情(摘自官方文档)
在这里插入图片描述

返回样例(摘自官方文档)
在这里插入图片描述

错误码解释(摘自官方文档)
错误码解释

直接附上程序
参数为本地文件的地址
附一个示例音频文件16k.wav

import pyaudio
import wave
import requests
import json
import base64
import os
def BaiduYuYin(fileurl):
    try:
        RATE = "16000"                  #采样率16KHz
        FORMAT = "wav"                  #wav格式
        CUID = "wate_play"
        DEV_PID = "1536"                #无标点普通话
        token = '你的token'

        # 以字节格式读取文件之后进行编码
        with open(fileurl, "rb") as f:
            speech = base64.b64encode(f.read()).decode('utf8')

        size = os.path.getsize(fileurl)
        headers = {'Content-Type': 'application/json'}
        url = "https://vop.baidu.com/server_api"
        data = {
            "format": FORMAT,
            "rate": RATE,
            "dev_pid": DEV_PID,
            "speech": speech,
            "cuid": CUID,
            "len": size,
            "channel": 1,
            "token": token,
        }
        req = requests.post(url, json.dumps(data), headers)
        result = json.loads(req.text)
        return result["result"][0][:-1]
    except:
        return '识别不清'

第一次写博客,希望大家多多指正,有什么问题请留言,一定及时回复。

2018-02-08 00:11:50 hfut_why 阅读数 6023
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5925 人正在学习 去看看 杨波

       最近项目需要,需要调研几家语音识别(离线/在线),语义理解,TTS(在线/离线),离线命令词,甚至百度的UNIT上下文使用等,虽然看的不怎么深入,但是也确实调研的不是,主要有百度,科大讯飞,搜狗,云知声,奇梦者等几家,还有包括硬件(科大的四麦直线麦克风,五麦环绕麦克风,最后升级的六麦环绕麦克风;奇梦者的四麦环绕麦克风+柱形麦克风阵列等)。也写了很多Demo,每一家的特色都不同。这里就不一一列举了。以后有机会在慢慢写下来,这里就简单给一个百度在线ASR和云知声离线TTS结合的案列,实现一个复读机的功能。

       因为现在比较晚了,我先上代码,后面会补充几点注意事项。

1,准备工作:

(1)百度SDK的JAR包bdasr_V3_xxx_xxx.jar与云知声的JAR包usc.jar:

百度SDK下载

云知声SDK下载

(先注册登录,选择服务再下载)

解压找到工程libs中的对应的jar(不在详说),添加在自己新建的工程的libs目录下,添加为library。

(2) so文件:同理,在刚刚下载的SDK中找到对应的so文件,然后早项目新建一个jniLibs目录(../src/main/)

(3)云知声离线TTS需要语音包(发不同音色使用的):使用时,需要先运行自己编写的工程,然后在对应设备的app安装的目录下新建tts文件夹,把下面三个文件放进去:

backend_female

backend_lzl

frontend_model

 

2,代码环节:

(1)AndroidManifest.xml:主要就是注意几个权限和百度的APP_ID,API_KEY,SECRET_KEY,这个需要自己创建应用,获取这三个值;这步不在累述。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="aoto.com.baidurecongdemo">

    <!-- begin: baidu speech sdk  权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/talk"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/talk"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.baidu.speech.APP_ID"
            android:value="XXXXXXX" />
        <meta-data
            android:name="com.baidu.speech.API_KEY"
            android:value="XXXXXXXXXXX..." />
        <meta-data
            android:name="com.baidu.speech.SECRET_KEY"
            android:value="XXXXXXXXXXXX...." />

        <service
            android:name=".ASRService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="aoto.com.ASRService" />
            </intent-filter>
        </service>
    </application>

</manifest>

 

(2)ASRService:这里我把百度语音识别写成了服务的形式,并开放了AIDL接口,别的应用可以直接调用即可(里面的方法未完善,学习者可以自行添加和修改)

package aoto.com.baidurecongdemo;


import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import com.baidu.speech.EventListener;
import com.baidu.speech.EventManager;
import com.baidu.speech.EventManagerFactory;
import com.baidu.speech.asr.SpeechConstant;
import com.unisound.client.SpeechConstants;
import com.unisound.client.SpeechSynthesizer;
import com.unisound.client.SpeechSynthesizerListener;

import org.json.JSONObject;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;


public class ASRService extends Service implements EventListener {
    private EventManager asr;
    public static String result;
    private boolean logTime = true;
    private String language;
    long startTime = 0;
    long endTime = 0;
    private MainActivity mainActivity = new MainActivity();


    private SpeechSynthesizer mTTSPlayer;
    private final String mFrontendModel= "/sdcard/unisound/tts/frontend_model";
    private final String mBackendModel = "/sdcard/unisound/tts/backend_lzl";

    //主动发数据
    final RemoteCallbackList<IRemoteServiceCallback> mCallbacks
            = new RemoteCallbackList<IRemoteServiceCallback>();
    private int mValue = 0;
    private static final int REPORT_MSG = 1;

    @Override
    public void onCreate() {
        System.out.println("服务创建了:" + "onCreate");
        asr = EventManagerFactory.create(this, "asr");
        asr.registerListener(this);
        super.onCreate();
        //初始化离线引擎
        initTts();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        System.out.println("服务开启了:" + "onStart");
        super.onStart(intent, startId);
    }

    /**
     * 测试参数填在这里
     */
    public void start() {
        Map<String, Object> params = new LinkedHashMap<String, Object>();
        String event = null;
        event = SpeechConstant.ASR_START; // 替换成测试的event
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);
        //判断调用者传过来的语言类型
        if (MainActivity.languge_id == 1) {
            params.put(SpeechConstant.PID, 1736);
        } else if (MainActivity.languge_id == 2) {
            params.put(SpeechConstant.PID, 1836);
        } else if (MainActivity.languge_id == 3) {
            params.put(SpeechConstant.PID, 1636);
        } else {
            params.put(SpeechConstant.PID, 1536);
        }
        System.out.println("MMMMMMMMMMMMMMMMMMLanguage:" + MainActivity.languge_id);
        // 请先使用如‘在线识别’界面测试和生成识别参数。 params同ActivityRecog类中myRecognizer.start(params);
        String json = null; //可以替换成自己的json
        json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
        asr.send(event, json, null, 0, 0);
        printLog("输入参数:" + json);
    }

    private void stop() {
        asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0); //
    }

    //   EventListener  回调方法
    /**
     * @param name   :当前asr状态
     * @param params :解析结果字符串
     * @author why
     */
    @Override
    public void onEvent(String name, String params, byte[] data, int offset, int length) {
        String logTxt = "name: " + name;
        if (params != null && !params.isEmpty()) {
            logTxt += " ;params :" + params;
            //通过name来确定当前状态,从而获取解析结果显示
            if (name.equals("asr.partial")) {
                String start = "[";
                String end = "]";
                //截取解析json字符串中结果显示
                result = StringTools.SubStringTwoChar(params, start, end);
                startTime = System.currentTimeMillis();
            }
        }

        if (name.equals("asr.finish")) {
            //识别结束
            if(MainActivity.btn.getText().toString().equals("停止")){
                if (result.equals("")||result==null){
                    result="没有识别到声音";
                }
                MainActivity.btn.setText("开始");
            }
            else{
                if (result.equals("")||result==null){
                    result="No sound at all";
                }
                MainActivity.btn.setText("start");
            }
            MainActivity.txtResult.setText(result);

            //TTS语音合成
            mTTSPlayer.playText(result);

        }

        //会话结束标识,发送广播传数据
        if (name.equals("asr.exit")) {
            mainActivity.test(result);
        }

        if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
            if (params.contains("\"nlu_result\"")) {
                if (length > 0 && data.length > 0) {
                    logTxt += ", 语义解析结果:" + new String(data, offset, length);
                }
            }
        } else if (data != null) {
            logTxt += " ;data length=" + data.length;
        }
        //打印识别日志
        printLog(logTxt);
    }

    //打印识别日志实现
    private void printLog(String text) {
        if (logTime) {
            text += "  ;time=" + System.currentTimeMillis();
        }
        text += "\n";
        Log.i(getClass().getName(), text);
    }


    //返回可调用服务方法的接口
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("MMMMMMMMMMMMMMMMM" + "服务绑定了!");
        return new MyASRresultAIDL();
    }

    //百度语音识别
    class MyASRresultAIDL extends ASRresultAIDL.Stub {
        @Override
        public String getASRResult() throws RemoteException {
            return result;
        }

        @Override
        public void callStart() throws RemoteException {
            start();
        }

        @Override
        public void callStop() throws RemoteException {
            stop();
        }
    }

    //初始化离线语音合成引擎实现
    private void initTts() {
        // 初始化语音合成对象
        //mTTSPlayer = new SpeechSynthesizer(this, Config.appKey, Config.secret);
        mTTSPlayer = new SpeechSynthesizer(this, "", "");
        System.out.println("TTTTTTTTTTTTTTTTTTS:"+mTTSPlayer);
        // 设置本地合成
        mTTSPlayer.setOption(SpeechConstants.TTS_SERVICE_MODE, SpeechConstants.TTS_SERVICE_MODE_LOCAL);
        File _FrontendModelFile = new File(mFrontendModel);
        if (!_FrontendModelFile.exists()) {
            System.out.println("文件:" + mFrontendModel + "不存在,请将assets下相关文件拷贝到SD卡指定目录!");
        }
        File _BackendModelFile = new File(mBackendModel);
        if (!_BackendModelFile.exists()) {
            System.out.println("文件:" + mBackendModel + "不存在,请将assets下相关文件拷贝到SD卡指定目录!");
        }
        // 设置前端模型
        mTTSPlayer.setOption(SpeechConstants.TTS_KEY_FRONTEND_MODEL_PATH, mFrontendModel);
        // 设置后端模型
        mTTSPlayer.setOption(SpeechConstants.TTS_KEY_BACKEND_MODEL_PATH, mBackendModel);
        // 设置回调监听
        mTTSPlayer.setTTSListener(new SpeechSynthesizerListener() {
            @Override
            public void onEvent(int type) {
                switch (type) {
                    case SpeechConstants.TTS_EVENT_INIT:
                        // 初始化成功回调
                        Log.i("", "回调成功 ");
                        break;
                    case SpeechConstants.TTS_EVENT_SYNTHESIZER_START:
                        // 开始合成回调
                        Log.i("", "开始同步");
                        break;
                    case SpeechConstants.TTS_EVENT_SYNTHESIZER_END:
                        // 合成结束回调
                        Log.i("", "结束同步");
                        break;
                    case SpeechConstants.TTS_EVENT_BUFFER_BEGIN:
                        // 开始缓存回调
                        Log.i("", "开始缓存 ");
                        break;
                    case SpeechConstants.TTS_EVENT_BUFFER_READY:
                        // 缓存完毕回调
                        Log.i("", "准备缓存 ");
                        break;
                    case SpeechConstants.TTS_EVENT_PLAYING_START:
                        // 开始播放回调
                        Log.i("", "播放开始 ");
                        break;
                    case SpeechConstants.TTS_EVENT_PLAYING_END:
                        // 播放完成回调
                        Log.i("", "播放结束 ");
                        break;
                    case SpeechConstants.TTS_EVENT_PAUSE:
                        // 暂停回调
                        Log.i("", "暂停 ");
                        break;
                    case SpeechConstants.TTS_EVENT_RESUME:
                        // 恢复回调
                        //log_i("resume");
                        break;
                    case SpeechConstants.TTS_EVENT_STOP:
                        // 停止回调
                        Log.i("", "停止");
                        break;
                    case SpeechConstants.TTS_EVENT_RELEASE:
                        // 释放资源回调
                        Log.i("", "释放资源");
                        break;
                    default:
                        break;
                }

            }

            @Override
            public void onError(int type, String errorMSG) {
                // 语音合成错误回调
                Log.e("","Error");
            }
        });

        // 初始化合成引擎
        int returnvalue= mTTSPlayer.init("");
        System.out.println("EEEEEEEEEEE:"+"初始化引擎"+returnvalue);
    }

}

(3)StringUtils : ASRService中使用的一个工具类

package aoto.com.baidurecongdemo;

/**
 * author:why
 * created on: 2018/1/31 15:25
 * description:
 */
public class StringTools {

    //截取固定字符床中指定两个字符或者字符串之间的子字符串

    /**
     *
     * @param target :要处理字符串
     * @param start :起始字符串/字符
     * @param end :结束字符串/字符
     * @return
     */
    public static String SubStringTwoChar(String target, String start, String end) {
        int startIndex = target.indexOf(start);
        int endIndex = target.indexOf(end);
        return target.substring(startIndex, endIndex).substring(start.length());
    }

}

(4)MainActivity:调用服务,演示效果

package aoto.com.baidurecongdemo;

import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;
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.AbsSpinner;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;

import com.baidu.speech.asr.SpeechConstant;

/**
 * @author why
 */
public class MainActivity extends AppCompatActivity implements InterfaceTest{

    protected TextView txtLog;
    public static TextView txtResult;
    public static Button btn;
    private String result;
    private static String DESC_TEXT = "在线识别日志";
    public static int languge_id = 0;
    private Intent intent;
    private MyServiceConnection connection;
    private ASRresultAIDL asRresultAIDL;
    private Spinner spinner;
    private String butContext;

    /**
     * 测试参数填在这里
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.common_mini);
        initView();
        intent = new Intent(this, ASRService.class);
        connection = new MyServiceConnection();
        bindService(intent, connection, BIND_AUTO_CREATE);

    }

    //触发语音识别开始与停止
    public void startOrEnd(View view) {
         butContext = btn.getText().toString();
        System.out.println("BBBBBBBBBBBBBBBBBBBBBB"+butContext);
        //先判断选择的语言
        if (butContext.equals("开始") || butContext.equals("start")) {
            //识别结果制空
            try {
                asRresultAIDL.callStart();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            if (butContext.equals("开始")) {
                ASRService.result="没有识别到声音";
                txtResult.setText("请说,我在听");
                btn.setText("停止");
            } else {
                ASRService.result="No sound at all";
                txtResult.setText("Please say,I am listening");
                btn.setText("stop");
            }
        } else {
            if (butContext.equals("停止")) {
                btn.setText("开始");
                try {
                    txtResult.setText("识别结果:" + asRresultAIDL.getASRResult());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            } else {
                btn.setText("start");
                try {
                    txtResult.setText("ASR result:" + asRresultAIDL.getASRResult());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            try {
                asRresultAIDL.callStop();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }

    private void initView() {
        txtResult = (TextView) findViewById(R.id.txtResult);
        txtLog = (TextView) findViewById(R.id.txtLog);
        btn = (Button) findViewById(R.id.btn);
        txtLog.setText(DESC_TEXT + "\n");
        spinner = findViewById(R.id.languge_list);
        //下拉框实现
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.Data, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setPrompt("选择语言");
        //设置下拉框监听
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                languge_id = position;
                System.out.println("QQQQQQQQQQQQQQQQQQQQQ"+languge_id);
                switch (languge_id) {
                    //普通话
                    case 0:
                        txtResult.setText("点击‘开始’");
                        btn.setText("开始");
                        break;
                    //英语
                    case 1:
                        //interfaceBaiduParams.setLanguage("English");
                        txtResult.setText("click 'start'");
                        btn.setText("start");
                        break;
                    // 四川话
                    case 2:
                        //interfaceBaiduParams.setLanguage("SiChuanHua");
                        txtResult.setText("点击‘开始’");
                        btn.setText("开始");
                        break;
                    //粤语
                    case 3:
                        //interfaceBaiduParams.setLanguage("YueYu");
                        txtResult.setText("点击‘开始’");
                        btn.setText("开始");
                        break;
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
    }

    @Override
    public void test(String str) {

    }

    private class MyServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

            asRresultAIDL = ASRresultAIDL.Stub.asInterface(iBinder);
            System.out.println("绑定服务成功了");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            System.out.println("解绑服务成功了");

        }
    }

}

(5)ASRresultAIDL.aidl:开放服务里面的方法,供其他应用调用

// ASRresultAIDL.aidl
package aoto.com.baidurecongdemo;

// Declare any non-default types here with import statements
interface ASRresultAIDL {
 String getASRResult();
 void callStart();
 void callStop();
}

(6)build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "aoto.com.baidurecongdemo"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        //加载对应so文件
        ndk{
            abiFilters 'armeabi'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
    implementation files('libs/bdasr_V3_20171108_9800a2a.jar')
    implementation files('libs/usc.jar')

}

3,注意事项:

(1)云知声离线TTSso文件不是X86的,所以window下的x86模拟器是用不了的,但是在window系统下运行arm的模拟器很卡,所以建议真机调试

(2)我这里在百度语音识别的地方只是实现了最简单的语音识别调用流程,很多的参数没有使用,学习者可以自己完善和添加

(3)我这里只添加了百度armeabi下的so文件,所以在gradle文件用ndk指定了(ndk已经安装),也可以什么都不加

(4)我这里主要是实现了一个复读机的功能,你说什么,那边会把识别文本语音合成播放出来,可以自己选择音色

(5)我这里百度开发了四种语言语音识别

注:欢迎扫码关注

 

没有更多推荐了,返回首页