【鸿蒙实战开发】HarmonyOS音频录制开发实现

192 篇文章 2 订阅
192 篇文章 0 订阅

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

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

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

  • OpenSL ES:一套跨平台标准化的音频Native API,同样提供音频输入原子能力,仅支持PCM格式,适用于从其他嵌入式平台移植,或依赖在Native层实现音频输入功能的录音应用使用。

  • OHAudio:用于音频输入的Native API,此API在设计上实现归一,同时支持普通音频通路和低时延通路。仅支持PCM格式,适用于依赖Native层实现音频输入功能的场景。

除上述方式外,也可以通过Media Kit实现音频播放。

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

开发音频录制应用须知

  • 应用可以调用麦克风录制音频,但该行为属于隐私敏感行为,在调用麦克风前,需要先向用户申请权限:ohos.permission.MICROPHONE。

    如何使用和管理麦克风请参考管理麦克风。

  • 如果需要持续录制或后台录制,请申请长时任务避免进入挂起(Suspend)状态。具体参考长时任务开发指导。

  • 录制需要在前台启动,启动后可以退后台。在后台启动录制将会失败。

使用AudioCapturer开发音频录制功能

AudioCapturer是音频采集器,用于录制PCM(Pulse Code Modulation)音频数据,适合有音频开发经验的开发者实现更灵活的录制功能。

开发指导

使用AudioCapturer录制音频涉及到AudioCapturer实例的创建、音频采集参数的配置、采集的开始与停止、资源的释放等。本开发指导将以一次录制音频数据的过程为例,向开发者讲解如何使用AudioCapturer进行音频录制,建议搭配AudioCapturer的API说明阅读。

下图展示了AudioCapturer的状态变化,在创建实例后,调用对应的方法可以进入指定的状态实现对应的行为。需要注意的是在确定的状态执行不合适的方法可能导致AudioCapturer发生错误,建议开发者在调用状态转换的方法前进行状态检查,避免程序运行产生预期以外的结果。

图1 AudioCapturer状态变化示意图

image.png

使用on(‘stateChange’)方法可以监听AudioCapturer的状态变化,每个状态对应值与说明见AudioState。

开发步骤及注意事项

  1. 配置音频采集参数并创建AudioCapturer实例,音频采集参数的详细信息可以查看AudioCapturerOptions。

    说明

    当设置Mic音频源(即SourceType为SOURCE_TYPE_MIC)时,需要申请麦克风权限ohos.permission.MICROPHONE,申请方式参考:向用户申请授权。

 import { audio } from '@kit.AudioKit';
 
 let 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 // 编码格式
 };
 
 let audioCapturerInfo: audio.AudioCapturerInfo = {
   source: audio.SourceType.SOURCE_TYPE_MIC,
   capturerFlags: 0
 };
 
 let audioCapturerOptions: audio.AudioCapturerOptions = {
   streamInfo: audioStreamInfo,
   capturerInfo: audioCapturerInfo
 };
 
 audio.createAudioCapturer(audioCapturerOptions, (err, data) => {
   if (err) {
     console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
   } else {
     console.info('Invoke createAudioCapturer succeeded.');
     let audioCapturer = data;
   }
 });
  1. 调用on(‘readData’)方法,订阅监听音频数据读入回调。
  import { BusinessError } from '@kit.BasicServicesKit';
 import { fileIo } from '@kit.CoreFileKit';

 let bufferSize: number = 0;
 class Options {
   offset?: number;
   length?: number;
 }

 let path = getContext().cacheDir;
 let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
 let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);

 let readDataCallback = (buffer: ArrayBuffer) => {
   let options: Options = {
     offset: bufferSize,
     length: buffer.byteLength
   }
   fileIo.writeSync(file.fd, buffer, options);
   bufferSize += buffer.byteLength;
 }
 audioCapturer.on('readData', readDataCallback);
  1. 调用start()方法进入running状态,开始录制音频。
 import { BusinessError } from '@kit.BasicServicesKit';

 audioCapturer.start((err: BusinessError) => {
   if (err) {
     console.error(`Capturer start failed, code is ${err.code}, message is ${err.message}`);
   } else {
     console.info('Capturer start success.');
   }
 });
  1. 调用stop()方法停止录制。
 import { BusinessError } from '@kit.BasicServicesKit';

 audioCapturer.stop((err: BusinessError) => {
   if (err) {
     console.error(`Capturer stop failed, code is ${err.code}, message is ${err.message}`);
   } else {
     console.info('Capturer stopped.');
   }
 });
  1. 调用release()方法销毁实例,释放资源。
 import { BusinessError } from '@kit.BasicServicesKit';

 audioCapturer.release((err: BusinessError) => {
   if (err) {
     console.error(`capturer release failed, code is ${err.code}, message is ${err.message}`);
   } else {
     console.info('capturer released.');
   }
 });

