Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 002c58fa authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Automerger Merge Worker
Browse files

Merge changes from topic "fix-aidl-mix-ports-and-bt" into main am: eafa78c9

parents de6a93d4 eafa78c9
Loading
Loading
Loading
Loading
+19 −18
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

#define LOG_TAG "AHAL_BluetoothPortProxy"
#define LOG_TAG "AHAL_BluetoothAudioPort"

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
@@ -254,12 +254,7 @@ bool BluetoothAudioPortAidl::inUse() const {
    return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
}

bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
    if (!interval_us) {
        LOG(ERROR) << __func__ << ": bad input arg";
        return false;
    }

bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t& interval_us) const {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
        return false;
@@ -272,16 +267,11 @@ bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) con
        return false;
    }

    *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
    interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
    return true;
}

bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
    if (!audio_cfg) {
        LOG(ERROR) << __func__ << ": bad input arg";
        return false;
    }

bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration& audio_cfg) {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
        return false;
@@ -293,15 +283,26 @@ bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const
        LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
        return false;
    }
    *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
    audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
    LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
                 << audio_cfg->toString() << "]";
    if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
                 << audio_cfg.toString() << "]";
    if (audio_cfg.channelMode == ChannelMode::UNKNOWN) {
        return false;
    }
    return true;
}

bool BluetoothAudioPortAidlOut::loadAudioConfig(PcmConfiguration& audio_cfg) {
    if (!BluetoothAudioPortAidl::loadAudioConfig(audio_cfg)) return false;
    // WAR to support Mono / 16 bits per sample as the Bluetooth stack requires
    if (audio_cfg.channelMode == ChannelMode::MONO && audio_cfg.bitsPerSample == 16) {
        mIsStereoToMono = true;
        audio_cfg.channelMode = ChannelMode::STEREO;
        LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
    }
    return true;
}

bool BluetoothAudioPortAidl::standby() {
    if (!inUse()) {
        LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
@@ -435,7 +436,7 @@ bool BluetoothAudioPortAidl::suspend() {
                retval = condWaitState(BluetoothStreamState::SUSPENDING);
            } else {
                LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
                           << " Hal fails";
                           << " failure to suspend stream";
            }
        }
    }
+205 −27
Original line number Diff line number Diff line
@@ -24,13 +24,25 @@

using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::hardware::bluetooth::audio::ChannelMode;
using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfigBase;
using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioOffloadInfo;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::MicrophoneInfo;
using aidl::android::media::audio::common::PcmType;
using android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
using android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;

// TODO(b/312265159) bluetooth audio should be in its own process
@@ -39,6 +51,35 @@ extern "C" binder_status_t createIBluetoothAudioProviderFactory();

namespace aidl::android::hardware::audio::core {

namespace {

PcmType pcmTypeFromBitsPerSample(int8_t bitsPerSample) {
    if (bitsPerSample == 8)
        return PcmType::UINT_8_BIT;
    else if (bitsPerSample == 16)
        return PcmType::INT_16_BIT;
    else if (bitsPerSample == 24)
        return PcmType::INT_24_BIT;
    else if (bitsPerSample == 32)
        return PcmType::INT_32_BIT;
    ALOGE("Unsupported bitsPerSample: %d", bitsPerSample);
    return PcmType::DEFAULT;
}

AudioChannelLayout channelLayoutFromChannelMode(ChannelMode mode) {
    if (mode == ChannelMode::MONO) {
        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
                AudioChannelLayout::LAYOUT_MONO);
    } else if (mode == ChannelMode::STEREO || mode == ChannelMode::DUALMONO) {
        return AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
                AudioChannelLayout::LAYOUT_STEREO);
    }
    ALOGE("Unsupported channel mode: %s", toString(mode).c_str());
    return AudioChannelLayout{};
}

}  // namespace

