【Android Audio】4、音频设备管理 【基于Android Q 】

4、音频设备管理 【基于Android Q 】

在这里插入图片描述

audio policy xml里面有2种角色:source和sink,每种角色又分为devicePorts和mixPorts。

type为AUDIO_PORT_TYPE_DEVICE
devicePorts(source):为实际的硬件输入设备,对应安卓的role为AUDIO_PORT_ROLE_SOURCE ;
devicePorts(sink):为实际的硬件输出设备,对应安卓的role为AUDIO_PORT_ROLE_SINK ;

type为AUDIO_PORT_TYPE_MIX
mixPorts(source):为AudioFlinger中的播放(AudioTrack)的线程,对应安卓的role为AUDIO_PORT_ROLE_SOURCE,mOutputs;
mixPorts(sink):为AudioFlinger中的录音(AudioRecord)的线程,对应安卓的role为AUDIO_PORT_ROLE_SINK,mInputs

routes:定义devicePort和mixPorts的路由策略。

通过该接口AudioSystem.listAudioPorts可获取到当前所有的端口

status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
                                            audio_port_type_t type,
                                            unsigned int *num_ports,
                                            struct audio_port *ports,
                                            unsigned int *generation)
{
...
    if (type == AUDIO_PORT_TYPE_NONE || type == AUDIO_PORT_TYPE_DEVICE) {
        // do not report devices with type AUDIO_DEVICE_IN_STUB or AUDIO_DEVICE_OUT_STUB
        // as they are used by stub HALs by convention
        if (role == AUDIO_PORT_ROLE_SINK || role == AUDIO_PORT_ROLE_NONE) {
            for (const auto& dev : mAvailableOutputDevices) {
                if (dev->type() == AUDIO_DEVICE_OUT_STUB) {
                    continue;
                }
                if (portsWritten < portsMax) {
                    dev->toAudioPort(&ports[portsWritten++]);
                    ALOGD("[%s:%d] output device role:%d, name:%s, type:%#x", __func__, __LINE__,
                        ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.device.type);
                }
                (*num_ports)++;
            }
        }
        if (role == AUDIO_PORT_ROLE_SOURCE || role == AUDIO_PORT_ROLE_NONE) {
            for (const auto& dev : mAvailableInputDevices) {
                if (dev->type() == AUDIO_DEVICE_IN_STUB) {
                    continue;
                }
                if (portsWritten < portsMax) {
                    dev->toAudioPort(&ports[portsWritten++]);
                    ALOGD("[%s:%d] input device role:%d, name:%s, type:%#x", __func__, __LINE__,
                        ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.device.type);
                }
                (*num_ports)++;
            }
        }
    }
    if (type == AUDIO_PORT_TYPE_NONE || type == AUDIO_PORT_TYPE_MIX) {
        if (role == AUDIO_PORT_ROLE_SINK || role == AUDIO_PORT_ROLE_NONE) {
            for (size_t i = 0; i < mInputs.size() && portsWritten < portsMax; i++) {
                mInputs[i]->toAudioPort(&ports[portsWritten++]);
                ALOGD("[%s:%d] sink mix role:%d, name:%s, handle:%d", __func__, __LINE__,
                    ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.mix.handle);
            }
            *num_ports += mInputs.size();
        }
        if (role == AUDIO_PORT_ROLE_SOURCE || role == AUDIO_PORT_ROLE_NONE) {
            size_t numOutputs = 0;
            for (size_t i = 0; i < mOutputs.size(); i++) {
                if (!mOutputs[i]->isDuplicated()) {
                    numOutputs++;
                    if (portsWritten < portsMax) {
                        mOutputs[i]->toAudioPort(&ports[portsWritten++]);
                        ALOGD("[%s:%d] source mix role:%d, name:%s, handle:%d", __func__, __LINE__,
                            ports[portsWritten-1].role, ports[portsWritten-1].name, ports[portsWritten-1].ext.mix.handle);
                    }
                }
            }
            *num_ports += numOutputs;
        }
    }
    *generation = curAudioPortGeneration();
    ALOGD("listAudioPorts() got %zu ports needed %d, generation:%d", portsWritten, *num_ports, *generation);
    return NO_ERROR;
}
typedef enum {
    AUDIO_PORT_ROLE_NONE = 0,
    AUDIO_PORT_ROLE_SOURCE = 1, // (::android::hardware::audio::common::V4_0::AudioPortRole.NONE implicitly + 1)
    AUDIO_PORT_ROLE_SINK = 2, // (::android::hardware::audio::common::V4_0::AudioPortRole.SOURCE implicitly + 1)
} audio_port_role_t;
typedef enum {
    AUDIO_PORT_TYPE_NONE = 0,
    AUDIO_PORT_TYPE_DEVICE = 1, // (::android::hardware::audio::common::V4_0::AudioPortType.NONE implicitly + 1)
    AUDIO_PORT_TYPE_MIX = 2, // (::android::hardware::audio::common::V4_0::AudioPortType.DEVICE implicitly + 1)
    AUDIO_PORT_TYPE_SESSION = 3, // (::android::hardware::audio::common::V4_0::AudioPortType.MIX implicitly + 1)
} audio_port_type_t;

在这里插入图片描述

