HarmonyOS鸿蒙Next中AudioCapturer录制音频时接入蓝牙耳机无法通过蓝牙耳机的麦克风进行音频录制

HarmonyOS鸿蒙Next中AudioCapturer录制音频时接入蓝牙耳机无法通过蓝牙耳机的麦克风进行音频录制 我想在接入蓝牙耳机的时候能够通过蓝牙耳机进行音频录制:

目前的问题:蓝牙耳机连接正常,开始录音,对着蓝牙耳机说话无法录制,对着手机麦克风说话可以录制。(录音依旧使用的手机麦克风)

调试信息:通过获取输入设备的方法可以看到蓝牙耳机的输入设备。开始录音后依旧走的手机的麦克风在进行音频录制。

// 使用getDevices()方法可以获取当前所有输入设备的信息。
audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG).then((data: audio.AudioDeviceDescriptors) => {
  console.info("StartAudio AudioDeviceDescriptors::" + JSON.stringify(data))
});

//结果(这里可以看到蓝牙耳机设备)
StartAudio AudioDeviceDescriptors::[{deviceRole:1,deviceType:7,id:62,name:"aigo T50",address:"E9:6F:40:E2:62:1B",networkId:"",displayName:"Mate 60 Pro",interruptGroupId:-1,volumeGroupId:-1,sampleRates:[16000,48000],channelCounts:[1,2],channelMasks:[0],channelIndexMasks:[0],encodingTypes:[0]},{deviceRole:1,deviceType:15,id:2,name:"",address:"",networkId:"",displayName:"Mate 60 Pro",interruptGroupId:-1,volumeGroupId:-1,sampleRates:[16000,48000],channelCounts:[1,2],channelMasks:[0],channelIndexMasks:[0],encodingTypes:[0]}]
//录音时监听音频录制流更改事件
audioStreamManager.on('audioCapturerChange', (AudioCapturerChangeInfoArray: audio.AudioCapturerChangeInfoArray) =>  {
  console.info("StartAudio AudioCapturerChangeInfoArray::" + JSON.stringify(AudioCapturerChangeInfoArray))
});

//结果(连上蓝牙耳机的情况下,这里还是手机麦克风)
StartAudio AudioCapturerChangeInfoArray::[{streamId:100393,clientUid:0,capturerState:-1,muted:false,capturerInfo:{source:7,capturerFlags:0},deviceDescriptors:[{deviceRole:1,deviceType:15,id:2,name:"",address:"",networkId:"",displayName:"Mate 60 Pro",interruptGroupId:-1,volumeGroupId:-1,sampleRates:[16000,48000],channelCounts:[1,2],channelMasks:[0],channelIndexMasks:[0],encodingTypes:[0]}]}]

更多关于HarmonyOS鸿蒙Next中AudioCapturer录制音频时接入蓝牙耳机无法通过蓝牙耳机的麦克风进行音频录制的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

整体代码如下:

const TAG = 'VoiceCallDemoForAudioCapturer';
class Options {
  offset?: number;
  length?: number;
}

// 与使用AudioCapturer开发音频录制功能过程相似,关键区别在于audioCapturerInfo参数和音频数据流向。
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, // Mic音频源
  source: audio.SourceType.SOURCE_TYPE_VOICE_COMMUNICATION, // 音源类型:语音通话。
  capturerFlags: 0 // 音频采集器标志:默认为0即可。
};
let audioCapturerOptions: audio.AudioCapturerOptions = {
  streamInfo: audioStreamInfo,
  capturerInfo: audioCapturerInfo
};
let path = getContext().cacheDir;
let filePath = path + '/StarWars10s-2C-48000-4SW.wav';
let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let readDataCallback = (buffer: ArrayBuffer) => {
  let options: Options = {
    offset: bufferSize,
    length: buffer.byteLength
  };
  fs.writeSync(file.fd, buffer, options);
  bufferSize += buffer.byteLength;
};

// 初始化,创建实例,设置监听事件。
const init = async () => {
  audio.createAudioCapturer(audioCapturerOptions, (err: BusinessError, capturer: audio.AudioCapturer) => { // 创建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.on('markReach', 1000, (position: number) => { // 订阅markReach事件,当采集的帧数达到1000帧时触发回调。
        if (position === 1000) {
          console.info('ON Triggered successfully');
        }
      });
      audioCapturer.on('periodReach', 2000, (position: number) => { // 订阅periodReach事件,当采集的帧数每达到2000时触发回调。
        if (position === 2000) {
          console.info('ON Triggered successfully');
        }
      });
      audioCapturer.on('readData', readDataCallback);
    }
  });
}

