当应用进行音频输出时,系统将依据音频流类型自动匹配对应的输出设备。如果系统输出设备不满足应用需求,应用可通过AVCastPicker或setDefaultOutputDevice实现音频输出设备路由切换。在连接音频外设(如蓝牙耳机、有线耳机)的情况下,应用还可通过setMediaOutputDevice强制将媒体输出切换到扬声器。
从API版本26.0.0开始,PC/2in1设备还支持基于AudioDeviceEnhanceManager和native_audio_device_enhance_manager.h的输出设备切换能力,应用可按应用级或音频流级精确指定输出设备,满足多设备场景下对声音输出去向的控制需求。
以下各步骤示例为片段代码,可通过示例代码右下方链接获取完整示例。其中,PC/2in1设备输出设备切换的完整示例请参见ArkTS示例和C/C++示例。
应用可以通过使用AVCastPicker组件为用户提供选择设备的入口。
该组件集成了设备发现、连接、认证等能力,可嵌入应用界面。用户点击后,系统自动识别并展示当前可切换的设备列表,支持在扬声器、耳机、智能音箱等输出设备间自由切换。
如果系统未连接外设(如蓝牙耳机),语音通话场景音频默认听筒播放,其他场景音频默认扬声器播放;外设接入后,系统优先从外设播放。应用可通过setDefaultOutputDevice更改默认输出设备,但仅对以下三种StreamUsage生效:
| 名称 | 值 | 说明 |
|---|---|---|
| STREAM_USAGE_VOICE_MESSAGE | 5 | 语音消息。 |
| STREAM_USAGE_VOICE_COMMUNICATION | 2 | VoIP语音通话。 |
| STREAM_USAGE_VIDEO_COMMUNICATION | 17 | VoIP视频通话。 |
支持的设备类型:
| 名称 | 值 | 说明 |
|---|---|---|
| EARPIECE | 1 | 听筒。 |
| SPEAKER | 2 | 扬声器。 |
| DEFAULT | 1000 | 跟随系统。 |
调用此接口后,系统会记录指定的默认输出设备。当无外接设备连接时,音频流将路由至指定默认输出设备播放;当外设接入时,系统优先从外设播放,外设断开后自动切换至设置的默认输出设备。
AudioRenderer和AudioSessionManager都提供了setDefaultOutputDevice接口,用于设置通话或语音的默认输出设备。
应用级接口优先级高于音频流级,如果同时调用了两个接口,AudioSessionManager的设置会覆盖AudioRenderer,AudioRenderer的设置将不再生效。
音频流级设置接口
从API version 12开始,应用可使用AudioRenderer的setDefaultOutputDevice设置默认设备为听筒和扬声器,调用前需要先获取AudioRenderer实例,设置默认设备的生命周期跟随音频流。调用setDefaultOutputDevice设置音频输出设备后,如需取消,可将参数设为audio.DeviceType.DEFAULT,将音频输出设备选择权交还给系统。
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
// 设置默认输出设备为扬声器。
audioRenderer.setDefaultOutputDevice(audio.DeviceType.SPEAKER).then(() => {
console.info('Succeeded in setting default output device.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set default output device. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
// 设置默认输出设备为听筒。
audioRenderer.setDefaultOutputDevice(audio.DeviceType.EARPIECE).then(() => {
console.info('Succeeded in setting default output device.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set default output device. Code: ${err.code}, message: ${err.message}`);
// ...
}); 应用级设置接口
从API version 20开始,应用激活AudioSession后,可使用AudioSessionManager的setDefaultOutputDevice设置默认输出设备,并通过AudioSessionManager.getDefaultOutputDevice查看默认设备是否设置成功,设置默认设备的生命周期跟随AudioSession。调用setDefaultOutputDevice设置音频输出设备后,如需取消,可将参数设为audio.DeviceType.DEFAULT,将音频输出设备选择权交还给系统。
由于AudioSessionManager是应用级设置,调用本接口设置默认音频输出设备,会对当前应用所有适用范围内的音频流生效,且会覆盖AudioRenderer的setDefaultOutputDevice接口设置的默认音频输出设备信息。
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
let audioManager = audio.getAudioManager();
let audioSessionManager = audioManager.getSessionManager();
// ...
// 应用根据业务场景设置适合自己的音频会话场景,激活AudioSession时,系统会根据应用选择的音频会话场景申请对应的音频焦点。
audioSessionManager.setAudioSessionScene(audio.AudioSessionScene.AUDIO_SESSION_SCENE_VOICE_COMMUNICATION);
// 设置音频会话策略。
let strategy: audio.AudioSessionStrategy = {
concurrencyMode: audio.AudioConcurrencyMode.CONCURRENCY_MIX_WITH_OTHERS
};
// 激活AudioSession。
audioSessionManager.activateAudioSession(strategy).then(() => {
console.info('Succeeded in activating audio session.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to activate audio session. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
// 设置默认输出设备为扬声器。
audioSessionManager.setDefaultOutputDevice(audio.DeviceType.SPEAKER).then(() => {
console.info('Succeeded in setting default output device.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set default output device. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
// 设置默认输出设备为听筒。
audioSessionManager.setDefaultOutputDevice(audio.DeviceType.EARPIECE).then(() => {
console.info('Succeeded in setting default output device.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set default output device. Code: ${err.code}, message: ${err.message}`);
// ...
}); 当系统连接蓝牙耳机或有线耳机等外设时,系统优先从外设播放。从API版本26.0.0开始,应用可使用AudioSessionManager的setMediaOutputDevice接口,强制将媒体输出设备切换为扬声器,使音频在连接外设的情况下仍从扬声器播放。
应用可使用AudioSessionManager的setMediaOutputDevice接口强制将媒体输出设备切换为扬声器。调用setMediaOutputDevice后,如需取消强制切换、恢复系统默认路由规则,可将参数设为audio.DeviceType.DEFAULT。
支持的设备类型:
| 名称 | 值 | 说明 |
|---|---|---|
| SPEAKER | 2 | 扬声器,强制将媒体输出切换到扬声器。 |
| DEFAULT | 1000 | 系统默认设备,清除强制切换,恢复系统默认路由规则。 |
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
let audioManager = audio.getAudioManager();
let audioSessionManager = audioManager.getSessionManager();
// ...
// 连接蓝牙耳机后,强制将媒体输出设备切换为扬声器。
audioSessionManager.setMediaOutputDevice(audio.DeviceType.SPEAKER).then(() => {
console.info('Succeeded in setting media output device to speaker.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set media output device. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
// 取消强制切换,将媒体输出设备选择权交还给系统默认路由规则。
audioSessionManager.setMediaOutputDevice(audio.DeviceType.DEFAULT).then(() => {
console.info('Succeeded in setting media output device to default.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set media output device. Code: ${err.code}, message: ${err.message}`);
// ...
}); PC/2in1设备经常存在多路输出设备可用(如内置扬声器、外接音箱、USB/蓝牙耳机等),系统默认的设备选择策略可能无法满足应用在各种场景下的输出需求。通过本能力,应用可按应用级或音频流级精确指定输出设备,满足多设备场景下对声音输出去向的控制需求。
使用前需先通过isEnhancedRoutingSupported或OH_AudioDeviceEnhanceManager_IsEnhancedRoutingSupported查询系统是否支持该能力,不支持时调用输出设备切换接口不生效,将继续使用当前输出设备。
ArkTS示例:
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
let audioManager = audio.getAudioManager();
let audioDeviceEnhanceManager: audio.AudioDeviceEnhanceManager = audioManager.getDeviceEnhanceManager();
// 查询系统是否支持当前管理器提供的增强路由能力。
let isSupported: boolean = audioDeviceEnhanceManager.isEnhancedRoutingSupported();
console.info(`Succeeded in querying whether enhanced routing is supported. Result: ${isSupported}.`); C/C++示例:
使用前需添加头文件:
#include <ohaudio/native_audio_device_enhance_manager.h> #include <ohaudio/native_audio_routing_manager.h> #include <ohaudio/native_audio_device_base.h> #include <ohaudio/native_audiocapturer.h> #include <ohaudio/native_audiorenderer.h> #include <ohaudio/native_audiostreambuilder.h>
napi_value IsEnhancedRoutingSupported(napi_env env, napi_callback_info info)
{
OH_AudioDeviceEnhanceManager *enhanceManager = nullptr;
OH_AudioCommon_Result result = OH_AudioManager_GetAudioDeviceEnhanceManager(&enhanceManager);
bool isSupported = false;
// 查询系统是否支持当前管理器提供的增强路由能力。
result = OH_AudioDeviceEnhanceManager_IsEnhancedRoutingSupported(enhanceManager, &isSupported);
// ...
} 输出设备切换支持应用级和音频流级两种粒度,应用级对应用下所有播放流生效,音频流级仅对指定播放流生效,且音频流级的优先级高于应用级。
若某条播放流已通过音频流级接口指定了专属输出设备,则该流使用其专属输出设备,应用内其他播放流仍使用应用级设置的输出设备或系统默认输出设备。
ArkTS示例:
应用级: 通过selectOutputDevice选择指定的输出设备,设置成功后对应用下创建的所有播放流生效。
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
let audioManager = audio.getAudioManager();
let audioDeviceEnhanceManager: audio.AudioDeviceEnhanceManager = audioManager.getDeviceEnhanceManager();
// 为应用选择输出设备,此处device可通过ArkTS完整示例查看获取方式。
audioDeviceEnhanceManager.selectOutputDevice(device).then(() => {
console.info('Succeeded in selecting output device.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to select output device. Code: ${err.code}, message: ${err.message}`);
// ...
}); 音频流级: 通过selectOutputDeviceForAudioRenderer为指定音频播放流选择输出设备,设置成功后仅对该播放流生效。
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
let audioManager = audio.getAudioManager();
let audioDeviceEnhanceManager: audio.AudioDeviceEnhanceManager = audioManager.getDeviceEnhanceManager();
// 为指定音频播放流设置首选输出设备,此处renderer和outputDevice可通过ArkTS完整示例查看获取方式。
audioDeviceEnhanceManager.selectOutputDeviceForAudioRenderer(renderer, outputDevice).then(() => {
console.info('Succeeded in selecting output device for audio renderer.');
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to select output device for audio renderer. Code: ${err.code}, message: ${err.message}`);
// ...
}); C/C++示例:
应用级: 通过OH_AudioDeviceEnhanceManager_SelectOutputDevice选择指定的输出设备。
// 获取音频设备增强管理器。
static OH_AudioDeviceEnhanceManager *GetEnhanceManager(std::string &errorMsg)
{
OH_AudioDeviceEnhanceManager *manager = nullptr;
OH_AudioCommon_Result result = OH_AudioManager_GetAudioDeviceEnhanceManager(&manager);
if (result != AUDIOCOMMON_RESULT_SUCCESS || manager == nullptr) {
errorMsg = "获取AudioDeviceEnhanceManager失败";
return nullptr;
}
bool isSupported = false;
OH_AudioDeviceEnhanceManager_IsEnhancedRoutingSupported(manager, &isSupported);
if (!isSupported) {
errorMsg = "Enhanced routing不支持,该功能不会生效";
return nullptr;
}
return manager;
}
struct DeviceSearchResult {
OH_AudioRoutingManager *routingManager;
OH_AudioDeviceDescriptorArray *deviceArray;
OH_AudioDeviceDescriptor *targetDescriptor;
};
// 获取音频可选设备。
static DeviceSearchResult FindDescriptorById(int32_t deviceId, OH_AudioDevice_Usage usage)
{
DeviceSearchResult search = {nullptr, nullptr, nullptr};
OH_AudioManager_GetAudioRoutingManager(&search.routingManager);
OH_AudioRoutingManager_GetAvailableDevices(search.routingManager, usage, &search.deviceArray);
if (search.deviceArray == nullptr) {
return search;
}
for (uint32_t i = 0; i < search.deviceArray->size; i++) {
uint32_t id = 0;
OH_AudioDeviceDescriptor_GetDeviceId(search.deviceArray->descriptors[i], &id);
if (id == static_cast<uint32_t>(deviceId)) {
search.targetDescriptor = search.deviceArray->descriptors[i];
break;
}
}
return search;
}
static void ReleaseDeviceSearch(DeviceSearchResult &search)
{
if (search.routingManager != nullptr && search.deviceArray != nullptr) {
OH_AudioRoutingManager_ReleaseDevices(search.routingManager, search.deviceArray);
}
}
// ...
// 为应用选择输出设备。
napi_value SelectOutputDevice(napi_env env, napi_callback_info info)
{
int32_t deviceId = 0;
ParseInt32Arg(env, info, deviceId);
std::string errorMsg;
OH_AudioDeviceEnhanceManager *enhanceManager = GetEnhanceManager(errorMsg);
// ...
DeviceSearchResult search = FindDescriptorById(deviceId, AUDIO_DEVICE_USAGE_MEDIA_OUTPUT);
OH_AudioCommon_Result result = OH_AudioDeviceEnhanceManager_SelectOutputDevice(
enhanceManager, search.targetDescriptor);
ReleaseDeviceSearch(search);
// ...
} 音频流级: 通过OH_AudioDeviceEnhanceManager_SelectOutputDeviceForAudioRenderer为指定音频播放流选择输出设备。
// 获取音频设备增强管理器。
static OH_AudioDeviceEnhanceManager *GetEnhanceManager(std::string &errorMsg)
{
OH_AudioDeviceEnhanceManager *manager = nullptr;
OH_AudioCommon_Result result = OH_AudioManager_GetAudioDeviceEnhanceManager(&manager);
if (result != AUDIOCOMMON_RESULT_SUCCESS || manager == nullptr) {
errorMsg = "获取AudioDeviceEnhanceManager失败";
return nullptr;
}
bool isSupported = false;
OH_AudioDeviceEnhanceManager_IsEnhancedRoutingSupported(manager, &isSupported);
if (!isSupported) {
errorMsg = "Enhanced routing不支持,该功能不会生效";
return nullptr;
}
return manager;
}
struct DeviceSearchResult {
OH_AudioRoutingManager *routingManager;
OH_AudioDeviceDescriptorArray *deviceArray;
OH_AudioDeviceDescriptor *targetDescriptor;
};
// 获取音频可选设备。
static DeviceSearchResult FindDescriptorById(int32_t deviceId, OH_AudioDevice_Usage usage)
{
DeviceSearchResult search = {nullptr, nullptr, nullptr};
OH_AudioManager_GetAudioRoutingManager(&search.routingManager);
OH_AudioRoutingManager_GetAvailableDevices(search.routingManager, usage, &search.deviceArray);
if (search.deviceArray == nullptr) {
return search;
}
for (uint32_t i = 0; i < search.deviceArray->size; i++) {
uint32_t id = 0;
OH_AudioDeviceDescriptor_GetDeviceId(search.deviceArray->descriptors[i], &id);
if (id == static_cast<uint32_t>(deviceId)) {
search.targetDescriptor = search.deviceArray->descriptors[i];
break;
}
}
return search;
}
static void ReleaseDeviceSearch(DeviceSearchResult &search)
{
if (search.routingManager != nullptr && search.deviceArray != nullptr) {
OH_AudioRoutingManager_ReleaseDevices(search.routingManager, search.deviceArray);
}
}
// 创建音频渲染器。
static OH_AudioRenderer *CreateAudioRenderer()
{
OH_AudioStreamBuilder *builder = nullptr;
if (OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_RENDERER) != AUDIOSTREAM_SUCCESS) {
return nullptr;
}
OH_AudioStreamBuilder_SetSamplingRate(builder, SAMPLE_RATE_48K);
OH_AudioStreamBuilder_SetChannelCount(builder, CHANNEL_COUNT_STEREO);
OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE);
OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW);
OH_AudioStreamBuilder_SetRendererInfo(builder, AUDIOSTREAM_USAGE_VOICE_COMMUNICATION);
OH_AudioRenderer *renderer = nullptr;
OH_AudioStreamBuilder_GenerateRenderer(builder, &renderer);
OH_AudioStreamBuilder_Destroy(builder);
return renderer;
}
// ...
// 为指定音频播放流设置首选输出设备。
napi_value SelectOutputDeviceForAudioRenderer(napi_env env, napi_callback_info info)
{
int32_t deviceId = 0;
ParseInt32Arg(env, info, deviceId);
std::string errorMsg;
OH_AudioDeviceEnhanceManager *enhanceManager = GetEnhanceManager(errorMsg);
// ...
OH_AudioRenderer *renderer = CreateAudioRenderer();
// ...
DeviceSearchResult search = FindDescriptorById(deviceId, AUDIO_DEVICE_USAGE_MEDIA_OUTPUT);
OH_AudioCommon_Result result = OH_AudioDeviceEnhanceManager_SelectOutputDeviceForAudioRenderer(
enhanceManager, renderer, search.targetDescriptor);
ReleaseDeviceSearch(search);
// ...
}