This project has moved and is read-only. For the latest updates, please go here.

Question about MP3 Streaming

Sep 11, 2012 at 12:36 AM
Edited Sep 11, 2012 at 12:40 AM

Hello there,

I am currently working developing an app during my free time to control my speakers via Windows phone (basic stuff like picking from a list of mp3s stored in my hard drive and the play them straight away).

It worked great until I decided to split the computer application in two (a server and client), the server handles the communication with the phone and passes the data into a slave machine (like a laptop).  I took the same approach given in the NAudio.MP3 Stream, sending individual mp3 frames via TCP (will move into UDP once I get the hang of it) to the client and then decompressing the via format and associating it with a DirectSoundOut.

Overwriting the file that is being played/pausing/resuming works fine but I am having trouble implementing a loop song feature, since DirectSoundOut object never changes it state to stopped (I assume this has to do with the fact that BufferedWaveProvider is a open stream with no termination) I am unable to detect that the song has finished and that I can reuse the buffer without having to redownload the MP3.

My code to handle the incoming MP3frames is as follow:

 

        private void StreamMP3()
        {
            try
            {
                Byte[] buffer = new byte[65536];
                Mp3Frame frame = null;
                Int32 CArtistID = -1;
                Int32 CSongID = -1;

                while (true)
                {
                    if (CArtistID != ArtistID || CSongID != SongID)
                    {

                        CArtistID = ArtistID;
                        CSongID = SongID;

                        DisposeObjects();

                        this.SoundOut = new DirectSoundOut();
                        this.SoundOut.PlaybackStopped += SoundOut_PlaybackStopped;
                    }


                Waiting:

                    if (FrameCounter >= FrameList.Count)
                    {
                        Thread.Sleep(250);
                        goto Waiting;
                    }

 
                    frame = FrameList[FrameCounter];

                    if (frame != null)
                    {
                        if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
                            Thread.Sleep(500);

                        if (decompressor == null)
                        {
                            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(100);

                            int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
                            bufferedWaveProvider.AddSamples(buffer, 0, decompressed);

                            this.volumeProvider = new VolumeWaveProvider16(bufferedWaveProvider);

                            SoundOut.Init(volumeProvider);
                            SoundOut.Play();

                        }
                        else
                        {
                            int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
                            bufferedWaveProvider.AddSamples(buffer, 0, decompressed);
                        }

                        FrameCounter++;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

 

 

I would like to ask what would be the best approach to achieve my goal as I am kind of clueless right now and been looking online for days.

Thanks for reading!

 

Alex

Sep 11, 2012 at 2:19 PM

I'd make my own custom IWaveProvider that uses BufferedWaveProvider but can be told that there is no more data to come. Then, in the Read method, if that flag is set and the bufferedWaveProvider has no queued bytes, return 0