Loading media/libaaudio/src/client/AudioStreamInternal.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -171,7 +171,7 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { mClockModel.setSampleRate(getSampleRate()); mClockModel.setSampleRate(getSampleRate()); mClockModel.setFramesPerBurst(mFramesPerBurst); mClockModel.setFramesPerBurst(mFramesPerBurst); if (getDataCallbackProc()) { if (isDataCallbackSet()) { mCallbackFrames = builder.getFramesPerDataCallback(); mCallbackFrames = builder.getFramesPerDataCallback(); if (mCallbackFrames > getBufferCapacity() / 2) { if (mCallbackFrames > getBufferCapacity() / 2) { ALOGE("%s - framesPerCallback too big = %d, capacity = %d", ALOGE("%s - framesPerCallback too big = %d, capacity = %d", Loading Loading @@ -290,7 +290,7 @@ aaudio_result_t AudioStreamInternal::requestStart() mNeedCatchUp.request(); // Ask data processing code to catch up when first timestamp received. mNeedCatchUp.request(); // Ask data processing code to catch up when first timestamp received. // Start data callback thread. // Start data callback thread. if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) { if (result == AAUDIO_OK && isDataCallbackSet()) { // Launch the callback loop thread. // Launch the callback loop thread. int64_t periodNanos = mCallbackFrames int64_t periodNanos = mCallbackFrames * AAUDIO_NANOS_PER_SECOND * AAUDIO_NANOS_PER_SECOND Loading media/libaaudio/src/client/AudioStreamInternalCapture.cpp +3 −14 Original line number Original line Diff line number Diff line Loading @@ -232,8 +232,7 @@ int64_t AudioStreamInternalCapture::getFramesRead() { void *AudioStreamInternalCapture::callbackLoop() { void *AudioStreamInternalCapture::callbackLoop() { aaudio_result_t result = AAUDIO_OK; aaudio_result_t result = AAUDIO_OK; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; AAudioStream_dataCallback appCallback = getDataCallbackProc(); if (!isDataCallbackSet()) return NULL; if (appCallback == nullptr) return NULL; // result might be a frame count // result might be a frame count while (mCallbackEnabled.load() && isActive() && (result >= 0)) { while (mCallbackEnabled.load() && isActive() && (result >= 0)) { Loading @@ -249,22 +248,12 @@ void *AudioStreamInternalCapture::callbackLoop() { // Only read some of the frames requested. Must have timed out. // Only read some of the frames requested. Must have timed out. result = AAUDIO_ERROR_TIMEOUT; result = AAUDIO_ERROR_TIMEOUT; } } AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); maybeCallErrorCallback(result); if (errorCallback != nullptr) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); } break; break; } } // Call application using the AAudio callback interface. // Call application using the AAudio callback interface. callbackResult = (*appCallback)( callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames); (AAudioStream *) this, getDataCallbackUserData(), mCallbackBuffer, mCallbackFrames); if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP"); ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP"); Loading media/libaaudio/src/client/AudioStreamInternalPlay.cpp +3 −14 Original line number Original line Diff line number Diff line Loading @@ -323,18 +323,13 @@ int64_t AudioStreamInternalPlay::getFramesWritten() void *AudioStreamInternalPlay::callbackLoop() { void *AudioStreamInternalPlay::callbackLoop() { aaudio_result_t result = AAUDIO_OK; aaudio_result_t result = AAUDIO_OK; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; AAudioStream_dataCallback appCallback = getDataCallbackProc(); if (!isDataCallbackSet()) return NULL; if (appCallback == nullptr) return NULL; int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); // result might be a frame count // result might be a frame count while (mCallbackEnabled.load() && isActive() && (result >= 0)) { while (mCallbackEnabled.load() && isActive() && (result >= 0)) { // Call application using the AAudio callback interface. // Call application using the AAudio callback interface. callbackResult = (*appCallback)( callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames); (AAudioStream *) this, getDataCallbackUserData(), mCallbackBuffer, mCallbackFrames); if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { // Write audio data to stream. This is a BLOCKING WRITE! // Write audio data to stream. This is a BLOCKING WRITE! Loading @@ -345,13 +340,7 @@ void *AudioStreamInternalPlay::callbackLoop() { // Only wrote some of the frames requested. Must have timed out. // Only wrote some of the frames requested. Must have timed out. result = AAUDIO_ERROR_TIMEOUT; result = AAUDIO_ERROR_TIMEOUT; } } AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); maybeCallErrorCallback(result); if (errorCallback != nullptr) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); } break; break; } } } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { Loading media/libaaudio/src/core/AAudioAudio.cpp +16 −8 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Log.h> #include <mutex> #include <time.h> #include <time.h> #include <pthread.h> #include <pthread.h> Loading Loading @@ -238,15 +239,22 @@ AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* buil AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) { { aaudio_result_t result = AAUDIO_ERROR_NULL; AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); ALOGD("AAudioStream_close(%p)", stream); ALOGD("AAudioStream_close(%p) called ---------------", stream); if (audioStream != nullptr) { if (audioStream != nullptr) { audioStream->close(); result = audioStream->safeClose(); // Close will only fail if called illegally, for example, from a callback. // That would result in deleting an active stream, which would cause a crash. if (result == AAUDIO_OK) { audioStream->unregisterPlayerBase(); audioStream->unregisterPlayerBase(); delete audioStream; delete audioStream; return AAUDIO_OK; } else { ALOGW("%s attempt to close failed. Close from another thread.", __func__); } } return AAUDIO_ERROR_NULL; } ALOGD("AAudioStream_close(%p) returned %d ---------", stream, result); return result; } } AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) Loading @@ -269,7 +277,7 @@ AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream) { { AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); ALOGD("AAudioStream_requestFlush(%p)", stream); ALOGD("AAudioStream_requestFlush(%p)", stream); return audioStream->requestFlush(); return audioStream->safeFlush(); } } AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream) Loading Loading @@ -324,7 +332,7 @@ AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream, } } // Don't allow writes when playing with a callback. // Don't allow writes when playing with a callback. if (audioStream->getDataCallbackProc() != nullptr && audioStream->isActive()) { if (audioStream->isDataCallbackActive()) { ALOGE("Cannot write to a callback stream when running."); ALOGE("Cannot write to a callback stream when running."); return AAUDIO_ERROR_INVALID_STATE; return AAUDIO_ERROR_INVALID_STATE; } } Loading media/libaaudio/src/core/AudioStream.cpp +98 −2 Original line number Original line Diff line number Diff line Loading @@ -43,7 +43,7 @@ AudioStream::~AudioStream() { LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), "aaudio stream still in use, state = %s", "~AudioStream() - still in use, state = %s", AAudio_convertStreamStateToText(getState())); AAudio_convertStreamStateToText(getState())); mPlayerBase->clearParentReference(); // remove reference to this AudioStream mPlayerBase->clearParentReference(); // remove reference to this AudioStream Loading Loading @@ -97,12 +97,56 @@ aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d", ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d", mDeviceId, mPerformanceMode, mDeviceId, mPerformanceMode, (mDataCallbackProc == nullptr ? "OFF" : "ON"), (isDataCallbackSet() ? "ON" : "OFF"), mFramesPerDataCallback); mFramesPerDataCallback); return AAUDIO_OK; return AAUDIO_OK; } } aaudio_result_t AudioStream::safeStart() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestStart(); } aaudio_result_t AudioStream::safePause() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestPause(); } aaudio_result_t AudioStream::safeFlush() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestFlush(); } aaudio_result_t AudioStream::safeStop() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestStop(); } aaudio_result_t AudioStream::safeClose() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return close(); } aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, aaudio_stream_state_t *nextState, aaudio_stream_state_t *nextState, Loading Loading @@ -200,6 +244,58 @@ aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanosec } } aaudio_data_callback_result_t AudioStream::maybeCallDataCallback(void *audioData, int32_t numFrames) { aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP; AAudioStream_dataCallback dataCallback = getDataCallbackProc(); if (dataCallback != nullptr) { // Store thread ID of caller to detect stop() and close() calls from callback. pid_t expected = CALLBACK_THREAD_NONE; if (mDataCallbackThread.compare_exchange_strong(expected, gettid())) { result = (*dataCallback)( (AAudioStream *) this, getDataCallbackUserData(), audioData, numFrames); mDataCallbackThread.store(CALLBACK_THREAD_NONE); } else { ALOGW("%s() data callback already running!", __func__); } } return result; } void AudioStream::maybeCallErrorCallback(aaudio_result_t result) { AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); if (errorCallback != nullptr) { // Store thread ID of caller to detect stop() and close() calls from callback. pid_t expected = CALLBACK_THREAD_NONE; if (mErrorCallbackThread.compare_exchange_strong(expected, gettid())) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); mErrorCallbackThread.store(CALLBACK_THREAD_NONE); } else { ALOGW("%s() error callback already running!", __func__); } } } // Is this running on the same thread as a callback? // Note: This cannot be implemented using a thread_local because that would // require using a thread_local variable that is shared between streams. // So a thread_local variable would prevent stopping or closing stream A from // a callback on stream B, which is currently legal and not so terrible. bool AudioStream::collidesWithCallback() const { pid_t thisThread = gettid(); // Compare the current thread ID with the thread ID of the callback // threads to see it they match. If so then this code is being // called from one of the stream callback functions. return ((mErrorCallbackThread.load() == thisThread) || (mDataCallbackThread.load() == thisThread)); } #if AAUDIO_USE_VOLUME_SHAPER #if AAUDIO_USE_VOLUME_SHAPER android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( const android::media::VolumeShaper::Configuration& configuration __unused, const android::media::VolumeShaper::Configuration& configuration __unused, Loading Loading
media/libaaudio/src/client/AudioStreamInternal.cpp +2 −2 Original line number Original line Diff line number Diff line Loading @@ -171,7 +171,7 @@ aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { mClockModel.setSampleRate(getSampleRate()); mClockModel.setSampleRate(getSampleRate()); mClockModel.setFramesPerBurst(mFramesPerBurst); mClockModel.setFramesPerBurst(mFramesPerBurst); if (getDataCallbackProc()) { if (isDataCallbackSet()) { mCallbackFrames = builder.getFramesPerDataCallback(); mCallbackFrames = builder.getFramesPerDataCallback(); if (mCallbackFrames > getBufferCapacity() / 2) { if (mCallbackFrames > getBufferCapacity() / 2) { ALOGE("%s - framesPerCallback too big = %d, capacity = %d", ALOGE("%s - framesPerCallback too big = %d, capacity = %d", Loading Loading @@ -290,7 +290,7 @@ aaudio_result_t AudioStreamInternal::requestStart() mNeedCatchUp.request(); // Ask data processing code to catch up when first timestamp received. mNeedCatchUp.request(); // Ask data processing code to catch up when first timestamp received. // Start data callback thread. // Start data callback thread. if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) { if (result == AAUDIO_OK && isDataCallbackSet()) { // Launch the callback loop thread. // Launch the callback loop thread. int64_t periodNanos = mCallbackFrames int64_t periodNanos = mCallbackFrames * AAUDIO_NANOS_PER_SECOND * AAUDIO_NANOS_PER_SECOND Loading
media/libaaudio/src/client/AudioStreamInternalCapture.cpp +3 −14 Original line number Original line Diff line number Diff line Loading @@ -232,8 +232,7 @@ int64_t AudioStreamInternalCapture::getFramesRead() { void *AudioStreamInternalCapture::callbackLoop() { void *AudioStreamInternalCapture::callbackLoop() { aaudio_result_t result = AAUDIO_OK; aaudio_result_t result = AAUDIO_OK; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; AAudioStream_dataCallback appCallback = getDataCallbackProc(); if (!isDataCallbackSet()) return NULL; if (appCallback == nullptr) return NULL; // result might be a frame count // result might be a frame count while (mCallbackEnabled.load() && isActive() && (result >= 0)) { while (mCallbackEnabled.load() && isActive() && (result >= 0)) { Loading @@ -249,22 +248,12 @@ void *AudioStreamInternalCapture::callbackLoop() { // Only read some of the frames requested. Must have timed out. // Only read some of the frames requested. Must have timed out. result = AAUDIO_ERROR_TIMEOUT; result = AAUDIO_ERROR_TIMEOUT; } } AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); maybeCallErrorCallback(result); if (errorCallback != nullptr) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); } break; break; } } // Call application using the AAudio callback interface. // Call application using the AAudio callback interface. callbackResult = (*appCallback)( callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames); (AAudioStream *) this, getDataCallbackUserData(), mCallbackBuffer, mCallbackFrames); if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP"); ALOGD("callback returned AAUDIO_CALLBACK_RESULT_STOP"); Loading
media/libaaudio/src/client/AudioStreamInternalPlay.cpp +3 −14 Original line number Original line Diff line number Diff line Loading @@ -323,18 +323,13 @@ int64_t AudioStreamInternalPlay::getFramesWritten() void *AudioStreamInternalPlay::callbackLoop() { void *AudioStreamInternalPlay::callbackLoop() { aaudio_result_t result = AAUDIO_OK; aaudio_result_t result = AAUDIO_OK; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; AAudioStream_dataCallback appCallback = getDataCallbackProc(); if (!isDataCallbackSet()) return NULL; if (appCallback == nullptr) return NULL; int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); // result might be a frame count // result might be a frame count while (mCallbackEnabled.load() && isActive() && (result >= 0)) { while (mCallbackEnabled.load() && isActive() && (result >= 0)) { // Call application using the AAudio callback interface. // Call application using the AAudio callback interface. callbackResult = (*appCallback)( callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames); (AAudioStream *) this, getDataCallbackUserData(), mCallbackBuffer, mCallbackFrames); if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { // Write audio data to stream. This is a BLOCKING WRITE! // Write audio data to stream. This is a BLOCKING WRITE! Loading @@ -345,13 +340,7 @@ void *AudioStreamInternalPlay::callbackLoop() { // Only wrote some of the frames requested. Must have timed out. // Only wrote some of the frames requested. Must have timed out. result = AAUDIO_ERROR_TIMEOUT; result = AAUDIO_ERROR_TIMEOUT; } } AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); maybeCallErrorCallback(result); if (errorCallback != nullptr) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); } break; break; } } } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { Loading
media/libaaudio/src/core/AAudioAudio.cpp +16 −8 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Log.h> #include <mutex> #include <time.h> #include <time.h> #include <pthread.h> #include <pthread.h> Loading Loading @@ -238,15 +239,22 @@ AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* buil AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) { { aaudio_result_t result = AAUDIO_ERROR_NULL; AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); ALOGD("AAudioStream_close(%p)", stream); ALOGD("AAudioStream_close(%p) called ---------------", stream); if (audioStream != nullptr) { if (audioStream != nullptr) { audioStream->close(); result = audioStream->safeClose(); // Close will only fail if called illegally, for example, from a callback. // That would result in deleting an active stream, which would cause a crash. if (result == AAUDIO_OK) { audioStream->unregisterPlayerBase(); audioStream->unregisterPlayerBase(); delete audioStream; delete audioStream; return AAUDIO_OK; } else { ALOGW("%s attempt to close failed. Close from another thread.", __func__); } } return AAUDIO_ERROR_NULL; } ALOGD("AAudioStream_close(%p) returned %d ---------", stream, result); return result; } } AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) Loading @@ -269,7 +277,7 @@ AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream) { { AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); AudioStream *audioStream = convertAAudioStreamToAudioStream(stream); ALOGD("AAudioStream_requestFlush(%p)", stream); ALOGD("AAudioStream_requestFlush(%p)", stream); return audioStream->requestFlush(); return audioStream->safeFlush(); } } AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream) AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream) Loading Loading @@ -324,7 +332,7 @@ AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream, } } // Don't allow writes when playing with a callback. // Don't allow writes when playing with a callback. if (audioStream->getDataCallbackProc() != nullptr && audioStream->isActive()) { if (audioStream->isDataCallbackActive()) { ALOGE("Cannot write to a callback stream when running."); ALOGE("Cannot write to a callback stream when running."); return AAUDIO_ERROR_INVALID_STATE; return AAUDIO_ERROR_INVALID_STATE; } } Loading
media/libaaudio/src/core/AudioStream.cpp +98 −2 Original line number Original line Diff line number Diff line Loading @@ -43,7 +43,7 @@ AudioStream::~AudioStream() { LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), "aaudio stream still in use, state = %s", "~AudioStream() - still in use, state = %s", AAudio_convertStreamStateToText(getState())); AAudio_convertStreamStateToText(getState())); mPlayerBase->clearParentReference(); // remove reference to this AudioStream mPlayerBase->clearParentReference(); // remove reference to this AudioStream Loading Loading @@ -97,12 +97,56 @@ aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder) (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT"); ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d", ALOGI("open() device = %d, perfMode = %d, callback: %s with frames = %d", mDeviceId, mPerformanceMode, mDeviceId, mPerformanceMode, (mDataCallbackProc == nullptr ? "OFF" : "ON"), (isDataCallbackSet() ? "ON" : "OFF"), mFramesPerDataCallback); mFramesPerDataCallback); return AAUDIO_OK; return AAUDIO_OK; } } aaudio_result_t AudioStream::safeStart() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestStart(); } aaudio_result_t AudioStream::safePause() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestPause(); } aaudio_result_t AudioStream::safeFlush() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestFlush(); } aaudio_result_t AudioStream::safeStop() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return requestStop(); } aaudio_result_t AudioStream::safeClose() { std::lock_guard<std::mutex> lock(mStreamLock); if (collidesWithCallback()) { ALOGE("%s cannot be called from a callback!", __func__); return AAUDIO_ERROR_INVALID_STATE; } return close(); } aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState, aaudio_stream_state_t *nextState, aaudio_stream_state_t *nextState, Loading Loading @@ -200,6 +244,58 @@ aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanosec } } aaudio_data_callback_result_t AudioStream::maybeCallDataCallback(void *audioData, int32_t numFrames) { aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP; AAudioStream_dataCallback dataCallback = getDataCallbackProc(); if (dataCallback != nullptr) { // Store thread ID of caller to detect stop() and close() calls from callback. pid_t expected = CALLBACK_THREAD_NONE; if (mDataCallbackThread.compare_exchange_strong(expected, gettid())) { result = (*dataCallback)( (AAudioStream *) this, getDataCallbackUserData(), audioData, numFrames); mDataCallbackThread.store(CALLBACK_THREAD_NONE); } else { ALOGW("%s() data callback already running!", __func__); } } return result; } void AudioStream::maybeCallErrorCallback(aaudio_result_t result) { AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); if (errorCallback != nullptr) { // Store thread ID of caller to detect stop() and close() calls from callback. pid_t expected = CALLBACK_THREAD_NONE; if (mErrorCallbackThread.compare_exchange_strong(expected, gettid())) { (*errorCallback)( (AAudioStream *) this, getErrorCallbackUserData(), result); mErrorCallbackThread.store(CALLBACK_THREAD_NONE); } else { ALOGW("%s() error callback already running!", __func__); } } } // Is this running on the same thread as a callback? // Note: This cannot be implemented using a thread_local because that would // require using a thread_local variable that is shared between streams. // So a thread_local variable would prevent stopping or closing stream A from // a callback on stream B, which is currently legal and not so terrible. bool AudioStream::collidesWithCallback() const { pid_t thisThread = gettid(); // Compare the current thread ID with the thread ID of the callback // threads to see it they match. If so then this code is being // called from one of the stream callback functions. return ((mErrorCallbackThread.load() == thisThread) || (mDataCallbackThread.load() == thisThread)); } #if AAUDIO_USE_VOLUME_SHAPER #if AAUDIO_USE_VOLUME_SHAPER android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( android::media::VolumeShaper::Status AudioStream::applyVolumeShaper( const android::media::VolumeShaper::Configuration& configuration __unused, const android::media::VolumeShaper::Configuration& configuration __unused, Loading