Being notified by WasApi when playing a song reaches EOF

Jan 19, 2015 at 6:52 PM
I have a simple player, with a list of songs to play.
A timer 10 times / second adjusts a Spectrum. The same timer SHOULD start the next song, if one if finished. First I tried to catch the Position and confront it with the total Length,
but that fails as (for a reason still to be discoverd) the song freequently simply restarts at the beginning.
Then I thought: there must be an event "Play is at EOF". I did not find it, but there is a STOPPED with (ab)normal end indication, that might be useful. I grew up with Basic, and it is only with this project, that I changed to c#. All goes well, but Events are so different!
I searched and read today for several hours, but I don't understand how to implement the STOPPED event in my source, so that the variable GotEOFNotification will be set to true. I see how you catch an event, but I don't discover which are the available events! RaiseEvent is VB only.
Probably it's only 2 or 3 lines, but which and where? Could you help me out?
        bool GotEOFNotification = false;
        ISoundOut soundOut = new WasapiOut();
        IWaveSource soundSource;
        MediaFoundationDecoder mediafoundationDecoder;
        LineSpectrum _lineSpectrum;
        void startPlay()
        {
            ..........
            soundSource = CodecFactory.Instance.GetCodec(fileName);
            var spectrumProvider = new BasicSpectrumProvider(soundSource.WaveFormat.Channels, soundSource.WaveFormat.SampleRate, fftSize);
            _lineSpectrum = new LineSpectrum(fftSize) {...}
            var notificationSource = new SingleBlockNotificationStream(soundSource);
            notificationSource.SingleBlockRead += (s, a) => spectrumProvider.Add(a.Left, a.Right);
            soundSource = notificationSource.ToWaveSource(16);
            soundOut.Initialize(new LoopStream(soundSource)); 
            soundOut.StoppedEvent.............. ???????????????????? ............ {
                 GotEOFNotification = true;
            }
            soundOut.Play();
            timer1.Enabled = true;
        }
        void timer_Tick(object sender, EventArgs e)
        {
            .......
            if (GotEOFNotification)
            {
                GotEOFNotification = false;
                if (ItemPlaying < playList.Items.Count)
                   PlayNext();
                else
                   stopPlay();
                }
            }
            ........
        }
   
Coordinator
Jan 20, 2015 at 6:16 PM
It starts from beginning because you are using the loopstream. Remove the usage of the loopstream class and it won t start from beginning anymore.
Jan 21, 2015 at 6:38 AM
Thank you. That's the problem with an example. One copies it, takes the parts that are needed, in this case without considering ALL that's inside!
Remains the "End of file" event, does that exists? I found out that Stopped is raised when I invoke the Stop method, not the EOF event.
Jan 22, 2015 at 8:02 PM
Your remark on the LoopStream made me think that a simple list of all usable (not internal) classes if missing in the documentation. It is easier to understand the examples, if I can see in seconds, what class is available and what it does.
So I wrote a little VB program that lists all classes and its summary in a html file. Could it be useful for you: see the result here and the source of the program here.
If I can contribute in other ways to get more documentation, just tell me your ideas.
Coordinator
Jan 26, 2015 at 9:02 PM
Well, the LoopStream class would provide a StreamFinished-event. You could set EnableLoop to false and use the StreamFinished event as your "EOF event".
For the documentation I would tend to use something like sandcastle to generate a documentation. Unfortunately, currently not all members of cscore got documented in form of xml comments.
Feb 18, 2015 at 7:10 PM
I solved my problem, of how to know when a song reaches EOF. Using the Loopstream was a mistake, I'm using now a GetCodec(fileName) -> SingleBlockNotificationStream(..) and I added the reporting of the EOF as a new notification. I did it as follows:
new (empty!) class SingleBlockStreamFinishedEventArgs :
using System;

namespace CSCore.Streams
{
    public class SingleBlockStreamFinishedEventArgs : EventArgs
    {
        public SingleBlockStreamFinishedEventArgs()
        {
           
        }
    }
}
Two modifications in SingleBlockNotificationStream:
in the declarations
           public event EventHandler<SingleBlockStreamFinishedEventArgs> SingleBlockStreamFinished;
and in the Read method
            if (read == 0 && SingleBlockStreamFinished != null) // signal END OF STREAM
                SingleBlockStreamFinished(this, new SingleBlockStreamFinishedEventArgs());
I can now add a handler in my main, that gets signalled when a stream reached EOF:
           notificationSource.SingleBlockStreamFinished += (s, a) => EOF=true;
used in my timer-loop to start a new song.

Works perfectly and it does not cause the glitch that VLC produces since some years (I have a rather slow DSL) when too many things are imported from the web before playing a new song!

For anybody who needs to do a similar job!

And thank you very much for this wonderful library. Little by little I start understanding bits and pieces.
Feb 18, 2015 at 7:41 PM
To Filoe: I saw that you added me to the credits and I'm the only one with a coded name; I invite you, to use my full name, if you whish, so everybody may see I'm Dutch: Martien van der Burgt. You may then delete this entry too.
Coordinator
Feb 19, 2015 at 10:17 PM
No problem. Fixed it.