// 开始一次音频采集。
const start = async () => {
  if (audioCapturer !== undefined) {
    let stateGroup: number[] = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
    if (stateGroup.indexOf(audioCapturer.state.valueOf()) === -1) { // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集。
      console.error(`${TAG}: start failed`);
      return;
    }
    audioCapturer.start((err: BusinessError) => {
      if (err) {
        console.error('Capturer start failed.');
      } else {
        console.info('Capturer start success.');
      }
    });

    audioCapturer.on('stateChange', (capturerState: audio.AudioState) => {
      console.info(`StartAudio State change to: ${capturerState}`)
    });

    let audioManager = audio.getAudioManager();
    let audioStreamManager = audioManager.getStreamManager();

    // 使用on('audioCapturerChange')监听音频录制流更改事件。 如果音频流监听应用需要在音频录制流状态变化、设备变化时获取通知,可以订阅该事件。
    audioStreamManager.on('audioCapturerChange', (AudioCapturerChangeInfoArray: audio.AudioCapturerChangeInfoArray) =>  {
      console.info("StartAudio AudioCapturerChangeInfoArray::" + JSON.stringify(AudioCapturerChangeInfoArray))
    });

    // 有时设备同时连接多个音频输入设备,需要指定音频输入设备进行音频录制,此时需要使用AudioRoutingManager接口进行输入设备的管理
    let audioRoutingManager = audioManager.getRoutingManager();  // 再调用AudioManager的方法创建AudioRoutingManager实例。

    // 使用getDevices()方法可以获取当前所有输入设备的信息。
    audioRoutingManager.getDevices(audio.DeviceFlag.INPUT_DEVICES_FLAG).then((data: audio.AudioDeviceDescriptors) => {
      console.info("StartAudio AudioDeviceDescriptors::" + JSON.stringify(data))
    });

    // 监听音频设备状态变化。
    audioRoutingManager.on('deviceChange', audio.DeviceFlag.INPUT_DEVICES_FLAG, (deviceChanged: audio.DeviceChangeAction) => {
      console.info("StartAudio DeviceChangeAction::", JSON.stringify(deviceChanged))
      // 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);  // 设备类型。
    });
  }
}

更多关于HarmonyOS鸿蒙Next中AudioCapturer录制音频时接入蓝牙耳机无法通过蓝牙耳机的麦克风进行音频录制的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,AudioCapturer录制音频时,默认使用设备内置麦克风。即使连接了蓝牙耳机,系统也不会自动切换至蓝牙耳机的麦克风进行录制。这是由于当前系统设计未支持自动切换音频输入源至蓝牙麦克风。开发者需手动配置音频输入源,或通过API指定使用蓝牙麦克风进行录制。

在HarmonyOS Next中,当使用AudioCapturer进行音频录制时,系统默认会优先使用手机内置麦克风。要切换到蓝牙耳机麦克风,需要显式设置输入设备。以下是解决方案:

  1. 首先确认蓝牙耳机已正确连接并识别为输入设备(如您代码所示已获取到设备)

  2. 在创建AudioCapturer时,需要指定音频源为MIC(7)并设置正确的设备ID:

let audioCapturerOptions = {
  streamInfo: {
    samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
    channels: audio.AudioChannel.CHANNEL_1,
    sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
    encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
  },
  capturerInfo: {
    source: audio.SourceType.SOURCE_TYPE_MIC,
    capturerFlags: 0
  }
};

// 创建AudioCapturer后设置输入设备
audioCapturer.setInputDevice(deviceId); // 使用getDevices获取的蓝牙设备ID
  1. 关键点:必须在开始录制前调用setInputDevice方法,并传入蓝牙耳机的设备ID。从您的日志看,当前使用的是设备ID为2的手机麦克风,应该切换到ID为62的蓝牙设备。

  2. 完整流程建议:

  • 监听蓝牙连接状态变化
  • 当蓝牙耳机连接时,获取其设备ID
  • 在AudioCapturer初始化后立即调用setInputDevice
  • 开始录制

注意:某些蓝牙耳机可能需要特殊配置或仅支持特定采样率,建议测试16000Hz和48000Hz两种采样率。

回到顶部