/// <summary> /// Frees all resources used by the output device, including stream by handle. /// </summary> private void Free() { bufferingCancellationTokenSource?.Cancel(); metadataCancellationTokenSource?.Cancel(); StopRecording(); MetadataChanged?.Invoke(Meta.Metadata.Empty); Metadata = Meta.Metadata.Empty; Pause(); Bass.BASS_ChannelStop(handle); Bass.BASS_Stop(); Bass.BASS_StreamFree(handle); Bass.BASS_Free(); }
/// <summary> /// Starts tracking metadata changes. /// </summary> /// <param name="cancellationToken">Cancellation handling token.</param> private void StartMetadataHandle(CancellationToken cancellationToken) { Task.Run(() => { while (!cancellationToken.IsCancellationRequested) { BASS_CHANNELINFO channelInfo = Bass.BASS_ChannelGetInfo(handle); Format format = Format.Unknown; if (channelInfo != null) { format = channelInfo.ctype.ToFormat(); } TAG_INFO tagInfo = new TAG_INFO(url); String songName = null; String artist = null; String title = null; Int32 bitrate = 0; if (BassTags.BASS_TAG_GetFromURL(handle, tagInfo)) { songName = tagInfo.ToString(); artist = tagInfo.artist; title = tagInfo.title; bitrate = tagInfo.bitrate; } IMetadata metadata = new Metadata(songName, artist, title, format, bitrate); if (!metadata.Equals(Metadata)) { Metadata = metadata; MetadataChanged?.Invoke(metadata); } Thread.Sleep(250); } }); }
private void _bufferLoop() { Console.WriteLine("[Buffering thread] Started."); _wavebuffer.DiscardOnBufferOverflow = true; // Buffering loop do { if (_cancel_buffer.IsCancellationRequested) { Console.WriteLine("[Buffering thread] Cancellation requested."); //_cancel_buffer_token.ThrowIfCancellationRequested(); //Console.WriteLine("[Buffering thread] WARNING: Cancellation token is not cleanly set!"); break; } // Checking metadata if (Metadata != stream.Metadata) { this.Metadata = stream.Metadata; Task.Factory.StartNew(() => { Console.WriteLine("[Buffering thread] Metadata has been changed to \"{0}\"", stream.Metadata); Console.WriteLine("[Buffering thread] Delaying because of the buffering...", stream.Metadata); Thread.Sleep(_wavebuffer.BufferedDuration); Console.WriteLine("[Buffering thread] Exposing metadata NOW.", stream.Metadata); if (MetadataChanged != null) { MetadataChanged.Invoke(this, new EventArgs()); } }); } // Seperated buffer long bufferSize = 1024 * (Codec == StreamCodec.MP3 ? 128 : 8); // 128 kB for MP3, 8 kB for OGG/AACplus byte[] buffer = new byte[bufferSize]; int decompressedLength = 0; switch (Codec) { case StreamCodec.MP3: // Decompress the frame decompressedLength = _decoderMp3.DecompressFrame(frame, buffer, 0); // Read next frame frame = Mp3Frame.LoadFromStream(stream); // Add the decompressed frame (samples) into the audio buffer for later playback _wavebuffer.AddSamples(buffer, 0, decompressedLength); break; default: throw new NotSupportedException(); } } while (true); _decoderMp3.Dispose(); stream.Close(); stream.Dispose(); }
private void _listen() { Headers = new Dictionary <string, string>(); foreach (string key in response.Headers.Keys) { // Ignore headers which are not needed for stream analysis if (!key.StartsWith("ice-") && !key.StartsWith("icy-") && !key.StartsWith("content-")) { continue; } Headers.Add(key.ToLower(), response.Headers[key]); } if (HasMetadata) { Metadata = new Dictionary <string, string>(); } ulong bufferSize = HasMetadata ? ulong.Parse(Headers["icy-metaint"]) : 8192 /* 8 kB */; byte[] buffer = new byte[bufferSize]; Stream stream = response.GetResponseStream(); int actualReadLength = 0; int packetLength = 0; while ((actualReadLength += //stream.Read(buffer, actualReadLength, buffer.Length - actualReadLength) (packetLength = stream.Read(buffer, 0, buffer.Length - actualReadLength)) ) > 0) { if (DataReceived != null) { DataReceived.Invoke(this, new LivestreamDataEventArgs(this, buffer.SubArray <byte>(0, packetLength))); } if (actualReadLength < buffer.Length) { continue; } // Reset stream counter actualReadLength = 0; if (HasMetadata) { int length = stream.ReadByte() * 16; // TODO: Handle sudden stream fails by catching length < 0 if (length == 0) { continue; } byte[] metadatabuffer = new byte[length]; stream.Read(metadatabuffer, 0, length); string rawmetadata = Encoding.UTF8.GetString(metadatabuffer).TrimEnd('\0'); // the metadata is padded with \0 bytes // This is some clean code for metadata decoding. :3 while (rawmetadata.Length > 0) { // Get the name string n = rawmetadata.Substring(0, rawmetadata.IndexOf('=')); rawmetadata = rawmetadata.Substring(rawmetadata.IndexOf('=') + 1); // Quoted? char delimitchar = ';'; if ( rawmetadata.StartsWith("'") || rawmetadata.StartsWith("\"") ) { delimitchar = rawmetadata[0]; rawmetadata = rawmetadata.Substring(1); } // Get the value int i = rawmetadata.Contains(delimitchar) ? rawmetadata.IndexOf(delimitchar) : rawmetadata.Length; string v = rawmetadata.Substring(0, i); rawmetadata = rawmetadata.Substring(i); // Add to metadata _setMetadata(n.Trim(), v); // No metadata available anymore if (rawmetadata.Length == 0) { break; } // Remove delimiter(s) from rest if ((rawmetadata = rawmetadata.Substring(1))[0] == ';') { rawmetadata = rawmetadata.Substring(1); } } if (MetadataChanged != null) { MetadataChanged.Invoke(this, new LivestreamMetadataEventArgs(this, this.Metadata)); } } } }
protected virtual void OnMetadataChanged() { MetadataChanged.Invoke(this, EventArgs.Empty); }
protected void RaiseMetadataChanged(SongMetadata metadata) { this.SongMetadata = metadata; MetadataChanged?.Invoke(this, new MediaStreamerMetadataChangedEventArgs(metadata)); }
/// <summary> /// Raise the metadata changed event. /// </summary> /// <remarks> /// Raises the metadata changed event. /// </remarks> /// <param name="metadata">The metadata that changed.</param> protected virtual void OnMetadataChanged(Metadata metadata) { MetadataChanged?.Invoke(this, new MetadataChangedEventArgs(metadata)); }
/// <summary> /// Explicitly invokes <see cref="MetadataChanged"/> to notify listeners. /// </summary> public void InvokeMetadataChanged() { MetadataChanged?.Invoke(this, EventArgs.Empty); }