diff options
author | Phil Burk <philburk@mobileer.com> | 2020-04-15 13:49:11 -0700 |
---|---|---|
committer | Phil Burk <philburk@mobileer.com> | 2020-04-15 13:49:11 -0700 |
commit | 68f7df0d535e8d282cd7bc5feeca9ac5a77fc081 (patch) | |
tree | df31885caee2c2fd0dacc72db5b3475b874055a5 | |
parent | 55d878a4e85e1994f2b5883366079b991500a25f (diff) | |
download | oboe-68f7df0d535e8d282cd7bc5feeca9ac5a77fc081.tar.gz |
oboe: add openSharedStream
To prevent race conditions with the onError callbacks
that were resulting in the use of a deleted stream.
For bug #820
-rw-r--r-- | include/oboe/AudioStream.h | 21 | ||||
-rw-r--r-- | include/oboe/AudioStreamBuilder.h | 3 | ||||
-rw-r--r-- | src/aaudio/AudioStreamAAudio.cpp | 20 | ||||
-rw-r--r-- | src/common/AudioStreamBuilder.cpp | 10 |
4 files changed, 52 insertions, 2 deletions
diff --git a/include/oboe/AudioStream.h b/include/oboe/AudioStream.h index d9b2046a..f2452585 100644 --- a/include/oboe/AudioStream.h +++ b/include/oboe/AudioStream.h @@ -418,6 +418,22 @@ public: ResultWithValue<int32_t> waitForAvailableFrames(int32_t numFrames, int64_t timeoutNanoseconds); + /* + * INTERNAL USE ONLY + * Set a weak_ptr to this stream from the shared_ptr so that we can + * later use a shared_ptr in the error callback. + */ + void setWeakThis(std::shared_ptr<oboe::AudioStream> &sharedStream) { + mWeakThis = sharedStream; + } + + /* + * Make a shared_ptr that will prevent this stream from being deleted. + */ + std::shared_ptr<oboe::AudioStream> lockWeakThis() { + return mWeakThis.lock(); + } + protected: /** @@ -497,17 +513,18 @@ protected: std::mutex mLock; // for synchronizing start/stop/close + private: int mPreviousScheduler = -1; std::atomic<bool> mDataCallbackEnabled{false}; std::atomic<bool> mErrorCallbackCalled{false}; - + std::weak_ptr<AudioStream> mWeakThis; }; /** - * This struct is a stateless functor which closes a audiostream prior to its deletion. + * This struct is a stateless functor which closes an AudioStream prior to its deletion. * This means it can be used to safely delete a smart pointer referring to an open stream. */ struct StreamDeleterFunctor { diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h index b0f7de8e..636803a7 100644 --- a/include/oboe/AudioStreamBuilder.h +++ b/include/oboe/AudioStreamBuilder.h @@ -25,6 +25,7 @@ namespace oboe { // This depends on AudioStream, so we use forward declaration, it will close and delete the stream struct StreamDeleterFunctor; using ManagedStream = std::unique_ptr<AudioStream, StreamDeleterFunctor>; + /** * Factory class for an audio Stream. */ @@ -399,6 +400,8 @@ public: */ Result openManagedStream(ManagedStream &stream); + Result openSharedStream(std::shared_ptr<oboe::AudioStream> &sharedStream); + private: /** diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp index b19ec915..383e9f60 100644 --- a/src/aaudio/AudioStreamAAudio.cpp +++ b/src/aaudio/AudioStreamAAudio.cpp @@ -74,6 +74,17 @@ static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream, LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__); } +// This runs in its own thread. +// Only one of these threads will be launched from internalErrorCallback(). +// Prevents deletion of the stream if the app is using AudioStreamBuilder::openSharedStream() +static void oboe_aaudio_error_thread_proc_shared(std::shared_ptr<AudioStream> sharedStream, + Result error) { + LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__); + AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get()); + oboe_aaudio_error_thread_proc(oboeStream, error); + LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__); +} + namespace oboe { /* @@ -101,12 +112,21 @@ void AudioStreamAAudio::internalErrorCallback( void *userData, aaudio_result_t error) { AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData); + + // Prevents deletion of the stream if the app is using AudioStreamBuilder::openSharedStream() + std::shared_ptr<AudioStream> sharedStream = oboeStream->lockWeakThis(); + // These checks should be enough because we assume that the stream close() // will join() any active callback threads and will not allow new callbacks. if (oboeStream->wasErrorCallbackCalled()) { // block extra error callbacks LOGE("%s() multiple error callbacks called!", __func__); } else if (stream != oboeStream->getUnderlyingStream()) { LOGD("%s() stream already closed", __func__); // can happen if there are bugs + } else if (sharedStream) { + // Handle error on a separate thread using shared pointer. + std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream, + static_cast<Result>(error)); + t.detach(); } else { // Handle error on a separate thread. std::thread t(oboe_aaudio_error_thread_proc, oboeStream, diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/AudioStreamBuilder.cpp index 9d446258..3ca3e103 100644 --- a/src/common/AudioStreamBuilder.cpp +++ b/src/common/AudioStreamBuilder.cpp @@ -186,4 +186,14 @@ Result AudioStreamBuilder::openManagedStream(oboe::ManagedStream &stream) { return result; } +Result AudioStreamBuilder::openSharedStream(std::shared_ptr<oboe::AudioStream> &sharedStream) { + sharedStream.reset(); + AudioStream *streamptr; + auto result = openStream(&streamptr); + sharedStream.reset(streamptr); + // Save a weak_ptr in the stream for use with callbacks. + streamptr->setWeakThis(sharedStream); + return result; +} + } // namespace oboe
\ No newline at end of file |