Проблемы с использованием Windows Core Audio
Всем привет,
Я столкнулся с некоторыми серьезными проблемами при использовании Windows Core Audio API.
Этот вопрос, как мне кажется, довольно специфичен и, возможно, слишком длинен для быстрого вопроса. Пожалуйста, дайте мне знать, являются ли дискуссионные форумы лучшим местом для этого.
Я также отметил этот вопрос следующим образом
C++
потому что это собственные API.Короче говоря чего бы я хотел достичь:
У меня есть медиаплеер. Изменение его громкости должно отражаться в звуковом микшере Windows и наоборот. Я изменяю громкость сеанса, а не основной том.
Это работает с одним маленьким, раздражающим исключением. Когда я перетаскиваю ползунок в звуковом микшере Windows, он начинает устанавливать громкость как сумасшедший. Я записал видео и загрузил его на YouTube, чтобы вы могли видеть, о чем я говорю. Вы можете найти его здесь - щелчок[^]. Слева вы видите звуковой микшер Windows, справа-мой медиаплеер.
Прежде чем я опубликую код, несколько замечаний.
Согласно с MSDN[^] Я должен активировать
IAudioClient
из IMMDevice
прежде чем я наконец смогу позвонить Initialize
на клиенте и начать запрашивать такие услуги, как ISimpleVolumeControl
или IAudioSessionControl
по телефону GetService
Вы можете увидеть мою реализацию во втором блоке комментариев (это WASAPI).Однако моя реализация не работает. Я получаю исключение, говорящее, что ссылка не установлена на объект. Вот почему я использую
IAudioSessionManager
чтобы получить контроль.Я был бы очень благодарен за любые подсказки, чтобы решить эту проблему ;)
Ах да, пока я не забыл. Я использую обертки CoreAudio от Vannatech[^].
Заранее спасибо.
Итак, код:
Класс
VolumeManager
, ViewModel создаст этот экземпляр.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 ); } ... }
Класс
EventClient
: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; }