Android Asr流程分析和调用实现

本文解析了Android ASR(自动语音识别)的调用流程和原理,介绍了核心源码路径,包括SpeechRecognizer、RecognitionListener和RecognitionService的作用。详细分析了外部客户端调用流程和服务端实现方法,强调了RecognitionService.SERVICE_INTERFACE的重要性。

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

ASR全称是Automatic Speech Recognition,是自动语音识别,将人说出来的化自动识别成文本。本文我们将简单快速的熟悉Android asr流程和外部调用原理。

在此先直接说明Android Asr流程原理,以便更容易理解后面的调用流程:
Android Asr只是定义了语音识别的接口,具体的引擎需要各个厂商单独定义,也就是说Android Asr只提供外部调用的接口,至于具体的语音识别功能需要其他引擎来支持,所以本文我们主要分析外部如何来调用Android Asr,至于语音识别引擎我们后续会以百度ASR引擎来讲解,接下来进入正题。

涉及的Android Asr 核心源码路径如下:
android.speech.SpeechRecognizer
android.speech.RecognitionListener
android.speech.RecognitionService

语音识别当然得需要录音,所以权限是必须的
外部调用方式,直接上代码分析:
private void initRecognizer() {
List list = this.getPackageManager().queryIntentServices(
new Intent(RecognitionService.SERVICE_INTERFACE), 0);
Log.i(TAG, " list.size=" + list.size());
// Toast.makeText(this, “Recognition Available”+ list.size(), Toast.LENGTH_SHORT).show();
for (ResolveInfo resolveInfo : list) {
// Toast.makeText(this, " resolveInfo=" + resolveInfo.toString(), Toast.LENGTH_SHORT).show();
Log.i(TAG, " resolveInfo=" + resolveInfo.toString());
}
if (SpeechRecognizer.isRecognitionAvailable(this)) {
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this,
new ComponentName(“com.ishare.asrengine”, “com.ishare.asrengine.engine.BaiduAsrService”));
mSpeechRecognizer.setRecognitionListener(this);
} else {
Toast.makeText(this, “Recognition UnAvailable”, Toast.LENGTH_SHORT).show();
}
}
关键信息在于三个方法:
SpeechRecognizer.isRecognitionAvailable(this)、SpeechRecognizer.createSpeechRecognizer、mSpeechRecognizer.setRecognitionListener(this);

SpeechRecognizer.isRecognitionAvailable判断是否有语音识别服务,查询所有的引擎服务,至少有一个时就可以使用,否则无法使用,也就是上面有没有语音识别引擎来支持此功能,没有的话肯定不能使用了,android是怎么来判断的呢。进isRecognitionAvailable,贴源码:final List list = context.getPackageManager().queryIntentServices(
new Intent(RecognitionService.SERVICE_INTERFACE), 0);
明白了吧,系统会查找有没有RecognitionService.SERVICE_INTERFACE这个action的服务,而这个服务当然是需要我们实现的,这个后面会有分析。

SpeechRecognizer.createSpeechRecognizer创建语音识别,其有两个参数,一个是context,另一个是serviceComponent,在此明白上面的服务检测了吧,创建语音识别的过程其实就是真正开启语音识别引擎服务的过程。

mSpeechRecognizer.setRecognitionListener(this);这个是监听,原理就是Asr引擎识别的过程和结果通过SpeechRecognizer回调,然后在此监听中来做处理,具体的监听能供大家参看源码,这里不做分析。

接下来调用mSpeechRecognizer.startListening(recognizerIntent);
这个没什么说的,就是启动语音识别。

以上就是外部客户端调用android Asr的流程,接下我们分析service,为什么要分析service,回想下,上面有个条件就是调用Asr的时候系统需要先检测是否有引擎服务,没有的话就不能用了,这个不用解释了吧,系统中不存在识别服务,肯定不能用识别功能,所以我们就需要做一个识别的服务,一般就会把像百度、讯飞等一些识别的sdk集成到这个服务里,本文中我们对服务只做功能讲解,具体的识别集成后续会以集成百度Asr为例类讲解,接下来就快速分析怎么来写这个服务类:
继承RecognitionService,在Mainfest中声明时候一定要定义action,上代码:






为什么要加这个action,返回前面的系统检查服务看源码就发现,系统就是检测有没有这个action服务,所以不管系统中集成哪个引擎,必须要启这个服务,而且必须是这个,这个action是android定义好的,自己不能换另外的action,这个非常重要,集成时候一定要注意。
继承RecognitionService后需要实现三个函数:
@Override
protected void onStartListening(Intent recognizerIntent, Callback listener) {
this.mRecognitionListener=listener;
startListen();
}

