@@ -33,7 +33,7 @@ public class LocalAudioTrackExecutor implements AudioTrackExecutor {
33
33
private final boolean useSeekGhosting ;
34
34
private final AudioFrameBuffer frameBuffer ;
35
35
private final AtomicReference <Thread > playingThread = new AtomicReference <>();
36
- private final AtomicBoolean queuedStop = new AtomicBoolean (false );
36
+ private final AtomicBoolean disposedOf = new AtomicBoolean (false );
37
37
private final AtomicLong queuedSeek = new AtomicLong (-1 );
38
38
private final AtomicLong lastFrameTimecode = new AtomicLong (0 );
39
39
private final AtomicReference <AudioTrackState > state = new AtomicReference <>(AudioTrackState .INACTIVE );
@@ -56,7 +56,7 @@ public LocalAudioTrackExecutor(InternalAudioTrack audioTrack, AudioConfiguration
56
56
57
57
this .audioTrack = audioTrack ;
58
58
AudioDataFormat currentFormat = configuration .getOutputFormat ();
59
- this .frameBuffer = configuration .getFrameBufferFactory ().create (bufferDuration , currentFormat , queuedStop );
59
+ this .frameBuffer = configuration .getFrameBufferFactory ().create (bufferDuration , currentFormat , disposedOf );
60
60
this .processingContext = new AudioProcessingContext (configuration , frameBuffer , playerOptions , currentFormat );
61
61
this .useSeekGhosting = useSeekGhosting ;
62
62
}
@@ -92,7 +92,15 @@ public void execute(TrackStateListener listener) {
92
92
log .debug ("Cleared a stray interrupt." );
93
93
}
94
94
95
- if (playingThread .compareAndSet (null , Thread .currentThread ())) {
95
+ synchronized (actionSynchronizer ) {
96
+ if (disposedOf .get ()) {
97
+ log .warn ("Attempt to execute executor that has been disposed of" );
98
+ return ;
99
+ }
100
+ }
101
+
102
+ boolean wasUpdated = playingThread .compareAndSet (null , Thread .currentThread ());
103
+ if (wasUpdated ) {
96
104
log .debug ("Starting to play track {} locally with listener {}" , audioTrack .getInfo ().identifier , listener );
97
105
98
106
state .set (AudioTrackState .LOADING );
@@ -105,7 +113,7 @@ public void execute(TrackStateListener listener) {
105
113
// Temporarily clear the interrupted status so it would not disrupt listener methods.
106
114
interrupt = findInterrupt (e );
107
115
108
- if (interrupt != null && checkStopped () ) {
116
+ if (interrupt != null ) {
109
117
log .debug ("Track {} was interrupted outside of execution loop." , audioTrack .getIdentifier ());
110
118
} else {
111
119
frameBuffer .setTerminateOnEmpty ();
@@ -140,31 +148,18 @@ public void execute(TrackStateListener listener) {
140
148
@ Override
141
149
public void stop () {
142
150
synchronized (actionSynchronizer ) {
151
+ disposedOf .set (true );
143
152
Thread thread = playingThread .get ();
144
153
145
154
if (thread != null ) {
146
155
log .debug ("Requesting stop for track {}" , audioTrack .getIdentifier ());
147
-
148
- queuedStop .compareAndSet (false , true );
149
156
thread .interrupt ();
150
157
} else {
151
158
log .debug ("Tried to stop track {} which is not playing." , audioTrack .getIdentifier ());
152
159
}
153
160
}
154
161
}
155
162
156
- /**
157
- * @return True if the track has been scheduled to stop and then clears the scheduled stop bit.
158
- */
159
- public boolean checkStopped () {
160
- if (queuedStop .compareAndSet (true , false )) {
161
- state .set (AudioTrackState .STOPPING );
162
- return true ;
163
- }
164
-
165
- return false ;
166
- }
167
-
168
163
/**
169
164
* Wait until all the frames from the frame buffer have been consumed. Keeps the buffering thread alive to keep it
170
165
* interruptible for seeking until buffer is empty.
@@ -176,24 +171,6 @@ public void waitOnEnd() throws InterruptedException {
176
171
frameBuffer .waitForTermination ();
177
172
}
178
173
179
- /**
180
- * Interrupt the buffering thread, either stop or seek should have been set beforehand.
181
- *
182
- * @return True if there was a thread to interrupt.
183
- */
184
- public boolean interrupt () {
185
- synchronized (actionSynchronizer ) {
186
- Thread thread = playingThread .get ();
187
-
188
- if (thread != null ) {
189
- thread .interrupt ();
190
- return true ;
191
- }
192
-
193
- return false ;
194
- }
195
- }
196
-
197
174
@ Override
198
175
public long getPosition () {
199
176
long seek = queuedSeek .get ();
@@ -336,7 +313,7 @@ private void interruptForSeek() {
336
313
private boolean handlePlaybackInterrupt (InterruptedException interruption , SeekExecutor seekExecutor ) {
337
314
Thread .interrupted ();
338
315
339
- if (checkStopped ()) {
316
+ if (disposedOf . get ()) {
340
317
markerTracker .trigger (STOPPED );
341
318
return false ;
342
319
}
@@ -345,7 +322,7 @@ private boolean handlePlaybackInterrupt(InterruptedException interruption, SeekE
345
322
346
323
if (seekResult != SeekResult .NO_SEEK ) {
347
324
// Double-check, might have received a stop request while seeking
348
- if (checkStopped ()) {
325
+ if (disposedOf . get ()) {
349
326
markerTracker .trigger (STOPPED );
350
327
return false ;
351
328
} else {
0 commit comments