如何选择音频录制开发方式

系统提供了多样化的API,来帮助开发者完成音频录制的开发,不同的API适用于不同录音输出格式、音频使用场景或不同开发语言。因此,选择合适的音频录制API,有助于降低开发工作量,实现更佳的音频录制效果。

AVRecorder:用于音频录制的ArkTS/JS API,集成了音频输入录制、音频编码和媒体封装的功能。开发者可以直接调用设备硬件如麦克风录音,并生成m4a音频文件。

AudioCapturer:用于音频输入的的ArkTS/JS API,仅支持PCM格式,需要应用持续读取音频数据进行工作。应用可以在音频输出后添加数据处理,要求开发者具备音频处理的基础知识,适用于更专业、更多样化的媒体录制应用开发。

开发音频录制应用须知

理解app在需要使用麦克风的时候是要主动向用户申请权限的,只有得到用户授权后,app才能调用麦克风收集录音数据

使用abilityAccessCtrl.createAtManager()向用户申请麦克风权限ohos.permission.MICROPHONE

用户点击【允许】则直接对app开放了麦克风权限(什么都不用做)

用户点击【禁止】则需要调起系统应用管理,让用户手动打开麦克风权限

使用AVRecorder开发音频录制功能

1.1 module.json5声明麦克风权限

"requestPermissions": [
      {
        "name":"ohos.permission.MICROPHONE",
        "usedScene": {},
        "reason":"$string:EntryAbility_desc"
      }
    ],

1.2  向用户申请麦克风授权

import { abilityAccessCtrl } from '@kit.AbilityKit'

const atManager = abilityAccessCtrl.createAtManager()
const result = await atManager.requestPermissionsFromUser(
  getContext(),
  ['ohos.permission.MICROPHONE']
)

1.3 准备一个文件接收录音信息

// 准备一个文件来接收录音数据写入
const filePath = getContext().filesDir + '/' + Date.now() + '.m4a'
// 以【创建】和【读写】权限打开文件
const file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
// 获取文件地址
const fd = file.fd 

1.4 准备录音配置对象

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}`  //第一步中的文件地址
}

1.5 开始录制

// 创建录音对象
const avRecorder = await media.createAVRecorder()
// 设置录制参数,config是第2步中的录音对象
await avRecorder.prepare(config)  
// 开启录音
await avRecorder.start() 

1.6  停止录制

// 停止录制
await avRecorder.stop()
// 销毁实例,退出录制。
await avRecorder.release()

2.1 播放音频文件

使用fd://文件fd结合 AVPlayer 来完成录音的播放

使用timeUpdate来监听播放时间的改变

const file = fs.openSync(录音文件路径, fs.OpenMode.READ_ONLY)
  const avPlayer = await media.createAVPlayer()
  avPlayer.on('stateChange', state => {
    if (state === 'initialized') {
      avPlayer.prepare()
    } else if (state === 'prepared') {
      avPlayer.loop = true
      avPlayer.play()
    }
  })
  // 当前播放时间改变
  avPlayer.on('timeUpdate', (time) => {

  })
  avPlayer.url = `fd://${file.fd}`

2.2 播放录音

import { abilityAccessCtrl, common, Want } from '@kit.AbilityKit'
import fs from '@ohos.file.fs';
import { media } from '@kit.MediaKit';

@Entry
@Component
struct AudioPage {
  @StorageProp('topHeight') topHeight: number = 0
  avRecorder: media.AVRecorder = Object()
  @State filePath: string = ''

  async aboutToAppear() {
    // 向用户发起麦克风的授权提示
    let mgr = abilityAccessCtrl.createAtManager()
    //  利用mgr对象向用户发起麦克风的授权
    let result = await mgr.requestPermissionsFromUser(getContext(), ['ohos.permission.MICROPHONE'])
    // AlertDialog.show({ message: JSON.stringify(result, null, 2) })

    //  引导用户进行麦克风的二次授权
    if (result.authResults[0] == -1) {
      //  表示用户禁止了,应该提示用户二次授权
      // 定义参数
      const want: Want = {
        bundleName: 'com.huawei.hmos.settings', //固定的
        abilityName: 'com.huawei.hmos.settings.MainAbility', //固定
        uri: 'application_info_entry', //固定
        parameters: {
          // ✨✨✨修改成你的应用包名,跳转到该应用的设置页面
          pushParams: 'com.itcast.interview_bjhm4App'  //我们开发的app的包名称 -> AppScope-> app.json5中获取
        }
      }

      // 利用上面的参数直接调起授权页面(操作系统)
      let ctx = getContext() as common.UIAbilityContext
      ctx.startAbility(want)
    }
  }

  build() {
    Column() {

      Text(this.filePath)

      Button('开始录制').onClick(async () => {
        // 1. 准备录制的文件
        let filePath = getContext().filesDir + '/' + Date.now() + '.m4a'
        this.filePath = filePath
        // 将这个文件以创建和读写权限打开
        let file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
        // file.fd
        //   2. 准备录制的参数
        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}`  //第一步中的文件地址
        }
        //   3. 创建AVRecorder对象开始录制
        // 创建录音对象
        const avRecorder = await media.createAVRecorder()
        this.avRecorder = avRecorder

        //   配置参数
        await avRecorder.prepare(config)
        await avRecorder.start()
        AlertDialog.show({ message: JSON.stringify('录音开始') })
      })

      Button('停止录制').onClick(async () => {
        await this.avRecorder.stop() //停止录音
        await this.avRecorder.release() //销毁和释放录音对象
      })

      Button('播放录音')
        .onClick(async () => {
          //  1. 获取当前录音文件的路径,用openSync打开
          const file = fs.openSync(this.filePath, fs.OpenMode.READ_ONLY) //以只读方式打开录音文件

          //   2. 创建播放对象 AVPlayer
          const avPlayer = await media.createAVPlayer()

          //   3. 注册stateChange监听
          avPlayer.on('stateChange', (state) => {
            if (state == 'initialized') {
              avPlayer.prepare()
            }

            if (state == 'prepared') {

              avPlayer.play()
            }
          })

          //   4. 赋值播放源: fd://文件的数字标记
          avPlayer.url = `fd://${file.fd}`

        })

    }
    .height('100%')
    .width('100%')

    .padding({ top: this.topHeight })

  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