@Override
protected void onCancel(Callback listener) {
cancelListen();
}

@Override
protected void onStopListening(Callback listener) {
stopListen();
}
启动、停止、取消,没错,当客户端调用启动函数
mSpeechRecognizer.startListening的时候跟进源码一路看下来,你会发现其实最后onStartListening才是语音识别服务的真正开始,当然onCancel就是取消,onStopListening就是停止,所以一般我们在集成其他Asr引擎的时候,在此service的onCreate中会做一些相应的初始化工作,比如引擎初始化、监听等等,然后在这三个函数中才是语音识别功能的实现,好了,现在梳理一下思路,其实很简单,SpeechRecognizer提供接口给外部调用,具体的引擎在RecognitionService
中实现,按照这个思路即可实现Android系统级别的Asr功能。

<think>我们正在处理一个关于在Android平台上实现语音数据的实时采集播放功能的问题。根据用户提供的引用,我们可以了解到: - 使用MediaRecorderMediaPlayer不能实时采集发送音频数据,因此需要使用AudioRecordAudioTrack(引用[2])。 - 引用[1]提到了一篇关于实现语音数据实时采集/播放的博客,但具体内容需要参考该博客。 - 引用[3]提到了百度在线语音识别SDK,但用户的问题主要集中在实时采集播放,而不是语音识别。 因此,我们将重点放在AudioRecordAudioTrack的使用上。 实现步骤大致如下: 1. 设置音频源参数(采样率、声道配置、音频格式)。 2. 创建AudioRecord对象用于录音(采集)。 3. 创建AudioTrack对象用于播放。 4. 在录音播放时使用单独的线程,以避免阻塞主线程。 5. 实时处理音频数据:从AudioRecord读取数据,然后写入AudioTrack进行播放。 注意:我们需要在AndroidManifest.xml中申请录音权限。 下面我们详细说明实现方法。 ### 1. 权限申请 在AndroidManifest.xml中添加录音权限: ```xml <uses-permission android:name="android.permission.RECORD_AUDIO" /> ``` ### 2. 音频参数设置 常用的音频参数: - 采样率:44100Hz(CD音质),但也可以根据设备支持情况选择其他采样率(如16000Hz)。 - 声道配置:单声道(CHANNEL_IN_MONO)或立体声(CHANNEL_IN_STEREO)。这里我们通常使用单声道,因为语音识别等场景常用单声道。 - 音频格式:ENCODING_PCM_16BIT(16位PCM)。 ### 3. 创建AudioRecord 初始化AudioRecord需要指定音频源、采样率、声道配置、音频格式缓冲区大小。缓冲区大小可以通过`AudioRecord.getMinBufferSize`获取。 ### 4. 创建AudioTrack 初始化AudioTrack需要指定流类型、采样率、声道配置、音频格式缓冲区大小,以及播放模式(通常使用MODE_STREAM)。 ### 5. 实现录音播放线程 我们使用两个线程(或一个线程同时处理)分别进行录音播放。由于是实时采集并播放,我们可以将录音得到的数据直接写入AudioTrack。 注意:从AudioRecord读取的音频数据可以直接传递给AudioTrack进行播放,这就是所谓的“回声”(loopback)测试。但实际应用中可能需要处理数据(如发送到网络或保存到文件),这里我们只实现实时播放。 ### 代码示例 ```java import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaRecorder; public class AudioLoopback { private static final int SAMPLE_RATE = 44100; // 采样率 private static final int CHANNEL_CONFIG_IN = AudioFormat.CHANNEL_IN_MONO; // 录音声道 private static final int CHANNEL_CONFIG_OUT = AudioFormat.CHANNEL_OUT_MONO; // 播放声道 private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; // 音频格式 private int bufferSize; // 缓冲区大小 private AudioRecord audioRecord; private AudioTrack audioTrack; private boolean isRecording = false; public AudioLoopback() { // 计算最小缓冲区大小 bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG_IN, AUDIO_FORMAT); // 创建AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL_CONFIG_IN, AUDIO_FORMAT, bufferSize); // 创建AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, CHANNEL_CONFIG_OUT, AUDIO_FORMAT, bufferSize, AudioTrack.MODE_STREAM); } public void start() { if (isRecording) { return; } isRecording = true; // 启动播放 audioTrack.play(); // 启动录音 audioRecord.startRecording(); // 启动录音线程 new Thread(new Runnable() { @Override public void run() { byte[] buffer = new byte[bufferSize]; while (isRecording) { // 从麦克风读取数据 int readBytes = audioRecord.read(buffer, 0, bufferSize); if (readBytes > 0) { // 将数据写入AudioTrack进行播放 audioTrack.write(buffer, 0, readBytes); } } } }).start(); } public void stop() { isRecording = false; audioRecord.stop(); audioTrack.stop(); } public void release() { audioRecord.release(); audioTrack.release(); } } ``` ### 注意事项 1. 在Android 6.0及以上版本,需要在运行时申请录音权限。 2. 确保在不需要时释放AudioRecordAudioTrack资源(如在Activity的onDestroy中调用release方法)。 3. 由于实时采集播放对延迟敏感,所以缓冲区大小设置要合适,过大会增加延迟,过小可能导致音频断断续续。 ### 性能优化 - 使用更小的缓冲区可以减少延迟,但需要测试设备的支持情况。 - 如果需要在处理数据(如网络传输)时播放,可能需要使用双缓冲区或环形缓冲区来避免数据丢失。 ### 相关问题 1. 如何降低实时音频采集播放的延迟? 2. 除了实时播放,如何将采集的音频数据实时传输到网络? 3. 在Android平台上如何实现语音数据的实时处理(如降噪、回声消除)? [^1]: [android实现语音数据实时采集/播放](http://blog.youkuaiyun.com/lantingshuxu/article/details/53520316) [^2]: [Android实现语音数据实时采集、播放](https://blog.youkuaiyun.com/weixin_39927850/article/details/111401831) [^3]: [百度Android在线语音识别SDK使用方法](https://blog.youkuaiyun.com/weixin_39927850/article/details/111401831)</think>### Android 实时语音采集与播放实现方法 在 Android 平台上实现语音数据的实时采集播放,需要使用底层音频 API(`AudioRecord` `AudioTrack`),而非高级的 `MediaRecorder`/`MediaPlayer`(无法实时处理原始数据)[^2]。以下是完整实现步骤: #### 一、核心流程 ```mermaid graph TD A[权限申请] --> B[配置音频参数] B --> C[初始化AudioRecord] B --> D[初始化AudioTrack] C --> E[启动采集线程] D --> F[启动播放线程] E --> G[实时读取PCM数据] F --> H[实时播放PCM数据] G --> I[数据处理/传输] ``` #### 二、代码实现 1. **AndroidManifest.xml 添加权限** ```xml <uses-permission android:name="android.permission.RECORD_AUDIO" /> ``` 2. **Java 核心代码** ```java // 配置音频参数(需设备支持) private static final int SAMPLE_RATE = 16000; // 16kHz采样率 private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; private int bufferSize; // 缓冲区大小 // 初始化AudioRecord bufferSize = AudioRecord.getMinBufferSize( SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT); AudioRecord recorder = new AudioRecord( MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize * 2); // 双倍缓冲防溢出 // 初始化AudioTrack AudioTrack player = new AudioTrack( AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AUDIO_FORMAT, bufferSize, AudioTrack.MODE_STREAM); // 采集线程 new Thread(() -> { byte[] buffer = new byte[bufferSize]; recorder.startRecording(); while (isRecording) { int bytesRead = recorder.read(buffer, 0, bufferSize); if (bytesRead > 0) { // 此处可添加数据处理(如网络传输/保存文件) player.write(buffer, 0, bytesRead); // 直接播放 } } recorder.stop(); }).start(); // 播放线程 player.play(); // 启动播放 ``` #### 三、关键参数说明 | 参数 | 推荐值 | 说明 | |------|--------|------| | 采样率 | 16000Hz | 语音识别常用采样率,平衡质量与延迟 | | 音频格式 | ENCODING_PCM_16BIT | 16位PCM原始数据 | | 声道 | CHANNEL_IN_MONO | 单声道节省带宽 | | 缓冲区 | 2×最小缓冲 | 防止数据溢出 | #### 四、优化建议 1. **延迟优化** - 使用 `AudioRecord.Callback` 事件驱动模式 - 降低采样率至 8000Hz(牺牲质量) - 采用环形缓冲区减少内存拷贝 2. **音频处理** ```java // 示例:实时音量检测 short[] samples = new short[bufferSize/2]; System.arraycopy(buffer, 0, samples, 0, samples.length); for (short sample : samples) { sum += Math.abs(sample); } float amplitude = sum / samples.length; ``` 3. **权限动态申请** ```java if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE); } ``` #### 五、典型应用场景 1. 实时语音通话(需配合网络传输) 2. 语音识别前端处理(如百度ASR SDK[^3]) 3. 音频实时特效处理 4. 声纹识别数据采集 > **注意**:测试时需佩戴耳机,避免扬声器声音被麦克风采集导致啸叫。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值