Skip to content

Commit 4d319f2

Browse files
authored
Make sure FilterAudioStream is alive in callbacks (#2325) (#2354)
1 parent 24c4986 commit 4d319f2

3 files changed

Lines changed: 73 additions & 19 deletions

File tree

include/oboe/AudioStream.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,30 @@ class AudioStream : public AudioStreamBase {
787787
return mWeakThis.lock();
788788
}
789789

790+
/**
791+
* Returns a pointer to the parent stream if this stream is wrapped
792+
* by a parent FilterAudioStream. May be unassigned if no parent exists.
793+
*/
794+
AudioStream *getParentStream() const {
795+
return mParentStream;
796+
}
797+
798+
/**
799+
* Returns true if this stream is owned by a parent FilterAudioStream.
800+
* When true, the parent must remain alive during callbacks.
801+
*/
802+
bool hasParentStream() const {
803+
return mHasParentStream;
804+
}
805+
806+
/**
807+
* Sets the parent wrapper stream. For internal use only.
808+
*/
809+
void setParentStream(AudioStream *parentStream) {
810+
mParentStream = parentStream;
811+
mHasParentStream = parentStream != nullptr;
812+
}
813+
790814
protected:
791815

792816
/**
@@ -898,6 +922,13 @@ class AudioStream : public AudioStreamBase {
898922

899923
std::weak_ptr<AudioStream> mWeakThis; // weak pointer to this object
900924

925+
// Pointer to parent stream.
926+
// Non-empty only when wrapped by another AudioStream.
927+
AudioStream *mParentStream{};
928+
929+
// Flag to indicate whether this stream is wrapped by a parent.
930+
bool mHasParentStream{};
931+
901932
/**
902933
* Number of frames which have been written into the stream
903934
*

src/aaudio/AudioStreamAAudio.cpp

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,37 @@ class AAudioStreamCollection {
7272
}
7373

7474
/**
75-
* Get a shared pointer to the stream. This is typically called from a callback thread.
75+
* Get a shared pointer to the stream and its parent (if wrapped by FilterAudioStream).
76+
* This is typically called from a callback thread.
77+
*
78+
* The shared pointers are valid only if the stream is opened with shared pointer and is not closed.
7679
*
7780
* @param stream raw pointer to the stream.
78-
* @return a pair of a boolean and a shared pointer to the stream. The boolean indicates
79-
* if the stream is present in the collection. The shared pointer is valid only if
80-
* the stream is opened with shared pointer and is not closed.
81+
* @return tuple:
82+
* - bool: indicates if the stream is present in the collection.
83+
* - shared_ptr to the stream.
84+
* - shared_ptr to the parent stream if wrapped by FilterAudioStream, nullptr otherwise.
8185
*/
82-
std::pair<bool, std::shared_ptr<oboe::AudioStream>> getStream(AudioStreamAAudio* stream) {
86+
std::tuple<bool,
87+
std::shared_ptr<oboe::AudioStream>,
88+
std::shared_ptr<oboe::AudioStream>>
89+
getStream(AudioStreamAAudio* stream) {
8390
if (stream == nullptr) {
84-
return {false, nullptr};
91+
return {false, nullptr, nullptr};
8592
}
8693
std::lock_guard<std::mutex> lock(mLock);
8794
if (mStreams.find(stream) != mStreams.end()) {
8895
auto sharedStream = stream->lockWeakThis();
89-
return {true, sharedStream};
96+
97+
// If wrapped by FilterAudioStream, the parent must remain alive because
98+
// callbacks are routed through it.
99+
std::shared_ptr<AudioStream> sharedParentStream;
100+
if (sharedStream && sharedStream->hasParentStream()) {
101+
sharedParentStream = sharedStream->getParentStream()->lockWeakThis();
102+
}
103+
return {true, sharedStream, sharedParentStream};
90104
}
91-
return {false, nullptr};
105+
return {false, nullptr, nullptr};
92106
}
93107

94108
private:
@@ -107,7 +121,7 @@ static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc(
107121
int32_t numFrames) {
108122

109123
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
110-
auto [isStreamAlive, sharedStream] =
124+
auto [isStreamAlive, sharedStream, sharedParentStream] =
111125
AAudioStreamCollection::getInstance().getStream(oboeStream);
112126
if (!isStreamAlive) {
113127
// Note that the stream is removed from the collection when close is called. However,
@@ -132,7 +146,7 @@ static int32_t oboe_aaudio_partial_data_callback_proc(
132146
void *audioData,
133147
int32_t numFrames) {
134148
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
135-
auto [isStreamAlive, sharedStream] =
149+
auto [isStreamAlive, sharedStream, sharedParentStream] =
136150
AAudioStreamCollection::getInstance().getStream(oboeStream);
137151
if (!isStreamAlive) {
138152
// Note that the stream is removed from the collection when close is called. However,
@@ -183,9 +197,10 @@ static void oboe_aaudio_error_thread_proc(AudioStreamAAudio *oboeStream,
183197

184198
// Callback thread for shared pointers.
185199
static void oboe_aaudio_error_thread_proc_shared(std::shared_ptr<AudioStream> sharedStream,
200+
std::shared_ptr<AudioStream> sharedParentStream,
186201
Result error) {
187202
LOGD("%s(,%d) - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__, error);
188-
// Hold the shared pointer while we use the raw pointer.
203+
// Hold the shared pointer(s) while we use the raw pointer.
189204
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get());
190205
oboe_aaudio_error_thread_proc_common(oboeStream, error);
191206
LOGD("%s() - exiting <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", __func__);
@@ -206,7 +221,8 @@ static void oboe_aaudio_presentation_thread_proc(AudioStreamAAudio *oboeStream)
206221

207222
// Callback thread for shared pointers
208223
static void oboe_aaudio_presentation_end_thread_proc_shared(
209-
std::shared_ptr<AudioStream> sharedStream) {
224+
std::shared_ptr<AudioStream> sharedStream,
225+
std::shared_ptr<AudioStream> sharedParentStream) {
210226
LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__);
211227
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get());
212228
oboe_aaudio_presentation_thread_proc_common(oboeStream);
@@ -231,7 +247,9 @@ static void oboe_aaudio_routing_changed_thread_proc(
231247

232248
// Callback thread for shared pointers
233249
static void oboe_aaudio_routing_changed_thread_proc_shared(
234-
std::shared_ptr<AudioStream> sharedStream, std::vector<int32_t> deviceIds) {
250+
std::shared_ptr<AudioStream> sharedStream,
251+
std::shared_ptr<AudioStream> sharedParentStream,
252+
std::vector<int32_t> deviceIds) {
235253
LOGD("%s() - entering >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", __func__);
236254
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(sharedStream.get());
237255
oboe_aaudio_routing_changed_thread_proc_common(oboeStream, deviceIds.data(),
@@ -278,7 +296,7 @@ void AudioStreamAAudio::internalErrorCallback(
278296
}
279297

280298
// Prevents deletion of the stream if the app is using AudioStreamBuilder::openStream(shared_ptr)
281-
auto [isStreamAlive, sharedStream] =
299+
auto [isStreamAlive, sharedStream, sharedParentStream] =
282300
AAudioStreamCollection::getInstance().getStream(oboeStream);
283301
if (!isStreamAlive) {
284302
// The stream is already closed. No need to call error callback.
@@ -295,7 +313,8 @@ void AudioStreamAAudio::internalErrorCallback(
295313
LOGW("%s() stream already closed or closing", __func__); // might happen if there are bugs
296314
} else if (sharedStream) {
297315
// Handle error on a separate thread using shared pointer.
298-
std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream, oboeResult);
316+
std::thread t(oboe_aaudio_error_thread_proc_shared, sharedStream, sharedParentStream,
317+
oboeResult);
299318
t.detach();
300319
} else {
301320
// Handle error on a separate thread.
@@ -1089,7 +1108,7 @@ void AudioStreamAAudio::internalPresentationEndCallback(AAudioStream *stream, vo
10891108
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
10901109

10911110
// Prevents deletion of the stream if the app is using AudioStreamBuilder::openStream(shared_ptr)
1092-
auto [isStreamAlive, sharedStream] =
1111+
auto [isStreamAlive, sharedStream, sharedParentStream] =
10931112
AAudioStreamCollection::getInstance().getStream(oboeStream);
10941113
if (!isStreamAlive) {
10951114
// Client has closed the stream, no need to call the presentation end callback here.
@@ -1100,7 +1119,8 @@ void AudioStreamAAudio::internalPresentationEndCallback(AAudioStream *stream, vo
11001119
LOGW("%s() stream already closed or closing", __func__); // might happen if there are bugs
11011120
} else if (sharedStream) {
11021121
// Handle error on a separate thread using shared pointer.
1103-
std::thread t(oboe_aaudio_presentation_end_thread_proc_shared, sharedStream);
1122+
std::thread t(oboe_aaudio_presentation_end_thread_proc_shared, sharedStream,
1123+
sharedParentStream);
11041124
t.detach();
11051125
} else {
11061126
// Handle error on a separate thread.
@@ -1114,7 +1134,7 @@ void AudioStreamAAudio::internalRoutingChangedCallback(
11141134
AudioStreamAAudio *oboeStream = reinterpret_cast<AudioStreamAAudio*>(userData);
11151135

11161136
// Prevents deletion of the stream if the app is using AudioStreamBuilder::openStream(shared_ptr)
1117-
auto [isStreamAlive, sharedStream] =
1137+
auto [isStreamAlive, sharedStream, sharedParentStream] =
11181138
AAudioStreamCollection::getInstance().getStream(oboeStream);
11191139
if (!isStreamAlive) {
11201140
// Client has closed the stream, no need to call the routing changed callback here.
@@ -1130,7 +1150,7 @@ void AudioStreamAAudio::internalRoutingChangedCallback(
11301150
if (oboeStream->getRoutingCallback() != nullptr) {
11311151
// Handle routing change on a separate thread using shared pointer.
11321152
std::thread t(oboe_aaudio_routing_changed_thread_proc_shared, sharedStream,
1133-
deviceIdsCopy);
1153+
sharedParentStream, deviceIdsCopy);
11341154
t.detach();
11351155
}
11361156
} else {

src/common/FilterAudioStream.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class FilterAudioStream : public AudioStream, AudioStreamCallback {
6262
mHardwareSampleRate = mChildStream->getHardwareSampleRate();
6363
mHardwareChannelCount = mChildStream->getHardwareChannelCount();
6464
mHardwareFormat = mChildStream->getHardwareFormat();
65+
66+
// Link child to parent so parent can be retained in callbacks.
67+
mChildStream->setParentStream(this);
6568
}
6669

6770
virtual ~FilterAudioStream() = default;

0 commit comments

Comments
 (0)