Loading audio/aidl/default/CapEngineConfigXmlConverter.cpp +24 −17 Original line number Diff line number Diff line Loading @@ -69,29 +69,36 @@ ConversionResult<AudioHalCapRule::CriterionRule> convertCriterionRuleToAidl( std::string criterionName = xsdcRule.getSelectionCriterion(); std::string criterionValue = xsdcRule.getValue(); if (iequals(criterionName, toString(Tag::availableInputDevices))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevices>(); rule.criterionTypeValue = VALUE_OR_RETURN(convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue)); AudioHalCapCriterionV2::AvailableDevices value; value.values.emplace_back(VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableInputDevices>(value); } else if (iequals(criterionName, toString(Tag::availableOutputDevices))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(); rule.criterionTypeValue = VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue)); AudioHalCapCriterionV2::AvailableDevices value; value.values.emplace_back(VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(value); } else if (iequals(criterionName, toString(Tag::availableInputDevicesAddresses))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(); rule.criterionTypeValue = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue); AudioHalCapCriterionV2::AvailableDevicesAddresses value; value.values.emplace_back(criterionValue); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(value); } else if (iequals(criterionName, toString(Tag::availableOutputDevicesAddresses))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(); rule.criterionTypeValue = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue); AudioHalCapCriterionV2::AvailableDevicesAddresses value; value.values.emplace_back(criterionValue); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(value); } else if (iequals(criterionName, toString(Tag::telephonyMode))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::telephonyMode>(); rule.criterionTypeValue = VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue)); AudioHalCapCriterionV2::TelephonyMode value; value.values.emplace_back(VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::telephonyMode>(value); } else if (!fastcmp<strncmp>(criterionName.c_str(), kXsdcForceConfigForUse, strlen(kXsdcForceConfigForUse))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>( VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName))); rule.criterionTypeValue = VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue)); AudioHalCapCriterionV2::ForceConfigForUse value; value.forceUse = VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName)); value.values.emplace_back(VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(value); } else { LOG(ERROR) << __func__ << " unrecognized criterion " << criterionName; return unexpected(BAD_VALUE); Loading audio/aidl/default/Module.cpp +107 −33 Original line number Diff line number Diff line Loading @@ -467,58 +467,132 @@ ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatc fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds); } // Otherwise, there are no streams to notify. }; auto restoreOldConnections = [&](const std::set<int32_t>& mixPortIds, const bool continueWithEmptyDevices) { for (const auto mixPort : mixPortIds) { if (auto it = oldConnections.find(mixPort); continueWithEmptyDevices || it != oldConnections.end()) { const std::vector<AudioDevice> d = it != oldConnections.end() ? getDevicesFromDevicePortConfigIds(it->second) : std::vector<AudioDevice>(); if (auto status = mStreams.setStreamConnectedDevices(mixPort, d); status.isOk()) { LOG(WARNING) << ":updateStreamsConnectedState: rollback: mix port config:" << mixPort << (d.empty() ? "; not connected" : std::string("; connected to ") + ::android::internal::ToString(d)); } else { // can't do much about rollback failures LOG(ERROR) << ":updateStreamsConnectedState: rollback: failed for mix port config:" << mixPort; } } } }; fillConnections(oldConnections, oldPatch); fillConnections(newConnections, newPatch); /** * Illustration of oldConnections and newConnections * * oldConnections { * a : {A,B,C}, * b : {D}, * d : {H,I,J}, * e : {N,O,P}, * f : {Q,R}, * g : {T,U,V}, * } * * newConnections { * a : {A,B,C}, * c : {E,F,G}, * d : {K,L,M}, * e : {N,P}, * f : {Q,R,S}, * g : {U,V,W}, * } * * Expected routings: * 'a': is ignored both in disconnect step and connect step, * due to same devices both in oldConnections and newConnections. * 'b': handled only in disconnect step with empty devices because 'b' is only present * in oldConnections. * 'c': handled only in connect step with {E,F,G} devices because 'c' is only present * in newConnections. * 'd': handled only in connect step with {K,L,M} devices because 'd' is also present * in newConnections and it is ignored in disconnected step. * 'e': handled only in connect step with {N,P} devices because 'e' is also present * in newConnections and it is ignored in disconnect step. please note that there * is no exclusive disconnection for device {O}. * 'f': handled only in connect step with {Q,R,S} devices because 'f' is also present * in newConnections and it is ignored in disconnect step. Even though stream is * already connected with {Q,R} devices and connection happens with {Q,R,S}. * 'g': handled only in connect step with {U,V,W} devices because 'g' is also present * in newConnections and it is ignored in disconnect step. There is no exclusive * disconnection with devices {T,U,V}. * * If, any failure, will lead to restoreOldConnections (rollback). * The aim of the restoreOldConnections is to make connections back to oldConnections. * Failures in restoreOldConnections aren't handled. */ 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, {}); std::set<int32_t> idsToConnectBackOnFailure; // disconnection step for (const auto& [oldMixPortConfigId, oldDevicePortConfigIds] : oldConnections) { if (auto it = newConnections.find(oldMixPortConfigId); it == newConnections.end()) { idsToConnectBackOnFailure.insert(oldMixPortConfigId); if (auto status = mStreams.setStreamConnectedDevices(oldMixPortConfigId, {}); status.isOk()) { LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " << mixPortConfigId << " has been disconnected"; LOG(DEBUG) << __func__ << ": The stream on port config id " << oldMixPortConfigId << " has been disconnected"; } else { // Disconnection is tricky to roll back, just register a failure. maybeFailure = std::move(status); // proceed to rollback even on one failure break; } } }); if (!maybeFailure.isOk()) return maybeFailure; 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 = getDevicesFromDevicePortConfigIds(connectionPair.second); } if (!maybeFailure.isOk()) { restoreOldConnections(idsToConnectBackOnFailure, false /*continueWithEmptyDevices*/); LOG(WARNING) << __func__ << ": failed to disconnect from old patch. attempted rollback"; return maybeFailure; } std::set<int32_t> idsToRollbackOnFailure; // connection step for (const auto& [newMixPortConfigId, newDevicePortConfigIds] : newConnections) { if (auto it = oldConnections.find(newMixPortConfigId); it == oldConnections.end() || it->second != newDevicePortConfigIds) { const auto connectedDevices = getDevicesFromDevicePortConfigIds(newDevicePortConfigIds); idsToRollbackOnFailure.insert(newMixPortConfigId); 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 " << mixPortConfigId; LOG(FATAL) << __func__ << ": No connected devices found for port config id " << newMixPortConfigId; } if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices); if (auto status = mStreams.setStreamConnectedDevices(newMixPortConfigId, connectedDevices); status.isOk()) { LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " << mixPortConfigId << " has been connected to: " LOG(DEBUG) << __func__ << ": The stream on port config id " << newMixPortConfigId << " has been connected to: " << ::android::internal::ToString(connectedDevices); } else { maybeFailure = std::move(status); idsToDisconnectOnFailure.insert(mixPortConfigId); // proceed to rollback even on one failure break; } } }); } if (!maybeFailure.isOk()) { LOG(WARNING) << __func__ << ": " << mType << ": Due to a failure, disconnecting streams on port config ids " << ::android::internal::ToString(idsToDisconnectOnFailure); std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(), [&](const auto& portConfigId) { auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); (void)status.isOk(); // Can't do much about a failure here. }); restoreOldConnections(idsToConnectBackOnFailure, false /*continueWithEmptyDevices*/); restoreOldConnections(idsToRollbackOnFailure, true /*continueWithEmptyDevices*/); LOG(WARNING) << __func__ << ": failed to connect for new patch. attempted rollback"; return maybeFailure; } return ndk::ScopedAStatus::ok(); } Loading audio/aidl/vts/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ cc_defaults { ], header_libs: [ "libaudioaidl_headers", "libaudioutils_headers", "libexpectedutils_headers", ], cflags: [ Loading audio/aidl/vts/EffectHelper.h +13 −4 Original line number Diff line number Diff line Loading @@ -429,19 +429,28 @@ class EffectHelper { } } // Generate multitone input between -1 to +1 using testFrequencies void generateMultiTone(const std::vector<int>& testFrequencies, std::vector<float>& input, const int samplingFrequency) { // Generate multitone input between -amplitude to +amplitude using testFrequencies // All test frequencies are considered having the same amplitude void generateSineWave(const std::vector<int>& testFrequencies, std::vector<float>& input, const float amplitude = 1.0, const int samplingFrequency = kSamplingFrequency) { for (size_t i = 0; i < input.size(); i++) { input[i] = 0; for (size_t j = 0; j < testFrequencies.size(); j++) { input[i] += sin(2 * M_PI * testFrequencies[j] * i / samplingFrequency); } input[i] /= testFrequencies.size(); input[i] *= amplitude / testFrequencies.size(); } } // Generate single tone input between -amplitude to +amplitude using testFrequency void generateSineWave(const int testFrequency, std::vector<float>& input, const float amplitude = 1.0, const int samplingFrequency = kSamplingFrequency) { generateSineWave(std::vector<int>{testFrequency}, input, amplitude, samplingFrequency); } // Use FFT transform to convert the buffer to frequency domain // Compute its magnitude at binOffsets std::vector<float> calculateMagnitude(const std::vector<float>& buffer, Loading audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp +33 −19 Original line number Diff line number Diff line Loading @@ -355,7 +355,6 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { const AudioHalCapRule& rule, const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) { const auto& compoundRule = rule.compoundRule; using TypeTag = AudioHalCapCriterionV2::Type::Tag; if (rule.nestedRules.empty() && rule.criterionRules.empty()) { EXPECT_EQ(compoundRule, AudioHalCapRule::CompoundRule::ALL); } Loading @@ -365,8 +364,8 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { ValidateAudioHalConfigurationRule(nestedRule, criteria); } for (const auto& criterionRule : rule.criterionRules) { auto selectionCriterion = criterionRule.criterion; auto criterionValue = criterionRule.criterionTypeValue; auto selectionCriterion = criterionRule.criterionAndValue; auto criterionValue = criterionRule.criterionAndValue; auto matchesWhen = criterionRule.matchingRule; auto criteriaIt = find_if(criteria.begin(), criteria.end(), [&](const auto& criterion) { return criterion.has_value() && Loading @@ -377,50 +376,65 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value(); switch (selectionCriterion.getTag()) { case AudioHalCapCriterionV2::availableInputDevices: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::availableInputDevices>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(), criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableOutputDevices: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::availableOutputDevices>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(), criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableInputDevicesAddresses: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType); const auto& values = criterionValue .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(), criterionValue.get<TypeTag::availableDevicesAddressesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableOutputDevicesAddresses: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType); const auto& values = criterionValue .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(), criterionValue.get<TypeTag::availableDevicesAddressesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::telephonyMode: { EXPECT_EQ(criterionValue.getTag(), TypeTag::telephonyModeType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::telephonyMode>().values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(), criterionValue.get<TypeTag::telephonyModeType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::forceConfigForUse: { EXPECT_EQ(criterionValue.getTag(), TypeTag::forcedConfigType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::forceConfigForUse>().values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::forceConfigForUse>(), criterionValue.get<TypeTag::forcedConfigType>(), matchesWhen); matchingCriterion.get<AudioHalCapCriterionV2::forceConfigForUse>(), values[0], matchesWhen); break; } default: Loading Loading
audio/aidl/default/CapEngineConfigXmlConverter.cpp +24 −17 Original line number Diff line number Diff line Loading @@ -69,29 +69,36 @@ ConversionResult<AudioHalCapRule::CriterionRule> convertCriterionRuleToAidl( std::string criterionName = xsdcRule.getSelectionCriterion(); std::string criterionValue = xsdcRule.getValue(); if (iequals(criterionName, toString(Tag::availableInputDevices))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevices>(); rule.criterionTypeValue = VALUE_OR_RETURN(convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue)); AudioHalCapCriterionV2::AvailableDevices value; value.values.emplace_back(VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableInputDevices>(value); } else if (iequals(criterionName, toString(Tag::availableOutputDevices))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(); rule.criterionTypeValue = VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue)); AudioHalCapCriterionV2::AvailableDevices value; value.values.emplace_back(VALUE_OR_RETURN( convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(value); } else if (iequals(criterionName, toString(Tag::availableInputDevicesAddresses))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(); rule.criterionTypeValue = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue); AudioHalCapCriterionV2::AvailableDevicesAddresses value; value.values.emplace_back(criterionValue); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(value); } else if (iequals(criterionName, toString(Tag::availableOutputDevicesAddresses))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(); rule.criterionTypeValue = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(criterionValue); AudioHalCapCriterionV2::AvailableDevicesAddresses value; value.values.emplace_back(criterionValue); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(value); } else if (iequals(criterionName, toString(Tag::telephonyMode))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::telephonyMode>(); rule.criterionTypeValue = VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue)); AudioHalCapCriterionV2::TelephonyMode value; value.values.emplace_back(VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::telephonyMode>(value); } else if (!fastcmp<strncmp>(criterionName.c_str(), kXsdcForceConfigForUse, strlen(kXsdcForceConfigForUse))) { rule.criterion = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>( VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName))); rule.criterionTypeValue = VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue)); AudioHalCapCriterionV2::ForceConfigForUse value; value.forceUse = VALUE_OR_RETURN(convertForceUseCriterionToAidl(criterionName)); value.values.emplace_back(VALUE_OR_RETURN(convertForcedConfigToAidl(criterionValue))); rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(value); } else { LOG(ERROR) << __func__ << " unrecognized criterion " << criterionName; return unexpected(BAD_VALUE); Loading
audio/aidl/default/Module.cpp +107 −33 Original line number Diff line number Diff line Loading @@ -467,58 +467,132 @@ ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatc fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds); } // Otherwise, there are no streams to notify. }; auto restoreOldConnections = [&](const std::set<int32_t>& mixPortIds, const bool continueWithEmptyDevices) { for (const auto mixPort : mixPortIds) { if (auto it = oldConnections.find(mixPort); continueWithEmptyDevices || it != oldConnections.end()) { const std::vector<AudioDevice> d = it != oldConnections.end() ? getDevicesFromDevicePortConfigIds(it->second) : std::vector<AudioDevice>(); if (auto status = mStreams.setStreamConnectedDevices(mixPort, d); status.isOk()) { LOG(WARNING) << ":updateStreamsConnectedState: rollback: mix port config:" << mixPort << (d.empty() ? "; not connected" : std::string("; connected to ") + ::android::internal::ToString(d)); } else { // can't do much about rollback failures LOG(ERROR) << ":updateStreamsConnectedState: rollback: failed for mix port config:" << mixPort; } } } }; fillConnections(oldConnections, oldPatch); fillConnections(newConnections, newPatch); /** * Illustration of oldConnections and newConnections * * oldConnections { * a : {A,B,C}, * b : {D}, * d : {H,I,J}, * e : {N,O,P}, * f : {Q,R}, * g : {T,U,V}, * } * * newConnections { * a : {A,B,C}, * c : {E,F,G}, * d : {K,L,M}, * e : {N,P}, * f : {Q,R,S}, * g : {U,V,W}, * } * * Expected routings: * 'a': is ignored both in disconnect step and connect step, * due to same devices both in oldConnections and newConnections. * 'b': handled only in disconnect step with empty devices because 'b' is only present * in oldConnections. * 'c': handled only in connect step with {E,F,G} devices because 'c' is only present * in newConnections. * 'd': handled only in connect step with {K,L,M} devices because 'd' is also present * in newConnections and it is ignored in disconnected step. * 'e': handled only in connect step with {N,P} devices because 'e' is also present * in newConnections and it is ignored in disconnect step. please note that there * is no exclusive disconnection for device {O}. * 'f': handled only in connect step with {Q,R,S} devices because 'f' is also present * in newConnections and it is ignored in disconnect step. Even though stream is * already connected with {Q,R} devices and connection happens with {Q,R,S}. * 'g': handled only in connect step with {U,V,W} devices because 'g' is also present * in newConnections and it is ignored in disconnect step. There is no exclusive * disconnection with devices {T,U,V}. * * If, any failure, will lead to restoreOldConnections (rollback). * The aim of the restoreOldConnections is to make connections back to oldConnections. * Failures in restoreOldConnections aren't handled. */ 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, {}); std::set<int32_t> idsToConnectBackOnFailure; // disconnection step for (const auto& [oldMixPortConfigId, oldDevicePortConfigIds] : oldConnections) { if (auto it = newConnections.find(oldMixPortConfigId); it == newConnections.end()) { idsToConnectBackOnFailure.insert(oldMixPortConfigId); if (auto status = mStreams.setStreamConnectedDevices(oldMixPortConfigId, {}); status.isOk()) { LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " << mixPortConfigId << " has been disconnected"; LOG(DEBUG) << __func__ << ": The stream on port config id " << oldMixPortConfigId << " has been disconnected"; } else { // Disconnection is tricky to roll back, just register a failure. maybeFailure = std::move(status); // proceed to rollback even on one failure break; } } }); if (!maybeFailure.isOk()) return maybeFailure; 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 = getDevicesFromDevicePortConfigIds(connectionPair.second); } if (!maybeFailure.isOk()) { restoreOldConnections(idsToConnectBackOnFailure, false /*continueWithEmptyDevices*/); LOG(WARNING) << __func__ << ": failed to disconnect from old patch. attempted rollback"; return maybeFailure; } std::set<int32_t> idsToRollbackOnFailure; // connection step for (const auto& [newMixPortConfigId, newDevicePortConfigIds] : newConnections) { if (auto it = oldConnections.find(newMixPortConfigId); it == oldConnections.end() || it->second != newDevicePortConfigIds) { const auto connectedDevices = getDevicesFromDevicePortConfigIds(newDevicePortConfigIds); idsToRollbackOnFailure.insert(newMixPortConfigId); 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 " << mixPortConfigId; LOG(FATAL) << __func__ << ": No connected devices found for port config id " << newMixPortConfigId; } if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices); if (auto status = mStreams.setStreamConnectedDevices(newMixPortConfigId, connectedDevices); status.isOk()) { LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id " << mixPortConfigId << " has been connected to: " LOG(DEBUG) << __func__ << ": The stream on port config id " << newMixPortConfigId << " has been connected to: " << ::android::internal::ToString(connectedDevices); } else { maybeFailure = std::move(status); idsToDisconnectOnFailure.insert(mixPortConfigId); // proceed to rollback even on one failure break; } } }); } if (!maybeFailure.isOk()) { LOG(WARNING) << __func__ << ": " << mType << ": Due to a failure, disconnecting streams on port config ids " << ::android::internal::ToString(idsToDisconnectOnFailure); std::for_each(idsToDisconnectOnFailure.begin(), idsToDisconnectOnFailure.end(), [&](const auto& portConfigId) { auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); (void)status.isOk(); // Can't do much about a failure here. }); restoreOldConnections(idsToConnectBackOnFailure, false /*continueWithEmptyDevices*/); restoreOldConnections(idsToRollbackOnFailure, true /*continueWithEmptyDevices*/); LOG(WARNING) << __func__ << ": failed to connect for new patch. attempted rollback"; return maybeFailure; } return ndk::ScopedAStatus::ok(); } Loading
audio/aidl/vts/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ cc_defaults { ], header_libs: [ "libaudioaidl_headers", "libaudioutils_headers", "libexpectedutils_headers", ], cflags: [ Loading
audio/aidl/vts/EffectHelper.h +13 −4 Original line number Diff line number Diff line Loading @@ -429,19 +429,28 @@ class EffectHelper { } } // Generate multitone input between -1 to +1 using testFrequencies void generateMultiTone(const std::vector<int>& testFrequencies, std::vector<float>& input, const int samplingFrequency) { // Generate multitone input between -amplitude to +amplitude using testFrequencies // All test frequencies are considered having the same amplitude void generateSineWave(const std::vector<int>& testFrequencies, std::vector<float>& input, const float amplitude = 1.0, const int samplingFrequency = kSamplingFrequency) { for (size_t i = 0; i < input.size(); i++) { input[i] = 0; for (size_t j = 0; j < testFrequencies.size(); j++) { input[i] += sin(2 * M_PI * testFrequencies[j] * i / samplingFrequency); } input[i] /= testFrequencies.size(); input[i] *= amplitude / testFrequencies.size(); } } // Generate single tone input between -amplitude to +amplitude using testFrequency void generateSineWave(const int testFrequency, std::vector<float>& input, const float amplitude = 1.0, const int samplingFrequency = kSamplingFrequency) { generateSineWave(std::vector<int>{testFrequency}, input, amplitude, samplingFrequency); } // Use FFT transform to convert the buffer to frequency domain // Compute its magnitude at binOffsets std::vector<float> calculateMagnitude(const std::vector<float>& buffer, Loading
audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp +33 −19 Original line number Diff line number Diff line Loading @@ -355,7 +355,6 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { const AudioHalCapRule& rule, const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) { const auto& compoundRule = rule.compoundRule; using TypeTag = AudioHalCapCriterionV2::Type::Tag; if (rule.nestedRules.empty() && rule.criterionRules.empty()) { EXPECT_EQ(compoundRule, AudioHalCapRule::CompoundRule::ALL); } Loading @@ -365,8 +364,8 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { ValidateAudioHalConfigurationRule(nestedRule, criteria); } for (const auto& criterionRule : rule.criterionRules) { auto selectionCriterion = criterionRule.criterion; auto criterionValue = criterionRule.criterionTypeValue; auto selectionCriterion = criterionRule.criterionAndValue; auto criterionValue = criterionRule.criterionAndValue; auto matchesWhen = criterionRule.matchingRule; auto criteriaIt = find_if(criteria.begin(), criteria.end(), [&](const auto& criterion) { return criterion.has_value() && Loading @@ -377,50 +376,65 @@ class AudioCoreConfig : public testing::TestWithParam<std::string> { AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value(); switch (selectionCriterion.getTag()) { case AudioHalCapCriterionV2::availableInputDevices: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::availableInputDevices>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(), criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableOutputDevices: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::availableOutputDevices>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(), criterionValue.get<TypeTag::availableDevicesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableInputDevicesAddresses: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType); const auto& values = criterionValue .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(), criterionValue.get<TypeTag::availableDevicesAddressesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::availableOutputDevicesAddresses: { EXPECT_EQ(criterionValue.getTag(), TypeTag::availableDevicesAddressesType); const auto& values = criterionValue .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>() .values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(), criterionValue.get<TypeTag::availableDevicesAddressesType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::telephonyMode: { EXPECT_EQ(criterionValue.getTag(), TypeTag::telephonyModeType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::telephonyMode>().values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(), criterionValue.get<TypeTag::telephonyModeType>(), matchesWhen); values[0], matchesWhen); break; } case AudioHalCapCriterionV2::forceConfigForUse: { EXPECT_EQ(criterionValue.getTag(), TypeTag::forcedConfigType); const auto& values = criterionValue.get<AudioHalCapCriterionV2::forceConfigForUse>().values; ASSERT_FALSE(values.empty()); validateAudioHalCapRule( matchingCriterion .get<AudioHalCapCriterionV2::forceConfigForUse>(), criterionValue.get<TypeTag::forcedConfigType>(), matchesWhen); matchingCriterion.get<AudioHalCapCriterionV2::forceConfigForUse>(), values[0], matchesWhen); break; } default: Loading