Loading media/libaudiohal/impl/DeviceHalAidl.cpp +32 −5 Original line number Diff line number Diff line Loading @@ -589,7 +589,6 @@ status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources, // that the HAL module uses `int32_t` for patch IDs. The following assert ensures // that both the framework and the HAL use the same value for "no ID": static_assert(AUDIO_PATCH_HANDLE_NONE == 0); int32_t aidlPatchId = static_cast<int32_t>(*patch); // Upon conversion, mix port configs contain audio configuration, while // device port configs contain device address. This data is used to find Loading @@ -611,12 +610,28 @@ status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources, ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig( sinks[i], isInput, 0))); } int32_t aidlPatchId = static_cast<int32_t>(*patch); Hal2AidlMapper::Cleanups cleanups(mMapperAccessor); { std::lock_guard l(mLock); // Check for patches that only exist for the framework, or have different HAL patch ID. if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) { if (aidlHalPatchId == aidlPatchId) { // This patch was previously released by the HAL. Thus we need to pass '0' // to the HAL to obtain a new patch. int32_t newAidlPatchId = 0; RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &newAidlPatchId, &cleanups)); mMapper.updateFwkPatch(aidlPatchId, newAidlPatchId); } else { RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &aidlHalPatchId, &cleanups)); } } else { RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &aidlPatchId, &cleanups)); } } *patch = static_cast<audio_patch_handle_t>(aidlPatchId); cleanups.disarmAll(); return OK; Loading @@ -631,7 +646,19 @@ status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) { return BAD_VALUE; } std::lock_guard l(mLock); RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch))); // Check for patches that only exist for the framework, or have different HAL patch ID. int32_t aidlPatchId = static_cast<int32_t>(patch); if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) { if (aidlHalPatchId == aidlPatchId) { // This patch was previously released by the HAL, just need to finish its removal. mMapper.eraseFwkPatch(aidlPatchId); return OK; } else { // This patch has a HAL patch ID which is different aidlPatchId = aidlHalPatchId; } } RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(aidlPatchId)); return OK; } Loading Loading @@ -988,7 +1015,7 @@ status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) { if (mModule == nullptr) return NO_INIT; { std::lock_guard l(mLock); mMapper.resetUnusedPatchesPortConfigsAndPorts(); mMapper.resetUnusedPatchesAndPortConfigs(); } ModuleDebug debug{ .simulateDeviceConnections = enabled }; status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug)); Loading media/libaudiohal/impl/Hal2AidlMapper.cpp +70 −61 Original line number Diff line number Diff line Loading @@ -102,8 +102,8 @@ Hal2AidlMapper::Hal2AidlMapper(const std::string& instance, const std::shared_pt } void Hal2AidlMapper::addStream( const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId) { mStreams.insert(std::pair(stream, std::pair(portConfigId, patchId))); const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId) { mStreams.insert(std::pair(stream, std::pair(mixPortConfigId, patchId))); } bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) { Loading Loading @@ -698,20 +698,23 @@ status_t Hal2AidlMapper::initialize() { return OK; } bool Hal2AidlMapper::isPortBeingHeld(int32_t portId) { // It is assumed that mStreams has already been cleaned up. for (const auto& s : mStreams) { if (portConfigBelongsToPort(s.second.first, portId)) return true; } for (const auto& [_, patch] : mPatches) { std::set<int32_t> Hal2AidlMapper::getPatchIdsByPortId(int32_t portId) { std::set<int32_t> result; for (const auto& [patchId, patch] : mPatches) { for (int32_t id : patch.sourcePortConfigIds) { if (portConfigBelongsToPort(id, portId)) return true; if (portConfigBelongsToPort(id, portId)) { result.insert(patchId); break; } } for (int32_t id : patch.sinkPortConfigIds) { if (portConfigBelongsToPort(id, portId)) return true; if (portConfigBelongsToPort(id, portId)) { result.insert(patchId); break; } } return false; } return result; } status_t Hal2AidlMapper::prepareToDisconnectExternalDevice(const AudioPort& devicePort) { Loading @@ -730,7 +733,7 @@ status_t Hal2AidlMapper::prepareToOpenStream( this, __func__, ioHandle, device.toString().c_str(), flags.toString().c_str(), toString(source).c_str(), config->toString().c_str(), mixPortConfig->toString().c_str()); resetUnusedPatchesPortConfigsAndPorts(); resetUnusedPatchesAndPortConfigs(); const AudioConfig initialConfig = *config; // Find / create AudioPortConfigs for the device port and the mix port, // then find / create a patch between them, and open a stream on the mix port. Loading Loading @@ -843,39 +846,52 @@ status_t Hal2AidlMapper::releaseAudioPatch(int32_t patchId) { return releaseAudioPatches({patchId}); } status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) { status_t result = OK; for (const auto patchId : patchIds) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { mPatches.erase(it); // Note: does not reset port configs. status_t Hal2AidlMapper::releaseAudioPatch(Patches::iterator it) { const int32_t patchId = it->first; if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) { ALOGE("%s: error while resetting patch %d: %s", __func__, patchId, status.getDescription().c_str()); result = statusTFromBinderStatus(status); return statusTFromBinderStatus(status); } mPatches.erase(it); for (auto it = mFwkPatches.begin(); it != mFwkPatches.end(); ++it) { if (it->second == patchId) { mFwkPatches.erase(it); break; } } return OK; } status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) { status_t result = OK; for (const auto patchId : patchIds) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { releaseAudioPatch(it); } else { ALOGE("%s: patch id %d not found", __func__, patchId); result = BAD_VALUE; } } resetUnusedPortConfigsAndPorts(); resetUnusedPortConfigs(); return result; } void Hal2AidlMapper::resetPortConfig(int32_t portConfigId) { if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) { mPortConfigs.erase(it); if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId); !status.isOk()) { ALOGE("%s: error while resetting port config %d: %s", __func__, portConfigId, status.getDescription().c_str()); } mPortConfigs.erase(it); return; } ALOGE("%s: port config id %d not found", __func__, portConfigId); } void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() { void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() { // Since patches can be created independently of streams via 'createOrUpdatePatch', // here we only clean up patches for released streams. std::set<int32_t> patchesToRelease; Loading @@ -889,52 +905,35 @@ void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() { it = mStreams.erase(it); } } // 'releaseAudioPatches' also resets unused port configs and ports. // 'releaseAudioPatches' also resets unused port configs. releaseAudioPatches(patchesToRelease); } void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() { void Hal2AidlMapper::resetUnusedPortConfigs() { // The assumption is that port configs are used to create patches // (or to open streams, but that involves creation of patches, too). Thus, // orphaned port configs can and should be reset. std::map<int32_t, int32_t /*portID*/> portConfigIds; std::set<int32_t> portConfigIdsToReset; std::transform(mPortConfigs.begin(), mPortConfigs.end(), std::inserter(portConfigIds, portConfigIds.end()), [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); }); std::inserter(portConfigIdsToReset, portConfigIdsToReset.end()), [](const auto& pcPair) { return pcPair.first; }); for (const auto& p : mPatches) { for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id); for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id); for (int32_t id : p.second.sourcePortConfigIds) portConfigIdsToReset.erase(id); for (int32_t id : p.second.sinkPortConfigIds) portConfigIdsToReset.erase(id); } for (int32_t id : mInitialPortConfigIds) { portConfigIds.erase(id); portConfigIdsToReset.erase(id); } for (const auto& s : mStreams) { portConfigIds.erase(s.second.first); } std::set<int32_t> retryDeviceDisconnection; for (const auto& portConfigAndIdPair : portConfigIds) { resetPortConfig(portConfigAndIdPair.first); if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second); it != mConnectedPorts.end() && it->second) { retryDeviceDisconnection.insert(portConfigAndIdPair.second); } } for (int32_t portId : retryDeviceDisconnection) { if (!isPortBeingHeld(portId)) { if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) { eraseConnectedPort(portId); ALOGD("%s: executed postponed external device disconnection for port ID %d", __func__, portId); } portConfigIdsToReset.erase(s.second.first); } } if (!retryDeviceDisconnection.empty()) { updateRoutes(); for (const auto& portConfigId : portConfigIdsToReset) { resetPortConfig(portConfigId); } } status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) { resetUnusedPatchesPortConfigsAndPorts(); resetUnusedPatchesAndPortConfigs(); if (connected) { AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device; std::optional<AudioPort> templatePort; Loading Loading @@ -980,7 +979,7 @@ status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s", __func__, mInstance.c_str(), connectedPort.toString().c_str(), it->second.toString().c_str()); mConnectedPorts[connectedPort.id] = false; mConnectedPorts.insert(connectedPort.id); if (erasePortAfterConnectionIt != mPorts.end()) { mPorts.erase(erasePortAfterConnectionIt); } Loading @@ -1007,17 +1006,27 @@ status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort 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. if (!isPortBeingHeld(portId)) { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( mModule->disconnectExternalDevice(portId))); eraseConnectedPort(portId); } else { ALOGD("%s: since device port ID %d is used by a stream, " "external device disconnection postponed", __func__, portId); mConnectedPorts[portId] = true; // Patches may still exist, the framework may reset or update them later. // For disconnection to succeed, need to release these patches first. if (std::set<int32_t> patchIdsToRelease = getPatchIdsByPortId(portId); !patchIdsToRelease.empty()) { FwkPatches releasedPatches; status_t status = OK; for (int32_t patchId : patchIdsToRelease) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { if (status = releaseAudioPatch(it); status != OK) break; releasedPatches.insert(std::make_pair(patchId, patchId)); } } resetUnusedPortConfigs(); mFwkPatches.merge(releasedPatches); LOG_ALWAYS_FATAL_IF(!releasedPatches.empty(), "mFwkPatches already contains some of released patches"); if (status != OK) return status; } RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(portId))); eraseConnectedPort(portId); } return updateRoutes(); } Loading media/libaudiohal/impl/Hal2AidlMapper.h +30 −9 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ class Hal2AidlMapper { const std::string& instance, const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module); void addStream(const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId); void addStream(const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId); status_t createOrUpdatePatch( const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources, const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks, Loading Loading @@ -91,13 +91,32 @@ class Hal2AidlMapper { ::aidl::android::media::audio::common::AudioPortConfig* portConfig, Cleanups* cleanups = nullptr); status_t releaseAudioPatch(int32_t patchId); void resetUnusedPatchesPortConfigsAndPorts(); void resetUnusedPatchesAndPortConfigs(); status_t setDevicePortConnectedState( const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected); // Methods to work with FwkPatches. void eraseFwkPatch(int32_t fwkPatchId) { mFwkPatches.erase(fwkPatchId); } int32_t findFwkPatch(int32_t fwkPatchId) { const auto it = mFwkPatches.find(fwkPatchId); return it != mFwkPatches.end() ? it->second : 0; } void updateFwkPatch(int32_t fwkPatchId, int32_t halPatchId) { mFwkPatches[fwkPatchId] = halPatchId; } private: // IDs of ports for connected external devices, and whether they are held by streams. using ConnectedPorts = std::map<int32_t /*port ID*/, bool>; // 'FwkPatches' is used to store patches that diverge from the framework's state. // Uses framework patch ID (aka audio_patch_handle_t) values for indexing. // When the 'key == value', that means Hal2AidlMapper has removed this patch, and it is absent // from 'mPatches', but it still "exists" for the framework. It will either remove it or // re-patch. If the framework re-patches, it will continue to use the same patch handle, // but the HAL will use the new one (since the old patch was reset), thus 'key != value' // for such patches. Since they "exist" both for the framework and the HAL, 'mPatches' // contains their data under HAL patch ID ('value' of 'FwkPatches'). // To avoid confusion, all patchIDs used by Hal2AidlMapper are HAL IDs. Mapping between // framework patch IDs and HAL patch IDs is done by DeviceHalAidl. using FwkPatches = std::map<int32_t /*audio_patch_handle_t*/, int32_t /*patch ID*/>; using Patches = std::map<int32_t /*patch ID*/, ::aidl::android::hardware::audio::core::AudioPatch>; using PortConfigs = std::map<int32_t /*port config ID*/, Loading @@ -107,12 +126,12 @@ class Hal2AidlMapper { // Answers the question "whether portID 'first' is reachable from portID 'second'?" // It's not a map because both portIDs are known. The matrix is symmetric. using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>; // There is always a port config ID set. The patch ID is set after stream // There is always a mix port config ID set. The patch ID is set after stream // creation, and can be set to '-1' later if the framework happens to create // a patch between the same endpoints. In that case, the ownership of the patch // is on the framework. using Streams = std::map<wp<StreamHalInterface>, std::pair<int32_t /*port config ID*/, int32_t /*patch ID*/>>; std::pair<int32_t /*mix port config ID*/, int32_t /*patch ID*/>>; const std::string mInstance; const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; Loading Loading @@ -168,7 +187,7 @@ class Hal2AidlMapper { const std::optional<::aidl::android::media::audio::common::AudioConfig>& config, const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags, int32_t ioHandle); bool isPortBeingHeld(int32_t portId); std::set<int32_t> getPatchIdsByPortId(int32_t portId); status_t prepareToOpenStreamHelper( int32_t ioHandle, int32_t devicePortId, int32_t devicePortConfigId, const ::aidl::android::media::audio::common::AudioIoFlags& flags, Loading @@ -181,10 +200,11 @@ class Hal2AidlMapper { auto it = mPortConfigs.find(portConfigId); return it != mPortConfigs.end() && it->second.portId == portId; } status_t releaseAudioPatch(Patches::iterator it); status_t releaseAudioPatches(const std::set<int32_t>& patchIds); void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); } void resetPortConfig(int32_t portConfigId); void resetUnusedPortConfigsAndPorts(); void resetUnusedPortConfigs(); status_t updateAudioPort( int32_t portId, ::aidl::android::media::audio::common::AudioPort* port); status_t updateRoutes(); Loading @@ -197,13 +217,14 @@ class Hal2AidlMapper { std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut; int32_t mDefaultInputPortId = -1; int32_t mDefaultOutputPortId = -1; FwkPatches mFwkPatches; PortConfigs mPortConfigs; std::set<int32_t> mInitialPortConfigIds; Patches mPatches; Routes mRoutes; RoutingMatrix mRoutingMatrix; Streams mStreams; ConnectedPorts mConnectedPorts; std::set<int32_t> mConnectedPorts; std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort> mDisconnectedPortReplacement; std::set<int32_t> mDynamicMixPortIds; Loading Loading
media/libaudiohal/impl/DeviceHalAidl.cpp +32 −5 Original line number Diff line number Diff line Loading @@ -589,7 +589,6 @@ status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources, // that the HAL module uses `int32_t` for patch IDs. The following assert ensures // that both the framework and the HAL use the same value for "no ID": static_assert(AUDIO_PATCH_HANDLE_NONE == 0); int32_t aidlPatchId = static_cast<int32_t>(*patch); // Upon conversion, mix port configs contain audio configuration, while // device port configs contain device address. This data is used to find Loading @@ -611,12 +610,28 @@ status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources, ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig( sinks[i], isInput, 0))); } int32_t aidlPatchId = static_cast<int32_t>(*patch); Hal2AidlMapper::Cleanups cleanups(mMapperAccessor); { std::lock_guard l(mLock); // Check for patches that only exist for the framework, or have different HAL patch ID. if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) { if (aidlHalPatchId == aidlPatchId) { // This patch was previously released by the HAL. Thus we need to pass '0' // to the HAL to obtain a new patch. int32_t newAidlPatchId = 0; RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &newAidlPatchId, &cleanups)); mMapper.updateFwkPatch(aidlPatchId, newAidlPatchId); } else { RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &aidlHalPatchId, &cleanups)); } } else { RETURN_STATUS_IF_ERROR(mMapper.createOrUpdatePatch( aidlSources, aidlSinks, &aidlPatchId, &cleanups)); } } *patch = static_cast<audio_patch_handle_t>(aidlPatchId); cleanups.disarmAll(); return OK; Loading @@ -631,7 +646,19 @@ status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) { return BAD_VALUE; } std::lock_guard l(mLock); RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(static_cast<int32_t>(patch))); // Check for patches that only exist for the framework, or have different HAL patch ID. int32_t aidlPatchId = static_cast<int32_t>(patch); if (int32_t aidlHalPatchId = mMapper.findFwkPatch(aidlPatchId); aidlHalPatchId != 0) { if (aidlHalPatchId == aidlPatchId) { // This patch was previously released by the HAL, just need to finish its removal. mMapper.eraseFwkPatch(aidlPatchId); return OK; } else { // This patch has a HAL patch ID which is different aidlPatchId = aidlHalPatchId; } } RETURN_STATUS_IF_ERROR(mMapper.releaseAudioPatch(aidlPatchId)); return OK; } Loading Loading @@ -988,7 +1015,7 @@ status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) { if (mModule == nullptr) return NO_INIT; { std::lock_guard l(mLock); mMapper.resetUnusedPatchesPortConfigsAndPorts(); mMapper.resetUnusedPatchesAndPortConfigs(); } ModuleDebug debug{ .simulateDeviceConnections = enabled }; status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug)); Loading
media/libaudiohal/impl/Hal2AidlMapper.cpp +70 −61 Original line number Diff line number Diff line Loading @@ -102,8 +102,8 @@ Hal2AidlMapper::Hal2AidlMapper(const std::string& instance, const std::shared_pt } void Hal2AidlMapper::addStream( const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId) { mStreams.insert(std::pair(stream, std::pair(portConfigId, patchId))); const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId) { mStreams.insert(std::pair(stream, std::pair(mixPortConfigId, patchId))); } bool Hal2AidlMapper::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) { Loading Loading @@ -698,20 +698,23 @@ status_t Hal2AidlMapper::initialize() { return OK; } bool Hal2AidlMapper::isPortBeingHeld(int32_t portId) { // It is assumed that mStreams has already been cleaned up. for (const auto& s : mStreams) { if (portConfigBelongsToPort(s.second.first, portId)) return true; } for (const auto& [_, patch] : mPatches) { std::set<int32_t> Hal2AidlMapper::getPatchIdsByPortId(int32_t portId) { std::set<int32_t> result; for (const auto& [patchId, patch] : mPatches) { for (int32_t id : patch.sourcePortConfigIds) { if (portConfigBelongsToPort(id, portId)) return true; if (portConfigBelongsToPort(id, portId)) { result.insert(patchId); break; } } for (int32_t id : patch.sinkPortConfigIds) { if (portConfigBelongsToPort(id, portId)) return true; if (portConfigBelongsToPort(id, portId)) { result.insert(patchId); break; } } return false; } return result; } status_t Hal2AidlMapper::prepareToDisconnectExternalDevice(const AudioPort& devicePort) { Loading @@ -730,7 +733,7 @@ status_t Hal2AidlMapper::prepareToOpenStream( this, __func__, ioHandle, device.toString().c_str(), flags.toString().c_str(), toString(source).c_str(), config->toString().c_str(), mixPortConfig->toString().c_str()); resetUnusedPatchesPortConfigsAndPorts(); resetUnusedPatchesAndPortConfigs(); const AudioConfig initialConfig = *config; // Find / create AudioPortConfigs for the device port and the mix port, // then find / create a patch between them, and open a stream on the mix port. Loading Loading @@ -843,39 +846,52 @@ status_t Hal2AidlMapper::releaseAudioPatch(int32_t patchId) { return releaseAudioPatches({patchId}); } status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) { status_t result = OK; for (const auto patchId : patchIds) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { mPatches.erase(it); // Note: does not reset port configs. status_t Hal2AidlMapper::releaseAudioPatch(Patches::iterator it) { const int32_t patchId = it->first; if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) { ALOGE("%s: error while resetting patch %d: %s", __func__, patchId, status.getDescription().c_str()); result = statusTFromBinderStatus(status); return statusTFromBinderStatus(status); } mPatches.erase(it); for (auto it = mFwkPatches.begin(); it != mFwkPatches.end(); ++it) { if (it->second == patchId) { mFwkPatches.erase(it); break; } } return OK; } status_t Hal2AidlMapper::releaseAudioPatches(const std::set<int32_t>& patchIds) { status_t result = OK; for (const auto patchId : patchIds) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { releaseAudioPatch(it); } else { ALOGE("%s: patch id %d not found", __func__, patchId); result = BAD_VALUE; } } resetUnusedPortConfigsAndPorts(); resetUnusedPortConfigs(); return result; } void Hal2AidlMapper::resetPortConfig(int32_t portConfigId) { if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) { mPortConfigs.erase(it); if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId); !status.isOk()) { ALOGE("%s: error while resetting port config %d: %s", __func__, portConfigId, status.getDescription().c_str()); } mPortConfigs.erase(it); return; } ALOGE("%s: port config id %d not found", __func__, portConfigId); } void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() { void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() { // Since patches can be created independently of streams via 'createOrUpdatePatch', // here we only clean up patches for released streams. std::set<int32_t> patchesToRelease; Loading @@ -889,52 +905,35 @@ void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() { it = mStreams.erase(it); } } // 'releaseAudioPatches' also resets unused port configs and ports. // 'releaseAudioPatches' also resets unused port configs. releaseAudioPatches(patchesToRelease); } void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() { void Hal2AidlMapper::resetUnusedPortConfigs() { // The assumption is that port configs are used to create patches // (or to open streams, but that involves creation of patches, too). Thus, // orphaned port configs can and should be reset. std::map<int32_t, int32_t /*portID*/> portConfigIds; std::set<int32_t> portConfigIdsToReset; std::transform(mPortConfigs.begin(), mPortConfigs.end(), std::inserter(portConfigIds, portConfigIds.end()), [](const auto& pcPair) { return std::make_pair(pcPair.first, pcPair.second.portId); }); std::inserter(portConfigIdsToReset, portConfigIdsToReset.end()), [](const auto& pcPair) { return pcPair.first; }); for (const auto& p : mPatches) { for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id); for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id); for (int32_t id : p.second.sourcePortConfigIds) portConfigIdsToReset.erase(id); for (int32_t id : p.second.sinkPortConfigIds) portConfigIdsToReset.erase(id); } for (int32_t id : mInitialPortConfigIds) { portConfigIds.erase(id); portConfigIdsToReset.erase(id); } for (const auto& s : mStreams) { portConfigIds.erase(s.second.first); } std::set<int32_t> retryDeviceDisconnection; for (const auto& portConfigAndIdPair : portConfigIds) { resetPortConfig(portConfigAndIdPair.first); if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second); it != mConnectedPorts.end() && it->second) { retryDeviceDisconnection.insert(portConfigAndIdPair.second); } } for (int32_t portId : retryDeviceDisconnection) { if (!isPortBeingHeld(portId)) { if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) { eraseConnectedPort(portId); ALOGD("%s: executed postponed external device disconnection for port ID %d", __func__, portId); } portConfigIdsToReset.erase(s.second.first); } } if (!retryDeviceDisconnection.empty()) { updateRoutes(); for (const auto& portConfigId : portConfigIdsToReset) { resetPortConfig(portConfigId); } } status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) { resetUnusedPatchesPortConfigsAndPorts(); resetUnusedPatchesAndPortConfigs(); if (connected) { AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device; std::optional<AudioPort> templatePort; Loading Loading @@ -980,7 +979,7 @@ status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s", __func__, mInstance.c_str(), connectedPort.toString().c_str(), it->second.toString().c_str()); mConnectedPorts[connectedPort.id] = false; mConnectedPorts.insert(connectedPort.id); if (erasePortAfterConnectionIt != mPorts.end()) { mPorts.erase(erasePortAfterConnectionIt); } Loading @@ -1007,17 +1006,27 @@ status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort 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. if (!isPortBeingHeld(portId)) { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( mModule->disconnectExternalDevice(portId))); eraseConnectedPort(portId); } else { ALOGD("%s: since device port ID %d is used by a stream, " "external device disconnection postponed", __func__, portId); mConnectedPorts[portId] = true; // Patches may still exist, the framework may reset or update them later. // For disconnection to succeed, need to release these patches first. if (std::set<int32_t> patchIdsToRelease = getPatchIdsByPortId(portId); !patchIdsToRelease.empty()) { FwkPatches releasedPatches; status_t status = OK; for (int32_t patchId : patchIdsToRelease) { if (auto it = mPatches.find(patchId); it != mPatches.end()) { if (status = releaseAudioPatch(it); status != OK) break; releasedPatches.insert(std::make_pair(patchId, patchId)); } } resetUnusedPortConfigs(); mFwkPatches.merge(releasedPatches); LOG_ALWAYS_FATAL_IF(!releasedPatches.empty(), "mFwkPatches already contains some of released patches"); if (status != OK) return status; } RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(portId))); eraseConnectedPort(portId); } return updateRoutes(); } Loading
media/libaudiohal/impl/Hal2AidlMapper.h +30 −9 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ class Hal2AidlMapper { const std::string& instance, const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module); void addStream(const sp<StreamHalInterface>& stream, int32_t portConfigId, int32_t patchId); void addStream(const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId); status_t createOrUpdatePatch( const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources, const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks, Loading Loading @@ -91,13 +91,32 @@ class Hal2AidlMapper { ::aidl::android::media::audio::common::AudioPortConfig* portConfig, Cleanups* cleanups = nullptr); status_t releaseAudioPatch(int32_t patchId); void resetUnusedPatchesPortConfigsAndPorts(); void resetUnusedPatchesAndPortConfigs(); status_t setDevicePortConnectedState( const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected); // Methods to work with FwkPatches. void eraseFwkPatch(int32_t fwkPatchId) { mFwkPatches.erase(fwkPatchId); } int32_t findFwkPatch(int32_t fwkPatchId) { const auto it = mFwkPatches.find(fwkPatchId); return it != mFwkPatches.end() ? it->second : 0; } void updateFwkPatch(int32_t fwkPatchId, int32_t halPatchId) { mFwkPatches[fwkPatchId] = halPatchId; } private: // IDs of ports for connected external devices, and whether they are held by streams. using ConnectedPorts = std::map<int32_t /*port ID*/, bool>; // 'FwkPatches' is used to store patches that diverge from the framework's state. // Uses framework patch ID (aka audio_patch_handle_t) values for indexing. // When the 'key == value', that means Hal2AidlMapper has removed this patch, and it is absent // from 'mPatches', but it still "exists" for the framework. It will either remove it or // re-patch. If the framework re-patches, it will continue to use the same patch handle, // but the HAL will use the new one (since the old patch was reset), thus 'key != value' // for such patches. Since they "exist" both for the framework and the HAL, 'mPatches' // contains their data under HAL patch ID ('value' of 'FwkPatches'). // To avoid confusion, all patchIDs used by Hal2AidlMapper are HAL IDs. Mapping between // framework patch IDs and HAL patch IDs is done by DeviceHalAidl. using FwkPatches = std::map<int32_t /*audio_patch_handle_t*/, int32_t /*patch ID*/>; using Patches = std::map<int32_t /*patch ID*/, ::aidl::android::hardware::audio::core::AudioPatch>; using PortConfigs = std::map<int32_t /*port config ID*/, Loading @@ -107,12 +126,12 @@ class Hal2AidlMapper { // Answers the question "whether portID 'first' is reachable from portID 'second'?" // It's not a map because both portIDs are known. The matrix is symmetric. using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>; // There is always a port config ID set. The patch ID is set after stream // There is always a mix port config ID set. The patch ID is set after stream // creation, and can be set to '-1' later if the framework happens to create // a patch between the same endpoints. In that case, the ownership of the patch // is on the framework. using Streams = std::map<wp<StreamHalInterface>, std::pair<int32_t /*port config ID*/, int32_t /*patch ID*/>>; std::pair<int32_t /*mix port config ID*/, int32_t /*patch ID*/>>; const std::string mInstance; const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; Loading Loading @@ -168,7 +187,7 @@ class Hal2AidlMapper { const std::optional<::aidl::android::media::audio::common::AudioConfig>& config, const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags, int32_t ioHandle); bool isPortBeingHeld(int32_t portId); std::set<int32_t> getPatchIdsByPortId(int32_t portId); status_t prepareToOpenStreamHelper( int32_t ioHandle, int32_t devicePortId, int32_t devicePortConfigId, const ::aidl::android::media::audio::common::AudioIoFlags& flags, Loading @@ -181,10 +200,11 @@ class Hal2AidlMapper { auto it = mPortConfigs.find(portConfigId); return it != mPortConfigs.end() && it->second.portId == portId; } status_t releaseAudioPatch(Patches::iterator it); status_t releaseAudioPatches(const std::set<int32_t>& patchIds); void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); } void resetPortConfig(int32_t portConfigId); void resetUnusedPortConfigsAndPorts(); void resetUnusedPortConfigs(); status_t updateAudioPort( int32_t portId, ::aidl::android::media::audio::common::AudioPort* port); status_t updateRoutes(); Loading @@ -197,13 +217,14 @@ class Hal2AidlMapper { std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut; int32_t mDefaultInputPortId = -1; int32_t mDefaultOutputPortId = -1; FwkPatches mFwkPatches; PortConfigs mPortConfigs; std::set<int32_t> mInitialPortConfigIds; Patches mPatches; Routes mRoutes; RoutingMatrix mRoutingMatrix; Streams mStreams; ConnectedPorts mConnectedPorts; std::set<int32_t> mConnectedPorts; std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort> mDisconnectedPortReplacement; std::set<int32_t> mDynamicMixPortIds; Loading