0

i'm working on a project in which sounds (.wav-files) should be played when some actions happen. The files are on the local drive in a subfolder of the project/location.

For playing the sounds synchronously one after another I have the following class:

public class Player
{
    private readonly BlockingCollection<Sound> _queue;

    public Player()
    {
        _queue = new BlockingCollection<Sound>();
        Task.Factory.StartNew(Play);
    }

    public void PlaySound(Sound sound)
    {
        _queue.Add(sound);
    }

    private void Play()
    {
        foreach (var sound in _queue.GetConsumingEnumerable())
        {
             var filename = GetFile(sound);
             using (var player = new System.Media.SoundPlayer(filename))
             {
                 player.PlaySync();
             }
        }
    }
}

The problem I encounter sometimes is, that the PlaySync method runs for over a minute until the sound is played. The soundfiles have a duration of 0,2 seconds. This only happens on the first call of the method. I tried laoding the files into memory and call the Load/LoadAsync method of the SoundPlayer class. This has no effect on the situation. The PlaySync-call sometimes need more than a minute.

I tried also the System.Windows.Media.MediaPlayer class but it looks to me that this class can only play sounds asynchronous and I need the sounds synchronous. The events like MediaEnded on this class are never called.

I tried for many days now to find a solution for this problem but didn't find anything. Could anyone help me?

I'm using WPF with the MVVM framework Prism and this class is instantiated inside a viewmodel.

  • Are you aware of the difference between synchronous and asynchronous? – Geoff James May 10 '17 at 15:03
  • Have you tried to play it in another thread (even if you need sync, there are ways to synchronice both threads)? Also, is very strange it takes so long to load a wav, I use it myself for playing audio effects and the firing is immediate even when loading the files for first time, have you checked the file format? What are the files sizes? – Gusman May 10 '17 at 15:03
  • You may want to take a look at [NAudio](https://github.com/naudio/NAudio) – Frauke May 10 '17 at 15:03
  • @FraukeNonnenmacher - good shout with NAudio - used it many times before now :) – Geoff James May 10 '17 at 15:03
  • @Gusman The sounds are already played in a different thread than the UI. It's running inside a foreach loop with BlockingCollection. For this I need tu use PlaySync because an async call would continue with the second sound and stops the first one. – Manuel Berger May 11 '17 at 06:34
  • File format should be ok and the file size is 23KB – Manuel Berger May 11 '17 at 06:36
  • Again, I'll ask @ManuelBerger - are you aware of the difference between synchronous and asynchronous programming? It sounds to me like you're misusing the `PlayAsync` by not `await`ing it and using it in an `async` method. If you are to just call `player.PlayAsync()` in synchronous code, the execution will just continue, as it just fires it off, and has no concept of the task and when it has finished execution etc. I would advise having a read up of how to write/consume asynchronous methods. HTH – Geoff James May 11 '17 at 12:00
  • @GeoffJames There is no method PlayAsync only a method Play which is not awaitable, the method starts a new thread which plays the sound. I also don't wanna play the sound asynchronous. Because of my foreach loop with BlockingCollection I need to play the sound synchronous and so I call the PlaySync method – Manuel Berger May 11 '17 at 13:08
  • @ManuelBerger ah, I may have misunderstood your question then, it's a little unclear to read (might be worth updating the paragraphs and code a little). What presentation framework are you using? If you're using something XAML-based, this answer might help: http://stackoverflow.com/a/6253239/6240567 – Geoff James May 11 '17 at 13:23
  • @ManuelBerger - as for your `MediaEnded` not being called; I'm not sure why/how this is. I would have a deeper look into debugging the issue. Failing that, the answer I linked to above uses WPF, and the reliability of the `MediaElement`'s `MediaEnded` event seems pretty airtight. – Geoff James May 11 '17 at 13:26
  • @GeoffJames I update my question and the code. I took a look at the linked question before but I like to do it without XAML-code. But maybe MediaElement could be worth a try. – Manuel Berger May 11 '17 at 14:45
  • @ManuelBerger What presentation framework are you using? You can still use the `MediaElement`... just create one from codebehind (if you are using something like WPF etc.) – Geoff James May 11 '17 at 14:46
  • @GeoffJames I use WPF. Isn't the MediaPlayer class the solution for using a MediaElement without XAML-code? But I will try use MediaElement tomorrow. – Manuel Berger May 11 '17 at 15:04
  • @ManuelBerger AFAIK they're 2 different things altogether. IIRC I have had to use a `MediaElement` declared in the XAML, but just made sure the `Visibility` was `Collapsed`. Something to do with it not being in the visual tree (if memory serves me) made it not play if you were declaring it in the codebehind. I could be wrong, don't hold me to it. Either way, use a `MediaElement` and that should do the trick. For future, you might want to declare what presentation framework you're using in your OP, which would save a bit of hassle having to stab in the dark etc. :) – Geoff James May 11 '17 at 15:08
  • Maybe the problem is the `GetFile` method? – Alexander Petrov May 11 '17 at 15:19
  • @AlexanderPetrov The GetFile method only has a switch in it and returns for every enum value the correct path to the .wav file and is correct – Manuel Berger May 12 '17 at 06:47

0 Answers0