社区录音机样例Recorder

​applications_app_samples/code/SystemFeature/Media/Recorder · OpenHarmony/applications_app_samples - AtomGit | GitCode​

修复一些bug以及增加选择麦克风功能,提供适用于API23的hap包,见文末

1、修复横屏状态下分屏布局问题

问题现象

录音结束后返回主页面,主页面和播放页面同时显示(一左一右),无法正常交互,必须重启应用才能恢复

问题原因

Index.ets 中的 onPortrait 方法监听屏幕方向变化,当检测到横屏时设置 this.isLand = true ,触发了系统的分屏布局模式。

修复方案

文件 : Index.ets

  onPortrait = (mediaQueryResult: mediaQuery.MediaQueryResult) => {
    // this.isLand = mediaQueryResult.matches;// 注释此行禁用横屏分屏
    Logger.info(TAG, `onPortrait: isLand=${this.isLand}`);
  }

2、修复路由栈增长导致多次返回问题

问题现象

播放录音页面点击左上角返回键返回到首页后,播放过几次就需要点击系统返回键几次才能退出到桌面。但在播放界面点击系统返回键返回到首页后,只需点击一次即可返回桌面。

问题原因

TitleWithBack.ets 中的返回按钮使用 router.replaceUrl({ url: 'pages/Index' }) ,每次都会在路由栈上添加一个新的 Index 页面,导致路由栈不断增长。

修复方案

文件 : TitleWithBack.ets

// 修改前
.onClick(() => {
  router.replaceUrl({ url: 'pages/Index' });
})

// 修改后
.onClick(() => {
  router.back();
})

3、添加麦克风选择功能

功能需求

在录音机应用中增加麦克风设备选择功能,支持切换内置麦克风、USB耳机麦等设备。

注:麦克风需要系统层支持才能识别;有些麦克风识别到了,采样率可能未适配也无法录音

实现方案

(1)在 RecordModel.ts 中添加麦克风管理方法

新增成员变量 :

 private audioRoutingManager: audio.AudioRoutingManager | null = null;
  private micDevices: audio.AudioDeviceDescriptors = [];
  private selectedMicDevice: audio.AudioDeviceDescriptor | null = null;
  private deviceChangeListener: ((deviceChanged: audio.DeviceChangeAction) => void) | null = null;

新增方法 :

方法名

功能说明

initAudioRoutingManager()

初始化音频路由管理器

getAvailableMicDevices()

获取可用麦克风设备列表

selectMicDevice(device)

选择指定麦克风设备

getSelectedMicDevice()

获取当前选中的麦克风设备

registerDeviceChangeListener(callback)

注册设备变化监听器

unregisterDeviceChangeListener()

注销设备变化监听器

核心代码 :

  async initAudioRoutingManager() {
    try {
      const audioManager = audio.getAudioManager();
      this.audioRoutingManager = audioManager.getRoutingManager();
      Logger.info(TAG, 'init audio routing manager success');
    } catch (error) {
      Logger.error(TAG, `init audio routing manager failed: ${error}`);
    }
  }

  async getAvailableMicDevices(): Promise<audio.AudioDeviceDescriptors> {
    if (!this.audioRoutingManager) {
      Logger.error(TAG, 'audio routing manager is not initialized');
      return [];
    }

    try {
      const devices = await this.audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG);
      this.micDevices = devices.filter((device: audio.AudioDeviceDescriptor) => {
        return device.deviceType === audio.DeviceType.MIC ||
          device.deviceType === audio.DeviceType.WIRED_HEADSET ||
          device.deviceType === audio.DeviceType.BLUETOOTH_SCO ||
          device.deviceType === audio.DeviceType.USB_HEADSET ||
          device.deviceType === 31;
      });

      if (this.micDevices.length > 0) {
        if (!this.selectedMicDevice || !this.micDevices.some((d: audio.AudioDeviceDescriptor) => d.id === this.selectedMicDevice!.id)) {
          this.selectedMicDevice = this.micDevices[0];
          try {
            await this.audioRoutingManager.selectInputDevice([this.selectedMicDevice]);
            Logger.info(TAG, `default select mic: ${this.getDeviceDisplayName(this.selectedMicDevice)}`);
          } catch (error) {
            Logger.error(TAG, `default select mic failed: ${error}`);
          }
        }
      } else {
        this.selectedMicDevice = null;
      }

      Logger.info(TAG, `available mic devices: ${this.micDevices.length}`);
      return this.micDevices;
    } catch (error) {
      Logger.error(TAG, `get available mic devices failed: ${error}`);
      return [];
    }
  }

  async selectMicDevice(device: audio.AudioDeviceDescriptor): Promise<boolean> {
    if (!this.audioRoutingManager) {
      Logger.error(TAG, 'audio routing manager is not initialized');
      return false;
    }

    try {
      await this.audioRoutingManager.selectInputDevice([device]);
      this.selectedMicDevice = device;
      Logger.info(TAG, `select mic device success: ${this.getDeviceDisplayName(device)}`);
      return true;
    } catch (error) {
      let err = error as BusinessError.BusinessError;
      Logger.error(TAG, `select mic device failed: ${err.code} - ${err.message}`);
      return false;
    }
  }

(2) 在 RecordPage.ets 中添加麦克风选择 UI

新增状态变量 :

@State micDevices: audio.AudioDeviceDescriptors = [];
@State selectedMicDevice: audio.AudioDeviceDescriptor | null = null;

    页面生命周期处理 :

     async aboutToAppear() {
        await this.recordModel.initAudioRoutingManager();
        await this.refreshMicDevices();
        this.recordModel.registerDeviceChangeListener(() => {
          this.refreshMicDevices();
        });
      }
    
      async refreshMicDevices() {
        this.micDevices = await this.recordModel.getAvailableMicDevices();
        this.selectedMicDevice = this.recordModel.getSelectedMicDevice();
      }

      麦克风选择 UI :

       Text('选择麦克风')
                    .fontColor(Color.Black)
                    .fontSize(22)
                    .fontWeight(FontWeight.Bold)
                    .margin({ bottom: 16 })
      
                  Row({ space: 8 }) {
                    ForEach(this.micDevices, (device: audio.AudioDeviceDescriptor) => {
                      Button(this.recordModel.getDeviceDisplayName(device))
                        .layoutWeight(1)
                        .height(48)
                        .fontSize(16)
                        .backgroundColor(this.selectedMicDevice?.id === device.id ? '#007DFF' : '#E0E0E0')
                        .fontColor(this.selectedMicDevice?.id === device.id ? '#FFFFFF' : '#333333')
                        .borderRadius(8)
                        .onClick(() => this.selectMicDevice(device))
                    }, (device: audio.AudioDeviceDescriptor) => device.id.toString())
                  }
                  .width('100%')
      
                  if (this.micDevices.length === 0) {
                    Text('未检测到麦克风设备')
                      .fontColor(Color.Gray)
                      .fontSize(18)
                      .margin({ top: 16 })
                  }

      修改文件清单

      文件路径

      修改内容

      entry/src/main/ets/pages/Index.ets

      注释横屏分屏布局控制代码

      entry/src/main/ets/common/TitleWithBack.ets

      返回按钮改用 router.back()

      entry/src/main/ets/pages/RecordPage.ets

      添加麦克风选择 UI 和返回键拦截

      entry/src/main/ets/model/RecordModel.ts

      添加麦克风设备管理方法

      hap文件下载地址:

      ​Recorder6.1.hap · 阿伟/hap - 码云 - 开源中国​

      联系方式2968675576@qq.com

      Logo

      社区规范:仅讨论OpenHarmony相关问题。

      更多推荐