Ejemplo n.º 1
0
        /// <summary>
        /// Callback function for the outputstream.
        /// </summary>
        /// <param name="streamHandle">Bass stream handle that requests sample data.</param>
        /// <param name="buffer">Buffer to write the sampledata to.</param>
        /// <param name="requestedBytes">Requested number of bytes.</param>
        /// <param name="userData"></param>
        /// <returns>Number of bytes read.</returns>
        private int OutputStreamWriteProc(int streamHandle, IntPtr buffer, int requestedBytes, IntPtr userData)
        {
            IInputSource inputSource;

            lock (_syncObj)
            {
                if (_state == SessionState.Reset)
                {
                    return(0);
                }
                inputSource = _currentInputSource;
                if (inputSource == null)
                {
                    _state = SessionState.Ended;
                    return((int)BASSStreamProc.BASS_STREAMPROC_END);
                }
            }

            try
            {
                BassStream stream = inputSource.OutputStream;
                int        read   = stream.Read(buffer, requestedBytes);

                bool doCheckNextInputSource = false;
                lock (_syncObj)
                    if (!_isAwaitingNextInputSource && stream.GetPosition() > stream.Length.Subtract(REQUEST_NEXT_ITEM_THRESHOLD))
                    { // Near end of the stream - make sure that next input source is available
                        _isAwaitingNextInputSource = true;
                        doCheckNextInputSource     = true;
                    }
                if (doCheckNextInputSource)
                {
                    _playbackProcessor.CheckInputSourceAvailable();
                }

                if (read > 0)
                {
                    // Normal case, we have finished
                    return(read);
                }

                // Old buffer ran out of samples - either we can get another valid input source below or we are finished. End wait state.
                _isAwaitingNextInputSource = false;

                // Nothing could be read from old input source. Second try: Next input source.
                IInputSource newInputSource = _playbackProcessor.PeekNextInputSource();

                // Special treatment for CD drives: If the new input source is from the same audio CD drive, we must take the stream over
                BassCDTrackInputSource bcdtisOld = inputSource as BassCDTrackInputSource;
                BassCDTrackInputSource bcdtisNew = newInputSource as BassCDTrackInputSource;
                if (bcdtisOld != null && bcdtisNew != null)
                {
                    if (bcdtisOld.SwitchTo(bcdtisNew))
                    {
                        _playbackProcessor.ClearNextInputSource();
                        return(OutputStreamWriteProc(streamHandle, buffer, requestedBytes, userData));
                    }
                }

                lock (_syncObj)
                {
                    _currentInputSource = null;
                    _controller.ScheduleDisposeObject_Async(inputSource);
                    if (newInputSource == null)
                    {
                        _state = SessionState.Ended;
                        return((int)BASSStreamProc.BASS_STREAMPROC_END);
                    }
                }

                if (!MatchesInputSource(newInputSource))
                { // The next available input source is not compatible, so end our stream. The playback processor will start a new playback session later.
                    lock (_syncObj)
                        _state = SessionState.Ended;
                    return((int)BASSStreamProc.BASS_STREAMPROC_END);
                }
                _playbackProcessor.ClearNextInputSource(); // Should be the contents of newInputSource
                lock (_syncObj)
                {
                    _currentInputSource = newInputSource;
                    _state = SessionState.Playing;
                }

                // Next try
                return(OutputStreamWriteProc(streamHandle, buffer, requestedBytes, userData));
            }
            catch (Exception)
            {
                // We might come here due to a race condition. To avoid that, we would have to employ a new manual locking mechanism
                // to avoid that during the execution of this method, no methods are called from outside which change our
                // streams/partner instances.
                return(0);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Moves to the next available input source.
        /// </summary>
        /// <remarks>
        /// This method blocks the calling thread as long as the switching to the new input source lasts. This includes
        /// the crossfading duration (if crossfading is done) or the fading out (if no crossfading is done).
        /// </remarks>
        protected void MoveToNextInputSource_Sync()
        {
            // TODO: Insert gap between tracks if we are in playback mode Normal
            IInputSource inputSource = PeekNextInputSource();

            if (_playbackSession != null)
            {
                BassCDTrackInputSource bcdtisNew          = inputSource as BassCDTrackInputSource;
                IInputSource           currentInputSource = _playbackSession.CurrentInputSource;
                BassCDTrackInputSource bcdtisOld          = currentInputSource as BassCDTrackInputSource;
                if (bcdtisOld != null && bcdtisNew != null)
                {
                    // Special treatment for CD drives: If the new input source is from the same audio CD drive, we must take the stream over
                    if (bcdtisOld.SwitchTo(bcdtisNew))
                    {
                        _playbackSession.IsAwaitingNextInputSource = false;
                        ClearNextInputSource();
                        return;
                    }
                }
                // TODO: Trigger crossfading if CF is configured
                _playbackSession.End(_internalState == InternalPlaybackState.Playing); // Only wait for fade out when we are playing
            }

            _internalState = InternalPlaybackState.Playing;
            if (inputSource == null)
            {
                Log.Debug("No more input sources available.");
            }
            else
            {
                Log.Debug("Playing next input source '{0}'", inputSource);
            }
            if (_playbackSession != null)
            {
                if (_playbackSession.InitializeWithNewInputSource(inputSource))
                {
                    _playbackSession.Play();
                    ClearNextInputSource();
                    return;
                }
                _playbackSession.Dispose();
                _playbackSession = null;
            }

            if (inputSource == null)
            {
                Ended();
                return;
            }

            _playbackSession = PlaybackSession.Create(_controller);
            if (_playbackSession == null)
            {
                _internalState = InternalPlaybackState.Stopped;
                return;
            }
            _playbackSession.Play();

            _internalState = InternalPlaybackState.Playing;
            _controller.StateReady();
        }