Created
August 9, 2012 07:06
-
-
Save markheath/3301840 to your computer and use it in GitHub Desktop.
NAudio Demo modified to play ShoutCast (courtesy of Stephen Cole)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Data; | |
using System.Drawing; | |
using System.Text; | |
using System.Windows.Forms; | |
using NAudio.Wave; | |
using System.Net; | |
using System.Threading; | |
using System.Net.Sockets; | |
using System.IO; | |
using System.Diagnostics; | |
using System.ComponentModel.Composition; | |
using System.Net.Configuration; | |
using System.Configuration; | |
namespace NAudioDemo | |
{ | |
public partial class MP3StreamingPanel : UserControl | |
{ | |
enum StreamingPlaybackState | |
{ | |
Stopped, | |
Playing, | |
Buffering, | |
Paused | |
} | |
public MP3StreamingPanel() | |
{ | |
InitializeComponent(); | |
this.volumeSlider1.VolumeChanged += new EventHandler(volumeSlider1_VolumeChanged); | |
this.Disposed += this.MP3StreamingPanel_Disposing; | |
} | |
void volumeSlider1_VolumeChanged(object sender, EventArgs e) | |
{ | |
if (this.volumeProvider != null) | |
{ | |
this.volumeProvider.Volume = this.volumeSlider1.Volume; | |
} | |
} | |
private BufferedWaveProvider bufferedWaveProvider; | |
private IWavePlayer waveOut; | |
private volatile StreamingPlaybackState playbackState; | |
private volatile bool fullyDownloaded; | |
private HttpWebRequest webRequest; | |
private VolumeWaveProvider16 volumeProvider; | |
delegate void ShowErrorDelegate(string message); | |
private void ShowError(string message) | |
{ | |
if (this.InvokeRequired) | |
{ | |
this.BeginInvoke(new ShowErrorDelegate(ShowError), message); | |
} | |
else | |
{ | |
MessageBox.Show(message); | |
} | |
} | |
private void UpdateSongName(string text) | |
{ | |
if (this.InvokeRequired) | |
{ | |
this.Invoke(new Action(() => UpdateSongName(text))); | |
} | |
else | |
{ | |
label3.Text = text; | |
} | |
} | |
private void StreamMP3(object state) | |
{ | |
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); | |
SettingsSection section = (SettingsSection)config.GetSection("system.net/settings"); | |
section.HttpWebRequest.UseUnsafeHeaderParsing = true; | |
config.Save(); | |
this.fullyDownloaded = false; | |
string url = (string)state; | |
webRequest = (HttpWebRequest)WebRequest.Create(url); | |
int metaInt = 0; // blocksize of mp3 data | |
webRequest.Headers.Clear(); | |
webRequest.Headers.Add("GET", "/ HTTP/1.0"); | |
// needed to receive metadata informations | |
webRequest.Headers.Add("Icy-MetaData", "1"); | |
webRequest.UserAgent = "WinampMPEG/5.09"; | |
HttpWebResponse resp = null; | |
try | |
{ | |
resp = (HttpWebResponse)webRequest.GetResponse(); | |
} | |
catch(WebException e) | |
{ | |
if (e.Status != WebExceptionStatus.RequestCanceled) | |
{ | |
ShowError(e.Message); | |
} | |
return; | |
} | |
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame | |
try | |
{ | |
// read blocksize to find metadata block | |
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint")); | |
} | |
catch | |
{ | |
} | |
IMp3FrameDecompressor decompressor = null; | |
try | |
{ | |
using (var responseStream = resp.GetResponseStream()) | |
{ | |
var readFullyStream = new ReadFullyStream(responseStream); | |
readFullyStream.metaInt = metaInt; | |
do | |
{ | |
if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4) | |
{ | |
Debug.WriteLine("Buffer getting full, taking a break"); | |
Thread.Sleep(500); | |
} | |
else | |
{ | |
Mp3Frame frame = null; | |
try | |
{ | |
frame = Mp3Frame.LoadFromStream(readFullyStream, true); | |
if (metaInt > 0) | |
UpdateSongName(readFullyStream.SongName); | |
else | |
UpdateSongName("No Song Info in Stream..."); | |
} | |
catch (EndOfStreamException) | |
{ | |
this.fullyDownloaded = true; | |
// reached the end of the MP3 file / stream | |
break; | |
} | |
catch (WebException) | |
{ | |
// probably we have aborted download from the GUI thread | |
break; | |
} | |
if (decompressor == null) | |
{ | |
// don't think these details matter too much - just help ACM select the right codec | |
// however, the buffered provider doesn't know what sample rate it is working at | |
// until we have a frame | |
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate); | |
decompressor = new AcmMp3FrameDecompressor(waveFormat); | |
this.bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat); | |
this.bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves | |
//this.bufferedWaveProvider.BufferedDuration = 250; | |
} | |
int decompressed = decompressor.DecompressFrame(frame, buffer, 0); | |
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed)); | |
bufferedWaveProvider.AddSamples(buffer, 0, decompressed); | |
} | |
} while (playbackState != StreamingPlaybackState.Stopped); | |
Debug.WriteLine("Exiting"); | |
// was doing this in a finally block, but for some reason | |
// we are hanging on response stream .Dispose so never get there | |
decompressor.Dispose(); | |
} | |
} | |
finally | |
{ | |
if (decompressor != null) | |
{ | |
decompressor.Dispose(); | |
} | |
} | |
} | |
private void buttonPlay_Click(object sender, EventArgs e) | |
{ | |
if (playbackState == StreamingPlaybackState.Stopped) | |
{ | |
playbackState = StreamingPlaybackState.Buffering; | |
this.bufferedWaveProvider = null; | |
ThreadPool.QueueUserWorkItem(new WaitCallback(StreamMP3), textBoxStreamingUrl.Text); | |
timer1.Enabled = true; | |
} | |
else if (playbackState == StreamingPlaybackState.Paused) | |
{ | |
playbackState = StreamingPlaybackState.Buffering; | |
} | |
} | |
private void StopPlayback() | |
{ | |
if (playbackState != StreamingPlaybackState.Stopped) | |
{ | |
if (!fullyDownloaded) | |
{ | |
webRequest.Abort(); | |
} | |
this.playbackState = StreamingPlaybackState.Stopped; | |
if (waveOut != null) | |
{ | |
waveOut.Stop(); | |
waveOut.Dispose(); | |
waveOut = null; | |
} | |
timer1.Enabled = false; | |
// n.b. streaming thread may not yet have exited | |
Thread.Sleep(500); | |
ShowBufferState(0); | |
} | |
} | |
private void ShowBufferState(double totalSeconds) | |
{ | |
labelBuffered.Text = String.Format("{0:0.0}s", totalSeconds); | |
progressBarBuffer.Value = (int)(totalSeconds * 1000); | |
} | |
private void timer1_Tick(object sender, EventArgs e) | |
{ | |
if (playbackState != StreamingPlaybackState.Stopped) | |
{ | |
if (this.waveOut == null && this.bufferedWaveProvider != null) | |
{ | |
Debug.WriteLine("Creating WaveOut Device"); | |
this.waveOut = CreateWaveOut(); | |
waveOut.PlaybackStopped += waveOut_PlaybackStopped; | |
this.volumeProvider = new VolumeWaveProvider16(bufferedWaveProvider); | |
this.volumeProvider.Volume = this.volumeSlider1.Volume; | |
waveOut.Init(volumeProvider); | |
progressBarBuffer.Maximum = (int)bufferedWaveProvider.BufferDuration.TotalMilliseconds; | |
} | |
else if (bufferedWaveProvider != null) | |
{ | |
var bufferedSeconds = bufferedWaveProvider.BufferedDuration.TotalSeconds; | |
ShowBufferState(bufferedSeconds); | |
// make it stutter less if we buffer up a decent amount before playing | |
if (bufferedSeconds < 0.5 && this.playbackState == StreamingPlaybackState.Playing && !this.fullyDownloaded) | |
{ | |
this.playbackState = StreamingPlaybackState.Buffering; | |
waveOut.Pause(); | |
Debug.WriteLine(String.Format("Paused to buffer, waveOut.PlaybackState={0}", waveOut.PlaybackState)); | |
} | |
else if (bufferedSeconds > 4 && this.playbackState == StreamingPlaybackState.Buffering) | |
{ | |
waveOut.Play(); | |
Debug.WriteLine(String.Format("Started playing, waveOut.PlaybackState={0}", waveOut.PlaybackState)); | |
this.playbackState = StreamingPlaybackState.Playing; | |
} | |
else if (this.fullyDownloaded && bufferedSeconds == 0) | |
{ | |
Debug.WriteLine("Reached end of stream"); | |
StopPlayback(); | |
} | |
} | |
} | |
} | |
private IWavePlayer CreateWaveOut() | |
{ | |
return new WaveOut(); | |
//return new DirectSoundOut(); | |
} | |
private void MP3StreamingPanel_Disposing(object sender, EventArgs e) | |
{ | |
StopPlayback(); | |
} | |
private void buttonPause_Click(object sender, EventArgs e) | |
{ | |
if (playbackState == StreamingPlaybackState.Playing || playbackState == StreamingPlaybackState.Buffering) | |
{ | |
waveOut.Pause(); | |
Debug.WriteLine(String.Format("User requested Pause, waveOut.PlaybackState={0}", waveOut.PlaybackState)); | |
playbackState = StreamingPlaybackState.Paused; | |
} | |
} | |
private void buttonStop_Click(object sender, EventArgs e) | |
{ | |
StopPlayback(); | |
} | |
private void waveOut_PlaybackStopped(object sender, StoppedEventArgs e) | |
{ | |
Debug.WriteLine("Playback Stopped"); | |
if (e.Exception != null) | |
{ | |
MessageBox.Show(String.Format("Playback Error {0}", e.Exception.Message)); | |
} | |
} | |
} | |
[Export(typeof(INAudioDemoPlugin))] | |
public class MP3StreamingPanelPlugin : INAudioDemoPlugin | |
{ | |
public string Name | |
{ | |
get { return "MP3 Streaming"; } | |
} | |
public Control CreatePanel() | |
{ | |
return new MP3StreamingPanel(); | |
} | |
} | |
} |
Hi, can you please provide me with a console version of this player?
If anyone still has interest in the solution: I wrote a working code to this modified version. Just ask me.
Hi Mwidev,
Can you please share the working code with me?
Also, do you know the site where I can get different .pls links?
@mwidev I'd be grateful if you could provide this code
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can you please publish your MODIFIED ReadFullyStream? I cant find
readFullyStream.metaInt
nor
readFullyStream.SongName
in the link you provided!