Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7ff88aa authored by jiabin's avatar jiabin
Browse files

Release all connected streams when routing device is changed.

When there is a routing change, the existing mmap endpoint is
invalidated and can no longer be used. In that case, release all
registered streams and set the endpoint as disconnected so that it won't
be reused by another new request. That also releases the resources from
the service side so that it won't be harmful if the clients don't close
the stream when receiving disconnect event.

Bug: 299360979
Test: atest AAudioTests
Test: test_idle_disconnected_shared_stream
Change-Id: I4d7c68d5c0d15b75cc2f07471f50bfedb6292da9
parent 49bff7d0
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -295,8 +295,10 @@ void *AudioStreamInternalCapture::callbackLoop() {
        if ((result != mCallbackFrames)) {
            ALOGE("callbackLoop: read() returned %d", result);
            if (result >= 0) {
                // Only read some of the frames requested. Must have timed out.
                result = AAUDIO_ERROR_TIMEOUT;
                // Only read some of the frames requested. The stream can be disconnected
                // or timed out.
                processCommands();
                result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
            }
            maybeCallErrorCallback(result);
            break;
+4 −2
Original line number Diff line number Diff line
@@ -353,8 +353,10 @@ void *AudioStreamInternalPlay::callbackLoop() {
            result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
            if ((result != mCallbackFrames)) {
                if (result >= 0) {
                    // Only wrote some of the frames requested. Must have timed out.
                    result = AAUDIO_ERROR_TIMEOUT;
                    // Only wrote some of the frames requested. The stream can be disconnected
                    // or timed out.
                    processCommands();
                    result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
                }
                maybeCallErrorCallback(result);
                break;
+8 −1
Original line number Diff line number Diff line
@@ -421,10 +421,17 @@ void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t portHandle)
    ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
    if (getDeviceId() != deviceId) {
        if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
            // When there is a routing changed, mmap stream should be disconnected. Set `mConnected`
            // as false here so that there won't be a new stream connect to this endpoint.
            mConnected.store(false);
            const android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
            std::thread asyncTask([holdEndpoint, deviceId]() {
                ALOGD("onRoutingChanged() asyncTask launched");
                holdEndpoint->disconnectRegisteredStreams();
                // When routing changed, the stream is disconnected and cannot be used except for
                // closing. In that case, it should be safe to release all registered streams.
                // This can help release service side resource in case the client doesn't close
                // the stream after receiving disconnect event.
                holdEndpoint->releaseRegisteredStreams();
                holdEndpoint->setDeviceId(deviceId);
            });
            asyncTask.detach();
+6 −2
Original line number Diff line number Diff line
@@ -219,9 +219,13 @@ aaudio_result_t AAudioServiceEndpointShared::getTimestamp(int64_t *positionFrame

void AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync() {
    android::sp<AAudioServiceEndpointShared> holdEndpoint(this);
    // When there is a routing changed, mmap stream should be disconnected. Set `mConnected`
    // as false here so that there won't be a new stream connect to this endpoint.
    mConnected.store(false);
    std::thread asyncTask([holdEndpoint]() {
        // We do not need the returned vector.
        holdEndpoint->disconnectRegisteredStreams();
        // When handling disconnection, the service side has disconnected. In that case,
        // it should be safe to release all registered streams.
        holdEndpoint->releaseRegisteredStreams();
    });
    asyncTask.detach();
}