HarmonyOS App开发 ——鸿蒙录音机应用App开发

本文将通过一个完整的音频录制与播放示例,介绍如何在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 (grantStatusi === 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)事件监听机制在音频开发中的应用。

这个实例为后续开发更复杂的音频处理应用奠定了坚实的基础,开发者可以在此基础上扩展音频编辑、特效处理等高级功能。

相关推荐
donk13145 小时前
React Native for OpenHarmony 实战:三方库 react-native-toast-message 的鸿蒙化适配指南
react native·react.js·音视频·harmonyos
Flutter_OH5 小时前
Flutter OHOS Dart 堆栈符号化
harmonyos
Flutter_OH6 小时前
Flutter OHOS Flutter 多设备自适应 DPI 指导文档
harmonyos
SuperHeroWu76 小时前
【HarmonyOS 7】 应用 Agent 接入云 A2A 与端 A2A 的实践详解
ai·harmonyos·小艺
用户29469405448167 小时前
个人开发者上架鸿蒙 AI 应用,最后倒在安全评估实名制这一格
harmonyos·deepseek
Keya7 小时前
HarmonyOS 开发实战:用 util.Aspect 玩转 AOP 切面编程
harmonyos
威哥爱编程8 小时前
HarmonyOS 7 Agent 开发实战 03:Tool Calling 让 AI 查实时订单与库存
agent·harmonyos
威哥爱编程8 小时前
HarmonyOS 7 Agent 开发实战 02:Agent 工程脚手架与对话 UI 骨架
agent·harmonyos
Georgewu16 小时前
【HarmonyOS 7】 HarmonyOS 应用 Skill创建和编排详解
harmonyos
Georgewu18 小时前
【HarmonyOS 7】 应用 Agent 接入云 A2A 与端 A2A 的实践详解
harmonyos