private void DisposeDecodingChannel() { if (_decodingChannel != null) { _decodingChannel.Stop(); _decodingChannel.Free(); _decodingChannel = null; } }
private void CreateDecodingChannel(string audioFilePath) { _decodingChannel = Channel.CreateFileStreamForDecoding(audioFilePath, _useFloatingPoint); _currentFilePath = audioFilePath; _channelLength = _decodingChannel.GetLength(); _decodePosition = 0; lock (_locker) { Monitor.Pulse(_locker); } }
/// <summary> /// Plays the playlist from the current item index. /// </summary> public void Play(double initialPosition, bool startPaused) { try { if (_isPlaying) { if (_currentLoop != null) { //Tracing.Log("Player.Play -- Stopping current loop..."); StopLoop(); } //Tracing.Log("Player.Play -- Stopping playback..."); Stop(); } RemoveSyncCallbacks(); _currentLoop = null; _positionOffset = 0; _currentMixPlaylistIndex = Playlist.CurrentItemIndex; // How many channels are left? int channelsToLoad = Playlist.Items.Count - Playlist.CurrentItemIndex; // If there are more than 2, just limit to 2 for now. The other channels are loaded dynamically. if (channelsToLoad > 2) channelsToLoad = 2; // Check for channels to load if (channelsToLoad == 0) throw new Exception("Error in Player.Play: There aren't any channels to play!"); // Load the current channel and the next channel if it exists for (int a = Playlist.CurrentItemIndex; a < Playlist.CurrentItemIndex + channelsToLoad; a++) _playlist.Items[a].Load(_useFloatingPoint); // Start decoding first playlist item //_decodingService.StartDecodingFile(_playlist.Items[0].AudioFile.FilePath, _positionOffset); try { // Create the streaming channel (set the frequency to the first file in the list) //Tracing.Log("Player.Play -- Creating streaming channel (SampleRate: " + _playlist.CurrentItem.AudioFile.SampleRate + " Hz, FloatingPoint: true)..."); #if IOS _streamProc = new STREAMPROC(StreamCallbackIOS); #else _streamProc = new STREAMPROC(StreamCallback); #endif _streamChannel = Channel.CreateStream(_playlist.CurrentItem.AudioFile.SampleRate, 2, _useFloatingPoint, _streamProc); //Tracing.Log("Player.Play -- Creating time shifting channel..."); _fxChannel = Channel.CreateStreamForTimeShifting(_streamChannel.Handle, true, _useFloatingPoint); //_fxChannel = Channel.CreateStreamForTimeShifting(_streamChannel.Handle, false, _useFloatingPoint); //_fxChannel = _streamChannel; } catch(Exception ex) { // Raise custom exception with information (so the client application can maybe deactivate floating point for example) PlayerCreateStreamException newEx = new PlayerCreateStreamException("The player has failed to create the stream channel (" + ex.Message + ").", ex); newEx.Decode = true; newEx.UseFloatingPoint = true; newEx.SampleRate = _playlist.CurrentItem.AudioFile.SampleRate; throw newEx; } // Check driver type if (_device.DriverType == DriverType.DirectSound) { try { // Create mixer stream Tracing.Log("Player.Play -- Creating mixer channel (DirectSound)..."); _mixerChannel = MixerChannel.CreateMixerStream(_playlist.CurrentItem.AudioFile.SampleRate, 2, _useFloatingPoint, false); _mixerChannel.AddChannel(_fxChannel.Handle); //_mixerChannel = _fxChannel; AddBPMCallbacks(); } catch (Exception ex) { // Raise custom exception with information (so the client application can maybe deactivate floating point for example) PlayerCreateStreamException newEx = new PlayerCreateStreamException("The player has failed to create the time shifting channel.", ex); newEx.UseFloatingPoint = true; newEx.UseTimeShifting = true; newEx.SampleRate = _playlist.CurrentItem.AudioFile.SampleRate; throw newEx; } } #if !IOS && !ANDROID else if (_device.DriverType == DriverType.ASIO) { try { // Create mixer stream Tracing.Log("Player.Play -- Creating mixer channel (ASIO)..."); _mixerChannel = MixerChannel.CreateMixerStream(_playlist.CurrentItem.AudioFile.SampleRate, 2, _useFloatingPoint, true); _mixerChannel.AddChannel(_fxChannel.Handle); } catch (Exception ex) { // Raise custom exception with information (so the client application can maybe deactivate floating point for example) PlayerCreateStreamException newEx = new PlayerCreateStreamException("The player has failed to create the time shifting channel.", ex); newEx.DriverType = DriverType.ASIO; newEx.UseFloatingPoint = true; newEx.UseTimeShifting = true; newEx.Decode = true; newEx.SampleRate = _playlist.CurrentItem.AudioFile.SampleRate; throw newEx; } // Set floating point BassAsio.BASS_ASIO_ChannelSetFormat(false, 0, BASSASIOFormat.BASS_ASIO_FORMAT_FLOAT); // Create callback asioProc = new ASIOPROC(AsioCallback); try { // Enable and join channels (for stereo output Tracing.Log("Player.Play -- Enabling ASIO channels..."); BassAsio.BASS_ASIO_ChannelEnable(false, 0, asioProc, new IntPtr(_mixerChannel.Handle)); Tracing.Log("Player.Play -- Joining ASIO channels..."); BassAsio.BASS_ASIO_ChannelJoin(false, 1, 0); // Set sample rate Tracing.Log("Player.Play -- Set ASIO sample rates..."); BassAsio.BASS_ASIO_ChannelSetRate(false, 0, _playlist.CurrentItem.AudioFile.SampleRate); BassAsio.BASS_ASIO_SetRate(_playlist.CurrentItem.AudioFile.SampleRate); } catch (Exception ex) { // Raise custom exception with information (so the client application can maybe deactivate floating point for example) PlayerCreateStreamException newEx = new PlayerCreateStreamException("The player has failed to enable or join ASIO channels.", ex); newEx.DriverType = DriverType.ASIO; newEx.SampleRate = _playlist.CurrentItem.AudioFile.SampleRate; throw newEx; } // Start playback Tracing.Log("Player.Play -- Starting ASIO buffering..."); if (!BassAsio.BASS_ASIO_Start(0)) { // Get BASS error BASSError error = Bass.BASS_ErrorGetCode(); // Raise custom exception with information (so the client application can maybe deactivate floating point for example) PlayerCreateStreamException newEx = new PlayerCreateStreamException("The player has failed to create the ASIO channel (" + error.ToString() + ").", null); newEx.DriverType = DriverType.ASIO; newEx.UseFloatingPoint = true; newEx.UseTimeShifting = true; newEx.Decode = true; newEx.SampleRate = _playlist.CurrentItem.AudioFile.SampleRate; throw newEx; } } else if (_device.DriverType == DriverType.WASAPI) { // Create mixer stream Tracing.Log("Player.Play -- Creating mixer channel (WASAPI)..."); _mixerChannel = MixerChannel.CreateMixerStream(_playlist.CurrentItem.AudioFile.SampleRate, 2, true, true); _mixerChannel.AddChannel(_fxChannel.Handle); // Start playback if (!BassWasapi.BASS_WASAPI_Start()) { // Get error BASSError error = Bass.BASS_ErrorGetCode(); throw new Exception("Player.Play error: Error playing files in WASAPI: " + error.ToString()); } } #endif // Set initial volume _mixerChannel.Volume = Volume; // Load 18-band equalizer //Tracing.Log("Player.Play -- Creating equalizer (Preset: " + _currentEQPreset + ")..."); AddEQ(_currentEQPreset); // Check if EQ is bypassed if (_isEQBypassed) { // Reset EQ //Tracing.Log("Player.Play -- Equalizer is bypassed; resetting EQ..."); ResetEQ(); } // Check if the song must be looped if (_repeatType == RepeatType.Song) _playlist.CurrentItem.Channel.SetFlags(BASSFlag.BASS_SAMPLE_LOOP, BASSFlag.BASS_SAMPLE_LOOP); long length = _playlist.CurrentItem.Channel.GetLength(); SetSyncCallback(length); _isPlaying = true; // Only the DirectSound mode needs to start the main channel since it's not in decode mode. if (_device.DriverType == DriverType.DirectSound) { // For iOS: This is required to update the AirPlay/remote player status Base.Start(); // Start playback //Tracing.Log("Player.Play -- Starting DirectSound playback..."); _mixerChannel.Play(false); if (startPaused) { if(initialPosition > 0) SetPosition(initialPosition); Base.Pause(); } _isPaused = startPaused; } // StartEncode(EncoderType.OGG); // StartCast(new CastServerParams() // { // Bitrate = 128, // Name = "Sessions Test Server", // Url = "localhost:8000", // Password = "******" // }); // Raise audio file finished event (if an event is subscribed) if (OnPlaylistIndexChanged != null) { PlayerPlaylistIndexChangedData data = new PlayerPlaylistIndexChangedData(); data.IsPlaybackStopped = false; data.AudioFileStarted = _playlist.CurrentItem.AudioFile; data.PlaylistName = "New playlist 1"; data.PlaylistCount = _playlist.Items.Count; data.PlaylistIndex = _playlist.CurrentItemIndex; if (Playlist.CurrentItemIndex < Playlist.Items.Count - 2) data.NextAudioFile = Playlist.Items[Playlist.CurrentItemIndex + 1].AudioFile; OnPlaylistIndexChanged(data); } } catch (Exception ex) { Tracing.Log("Player.Play error: " + ex.Message + "\n" + ex.StackTrace); throw; } }
/// <summary> /// Frees the device currently used for playback. /// </summary> public void FreeDevice() { if (!_isDeviceInitialized) return; #if !IOS && !ANDROID // Check driver type if (_device.DriverType == DriverType.ASIO) { // Free ASIO device if (!BassAsio.BASS_ASIO_Free()) { // Get error BASSError error = Bass.BASS_ErrorGetCode(); throw new Exception("Error freeing ASIO device: " + error.ToString()); } } else if (_device.DriverType == DriverType.WASAPI) { // Free WASAPI device if (!BassWasapi.BASS_WASAPI_Free()) { // Get error BASSError error = Bass.BASS_ErrorGetCode(); throw new Exception("Error freeing WASAPI device: " + error.ToString()); } } #endif Base.Free(); _mixerChannel = null; _device = null; _isDeviceInitialized = false; }
/// <summary> /// Disposes the current channel. /// </summary> public void Dispose() { #if !PCL && !WINDOWSSTORE && !WINDOWS_PHONE // Check if a channel already exists if (_channel != null) { try { // Stop and free channel Console.WriteLine("Freeing channel " + AudioFile.FilePath + "..."); _channel.Stop(); _channel.Free(); _channel = null; } catch(Exception ex) { if(_audioFile != null) Console.WriteLine("Could not dispose channel " + AudioFile.FilePath + ": " + ex.Message); } // // Check if the channel is in use // if (channel.IsActive() == BASSActive.BASS_ACTIVE_PLAYING) // { // // Stop and free channel // channel.Stop(); // channel.Free(); // channel = null; // } } #endif _isLoaded = false; }
/// <summary> /// Loads the current channel and audio file metadata. /// </summary> public void Load(bool useFloatingPoint) { // Load audio file metadata _audioFile.RefreshMetadata(); #if !PCL && !WINDOWSSTORE && !WINDOWS_PHONE // Check if a channel already exists if(_channel != null) Dispose(); // Load channel _channel = Channel.CreateFileStreamForDecoding(_audioFile.FilePath, useFloatingPoint); _lengthBytes = _channel.GetLength(); // Divide length by 2 if using floating point if (_channel.IsFloatingPoint) _lengthBytes /= 2; // Check if this is a FLAC file over 44100Hz if (_audioFile.FileType == AudioFileFormat.FLAC && _audioFile.SampleRate > 44100) _lengthBytes = (long)((float)_lengthBytes * 1.5f); _lengthSamples = ConvertAudio.ToPCM(_lengthBytes, (uint)_audioFile.BitsPerSample, 2); _lengthMilliseconds = (int)ConvertAudio.ToMS(_lengthSamples, (uint)_audioFile.SampleRate); _lengthString = Conversion.MillisecondsToTimeString((ulong)_lengthMilliseconds); #endif _isLoaded = true; }