libaudiohal@aidl: Fix handling of point-to-point connections

Point-to-point connections (analog, HDMI, SPDIF) do not use
a device address. Reflect that in `GenerateUniqueDeviceAddress`.
When looking for a device port by address, check if there is
a connected device, and use the connected device port.

Bug: 300648357
Test: atest audiosystem_tests
Change-Id: Ic89fe25f1b757d8d95da0cbef09aa55887e62f4f
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index b09a379..2869ca4 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -615,28 +615,37 @@
 
 android::media::audio::common::AudioPort GenerateUniqueDeviceAddress(
         const android::media::audio::common::AudioPort& port) {
+    // Point-to-point connections do not use addresses.
+    static const std::set<std::string> kPointToPointConnections = {
+            AudioDeviceDescription::CONNECTION_ANALOG(), AudioDeviceDescription::CONNECTION_HDMI(),
+            AudioDeviceDescription::CONNECTION_HDMI_ARC(),
+            AudioDeviceDescription::CONNECTION_HDMI_EARC(),
+            AudioDeviceDescription::CONNECTION_SPDIF()};
     static int nextId = 0;
     using Tag = AudioDeviceAddress::Tag;
+    const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
     AudioDeviceAddress address;
-    switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
-        case Tag::id:
-            address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
-            break;
-        case Tag::mac:
-            address = AudioDeviceAddress::make<Tag::mac>(
-                    std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv4:
-            address = AudioDeviceAddress::make<Tag::ipv4>(
-                    std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
-            break;
-        case Tag::ipv6:
-            address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
-                    0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
-            break;
-        case Tag::alsa:
-            address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
-            break;
+    if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+        switch (suggestDeviceAddressTag(deviceDescription)) {
+            case Tag::id:
+                address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+                break;
+            case Tag::mac:
+                address = AudioDeviceAddress::make<Tag::mac>(
+                        std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv4:
+                address = AudioDeviceAddress::make<Tag::ipv4>(
+                        std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+                break;
+            case Tag::ipv6:
+                address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+                        0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+                break;
+            case Tag::alsa:
+                address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+                break;
+        }
     }
     android::media::audio::common::AudioPort result = port;
     result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 362f373..131684c 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -1080,6 +1080,7 @@
                 "%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;
     } else {  // !connected
         AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
         auto portsIt = findPort(matchDevice);
@@ -1099,10 +1100,11 @@
             RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
                             mModule->disconnectExternalDevice(portId)));
             mPorts.erase(portsIt);
+            mConnectedPorts.erase(portId);
         } else {
             ALOGD("%s: since device port ID %d is used by a stream, "
                     "external device disconnection postponed", __func__, portId);
-            mConnectedPortIdsHeldByStreams.insert(portId);
+            mConnectedPorts[portId] = true;
         }
     }
     return updateRoutes();
@@ -1601,8 +1603,25 @@
     } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
         return mPorts.find(mDefaultOutputPortId);
     }
-    return std::find_if(mPorts.begin(), mPorts.end(),
-            [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+    if (device.address.getTag() != AudioDeviceAddress::id ||
+            !device.address.get<AudioDeviceAddress::id>().empty()) {
+        return std::find_if(mPorts.begin(), mPorts.end(),
+                [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+    }
+    // For connection w/o an address, two ports can be found: the template port,
+    // and a connected port (if exists). Make sure we return the connected port.
+    DeviceHalAidl::Ports::iterator portIt = mPorts.end();
+    for (auto it = mPorts.begin(); it != mPorts.end(); ++it) {
+        if (audioDeviceMatches(device, it->second)) {
+            if (mConnectedPorts.find(it->first) != mConnectedPorts.end()) {
+                return it;
+            } else {
+                // Will return 'it' if there is no connected port.
+                portIt = it;
+            }
+        }
+    }
+    return portIt;
 }
 
 DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
@@ -1765,7 +1784,8 @@
     std::set<int32_t> retryDeviceDisconnection;
     for (const auto& portConfigAndIdPair : portConfigIds) {
         resetPortConfig(portConfigAndIdPair.first);
-        if (mConnectedPortIdsHeldByStreams.count(portConfigAndIdPair.second) != 0) {
+        if (const auto it = mConnectedPorts.find(portConfigAndIdPair.second);
+                it != mConnectedPorts.end() && it->second) {
             retryDeviceDisconnection.insert(portConfigAndIdPair.second);
         }
     }
@@ -1774,7 +1794,7 @@
             TIME_CHECK();
             if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) {
                 mPorts.erase(portId);
-                mConnectedPortIdsHeldByStreams.erase(portId);
+                mConnectedPorts.erase(portId);
                 ALOGD("%s: executed postponed external device disconnection for port ID %d",
                         __func__, portId);
             }
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 329adba..da96d80 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -187,6 +187,8 @@
         Status status = Status::UNKNOWN;
         MicrophoneInfoProvider::Info info;
     };
+    // IDs of ports for connected external devices, and whether they are held by streams.
+    using ConnectedPorts = std::map<int32_t /*port ID*/, bool>;
     using Patches = std::map<int32_t /*patch ID*/,
             ::aidl::android::hardware::audio::core::AudioPatch>;
     using PortConfigs = std::map<int32_t /*port config ID*/,
@@ -313,7 +315,7 @@
     std::mutex mLock;
     std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
     std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
-    std::set<int32_t> mConnectedPortIdsHeldByStreams;
+    ConnectedPorts mConnectedPorts;
 };
 
 } // namespace android