HarmonyOS 鸿蒙Next中自动和手动切换音频设备问题

HarmonyOS 鸿蒙Next中自动和手动切换音频设备问题 【问题描述】:自动和手动切换音频设备问题

【问题现象】:

1、无法获取到所有可切换输出音频设备列表信息;

2、使用setDefaultOutputDevice可切换设备类型有限(外接有线耳机和蓝牙耳机等),且使用AVCastPicker切换后,再次调用本接口不生效;

3、使用AVCastPicker无法自动切换扬声器,无法通过设置属性改变其状态;

4、使用C底层代码切换成扬声器后,无法改变AVCastPicker状态,AVCastPicker状态还是听筒,此时需要点击AVCastPicker两次才能切换成听筒;

【版本信息】:DevEco Studio 5.0.2 Release、HarmonyOS 5.1.0、 sdk5.0.1(13)

【复现代码】:

AVCastPicker() //进入会议自动切换api未知

【尝试解决方案】:使用audioRoutingManager?.setCommunicationDevice单独修改扬声器的状态(但官网显示后续setCommunicationDevice接口会废弃)

【问题场景】:

我想自动切换音频设备,主要是不用AVCastPicker的话,我拿不到所有可输出设备信息,我想切换也不知道切换成啥。现在用AVCastPicker和setDefaultOutputDevice都实现不了,视频会议有需要设置进会是否开启扬声器需求


更多关于HarmonyOS 鸿蒙Next中自动和手动切换音频设备问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

11 回复

【问题描述】:自动和手动切换音频设备问题

【解决方案】:视频会议场景下,参考管理全局音频输出设备

推荐参考使用通话设备切换组件,使用AVCastPicker手动切换设备。

1.如何获取所有可切换输出音频设备列表信息

名称 说明
OUTPUT_DEVICES_FLAG 1 输出设备。
INPUT_DEVICES_FLAG 2 输入设备。
ALL_DEVICES_FLAG 3 所有设备。
import { audio } from '@kit.AudioKit';
// getDevices方法异步获取音频设备列表
audioRoutingManager.getDevices(audio.DeviceFlag.OUTPUT_DEVICES_FLAG).then((data: audio.AudioDeviceDescriptors) => {
  console.info("可用设备列表: " + JSON.stringify(data));
});
// getDevicesSync方法同步获取音频设备列表
let devices = audioRoutingManager.getDevicesSync(audio.DeviceFlag.OUTPUT_DEVICES_FLAG);
console.info("可用设备列表: " + JSON.stringify(devices));
名称 说明
MEDIA_OUTPUT_DEVICES 1 媒体输出设备。
MEDIA_INPUT_DEVICES 2 媒体输入设备。
ALL_MEDIA_DEVICES 3 所有媒体设备。
CALL_OUTPUT_DEVICES 4 通话输出设备。
CALL_INPUT_DEVICES 8 通话输入设备。
ALL_CALL_DEVICES 12 所有通话设备。
import { audio } from '@kit.AudioKit';

let devices = audioRoutingManager.getAvailableDevices(audio.DeviceUsage.MEDIA_OUTPUT_DEVICES);
console.info("可用设备列表: " + JSON.stringify(devices));

2. 使用setDefaultOutputDevice切换本机音频默认输出设备

setDefaultOutputDevice是切换本机音频默认输出设备,是一个受限制的自动强制选择音频输出设备的接口。

可以使用Interface(AudioSessionManager)中的setDefaultOutputDevice,优先级高于Interface(AudioRenderer)中的setDefaultOutputDevice)实现切换本机音频默认输出设备

Interface(AudioSessionManager)中的setDefaultOutputDevice本接口适用于以下情况:

  • 当设置的AudioSessionScene为VoIP场景时,激活AudioSession后立即生效。若AudioSessionScene为非VoIP场景,激活AudioSession时不会生效,仅在启动播放的StreamUsage为语音消息、VoIP语音通话或VoIP视频通话时才生效。支持听筒、扬声器和系统默认设备。

  • 本接口允许在AudioSessionManager创建后随时调用,系统会记录应用设置的默认本机内置发声设备。但只有激活AudioSession后才能生效。应用启动播放时,若外接设备如蓝牙耳机或有线耳机已接入,系统优先从外接设备发声,此时调用本接口会记录设置的本机内置发声设备,外设移除后生效。否则,系统遵循应用设置的默认本机内置发声设备。

  • 本接口优先级低于AVCastPicker。如果使用AVCastPicker切换过发声设备,再次调用本接口将不生效。