ModuleBluetooth::ModuleBluetooth(std::unique_ptr<Module::Configuration>&& config)
    : Module(Type::BLUETOOTH, std::move(config)) {
    // TODO(b/312265159) bluetooth audio should be in its own process
@@ -95,67 +136,131 @@ ndk::ScopedAStatus ModuleBluetooth::setMicMute(bool in_mute __unused) {
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ndk::ScopedAStatus ModuleBluetooth::setAudioPortConfig(const AudioPortConfig& in_requested,
                                                       AudioPortConfig* out_suggested,
                                                       bool* _aidl_return) {
    auto fillConfig = [this](const AudioPort& port, AudioPortConfig* config) {
        if (port.ext.getTag() == AudioPortExt::device) {
            CachedProxy proxy;
            auto status = findOrCreateProxy(port, proxy);
            if (status.isOk()) {
                const auto& pcmConfig = proxy.pcmConfig;
                LOG(DEBUG) << "setAudioPortConfig: suggesting port config from "
                           << pcmConfig.toString();
                const auto pcmType = pcmTypeFromBitsPerSample(pcmConfig.bitsPerSample);
                const auto channelMask = channelLayoutFromChannelMode(pcmConfig.channelMode);
                if (pcmType != PcmType::DEFAULT && channelMask != AudioChannelLayout{}) {
                    config->format =
                            AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = pcmType};
                    config->channelMask = channelMask;
                    config->sampleRate = Int{.value = pcmConfig.sampleRateHz};
                    config->flags = port.flags;
                    config->ext = port.ext;
                    return true;
                }
            }
        }
        return generateDefaultPortConfig(port, config);
    };
    return Module::setAudioPortConfigImpl(in_requested, fillConfig, out_suggested, _aidl_return);
}

ndk::ScopedAStatus ModuleBluetooth::checkAudioPatchEndpointsMatch(
        const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
    // Both sources and sinks must be non-empty, this is guaranteed by 'setAudioPatch'.
    const bool isInput = sources[0]->ext.getTag() == AudioPortExt::device;
    const int32_t devicePortId = isInput ? sources[0]->portId : sinks[0]->portId;
    const auto proxyIt = mProxies.find(devicePortId);
    if (proxyIt == mProxies.end()) return ndk::ScopedAStatus::ok();
    const auto& pcmConfig = proxyIt->second.pcmConfig;
    const AudioPortConfig* mixPortConfig = isInput ? sinks[0] : sources[0];
    if (!StreamBluetooth::checkConfigParams(
                pcmConfig, AudioConfigBase{.sampleRate = mixPortConfig->sampleRate->value,
                                           .channelMask = *(mixPortConfig->channelMask),
                                           .format = *(mixPortConfig->format)})) {
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    }
    if (int32_t handle = mixPortConfig->ext.get<AudioPortExt::mix>().handle; handle > 0) {
        mConnections.insert(std::pair(handle, devicePortId));
    }
    return ndk::ScopedAStatus::ok();
}

void ModuleBluetooth::onExternalDeviceConnectionChanged(const AudioPort& audioPort,
                                                        bool connected) {
    if (!connected) mProxies.erase(audioPort.id);
}

ndk::ScopedAStatus ModuleBluetooth::createInputStream(
        StreamContext&& context, const SinkMetadata& sinkMetadata,
        const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
    CachedProxy proxy;
    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
    return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
                                                   microphones, getBtProfileManagerHandles());
                                                   microphones, getBtProfileManagerHandles(),
                                                   proxy.ptr, proxy.pcmConfig);
}

ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
        StreamContext&& context, const SourceMetadata& sourceMetadata,
        const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
    CachedProxy proxy;
    RETURN_STATUS_IF_ERROR(fetchAndCheckProxy(context, proxy));
    return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
                                                    offloadInfo, getBtProfileManagerHandles());
                                                    offloadInfo, getBtProfileManagerHandles(),
                                                    proxy.ptr, proxy.pcmConfig);
}

ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort, int32_t) {
ndk::ScopedAStatus ModuleBluetooth::populateConnectedDevicePort(AudioPort* audioPort,
                                                                int32_t nextPortId) {
    if (audioPort->ext.getTag() != AudioPortExt::device) {
        LOG(ERROR) << __func__ << ": not a device port: " << audioPort->toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
        LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory AIDL service not available";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    const auto& devicePort = audioPort->ext.get<AudioPortExt::device>();
    const auto& description = devicePort.device.type;
    // Since the configuration of the BT module is static, there is nothing to populate here.
    // However, this method must return an error when the device can not be connected,
    // this is determined by the status of BT profiles.
    // This method must return an error when the device can not be connected.
    if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP) {
        bool isA2dpEnabled = false;
        if (!!mBluetoothA2dp) {
            RETURN_STATUS_IF_ERROR((*mBluetoothA2dp).isEnabled(&isA2dpEnabled));
        }
        LOG(DEBUG) << __func__ << ": isA2dpEnabled: " << isA2dpEnabled;
        return isA2dpEnabled ? ndk::ScopedAStatus::ok()
                             : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        if (!isA2dpEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE) {
        bool isLeEnabled = false;
        if (!!mBluetoothLe) {
            RETURN_STATUS_IF_ERROR((*mBluetoothLe).isEnabled(&isLeEnabled));
        }
        LOG(DEBUG) << __func__ << ": isLeEnabled: " << isLeEnabled;
        return isLeEnabled ? ndk::ScopedAStatus::ok()
                           : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        if (!isLeEnabled) return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
               description.type == AudioDeviceType::OUT_HEARING_AID) {
        // Hearing aids can use a number of profiles, thus the only way to check
        // connectivity is to try to talk to the BT HAL.
        if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::
                    IsAidlAvailable()) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
        std::shared_ptr<BluetoothAudioPortAidl> proxy = std::shared_ptr<BluetoothAudioPortAidl>(
                std::make_shared<BluetoothAudioPortAidlOut>());
        if (proxy->registerPort(description)) {
            LOG(DEBUG) << __func__ << ": registered hearing aid port";
            proxy->unregisterPort();
            return ndk::ScopedAStatus::ok();
        }
        LOG(DEBUG) << __func__ << ": failed to register hearing aid port";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
        // Hearing aids can use a number of profiles, no single switch exists.
    } else {
        LOG(ERROR) << __func__ << ": unsupported device type: " << audioPort->toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }
    CachedProxy proxy;
    RETURN_STATUS_IF_ERROR(createProxy(*audioPort, nextPortId, proxy));
    // Since the device is already connected and configured by the BT stack, provide
    // the current configuration instead of all possible profiles.
    const auto& pcmConfig = proxy.pcmConfig;
    audioPort->profiles.clear();
    audioPort->profiles.push_back(
            AudioProfile{.format = AudioFormatDescription{.type = AudioFormatType::PCM,
                                                          .pcm = pcmTypeFromBitsPerSample(
                                                                  pcmConfig.bitsPerSample)},
                         .channelMasks = std::vector<AudioChannelLayout>(
                                 {channelLayoutFromChannelMode(pcmConfig.channelMode)}),
                         .sampleRates = std::vector<int>({pcmConfig.sampleRateHz})});
    LOG(DEBUG) << __func__ << ": " << audioPort->toString();
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
    LOG(DEBUG) << __func__ << ": is not supported";
@@ -167,4 +272,77 @@ ndk::ScopedAStatus ModuleBluetooth::onMasterVolumeChanged(float) {
    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

int32_t ModuleBluetooth::getNominalLatencyMs(const AudioPortConfig& portConfig) {
    const auto connectionsIt = mConnections.find(portConfig.ext.get<AudioPortExt::mix>().handle);
    if (connectionsIt != mConnections.end()) {
        const auto proxyIt = mProxies.find(connectionsIt->second);
        if (proxyIt != mProxies.end()) {
            auto proxy = proxyIt->second.ptr;
            size_t dataIntervalUs = 0;
            if (!proxy->getPreferredDataIntervalUs(dataIntervalUs)) {
                LOG(WARNING) << __func__ << ": could not fetch preferred data interval";
            }
            const bool isInput = portConfig.flags->getTag() == AudioIoFlags::input;
            return isInput ? StreamInBluetooth::getNominalLatencyMs(dataIntervalUs)
                           : StreamOutBluetooth::getNominalLatencyMs(dataIntervalUs);
        }
    }
    LOG(ERROR) << __func__ << ": no connection or proxy found for " << portConfig.toString();
    return Module::getNominalLatencyMs(portConfig);
}

ndk::ScopedAStatus ModuleBluetooth::createProxy(const AudioPort& audioPort, int32_t instancePortId,
                                                CachedProxy& proxy) {
    const bool isInput = audioPort.flags.getTag() == AudioIoFlags::input;
    proxy.ptr = isInput ? std::shared_ptr<BluetoothAudioPortAidl>(
                                  std::make_shared<BluetoothAudioPortAidlIn>())
                        : std::shared_ptr<BluetoothAudioPortAidl>(
                                  std::make_shared<BluetoothAudioPortAidlOut>());
    const auto& devicePort = audioPort.ext.get<AudioPortExt::device>();
    if (const auto device = devicePort.device.type; !proxy.ptr->registerPort(device)) {
        LOG(ERROR) << __func__ << ": failed to register BT port for " << device.toString();
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    if (!proxy.ptr->loadAudioConfig(proxy.pcmConfig)) {
        LOG(ERROR) << __func__ << ": state=" << proxy.ptr->getState()
                   << ", failed to load audio config";
        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
    }
    mProxies.insert(std::pair(instancePortId, proxy));
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus ModuleBluetooth::fetchAndCheckProxy(const StreamContext& context,
                                                       CachedProxy& proxy) {
    const auto connectionsIt = mConnections.find(context.getMixPortHandle());
    if (connectionsIt != mConnections.end()) {
        const auto proxyIt = mProxies.find(connectionsIt->second);
        if (proxyIt != mProxies.end()) {
            proxy = proxyIt->second;
            mProxies.erase(proxyIt);
        }
        mConnections.erase(connectionsIt);
    }
    if (proxy.ptr != nullptr) {
        if (!StreamBluetooth::checkConfigParams(
                    proxy.pcmConfig, AudioConfigBase{.sampleRate = context.getSampleRate(),
                                                     .channelMask = context.getChannelLayout(),
                                                     .format = context.getFormat()})) {
            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
        }
    }
    // Not having a proxy is OK, it may happen in VTS tests when streams are opened on unconnected
    // mix ports.
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus ModuleBluetooth::findOrCreateProxy(const AudioPort& audioPort,
                                                      CachedProxy& proxy) {
    if (auto proxyIt = mProxies.find(audioPort.id); proxyIt != mProxies.end()) {
        proxy = proxyIt->second;
        return ndk::ScopedAStatus::ok();
    }
    return createProxy(audioPort, audioPort.id, proxy);
}

}  // namespace aidl::android::hardware::audio::core
+103 −163

File changed.

Preview size limit exceeded, changes collapsed.

+8 −12
Original line number Diff line number Diff line
@@ -73,12 +73,7 @@ class BluetoothAudioPort {
     * Bluetooth stack
     */
    virtual bool loadAudioConfig(
            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;

    /**
     * WAR to support Mono mode / 16 bits per sample
     */
    virtual void forcePcmStereoToMono(bool) = 0;
            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration&) = 0;

    /**
     * When the Audio framework / HAL wants to change the stream state, it invokes
@@ -145,7 +140,7 @@ class BluetoothAudioPort {

    virtual bool isLeAudio() const = 0;

    virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
    virtual bool getPreferredDataIntervalUs(size_t&) const = 0;

    virtual size_t writeData(const void*, size_t) const { return 0; }

@@ -162,10 +157,8 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort {

    void unregisterPort() override;

    bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
            const override;

    void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
    bool loadAudioConfig(
            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;

    bool standby() override;
    bool start() override;
@@ -193,7 +186,7 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort {

    bool isLeAudio() const override;

    bool getPreferredDataIntervalUs(size_t* interval_us) const override;
    bool getPreferredDataIntervalUs(size_t& interval_us) const override;

  protected:
    uint16_t mCookie;
@@ -228,6 +221,9 @@ class BluetoothAudioPortAidl : public BluetoothAudioPort {

class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
  public:
    bool loadAudioConfig(
            ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& audio_cfg) override;

    // The audio data path to the Bluetooth stack (Software encoding)
    size_t writeData(const void* buffer, size_t bytes) const override;
};
+30 −0
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

#pragma once

#include <map>

#include "core-impl/Bluetooth.h"
#include "core-impl/DevicePortProxy.h"
#include "core-impl/Module.h"

namespace aidl::android::hardware::audio::core {
@@ -31,6 +34,11 @@ class ModuleBluetooth final : public Module {
    ModuleBluetooth(std::unique_ptr<Configuration>&& config);

  private:
    struct CachedProxy {
        std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl> ptr;
        ::aidl::android::hardware::bluetooth::audio::PcmConfiguration pcmConfig;
    };

    ChildInterface<BluetoothA2dp>& getBtA2dp();
    ChildInterface<BluetoothLe>& getBtLe();
    BtProfileHandles getBtProfileManagerHandles();
@@ -40,6 +48,17 @@ class ModuleBluetooth final : public Module {
    ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
    ndk::ScopedAStatus setMicMute(bool in_mute) override;

    ndk::ScopedAStatus setAudioPortConfig(
            const ::aidl::android::media::audio::common::AudioPortConfig& in_requested,
            ::aidl::android::media::audio::common::AudioPortConfig* out_suggested,
            bool* _aidl_return) override;

    ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
            const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
            override;
    void onExternalDeviceConnectionChanged(
            const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
    ndk::ScopedAStatus createInputStream(
            StreamContext&& context,
            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
@@ -56,9 +75,20 @@ class ModuleBluetooth final : public Module {
            int32_t nextPortId) override;
    ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
    ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
    int32_t getNominalLatencyMs(
            const ::aidl::android::media::audio::common::AudioPortConfig& portConfig) override;

    ndk::ScopedAStatus createProxy(
            const ::aidl::android::media::audio::common::AudioPort& audioPort,
            int32_t instancePortId, CachedProxy& proxy);
    ndk::ScopedAStatus fetchAndCheckProxy(const StreamContext& context, CachedProxy& proxy);
    ndk::ScopedAStatus findOrCreateProxy(
            const ::aidl::android::media::audio::common::AudioPort& audioPort, CachedProxy& proxy);

    ChildInterface<BluetoothA2dp> mBluetoothA2dp;
    ChildInterface<BluetoothLe> mBluetoothLe;
    std::map<int32_t /*instantiated device port ID*/, CachedProxy> mProxies;
    std::map<int32_t /*mix port handle*/, int32_t /*instantiated device port ID*/> mConnections;
};

}  // namespace aidl::android::hardware::audio::core
Loading