private bool handlePlaybackInterrupt(InterruptedException interruption, SeekExecutor seekExecutor)
        {
            java.lang.Thread.interrupted();

            if (checkStopped())
            {
                markerTracker.trigger(STOPPED);
                return(false);
            }
            else if (checkPendingSeek(seekExecutor))
            {
                // Double-check, might have received a stop request while seeking
                if (checkStopped())
                {
                    markerTracker.trigger(STOPPED);
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            else if (interruption != null)
            {
                System.Threading.Thread.CurrentThread.Interrupt();
                throw new FriendlyException("The track was unexpectedly terminated.", SUSPICIOUS, interruption);
            }
            else
            {
                return(true);
            }
        }
        /// <summary>
        /// Performs a seek if it scheduled. </summary>
        /// <param name="seekExecutor"> Callback for performing a seek on the track </param>
        /// <returns> True if a seek was performed </returns>
        private bool checkPendingSeek(SeekExecutor seekExecutor)
        {
            if (!audioTrack.Seekable)
            {
                return(false);
            }

            long seekPosition;

            lock (actionSynchronizer)
            {
                seekPosition = pendingSeek.get();

                if (seekPosition == -1)
                {
                    return(false);
                }

                log.LogDebug("Track {} interrupted for seeking to {}.", audioTrack.Identifier, seekPosition);
                applySeekState(seekPosition);
            }

            try
            {
                seekExecutor.performSeek(seekPosition);
            }
            catch (System.Exception e)
            {
                throw ExceptionTools.wrapUnfriendlyExceptions("Something went wrong when seeking to a position.", FAULT, e);
            }

            return(true);
        }
        /// <summary>
        /// Execute the read and seek loop for the track. </summary>
        /// <param name="readExecutor"> Callback for reading the track </param>
        /// <param name="seekExecutor"> Callback for performing a seek on the track, may be null on a non-seekable track </param>
        public virtual void executeProcessingLoop(ReadExecutor readExecutor, SeekExecutor seekExecutor)
        {
            bool proceed = true;

            checkPendingSeek(seekExecutor);

            while (proceed)
            {
                state.set(AudioTrackState.PLAYING);
                proceed = false;

                try
                {
                    // An interrupt may have been placed while we were handling the previous one.
                    if (java.lang.Thread.interrupted() && !handlePlaybackInterrupt(null, seekExecutor))
                    {
                        break;
                    }

                    InterruptibleForSeek = true;
                    readExecutor.performRead();
                    InterruptibleForSeek = false;

                    // Must not finish before terminator frame has been consumed the user may still want to perform seeks until then
                    waitOnEnd();
                }
                catch (System.Exception e)
                {
                    InterruptibleForSeek = false;
                    InterruptedException interruption = findInterrupt(e);

                    if (interruption != null)
                    {
                        proceed = handlePlaybackInterrupt(interruption, seekExecutor);
                    }
                    else
                    {
                        throw ExceptionTools.wrapUnfriendlyExceptions("Something went wrong when decoding the track.", FAULT, e);
                    }
                }
            }
        }