完整示例

下面展示了使用AudioCapturer录制音频的完整示例代码。

import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';

const TAG = 'AudioCapturerDemo';

class Options {
  offset?: number;
  length?: number;
}

let context = getContext(this);
let bufferSize: number = 0;
let audioCapturer: audio.AudioCapturer | undefined = undefined;
let 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 // 编码格式
}
let audioCapturerInfo: audio.AudioCapturerInfo = {
  source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型
  capturerFlags: 0 // 音频采集器标志
}
let audioCapturerOptions: audio.AudioCapturerOptions = {
  streamInfo: audioStreamInfo,
  capturerInfo: audioCapturerInfo
}

let path = getContext().cacheDir;
let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
let file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);

let readDataCallback = (buffer: ArrayBuffer) => {
   let options: Options = {
      offset: bufferSize,
      length: buffer.byteLength
   }
   fileIo.writeSync(file.fd, buffer, options);
   bufferSize += buffer.byteLength;
}

// 初始化,创建实例,设置监听事件
function init() {
  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // 创建AudioCapturer实例
    if (err) {
      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
      return;
    }
    console.info(`${TAG}: create AudioCapturer success`);
    audioCapturer = capturer;
    if (audioCapturer !== undefined) {
       (audioCapturer as audio.AudioCapturer).on('readData', readDataCallback);
    }
  });
}

// 开始一次音频采集
function start() {
  if (audioCapturer !== undefined) {
    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
    if (stateGroup.indexOf((audioCapturer as audio.AudioCapturer).state.valueOf()) === -1) { // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集
      console.error(`${TAG}: start failed`);
      return;
    }

    // 启动采集
    (audioCapturer as audio.AudioCapturer).start((err: BusinessError) => {
      if (err) {
        console.error('Capturer start failed.');
      } else {
        console.info('Capturer start success.');
      }
    });
  }
}

