本文将通过一个完整的音频录制与播放示例,介绍如何在HarmonyOS应用中实现音频采集和播放功能。该应用包含开始录音、结束录音、播放录音和停止播放四个核心功能按钮,展示了HarmonyOS音频相关API的使用方法
1 App概述
1.1 功能介绍
本应用主要实现以下功能:
音频录制:通过设备麦克风采集音频数据并保存为PCM文件。
音频播放:读取PCM文件并通过音频设备进行播放。
状态显示:实时显示音频数据处理状态和字节数统计。
资源管理:完善的音频资源申请、使用和释放机制。
1.2 技术组件
应用使用了以下HarmonyOS ArkUI框架组件和API:
按钮组件(Button)
文本组件(Text)
弹性布局组件(Flex)
水平布局组件(Row)
垂直布局组件(Column)
音频采集器(audio.AudioCapturer)
音频渲染器(audio.AudioRenderer)
文件操作API(fileIo)
2 实战:实现音频录制播放应用
2.1 应用首页
Index.ets文件作为应用的入口页面,包含完整的UI布局和业务逻辑,首先初始化音频配置参数、音频渲染器实例、音频采集器实例。代码如下:
|
import { audio } from '@kit.AudioKit'; import { fileIo } from '@kit.CoreFileKit';
// 录音文件缓存位置 const filePath: string = getContext().cacheDir + '/result_48000_1.pcm';
@Entry @Component struct Index {
@State message: string = '待开始';
// ...音频配置参数
private audioRendererInfo: audio.AudioRendererInfo = {
usage: audio.StreamUsage.STREAM_USAGE_MOVIE,
rendererFlags: 0
};
// 音频渲染器实例
private audioRenderer: audio.AudioRenderer | null = null private audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
};
private audioCapturerInfo: audio.AudioCapturerInfo = { source: audio.SourceType.SOURCE_TYPE_MIC, capturerFlags: 0
};
// 音频采集器实例
private audioCapturer: audio.AudioCapturer | null = null
}
|
2.2 核心组件实现
2.2.1 UI布局组件
应用界面采用垂直布局,包含状态显示文本和四个功能按钮。
|
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button(('开始录音'), { type: ButtonType.Capsule })
.width(240)
.fontSize(40)
.fontWeight(FontWeight.Medium)
.margin({ top: 20, bottom: 20 })
.onClick(() => {
this.startCapturer(filePath)
})
Button(('结束录音'), { type: ButtonType.Capsule })
.width(240)
.fontSize(40)
.fontWeight(FontWeight.Medium)
.margin({ top: 20, bottom: 20 })
.onClick(() => {
// 获取结果
this.stopCapturer();
})
Button(('播放录音'), { type: ButtonType.Capsule })
.width(240)
.fontSize(40)
.fontWeight(FontWeight.Medium)
.margin({ top: 20, bottom: 20 })
.onClick(() => {
this.startRenderer(filePath)
})
Button(('停止播放'), { type: ButtonType.Capsule })
.width(240)
.fontSize(40)
.fontWeight(FontWeight.Medium)
.margin({ top: 20, bottom: 20 })
.onClick(() => {
this.stopRenderer();
})
}
.width('100%')
}
.height('100%') } |
2.2.2音频采集器管理
实现音频采集器的创建、启动和停止功能。
|
// 获取音频采集器实例 async getAudioCapturer() {
// 如果已经存在,直接返回
if (this.audioCapturer) {
return this.audioCapturer
}
// 创建音频采集器
const audioCapturer = await audio.createAudioCapturer({
streamInfo: this.audioStreamInfo,
capturerInfo: this.audioCapturerInfo
})
// 保存方便下次直接获取
this.audioCapturer = audioCapturer
// 返回音频采集器
return audioCapturer }
// 开始录音 async startCapturer(filePath: string) {
// 根据 filePath 打开文件,可读可写模式,如果文件不存在自动创建
const file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
// 1. 获取音频采集器
const audioCapturer = await this.getAudioCapturer()
// 偏移值
let bufferSize: number = 0
// 2. 调用on('readData')方法,订阅监听音频数据读入回调
audioCapturer.on('readData', (buffer) => {
// 把采集的音频信息写入到打开的文件中
fileIo.writeSync(file.fd, buffer, { offset: bufferSize, length: buffer.byteLength })
// 累加偏移值
bufferSize += buffer.byteLength
// 测试用的
this.message = bufferSize.toString();
})
// 3. 开始录音采集
audioCapturer.start() }
async stopCapturer(){
// 获取音频采集器
const audioCapturer = await this.getAudioCapturer()
await audioCapturer.stop() // 停止采集
audioCapturer.release() // 释放资源
this.audioCapturer = null // 重置采集器变量
// 测试用的
this.message = '停止录音'; }
|
2.2.3音频渲染器管理
实现音频播放器的创建、播放和停止功能
|
// 获取音频渲染器(播放器) async getAudioRenderer() {
if (this.audioRenderer) {
return this.audioRenderer
}
this.audioRenderer = await audio.createAudioRenderer({
streamInfo: this.audioStreamInfo,
rendererInfo: this.audioRendererInfo
})
return this.audioRenderer }
// 播放录音 async startRenderer(filePath: string) {
// 根据路径打开文件
const file = fileIo.openSync(filePath)
// 获取文件信息,如果读取时已经超出文件大小,自动停止
const stat = fileIo.statSync(file.fd)
// 1. 获取音频渲染器(播放器)
const audioRenderer = await this.getAudioRenderer()
// 偏移值
let bufferSize: number = 0
// 2. 调用on('writeData')方法,订阅监听音频数据写入回调
let writeDataCallback = (buffer: ArrayBuffer) => {
fileIo.readSync(file.fd, buffer, { offset: bufferSize, length: buffer.byteLength })
bufferSize += buffer.byteLength
this.message = bufferSize.toString()
if (bufferSize >= stat.size) {
// 停止渲染器(播放器)
audioRenderer.stop() // 停止
audioRenderer.release() // 释放资源
this.audioRenderer = null // 清理变量
} }
audioRenderer.on('writeData', writeDataCallback)
// 3. 启动音频渲染器(播放器)
audioRenderer.start() }
// 停止播放录音 async stopRenderer() {
// 获取音频渲染器(播放器)
const audioRenderer = await this.getAudioRenderer()
if (
audioRenderer.state === audio.AudioState.STATE_RUNNING
||
audioRenderer.state === audio.AudioState.STATE_PAUSED
) {
await audioRenderer.stop() // 停止
audioRenderer.release() // 释放资源
this.audioRenderer = null // 清理变量
}
this.message = '停止播放' } |
2.2.4 音频参数配置
应用使用标准的音频参数配置,确保录制和播放的质量:
|
private audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式 };
|
3 注意事项
3.1 权限配置
在module.json5中配置必要的音频权限:
|
"requestPermissions":[ {
"name" : "ohos.permission.INTERNET"
}, {
"name" : "ohos.permission.MICROPHONE",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"always"
} } ] |
3.2 权限校验
在entry\src\main\ets\entryability\EntryAbility.ets文件中,进行权限校验,用户同意授权后可以访问Index.ets文件。
|
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
// 权限校验
let context = this.context;
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let permissions: Array<Permissions> = ["ohos.permission.MICROPHONE"];
// requestPermissionsFromUser会判断权限的授权状态
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户同意授权
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
} else {
// 用户拒绝授权
return;
} }
// 授权成功
}).catch((err: BusinessError) => {
console.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`);
}) }
|
4 应用效果展示
应用运行效果如图所示,界面简洁明了,包含状态显示区和功能操作区。用户可以通过按钮完成完整的录音播放流程。

点击“开始录音”,录音时使用本地麦克风进行录制,如图所示:

点击“结束录音”,如图所示:

点击“播放录音”,如图所示:

点击“停止播放”,如图所示:

5 小结
本文详细介绍了HarmonyOS音频录制播放应用的完整开发过程,涵盖了音频采集、播放、文件操作等核心功能。通过本实例的学习,开发者可以掌握:
(1)HarmonyOS音频API的基本使用方法。
(2)音频采集器和渲染器的生命周期管理。
(3)文件读写操作与音频数据的处理。
(4)事件监听机制在音频开发中的应用。
这个实例为后续开发更复杂的音频处理应用奠定了坚实的基础,开发者可以在此基础上扩展音频编辑、特效处理等高级功能。
所有评论(0)