status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& device,
                                                   audio_policy_dev_state_t state,
                                                   SortedVector<audio_io_handle_t>& outputs)
{
    audio_devices_t deviceType = device->type();
    const String8 &address = device->address();
    sp<SwAudioOutputDescriptor> desc;

    if (audio_device_is_digital(deviceType)) {
        // erase all current sample rates, formats and channel masks
        device->clearAudioProfiles();
    }

    if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
        // first list already open outputs that can be routed to this device
        for (size_t i = 0; i < mOutputs.size(); i++) {
            desc = mOutputs.valueAt(i);
            if (!desc->isDuplicated() && desc->supportsDevice(device)
                    && desc->deviceSupportsEncodedFormats(deviceType)) {
                ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
                      mOutputs.keyAt(i), device->toString().c_str());
                outputs.add(mOutputs.keyAt(i));
            }
        }
        // then look for output profiles that can be routed to this device
        SortedVector< sp<IOProfile> > profiles;
        // 遍历所有xml的包含该device的profiles
        for (const auto& hwModule : mHwModules) {
            for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
                sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
                if (profile->supportsDevice(device)) {
                    profiles.add(profile);
                    ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
                          j, hwModule->getName());
                }
            }
        }

        ALOGV("  found %zu profiles, %zu outputs", profiles.size(), outputs.size());

        if (profiles.isEmpty() && outputs.isEmpty()) {
            ALOGW("checkOutputsForDevice(): No output available for device %04x", deviceType);
            return BAD_VALUE;
        }

        // open outputs for matching profiles if needed. Direct outputs are also opened to
        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
            sp<IOProfile> profile = profiles[profile_index];

            // nothing to do if one output is already opened for this profile
            size_t j;
            for (j = 0; j < outputs.size(); j++) {
                desc = mOutputs.valueFor(outputs.itemAt(j));
                if (!desc->isDuplicated() && desc->mProfile == profile) {
                    // matching profile: save the sample rates, format and channel masks supported
                    // by the profile in our device descriptor
                    if (audio_device_is_digital(deviceType)) {
                        device->importAudioPort(profile);
                    }
                    break;
                }
            }
            if (j != outputs.size()) {
                continue;
            }

            if (!profile->canOpenNewIo()) {
                ALOGW("Max Output number %u already opened for this profile %s",
                      profile->maxOpenCount, profile->getTagName().c_str());
                continue;
            }

            ALOGD("opening output for device %08x with params %s profile %p name %s",
                  deviceType, address.string(), profile.get(), profile->getName().string());
            desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            ALOGI("[%s:%d]  open_ ", __func__, __LINE__);
            status_t status = desc->open(nullptr, DeviceVector(device),
                                         AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);

            if (status == NO_ERROR) {
                // Here is where the out_set_parameters() for card & device gets called
                if (!address.isEmpty()) {
                    char *param = audio_device_address_to_parameter(deviceType, address);
                    mpClientInterface->setParameters(output, String8(param));
                    free(param);
                }
                updateAudioProfiles(device, output, profile->getAudioProfiles());
                if (!profile->hasValidAudioProfile()) {
                    ALOGW("checkOutputsForDevice() missing param");
                    desc->close();
                    output = AUDIO_IO_HANDLE_NONE;
                } else if (profile->hasDynamicAudioProfile()) {
                    ALOGI("[%s:%d]  close_ ", __func__, __LINE__);
                    desc->close();
                    output = AUDIO_IO_HANDLE_NONE;
                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
                    profile->pickAudioProfile(
                            config.sample_rate, config.channel_mask, config.format);
                    config.offload_info.sample_rate = config.sample_rate;
                    config.offload_info.channel_mask = config.channel_mask;
                    config.offload_info.format = config.format;
                    ALOGI("[%s:%d]  open_ ", __func__, __LINE__);

                    status_t status = desc->open(&config, DeviceVector(device),
                                                 AUDIO_STREAM_DEFAULT,
                                                 AUDIO_OUTPUT_FLAG_NONE, &output);
                    if (status != NO_ERROR) {
                        output = AUDIO_IO_HANDLE_NONE;
                    }
                ...
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Android设备的音频切换到蓝牙耳机,可以按照以下步骤进行操作: 首先,确保蓝牙耳机已经与Android设备成功配对。在设备的设置菜单中,找到“蓝牙”选项,并打开蓝牙功能。在配对列表中选择你的蓝牙耳机,并进行配对。 一旦蓝牙耳机成功连接,可以采取以下两种方法将音频切换到蓝牙耳机: 方法一:在通知面板中切换音频输出。下滑打开通知面板,在音频控制器中,通常会显示设备当前正在使用的音频输出设备。点击该设备图标,会弹出一个菜单,其中列出了所有可用的音频输出选项,包择轨蓝牙耳机作为当前音频输出设备。 方法二:在设置菜单中切换音频输出。进入设备的设置菜单,在“声音和振动”或类似的选项下,找到“音频输出”或“音频设备”选项。点击该选项,会列出所有可用的音频输出设备,包括蓝牙耳机。选择蓝牙耳机作为当前音频输出设备。 一旦成功切换音频输出到蓝牙耳机,Android设备的所有音频输出,包括音乐、视频和通话声音,都会通过蓝牙耳机进行播放。如果将蓝牙耳机关闭或与设备断开连接,音频输出将自动切换回设备的内置扬声器。 总结来说,要将Android设备的音频切换到蓝牙耳机,需要确保设备和蓝牙耳机成功配对。然后,在通知面板或设置菜单中选择蓝牙耳机作为音频输出设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值