// 停止采集
function stop() {
  if (audioCapturer !== undefined) {
    // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止
    if ((audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_RUNNING && (audioCapturer as audio.AudioCapturer).state.valueOf() !== audio.AudioState.STATE_PAUSED) {
      console.info('Capturer is not running or paused');
      return;
    }

    //停止采集
    (audioCapturer as audio.AudioCapturer).stop((err: BusinessError) => {
      if (err) {
        console.error('Capturer stop failed.');
      } else {
        fileIo.close(file);
        console.info('Capturer stop success.');
      }
    });
  }
}

// 销毁实例,释放资源
function release() {
  if (audioCapturer !== undefined) {
    // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release
    if ((audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_RELEASED || (audioCapturer as audio.AudioCapturer).state.valueOf() === audio.AudioState.STATE_NEW) {
      console.info('Capturer already released');
      return;
    }

    //释放资源
    (audioCapturer as audio.AudioCapturer).release((err: BusinessError) => {
      if (err) {
        console.error('Capturer release failed.');
      } else {
        console.info('Capturer release success.');
      }
    });
  }
}

使用OHAudio开发音频录制功能(C/C++)

OHAudio是系统在API version 10中引入的一套C API,此API在设计上实现归一,同时支持普通音频通路和低时延通路。仅支持PCM格式,适用于依赖Native层实现音频输入功能的场景。

使用入门

开发者要使用OHAudio提供的播放或者录制能力,需要添加对应的头文件。

在 CMake 脚本中链接动态库

target_link_libraries(sample PUBLIC libohaudio.so)

添加头文件

开发者通过引入<native_audiostreambuilder.h>和<native_audiocapturer.h>头文件,使用音频录制相关API。

#include <ohaudio/native_audiocapturer.h>
#include <ohaudio/native_audiostreambuilder.h>

音频流构造器

OHAudio提供OH_AudioStreamBuilder接口,遵循构造器设计模式,用于构建音频流。开发者需要根据业务场景,指定对应的OH_AudioStream_Type 。

OH_AudioStream_Type包含两种类型:

  • AUDIOSTREAM_TYPE_RENDERER
  • AUDIOSTREAM_TYPE_CAPTURER

使用OH_AudioStreamBuilder_Create创建构造器示例:

OH_AudioStreamBuilder* builder;
OH_AudioStreamBuilder_Create(&builder, streamType);

在音频业务结束之后,开发者应该执行OH_AudioStreamBuilder_Destroy接口来销毁构造器。

OH_AudioStreamBuilder_Destroy(builder);

开发步骤及注意事项

详细的API说明请参考OHAudio API参考。

开发者可以通过以下几个步骤来实现一个简单的录制功能。

  1. 创建构造器
OH_AudioStreamBuilder* builder;
OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_CAPTURER);
  1. 配置音频流参数

    创建音频录制构造器后,可以设置音频流所需要的参数,可以参考下面的案例。

// 设置音频采样率
OH_AudioStreamBuilder_SetSamplingRate(builder, 48000);
// 设置音频声道
OH_AudioStreamBuilder_SetChannelCount(builder, 2);
// 设置音频采样格式
OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
// 设置音频流的编码类型
OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
// 设置输入音频流的工作场景
OH_AudioStreamBuilder_SetCapturerInfo(builder, AUDIOSTREAM_SOURCE_TYPE_MIC);
同样,音频录制的音频数据要通过回调接口写入,开发者要实现回调接口,使用OH_AudioStreamBuilder_SetCapturerCallback设置回调函数。回调函数的声明请查看OH_AudioCapturer_Callbacks 。
  1. 设置音频回调函数

    多音频并发处理可参考文档处理音频焦点事件,仅接口语言差异。

   // 自定义写入数据函数
int32_t MyOnReadData(
    OH_AudioCapturer* capturer,
    void* userData,
    void* buffer,
    int32_t length)
{
    // 从buffer中取出length长度的录音数据
    return 0;
}
// 自定义音频流事件函数
int32_t MyOnStreamEvent(
    OH_AudioCapturer* capturer,
    void* userData,
    OH_AudioStream_Event event)
{
    // 根据event表示的音频流事件信息,更新播放器状态和界面
    return 0;
}
// 自定义音频中断事件函数
int32_t MyOnInterruptEvent(
    OH_AudioCapturer* capturer,
    void* userData,
    OH_AudioInterrupt_ForceType type,
    OH_AudioInterrupt_Hint hint)
{
    // 根据type和hint表示的音频中断信息,更新录制器状态和界面
    return 0;
}
// 自定义异常回调函数
int32_t MyOnError(
    OH_AudioCapturer* capturer,
    void* userData,
    OH_AudioStream_Result error)
{
    // 根据error表示的音频异常信息,做出相应的处理
    return 0;
}

OH_AudioCapturer_Callbacks callbacks;
// 配置回调函数
callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;
callbacks.OH_AudioCapturer_OnStreamEvent = MyOnStreamEvent;
callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent;
callbacks.OH_AudioCapturer_OnError = MyOnError;

// 设置音频输入流的回调
OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr);

为了避免不可预期的行为,在设置音频回调函数时,请确保OH_AudioCapturer_Callbacks的每一个回调都被自定义的回调方法空指针初始化。

