home
products
contribute
download
documentation
forum
Home
Forums
New posts
Search forums
What's new
New posts
All posts
Latest activity
Members
Registered members
Current visitors
Donate
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Search titles only
By:
Menu
Log in
Register
Navigation
Install the app
Install
More options
Contact us
Close Menu
Forums
MediaPortal 1
Support
General Support
[MP1-4838] Volume control no longer functions properly when changing audio device
Contact us
RSS
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="Rick164" data-source="post: 1208190" data-attributes="member: 17766"><p>So far going pretty well and decided to redo parts of VolumeHandler like [USER=82144]@mm1352000[/USER] suggested <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile :)" loading="lazy" data-shortname=":)" /></p><p></p><p><a href="https://gist.github.com/RickDB/f2e2b7f723ef2c974250334b0415f799" target="_blank">https://gist.github.com/RickDB/f2e2b7f723ef2c974250334b0415f799</a></p><p></p><p>The CoreAudioController still needs a few new events there but gonna test it some more today, for default device it will do a compare soon and if different will just handle the re-init for us in the background.</p><p></p><p>[code][2017-01-08 16:37:42,196] [Error ] [MPMain ] [ERROR] - Volume handler - got default audio device DENON-AVRHD-4 (NVIDIA High Definition Audio)</p><p>[2017-01-08 16:38:24,848] [Error ] [MPMain ] [ERROR] - Volume handler - setting volume to 0</p><p>[2017-01-08 16:38:24,848] [Error ] [MPMain ] [ERROR] - Volume handler - setting volume to 10</p><p>[/code]</p><p></p><p>// Update</p><p></p><p>Just looked at the Mixer class and seems better suited there (less code needed)</p><p></p><p>// Update 2</p><p></p><p>Removed AudioEndPoint entirely which results in this which works well during testing, subscribes to 2 events:</p><p></p><p>- Audio device changed (i.e. our initial bug report)</p><p>- Volume changed</p><p></p><p>Upside is that it's aware of any device / volume changes even outside of Mediaportal.</p><p></p><p>[code]#region Copyright (C) 2005-2011 Team MediaPortal</p><p></p><p>// Copyright (C) 2005-2011 Team MediaPortal</p><p>// https://www.team-mediaportal.com</p><p>//</p><p>// MediaPortal is free software: you can redistribute it and/or modify</p><p>// it under the terms of the GNU General Public License as published by</p><p>// the Free Software Foundation, either version 2 of the License, or</p><p>// (at your option) any later version.</p><p>//</p><p>// MediaPortal is distributed in the hope that it will be useful,</p><p>// but WITHOUT ANY WARRANTY; without even the implied warranty of</p><p>// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</p><p>// GNU General Public License for more details.</p><p>//</p><p>// You should have received a copy of the GNU General Public License</p><p>// along with MediaPortal. If not, see <http://www.gnu.org/licenses/>.</p><p></p><p>#endregion</p><p></p><p>using System;</p><p>using System.Runtime.InteropServices;</p><p>using AudioSwitcher.AudioApi;</p><p>using AudioSwitcher.AudioApi.CoreAudio;</p><p>using AudioSwitcher.AudioApi.Observables;</p><p>using MediaPortal.ExtensionMethods;</p><p>using MediaPortal.GUI.Library;</p><p></p><p>namespace MediaPortal.Mixer</p><p>{</p><p> public sealed class Mixer : IDisposable</p><p> {</p><p> #region Events</p><p></p><p> public event MixerEventHandler LineChanged;</p><p> public event MixerEventHandler ControlChanged;</p><p> </p><p> #endregion Events</p><p></p><p> #region Methods</p><p></p><p> public void Close()</p><p> {</p><p> lock (this)</p><p> {</p><p> if (_handle == IntPtr.Zero)</p><p> {</p><p> return;</p><p> }</p><p></p><p> MixerNativeMethods.mixerClose(_handle);</p><p></p><p> _handle = IntPtr.Zero;</p><p> }</p><p> }</p><p></p><p> public void Dispose()</p><p> {</p><p> if (_mixerControlDetailsVolume != null)</p><p> {</p><p> _mixerControlDetailsVolume.SafeDispose();</p><p> }</p><p></p><p> if (_mixerControlDetailsMute != null)</p><p> {</p><p> _mixerControlDetailsMute.SafeDispose();</p><p> }</p><p></p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> _audioDefaultDevice.SafeDispose();</p><p> }</p><p></p><p> if (_mixerEventListener != null)</p><p> {</p><p> _mixerEventListener.LineChanged -= new MixerEventHandler(OnLineChanged);</p><p> _mixerEventListener.ControlChanged -= new MixerEventHandler(OnControlChanged);</p><p> }</p><p></p><p> Close();</p><p></p><p> if (_mixerEventListener != null)</p><p> {</p><p> _mixerEventListener.DestroyHandle();</p><p> _mixerEventListener = null;</p><p> }</p><p> }</p><p></p><p> public void Open()</p><p> {</p><p> Open(0, false);</p><p> }</p><p></p><p> public void Open(int mixerIndex, bool isDigital)</p><p> {</p><p> lock (this)</p><p> {</p><p> _waveVolume = isDigital;</p><p> if (isDigital)</p><p> {</p><p> _componentType = MixerComponentType.SourceWave;</p><p> }</p><p> else</p><p> {</p><p> _componentType = MixerComponentType.DestinationSpeakers;</p><p> }</p><p> // not enough to change this..</p><p></p><p> // Use Endpoint Volume API for Vista/Win7 if master volume is selected and always for Win8 to handle muting of master volume</p><p> if ((OSInfo.OSInfo.VistaOrLater() && _componentType == MixerComponentType.DestinationSpeakers) ||</p><p> OSInfo.OSInfo.Win8OrLater())</p><p> {</p><p> try</p><p> {</p><p> _audioController = new CoreAudioController();</p><p> _audioDefaultDevice = _audioController.GetDefaultDevice(DeviceType.Playback, Role.Multimedia);</p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> Log.Error($"Mixer audio device: {_audioDefaultDevice.FullName}");</p><p> Log.Error($"Mixer audio device volume: {_audioDefaultDevice.Volume}");</p><p></p><p> // AudioEndpointVolume_OnVolumeNotification</p><p> _audioDefaultDevice.VolumeChanged.Subscribe(x =></p><p> {</p><p> OnVolumeChange();</p><p> });</p><p> _audioController.AudioDeviceChanged.Subscribe(x =></p><p> {</p><p> OnDeviceChange();</p><p> });</p><p></p><p></p><p> _isMuted = _audioDefaultDevice.IsMuted;</p><p> _volume = (int) _audioDefaultDevice.Volume;</p><p> Log.Error($"Mixer audio device volume rounded: {_volume}");</p><p> }</p><p> }</p><p> catch (Exception)</p><p> {</p><p> _isMuted = false;</p><p> _volume = 100;</p><p> }</p><p> }</p><p></p><p> // Use Windows Multimedia mixer functions for XP and for Vista and later if wave volume is selected</p><p> if (_componentType == MixerComponentType.SourceWave || !OSInfo.OSInfo.VistaOrLater())</p><p> {</p><p> if (_mixerEventListener == null)</p><p> {</p><p> _mixerEventListener = new MixerEventListener();</p><p> _mixerEventListener.Start();</p><p> }</p><p> _mixerEventListener.LineChanged += new MixerEventHandler(OnLineChanged);</p><p> _mixerEventListener.ControlChanged += new MixerEventHandler(OnControlChanged);</p><p></p><p> MixerNativeMethods.MixerControl mc = new MixerNativeMethods.MixerControl();</p><p></p><p> mc.Size = 0;</p><p> mc.ControlId = 0;</p><p> mc.ControlType = MixerControlType.Volume;</p><p> mc.fdwControl = 0;</p><p> mc.MultipleItems = 0;</p><p> mc.ShortName = string.Empty;</p><p> mc.Name = string.Empty;</p><p> mc.Minimum = 0;</p><p> mc.Maximum = 0;</p><p> mc.Reserved = 0;</p><p></p><p> IntPtr handle = IntPtr.Zero;</p><p></p><p> if (</p><p> MixerNativeMethods.mixerOpen(ref handle, mixerIndex, _mixerEventListener.Handle, 0,</p><p> MixerFlags.CallbackWindow) !=</p><p> MixerError.None)</p><p> {</p><p> throw new InvalidOperationException();</p><p> }</p><p></p><p> _handle = handle;</p><p></p><p> _mixerControlDetailsVolume = GetControl(_componentType, MixerControlType.Volume);</p><p> _mixerControlDetailsMute = GetControl(_componentType, MixerControlType.Mute);</p><p></p><p> _isMuted = (int) GetValue(_componentType, MixerControlType.Mute) == 1;</p><p> _volume = (int) GetValue(_componentType, MixerControlType.Volume);</p><p> }</p><p> }</p><p> }</p><p></p><p> private MixerNativeMethods.MixerControlDetails GetControl(MixerComponentType componentType,</p><p> MixerControlType controlType)</p><p> {</p><p> try</p><p> {</p><p> MixerNativeMethods.MixerLine mixerLine = new MixerNativeMethods.MixerLine(componentType);</p><p></p><p> if (MixerNativeMethods.mixerGetLineInfoA(_handle, ref mixerLine, MixerLineFlags.ComponentType) !=</p><p> MixerError.None)</p><p> {</p><p> throw new InvalidOperationException("Mixer.GetControl.1");</p><p> }</p><p></p><p> using (</p><p> MixerNativeMethods.MixerLineControls mixerLineControls =</p><p> new MixerNativeMethods.MixerLineControls(mixerLine.LineId, controlType))</p><p> {</p><p> if (MixerNativeMethods.mixerGetLineControlsA(_handle, mixerLineControls, MixerLineControlFlags.OneByType) !=</p><p> MixerError.None)</p><p> {</p><p> throw new InvalidOperationException("Mixer.GetControl.2");</p><p> }</p><p></p><p> MixerNativeMethods.MixerControl mixerControl =</p><p> (MixerNativeMethods.MixerControl)</p><p> Marshal.PtrToStructure(mixerLineControls.Data, typeof (MixerNativeMethods.MixerControl));</p><p></p><p> return new MixerNativeMethods.MixerControlDetails(mixerControl.ControlId);</p><p> }</p><p> }</p><p> catch (Exception)</p><p> {</p><p> // Catch exception when audio device is disconnected</p><p> }</p><p> return null;</p><p> }</p><p></p><p> private object GetValue(MixerComponentType componentType, MixerControlType controlType)</p><p> {</p><p> try</p><p> {</p><p> MixerNativeMethods.MixerLine mixerLine = new MixerNativeMethods.MixerLine(componentType);</p><p></p><p> if (MixerNativeMethods.mixerGetLineInfoA(_handle, ref mixerLine, MixerLineFlags.ComponentType) !=</p><p> MixerError.None)</p><p> {</p><p> throw new InvalidOperationException("Mixer.OpenControl.1");</p><p> }</p><p></p><p> using (</p><p> MixerNativeMethods.MixerLineControls mixerLineControls =</p><p> new MixerNativeMethods.MixerLineControls(mixerLine.LineId, controlType))</p><p> {</p><p> MixerNativeMethods.mixerGetLineControlsA(_handle, mixerLineControls, MixerLineControlFlags.OneByType);</p><p> MixerNativeMethods.MixerControl mixerControl =</p><p> (MixerNativeMethods.MixerControl)</p><p> Marshal.PtrToStructure(mixerLineControls.Data, typeof(MixerNativeMethods.MixerControl));</p><p></p><p> using (</p><p> MixerNativeMethods.MixerControlDetails mixerControlDetails =</p><p> new MixerNativeMethods.MixerControlDetails(mixerControl.ControlId))</p><p> {</p><p> MixerNativeMethods.mixerGetControlDetailsA(_handle, mixerControlDetails, 0);</p><p></p><p> return Marshal.ReadInt32(mixerControlDetails.Data);</p><p> }</p><p> }</p><p> }</p><p> catch (Exception)</p><p> {</p><p> // Catch exception when audio device is disconnected</p><p> }</p><p> // Set Volume to 30000 when audio recover</p><p> return 30000;</p><p> }</p><p></p><p> private void SetValue(MixerNativeMethods.MixerControlDetails control, bool value)</p><p> {</p><p> if (control == null)</p><p> {</p><p> return;</p><p> }</p><p></p><p> Marshal.WriteInt32(control.Data, value ? 1 : 0);</p><p> MixerNativeMethods.mixerSetControlDetails(_handle, control, 0);</p><p> }</p><p></p><p> private void SetValue(MixerNativeMethods.MixerControlDetails control, int value)</p><p> {</p><p> if (control == null)</p><p> {</p><p> return;</p><p> }</p><p></p><p> Marshal.WriteInt32(control.Data, value);</p><p> MixerNativeMethods.mixerSetControlDetails(_handle, control, 0);</p><p> }</p><p></p><p> private void OnLineChanged(object sender, MixerEventArgs e)</p><p> {</p><p> if (LineChanged != null)</p><p> {</p><p> LineChanged(sender, e);</p><p> }</p><p> }</p><p></p><p> private void OnControlChanged(object sender, MixerEventArgs e)</p><p> {</p><p> bool wasMuted = _isMuted;</p><p> int lastVolume = _volume;</p><p> _isMuted = (int)GetValue(_componentType, MixerControlType.Mute) == 1;</p><p> _volume = (int)GetValue(_componentType, MixerControlType.Volume);</p><p></p><p> if (ControlChanged != null && (wasMuted != _isMuted || lastVolume != _volume))</p><p> {</p><p> ControlChanged(sender, e);</p><p> }</p><p> }</p><p></p><p> void OnVolumeChange()</p><p> {</p><p> bool wasMuted = _isMuted;</p><p> int lastVolume = _volume;</p><p> _isMuted = _audioDefaultDevice.IsMuted;</p><p> if (_waveVolume && OSInfo.OSInfo.Win8OrLater())</p><p> {</p><p> _isMutedVolume = (int) GetValue(_componentType, MixerControlType.Mute) == 1;</p><p> }</p><p> _volume = (int)Math.Round(_audioDefaultDevice.Volume * VolumeMaximum);</p><p></p><p> if (ControlChanged != null && (wasMuted != _isMuted || lastVolume != _volume))</p><p> {</p><p> ControlChanged(null, null);</p><p> if (_waveVolume && OSInfo.OSInfo.Win8OrLater() && (_isMutedVolume != IsMuted))</p><p> {</p><p> SetValue(_mixerControlDetailsMute, _isMuted);</p><p> }</p><p> }</p><p> }</p><p></p><p> void OnDeviceChange()</p><p> {</p><p> _audioDefaultDevice = _audioController.GetDefaultDevice(DeviceType.Playback, Role.Multimedia);</p><p> }</p><p></p><p> #endregion Methods</p><p></p><p> #region Properties</p><p></p><p> public bool IsMuted</p><p> {</p><p> get { lock (this) return _isMuted; }</p><p> set</p><p> {</p><p> lock (this)</p><p> {</p><p> if (OSInfo.OSInfo.VistaOrLater() && (_componentType == MixerComponentType.DestinationSpeakers))</p><p> {</p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> _audioDefaultDevice.Mute(value);</p><p> }</p><p> }</p><p> else</p><p> {</p><p> //SetValue(_mixerControlDetailsMute, _isMuted = value);</p><p> SetValue(_mixerControlDetailsMute, value);</p><p> if (_waveVolume && OSInfo.OSInfo.Win8OrLater())</p><p> {</p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> _audioDefaultDevice.Mute(value);</p><p> }</p><p> }</p><p> }</p><p> }</p><p> }</p><p> }</p><p></p><p></p><p> public int Volume</p><p> {</p><p> get { lock (this) return _volume; }</p><p> set</p><p> {</p><p> lock (this)</p><p> {</p><p> if (OSInfo.OSInfo.VistaOrLater() && (_componentType == MixerComponentType.DestinationSpeakers))</p><p> {</p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> _audioDefaultDevice.Volume = (float) ((float) (value)/(float) (this.VolumeMaximum));</p><p> }</p><p> }</p><p> else</p><p> {</p><p> //SetValue(_mixerControlDetailsVolume, _volume = Math.Max(this.VolumeMinimum, Math.Min(this.VolumeMaximum, value)));</p><p> SetValue(_mixerControlDetailsVolume, Math.Max(this.VolumeMinimum, Math.Min(this.VolumeMaximum, value)));</p><p> if (_waveVolume && OSInfo.OSInfo.Win8OrLater())</p><p> {</p><p> if (_audioDefaultDevice != null)</p><p> {</p><p> _audioDefaultDevice.Volume = (float) ((float) (value)/(float) (this.VolumeMaximum));</p><p> }</p><p> }</p><p> }</p><p> }</p><p> }</p><p> }</p><p></p><p> public int VolumeMaximum</p><p> {</p><p> get { return 65535; }</p><p> }</p><p></p><p> public int VolumeMinimum</p><p> {</p><p> get { return 0; }</p><p> }</p><p></p><p> #endregion Properties</p><p></p><p> #region Fields</p><p></p><p> private MixerComponentType _componentType = MixerComponentType.DestinationSpeakers;</p><p> private IntPtr _handle;</p><p> private bool _isMuted;</p><p> private bool _isMutedVolume;</p><p> private static MixerEventListener _mixerEventListener;</p><p> private int _volume;</p><p> private MixerNativeMethods.MixerControlDetails _mixerControlDetailsVolume;</p><p> private MixerNativeMethods.MixerControlDetails _mixerControlDetailsMute;</p><p> private CoreAudioController _audioController;</p><p> private CoreAudioDevice _audioDefaultDevice;</p><p> private bool _waveVolume;</p><p></p><p> #endregion Fields</p><p> }</p><p>}[/code]</p></blockquote><p></p>
[QUOTE="Rick164, post: 1208190, member: 17766"] So far going pretty well and decided to redo parts of VolumeHandler like [USER=82144]@mm1352000[/USER] suggested :) [URL]https://gist.github.com/RickDB/f2e2b7f723ef2c974250334b0415f799[/URL] The CoreAudioController still needs a few new events there but gonna test it some more today, for default device it will do a compare soon and if different will just handle the re-init for us in the background. [code][2017-01-08 16:37:42,196] [Error ] [MPMain ] [ERROR] - Volume handler - got default audio device DENON-AVRHD-4 (NVIDIA High Definition Audio) [2017-01-08 16:38:24,848] [Error ] [MPMain ] [ERROR] - Volume handler - setting volume to 0 [2017-01-08 16:38:24,848] [Error ] [MPMain ] [ERROR] - Volume handler - setting volume to 10 [/code] // Update Just looked at the Mixer class and seems better suited there (less code needed) // Update 2 Removed AudioEndPoint entirely which results in this which works well during testing, subscribes to 2 events: - Audio device changed (i.e. our initial bug report) - Volume changed Upside is that it's aware of any device / volume changes even outside of Mediaportal. [code]#region Copyright (C) 2005-2011 Team MediaPortal // Copyright (C) 2005-2011 Team MediaPortal // https://www.team-mediaportal.com // // MediaPortal is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // MediaPortal is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with MediaPortal. If not, see <http://www.gnu.org/licenses/>. #endregion using System; using System.Runtime.InteropServices; using AudioSwitcher.AudioApi; using AudioSwitcher.AudioApi.CoreAudio; using AudioSwitcher.AudioApi.Observables; using MediaPortal.ExtensionMethods; using MediaPortal.GUI.Library; namespace MediaPortal.Mixer { public sealed class Mixer : IDisposable { #region Events public event MixerEventHandler LineChanged; public event MixerEventHandler ControlChanged; #endregion Events #region Methods public void Close() { lock (this) { if (_handle == IntPtr.Zero) { return; } MixerNativeMethods.mixerClose(_handle); _handle = IntPtr.Zero; } } public void Dispose() { if (_mixerControlDetailsVolume != null) { _mixerControlDetailsVolume.SafeDispose(); } if (_mixerControlDetailsMute != null) { _mixerControlDetailsMute.SafeDispose(); } if (_audioDefaultDevice != null) { _audioDefaultDevice.SafeDispose(); } if (_mixerEventListener != null) { _mixerEventListener.LineChanged -= new MixerEventHandler(OnLineChanged); _mixerEventListener.ControlChanged -= new MixerEventHandler(OnControlChanged); } Close(); if (_mixerEventListener != null) { _mixerEventListener.DestroyHandle(); _mixerEventListener = null; } } public void Open() { Open(0, false); } public void Open(int mixerIndex, bool isDigital) { lock (this) { _waveVolume = isDigital; if (isDigital) { _componentType = MixerComponentType.SourceWave; } else { _componentType = MixerComponentType.DestinationSpeakers; } // not enough to change this.. // Use Endpoint Volume API for Vista/Win7 if master volume is selected and always for Win8 to handle muting of master volume if ((OSInfo.OSInfo.VistaOrLater() && _componentType == MixerComponentType.DestinationSpeakers) || OSInfo.OSInfo.Win8OrLater()) { try { _audioController = new CoreAudioController(); _audioDefaultDevice = _audioController.GetDefaultDevice(DeviceType.Playback, Role.Multimedia); if (_audioDefaultDevice != null) { Log.Error($"Mixer audio device: {_audioDefaultDevice.FullName}"); Log.Error($"Mixer audio device volume: {_audioDefaultDevice.Volume}"); // AudioEndpointVolume_OnVolumeNotification _audioDefaultDevice.VolumeChanged.Subscribe(x => { OnVolumeChange(); }); _audioController.AudioDeviceChanged.Subscribe(x => { OnDeviceChange(); }); _isMuted = _audioDefaultDevice.IsMuted; _volume = (int) _audioDefaultDevice.Volume; Log.Error($"Mixer audio device volume rounded: {_volume}"); } } catch (Exception) { _isMuted = false; _volume = 100; } } // Use Windows Multimedia mixer functions for XP and for Vista and later if wave volume is selected if (_componentType == MixerComponentType.SourceWave || !OSInfo.OSInfo.VistaOrLater()) { if (_mixerEventListener == null) { _mixerEventListener = new MixerEventListener(); _mixerEventListener.Start(); } _mixerEventListener.LineChanged += new MixerEventHandler(OnLineChanged); _mixerEventListener.ControlChanged += new MixerEventHandler(OnControlChanged); MixerNativeMethods.MixerControl mc = new MixerNativeMethods.MixerControl(); mc.Size = 0; mc.ControlId = 0; mc.ControlType = MixerControlType.Volume; mc.fdwControl = 0; mc.MultipleItems = 0; mc.ShortName = string.Empty; mc.Name = string.Empty; mc.Minimum = 0; mc.Maximum = 0; mc.Reserved = 0; IntPtr handle = IntPtr.Zero; if ( MixerNativeMethods.mixerOpen(ref handle, mixerIndex, _mixerEventListener.Handle, 0, MixerFlags.CallbackWindow) != MixerError.None) { throw new InvalidOperationException(); } _handle = handle; _mixerControlDetailsVolume = GetControl(_componentType, MixerControlType.Volume); _mixerControlDetailsMute = GetControl(_componentType, MixerControlType.Mute); _isMuted = (int) GetValue(_componentType, MixerControlType.Mute) == 1; _volume = (int) GetValue(_componentType, MixerControlType.Volume); } } } private MixerNativeMethods.MixerControlDetails GetControl(MixerComponentType componentType, MixerControlType controlType) { try { MixerNativeMethods.MixerLine mixerLine = new MixerNativeMethods.MixerLine(componentType); if (MixerNativeMethods.mixerGetLineInfoA(_handle, ref mixerLine, MixerLineFlags.ComponentType) != MixerError.None) { throw new InvalidOperationException("Mixer.GetControl.1"); } using ( MixerNativeMethods.MixerLineControls mixerLineControls = new MixerNativeMethods.MixerLineControls(mixerLine.LineId, controlType)) { if (MixerNativeMethods.mixerGetLineControlsA(_handle, mixerLineControls, MixerLineControlFlags.OneByType) != MixerError.None) { throw new InvalidOperationException("Mixer.GetControl.2"); } MixerNativeMethods.MixerControl mixerControl = (MixerNativeMethods.MixerControl) Marshal.PtrToStructure(mixerLineControls.Data, typeof (MixerNativeMethods.MixerControl)); return new MixerNativeMethods.MixerControlDetails(mixerControl.ControlId); } } catch (Exception) { // Catch exception when audio device is disconnected } return null; } private object GetValue(MixerComponentType componentType, MixerControlType controlType) { try { MixerNativeMethods.MixerLine mixerLine = new MixerNativeMethods.MixerLine(componentType); if (MixerNativeMethods.mixerGetLineInfoA(_handle, ref mixerLine, MixerLineFlags.ComponentType) != MixerError.None) { throw new InvalidOperationException("Mixer.OpenControl.1"); } using ( MixerNativeMethods.MixerLineControls mixerLineControls = new MixerNativeMethods.MixerLineControls(mixerLine.LineId, controlType)) { MixerNativeMethods.mixerGetLineControlsA(_handle, mixerLineControls, MixerLineControlFlags.OneByType); MixerNativeMethods.MixerControl mixerControl = (MixerNativeMethods.MixerControl) Marshal.PtrToStructure(mixerLineControls.Data, typeof(MixerNativeMethods.MixerControl)); using ( MixerNativeMethods.MixerControlDetails mixerControlDetails = new MixerNativeMethods.MixerControlDetails(mixerControl.ControlId)) { MixerNativeMethods.mixerGetControlDetailsA(_handle, mixerControlDetails, 0); return Marshal.ReadInt32(mixerControlDetails.Data); } } } catch (Exception) { // Catch exception when audio device is disconnected } // Set Volume to 30000 when audio recover return 30000; } private void SetValue(MixerNativeMethods.MixerControlDetails control, bool value) { if (control == null) { return; } Marshal.WriteInt32(control.Data, value ? 1 : 0); MixerNativeMethods.mixerSetControlDetails(_handle, control, 0); } private void SetValue(MixerNativeMethods.MixerControlDetails control, int value) { if (control == null) { return; } Marshal.WriteInt32(control.Data, value); MixerNativeMethods.mixerSetControlDetails(_handle, control, 0); } private void OnLineChanged(object sender, MixerEventArgs e) { if (LineChanged != null) { LineChanged(sender, e); } } private void OnControlChanged(object sender, MixerEventArgs e) { bool wasMuted = _isMuted; int lastVolume = _volume; _isMuted = (int)GetValue(_componentType, MixerControlType.Mute) == 1; _volume = (int)GetValue(_componentType, MixerControlType.Volume); if (ControlChanged != null && (wasMuted != _isMuted || lastVolume != _volume)) { ControlChanged(sender, e); } } void OnVolumeChange() { bool wasMuted = _isMuted; int lastVolume = _volume; _isMuted = _audioDefaultDevice.IsMuted; if (_waveVolume && OSInfo.OSInfo.Win8OrLater()) { _isMutedVolume = (int) GetValue(_componentType, MixerControlType.Mute) == 1; } _volume = (int)Math.Round(_audioDefaultDevice.Volume * VolumeMaximum); if (ControlChanged != null && (wasMuted != _isMuted || lastVolume != _volume)) { ControlChanged(null, null); if (_waveVolume && OSInfo.OSInfo.Win8OrLater() && (_isMutedVolume != IsMuted)) { SetValue(_mixerControlDetailsMute, _isMuted); } } } void OnDeviceChange() { _audioDefaultDevice = _audioController.GetDefaultDevice(DeviceType.Playback, Role.Multimedia); } #endregion Methods #region Properties public bool IsMuted { get { lock (this) return _isMuted; } set { lock (this) { if (OSInfo.OSInfo.VistaOrLater() && (_componentType == MixerComponentType.DestinationSpeakers)) { if (_audioDefaultDevice != null) { _audioDefaultDevice.Mute(value); } } else { //SetValue(_mixerControlDetailsMute, _isMuted = value); SetValue(_mixerControlDetailsMute, value); if (_waveVolume && OSInfo.OSInfo.Win8OrLater()) { if (_audioDefaultDevice != null) { _audioDefaultDevice.Mute(value); } } } } } } public int Volume { get { lock (this) return _volume; } set { lock (this) { if (OSInfo.OSInfo.VistaOrLater() && (_componentType == MixerComponentType.DestinationSpeakers)) { if (_audioDefaultDevice != null) { _audioDefaultDevice.Volume = (float) ((float) (value)/(float) (this.VolumeMaximum)); } } else { //SetValue(_mixerControlDetailsVolume, _volume = Math.Max(this.VolumeMinimum, Math.Min(this.VolumeMaximum, value))); SetValue(_mixerControlDetailsVolume, Math.Max(this.VolumeMinimum, Math.Min(this.VolumeMaximum, value))); if (_waveVolume && OSInfo.OSInfo.Win8OrLater()) { if (_audioDefaultDevice != null) { _audioDefaultDevice.Volume = (float) ((float) (value)/(float) (this.VolumeMaximum)); } } } } } } public int VolumeMaximum { get { return 65535; } } public int VolumeMinimum { get { return 0; } } #endregion Properties #region Fields private MixerComponentType _componentType = MixerComponentType.DestinationSpeakers; private IntPtr _handle; private bool _isMuted; private bool _isMutedVolume; private static MixerEventListener _mixerEventListener; private int _volume; private MixerNativeMethods.MixerControlDetails _mixerControlDetailsVolume; private MixerNativeMethods.MixerControlDetails _mixerControlDetailsMute; private CoreAudioController _audioController; private CoreAudioDevice _audioDefaultDevice; private bool _waveVolume; #endregion Fields } }[/code] [/QUOTE]
Insert quotes…
Verification
Post reply
Forums
MediaPortal 1
Support
General Support
[MP1-4838] Volume control no longer functions properly when changing audio device
Contact us
RSS
Top
Bottom