/// <summary>
        /// Creates an <see cref="IInputSource"/> object for a given mediaitem.
        /// </summary>
        /// <param name="resourceLocator">Locator instance to the media item to create the input source for.</param>
        /// <param name="mimeType">Mime type of the media item, if present. May be <c>null</c>.</param>
        /// <returns>Input source object for the given <paramref name="resourceLocator"/> or <c>null</c>, if no input source
        /// could be created.</returns>
        public IInputSource CreateInputSource(IResourceLocator resourceLocator, string mimeType)
        {
            if (!CanPlay(resourceLocator, mimeType))
            {
                return(null);
            }
            IInputSource result;

            _accessor = resourceLocator.CreateAccessor();

            AudioCDResourceAccessor acdra = _accessor as AudioCDResourceAccessor;

            if (acdra != null)
            {
                result = BassCDTrackInputSource.Create(acdra.Drive, acdra.TrackNo);
            }
            else
            {
                string filePath = _accessor.ResourcePathName;
                // Network streams
                INetworkResourceAccessor netra = _accessor as INetworkResourceAccessor;
                if (netra != null)
                {
                    result = BassWebStreamInputSource.Create(netra.URL);
                }
                // CDDA
                else if (URLUtils.IsCDDA(filePath))
                {
                    ILocalFsResourceAccessor lfra = _accessor as ILocalFsResourceAccessor;
                    if (lfra == null)
                    {
                        return(null);
                    }
                    using (lfra.EnsureLocalFileSystemAccess())
                        result = BassFsCDTrackInputSource.Create(lfra.LocalFileSystemPath);
                }
                else
                {
                    // Filesystem resources
                    IFileSystemResourceAccessor fsra = _accessor as IFileSystemResourceAccessor;
                    if (fsra == null)
                    {
                        return(null);
                    }
                    if (URLUtils.IsMODFile(filePath))
                    {
                        result = BassMODFileInputSource.Create(fsra);
                    }
                    else
                    {
                        result = BassAudioFileInputSource.Create(fsra);
                    }
                }
            }
            Log.Debug("InputSourceFactory: Creating input source for media resource '{0}' of type '{1}'", _accessor, result.GetType());
            return(result);
        }
Example #2
0
        /// <summary>
        /// Creates an <see cref="IInputSource"/> object for a given mediaitem.
        /// </summary>
        /// <param name="resourceLocator">Locator instance to the media item to create the input source for.</param>
        /// <param name="mimeType">Mime type of the media item, if present. May be <c>null</c>.</param>
        /// <returns>Input source object for the given <paramref name="resourceLocator"/> or <c>null</c>, if no input source
        /// could be created.</returns>
        public IInputSource CreateInputSource(IResourceLocator resourceLocator, string mimeType)
        {
            if (!CanPlay(resourceLocator, mimeType))
            {
                return(null);
            }
            IInputSource result;

            using (IResourceAccessor accessor = resourceLocator.CreateAccessor())
            {
                AudioCDResourceAccessor acdra = accessor as AudioCDResourceAccessor;
                if (acdra != null)
                {
                    result = BassCDTrackInputSource.Create(acdra.Drive, acdra.TrackNo);
                }
                else
                {
                    string filePath = accessor.ResourcePathName;
                    if (URLUtils.IsCDDA(filePath))
                    {
                        ILocalFsResourceAccessor lfra = accessor as ILocalFsResourceAccessor;
                        if (lfra == null)
                        {
                            return(null);
                        }
                        result = BassFsCDTrackInputSource.Create(lfra.LocalFileSystemPath);
                    }
                    else
                    {
                        IFileSystemResourceAccessor fsra = accessor as ILocalFsResourceAccessor;
                        if (fsra == null)
                        {
                            return(null);
                        }
                        if (URLUtils.IsMODFile(filePath))
                        {
                            result = BassMODFileInputSource.Create(fsra);
                        }
                        else
                        {
                            result = BassAudioFileInputSource.Create(fsra);
                        }
                    }
                    // TODO: Handle web streams when we have resource accessors for web URLs: BassWebStreamInputSource.Create(...);
                }
                Log.Debug("InputSourceFactory: Creating input source for media resource '{0}' of type '{1}'", accessor, result.GetType());
            }

            return(result);
        }
Example #3
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);
            }
        }
Example #4
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();
        }