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

Commit 0da62dd0 authored by Mikhail Naganov's avatar Mikhail Naganov Committed by Gerrit Code Review
Browse files

Merge changes I7df6e323,I0e3412b9 into main

* changes:
  audio: Fix notification of streams of the device change
  audio: Fix update of an existing patch
parents ac9f70ee 89a8ea96
Loading
Loading
Loading
Loading
+47 −21
Original line number Diff line number Diff line
@@ -340,21 +340,43 @@ void Module::registerPatch(const AudioPatch& patch) {

ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                       const AudioPatch& newPatch) {
    // Streams from the old patch need to be disconnected, streams from the new
    // patch need to be connected. If the stream belongs to both patches, no need
    // to update it.
    // Notify streams about the new set of devices they are connected to.
    auto maybeFailure = ndk::ScopedAStatus::ok();
    std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
    idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
                           oldPatch.sourcePortConfigIds.end());
    idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
    idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
    idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
    std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
        if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
    using Connections =
            std::map<int32_t /*mixPortConfigId*/, std::set<int32_t /*devicePortConfigId*/>>;
    Connections oldConnections, newConnections;
    auto fillConnectionsHelper = [&](Connections& connections,
                                     const std::vector<int32_t>& mixPortCfgIds,
                                     const std::vector<int32_t>& devicePortCfgIds) {
        for (int32_t mixPortCfgId : mixPortCfgIds) {
            connections[mixPortCfgId].insert(devicePortCfgIds.begin(), devicePortCfgIds.end());
        }
    };
    auto fillConnections = [&](Connections& connections, const AudioPatch& patch) {
        if (std::find_if(patch.sourcePortConfigIds.begin(), patch.sourcePortConfigIds.end(),
                         [&](int32_t portConfigId) { return mStreams.count(portConfigId) > 0; }) !=
            patch.sourcePortConfigIds.end()) {
            // Sources are mix ports.
            fillConnectionsHelper(connections, patch.sourcePortConfigIds, patch.sinkPortConfigIds);
        } else if (std::find_if(patch.sinkPortConfigIds.begin(), patch.sinkPortConfigIds.end(),
                                [&](int32_t portConfigId) {
                                    return mStreams.count(portConfigId) > 0;
                                }) != patch.sinkPortConfigIds.end()) {
            // Sources are device ports.
            fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds);
        }  // Otherwise, there are no streams to notify.
    };
    fillConnections(oldConnections, oldPatch);
    fillConnections(newConnections, newPatch);

    std::for_each(oldConnections.begin(), oldConnections.end(), [&](const auto& connectionPair) {
        const int32_t mixPortConfigId = connectionPair.first;
        if (auto it = newConnections.find(mixPortConfigId);
            it == newConnections.end() || it->second != connectionPair.second) {
            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, {});
                status.isOk()) {
                LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
                           << portConfigId << " has been disconnected";
                           << mixPortConfigId << " has been disconnected";
            } else {
                // Disconnection is tricky to roll back, just register a failure.
                maybeFailure = std::move(status);
@@ -362,23 +384,26 @@ ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatc
        }
    });
    if (!maybeFailure.isOk()) return maybeFailure;
    std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
        if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
            const auto connectedDevices = findConnectedDevices(portConfigId);
    std::set<int32_t> idsToDisconnectOnFailure;
    std::for_each(newConnections.begin(), newConnections.end(), [&](const auto& connectionPair) {
        const int32_t mixPortConfigId = connectionPair.first;
        if (auto it = oldConnections.find(mixPortConfigId);
            it == oldConnections.end() || it->second != connectionPair.second) {
            const auto connectedDevices = findConnectedDevices(mixPortConfigId);
            if (connectedDevices.empty()) {
                // This is important as workers use the vector size to derive the connection status.
                LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
                              "config id "
                           << portConfigId;
                           << mixPortConfigId;
            }
            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices);
                status.isOk()) {
                LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
                           << portConfigId << " has been connected to: "
                           << mixPortConfigId << " has been connected to: "
                           << ::android::internal::ToString(connectedDevices);
            } else {
                maybeFailure = std::move(status);
                idsToDisconnectOnFailure.insert(portConfigId);
                idsToDisconnectOnFailure.insert(mixPortConfigId);
            }
        }
    });
@@ -515,7 +540,7 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA
        }
    }

    connectedPort.id = ++getConfig().nextPortId;
    connectedPort.id = getConfig().nextPortId++;
    auto [connectedPortsIt, _] =
            mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
    LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
