aaudio: teardown stream based on a port handle
Needed for silencing specific input streams.
Pass AAudioService reference into AAudioServiceEndpointMMAP.
Use it to find a specific stream by PortHandle then
stop it and disconnect it.
Bug: 72134552
Test: b/72134552#comment10
Change-Id: Ibdf242f834c83b47c967c3cc634ed1083b019d4a
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index ab8f4ed..04fee13 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -150,7 +150,7 @@
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
- AAudioService &aaudioService __unused,
+ AAudioService &aaudioService,
const aaudio::AAudioStreamRequest &request) {
std::lock_guard<std::mutex> lock(mExclusiveLock);
@@ -166,13 +166,14 @@
// Already open so do not allow a second stream.
return nullptr;
} else {
- sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP();
+ sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService);
ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
endpointMMap.get(), configuration.getDeviceId());
endpoint = endpointMMap;
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
+ ALOGE("openExclusiveEndpoint(), open failed");
endpoint.clear();
} else {
mExclusiveStreams.push_back(endpointMMap);
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index ad5bb3a..5675b0b 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -288,11 +288,11 @@
aaudio_result_t result = AAUDIO_OK;
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("unregisterAudioThread(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("%s(), illegal stream handle = 0x%0x", __func__, streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
if (serviceStream->getRegisteredThread() != clientThreadId) {
- ALOGE("AAudioService::unregisterAudioThread(), wrong thread");
+ ALOGE("%s(), wrong thread", __func__);
result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
} else {
serviceStream->setRegisteredThread(0);
@@ -305,7 +305,7 @@
audio_port_handle_t *clientHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("startClient(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("%s(), illegal stream handle = 0x%0x", __func__, streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
aaudio_result_t result = serviceStream->startClient(client, clientHandle);
@@ -313,12 +313,28 @@
}
aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
- audio_port_handle_t clientHandle) {
+ audio_port_handle_t portHandle) {
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
- ALOGE("stopClient(), illegal stream handle = 0x%0x", streamHandle);
+ ALOGE("%s(), illegal stream handle = 0x%0x", __func__, streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
- aaudio_result_t result = serviceStream->stopClient(clientHandle);
+ aaudio_result_t result = serviceStream->stopClient(portHandle);
+ return checkForPendingClose(serviceStream, result);
+}
+
+// This is only called internally when AudioFlinger wants to tear down a stream.
+// So we do not have to check permissions.
+aaudio_result_t AAudioService::disconnectStreamByPortHandle(audio_port_handle_t portHandle) {
+ ALOGD("%s(%d) called", __func__, portHandle);
+ sp<AAudioServiceStreamBase> serviceStream =
+ mStreamTracker.findStreamByPortHandle(portHandle);
+ if (serviceStream.get() == nullptr) {
+ ALOGE("%s(), could not find stream with portHandle = %d", __func__, portHandle);
+ return AAUDIO_ERROR_INVALID_HANDLE;
+ }
+ serviceStream->incrementServiceReferenceCount();
+ aaudio_result_t result = serviceStream->stop();
+ serviceStream->disconnect();
return checkForPendingClose(serviceStream, result);
}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index bdd9e0b..d21b1cd 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -83,6 +83,8 @@
aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
audio_port_handle_t clientHandle) override;
+ aaudio_result_t disconnectStreamByPortHandle(audio_port_handle_t portHandle);
+
private:
/**
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 96e621a..0349034 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -78,6 +78,17 @@
return result.str();
}
+// @return true if stream found
+bool AAudioServiceEndpoint::isStreamRegistered(audio_port_handle_t portHandle) {
+ std::lock_guard<std::mutex> lock(mLockStreams);
+ for (const auto stream : mRegisteredStreams) {
+ if (stream->getPortHandle() == portHandle) {
+ return true;
+ }
+ }
+ return false;
+}
+
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
mConnected.store(false);
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 6312c51..6015b28 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -102,6 +102,13 @@
}
protected:
+
+ /**
+ * @param portHandle
+ * @return return true if a stream with the given portHandle is registered
+ */
+ bool isStreamRegistered(audio_port_handle_t portHandle);
+
void disconnectRegisteredStreams();
mutable std::mutex mLockStreams;
@@ -116,7 +123,6 @@
int32_t mRequestedDeviceId = 0;
std::atomic<bool> mConnected{true};
-
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 5f1de76..f9e21fb 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -48,8 +48,10 @@
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
-AAudioServiceEndpointMMAP::AAudioServiceEndpointMMAP()
- : mMmapStream(nullptr) {}
+
+AAudioServiceEndpointMMAP::AAudioServiceEndpointMMAP(AAudioService &audioService)
+ : mMmapStream(nullptr)
+ , mAAudioService(audioService) {}
AAudioServiceEndpointMMAP::~AAudioServiceEndpointMMAP() {}
@@ -277,14 +279,21 @@
}
aaudio_result_t AAudioServiceEndpointMMAP::startStream(sp<AAudioServiceStreamBase> stream,
- audio_port_handle_t *clientHandle) {
+ audio_port_handle_t *clientHandle __unused) {
// Start the client on behalf of the AAudio service.
// Use the port handle that was provided by openMmapStream().
- return startClient(mMmapClient, &mPortHandle);
+ audio_port_handle_t tempHandle = mPortHandle;
+ aaudio_result_t result = startClient(mMmapClient, &tempHandle);
+ // When AudioFlinger is passed a valid port handle then it should not change it.
+ LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
+ "%s() port handle not expected to change from %d to %d",
+ __func__, mPortHandle, tempHandle);
+ ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
+ return result;
}
aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
- audio_port_handle_t clientHandle) {
+ audio_port_handle_t clientHandle __unused) {
mFramesTransferred.reset32();
// Round 64-bit counter up to a multiple of the buffer capacity.
@@ -293,24 +302,27 @@
// when the stream is stopped.
mFramesTransferred.roundUp64(getBufferCapacity());
+ // Use the port handle that was provided by openMmapStream().
+ ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
return stopClient(mPortHandle);
}
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- ALOGV("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
+ ALOGD("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
audio_port_handle_t originalHandle = *clientHandle;
status_t status = mMmapStream->start(client, clientHandle);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- ALOGV("%s() , %d => %d returns %d", __func__, originalHandle, *clientHandle, result);
+ ALOGD("%s() , portHandle %d => %d, returns %d", __func__, originalHandle, *clientHandle, result);
return result;
}
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
+ ALOGD("%s(portHandle = %d), called", __func__, clientHandle);
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- ALOGV("%s(%d) returns %d", __func__, clientHandle, result);
+ ALOGD("%s(portHandle = %d), returns %d", __func__, clientHandle, result);
return result;
}
@@ -343,11 +355,19 @@
return 0; // TODO
}
-
-void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t handle __unused) {
- ALOGD("%s(%p) called", __func__, this);
- //TODO: disconnect only stream corresponding to handle received
- disconnectRegisteredStreams();
+// 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);
+ // Are we tearing down the EXCLUSIVE MMAP stream?
+ if (isStreamRegistered(portHandle)) {
+ ALOGD("%s(%d) tearing down this entire MMAP endpoint", __func__, portHandle);
+ disconnectRegisteredStreams();
+ } else {
+ // Must be a SHARED stream?
+ ALOGD("%s(%d) disconnect a specific stream", __func__, portHandle);
+ aaudio_result_t result = mAAudioService.disconnectStreamByPortHandle(portHandle);
+ ALOGD("%s(%d) disconnectStreamByPortHandle returned %d", __func__, portHandle, result);
+ }
};
void AAudioServiceEndpointMMAP::onVolumeChanged(audio_channel_mask_t channels,
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index c4c943d..5e815e0 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -42,7 +42,7 @@
, public android::MmapStreamCallback {
public:
- AAudioServiceEndpointMMAP();
+ explicit AAudioServiceEndpointMMAP(android::AAudioService &audioService);
virtual ~AAudioServiceEndpointMMAP();
@@ -88,8 +88,12 @@
// Interface to the AudioFlinger MMAP support.
android::sp<android::MmapStreamInterface> mMmapStream;
struct audio_mmap_buffer_info mMmapBufferinfo;
+
+ // There is only one port associated with an MMAP endpoint.
audio_port_handle_t mPortHandle = AUDIO_PORT_HANDLE_NONE;
+ android::AAudioService &mAAudioService;
+
android::base::unique_fd mAudioDataFileDescriptor;
int64_t mHardwareTimeOffsetNanos = 0; // TODO get from HAL
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 227250c..d671710 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -30,7 +30,7 @@
namespace aaudio {
/**
- * This manages an internal stream that is shared by multiple Client streams.
+ * This manages an AudioStreamInternal that is shared by multiple Client streams.
*/
class AAudioServiceEndpointShared : public AAudioServiceEndpoint {
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 18f14ee..c943008 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -61,7 +61,7 @@
}
std::string AAudioServiceStreamBase::dumpHeader() {
- return std::string(" T Handle UId Run State Format Burst Chan Capacity");
+ return std::string(" T Handle UId Port Run State Format Burst Chan Capacity");
}
std::string AAudioServiceStreamBase::dump() const {
@@ -70,6 +70,7 @@
result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << mHandle
<< std::dec << std::setfill(' ') ;
result << std::setw(6) << mMmapClient.clientUid;
+ result << std::setw(7) << mClientHandle;
result << std::setw(4) << (isRunning() ? "yes" : " no");
result << std::setw(6) << getState();
result << std::setw(7) << getFormat();
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 3720596..d8102be 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -180,6 +180,10 @@
mHandle = handle;
}
+ audio_port_handle_t getPortHandle() const {
+ return mClientHandle;
+ }
+
aaudio_stream_state_t getState() const {
return mState;
}
@@ -269,6 +273,7 @@
int32_t mFramesPerBurst = 0;
android::AudioClient mMmapClient; // set in open, used in MMAP start()
+ // TODO rename mClientHandle to mPortHandle to be more consistent with AudioFlinger.
audio_port_handle_t mClientHandle = AUDIO_PORT_HANDLE_NONE;
SimpleDoubleBuffer<Timestamp> mAtomicTimestamp;
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
index ef88b34..9d5d8fc 100644
--- a/services/oboeservice/AAudioStreamTracker.cpp
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -53,6 +53,26 @@
return serviceStream;
}
+
+// The port handle is only available when the stream is started.
+// So we have to iterate over all the streams.
+// Luckily this rarely happens.
+sp<AAudioServiceStreamBase> AAudioStreamTracker::findStreamByPortHandle(
+ audio_port_handle_t portHandle) {
+ std::lock_guard<std::mutex> lock(mHandleLock);
+ sp<AAudioServiceStreamBase> serviceStream;
+ auto it = mStreamsByHandle.begin();
+ while (it != mStreamsByHandle.end()) {
+ auto candidate = it->second;
+ if (candidate->getPortHandle() == portHandle) {
+ serviceStream = candidate;
+ break;
+ }
+ it++;
+ }
+ return serviceStream;
+}
+
// advance to next legal handle value
__attribute__((no_sanitize("integer")))
aaudio_handle_t AAudioStreamTracker::bumpHandle(aaudio_handle_t handle) {
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index 70d440d..54e46ca 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -46,6 +46,14 @@
android::sp<aaudio::AAudioServiceStreamBase> getStreamByHandle(aaudio_handle_t streamHandle);
/**
+ * Look up a stream based on the AudioPolicy portHandle.
+ * @param portHandle
+ * @return strong pointer to the stream if found or to nullptr
+ */
+ android::sp<aaudio::AAudioServiceStreamBase> findStreamByPortHandle(
+ audio_port_handle_t portHandle);
+
+ /**
* Store a strong pointer to the stream and return a unique handle for future reference.
* The handle is guaranteed not to collide with an existing stream.
* @param serviceStream