mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:23:37 +00:00
Merge "audio: add rollback support for streams in setAudioPatch." into main
This commit is contained in:
@@ -467,58 +467,132 @@ ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatc
|
||||
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 "
|
||||
<< mixPortConfigId << " has been disconnected";
|
||||
} else {
|
||||
// Disconnection is tricky to roll back, just register a failure.
|
||||
maybeFailure = std::move(status);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
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);
|
||||
};
|
||||
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::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) << __func__ << ": The stream on port config id " << oldMixPortConfigId
|
||||
<< " has been disconnected";
|
||||
} else {
|
||||
maybeFailure = std::move(status);
|
||||
// proceed to rollback even on one failure
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user