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

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

Merge "libaudiohal@aidl: Properly handle "legacy" r_submix case" into main am: 636a5b50

parents 98f296ec 636a5b50
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -79,8 +79,8 @@ public:

    bool equals(const sp<DeviceDescriptorBase>& other) const;

    status_t writeToParcelable(media::AudioPortFw* parcelable) const;
    status_t readFromParcelable(const media::AudioPortFw& parcelable);
    virtual status_t writeToParcelable(media::AudioPortFw* parcelable) const;
    virtual status_t readFromParcelable(const media::AudioPortFw& parcelable);

protected:
    AudioDeviceTypeAddr mDeviceTypeAddr;
+152 −25
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <media/AidlConversionNdkCpp.h>
#include <media/AidlConversionUtil.h>
#include <mediautils/TimeCheck.h>
#include <system/audio.h>
#include <Utils.h>
#include <utils/Log.h>

@@ -41,6 +42,7 @@ using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfig;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceAddress;
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;
@@ -185,23 +187,77 @@ status_t DeviceHalAidl::initCheck() {
    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
    ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
            __func__, mInstance.c_str());
    std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
            [](const auto& p) { return std::make_pair(p.id, p); });
    mDefaultInputPortId = mDefaultOutputPortId = -1;
    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
    for (const auto& pair : mPorts) {
        const auto& p = pair.second;
        if (p.ext.getTag() == AudioPortExt::Tag::device &&
                (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
            if (p.flags.getTag() == AudioIoFlags::Tag::input) {
                mDefaultInputPortId = p.id;
            } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
                mDefaultOutputPortId = p.id;
    for (auto it = ports.begin(); it != ports.end(); ) {
        const auto& port = *it;
        if (port.ext.getTag() != AudioPortExt::Tag::device) {
            ++it;
            continue;
        }
        const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>();
        if ((deviceExt.flags & defaultDeviceFlag) != 0) {
            if (port.flags.getTag() == AudioIoFlags::Tag::input) {
                mDefaultInputPortId = port.id;
            } else if (port.flags.getTag() == AudioIoFlags::Tag::output) {
                mDefaultOutputPortId = port.id;
            }
        }
        // For compatibility with HIDL, hide "template" remote submix ports from ports list.
        if (const auto& devDesc = deviceExt.device;
                (devDesc.type.type == AudioDeviceType::IN_SUBMIX ||
                        devDesc.type.type == AudioDeviceType::OUT_SUBMIX) &&
                devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) {
            if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) {
                mRemoteSubmixIn = port;
            } else {
                mRemoteSubmixOut = port;
            }
            it = ports.erase(it);
        } else {
            ++it;
        }
    }
    if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) {
        ALOGE("%s: The configuration only has input or output remote submix device, must have both",
                __func__);
        mRemoteSubmixIn.reset();
        mRemoteSubmixOut.reset();
    }
    if (mRemoteSubmixIn.has_value()) {
        AudioPort connectedRSubmixIn = *mRemoteSubmixIn;
        connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address =
                AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
        ALOGD("%s: connecting remote submix input", __func__);
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
                                connectedRSubmixIn, &connectedRSubmixIn)));
        // The template port for the remote submix input couldn't be "default" because it is not
        // attached. The connected port can now be made default because we never disconnect it.
        if (mDefaultInputPortId == -1) {
            mDefaultInputPortId = connectedRSubmixIn.id;
        }
        ports.push_back(std::move(connectedRSubmixIn));

        // Remote submix output must not be connected until the framework actually starts
        // using it, however for legacy compatibility we need to provide an "augmented template"
        // port with an address and profiles. It is obtained by connecting the output and then
        // immediately disconnecting it. This is a cheap operation as we don't open any streams.
        AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut;
        tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address =
                AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS;
        ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__);
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
                                tempConnectedRSubmixOut, &tempConnectedRSubmixOut)));
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
                                tempConnectedRSubmixOut.id)));
        tempConnectedRSubmixOut.id = mRemoteSubmixOut->id;
        ports.push_back(std::move(tempConnectedRSubmixOut));
    }

    ALOGI("%s: module %s default port ids: input %d, output %d",
            __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
    std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
            [](const auto& p) { return std::make_pair(p.id, p); });
    RETURN_STATUS_IF_ERROR(updateRoutes());
    std::vector<AudioPortConfig> portConfigs;
    RETURN_STATUS_IF_ERROR(
@@ -1079,6 +1135,7 @@ status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_por
}