@@ -865,6 +890,7 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa
        patches.push_back(*_aidl_return);
    } else {
        oldPatch = *existing;
        *existing = *_aidl_return;
    }
    patchesBackup = mPatches;
    registerPatch(*_aidl_return);
+53 −1
Original line number Diff line number Diff line
@@ -1238,13 +1238,27 @@ class WithAudioPatch {
                   const AudioPortConfig& portConfig2)
        : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
          mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
    WithAudioPatch(const WithAudioPatch& patch, const AudioPortConfig& srcPortConfig,
                   const AudioPortConfig& sinkPortConfig)
        : mInitialPatch(patch.mPatch),
          mSrcPortConfig(srcPortConfig),
          mSinkPortConfig(sinkPortConfig),
          mModule(patch.mModule),
          mPatch(patch.mPatch) {}
    WithAudioPatch(const WithAudioPatch&) = delete;
    WithAudioPatch& operator=(const WithAudioPatch&) = delete;
    ~WithAudioPatch() {
        if (mModule != nullptr && mPatch.id != 0) {
            if (mInitialPatch.has_value()) {
                AudioPatch ignored;
                // This releases our port configs so that they can be reset.
                EXPECT_IS_OK(mModule->setAudioPatch(*mInitialPatch, &ignored))
                        << "patch id " << mInitialPatch->id;
            } else {
                EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
            }
        }
    }
    void SetUpPortConfigs(IModule* module) {
        ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
        ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
@@ -1264,6 +1278,16 @@ class WithAudioPatch {
            EXPECT_GT(latencyMs, 0) << "patch id " << getId();
        }
    }
    void VerifyAgainstAllPatches(IModule* module) {
        std::vector<AudioPatch> allPatches;
        ASSERT_IS_OK(module->getAudioPatches(&allPatches));
        const auto& patchIt = findById(allPatches, getId());
        ASSERT_NE(patchIt, allPatches.end()) << "patch id " << getId();
        if (get() != *patchIt) {
            FAIL() << "Stored patch: " << get().toString() << " is not the same as returned "
                   << "by the HAL module: " << patchIt->toString();
        }
    }
    int32_t getId() const { return mPatch.id; }
    const AudioPatch& get() const { return mPatch; }
    const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
@@ -1273,6 +1297,7 @@ class WithAudioPatch {
    }

  private:
    std::optional<AudioPatch> mInitialPatch;
    WithAudioPortConfig mSrcPortConfig;
    WithAudioPortConfig mSinkPortConfig;
    IModule* mModule = nullptr;
@@ -3637,9 +3662,12 @@ class AudioModulePatch : public AudioCoreModule {
                    patches.push_back(
                            std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
                    EXPECT_NO_FATAL_FAILURE(
                            patches[patches.size() - 1]->VerifyAgainstAllPatches(module.get()));
                } else {
                    WithAudioPatch patch(srcSink.first, srcSink.second);
                    EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
                    EXPECT_NO_FATAL_FAILURE(patch.VerifyAgainstAllPatches(module.get()));
                }
            }
        }
@@ -3660,6 +3688,29 @@ class AudioModulePatch : public AudioCoreModule {
        }
    }

    void UpdatePatchPorts(bool isInput) {
        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
        if (srcSinkGroups.empty()) {
            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
        }
        bool hasAtLeastOnePair = false;
        for (const auto& srcSinkGroup : srcSinkGroups) {
            const auto& srcSinks = srcSinkGroup.second;
            if (srcSinks.size() < 2) continue;
            hasAtLeastOnePair = true;
            const auto& pair1 = srcSinks[0];
            const auto& pair2 = srcSinks[1];
            WithAudioPatch patch(pair1.first, pair1.second);
            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
            WithAudioPatch update(patch, pair2.first, pair2.second);
            EXPECT_NO_FATAL_FAILURE(update.SetUp(module.get()));
            EXPECT_NO_FATAL_FAILURE(update.VerifyAgainstAllPatches(module.get()));
        }
        if (!hasAtLeastOnePair) {
            GTEST_SKIP() << "No routes with multiple sources";
        }
    }

    void UpdateInvalidPatchId(bool isInput) {
        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
        if (srcSinkGroups.empty()) {
@@ -3699,6 +3750,7 @@ TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
TEST_PATCH_BOTH_DIRECTIONS(UpdatePatchPorts);

TEST_P(AudioModulePatch, ResetInvalidPatchId) {
    std::set<int32_t> patchIds;