HarmonyOS Next->鸿蒙修仙传之我要录音 -> AvRecorder

打印 上一主题 下一主题

主题 1890|帖子 1890|积分 5670

结果图:
 



要想录音,得开启录音权限副本:

       1. 在module.json5里配置麦克风权限:
  1. "requestPermissions": [
  2.       {
  3.         "name": "ohos.permission.MICROPHONE",
  4.         "usedScene": {},
  5.         "reason": "$string:MICROPHONE_use_reason"
  6.       }
  7. ]
复制代码
        2. 麦克风权限是用户级权限,必要向用户申请,可以用上篇封装的请求权限工具发起申请。
开启/关闭录音要借助音频工具:AVRecorder 

  1. /**
  2.   * 开始录音
  3. */
  4. async startRecord() {
  5.     // 创建音频接收对象
  6.     const avRecorder = await media.createAVRecorder()
  7.     const ctx = getContext(this) // 获取上下文
  8.     const filePath = ctx.filesDir + '/' + Date.now() + '.m4a' // 创建文件路径
  9.     const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE) // 打开或创建文件
  10.     this.fd = file.fd // 存到全局
  11.     // 创建音频配置
  12.     const avConfig: media.AVRecorderConfig = {
  13.       audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源设置为麦克风
  14.       profile: {
  15.         audioBitrate: 100000, // 音频比特率
  16.         audioChannels: 2, // 音频声道数
  17.         audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
  18.         audioSampleRate: 48000, // 音频采样率
  19.         fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
  20.       },
  21.       url: `fd://${file.fd}`, // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处
  22.     }
  23.     // 准备录音
  24.     await avRecorder.prepare(avConfig)
  25.     // 开始录音
  26.     await avRecorder.start()
  27.     // 把音频对象存到全局存到全局
  28.     this.avRecorder = avRecorder
  29.     // 持续监听声音的振幅
  30.     this.timerId = setInterval(async () => {
  31.       const res = await avRecorder.getAudioCapturerMaxAmplitude() // 获取声音振幅>数字
  32.       this.maxAmplitude = res // 赋值到全局
  33.     }, 100)
  34.   }
  35. /**
  36.   * 结束录音
  37. */
  38. async stopRecord() {
  39.     if (this.avRecorder) {
  40.       await this.avRecorder.stop() // 停止录音
  41.       await this.avRecorder.release() // 释放资源
  42.       fileIo.closeSync(this.fd) // 关闭文件
  43.       clearInterval(this.timerId) // 清除定时器
  44.       this.maxAmplitude = 0 // 重置振幅
  45.     }
  46. }
复制代码
绑定对应的变乱分别调用录音和结束录音 

 振幅拿到了,现在要给它动态展示出来:

        循环30个柱子,高度参差不齐,随着振幅变 -> 监听振幅,盘算高度
  1. // AudioBoComp组件
  2. @Component
  3. export struct AudioBoComp {
  4.   @Prop @Watch('onChange') maxAmplitude: number // 振幅
  5.   @State per: number = 0 // 高
  6.   onChange() {
  7.     // 过渡
  8.     animateTo({ duration: 100 }, () => {
  9.       if (this.maxAmplitude < 500) { // 500以下高度为零
  10.         this.per = 0
  11.       } else if (this.maxAmplitude > 30000) { // 30000以上高度为1
  12.         this.per = 1
  13.       } else { // 高度为振幅比最大高
  14.         this.per = this.maxAmplitude / 30000
  15.       }
  16.     })
  17.   }
  18.   build() {
  19.     Row({ space: 5 }) {
  20.       // 循环30个柱子
  21.       ForEach(Array.from({ length: 30 }), () => {
  22.         Column()
  23.           .layoutWeight(1)
  24.           .height(this.per * 100 * Math.random()) // 高度按振幅 随机 这样才参差不齐
  25.           .backgroundColor('#ff08a9be')
  26.       })
  27.     }
  28.     .width('100%')
  29.     .height(100)
  30.   }
  31. }
复制代码
我们把它封装成一个组件吧,以后还能直接用 

  1. <strong>AudioBoComp({maxAmplitude: this.maxAmplitude})把振幅穿过去</strong>
