From 85732f4121889191410448cfc19c336e0ea69285 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 19 Mar 2020 11:31:10 -0700 Subject: [PATCH] audio policy: fix mmap stream invalidation logic Implement a MMAP stream invalidation logic consistent with AAudio disconnect callback policy. - When a MMAP stream is opened with a preferred device selection: Invalidate the stream only when the preferred device becomes unavailable, either because disconnected or not selectable by highest priority use case. - When a MMAP stream is opened without explicit device selection: Invalidate the stream when current device selection changes due to the routing rules applicable to the stream's audio attributes (attributes of first client on that stream). Bug: 144020984 Test: OboeTester > TEST DISCONNECT Change-Id: I70fde0bc8ab9d544b8d3badb713e6239d792cbdb --- .../include/AudioIODescriptorInterface.h | 21 +++++++++++++++---- .../include/PolicyAudioPort.h | 9 ++++++++ .../managerdefault/AudioPolicyManager.cpp | 4 +--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h index 6e2963245c..1596ff77e7 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h @@ -41,11 +41,24 @@ sp findPreferredDevice( IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices) { auto activeClients = desc->clientsList(true /*activeOnly*/); - auto activeClientsWithRoute = - desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/); active = activeClients.size() > 0; - if (active && activeClients.size() == activeClientsWithRoute.size()) { - return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId()); + + if (active) { + // On MMAP IOs, the preferred device is selected by the first client (virtual client + // created when the mmap stream is opened). This client is never active. + // On non MMAP IOs, the preferred device is honored only if all active clients have + // a preferred device in which case the first client drives the selection. + if (desc->getPolicyAudioPort()->isMmap()) { + // The client list is never empty on a MMAP IO + return devices.getDeviceFromId( + desc->clientsList(false /*activeOnly*/)[0]->preferredDeviceId()); + } else { + auto activeClientsWithRoute = + desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/); + if (activeClients.size() == activeClientsWithRoute.size()) { + return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId()); + } + } } return nullptr; } diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h index 99df3c06cd..d2f629734a 100644 --- a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h +++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h @@ -107,6 +107,15 @@ public: (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)); } + inline bool isMmap() const + { + return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) + && (((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) && + ((mFlags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0)) + || ((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SINK) && + ((mFlags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0))); + } + void addRoute(const sp &route) { mRoutes.add(route); } const AudioRouteVector &getRoutes() const { return mRoutes; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index ffc3a0fd8b..3615669ce7 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -2406,9 +2406,7 @@ void AudioPolicyManager::checkCloseInputs() { for (size_t i = 0; i < mInputs.size(); i++) { const sp input = mInputs.valueAt(i); if (input->clientsList().size() == 0 - || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices()) - || (input->getPolicyAudioPort()->getFlags() - & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) { + || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) { inputsToClose.push_back(mInputs.keyAt(i)); } else { bool close = false;