status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
    TIME_CHECK();
    if (!mModule) return NO_INIT;
    if (port == nullptr) {
@@ -1104,8 +1161,28 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool
    }
    if (connected) {
        AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
        std::optional<AudioPort> templatePort;
        auto erasePortAfterConnectionIt = mPorts.end();
        // Connection of remote submix out with address "0" is a special case. Since there is
        // already an "augmented template" port with this address in mPorts, we need to replace
        // it with a connected port.
        // Connection of remote submix outs with any other address is done as usual except that
        // the template port is in `mRemoteSubmixOut`.
        if (mRemoteSubmixOut.has_value() &&
                matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) {
            if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
                            AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
                erasePortAfterConnectionIt = findPort(matchDevice);
            }
            templatePort = mRemoteSubmixOut;
        } else if (mRemoteSubmixIn.has_value() &&
                matchDevice.type.type == AudioDeviceType::IN_SUBMIX) {
            templatePort = mRemoteSubmixIn;
        } else {
            // Reset the device address to find the "template" port.
            matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
        }
        if (!templatePort.has_value()) {
            auto portsIt = findPort(matchDevice);
            if (portsIt == mPorts.end()) {
                // Since 'setConnectedState' is called for all modules, it is normal when the device
@@ -1115,9 +1192,12 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool
                ALOGD("%s: device port for device %s found in the module %s",
                        __func__, matchDevice.toString().c_str(), mInstance.c_str());
            }
            templatePort = portsIt->second;
        }
        resetUnusedPatchesAndPortConfigs();

        // Use the ID of the "template" port, use all the information from the provided port.
        aidlPort.id = portsIt->first;
        aidlPort.id = templatePort->id;
        AudioPort connectedPort;
        RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
                                aidlPort, &connectedPort)));
