tags:

views:

31

answers:

1

Hello,

I have a plugin system in my app and I would like to prevent those plugins from playing sounds. It doesn't have to be a perfect solution that cannot be overriden by a plugin.

EDIT: Sounds will be played via MediaElement in plugins

Thanks for an answer!

+1  A: 

Disabling sounds in all MediaElements in a Window is easy. Just create an attached inherited property that enforces IsMuted=false on any MediaElement it is applied to. The property would be used like this:

<Window my:Silencer.Silence="true" ...>
  ...
</Window>

Here is how it would be implemented:

public class Silencer : DependencyObject
{
  // Silence
  public static bool GetSilence(DependencyObject obj) { return (bool)obj.GetValue(SilenceProperty); }
  public static void SetSilence(DependencyObject obj, bool value) { obj.SetValue(SilenceProperty, value); }
  public static readonly DependencyProperty SilenceProperty = DependencyProperty.RegisterAttached("Silence", typeof(bool), typeof(Silencer), new FrameworkPropertyMetadata
  {
    Inherits = true,
    PropertyChangedCallback = (obj, e) =>
      {
        var element = obj as MediaElement; if(element==null) return;
        if((bool)e.NewValue)
        {
          element.SetBinding(UnmuteDetectedProperty, new Binding("IsMuted") { RelativeSource = RelativeSource.Self });
          element.IsMuted = true;
        }
        else
        {
          element.ClearValue(UnmuteDetectedProperty);
          element.IsMuted = false;
        }
      }
  });

  // UnmuteDetected
  public static readonly DependencyProperty UnmuteDetectedProperty = DependencyProperty.RegisterAttached("UnmuteDetected", typeof(bool), typeof(Silencer), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        ((MediaElement)obj).IsMuted = GetSilence(obj);
      }
  });
}

How it works: When Silencer is set to true on the Window, all descendants get a property change notification. This includes any MediaElement that is already in the Window or is later added to the Window. The property change notification causes the MediaElement's UnmuteDetected property to be bound to IsMuted, then IsMuted is set to true. If the plugin's code sets IsMuted=false, it will trigger the second PropertyChangedCallback which will set it back true again.

Note that this only works for MediaElements, and only if they are added to the visual tree.

Blocking more than just MediaElement sounds

A more comprehensive method of blocking all sound from your application is Vista's core audio APIs (also available in Windows 7), specifically the ISimpleAudioVolume interface. This can be used to block almost all ways an application can produce audio, with the exception of PlaySound() and other techniques that route their output to the system-notification audio session. Blocking sound directed to the system-notification session requires intercepting Windows calls using native code.

Ray Burns
Thank you very much for detailed answer!
MartyIX