音频录制是一项常见需求,应用场景包括语音备忘、音乐创作和实时通讯等。鸿蒙OS 提供了多种音频录制API,以满足不同开发需求。本文将介绍三种主要的音频录制方法,帮助你根据项目需求选择合适的技术。
1. AVRecorder
AVRecorder 是鸿蒙系统提供的功能全面的音频及视频录制接口,适用于 ArkTS 和 JS 开发环境。支持直接调用设备麦克风录音,并内建音频编码和媒体文件封装功能,简化了从录音到文件保存的整个流程,适合需要快速实现基本录音功能的开发者。
2. AudioCapturer
AudioCapturer 专门用于音频输入捕捉,适合需要对音频数据进行深度加工或有特定格式要求的应用。该接口输出未经压缩的PCM格式数据,开发者需自行管理音频数据的读取和后续处理。如果你的应用需要高度灵活的音频处理能力,如实现噪声抑制或音效增强,AudioCapturer 能提供充分的控制权。
3. OpenSL ES 面向专业音频开发者的原生接口
OpenSL ES 是跨平台的音频处理标准,为高性能、低延迟的音频应用而设计,是鸿蒙OS 中唯一的音频原生API选项。它同样支持PCM格式的音频输入,适合从其他平台移植音频处理代码或需要在系统底层直接操作音频流的项目。选择OpenSL ES意味着更多的控制自由度,但也要求开发者具备深厚的音频编程知识和底层开发经验。
关于用户权限
无论采用哪种录制方式,应用程序在访问麦克风前,都必须通过系统申请并获得用户的明确同意——即获取”ohos.permission.MICROPHONE”权限。
在使用鸿蒙OS系统开发应用程序时,若需实现音频录制功能,可以借助AVRecorder
这一强大工具。下面是一个简化且详细解说的指南,帮助开发者逐步实现从初始化到完成音频录制的整个过程,包括开始、暂停、恢复、停止及资源管理等关键步骤。
AVRecorder 使用实例
通过以下 JavaScript 代码创建一个 AVRecorder
实例。成功创建后,该实例将处于idle
(空闲)状态,准备进行下一步配置。
import media from '@ohos.multimedia.media';
// 创建AVRecorder实例
let avRecorder;
media.createAVRecorder()
.then((recorder) => {
avRecorder = recorder;
console.log("AVRecorder实例创建成功");
})
.catch((err) => {
console.error("创建AVRecorder失败,错误码:${err.code},错误信息:${err.message}");
});
设置监听事件
为了及时响应录制过程中的状态变化和错误信息,需要为 AVRecorder
实例添加两个监听器:stateChange
和error
。
stateChange
:当录音机状态发生变化时触发,比如从准备就绪变为开始录制。error
:如果在录制过程中遇到任何错误,此事件会被触发。
// 状态变化监听
avRecorder.on('stateChange', (state, reason) => {
console.log(`当前状态变为:${state}`);
// 根据状态变化做相应处理
});
// 错误监听
avRecorder.on('error', (err) => {
console.error(`录音机出错,错误码:${err.code},错误信息:${err.message}`);
});
配置录制参数并准备录制
接下来,需要定义音频录制的具体参数,如比特率、声道数、编码格式等,并通过prepare()
方法使AVRecorder进入prepared
状态,等待开始录制。
const avProfile = {
audioBitrate: 100000, // 音频比特率设为100kbps
audioChannels: 2, // 使用双声道
audioCodec: media.CodecMimeType.AUDIO_AAC, // 采用AAC编码
audioSampleRate: 48000, // 采样率为48kHz
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 文件封装格式为MPEG-4
};
const avConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 使用麦克风作为音频输入
profile: avProfile,
url: 'fd://35', // 填入之前通过其他方式创建的音频文件描述符
};
avRecorder.prepare(avConfig)
.then(() => {
console.log("录音准备就绪");
})
.catch((err) => {
console.error("准备录音失败,错误码:${err.code},错误信息:${err.message}");
});
控制录制流程
调用不同的方法来控制录制流程:
- 开始录制:调用
start()
,进入started
状态。 - 暂停录制:调用
pause()
,转至paused
状态。 - 恢复录制:调用
resume()
,回到started
状态。 - 停止录制:调用
stop()
,进入stopped
状态。
资源管理和实例销毁
录制结束后,为了释放资源和重新开始新的录制,可以执行以下操作:
- 重置资源:通过
reset()
将AVRecorder恢复到idle
状态,以便重新配置参数。 - 销毁实例:调用
release()
将AVRecorder置于released
状态,彻底结束录制并释放所有资源。
AudioCapturer 音频录制实例
AudioCapturer 主要用于捕获和录制PCM(脉冲编码调制)格式的音频数据。PCM是一种未经压缩的数字音频编码格式,能够保证高质量的音频录制。
配置音频采集参数并创建AudioCapturer实例
导入audio模块
import audio from '@ohos.multimedia.audio';
设置音频流的相关参数
let audioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100, // 采样率设置为44.1kHz
channels: audio.AudioChannel.CHANNEL_2, // 双声道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 16位小端格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 原始PCM编码
};
设置音频采集器的信息
let audioCapturerInfo = {
source: audio.SourceType.SOURCE_TYPE_MIC, // 从麦克风采集音频
capturerFlags: 0 // 默认标志
};
将上面的信息组合成AudioCapturer的配置选项
let audioCapturerOptions = {
streamInfo: audioStreamInfo,
capturerInfo: audioCapturerInfo
};
使用这些配置来创建AudioCapturer实例
audio.createAudioCapturer(audioCapturerOptions, (err, data) => {
if (err) {
console.error(`创建AudioCapturer失败, 错误码: ${err.code}, 错误信息: ${err.message}`);
} else {
console.info('成功创建AudioCapturer实例.');
let audioCapturer = data;
}
});
开始录音
创建AudioCapturer实例后,我们可以调用start()方法开始录音
audioCapturer.start((err) => {
if (err) {
console.error(`开始录音失败, 错误码: ${err.code}, 错误信息: ${err.message}`);
} else {
console.info('开始录音成功.');
}
});
读取和保存音频数据
在录音过程中,我们需要不断读取 AudioCapturer 的缓冲区,并将数据保存到文件中
import fs from '@ohos.file.fs';
// 打开文件准备写入
let file = fs.openSync(path, 0o2 | 0o100); // 0o2表示写入模式,0o100表示如果文件不存在则创建
// 获取缓冲区大小
let bufferSize = await audioCapturer.getBufferSize();
// 读取音频数据
let buffer = await audioCapturer.read(bufferSize, true);
// 将数据写入文件
fs.writeSync(file.fd, buffer);
注意: 在实际应用中,你可能需要在一个循环中反复执行读取和写入操作,直到录音结束。
停止录音
当需要停止录音时,调用stop()方法
audioCapturer.stop((err) => {
if (err) {
console.error(`停止录音失败, 错误码: ${err.code}, 错误信息: ${err.message}`);
} else {
console.info('录音已停止.');
}
});
释放资源
使用完AudioCapturer后,需要调用release()方法来释放资源
audioCapturer.release((err) => {
if (err) {
console.error(`释放AudioCapturer失败, 错误码: ${err.code}, 错误信息: ${err.message}`);
} else {
console.info('AudioCapturer资源已释放.');
}
});
我很乐意为您解释、细化和润色这段关于在鸿蒙OS上使用OpenSL ES开发音频录制功能的文字。我会使用简单易懂的技术语气,并增加必要的上下文和解释。
OpenSL ES 音频录制示例
OpenSL ES(Open Sound Library for Embedded Systems)是一个专为嵌入式系统设计的开放音频处理库。
添加必要的头文件
#include "SLES/OpenSLES.h"
#include "SLES/OpenSLES_OpenHarmony.h"
#include "SLES/OpenSLES_Platform.h"
创建和实例化引擎对象
OpenSL ES使用”引擎”作为所有音频操作的起点,需要创建并实例化这个引擎对象。
SLObjectItf engineObject = nullptr;
slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
slCreateEngine
函数创建引擎对象,Realize
函数实例化该对象。
获取引擎接口
接下来,获取引擎接口,这个接口将用于后续的操作。
SLEngineItf engineItf = nullptr;
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineItf);
配置录音器并创建录音对象
这一步我们需要配置录音的输入源和输出源,然后创建录音对象。
// 配置输入源
SLDataLocator_IODevice io_device = {
SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT,
NULL
};
SLDataSource audioSource = {&io_device, NULL};
// 配置输出源
SLDataLocator_BufferQueue buffer_queue = {
SL_DATALOCATOR_BUFFERQUEUE,
3
};
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM,
1, // 单声道
SL_SAMPLINGRATE_44_1, // 采样率: 44100Hz
SL_PCMSAMPLEFORMAT_FIXED_16, // 16位整数格式
0,
0,
0
};
SLDataSink audioSink = {&buffer_queue, &format_pcm};
// 创建录音对象
SLObjectItf pcmCapturerObject = nullptr;
(*engineItf)->CreateAudioRecorder(engineItf, &pcmCapturerObject,
&audioSource, &audioSink, 0, nullptr, nullptr);
(*pcmCapturerObject)->Realize(pcmCapturerObject, SL_BOOLEAN_FALSE);
获取录音接口
为了控制录音过程,我们需要获取录音接口。
SLRecordItf recordItf;
(*pcmCapturerObject)->GetInterface(pcmCapturerObject, SL_IID_RECORD, &recordItf);
获取缓冲队列接口
缓冲队列接口用于管理录音数据的缓冲。
SLOHBufferQueueItf bufferQueueItf;
(*pcmCapturerObject)->GetInterface(pcmCapturerObject, SL_IID_OH_BUFFERQUEUE, &bufferQueueItf);
注册缓冲队列回调
使用一个回调函数来处理录制的音频数据。
static void BufferQueueCallback(SLOHBufferQueueItf bufferQueueItf, void *pContext, SLuint32 size) {
SLuint8 *buffer = nullptr;
SLuint32 pSize = 0;
(*bufferQueueItf)->GetBuffer(bufferQueueItf, &buffer, &pSize);
if (buffer != nullptr) {
// 在这里处理录音数据
(*bufferQueueItf)->Enqueue(bufferQueueItf, buffer, size);
}
}
void *pContext; // 可以传入自定义的上下文信息
(*bufferQueueItf)->RegisterCallback(bufferQueueItf, BufferQueueCallback, pContext);
每当有新的音频数据可用时,这个回调函数就会被调用。
开始录音
现在可以开始录音了。
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
结束录音
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
(*pcmCapturerObject)->Destroy(pcmCapturerObject);
记得在完成录音后释放资源。