@@ -1127,6 +1207,9 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool
                __func__, mInstance.c_str(), connectedPort.toString().c_str(),
                it->second.toString().c_str());
        mConnectedPorts[connectedPort.id] = false;
        if (erasePortAfterConnectionIt != mPorts.end()) {
            mPorts.erase(erasePortAfterConnectionIt);
        }
    } else {  // !connected
        AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
        auto portsIt = findPort(matchDevice);
@@ -1139,14 +1222,24 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool
                    __func__, matchDevice.toString().c_str(), mInstance.c_str());
        }
        resetUnusedPatchesAndPortConfigs();

        // Disconnection of remote submix out with address "0" is a special case. We need to replace
        // the connected port entry with the "augmented template".
        const int32_t portId = portsIt->second.id;
        if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX &&
                matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>(
                        AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) {
            mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut);
            auto& port = mDisconnectedPortReplacement.second;
            port.ext.get<AudioPortExt::Tag::device>().device = matchDevice;
            port.profiles = portsIt->second.profiles;
        }
        // Streams are closed by AudioFlinger independently from device disconnections.
        // It is possible that the stream has not been closed yet.
        const int32_t portId = portsIt->second.id;
        if (!isPortHeldByAStream(portId)) {
            RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
                            mModule->disconnectExternalDevice(portId)));
            mPorts.erase(portsIt);
            mConnectedPorts.erase(portId);
            eraseConnectedPort(portId);
        } else {
            ALOGD("%s: since device port ID %d is used by a stream, "
                    "external device disconnection postponed", __func__, portId);
@@ -1216,6 +1309,17 @@ status_t DeviceHalAidl::createOrUpdatePortConfig(
    return OK;
}

void DeviceHalAidl::eraseConnectedPort(int32_t portId) {
    mPorts.erase(portId);
    mConnectedPorts.erase(portId);
    if (mDisconnectedPortReplacement.first == portId) {
        const auto& port = mDisconnectedPortReplacement.second;
        mPorts.insert(std::make_pair(port.id, port));
        ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
        mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
    }
}

status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters(
        AudioParameter &keys, AudioParameter *result) {
    TIME_CHECK();
@@ -1847,8 +1951,7 @@ void DeviceHalAidl::resetUnusedPortConfigs() {
        if (!isPortHeldByAStream(portId)) {
            TIME_CHECK();
            if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
                mPorts.erase(portId);
                mConnectedPorts.erase(portId);
                eraseConnectedPort(portId);
                ALOGD("%s: executed postponed external device disconnection for port ID %d",
                        __func__, portId);
            }
@@ -1865,6 +1968,30 @@ status_t DeviceHalAidl::updateRoutes() {
            statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes)));
    ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes",
            __func__, mInstance.c_str());
    if (mRemoteSubmixIn.has_value()) {
        // Remove mentions of the template remote submix input from routes.
        int32_t rSubmixInId = mRemoteSubmixIn->id;
        // Remove mentions of the template remote submix out only if it is not in mPorts
        // (that means there is a connected port in mPorts).
        int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ?
                mRemoteSubmixOut->id : -1;
        for (auto it = mRoutes.begin(); it != mRoutes.end();) {
            auto& route = *it;
            if (route.sinkPortId == rSubmixOutId) {
                it = mRoutes.erase(it);
                continue;
            }
            if (auto sourceIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(),
                            rSubmixInId); sourceIt != route.sourcePortIds.end()) {
                route.sourcePortIds.erase(sourceIt);
                if (route.sourcePortIds.empty()) {
                    it = mRoutes.erase(it);
                    continue;
                }
            }
            ++it;
        }
    }
    mRoutingMatrix.clear();
    for (const auto& r : mRoutes) {
        for (auto portId : r.sourcePortIds) {
+7 −0
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl,
    status_t createOrUpdatePortConfig(
            const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
            PortConfigs::iterator* result, bool *created);
    void eraseConnectedPort(int32_t portId);
    status_t filterAndRetrieveBtA2dpParameters(AudioParameter &keys, AudioParameter *result);
    status_t filterAndUpdateBtA2dpParameters(AudioParameter &parameters);
    status_t filterAndUpdateBtHfpParameters(AudioParameter &parameters);
@@ -313,6 +314,10 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl,
    std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose>
        mSoundDose = nullptr;
    Ports mPorts;
    // Remote submix "template" ports (no address specified, no profiles).
    // They are excluded from `mPorts` as their presence confuses the framework code.
    std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn;
    std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut;
    int32_t mDefaultInputPortId = -1;
    int32_t mDefaultOutputPortId = -1;
    PortConfigs mPortConfigs;
@@ -326,6 +331,8 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl,
    std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
    std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
    ConnectedPorts mConnectedPorts;
    std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
            mDisconnectedPortReplacement;
};

} // namespace android
+3 −1
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ public:
    void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort,
                                            bool force = false);

    status_t readFromParcelable(const media::AudioPortFw& parcelable) override;

    void setEncapsulationInfoFromHal(AudioPolicyClientInterface *clientInterface);

    void dump(String8 *dst, int spaces, bool verbose = true) const;
@@ -104,7 +106,7 @@ private:
    std::string mTagName; // Unique human readable identifier for a device port found in conf file.
    audio_format_t      mCurrentEncodedFormat;
    bool                mIsDynamic = false;
    const std::string   mDeclaredAddress; // Original device address
    std::string         mDeclaredAddress; // Original device address
};

class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
+9 −2
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@

namespace android {

using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceType;
using media::audio::common::AudioIoFlags;
using media::audio::common::AudioPortDeviceExt;
using media::audio::common::AudioPortExt;
@@ -113,12 +115,17 @@ status_t aidl2legacy_AudioHwModule_HwModule(const media::AudioHwModule& aidl,
            ports.emplace(aidlPort.id, devicePort);

            if (const auto& deviceExt = aidlPort.ext.get<AudioPortExt::device>();
                    deviceExt.device.type.connection.empty()) {  // Attached device
                    deviceExt.device.type.connection.empty() ||
                    // DeviceHalAidl connects remote submix input with an address.
                    (deviceExt.device.type.type == AudioDeviceType::IN_SUBMIX &&
                            deviceExt.device.address != AudioDeviceAddress())) {
                // Attached device.
                if (isInput) {
                    attachedInputDevices->add(devicePort);
                } else {
                    attachedOutputDevices->add(devicePort);
                    if ((deviceExt.flags & defaultDeviceFlag) != 0) {
                    if (*defaultOutputDevice == nullptr &&
                            (deviceExt.flags & defaultDeviceFlag) != 0) {
                        *defaultOutputDevice = devicePort;
                    }
                }
Loading