// 自定义写入数据函数
int32_t MyOnReadData(
    OH_AudioCapturer* capturer,
    void* userData,
    void* buffer,
    int32_t length)
{
    // 从buffer中取出length长度的录音数据
    return 0;
}
// 自定义音频中断事件函数
int32_t MyOnInterruptEvent(
    OH_AudioCapturer* capturer,
    void* userData,
    OH_AudioInterrupt_ForceType type,
    OH_AudioInterrupt_Hint hint)
{
    // 根据type和hint表示的音频中断信息,更新录制器状态和界面
    return 0;
}
OH_AudioCapturer_Callbacks callbacks;

// 配置回调函数,如果需要监听,则赋值
callbacks.OH_AudioCapturer_OnReadData = MyOnReadData;
callbacks.OH_AudioCapturer_OnInterruptEvent = MyOnInterruptEvent;

// (必选)如果不需要监听,使用空指针初始化
callbacks.OH_AudioCapturer_OnStreamEvent = nullptr;
callbacks.OH_AudioCapturer_OnError = nullptr;
  1. 构造录制音频流
OH_AudioCapturer* audioCapturer;
OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer);
  1. 使用音频流

    录制音频流包含下面接口,用来实现对音频流的控制。

    接口说明
    OH_AudioStream_Result OH_AudioCapturer_Start(OH_AudioCapturer* capturer)开始录制
    OH_AudioStream_Result OH_AudioCapturer_Pause(OH_AudioCapturer* capturer)暂停录制
    OH_AudioStream_Result OH_AudioCapturer_Stop(OH_AudioCapturer* capturer)停止录制
    OH_AudioStream_Result OH_AudioCapturer_Flush(OH_AudioCapturer* capturer)释放缓存数据
    OH_AudioStream_Result OH_AudioCapturer_Release(OH_AudioCapturer* capturer)释放录制实例
  2. 释放构造器

    构造器不再使用时,需要释放相关资源。

OH_AudioStreamBuilder_Destroy(builder);

设置低时延模式

当设备支持低时延通路时,开发者可以使用低时延模式创建音频录制构造器,获得更高质量的音频体验。

开发流程与普通录制场景一致,仅需要在创建音频录制构造器时,调用OH_AudioStreamBuilder_SetLatencyMode()设置低时延模式。

开发示例

OH_AudioStream_LatencyMode latencyMode = AUDIOSTREAM_LATENCY_MODE_FAST;
OH_AudioStreamBuilder_SetLatencyMode(builder, latencyMode);

管理麦克风

因为在录制过程中需要使用麦克风录制相关音频数据,所以建议开发者在调用录制接口前查询麦克风状态,并在录制过程中监听麦克风的状态变化,避免影响录制效果。

在音频录制过程中,用户可以将麦克风静音,此时录音过程正常进行,录制生成的数据文件的大小随录制时长递增,但写入文件的数据均为0,即无声数据(空白数据)。

开发步骤及注意事项

在AudioVolumeGroupManager中提供了管理麦克风状态的方法,接口的详细说明请参考API文档。

  1. 创建audioVolumeGroupManager对象。
import { audio } from '@kit.AudioKit';

let audioVolumeGroupManager: audio.AudioVolumeGroupManager;
async function loadVolumeGroupManager() { //创建audioVolumeGroupManager对象
  const groupid = audio.DEFAULT_VOLUME_GROUP_ID;
  audioVolumeGroupManager = await audio.getAudioManager().getVolumeManager().getVolumeGroupManager(groupid);
  console.info('audioVolumeGroupManager create success.');
}
  1. 调用isMicrophoneMute查询麦克风当前静音状态,返回true为静音,false为非静音。
async function isMicrophoneMute() { //查询麦克风是否静音
  await audioVolumeGroupManager.isMicrophoneMute().then((value: boolean) => {
    console.info(`isMicrophoneMute is: ${value}.`);
  });
}

音频录制流管理

