需要源码和相关资源请点赞关注收藏后评论区留下QQ~~~
一、在线语音识别
云知声的语音识别同样采用WebSocket接口,待识别的音频流支持MP3和PCM两种格式,对于在线语音识别来说,云知声使用JSON串封装报文,待识别的音频以二进制形式发给服务器,可分为以下几个步骤
云知声平台的创建及使用可以参考以下这篇博客
1:定义WebSocket客户端的语音识别功能
在请求报文中填写朗读领域 音频格式 采样率等识别参数 再把JSON串传给WebSocket服务器
把字节数字格式的原始音频通过sendBinary方法分批发给服务器
等到所有音频数据发送完毕 再向服务器发一个结束识别的报文 也就是type字段为end的JSON串
在识别过程中 服务器还会数次返回JSON格式的应答报文 只有报文中的end字段为true时才表示识别结束
2:定义PCM音频的实时录制线程
在线识别的音频源既可能是实时录制的音频文件,也可能是PCM音频,在实时录音的情况下,还需自定义专门的录音线程,每录制一段PCM数据就发给WebSocket服务器
3:创建并启动语音识别任务
回到测试页面的获得代码,先创建 WebSocket客户端的语音识别任务,再通过WebSocket客户端启动语音识别任务 串联之后的在线识别语音
点击开始实时识别按钮后开始说话,然后可以观察到语音识别结果
也可以点击右上角的识别样本音频,这时候会自动播放一段古诗 然后再点击识别
代码如下
Java类
package com.example.voice; import android.media.AudioFormat; import android.os.Bundle; import android.os.Environment; import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.example.voice.constant.SoundConstant; import com.example.voice.task.AsrClientEndpoint; import com.example.voice.task.VoicePlayTask; import com.example.voice.task.VoiceRecognizeTask; import com.example.voice.util.AssetsUtil; import com.example.voice.util.SoundUtil; public class VoiceRecognizeActivity extends AppCompatActivity { private final static String TAG = "VoiceRecognizeActivity"; private String SAMPLE_FILE = "sample/spring.pcm"; // 样本音频名称 private TextView tv_recognize_text; // 声明一个文本视图对象 private Button btn_recognize; // 声明一个按钮对象 private String mSamplePath; // 样本音频的文件路径 private boolean isRecognizing = false; // 是否正在识别 private VoiceRecognizeTask mRecognizeTask; // 声明一个原始音频识别线程对象 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_voice_recognize); findViewById(R.id.iv_back).setOnClickListener(v -> finish()); TextView tv_title = findViewById(R.id.tv_title); tv_title.setText("在线语音识别"); TextView tv_option = findViewById(R.id.tv_option); tv_option.setText("识别样本音频"); tv_recognize_text = findViewById(R.id.tv_recognize_text); btn_recognize = findViewById(R.id.btn_recognize); btn_recognize.setOnClickListener(v -> { if (!isRecognizing) { // 未在识别 btn_recognize.setText("停止实时识别"); new Thread(() -> onlineRecognize("")).start(); // 启动在线识别语音的线程 } else { // 正在识别 btn_recognize.setText("开始实时识别"); new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程 } isRecognizing = !isRecognizing; }); tv_option.setOnClickListener(v -> { new Thread(() -> onlineRecognize(mSamplePath)).start(); // 启动在线识别语音的线程 }); mSamplePath = String.format("%s/%s", getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), SAMPLE_FILE); // 把资产目录下的样本音频文件复制到存储卡 new Thread(() -> AssetsUtil.Assets2Sd(this, SAMPLE_FILE, mSamplePath)).start(); } // 在线识别音频文件(文件路径为空的话,表示识别实时语音) private void onlineRecognize(String filePath) { runOnUiThread(() -> { tv_recognize_text.setText(""); Toast.makeText(this, "开始识别语音", Toast.LENGTH_SHORT).show(); }); // 创建语音识别任务,并指定语音监听器 AsrClientEndpoint asrTask = new AsrClientEndpoint(this, filePath, arg -> { Log.d(TAG, "arg[0]="+arg[0]+",arg[2]="+arg[2]); tv_recognize_text.setText(arg[2].toString()); if (Boolean.TRUE.equals(arg[0])) { Toast.makeText(this, "语音识别结束", Toast.LENGTH_SHORT).show(); } }); SoundUtil.startSoundTask(SoundConstant.URL_ASR, asrTask); // 启动语音识别任务 if (TextUtils.isEmpty(filePath)) { // 文件路径为空,表示识别实时语音 // 创建一个原始音频识别线程 mRecognizeTask = new VoiceRecognizeTask(this, asrTask); mRecognizeTask.start(); // 启动原始音频识别线程 } else { // 文件路径非空,表示识别音频文件 int[] params = new int[] {16000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT}; // 创建一个原始音频播放线程 VoicePlayTask playTask = new VoicePlayTask(this, filePath, params); playTask.start(); // 启动原始音频播放线程 } } @Override protected void onPause() { super.onPause(); if (mRecognizeTask != null) { new Thread(() -> mRecognizeTask.cancel()).start(); // 启动取消识别语音的线程 } } }
任务类
package com.example.voice.task; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; public class VoiceRecognizeTask extends Thread { private final static String TAG = "VoiceRecognizeTask"; private Activity mAct; // 声明一个活动实例 private int mFrequence = 16000; // 音频的采样频率,单位赫兹 private int mChannel = AudioFormat.CHANNEL_IN_MONO; // 音频的声道类型 private int mFormat = AudioFormat.ENCODING_PCM_16BIT; // 音频的编码格式 private boolean isCancel = false; // 是否取消录音 private AsrClientEndpoint mAsrTask; // 语音识别任务 public VoiceRecognizeTask(Activity act, AsrClientEndpoint asrTask) { mAct = act; mAsrTask = asrTask; } @Override public void run() { // 根据定义好的几个配置,来获取合适的缓冲大小 int bufferSize = AudioRecord.getMinBufferSize(mFrequence, mChannel, mFormat); bufferSize = Math.max(bufferSize, 9600); byte[] buffer = new byte[bufferSize]; // 创建缓冲区 // 根据音频配置和缓冲区构建原始音频录制实例 AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, mFrequence, mChannel, mFormat, bufferSize); // 设置需要通知的时间周期为1秒 record.setPositionNotificationPeriod(1000); record.startRecording(); // 开始录制原始音频 int i=0; // 没有取消录制,则持续读取缓冲区 while (!isCancel) { int bufferReadResult = record.read(buffer, 0, buffer.length); mAsrTask.sendRealtimeAudio(i++, buffer, bufferReadResult); } record.stop(); // 停止原始音频录制 } // 取消实时录音 public void cancel() { isCancel = true; mAsrTask.stopAsr(); // 停止语音识别 } }
客户端类
package com.example.voice.task; import android.app.Activity; import android.text.TextUtils; import android.util.Log; import org.json.JSONObject; import javax.websocket.*; import java.io.FileInputStream; import java.io.InputStream; import java.nio.ByteBuffer; @ClientEndpoint public class AsrClientEndpoint { private final static String TAG = "AsrClientEndpoint"; private Activity mAct; // 声明一个活动实例 private String mFileName; // 语音文件名称 private VoiceListener mListener; // 语音监听器 private Session mSession; // 连接会话 public AsrClientEndpoint(Activity act, String fileName, VoiceListener listener) { mAct = act; mFileName = fileName; mListener = listener; } @OnOpen public void onOpen(final Session session) { mSession = session; Log.d(TAG, "->创建连接成功"); try { // 组装请求开始的json报文 JSONObject frame = new JSONObject(); frame.put("type", "start"); JSONObject data = new JSONObject(); frame.put("data", data); data.put("domain", "general"); // 领域。general(通用),law(司法),technology(科技),medical(医疗) data.put("lang", "cn"); // 语言。cn(中文普通话)、en(英语) data.put("format", "pcm"); // 音频格式。支持mp3和pcm data.put("sample", "16k"); // 采样率。16k,8k data.put("variable", "true"); // 是否可变结果 data.put("punctuation", "true"); // 是否开启标点 data.put("post_proc", "true"); // 是否开启数字转换 data.put("acoustic_setting", "near"); // 音响设置。near近讲,far远讲 data.put("server_vad", "false"); // 智能断句 data.put("max_start_silence", "1000"); // 智能断句前静音 data.put("max_end_silence", "500"); // 智能断句尾静音 // 发送开始请求 session.getBasicRemote().sendText(frame.toString()); } catch (Exception e) { e.printStackTrace(); } // 文件名非空,表示从音频文件中识别文本 if (!TextUtils.isEmpty(mFileName)) { new Thread(() -> sendAudioData(session)).start(); } } // 发送音频文件的语音数据 private void sendAudioData(final Session session) { try (InputStream is = new FileInputStream(mFileName)) { byte[] audioData = new byte[9600]; int length = 0; while ((length = is.read(audioData)) != -1) { Log.d(TAG, "发送语音数据 length="+length); ByteBuffer buffer = ByteBuffer.wrap(audioData, 0, length); session.getAsyncRemote().sendBinary(buffer); Thread.sleep(200); // 模拟采集音频休眠 } } catch (Exception e) { e.printStackTrace(); } stopAsr(); // 停止语音识别 } // 发送实时语音数据 public synchronized void sendRealtimeAudio(int seq, byte[] data, int length) { if (mSession!=null && mSession.isOpen()) { Log.d(TAG, "发送语音数据 seq="+seq+",length="+length); ByteBuffer buffer = ByteBuffer.wrap(data, 0, length); mSession.getAsyncRemote().sendBinary(buffer); } } // 停止语音识别 public void stopAsr() { try { // 组装请求结束的json报文 JSONObject frame = new JSONObject(); frame.put("type", "end"); if (mSession!=null && mSession.isOpen()) { // 发送结束请求 mSession.getBasicRemote().sendText(frame.toString()); } } catch (Exception e) { e.printStackTrace(); } } @OnMessage public void processMessage(Session session, String message) { Log.d(TAG, "服务端返回:" + message); try { JSONObject jsonObject = new JSONObject(message); boolean end = jsonObject.getBoolean("end"); // 是否结束识别 int code = jsonObject.getInt("code"); // 处理结果 String msg = jsonObject.getString("msg"); // 结果说明 if (code != 0) { Log.d(TAG, "错误码:" + code + ",错误描述:" + msg); return; } String text = jsonObject.getString("text"); mAct.runOnUiThread(() -> mListener.voiceDealEnd(end, msg, text)); if (end) { Log.d(TAG, mFileName + "识别结束"); session.close(); // 关闭连接会话 } } catch (Exception e) { e.printStackTrace(); } } @OnError public void processError(Throwable t) { t.printStackTrace(); } }
创作不易 觉得有帮助请点赞关注收藏~~~