aaudio: process callbacks asynchronously
Spawn a thread to handle the disconnects for onRoutingChanged()
and onTearDown(). This is to prevent deadlocks when calling back into
AudioFlinger.
Bug: 155819038
Test: See bug for repro steps with OboeTester
Test: Also run TEST DISCONNECT in OboeTester. It was failing.
Test: atest CtsNativeMediaAAudioTestCases
Change-Id: I83212fea140d3b6beca9aa737606a77a7c97b007
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 9dab770..0843e0b 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -23,10 +23,10 @@
#include <map>
#include <mutex>
#include <sstream>
+#include <thread>
#include <utils/Singleton.h>
#include <vector>
-
#include "AAudioEndpointManager.h"
#include "AAudioServiceEndpoint.h"
@@ -36,7 +36,6 @@
#include "AAudioServiceEndpointPlay.h"
#include "AAudioServiceEndpointMMAP.h"
-
#define AAUDIO_BUFFER_CAPACITY_MIN 4 * 512
#define AAUDIO_SAMPLE_RATE_DEFAULT 48000
@@ -48,7 +47,6 @@
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
-
AAudioServiceEndpointMMAP::AAudioServiceEndpointMMAP(AAudioService &audioService)
: mMmapStream(nullptr)
, mAAudioService(audioService) {}
@@ -318,9 +316,8 @@
return 0; // TODO
}
-// This is called by AudioFlinger when it wants to destroy a stream.
-void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t portHandle) {
- ALOGD("%s(portHandle = %d) called", __func__, portHandle);
+// This is called by onTearDown() in a separate thread to avoid deadlocks.
+void AAudioServiceEndpointMMAP::handleTearDownAsync(audio_port_handle_t portHandle) {
// Are we tearing down the EXCLUSIVE MMAP stream?
if (isStreamRegistered(portHandle)) {
ALOGD("%s(%d) tearing down this entire MMAP endpoint", __func__, portHandle);
@@ -333,6 +330,13 @@
}
};
+// This is called by AudioFlinger when it wants to destroy a stream.
+void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t portHandle) {
+ ALOGD("%s(portHandle = %d) called", __func__, portHandle);
+ std::thread asyncTask(&AAudioServiceEndpointMMAP::handleTearDownAsync, this, portHandle);
+ asyncTask.detach();
+}
+
void AAudioServiceEndpointMMAP::onVolumeChanged(audio_channel_mask_t channels,
android::Vector<float> values) {
// TODO Do we really need a different volume for each channel?
@@ -345,12 +349,20 @@
}
};
-void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
+void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t portHandle) {
+ const int32_t deviceId = static_cast<int32_t>(portHandle);
ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
- if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
- disconnectRegisteredStreams();
+ if (getDeviceId() != deviceId) {
+ if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
+ std::thread asyncTask([this, deviceId]() {
+ disconnectRegisteredStreams();
+ setDeviceId(deviceId);
+ });
+ asyncTask.detach();
+ } else {
+ setDeviceId(deviceId);
+ }
}
- setDeviceId(deviceId);
};
/**