对于录制音频类的应用,开发者需要关注该应用的音频流的状态以做出相应的操作,比如监听到状态为结束时,及时提示用户录制已结束。

读取或监听应用内音频流状态变化

参考使用AudioCapturer开发音频录制功能或audio.createAudioCapturer,完成AudioCapturer的创建,然后可以通过以下两种方式查看音频流状态的变化:

  • 方法1:直接查看AudioCapturer的state:
let audioCapturerState: audio.AudioState = audioCapturer.state;
console.info(`Current state is: ${audioCapturerState }`)
  • 方法2:注册stateChange监听AudioCapturer的状态变化:
audioCapturer.on('stateChange', (capturerState: audio.AudioState) => {
  console.info(`State change to: ${capturerState}`)
});

获取state后可对照AudioState来进行相应的操作,比如显示录制结束的提示等。

读取或监听所有录制流的变化

如果部分应用需要查询获取所有音频流的变化信息,可以通过AudioStreamManager读取或监听所有音频流的变化。

如下为音频流管理调用关系图:

image.png

在进行应用开发的过程中,开发者需要使用getStreamManager()创建一个AudioStreamManager实例,进而通过该实例管理音频流。开发者可通过调用on(‘audioCapturerChange’)监听音频流的变化,在音频流状态变化、设备变化时获得通知,同时可通过off(‘audioCapturerChange’)取消相关事件的监听。另外,开发者可以通过主动调用getCurrentAudioCapturerInfoArray()查询录制流的唯一ID、录制流客户端的UID、以及流状态等信息。

详细API含义可参考音频管理API文档AudioStreamManager。

开发步骤及注意事项

  1. 创建AudioStreamManager实例。

    在使用AudioStreamManager的API前,需要使用getStreamManager()创建一个AudioStreamManager实例。

import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';

let audioManager = audio.getAudioManager();
let audioStreamManager = audioManager.getStreamManager();
  1. 使用on(‘audioCapturerChange’)监听音频录制流更改事件。 如果音频流监听应用需要在音频录制流状态变化、设备变化时获取通知,可以订阅该事件。
audioStreamManager.on('audioCapturerChange', (AudioCapturerChangeInfoArray: audio.AudioCapturerChangeInfoArray) =>  {
  for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) {
    console.info(`## CapChange on is called for element ${i} ##`);
    console.info(`StreamId for ${i} is: ${AudioCapturerChangeInfoArray[i].streamId}`);
    console.info(`Source for ${i} is: ${AudioCapturerChangeInfoArray[i].capturerInfo.source}`);
    console.info(`Flag  ${i} is: ${AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags}`);
    let devDescriptor: audio.AudioDeviceDescriptors = AudioCapturerChangeInfoArray[i].deviceDescriptors;
    for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) {
      console.info(`Id: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id}`);
      console.info(`Type: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType}`);
      console.info(`Role: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole}`);
      console.info(`Name: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name}`);
      console.info(`Address: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address}`);
      console.info(`SampleRates: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]}`);
      console.info(`ChannelCounts ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]}`);
      console.info(`ChannelMask: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks}`);
    }
  }
});
  1. (可选)使用off(‘audioCapturerChange’)取消监听音频录制流变化。
