none
SoundPlayerAction plays crazy noise

    Question

  • In a style for Buttons I use, I call a SoundPlayerAction from the Click EventTrigger that plays a .wav file embedded just like you would embed an image for WPF.

     

    The first time you click one of my buttons, you hear this crazy static from the speakers, but each time after is fine.  I've had similar issues in the past with System.Media.SoundPlayer and wav files from memory, which is under the hood, I'm sure.

     

    Now I realize this is newly supported in .Net 3.5, I used to have to use loose .wav files with SoundPlayerAction, but is there a way to fix it?  Or do I just need to go back to loose files? 

     

    I personally don't like loose files, because I might want other developers to use my style without worrying about a silly wav file.

    Thursday, April 24, 2008 2:47 PM

Answers

  •  Even after all this work, it still happened!

    It seems the issue is linked to the GC, apparently if it collects while playing and the memory containing the wav file gets moved around, the unmanaged code playing the sound can't handle it.  So it seems a complicated layout pass can cause the GC to collect, and so it seemed to indirectly cause my issue.  This is also why it was so hard to recreate consistently.

    Here is a link to the fix which uses a pinned GCHandle to prevent this:
    http://www.codeproject.com/KB/audio-video/soundplayerbug.aspx


    I know pinning can be a performance impacting thing, does anyone know how much it could affect an application with many, many sounds?
    Tuesday, July 08, 2008 2:58 PM

All replies

  • After further inspection loose files cause this issue as well, I have another app that was compiled with .Net 3.0 and the loose file version of my button.

     

    It seems that any PC with .Net 3.5 installed will cause the crazy static to play once after a few clicks, but then it doesn't happen again for the lifetime of the program.

     

    Is there something wrong with .Net 3.5's SoundPlayerAction?  I can't be blasting static at my end-users.

    Friday, April 25, 2008 1:46 PM
  •  Jonathan.Peppers wrote:

    It seems that any PC with .Net 3.5 installed will cause the crazy static to play once after a few clicks, but then it doesn't happen again for the lifetime of the program.


    Could you please elaborate what you mean by "crazy static"? do you mean "delay" or something else? you could send your test project to me for repro if you are willing to do so. You can find my email address at my personal profile page.

    Thanks
    Monday, April 28, 2008 3:41 AM
  • To describe the sound more clearly, it sounds like someone is blowing into a microphone for a portion of a second and then the remainder of my wav file comes through.

     

    I'm having trouble creating a repro for you, the repro (I can't send you my app) does it only like 1 in 25 tries, and that's not reliable enough to send to you, but I seem to have found a workaround.

     

    In my app, the click event handler on my button shows a new Grid with many controls/images on it.  So I think the problem is when the SoundPlayerAction is playing during the first Layout pass on my Grid (which is a very complicated one).

     

    So I tried forcing my complicated Grid to fire it's layout pass on load (by making my Grid visible on load and putting my loading screen over top of it), and it has drastically reduced the amount of times I get the noise.  Note: my images are already cached on load.

     

    I still get the noise occasionally, however, when a button click event sets a new style on a control for the first time (which I assume is forcing a layout pass in my style's ControlTemplate).

     

    So does this provide any clues?  Am I better off subclassing Button and using System.Media.SoundPlayer instead?

     

    Or is there a good way to force every layout pass in my app during a loading screen?  This would be more optimal for me anyways, since I'd rather not have screen load a little slower the first time you go to them.

    Monday, April 28, 2008 3:42 PM
  • I don't know if SoundPlayer will playback the file asynchronously, but you could try WPF's MediaPlayer, because MediaPlayer playback things at composition thread which will reduce the possibility that UI thread get messed up with audio playback.

    Hope this helps
    Tuesday, April 29, 2008 6:00 AM
  • It didn't work for what I needed, I couldn't get MediaElement to work properly from within a style.

     

    So I looked at writing my own TriggerAction that would play my pop noise... too bad MS made all the functions I needed to override internal.

     

    But I found a workaround...  A way to subclass something to be used as a TriggerAction.

     

    I derived from AnimationTimeline as so:

     

    Code Snippet

    public class Pop : AnimationTimeline

    {

    private static Assembly _assembly = Assembly.GetExecutingAssembly();

    private static SoundPlayer _player = new SoundPlayer(_assembly.GetManifestResourceStream("Utopia.UI.Sounds.Pop.wav"));

    public override Type TargetPropertyType

    {

    get { return typeof(object); }

    }

    protected override Freezable CreateInstanceCore()

    {

    return new Pop();

    }

    protected override Clock AllocateClock()

    {

    _player.Play();

    return base.AllocateClock();

    }

    }

     

     

    Embedded my sound as an EmbeddedResource, and made this animation animate the Tag property (to prevent InvalidOperationException from not having a true Storyboard.TargetProperty) on my button on the Click event trigger.

     

    This solution is absolutely retarded.  But it works perfect!  Why can't SoundPlayerAction work properly?

    Monday, May 05, 2008 6:32 PM
  • I finally just derived from button, and put the above code in the OnClick override.

     

    Microsoft really needs to make TriggerActions/TriggerBase protected virtual methods non-internal, it would be very nice to create your own (Especially since SoundPlayerAction needs fixing).  I don't personally see a reason they're internal, I'd understand if it created something unsafe like a handle to a bitmap or something that needs to be under the hood, but oh well...

    Monday, May 19, 2008 12:57 PM
  •  Even after all this work, it still happened!

    It seems the issue is linked to the GC, apparently if it collects while playing and the memory containing the wav file gets moved around, the unmanaged code playing the sound can't handle it.  So it seems a complicated layout pass can cause the GC to collect, and so it seemed to indirectly cause my issue.  This is also why it was so hard to recreate consistently.

    Here is a link to the fix which uses a pinned GCHandle to prevent this:
    http://www.codeproject.com/KB/audio-video/soundplayerbug.aspx


    I know pinning can be a performance impacting thing, does anyone know how much it could affect an application with many, many sounds?
    Tuesday, July 08, 2008 2:58 PM