Loading media/libaaudio/src/client/AudioStreamInternal.cpp +19 −10 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterfa } AudioStreamInternal::~AudioStreamInternal() { ALOGD("%s() %p called", __func__, this); } aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { Loading Loading @@ -270,21 +271,21 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { return result; error: releaseCloseFinal(); safeReleaseClose(); return result; } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::release_l() { aaudio_result_t result = AAUDIO_OK; ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle); ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle); if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) { aaudio_stream_state_t currentState = getState(); // Don't release a stream while it is running. Stop it first. // If DISCONNECTED then we should still try to stop in case the // error callback is still running. if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) { requestStop(); requestStop_l(); } logReleaseBufferState(); Loading Loading @@ -330,7 +331,7 @@ static void *aaudio_callback_thread_proc(void *context) * The processing code will then save the current offset * between client and server and apply that to any position given to the app. */ aaudio_result_t AudioStreamInternal::requestStart() aaudio_result_t AudioStreamInternal::requestStart_l() { int64_t startTime; if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { Loading Loading @@ -373,7 +374,7 @@ aaudio_result_t AudioStreamInternal::requestStart() * AAUDIO_NANOS_PER_SECOND / getSampleRate(); mCallbackEnabled.store(true); result = createThread(periodNanos, aaudio_callback_thread_proc, this); result = createThread_l(periodNanos, aaudio_callback_thread_proc, this); } if (result != AAUDIO_OK) { setState(originalState); Loading @@ -399,26 +400,29 @@ int64_t AudioStreamInternal::calculateReasonableTimeout() { } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::stopCallback() aaudio_result_t AudioStreamInternal::stopCallback_l() { if (isDataCallbackSet() && (isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) { mCallbackEnabled.store(false); aaudio_result_t result = joinThread(NULL); // may temporarily unlock mStreamLock aaudio_result_t result = joinThread_l(NULL); // may temporarily unlock mStreamLock if (result == AAUDIO_ERROR_INVALID_HANDLE) { ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__); result = AAUDIO_OK; } return result; } else { ALOGD("%s() skipped, isDataCallbackSet() = %d, isActive() = %d, getState() = %d", __func__, isDataCallbackSet(), isActive(), getState()); return AAUDIO_OK; } } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::requestStop() { aaudio_result_t result = stopCallback(); aaudio_result_t AudioStreamInternal::requestStop_l() { aaudio_result_t result = stopCallback_l(); if (result != AAUDIO_OK) { ALOGW("%s() stop callback returned %d, returning early", __func__, result); return result; } // The stream may have been unlocked temporarily to let a callback finish Loading @@ -426,6 +430,7 @@ aaudio_result_t AudioStreamInternal::requestStop() { // Check to make sure the stream still needs to be stopped. // See also AudioStream::safeStop(). if (!(isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) { ALOGD("%s() returning early, not active or disconnected", __func__); return AAUDIO_OK; } Loading Loading @@ -805,11 +810,15 @@ int32_t AudioStreamInternal::getBufferCapacity() const { return mBufferCapacityInFrames; } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) { return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst())); } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::joinThread_l(void** returnArg) { return AudioStream::joinThread_l(returnArg, calculateReasonableTimeout(getFramesPerBurst())); } bool AudioStreamInternal::isClockModelInControl() const { return isActive() && mAudioEndpoint->isFreeRunning() && mClockModel.isRunning(); } media/libaaudio/src/client/AudioStreamInternal.h +5 −3 Original line number Diff line number Diff line Loading @@ -44,9 +44,9 @@ public: AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService); virtual ~AudioStreamInternal(); aaudio_result_t requestStart() override; aaudio_result_t requestStart_l() override; aaudio_result_t requestStop() override; aaudio_result_t requestStop_l() override; aaudio_result_t getTimestamp(clockid_t clockId, int64_t *framePosition, Loading Loading @@ -117,7 +117,9 @@ protected: aaudio_result_t processCommands(); aaudio_result_t stopCallback(); aaudio_result_t stopCallback_l(); aaudio_result_t joinThread_l(void** returnArg); virtual void prepareBuffersForStart() {} Loading media/libaaudio/src/client/AudioStreamInternalPlay.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) getDeviceChannelCount()); if (result != AAUDIO_OK) { releaseCloseFinal(); safeReleaseClose(); } // Sample rate is constrained to common values by now and should not overflow. int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND; Loading @@ -66,9 +66,9 @@ aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternalPlay::requestPause() aaudio_result_t AudioStreamInternalPlay::requestPause_l() { aaudio_result_t result = stopCallback(); aaudio_result_t result = stopCallback_l(); if (result != AAUDIO_OK) { return result; } Loading @@ -83,7 +83,7 @@ aaudio_result_t AudioStreamInternalPlay::requestPause() return mServiceInterface.pauseStream(mServiceStreamHandle); } aaudio_result_t AudioStreamInternalPlay::requestFlush() { aaudio_result_t AudioStreamInternalPlay::requestFlush_l() { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { ALOGW("%s() mServiceStreamHandle invalid", __func__); return AAUDIO_ERROR_INVALID_STATE; Loading media/libaaudio/src/client/AudioStreamInternalPlay.h +2 −2 Original line number Diff line number Diff line Loading @@ -35,9 +35,9 @@ public: aaudio_result_t open(const AudioStreamBuilder &builder) override; aaudio_result_t requestPause() override; aaudio_result_t requestPause_l() override; aaudio_result_t requestFlush() override; aaudio_result_t requestFlush_l() override; bool isFlushSupported() const override { // Only implement FLUSH for OUTPUT streams. Loading media/libaaudio/src/core/AudioStream.cpp +52 −22 Original line number Diff line number Diff line Loading @@ -42,16 +42,20 @@ AudioStream::AudioStream() : mPlayerBase(new MyPlayerBase()) , mStreamId(AAudio_getNextStreamId()) { // mThread is a pthread_t of unknown size so we need memset. memset(&mThread, 0, sizeof(mThread)); setPeriodNanoseconds(0); } AudioStream::~AudioStream() { // Please preserve this log because there have been several bugs related to // Please preserve these logs because there have been several bugs related to // AudioStream deletion and late callbacks. ALOGD("%s(s#%u) mPlayerBase strongCount = %d", __func__, getId(), mPlayerBase->getStrongCount()); ALOGE_IF(pthread_equal(pthread_self(), mThread), "%s() destructor running in callback", __func__); ALOGE_IF(mHasThread, "%s() callback thread never join()ed", __func__); // If the stream is deleted when OPEN or in use then audio resources will leak. // This would indicate an internal error. So we want to find this ASAP. LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED Loading Loading @@ -164,7 +168,7 @@ aaudio_result_t AudioStream::systemStart() { return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = requestStart(); aaudio_result_t result = requestStart_l(); if (result == AAUDIO_OK) { // We only call this for logging in "dumpsys audio". So ignore return code. (void) mPlayerBase->start(); Loading Loading @@ -214,7 +218,7 @@ aaudio_result_t AudioStream::systemPause() { return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = requestPause(); aaudio_result_t result = requestPause_l(); if (result == AAUDIO_OK) { // We only call this for logging in "dumpsys audio". So ignore return code. (void) mPlayerBase->pause(); Loading @@ -239,7 +243,7 @@ aaudio_result_t AudioStream::safeFlush() { return result; } return requestFlush(); return requestFlush_l(); } aaudio_result_t AudioStream::systemStopFromCallback() { Loading Loading @@ -299,11 +303,11 @@ aaudio_result_t AudioStream::safeStop() { return AAUDIO_ERROR_INVALID_STATE; } return requestStop(); return requestStop_l(); } aaudio_result_t AudioStream::safeRelease() { // This get temporarily unlocked in the MMAP release() when joining callback threads. // This may get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); Loading @@ -322,7 +326,14 @@ aaudio_result_t AudioStream::safeReleaseClose() { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } releaseCloseFinal(); releaseCloseFinal_l(); return AAUDIO_OK; } aaudio_result_t AudioStream::safeReleaseCloseFromCallback() { // This get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); releaseCloseFinal_l(); return AAUDIO_OK; } Loading Loading @@ -403,23 +414,28 @@ void* AudioStream::wrapUserThread() { return procResult; } // This is the entry point for the new thread created by createThread(). // This is the entry point for the new thread created by createThread_l(). // It converts the 'C' function call to a C++ method call. static void* AudioStream_internalThreadProc(void* threadArg) { AudioStream *audioStream = (AudioStream *) threadArg; // Use an sp<> to prevent the stream from being deleted while running. // Prevent the stream from being deleted while being used. // This is just for extra safety. It is probably not needed because // this callback should be joined before the stream is closed. android::sp<AudioStream> protectedStream(audioStream); // Balance the incStrong() in createThread_l(). protectedStream->decStrong(nullptr); return protectedStream->wrapUserThread(); } // This is not exposed in the API. // But it is still used internally to implement callbacks for MMAP mode. aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, aaudio_result_t AudioStream::createThread_l(int64_t periodNanoseconds, aaudio_audio_thread_proc_t threadProc, void* threadArg) { if (mHasThread) { ALOGE("createThread() - mHasThread already true"); ALOGE("%s() - mHasThread already true", __func__); return AAUDIO_ERROR_INVALID_STATE; } if (threadProc == nullptr) { Loading @@ -429,10 +445,14 @@ aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, mThreadProc = threadProc; mThreadArg = threadArg; setPeriodNanoseconds(periodNanoseconds); // Prevent this object from getting deleted before the thread has a chance to create // its strong pointer. Assume the thread will call decStrong(). this->incStrong(nullptr); int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this); if (err != 0) { android::status_t status = -errno; ALOGE("createThread() - pthread_create() failed, %d", status); ALOGE("%s() - pthread_create() failed, %d", __func__, status); this->decStrong(nullptr); // Because the thread won't do it. return AAudioConvert_androidToAAudioResult(status); } else { // TODO Use AAudioThread or maybe AndroidThread Loading @@ -452,17 +472,23 @@ aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, } } aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) { // This may get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); return joinThread_l(returnArg, timeoutNanoseconds); } // This must be called under mStreamLock. aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds __unused) aaudio_result_t AudioStream::joinThread_l(void** returnArg, int64_t /* timeoutNanoseconds */) { if (!mHasThread) { ALOGE("joinThread() - but has no thread"); ALOGD("joinThread() - but has no thread"); return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = AAUDIO_OK; // If the callback is stopping the stream because the app passed back STOP // then we don't need to join(). The thread is already about to exit. if (pthread_self() != mThread) { if (!pthread_equal(pthread_self(), mThread)) { // Called from an app thread. Not the callback. // Unlock because the callback may be trying to stop the stream but is blocked. mStreamLock.unlock(); Loading @@ -477,11 +503,15 @@ aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanosec if (err) { ALOGE("%s() pthread_join() returns err = %d", __func__, err); result = AAudioConvert_androidToAAudioResult(-err); } } } else { ALOGD("%s() pthread_join succeeded", __func__); // This must be set false so that the callback thread can be created // when the stream is restarted. mHasThread = false; } } else { ALOGD("%s() pthread_join() called on itself!", __func__); } return (result != AAUDIO_OK) ? result : mThreadRegistrationResult; } Loading Loading
media/libaaudio/src/client/AudioStreamInternal.cpp +19 −10 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterfa } AudioStreamInternal::~AudioStreamInternal() { ALOGD("%s() %p called", __func__, this); } aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { Loading Loading @@ -270,21 +271,21 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { return result; error: releaseCloseFinal(); safeReleaseClose(); return result; } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::release_l() { aaudio_result_t result = AAUDIO_OK; ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle); ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle); if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) { aaudio_stream_state_t currentState = getState(); // Don't release a stream while it is running. Stop it first. // If DISCONNECTED then we should still try to stop in case the // error callback is still running. if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) { requestStop(); requestStop_l(); } logReleaseBufferState(); Loading Loading @@ -330,7 +331,7 @@ static void *aaudio_callback_thread_proc(void *context) * The processing code will then save the current offset * between client and server and apply that to any position given to the app. */ aaudio_result_t AudioStreamInternal::requestStart() aaudio_result_t AudioStreamInternal::requestStart_l() { int64_t startTime; if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { Loading Loading @@ -373,7 +374,7 @@ aaudio_result_t AudioStreamInternal::requestStart() * AAUDIO_NANOS_PER_SECOND / getSampleRate(); mCallbackEnabled.store(true); result = createThread(periodNanos, aaudio_callback_thread_proc, this); result = createThread_l(periodNanos, aaudio_callback_thread_proc, this); } if (result != AAUDIO_OK) { setState(originalState); Loading @@ -399,26 +400,29 @@ int64_t AudioStreamInternal::calculateReasonableTimeout() { } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::stopCallback() aaudio_result_t AudioStreamInternal::stopCallback_l() { if (isDataCallbackSet() && (isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) { mCallbackEnabled.store(false); aaudio_result_t result = joinThread(NULL); // may temporarily unlock mStreamLock aaudio_result_t result = joinThread_l(NULL); // may temporarily unlock mStreamLock if (result == AAUDIO_ERROR_INVALID_HANDLE) { ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__); result = AAUDIO_OK; } return result; } else { ALOGD("%s() skipped, isDataCallbackSet() = %d, isActive() = %d, getState() = %d", __func__, isDataCallbackSet(), isActive(), getState()); return AAUDIO_OK; } } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::requestStop() { aaudio_result_t result = stopCallback(); aaudio_result_t AudioStreamInternal::requestStop_l() { aaudio_result_t result = stopCallback_l(); if (result != AAUDIO_OK) { ALOGW("%s() stop callback returned %d, returning early", __func__, result); return result; } // The stream may have been unlocked temporarily to let a callback finish Loading @@ -426,6 +430,7 @@ aaudio_result_t AudioStreamInternal::requestStop() { // Check to make sure the stream still needs to be stopped. // See also AudioStream::safeStop(). if (!(isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) { ALOGD("%s() returning early, not active or disconnected", __func__); return AAUDIO_OK; } Loading Loading @@ -805,11 +810,15 @@ int32_t AudioStreamInternal::getBufferCapacity() const { return mBufferCapacityInFrames; } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) { return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst())); } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternal::joinThread_l(void** returnArg) { return AudioStream::joinThread_l(returnArg, calculateReasonableTimeout(getFramesPerBurst())); } bool AudioStreamInternal::isClockModelInControl() const { return isActive() && mAudioEndpoint->isFreeRunning() && mClockModel.isRunning(); }
media/libaaudio/src/client/AudioStreamInternal.h +5 −3 Original line number Diff line number Diff line Loading @@ -44,9 +44,9 @@ public: AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService); virtual ~AudioStreamInternal(); aaudio_result_t requestStart() override; aaudio_result_t requestStart_l() override; aaudio_result_t requestStop() override; aaudio_result_t requestStop_l() override; aaudio_result_t getTimestamp(clockid_t clockId, int64_t *framePosition, Loading Loading @@ -117,7 +117,9 @@ protected: aaudio_result_t processCommands(); aaudio_result_t stopCallback(); aaudio_result_t stopCallback_l(); aaudio_result_t joinThread_l(void** returnArg); virtual void prepareBuffersForStart() {} Loading
media/libaaudio/src/client/AudioStreamInternalPlay.cpp +4 −4 Original line number Diff line number Diff line Loading @@ -56,7 +56,7 @@ aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) getDeviceChannelCount()); if (result != AAUDIO_OK) { releaseCloseFinal(); safeReleaseClose(); } // Sample rate is constrained to common values by now and should not overflow. int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND; Loading @@ -66,9 +66,9 @@ aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) } // This must be called under mStreamLock. aaudio_result_t AudioStreamInternalPlay::requestPause() aaudio_result_t AudioStreamInternalPlay::requestPause_l() { aaudio_result_t result = stopCallback(); aaudio_result_t result = stopCallback_l(); if (result != AAUDIO_OK) { return result; } Loading @@ -83,7 +83,7 @@ aaudio_result_t AudioStreamInternalPlay::requestPause() return mServiceInterface.pauseStream(mServiceStreamHandle); } aaudio_result_t AudioStreamInternalPlay::requestFlush() { aaudio_result_t AudioStreamInternalPlay::requestFlush_l() { if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { ALOGW("%s() mServiceStreamHandle invalid", __func__); return AAUDIO_ERROR_INVALID_STATE; Loading
media/libaaudio/src/client/AudioStreamInternalPlay.h +2 −2 Original line number Diff line number Diff line Loading @@ -35,9 +35,9 @@ public: aaudio_result_t open(const AudioStreamBuilder &builder) override; aaudio_result_t requestPause() override; aaudio_result_t requestPause_l() override; aaudio_result_t requestFlush() override; aaudio_result_t requestFlush_l() override; bool isFlushSupported() const override { // Only implement FLUSH for OUTPUT streams. Loading
media/libaaudio/src/core/AudioStream.cpp +52 −22 Original line number Diff line number Diff line Loading @@ -42,16 +42,20 @@ AudioStream::AudioStream() : mPlayerBase(new MyPlayerBase()) , mStreamId(AAudio_getNextStreamId()) { // mThread is a pthread_t of unknown size so we need memset. memset(&mThread, 0, sizeof(mThread)); setPeriodNanoseconds(0); } AudioStream::~AudioStream() { // Please preserve this log because there have been several bugs related to // Please preserve these logs because there have been several bugs related to // AudioStream deletion and late callbacks. ALOGD("%s(s#%u) mPlayerBase strongCount = %d", __func__, getId(), mPlayerBase->getStrongCount()); ALOGE_IF(pthread_equal(pthread_self(), mThread), "%s() destructor running in callback", __func__); ALOGE_IF(mHasThread, "%s() callback thread never join()ed", __func__); // If the stream is deleted when OPEN or in use then audio resources will leak. // This would indicate an internal error. So we want to find this ASAP. LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED Loading Loading @@ -164,7 +168,7 @@ aaudio_result_t AudioStream::systemStart() { return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = requestStart(); aaudio_result_t result = requestStart_l(); if (result == AAUDIO_OK) { // We only call this for logging in "dumpsys audio". So ignore return code. (void) mPlayerBase->start(); Loading Loading @@ -214,7 +218,7 @@ aaudio_result_t AudioStream::systemPause() { return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = requestPause(); aaudio_result_t result = requestPause_l(); if (result == AAUDIO_OK) { // We only call this for logging in "dumpsys audio". So ignore return code. (void) mPlayerBase->pause(); Loading @@ -239,7 +243,7 @@ aaudio_result_t AudioStream::safeFlush() { return result; } return requestFlush(); return requestFlush_l(); } aaudio_result_t AudioStream::systemStopFromCallback() { Loading Loading @@ -299,11 +303,11 @@ aaudio_result_t AudioStream::safeStop() { return AAUDIO_ERROR_INVALID_STATE; } return requestStop(); return requestStop_l(); } aaudio_result_t AudioStream::safeRelease() { // This get temporarily unlocked in the MMAP release() when joining callback threads. // This may get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); Loading @@ -322,7 +326,14 @@ aaudio_result_t AudioStream::safeReleaseClose() { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } releaseCloseFinal(); releaseCloseFinal_l(); return AAUDIO_OK; } aaudio_result_t AudioStream::safeReleaseCloseFromCallback() { // This get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); releaseCloseFinal_l(); return AAUDIO_OK; } Loading Loading @@ -403,23 +414,28 @@ void* AudioStream::wrapUserThread() { return procResult; } // This is the entry point for the new thread created by createThread(). // This is the entry point for the new thread created by createThread_l(). // It converts the 'C' function call to a C++ method call. static void* AudioStream_internalThreadProc(void* threadArg) { AudioStream *audioStream = (AudioStream *) threadArg; // Use an sp<> to prevent the stream from being deleted while running. // Prevent the stream from being deleted while being used. // This is just for extra safety. It is probably not needed because // this callback should be joined before the stream is closed. android::sp<AudioStream> protectedStream(audioStream); // Balance the incStrong() in createThread_l(). protectedStream->decStrong(nullptr); return protectedStream->wrapUserThread(); } // This is not exposed in the API. // But it is still used internally to implement callbacks for MMAP mode. aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, aaudio_result_t AudioStream::createThread_l(int64_t periodNanoseconds, aaudio_audio_thread_proc_t threadProc, void* threadArg) { if (mHasThread) { ALOGE("createThread() - mHasThread already true"); ALOGE("%s() - mHasThread already true", __func__); return AAUDIO_ERROR_INVALID_STATE; } if (threadProc == nullptr) { Loading @@ -429,10 +445,14 @@ aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, mThreadProc = threadProc; mThreadArg = threadArg; setPeriodNanoseconds(periodNanoseconds); // Prevent this object from getting deleted before the thread has a chance to create // its strong pointer. Assume the thread will call decStrong(). this->incStrong(nullptr); int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this); if (err != 0) { android::status_t status = -errno; ALOGE("createThread() - pthread_create() failed, %d", status); ALOGE("%s() - pthread_create() failed, %d", __func__, status); this->decStrong(nullptr); // Because the thread won't do it. return AAudioConvert_androidToAAudioResult(status); } else { // TODO Use AAudioThread or maybe AndroidThread Loading @@ -452,17 +472,23 @@ aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds, } } aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) { // This may get temporarily unlocked in the MMAP release() when joining callback threads. std::lock_guard<std::mutex> lock(mStreamLock); return joinThread_l(returnArg, timeoutNanoseconds); } // This must be called under mStreamLock. aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds __unused) aaudio_result_t AudioStream::joinThread_l(void** returnArg, int64_t /* timeoutNanoseconds */) { if (!mHasThread) { ALOGE("joinThread() - but has no thread"); ALOGD("joinThread() - but has no thread"); return AAUDIO_ERROR_INVALID_STATE; } aaudio_result_t result = AAUDIO_OK; // If the callback is stopping the stream because the app passed back STOP // then we don't need to join(). The thread is already about to exit. if (pthread_self() != mThread) { if (!pthread_equal(pthread_self(), mThread)) { // Called from an app thread. Not the callback. // Unlock because the callback may be trying to stop the stream but is blocked. mStreamLock.unlock(); Loading @@ -477,11 +503,15 @@ aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanosec if (err) { ALOGE("%s() pthread_join() returns err = %d", __func__, err); result = AAudioConvert_androidToAAudioResult(-err); } } } else { ALOGD("%s() pthread_join succeeded", __func__); // This must be set false so that the callback thread can be created // when the stream is restarted. mHasThread = false; } } else { ALOGD("%s() pthread_join() called on itself!", __func__); } return (result != AAUDIO_OK) ? result : mThreadRegistrationResult; } Loading