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
gugelfrei
Phil Burk 6 years ago
parent f255369091
commit bbd5286e99

@ -392,19 +392,25 @@ aaudio_result_t AudioStreamInternal::unregisterThread() {
}
aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
audio_port_handle_t *portHandle) {
ALOGV("%s() called", __func__);
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle);
aaudio_result_t result = mServiceInterface.startClient(mServiceStreamHandle,
client, portHandle);
ALOGV("%s(%d) returning %d", __func__, *portHandle, result);
return result;
}
aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t clientHandle) {
aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t portHandle) {
ALOGV("%s(%d) called", __func__, portHandle);
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.stopClient(mServiceStreamHandle, clientHandle);
aaudio_result_t result = mServiceInterface.stopClient(mServiceStreamHandle, portHandle);
ALOGV("%s(%d) returning %d", __func__, portHandle, result);
return result;
}
aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,

@ -150,7 +150,7 @@ sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &aud
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
AAudioService &aaudioService __unused,
AAudioService &aaudioService,
const aaudio::AAudioStreamRequest &request) {
std::lock_guard<std::mutex> lock(mExclusiveLock);
@ -166,13 +166,14 @@ sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
// 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);

@ -288,11 +288,11 @@ aaudio_result_t AAudioService::unregisterAudioThread(aaudio_handle_t streamHandl
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 @@ aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
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::startClient(aaudio_handle_t streamHandle,
}
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);
}

@ -83,6 +83,8 @@ public:
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:
/**

@ -78,6 +78,17 @@ std::string AAudioServiceEndpoint::dump() const {
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);

@ -102,6 +102,13 @@ public:
}
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 @@ protected:
int32_t mRequestedDeviceId = 0;
std::atomic<bool> mConnected{true};
};
} /* namespace aaudio */

@ -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::close() {
}
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 @@ aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase
// 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 @@ aaudio_result_t AAudioServiceEndpointMMAP::getTimestamp(int64_t *positionFrames,
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,

@ -42,7 +42,7 @@ class AAudioServiceEndpointMMAP
, public android::MmapStreamCallback {
public:
AAudioServiceEndpointMMAP();
explicit AAudioServiceEndpointMMAP(android::AAudioService &audioService);
virtual ~AAudioServiceEndpointMMAP();
@ -88,8 +88,12 @@ private:
// 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

@ -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 {

@ -61,7 +61,7 @@ AAudioServiceStreamBase::~AAudioServiceStreamBase() {
}
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 @@ std::string AAudioServiceStreamBase::dump() const {
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();

@ -180,6 +180,10 @@ public:
mHandle = handle;
}
audio_port_handle_t getPortHandle() const {
return mClientHandle;
}
aaudio_stream_state_t getState() const {
return mState;
}
@ -269,6 +273,7 @@ protected:
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;

@ -53,6 +53,26 @@ sp<AAudioServiceStreamBase> AAudioStreamTracker::getStreamByHandle(
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) {

@ -45,6 +45,14 @@ public:
*/
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.

Loading…
Cancel
Save