赞
踩
之前一片文章简单讲述了通过TTS和Audio相关API控制文本输出语音的方法,接下来学习一下其他原生方式的语音播放功能。
// 定义MediaPlayer
private var mediaPlayer: MediaPlayer?
// 初始化 MediaPlayer 传入了需要播报的音频文件 这是一个 .wav类型文件 (就是无损压缩格式,缺点文件大 优点兼容性好)
// 也可也通过方法传入新的音频文件
private fun initMediaPlayer(){
mediaPlayer = MediaPlayer.create(TruckerPathApplication.appContext, R.raw.xxx)
}
/** * 播放提示音 */ private fun playSpeedWarningRing() { try { // 上一篇讲过这个是获取音频焦点,使得提示音更突出,其他声音略微缩小 audioFocusManager.requestAudioFocus() // 判断是否正在播放 if (mediaPlayer?.isPlaying != true) { // 开始播放 mediaPlayer?.start() } } catch (e: IllegalStateException) { if (BuildConfig.DEBUG) { e.printStackTrace() } } finally { // 一定最后要释放音频焦点 audioFocusManager.abandonAudioFocus() } }
/**
* 释放mediaPlayer
*/
private fun releaseMediaPlayer() {
mediaPlayer?.release()
mediaPlayer = null
}
MediaPlayer 更适合播放较长的音频文件,例如音乐、电影和电台等。它支持多种音频格式,如 MP3、AAC、WMA 等,同时还支持多媒体的控制,如暂停、停止、重复播放等。MediaPlayer 可以在后台运行,即使应用切换到后台或锁屏状态下仍然可以继续播放,也可以通过 Notification 和 MediaSession 等类实现前台播放通知和多媒体控制。
MediaPlayer 播放音频时,它只会在内存中缓存正在播放的音频数据,而不会一次性将整个音频文件加载到内存中。当 MediaPlayer 播放完缓存中的数据时,它会自动从硬盘中读取下一部分音频数据,并逐步地进行播放。
因此,相比于 SoundPool 在内存中预加载音频资源的方式,MediaPlayer 可以更加灵活地管理内存资源,避免资源浪费。同时,MediaPlayer 也可以播放较长的音频文件,适合用于播放音乐等长时间的音频文件。
不过,需要注意的是,MediaPlayer 在播放完音频文件后,并不会自动释放内存资源,这需要开发者手动调用 MediaPlayer 的 release() 方法来释放相关资源,避免内存泄漏的问题。
SoundPool 对于 MediaPlayer 来说有如下特点:
SoundPool 主要用于播放短促音效,例如游戏中的背景音乐、点击声和爆炸声等。
优点:
提高播放性能:内存池可以避免频繁的 I/O 操作和内存分配,从而减少 CPU 的开销,提高播放性能。
降低功耗:由于内存池可以避免频繁的 I/O 操作,因此可以降低硬件设备的功耗,从而延长电池寿命。
支持多个音效同时播放:SoundPool 可以同时播放多个音效,这对于一些需要多种音效混合的场景非常有用。
实现音效的循环播放和变速播放等特效:SoundPool 支持音效的循环播放和变速播放等特效,这对于游戏等应用场景非常有用。
缺点:
SoundPool 也存在一些缺点:
可能存在资源浪费:由于 SoundPool 在内存中预加载音频资源,因此如果音频文件较大,可能会浪费过多的内存资源。
受限于硬件设备:SoundPool 的播放性能和效果可能受限于硬件设备的音频处理能力,因此在一些低端设备上可能会出现问题。
不支持播放较长的音频文件:由于 SoundPool 音频资源需要预加载到内存中,因此不适合播放较长的音频文件。
// 在 Activity 中定义 SoundPool 变量
private SoundPool soundPool;
// 在 onCreate() 方法中初始化 SoundPool
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
// 加载音频文件
int soundId = soundPool.load(this, R.raw.sound_effect, 1);
// 在需要播放音频文件的时候调用 play() 方法
soundPool.play(soundId, 1, 1, 0, 0, 1);
SoundPool(int maxStreams, int streamType, int srcQuality):构造函数,用于创建 SoundPool 对象。 maxStreams:最大能同时播放的音频数量。 streamType:指定音频流的类型,如 AudioManager.STREAM_MUSIC 等。 srcQuality:指定音频质量,取值范围为 0~4,0 表示最差,4 表示最好。 load(Context context, int resId, int priority):加载音频文件。 context:应用程序上下文。 resId:音频文件的资源 ID。 priority:指定加载音频文件的优先级。 setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener):设置加载音频文件完成的监听器。 play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate):播放音频文件。 soundID:音频文件的 ID。 leftVolume:左声道音量。 rightVolume:右声道音量。 priority:指定播放音频文件的优先级。 loop:指定循环播放的次数,-1 表示无限循环。 rate:指定播放速度,1 表示正常速度。 pause(int streamID):暂停指定 streamID 的音频文件播放。 resume(int streamID):恢复指定 streamID 的音频文件播放。 stop(int streamID):停止指定 streamID 的音频文件播放。 release():释放 SoundPool 对象占用的资源。 注意:SoundPool 在 Android 5.0 以上版本已经不建议使用,建议使用 SoundPool.Builder 或者 MediaPlayer 等其他方式来播放音频。
AudioTrack 是一个用于播放音频的类,它可以直接控制音频数据的采样率、位宽和声道数等参数,适用于需要对音频进行实时处理的场景。
相比于 MediaPlayer,AudioTrack 的优点是:
但是 AudioTrack 也有一些缺点,例如需要自己实现音频文件解码等功能。
int sampleRate = 44100; int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat); AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, bufferSize, AudioTrack.MODE_STREAM); byte[] buffer = new byte[bufferSize]; File file = new File(Environment.getExternalStorageDirectory(), "audio.pcm"); try { FileInputStream inputStream = new FileInputStream(file); audioTrack.play(); int length; while ((length = inputStream.read(buffer)) > 0) { audioTrack.write(buffer, 0, length); } audioTrack.stop(); audioTrack.release(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); }
AudioRecord是Android平台上用于实现音频采集的类。它可以从系统中的音频输入源(比如麦克风)读取音频数据,并将数据存储到内存中或写入到文件中。通常,我们可以将AudioRecord与AudioTrack一起使用,实现实时的音频录制和播放。
使用AudioRecord类可以实现以下功能:
音频数据采集:可以从不同的音频输入源(比如麦克风、电话线路、蓝牙耳机等)获取音频数据。
音频数据读取:可以将采集到的音频数据存储到内存中或写入到文件中。
音频格式支持:支持多种音频格式(比如PCM、AAC、MP3等)的采集和处理。
需要注意的是,使用AudioRecord需要注意以下几个方面:
音频源的选择:需要根据实际情况选择正确的音频输入源,比如麦克风、电话线路、蓝牙耳机等。
音频格式的设置:需要根据实际情况设置正确的音频格式(比如采样率、位深、声道数等)。
音频缓冲区的设置:需要根据实际情况设置正确的音频缓冲区大小,以确保能够正确地读取和处理音频数据。
总之,AudioRecord是Android平台上非常重要的音频采集类之一,它可以帮助我们实现音频数据的采集、处理和存储等功能。
通过 AudioRecord 获取音频,再通过 Google Speech-to-Text API 转换成文本 示例代码如下:
private static final int RECORDER_SAMPLERATE = 16000; private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO; private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT; private AudioRecord audioRecorder; private boolean isRecording = false; // 启动录音 private void startRecording() { int bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING); audioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize); // 开启录音线程 isRecording = true; new Thread(new Runnable() { @Override public void run() { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); byte[] buffer = new byte[bufferSize]; audioRecorder.startRecording(); while (isRecording) { int bytesRead = audioRecorder.read(buffer, 0, buffer.length); // 将录制的音频转换成文本信息 if (bytesRead > 0) { try { // 将录制的音频数据传递给语音识别引擎 SpeechRecognizer recognizer = SpeechRecognizer.createSpeechRecognizer(MainActivity.this); recognizer.setRecognitionListener(new RecognitionListener() { @Override public void onResults(Bundle results) { ArrayList<String> voiceResults = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); if (voiceResults != null && voiceResults.size() > 0) { String text = voiceResults.get(0); // 处理识别结果 Log.d(TAG, "识别结果:" + text); } } // 省略其他回调方法的实现 }); Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()); recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3); recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 1500); recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS, 1500); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(outputStream); for (int i = 0; i < bytesRead; i++) { dataOutputStream.writeShort(buffer[i]); } byte[] bytes = outputStream.toByteArray(); recognizer.startListening(recognizerIntent, new AudioRecord.AudioInputCaptureCallback() { @Override public void onInputCaptured(byte[] audioData) { // 将录制的音频数据传递给语音识别引擎 recognizer.writeAudio(audioData, 0, audioData.length); } }); recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName()); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en-US");
udioRecord默认情况下是没有提供降噪功能的,因此需要通过一些额外的处理来实现降噪。常用的方法是使用数字信号处理(DSP)算法来滤除不想要的噪声,例如高通滤波器和自适应滤波器等。
在Android中,可以通过使用AudioRecord的setAudioSource方法设置声音来源,并在构造AudioRecord对象时指定降噪的配置参数。例如,可以通过设置音频来源为麦克风并启用降噪来实现降噪录音,示例代码如下:
int audioSource = MediaRecorder.AudioSource.MIC;
int sampleRate = 44100;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
NoiseSuppressor noiseSuppressor = NoiseSuppressor.create(audioRecord.getAudioSessionId());
audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);
if (NoiseSuppressor.isAvailable() && noiseSuppressor != null) {
noiseSuppressor.setEnabled(true);
}
在上面的代码中,我们通过调用NoiseSuppressor.create()方法创建一个NoiseSuppressor实例,并将其应用到当前AudioRecord实例的音频会话中。另外,我们还可以通过调用NoiseSuppressor.isAvailable()方法来检查当前设备是否支持噪声抑制功能。
关于音频播放:如果长音视频更适合 MediaPlayer 或者对于一些内存比较紧张的情况也适用,因为MediaPlayer 不会将整个视频读取到内存。如果是比较短的音频更适合SoundPool,性能好,使用简单,适合循环播放,因为直接从内存读取避免重复I/O操作。如果需要增加各种复杂处理 可以使用 AudioTrack ,缺点是需要自己做解码。如果需要录音等功能则可以使用 AudioRecord ,但是还需要一些降噪处理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。