audioStreamManager.off('audioCapturerChange');
console.info('CapturerChange Off is called');
  1. (可选)使用getCurrentAudioCapturerInfoArray()获取当前音频录制流的信息。

    该接口可获取音频录制流唯一ID、音频录制客户端的UID、音频状态以及音频捕获器的其他信息。

    说明

    对所有音频流状态进行监听的应用需要声明权限ohos.permission.USE_BLUETOOTH,否则无法获得实际的设备名称和设备地址信息,查询到的设备名称和设备地址(蓝牙设备的相关属性)将为空字符串。

  async function getCurrentAudioCapturerInfoArray(){
  await audioStreamManager.getCurrentAudioCapturerInfoArray().then((AudioCapturerChangeInfoArray: audio.AudioCapturerChangeInfoArray) => {
    console.info('getCurrentAudioCapturerInfoArray  Get Promise Called ');
    if (AudioCapturerChangeInfoArray != null) {
      for (let i = 0; i < AudioCapturerChangeInfoArray.length; i++) {
        console.info(`StreamId for ${i} is: ${AudioCapturerChangeInfoArray[i].streamId}`);
        console.info(`Source for ${i} is: ${AudioCapturerChangeInfoArray[i].capturerInfo.source}`);
        console.info(`Flag  ${i} is: ${AudioCapturerChangeInfoArray[i].capturerInfo.capturerFlags}`);
        for (let j = 0; j < AudioCapturerChangeInfoArray[i].deviceDescriptors.length; j++) {
          console.info(`Id: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].id}`);
          console.info(`Type: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceType}`);
          console.info(`Role: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].deviceRole}`);
          console.info(`Name: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].name}`);
          console.info(`Address: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].address}`);
          console.info(`SampleRates: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].sampleRates[0]}`);
          console.info(`ChannelCounts ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelCounts[0]}`);
          console.info(`ChannelMask: ${i} : ${AudioCapturerChangeInfoArray[i].deviceDescriptors[j].channelMasks}`);
        }
      }
    }
  }).catch((err: BusinessError) => {
    console.error(`Invoke getCurrentAudioCapturerInfoArray failed, code is ${err.code}, message is ${err.message}`);
  });
}

音频输入设备管理

有时设备同时连接多个音频输入设备,需要指定音频输入设备进行音频录制,此时需要使用AudioRoutingManager接口进行输入设备的管理,API说明可以参考AudioRoutingManager API文档。

创建AudioRoutingManager实例

在使用AudioRoutingManager管理音频设备前,需要先导入模块并创建实例。

import { audio } from '@kit.AudioKit';  // 导入audio模块

let audioManager = audio.getAudioManager();  // 需要先创建AudioManager实例
let audioRoutingManager = audioManager.getRoutingManager();  // 再调用AudioManager的方法创建AudioRoutingManager实例

支持的音频输入设备类型

目前支持的音频输入设备见下表:

名称说明
WIRED_HEADSET3有线耳机,带麦克风。
BLUETOOTH_SCO7蓝牙设备SCO(Synchronous Connection Oriented)连接。
MIC15麦克风。
USB_HEADSET22USB耳机,带麦克风。

获取输入设备信息

使用getDevices()方法可以获取当前所有输入设备的信息。

import { audio } from '@kit.AudioKit';

audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG).then((data: audio.AudioDeviceDescriptors) => {
  console.info('Promise returned to indicate that the device list is obtained.');
});

监听设备连接状态变化

可以设置监听事件来监听设备连接状态的变化,当有设备连接或断开时触发回调:

import { audio } from '@kit.AudioKit';

// 监听音频设备状态变化
audioRoutingManager.on('deviceChange', audio.DeviceFlag.INPUT_DEVICES_FLAG, (deviceChanged: audio.DeviceChangeAction) => {
  console.info('device change type : ' + deviceChanged.type);  // 设备连接状态变化,0为连接,1为断开连接
  console.info('device descriptor size : ' + deviceChanged.deviceDescriptors.length);
  console.info('device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceRole);  // 设备角色
  console.info('device change descriptor : ' + deviceChanged.deviceDescriptors[0].deviceType);  // 设备类型
});

// 取消监听音频设备状态变化
audioRoutingManager.off('deviceChange', (deviceChanged: audio.DeviceChangeAction) => {
  console.info('Should be no callback.');
});

写在最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。

希望这一份鸿蒙学习文档能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料

请点击→纯血版全套鸿蒙HarmonyOS学习文档

鸿蒙(HarmonyOS NEXT)5.0最新学习路线

在这里插入图片描述

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

《鸿蒙 (HarmonyOS)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习文档,请点击→纯血版全套鸿蒙HarmonyOS学习文档

在这里插入图片描述

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值