
《鸿蒙开发实战:音频录制、文件读取与播放功能全解析》
完整的录制音频的流程:1.由于录音会调用手机端麦克风,所以需要做如下权限配置,在项目的module.json5中声明麦克风的使用权限使用鸿蒙的底层api来向用户申请麦克风的使用权限使用abilityAccessCtrl这个api来授权如果用户禁止使用麦克风,则使用UIAbilityContent的startAbility来进行二次引导授权此时用户如果点击了禁止,我们应该引导用户进行二次权限设置。
引言
随着HarmonyOS生态的快速发展,音频处理能力成为应用开发的核心需求之一。本文将从音频录制、文件存储管理、音频播放三个模块出发,结合完整代码示例,详解鸿蒙系统中音频功能的全链路开发实践。
1.1 核心模块
- 音频录制:基于Meadia Kit的AVRecorder实现高精度录音,支持实时波形显示。
- 文件管理:通过沙箱路径读写音频文件,适配不同设备存储策略。
- 音频播放:利用
AVPlayer
组件实现本地文件播放与状态控制。
二、音频录制实现
1、申请权限
在module.json5声明麦克风权限
//src/main/module.json5
"requestPermissions": [
{
"name":"ohos.permission.MICROPHONE",
"usedScene": {},
"reason":"$string:EntryAbility_desc"
}
],
首先录音,那必然是需要录音权限,我们先询问用户申请录音权限,只有拿到录音权限之后才能够去录音。
使用
abilityAccessCtrl.createAtManager()
向用户申请麦克风权限ohos.permission.MICROPHONE
async apply_for_right(){
// 向用户申请麦克风权限
const manager = abilityAccessCtrl.createAtManager()
const result = await manager.requestPermissionsFromUser(getContext(), ['ohos.permission.MICROPHONE'])
if(result.authResults[0] === -1) {
// 表示用户点击了禁用,直接打开设置页面,要用户去设置
// 定义参数
const want: Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// ✨✨✨修改成你的应用包名,跳转到该应用的设置页面 (包名在APP.json5)
pushParams: 'com.example.hm_mianjing'
}
}
const uiContext = getContext() as common.UIAbilityContext
// 调起手机设置中的当前应用设置面板
uiContext.startAbility(want)
}
}
如果用户点击了不允许录音,那我们便要向用户二次申请授权
在“设置”应用中的路径:设置 > 应用和元服务 > 某个应用
跳转的核心代码
// 定义参数
const want: Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// ✨✨✨修改成你的应用包名,跳转到该应用的设置页面
pushParams: 'com.itcast.interview_bjhm4App'
}
}
const uiContext = getContext() as common.UIAbilityContext
// 调起手机设置中的当前应用设置面板
uiContext.startAbility(want)
2.录制音频
利用AVRecorder
录制基本的.m4a的音频文件
录制的核心代码
// 准备一个文件来接收录音数据写入
const filePath = getContext().filesDir + '/' + Date.now() + '.m4a'
// 以【创建】和【读写】权限打开文件
const file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
// 获取文件地址
const fd = file.fd
录音的配置对象
const config: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, //音频采集源为麦克风
profile: {
audioBitrate: 100000, // 音频比特率
audioChannels: 1, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前只支持aac
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前只支持m4a
},
url: `fd://${file.fd}` //第一步中的文件地址
}
完整的录制代码
// 录制
async transcribe(){
// 1. 创建了录音对象
this.avRecorder = await media.createAVRecorder()
// 2.事件监听
// 状态上报回调函数
this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
console.log(`current state is ${state}`);
// 用户可以在此补充状态发生切换后想要进行的动作
})
// 错误上报回调函数
this.avRecorder.on('error', (err: BusinessError) => {
console.error(`avRecorder failed, code is ${err.code}, message is ${err.message}`);
})
// 3.配置录音参数
let avProfile: media.AVRecorderProfile = {
audioBitrate: 100000, // 音频比特率
audioChannels: 2, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
};
const context: Context = getContext(this); // 参考应用文件访问与管理
this.filePath = context.filesDir + '/'+ Date.now() + '.mp3';
let audioFile: fs.File = fs.openSync(this.filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let fileFd: number = audioFile.fd; // 获取文件fd
let avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源,这里设置为麦克风
profile: avProfile,
url: 'fd://' + fileFd.toString(), // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处
};
await this.avRecorder.prepare(avConfig)
// 4. 开始录音
this.avRecorder.start()
}
3.播放音频
使用fd://文件fd
结合 AVPlayer 来完成录音的播放
使用 timeUpdate
来监听播放时间的改变
//创建播放器对象
const player = await media.createAVPlayer();
player.on('stateChange',state=>{
if (state === 'initialized') {
player.prepare()
}else if(state === 'prepared'){
// player.loop = true
player.play()
}
})
const file = fs.openSync(this.filePath,fs.OpenMode.READ_ONLY)
// 赋值播放源: fd://文件的数字标记
player.url = 'fd://' + file.fd
完整代码
import { abilityAccessCtrl, common, Want } from '@kit.AbilityKit'
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import fs from '@ohos.file.fs';
import { relationalStore } from '@kit.ArkData';
import json from '@ohos.util.json';
interface IArticle {
id: number
title: string
content: string
create_time: number
}
@Entry
@Component
struct AvrecorderAndRdbDemoPage {
// 数据库表名
tableName: string = 'article' //数据库的表名称,由我们自己定义
store: relationalStore.RdbStore = {} as relationalStore.RdbStore
filePath: string = ''
@State buttonColor:boolean = false
// 创建AVRecorder实例
avRecorder: media.AVRecorder = {} as media.AVRecorder
// 申请权限
async apply_for_right(){
// 向用户申请麦克风权限
const manager = abilityAccessCtrl.createAtManager()
const result = await manager.requestPermissionsFromUser(getContext(), ['ohos.permission.MICROPHONE'])
if(result.authResults[0] === -1) {
// 表示用户点击了禁用,直接打开设置页面,要用户去设置
// 定义参数
const want: Want = {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// ✨✨✨修改成你的应用包名,跳转到该应用的设置页面 (包名在APP.json5)
pushParams: 'com.example.hm_mianjing'
}
}
const uiContext = getContext() as common.UIAbilityContext
// 调起手机设置中的当前应用设置面板
uiContext.startAbility(want)
}
}
// 录制
async transcribe(){
// 1. 创建了录音对象
this.avRecorder = await media.createAVRecorder()
// 2.事件监听
// 状态上报回调函数
this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
console.log(`current state is ${state}`);
// 用户可以在此补充状态发生切换后想要进行的动作
})
// 错误上报回调函数
this.avRecorder.on('error', (err: BusinessError) => {
console.error(`avRecorder failed, code is ${err.code}, message is ${err.message}`);
})
// 3.配置录音参数
let avProfile: media.AVRecorderProfile = {
audioBitrate: 100000, // 音频比特率
audioChannels: 2, // 音频声道数
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
audioSampleRate: 48000, // 音频采样率
fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
};
const context: Context = getContext(this); // 参考应用文件访问与管理
this.filePath = context.filesDir + '/'+ Date.now() + '.mp3';
let audioFile: fs.File = fs.openSync(this.filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let fileFd: number = audioFile.fd; // 获取文件fd
let avConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源,这里设置为麦克风
profile: avProfile,
url: 'fd://' + fileFd.toString(), // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处
};
await this.avRecorder.prepare(avConfig)
// 4. 开始录音
this.avRecorder.start()
}
build() {
Column({space:10}){
Button('获取权限')
.onClick(()=>{
this.apply_for_right()
})
.margin({bottom:20})
Row({space:10}){
Button('开始录制')
.onClick(() => {
this.buttonColor = true
this.transcribe()
})
Button('停止录制')
.backgroundColor(this.buttonColor? Color.Red :'common_blue')
.onClick(() => {
this.buttonColor = false
// 停止录制
this.avRecorder.stop();
// 重置资源
this.avRecorder.reset();
// 销毁实例
this.avRecorder.release();
})
}
Button('播放音频')
.margin({top:20})
.onClick(async ()=>{
//创建播放器对象
const player = await media.createAVPlayer();
player.on('stateChange',state=>{
if (state === 'initialized') {
player.prepare()
}else if(state === 'prepared'){
// player.loop = true
player.play()
}
})
const file = fs.openSync(this.filePath,fs.OpenMode.READ_ONLY)
// 赋值播放源: fd://文件的数字标记
player.url = 'fd://' + file.fd
})
}.width('100%')
.height('100%')
}
}
总结:
完整的录制音频的流程:
1.由于录音会调用手机端麦克风,所以需要做如下权限配置,在项目的module.json5中声明麦克风的使用权限使用鸿蒙的底层api来向用户申请麦克风的使用权限使用abilityAccessCtrl这个api来授权
如果用户禁止使用麦克风,则使用UIAbilityContent的startAbility来进行二次引导授权此时用户如果点击了禁止,我们应该引导用户进行二次权限设置。
2.此时可以使用 AVRecorder对象来进行音频的录制在应用程序目录的files下准备一个文件用来接收音频数据的利用AVRecorder的start方法来采集麦克风的音频数据。
3.此时自动将音频数据保存到文件中使用AVPlayer对象播放录制好的音频。
适用HarmonyOS NEXT / API12或以上版本 -----------------
更多推荐
所有评论(0)