复制代码
整体代码:

  录音页:

  1. import { Permissions } from '@kit.AbilityKit';
  2. import { permission } from '../utils'; // 上篇封装的权限工具
  3. import { promptAction, router } from '@kit.ArkUI';
  4. import { media } from '@kit.MediaKit';
  5. import { fileIo } from '@kit.CoreFileKit';
  6. import { AudioBoComp } from '../components'; // 波动组件
  7. @Entry
  8. @Component
  9. struct AudioPage {
  10.   // 1. 权限列表
  11.   permissions: Permissions[] = ['ohos.permission.MICROPHONE']
  12.   confirmConfig:  promptAction.ShowDialogOptions = {
  13.     title: "温馨提示",
  14.     message: "未授权使用麦克风将无法使用该面试录音功能,是否前往设置进行授权?",
  15.     buttons: [
  16.       { text: '离开', color: '#ccc' },
  17.       { text: '去授权', color: $r('app.color.black') }
  18.     ]
  19.   } // 弹窗配置
  20.   // 2. 音频接收对象
  21.   avRecorder?: media.AVRecorder
  22.   // 3. 写入的文件fd
  23.   fd?: number
  24.   // 4. 记录声音的振幅
  25.   @State maxAmplitude: number = 0
  26.   timerId = 0 // 定时器id
  27.   async aboutToAppear() {
  28.     // 进入改页面时,获取权限
  29.     this.getPermission()
  30.   }
  31.   /**
  32.    * 获取麦克风权限
  33.    */
  34.   async getPermission(){
  35.     try {
  36.       // 1. 第一次拉起授权
  37.       const isOk1 = await permission.requestPermission(this.permissions)
  38.       if(isOk1) return
  39.       // 2. 弹窗再次确认
  40.       const res = await promptAction.showDialog(this.confirmConfig)
  41.       if(res.index === 1){
  42.         // 3. 二次授权
  43.         const isOk2 = await permission.permissionSetting(this.permissions)
  44.         if(isOk2) return
  45.       }
  46.       // 授权都不通过,退出该页面
  47.       router.back()
  48.     } catch (e) {
  49.       promptAction.showToast({message: '用户授权出现问题'})
  50.       router.back()
  51.     }
  52.   }
  53.   /**
  54.    * 开始录音
  55.    */
  56.   async startRecord(){
  57.     // 创建音频接收对象
  58.     const avRecorder = await media.createAVRecorder()
  59.     const ctx = getContext(this) // 获取上下文
  60.     const filePath = ctx.filesDir + '/' + Date.now() + '.m4a' // 创建文件路径
  61.     const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE) // 打开或创建文件
  62.     this.fd = file.fd // 存到全局
  63.     // 创建音频配置
  64.     const avConfig: media.AVRecorderConfig = {
  65.       audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源设置为麦克风
  66.       profile: {
  67.         audioBitrate: 100000, // 音频比特率
  68.         audioChannels: 2, // 音频声道数
  69.         audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式,当前支持ACC,MP3,G711MU
  70.         audioSampleRate: 48000, // 音频采样率
  71.         fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式,当前支持MP4,M4A,MP3,WAV
  72.       },
  73.       url: `fd://${file.fd}`, // 参考应用文件访问与管理中的开发示例获取创建的音频文件fd填入此处
  74.     }
  75.     // 准备录音
  76.     await avRecorder.prepare(avConfig)
  77.     // 开始录音
  78.     await avRecorder.start()
  79.     // 把音频对象存到全局存到全局
  80.     this.avRecorder = avRecorder
  81.     // 持续监听声音的振幅
  82.     this.timerId = setInterval(async ()=>{
  83.       const res = await avRecorder.getAudioCapturerMaxAmplitude() // 获取声音振幅
  84.       this.maxAmplitude = res // 赋值到全局
  85.     }, 100)
  86.   }
  87.   /**
  88.    * 结束录音
  89.    */
  90.   async stopRecord(){
  91.     if (this.avRecorder) {
  92.       await this.avRecorder.stop() // 停止录音
  93.       await this.avRecorder.release() // 释放资源
  94.       fileIo.closeSync(this.fd) // 关闭文件
  95.       clearInterval(this.timerId) // 清除定时器
  96.       this.maxAmplitude = 0 // 重置振幅
  97.     }
  98.   }
  99.   build() {
  100.     Column({space: 5}){
  101.       AudioBoComp({maxAmplitude: this.maxAmplitude})
  102.       Button('开始录音')
  103.         .onClick(()=>{
  104.           this.startRecord()
  105.         })
  106.       Button('结束录音')
  107.         .onClick(()=>{
  108.           this.stopRecord()
  109.         })
  110.     }
  111.     .justifyContent(FlexAlign.Center)
  112.     .height('100%')
  113.     .width('100%')
  114.   }
  115. }
复制代码
振幅组件: 

  1. @Component
  2. export struct AudioBoComp {
  3.   @Prop @Watch('onChange') maxAmplitude: number // 振幅
  4.   @State per: number = 0 // 高
  5.   onChange() {
  6.     // 过渡
  7.     animateTo({ duration: 100 }, () => {
  8.       if (this.maxAmplitude < 500) { // 500以下高度为零
  9.         this.per = 0
  10.       } else if (this.maxAmplitude > 30000) { // 30000以上高度为1
  11.         this.per = 1
  12.       } else { // 高度为振幅比最大高
  13.         this.per = this.maxAmplitude / 30000
  14.       }
  15.     })
  16.   }
  17.   build() {
  18.     Row({ space: 5 }) {
  19.       // 循环30个柱子
  20.       ForEach(Array.from({ length: 30 }), () => {
  21.         Column()
  22.           .layoutWeight(1)
  23.           .height(this.per * 100 * Math.random()) // 高度按振幅 随机 这样才参差不齐
  24.           .backgroundColor('#ff08a9be')
  25.       })
  26.     }
  27.     .width('100%')
  28.     .height(100)
  29.   }
  30. }
复制代码
   权限工具:

  1. import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit'
  2. class Permission {
  3.   // 申请权限
  4.   async requestPermission(permissions: Permissions[]) {
  5.     // 1. 创建权限管理对象
  6.     const atManager = abilityAccessCtrl.createAtManager()
  7.     // 2. 弹窗授权窗口
  8.     const ctx = AppStorage.get<Context>('context')
  9.     if (ctx) {
  10.       const res =  await atManager.requestPermissionsFromUser(ctx, permissions)
  11.       // 3. 判断用户是否授权
  12.       const flag = res.authResults.every(item => item === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED )
  13.       return flag
  14.     } else {
  15.       return false
  16.     }
  17.   }
  18.   // 二次申请
  19.   async permissionSetting(permissions: Permissions[]) {
  20.     const atManager = abilityAccessCtrl.createAtManager()
  21.     const ctx = AppStorage.get<Context>('context')
  22.     if (ctx) {
  23.       const res = await atManager.requestPermissionOnSetting(ctx, permissions)
  24.       const flag = res.every(item => item === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
  25.       return flag
  26.     }
  27.     return false
  28.   }
  29. }
  30. export const permission = new Permission()
复制代码
天选之人

        



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

花瓣小跑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表