aaudio: fix EXCLUSIVE mode interfering with SHARED
The MMAP endpoints were not tracked by the EndpointManager
so it could not broker EXCLUSIVE access. To fix this the MMAP stream
was refactored to use a per-client stream and a per-device endpoint.
Cleanup close() of MMAP stream.
Add AAudioServiceEndpointShared.cpp.
Extract AAudioServiceEndpointMMAP from AAudioServiceStreamMMAP.
Track MMAP endpoints so we can manage EXCLUSIVE and SHARED access.
Bug: 64494572
Bug: 64310586
Test: see bug, use write_sine to play a shared stream and a excl stream
Change-Id: I5053193abfd9b8a69a2f7e1110739d65e2af5d64
Merged-In: I5053193abfd9b8a69a2f7e1110739d65e2af5d64
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 81f1d1b..cba5bc8 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -33,17 +33,14 @@
#include "core/AudioStreamBuilder.h"
#include "AAudioServiceEndpoint.h"
#include "AAudioServiceStreamShared.h"
+#include "AAudioServiceEndpointShared.h"
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
-#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND)
-
-// Wait at least this many times longer than the operation should take.
-#define MIN_TIMEOUT_OPERATIONS 4
-
-// This is the maximum size in frames. The effective size can be tuned smaller at runtime.
-#define DEFAULT_BUFFER_CAPACITY (48 * 8)
+AAudioServiceEndpoint::~AAudioServiceEndpoint() {
+ ALOGD("AAudioServiceEndpoint::~AAudioServiceEndpoint() destroying endpoint %p", this);
+}
std::string AAudioServiceEndpoint::dump() const {
std::stringstream result;
@@ -53,20 +50,20 @@
50 /* times */,
20 /* sleepMs */);
if (!isLocked) {
- result << "EndpointManager may be deadlocked\n";
+ result << "AAudioServiceEndpoint may be deadlocked\n";
}
- AudioStreamInternal *stream = mStreamInternal;
- if (stream == nullptr) {
- result << "null stream!" << "\n";
- } else {
- result << "mmap stream: rate = " << stream->getSampleRate() << "\n";
- }
-
- result << " Registered Streams:" << "\n";
+ result << " Direction: " << ((getDirection() == AAUDIO_DIRECTION_OUTPUT)
+ ? "OUTPUT" : "INPUT") << "\n";
+ result << " Sample Rate: " << getSampleRate() << "\n";
+ result << " Frames Per Burst: " << mFramesPerBurst << "\n";
+ result << " Reference Count: " << mOpenCount << "\n";
+ result << " Requested Device Id: " << mRequestedDeviceId << "\n";
+ result << " Device Id: " << getDeviceId() << "\n";
+ result << " Registered Streams: " << "\n";
result << AAudioServiceStreamShared::dumpHeader() << "\n";
- for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
- result << sharedStream->dump() << "\n";
+ for (const auto stream : mRegisteredStreams) {
+ result << stream->dump() << "\n";
}
if (isLocked) {
@@ -75,113 +72,44 @@
return result.str();
}
-// Set up an EXCLUSIVE MMAP stream that will be shared.
-aaudio_result_t AAudioServiceEndpoint::open(const AAudioStreamConfiguration& configuration) {
- mRequestedDeviceId = configuration.getDeviceId();
- mStreamInternal = getStreamInternal();
-
- AudioStreamBuilder builder;
- builder.setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
- // Don't fall back to SHARED because that would cause recursion.
- builder.setSharingModeMatchRequired(true);
- builder.setDeviceId(mRequestedDeviceId);
- builder.setFormat(configuration.getFormat());
- builder.setSampleRate(configuration.getSampleRate());
- builder.setSamplesPerFrame(configuration.getSamplesPerFrame());
- builder.setDirection(getDirection());
- builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
-
- return getStreamInternal()->open(builder);
-}
-
-aaudio_result_t AAudioServiceEndpoint::close() {
- return getStreamInternal()->close();
-}
-
-// TODO, maybe use an interface to reduce exposure
-aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamShared>sharedStream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
- mRegisteredStreams.push_back(sharedStream);
- return AAUDIO_OK;
-}
-
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamShared>sharedStream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
- mRegisteredStreams.erase(std::remove(mRegisteredStreams.begin(), mRegisteredStreams.end(), sharedStream),
- mRegisteredStreams.end());
- return AAUDIO_OK;
-}
-
-aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
- aaudio_result_t result = AAUDIO_OK;
- if (++mRunningStreams == 1) {
- // TODO use real-time technique to avoid mutex, eg. atomic command FIFO
- std::lock_guard<std::mutex> lock(mLockStreams);
- result = getStreamInternal()->requestStart();
- startSharingThread_l();
- }
- return result;
-}
-
-aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
- // Don't lock here because the disconnectRegisteredStreams also uses the lock.
- if (--mRunningStreams == 0) { // atomic
- stopSharingThread();
- getStreamInternal()->requestStop();
- }
- return AAUDIO_OK;
-}
-
-static void *aaudio_endpoint_thread_proc(void *context) {
- AAudioServiceEndpoint *endpoint = (AAudioServiceEndpoint *) context;
- if (endpoint != NULL) {
- return endpoint->callbackLoop();
- } else {
- return NULL;
- }
-}
-
-aaudio_result_t AAudioServiceEndpoint::startSharingThread_l() {
- // Launch the callback loop thread.
- int64_t periodNanos = getStreamInternal()->getFramesPerBurst()
- * AAUDIO_NANOS_PER_SECOND
- / getSampleRate();
- mCallbackEnabled.store(true);
- return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
-}
-
-aaudio_result_t AAudioServiceEndpoint::stopSharingThread() {
- mCallbackEnabled.store(false);
- aaudio_result_t result = getStreamInternal()->joinThread(NULL);
- return result;
-}
-
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
- for(auto sharedStream : mRegisteredStreams) {
- sharedStream->stop();
- sharedStream->disconnect();
+ for (const auto stream : mRegisteredStreams) {
+ stream->stop();
+ stream->disconnect();
}
mRegisteredStreams.clear();
}
+aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamBase>stream) {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ mRegisteredStreams.push_back(stream);
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamBase>stream) {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ mRegisteredStreams.erase(std::remove(
+ mRegisteredStreams.begin(), mRegisteredStreams.end(), stream),
+ mRegisteredStreams.end());
+ return AAUDIO_OK;
+}
+
bool AAudioServiceEndpoint::matches(const AAudioStreamConfiguration& configuration) {
+ if (configuration.getDirection() != getDirection()) {
+ return false;
+ }
if (configuration.getDeviceId() != AAUDIO_UNSPECIFIED &&
- configuration.getDeviceId() != mStreamInternal->getDeviceId()) {
+ configuration.getDeviceId() != getDeviceId()) {
return false;
}
if (configuration.getSampleRate() != AAUDIO_UNSPECIFIED &&
- configuration.getSampleRate() != mStreamInternal->getSampleRate()) {
+ configuration.getSampleRate() != getSampleRate()) {
return false;
}
if (configuration.getSamplesPerFrame() != AAUDIO_UNSPECIFIED &&
- configuration.getSamplesPerFrame() != mStreamInternal->getSamplesPerFrame()) {
+ configuration.getSamplesPerFrame() != getSamplesPerFrame()) {
return false;
}
return true;
}
-
-
-aaudio_result_t AAudioServiceEndpoint::getTimestamp(int64_t *positionFrames, int64_t *timeNanos) {
- return mStreamInternal->getTimestamp(CLOCK_MONOTONIC, positionFrames, timeNanos);
-}