audio: Clarify profiles management for external devices
Clarify what should happen to mix port profiles after
connection of an external device. Add a test to verify
this behavior.
Also, add an XML file for the test runner for
VtsHalAudioCoreTargetTest.
Bug: 273252382
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I3381dd29c5922bf31fa3a8ae6fa273597e8333a1
Merged-In: I3381dd29c5922bf31fa3a8ae6fa273597e8333a1
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 71dc459..6b417a4 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -456,38 +456,45 @@
LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
<< connectedDevicePort.device.toString();
// Check if there is already a connected port with for the same external device.
- for (auto connectedPortId : mConnectedDevicePorts) {
- auto connectedPortIt = findById<AudioPort>(ports, connectedPortId);
+ for (auto connectedPortPair : mConnectedDevicePorts) {
+ auto connectedPortIt = findById<AudioPort>(ports, connectedPortPair.first);
if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
connectedDevicePort.device) {
LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
- << " is already connected at the device port id " << connectedPortId;
+ << " is already connected at the device port id "
+ << connectedPortPair.first;
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
}
}
if (!mDebug.simulateDeviceConnections) {
- // In a real HAL here we would attempt querying the profiles from the device.
- LOG(ERROR) << __func__ << ": failed to query supported device profiles";
- // TODO: Check the return value when it is ready for actual devices.
- populateConnectedDevicePort(&connectedPort);
+ if (ndk::ScopedAStatus status = populateConnectedDevicePort(&connectedPort);
+ !status.isOk()) {
+ return status;
+ }
+ } else {
+ auto& connectedProfiles = getConfig().connectedProfiles;
+ if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+ connectedProfilesIt != connectedProfiles.end()) {
+ connectedPort.profiles = connectedProfilesIt->second;
+ }
+ }
+ if (connectedPort.profiles.empty()) {
+ LOG(ERROR) << "Profiles of a connected port still empty after connecting external device "
+ << connectedPort.toString();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
connectedPort.id = ++getConfig().nextPortId;
- mConnectedDevicePorts.insert(connectedPort.id);
+ auto [connectedPortsIt, _] =
+ mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>()));
LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
<< "connected port ID " << connectedPort.id;
- auto& connectedProfiles = getConfig().connectedProfiles;
- if (auto connectedProfilesIt = connectedProfiles.find(templateId);
- connectedProfilesIt != connectedProfiles.end()) {
- connectedPort.profiles = connectedProfilesIt->second;
- }
ports.push_back(connectedPort);
onExternalDeviceConnectionChanged(connectedPort, true /*connected*/);
- *_aidl_return = std::move(connectedPort);
+ std::vector<int32_t> routablePortIds;
std::vector<AudioRoute> newRoutes;
auto& routes = getConfig().routes;
for (auto& r : routes) {
@@ -497,15 +504,30 @@
newRoute.sinkPortId = connectedPort.id;
newRoute.isExclusive = r.isExclusive;
newRoutes.push_back(std::move(newRoute));
+ routablePortIds.insert(routablePortIds.end(), r.sourcePortIds.begin(),
+ r.sourcePortIds.end());
} else {
auto& srcs = r.sourcePortIds;
if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
srcs.push_back(connectedPort.id);
+ routablePortIds.push_back(r.sinkPortId);
}
}
}
routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
+ // Note: this is a simplistic approach assuming that a mix port can only be populated
+ // from a single device port. Implementing support for stuffing dynamic profiles with a superset
+ // of all profiles from all routable dynamic device ports would be more involved.
+ for (const auto mixPortId : routablePortIds) {
+ auto portsIt = findById<AudioPort>(ports, mixPortId);
+ if (portsIt != ports.end() && portsIt->profiles.empty()) {
+ portsIt->profiles = connectedPort.profiles;
+ connectedPortsIt->second.push_back(portsIt->id);
+ }
+ }
+ *_aidl_return = std::move(connectedPort);
+
return ndk::ScopedAStatus::ok();
}
@@ -520,7 +542,8 @@
LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (mConnectedDevicePorts.count(in_portId) == 0) {
+ auto connectedPortsIt = mConnectedDevicePorts.find(in_portId);
+ if (connectedPortsIt == mConnectedDevicePorts.end()) {
LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
@@ -541,7 +564,6 @@
}
onExternalDeviceConnectionChanged(*portIt, false /*connected*/);
ports.erase(portIt);
- mConnectedDevicePorts.erase(in_portId);
LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
auto& routes = getConfig().routes;
@@ -556,6 +578,14 @@
}
}
+ for (const auto mixPortId : connectedPortsIt->second) {
+ auto mixPortIt = findById<AudioPort>(ports, mixPortId);
+ if (mixPortIt != ports.end()) {
+ mixPortIt->profiles = {};
+ }
+ }
+ mConnectedDevicePorts.erase(connectedPortsIt);
+
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 4dd0133..70320e4 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -33,7 +33,8 @@
std::vector<::aidl::android::media::audio::common::AudioPort> ports;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
- // Port id -> List of profiles to use when the device port state is set to 'connected'.
+ // Port id -> List of profiles to use when the device port state is set to 'connected'
+ // in connection simulation mode.
std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
connectedProfiles;
std::vector<AudioRoute> routes;
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 2cbda7d..83ecfaa 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -177,8 +177,10 @@
ChildInterface<IBluetooth> mBluetooth;
ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
ChildInterface<IBluetoothLe> mBluetoothLe;
- // ids of ports created at runtime via 'connectExternalDevice'.
- std::set<int32_t> mConnectedDevicePorts;
+ // ids of device ports created at runtime via 'connectExternalDevice'.
+ // Also stores ids of mix ports with dynamic profiles which got populated from the connected
+ // port.
+ std::map<int32_t, std::vector<int32_t>> mConnectedDevicePorts;
Streams mStreams;
// Maps port ids and port config ids to patch ids.
// Multimap because both ports and configs can be used by multiple patches.