3. 使用AVCastPicker切换音频输出设备

参考:使用通话设备切换组件,AVCastPicker仅用于用户手动切换设备,不提供自动强制选择设备的接口。

4. 使用setCommunicationDevice通话场景下异步强制选择扬声器

注意setCommunicationDevice后续不再启用,系统不再提供给应用直接自动切换设备的接口。该接口由于功能设计变化,将在后续版本废弃,不建议开发者使用。推荐使用AVSession提供的设备切换组件,实现通话设备切换。

通信设备类型(CommunicationDeviceType)是系统预置的可用于通话场景的设备,当前仅支持选择扬声器,应用可以使用AudioRoutingManagerisCommunicationDeviceActive函数获取指定通信设备的激活状态,使用AudioRoutingManagersetCommunicationDevice设置通信设备的激活状态,通过激活设备来实现通话场景音频设备的切换。

5、使用系统接口自动强制选择音频设备

使用系统接口自动强制选择音频设备需要系统权限ohos.permission.MANAGE_AUDIO_CONFIG,该权限仅系统应用可申请,不提供给普通应用使用。

更多关于HarmonyOS 鸿蒙Next中自动和手动切换音频设备问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


cke_122.png

大佬,我的编辑器咋提示没有selectOutputDevice这个方法呀

系统接口仅供系统应用使用,

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

  1. 无法获取所有可切换输出音频设备列表信息

依据

  • getAvailableDevices(deviceUsage: DeviceUsage): AudioDeviceDescriptors 方法可以获取音频可选设备列表(同步返回结果)。
  • getDevicesSync(deviceFlag: DeviceFlag): AudioDeviceDescriptors 也可获取设备列表,但注意其返回可能包含听筒(EARPIECE)设备。

建议方案

使用 getAvailableDevices 并指定设备用途(如 MEDIA_OUTPUT_DEVICES)来获取当前可用的输出设备列表。示例:

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

try {
  let devices = audioRoutingManager.getAvailableDevices(audio.DeviceUsage.MEDIA_OUTPUT_DEVICES);
  console.info("可用设备列表: " + JSON.stringify(devices));
} catch (err) {
  console.error("获取设备列表失败: " + err);
}

注意:设备列表可能包括扬声器(SPEAKER)、有线耳机(WIRED_HEADSET)、蓝牙设备(BLUETOOTH_A2DP)等,但具体设备依赖实际连接状态。


2. setDefaultOutputDevice 的限制和 AVCastPicker 的优先级问题

依据

  • setDefaultOutputDevice 仅适用于 语音消息、VoIP语音通话或VoIP视频通话 场景,且仅支持听筒(EARPIECE)、扬声器(SPEAKER)和系统默认设备(DEFAULT)。外接设备(如蓝牙耳机)不支持通过此接口设置
  • 如果使用 AVCastPicker 切换过设备,再次调用 setDefaultOutputDevice 将不生效(AVCastPicker 优先级更高)。

建议方案

  • 若需切换外接设备(如蓝牙耳机),必须使用 AVCastPicker 组件(推荐)或系统级路由 API(如 selectOutputDevice)。
  • 自动切换需求应通过编程方式调用 selectOutputDeviceselectOutputDeviceByFilter(见下文)。

3. AVCastPicker 无法自动切换扬声器及状态同步问题

依据

  • AVCastPicker 是 UI 组件,用于用户手动切换设备。它本身不提供直接编程控制接口(如设置属性自动切换)。
  • 应用可通过监听设备变化事件(如 preferOutputDeviceChangeForRendererInfo)更新 UI 状态,实现自定义样式。

自动切换的替代方案

使用 AudioRoutingManager 的 selectOutputDeviceselectOutputDeviceByFilter 接口直接切换设备:

// 示例:切换到扬声器
let deviceDesc: audio.AudioDeviceDescriptors = [{
  deviceRole: audio.DeviceRole.OUTPUT_DEVICE,
  deviceType: audio.DeviceType.SPEAKER, // 设备类型:扬声器
  id: 1, // 需从设备列表中获取实际ID
  // ... 其他参数(如name、address等需匹配实际设备)
}];

audioRoutingManager.selectOutputDevice(deviceDesc).then(() => {
  console.info("切换到扬声器成功");
}).catch((err: BusinessError) => {
  console.error("切换失败: " + err);
});

