[C#] Windows Core Audio

holy

Lieutenant
Dabei seit
Aug. 2008
Beiträge
533
Hallo zusammen,

ich habe eben auf CodeProject eine Frage veröffentlicht und würde diese auch gerne hier stellen. Das Original gibt's hier.

Kurz zusammen gefasst:
Es geht um die Audio-Steuerung eines Media Players. Über den Lautstärkenregler im Media Player soll die Lautstärke der aktuellen Audio Session geändert werden. Umgekehrt muss der Regler im Player geupdatet werden, sollte der User im Windows Sound Mixer die Lautstärke ändern. Das ist alles soweit kein Problem.

Interessant wird es nun, wenn ich im Windows Sound Mixer den Slider per Drag'n Drop verschiebe. Der Knabe rastet dann völlig aus ;( Ich habe leider keine Ahnung wieso.
Hier gibt es ein Video dazu - klick.

Die Klasse VolumeManager wird in einem ViewModel instanziert und bindet an den Volume-Slider.

Ich bin für jegliche Art von Hilfe dankbar ;)

Code:
Code:
public sealed class VolumeManager : INotifyPropertyChanged, IDisposable
{
...
    private readonly EventClient _eventClient;
    private readonly IAudioSessionControl _sessionControl;
    private readonly ISimpleAudioVolume _simpleVolume;
...
    public VolumeManager()
    {
        var type = 
            Type.GetTypeFromCLSID( 
                Guid.Parse( ComCLSIDs.MMDeviceEnumeratorCLSID ) );
        IMMDeviceEnumerator deviceEnumerator = 
            (IMMDeviceEnumerator)Activator.CreateInstance( type );
 
        IMMDevice device;
        Marshal.ThrowExceptionForHR( 
            deviceEnumerator.GetDefaultAudioEndpoint( 
                DataFlow.eRender, 
                ERole.eMultimedia, 
                out device ) );
 
        // see: http://msdn.microsoft.com/en-us/library/ms886177.aspx
        // CLSCTX_INPROC_SERVER = 0x1
        // CLSCTX_INPROC_HANDLER = 0x2
        // CLSCTX_LOCAL_SERVER = 0x4
        // CLSCTX_REMOTE_SERVER = 0x10
        const uint CLSCTX_ALL = 0x1 | 0x2 | 0x4 | 0x10;
 
        object obj;
        Marshal.ThrowExceptionForHR( 
            device.Activate( 
                Guid.Parse( ComIIDs.IAudioSessionManagerIID ), 
                CLSCTX_ALL, 
                IntPtr.Zero, 
                out obj ) );
        IAudioSessionManager manager = (IAudioSessionManager)obj;
 
        // see: http://msdn.microsoft.com/en-        us/library/windows/desktop/dd371455(v=vs.85).aspx

        // Marshal.ThrowExceptionForHR(
        //     device.Activate(
        //         Guid.Parse( ComIIDs.IAudioClientIID ),
        //         CLSCTX_ALL, 
        //         IntPtr.Zero,
        //         out obj ) );
        // IAudioClient client = (IAudioClient)obj;
            
        // int hr = client.Initialize( 
        //     AUDCLNT_SHAREMODE.AUDCLNT_SHAREMODE_SHARED, 
        //     0, 
        //     0,
        //     0,
        //     IntPtr.Zero,
        //     Guid.NewGuid() );
        //
        // says: reference not set to an object ;(
        // Exception ex = Marshal.GetExceptionForHR( hr );

        // client.GetService( 
        //     Guid.Parse( ComIIDs.IAudioSessionControlIID ), out obj );
        // _sessionControl = (IAudioSessionControl)obj;

        // client.GetService( 
        //     Guid.Parse( ComIIDs.ISimpleAudioVolumeIID ), out obj );
        // _simpleVolume = (ISimpleAudioVolume)obj;
            
        Marshal.ThrowExceptionForHR( 
               manager.GetAudioSessionControl( 
                   streamFlags: 0, 
                   sessionControl: out _sessionControl ) );
        Marshal.ThrowExceptionForHR( 
               manager.GetSimpleAudioVolume( 
                   streamFlags: 0, 
                   audioVolume: out _simpleVolume ) );
 
        // Marshal.ThrowExceptionForHR( 
        //     manager.GetAudioSessionControl( 
        //         Guid.Empty, 
        //         0,
        //         out _sessionControl ) );
        // Marshal.ThrowExceptionForHR( 
        //     manager.GetSimpleAudioVolume( 
        //         Guid.Empty,
        //         0,
        //         out _simpleVolume ) );

        Marshal.ThrowExceptionForHR( 
            Marshal.FinalReleaseComObject( deviceEnumerator ) );
        Marshal.ThrowExceptionForHR( 
            Marshal.FinalReleaseComObject( device ) );
        Marshal.ThrowExceptionForHR( 
            Marshal.FinalReleaseComObject( manager ) );
 
        _eventClient = new EventClient();
        Marshal.ThrowExceptionForHR( 
            _sessionControl.RegisterAudioSessionNotification( _eventClient ) );
 
        _eventClient.VolumeChanged += OnVolumeChanged;
    }
 
...
 
