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 (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)事件监听机制在音频开发中的应用。

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

相关推荐
2601_949593655 小时前
基础入门 React Native 鸿蒙跨平台开发:BackHandler 返回键控制
react native·react.js·harmonyos
mocoding5 小时前
使用Flutter强大的图标库fl_chart优化鸿蒙版天气预报温度、降水量、湿度展示
flutter·华为·harmonyos
Cobboo6 小时前
i单词上架鸿蒙应用市场之路:一次从 Android 到 HarmonyOS 的完整实战
android·华为·harmonyos
2601_949593656 小时前
高级进阶 React Native 鸿蒙跨平台开发:LinearGradient 动画渐变效果
react native·react.js·harmonyos
熊猫钓鱼>_>7 小时前
【开源鸿蒙跨平台开发先锋训练营】鸿蒙应用开发 Day 10 - React Native for OpenHarmony 实战:多端响应式布局与高可用交互设计
华为·开源·交互·harmonyos·鸿蒙·rn·gridrow
摘星编程7 小时前
React Native鸿蒙:自定义useField字段状态绑定
react native·react.js·harmonyos
人工智能知识库8 小时前
华为数通HCIA-Datacom H12-811题库(26最新详细解析)
华为·hcia-datacom·题库·h12-811·最新题库
酣大智8 小时前
参考模型--数据链路层
运维·网络·网络协议·tcp/ip·华为
Miguo94well8 小时前
Flutter框架跨平台鸿蒙开发——学校校历APP的开发流程
flutter·华为·harmonyos·鸿蒙
一起养小猫8 小时前
Flutter for OpenHarmony网络请求与数据持久化完全指南
开发语言·网络·jvm·数据库·flutter·harmonyos