引言
录音和音频播放在app中是一个很常见的功能,本文将介绍在HarmonyOS 如何使用录音和音频播放功能。
功能介绍
1.录音
1.1 使用录音前需要先申请录音权限
在 config.json文件中添加权限声明
"reqPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "the app need microphone",
"usedScene": {
"ability": [
"com.iflytek.demo.MainAbility"
],
"when": "always"
}
}
] 然后在MainAbility中动态申请麦克风权限
private void requestPermission() {
if (verifySelfPermission("ohos.permission.MICROPHONE") != IBundleManager.PERMISSION_GRANTED) {
// 应用未被授予权限
if (canRequestPermission("ohos.permission.MICROPHONE")) {
// 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示)
requestPermissionsFromUser(new String[]{"ohos.permission.MICROPHONE"}, REQUEST_MICROPHONE);
} else {
// 显示应用需要权限的理由,提示用户进入设置授权
}
} else {
// 权限已被授予
}
}
/**
* 权限回调
*/
@Override
public void onRequestPermissionsFromUserResult(int requestCode,
String[] permissions,
int[] grantResults) {
switch (requestCode) {
case REQUEST_MICROPHONE: {
// 匹配requestPermissions的requestCode
if (grantResults.length > 0 && grantResults[0] == IBundleManager.PERMISSION_GRANTED) {
// 权限被授予
// 注意:因时间差导致接口权限检查时有无权限,所以对那些因无权限而抛异常的接口进行异常捕获处理
AppLog.e("MainAbility", "已经获取到录音权限");
} else {
// 权限被拒绝
AppLog.e("MainAbility", "录音权限被拒绝");
}
}
}
} 1.2 录音功能使用的是 AudioCapturer类,主要接口如下:
| 接口名 | 描述 |
| ---------------------------------------------------- | --------------------------------------------- |
| AudioCapturer(AudioCapturerInfo audioCapturerInfo) throws IllegalArgumentException | 构造函数,设置录音相关音频参数,使用默认录音设备。 |
| getMinBufferSize(int sampleRate, int channelCount, int audioFormat) | 获取指定参数条件下所需的最小缓冲区大小。 |
| addSoundEffect(UUID type, String packageName) | 增加录音的音频音效。 |
| start() | 开始录音。 |
| read(byte[] data, int offset, int size) | 读取音频数据。 |
| stop() | 停止录音。 |
| release() | 释放录音资源。 |
初始化AudioCapturer,先通过 AudioStreamInfo设置录音音频基本参数,再通过AudioCapturerInfo设置录音源等信息。
/**
* 创建默认的录音对象
*/
public void initConfig() {
if (audioCapturer != null && audioCapturer.getState() != AudioCapturer.State.STATE_STOPPED) {
audioCapturer.release();
}
audioCapturer = null;
AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
// 音频采样率 16000
.sampleRate(AUDIO_SAMPLE_RATE)
// 录音数据格式 16-bit PCM
.encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
// 声道设置 单声道
.channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO)
.build();
AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder()
.audioStreamInfo(audioStreamInfo)
// 录音源
.audioInputSource(AudioCapturerInfo.AudioInputSource.AUDIO_INPUT_SOURCE_MIC)
.build();
audioCapturer = new AudioCapturer(audioCapturerInfo);
bufferSizeInBytes = AudioCapturer.getMinBufferSize(AUDIO_SAMPLE_RATE, 1, 2);
} 开始录音,通过 audioCapturer.read() 获取音频。
/**
* 开始录音
*
* @param listener 音频流的监听回调
*/
public void startRecord(final RecordListener listener) {
if (audioCapturer.getState() == AudioCapturer.State.STATE_UNINITIALIZED) {
throw new IllegalStateException("AudioCapturer need init first");
}
if (isRecording()) {
throw new IllegalStateException("AudioCapturer is in recording now");
}
// 开始录音
audioCapturer.start();
final byte[] audioData = new byte[bufferSizeInBytes];
while (isRecording()) {
int size = audioCapturer.read(audioData, 0, bufferSizeInBytes);
if (size > 0 && listener != null) {
if (size == bufferSizeInBytes) {
// 通过回掉回传录音数据
listener.onRead(audioData);
} else {
// 通过回掉回传录音数据
final byte[] copy = new byte[size];
System.arraycopy(audioData, 0, copy, 0, size);
listener.onRead(copy);
}
}
}
if (finishCallBack != null) {
finishCallBack.onFinish();
}
} 停止录音
/**
* 停止录音
*/
public synchronized void stopRecord() {
if (isRecording()) {
audioCapturer.stop();
}
}
/**
* 释放资源
*/
public synchronized void release() {
if (audioCapturer != null) {
audioCapturer.release();
audioCapturer = null;
}
} 2. 音频播放
HarmonyOS 中,播放音频主要有 AudioRenderer 、Player 、SoundPlayer 3个类
AudioRenderer 用于播放pcm音频流 Player 主要用于播放mp3、m4a等格式的音频
SoundPlayer 用于播放短音频 2.1 AudioRenderer播放pcm音频
/**
* 播放pcm
*
* @param file pcm文件
*/
private void playPcm(File file) {
if (file == null || !file.exists()) {
showToast("文件不存在");
return;
}
AudioStreamInfo streamInfo = new AudioStreamInfo.Builder()
// 16kHz
.sampleRate(16000)
// 混音
.audioStreamFlag(AudioStreamInfo.AudioStreamFlag.AUDIO_STREAM_FLAG_MAY_DUCK)
// 16-bit PCM
.encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
// 单声道输出
.channelMask(AudioStreamInfo.ChannelMask.CHANNEL_OUT_MONO)
// 媒体类音频
.streamUsage(AudioStreamInfo.StreamUsage.STREAM_USAGE_MEDIA)
.build();
AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder().audioStreamInfo(streamInfo)
// pcm格式的输出流
.audioStreamOutputFlag(AudioRendererInfo.AudioStreamOutputFlag.AUDIO_STREAM_OUTPUT_FLAG_DIRECT_PCM)
.bufferSizeInBytes(1280)
// false表示分段传输buffer并播放,true表示整个音频流一次性传输到HAL层播放
.isOffload(false)
.build();
AudioRenderer renderer = new AudioRenderer(audioRendererInfo, AudioRenderer.PlayMode.MODE_STREAM);
renderer.start();
try {
FileInputStream inputStream = new FileInputStream(file);
byte[] temp = new byte[1280];
while (inputStream.available() > temp.length) {
int read = inputStream.read(temp);
// 写入pcm到播放器
renderer.write(temp, 0, read);
}
} catch (Exception e) {
e.printStackTrace();
}
} 2.2 Player 播放mp3
/**
* 播放音频
*
* @param file 源文件位置
*/
private void playMp3(File file) {
try {
player = new Player(getContext());
FileInputStream in = new FileInputStream(file);
// 从输入流获取FD对象
FileDescriptor fd = in.getFD();
player.setSource(new Source(fd));
player.prepare();
player.play();
} catch (Exception e) {
e.printStackTrace();
}
}<span style="background-color: rgb(255, 255, 255);"> </span>
|