注意事项

  • selectOutputDevice 是系统接口,可能需要系统权限(如 ohos.permission.MANAGE_AUDIO_CONFIG)。
  • 设备描述符(如 id)必须与当前可用设备匹配(可通过 getAvailableDevices 获取)。

4. C底层代码切换后 AVCastPicker 状态不同步的问题

依据

  • AVCastPicker 的状态与 AVSession 绑定。若通过底层C代码直接切换设备,可能绕过 AVSession 框架,导致状态不同步。
  • 设备切换应统一通过 AVSession 管理(如使用 castAudio 系统接口),以确保 AVCastPicker 状态同步。

解决方案

  • 避免直接使用底层C接口切换设备。应通过 ArkTS 层的 AVSessionAudioRoutingManager 接口操作。
  • 若必须用C代码,需确保调用后主动通知 AVSession 更新状态。

针对视频会议场景的自动切换方案

核心需求:进入会议时自动开启扬声器。

推荐方案

  1. 获取设备列表:使用 getAvailableDevices 确认扬声器可用。
  2. 自动切换设备:通过 selectOutputDevice 直接切换到扬声器(而非依赖 AVCastPicker)。
  3. 监听切换结果:注册 outputDeviceChange 事件确认切换成功。

示例代码

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

// 1. 创建AudioRenderer(通话场景需使用VOICE_COMMUNICATION类型)
let rendererInfo: audio.AudioRendererInfo = {
  usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, // 语音通话场景
  rendererFlags: 0
};
let audioRenderer = await audio.createAudioRenderer({ rendererInfo });

// 2. 自动切换到扬声器
let speakerDevice = audioRoutingManager.getAvailableDevices(audio.DeviceUsage.MEDIA_OUTPUT_DEVICES)
  .find(device => device.deviceType === audio.DeviceType.SPEAKER);

if (speakerDevice) {
  audioRoutingManager.selectOutputDevice([speakerDevice]).then(() => {
    console.info("扬声器切换成功");
  }).catch((err: BusinessError) => {
    console.error("切换失败: " + err);
  });
}

// 3. 监听设备变化(可选)
audioRenderer.on('outputDeviceChange', (devices: audio.AudioDeviceDescriptors) => {
  console.info("当前输出设备: " + devices[0].deviceType);
});

大佬,我的编辑器咋提示没有selectOutputDevice这个方法呀,

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

系统权限仅开放给系统应用,普通应用无法申请。不开放自动强制选择音频输出设备的接口。

在HarmonyOS鸿蒙Next中,音频设备切换支持自动和手动两种模式。自动模式下,系统根据连接状态和设备优先级自动选择音频输出设备,例如插入有线耳机时自动切换到耳机输出。手动切换需在控制中心或设置中指定音频路由,用户可主动选择扬声器、蓝牙设备等。切换逻辑基于设备连接事件和用户操作,系统API如AudioRoutingManager管理相关行为。音频策略确保切换过程无中断,维持播放连贯性。

在HarmonyOS Next中,音频设备切换涉及AVCastPickerAudioRoutingManager的配合使用。针对您的问题:

  1. 获取音频设备列表:通过AudioRoutingManager.getDevices()获取所有可用音频设备,使用AudioDeviceDescriptor筛选输出设备(如扬声器、耳机)。

  2. 自动切换扬声器

    • 进入会议时,调用AudioRoutingManager.setCommunicationDevice(AudioDeviceDescriptor),传入扬声器设备描述符,实现自动切换。
    • 尽管setCommunicationDevice可能废弃,但目前是推荐方案,后续可关注API更新。
  3. 状态同步问题

    • 使用AVCastPicker时,通过监听onAudioDeviceSelected事件同步设备状态。
    • 若底层切换导致状态不一致,需在代码中手动调用AVCastPicker.updateDevice()刷新界面。
  4. 代码示例

    // 获取设备列表
    let devices = audioRoutingManager.getDevices(AudioDeviceFlag.OUTPUT_DEVICES_FLAG);
    // 自动切换至扬声器
    audioRoutingManager.setCommunicationDevice(speakerDescriptor);
    // 监听AVCastPicker选择
    AVCastPicker({ onAudioDeviceSelected: (device) => { /* 处理逻辑 */ } });
    

建议结合事件监听与状态管理,确保UI与底层状态一致。当前可继续使用setCommunicationDevice,同时关注HarmonyOS SDK更新。

回到顶部