    // remarks: e.Volume is float [0,1]
    private void OnVolumeChanged( object sender, VolumeEventArgs e )
    {
        IsMuted = e.IsMuted;
        int scalar = Convert.ToInt32( (e.Volume * 100) + 0.5 );
        Volume = scalar;
    }
 
...
    private int _volume;
    public int Volume
    {
        get
        {
            return _volume;
        }
 
        set
        {
            if ( _volume == value )
            {
                return;
            }
 
            int ihr = -1;
            if ( value < 0 )
            {
                ihr = _simpleVolume.SetMasterVolume( 0, Guid.Empty );
            }
 
            if ( value > 100 )
            {
                ihr = _simpleVolume.SetMasterVolume( 1, Guid.Empty );
            }
 
            float scalar = Convert.ToSingle( (double)value / 100 );
            int hr = _simpleVolume.SetMasterVolume( scalar, Guid.Empty );
 
            if ( hr == 0 || ihr == 0)
            {
                _volume = value;
                OnPropertyChanged( "Volume" );
            }
        }
    }
 
...
 
    public void Dispose()
    {
        _sessionControl.UnregisterAudioSessionNotification( _eventClient );
        Marshal.FinalReleaseComObject( _simpleVolume );
        Marshal.FinalReleaseComObject( _sessionControl );
    }
 
...
 
}
Und

Code:
internal class EventClient : IAudioSessionEvents
{
    public delegate void VolumeEventHandler( object sender, VolumeEventArgs e );
    public event VolumeEventHandler VolumeChanged;
 
...
 
    public int OnSimpleVolumeChanged( float volume, bool isMuted, ref Guid eventContext )
    {
        if ( VolumeChanged != null )
        {
            var args = new VolumeEventArgs( volume, isMuted, eventContext );
            VolumeChanged( this, args );
        }
           
        return 0;
    }
}
 

Darlis

Commodore
Dabei seit
Jan. 2011
Beiträge
4.231
Meine grobe Vermutung: Wenn du den Slider verschiebst, wird der auch der Wert im Soundmixer verstellt, worauf du aber wieder ein Event zum ändern deines Sliders bekommst während du noch am draggen bist. Das generiert vermutlich wieder ein Event an der Soundmixer usw...
 

holy

Lieutenant
Ersteller dieses Themas
Dabei seit
Aug. 2008
Beiträge
533
OK, sorry, die Info fehlt hier.
Wird der Slider in Windows geändert, löst dies nur ein Update der UI aus, aber es wird nicht noch einmal die Lautstärke gesetzt.
Ergänzung ()

Solved.
Falls jemand jemals den Code brauchen sollte, er steht als Solution 1 unter der Frage bei CodeProject.
 
Top