mirror of
https://github.com/Sarsoo/Spotify.NET.git
synced 2024-12-24 23:16:28 +00:00
Fixed occasional COMException in GetSpotifyVolumeObject (#222)
* Added volume controls in Example app * Fixed occasional COMException when using Get- or SetSpotifyVolume This exception only happens if Spotify is using an audio device different from the default one. Such a thing is only possible (as of v1.0.75.483.g7ff4a0dc) when using the "--enable-audio-graph" command line argument, that makes available the "Playback device" advanced option in Spotify.
This commit is contained in:
parent
4b40a1b477
commit
159b60331e
58
SpotifyAPI.Example/LocalControl.Designer.cs
generated
58
SpotifyAPI.Example/LocalControl.Designer.cs
generated
@ -61,6 +61,10 @@
|
|||||||
this.artistLinkLabel = new System.Windows.Forms.LinkLabel();
|
this.artistLinkLabel = new System.Windows.Forms.LinkLabel();
|
||||||
this.titleLinkLabel = new System.Windows.Forms.LinkLabel();
|
this.titleLinkLabel = new System.Windows.Forms.LinkLabel();
|
||||||
this.smallAlbumPicture = new System.Windows.Forms.PictureBox();
|
this.smallAlbumPicture = new System.Windows.Forms.PictureBox();
|
||||||
|
this.volumeDownBtn = new System.Windows.Forms.Button();
|
||||||
|
this.volumeUpBtn = new System.Windows.Forms.Button();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.volumeMixerLabel = new System.Windows.Forms.Label();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.bigAlbumPicture)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.bigAlbumPicture)).BeginInit();
|
||||||
this.groupBox1.SuspendLayout();
|
this.groupBox1.SuspendLayout();
|
||||||
this.trackInfoBox.SuspendLayout();
|
this.trackInfoBox.SuspendLayout();
|
||||||
@ -69,7 +73,7 @@
|
|||||||
//
|
//
|
||||||
// bigAlbumPicture
|
// bigAlbumPicture
|
||||||
//
|
//
|
||||||
this.bigAlbumPicture.Location = new System.Drawing.Point(327, 13);
|
this.bigAlbumPicture.Location = new System.Drawing.Point(330, 13);
|
||||||
this.bigAlbumPicture.Name = "bigAlbumPicture";
|
this.bigAlbumPicture.Name = "bigAlbumPicture";
|
||||||
this.bigAlbumPicture.Size = new System.Drawing.Size(640, 640);
|
this.bigAlbumPicture.Size = new System.Drawing.Size(640, 640);
|
||||||
this.bigAlbumPicture.TabIndex = 2;
|
this.bigAlbumPicture.TabIndex = 2;
|
||||||
@ -77,6 +81,10 @@
|
|||||||
//
|
//
|
||||||
// groupBox1
|
// groupBox1
|
||||||
//
|
//
|
||||||
|
this.groupBox1.Controls.Add(this.volumeMixerLabel);
|
||||||
|
this.groupBox1.Controls.Add(this.label9);
|
||||||
|
this.groupBox1.Controls.Add(this.volumeUpBtn);
|
||||||
|
this.groupBox1.Controls.Add(this.volumeDownBtn);
|
||||||
this.groupBox1.Controls.Add(this.repeatShuffleLabel);
|
this.groupBox1.Controls.Add(this.repeatShuffleLabel);
|
||||||
this.groupBox1.Controls.Add(this.label6);
|
this.groupBox1.Controls.Add(this.label6);
|
||||||
this.groupBox1.Controls.Add(this.versionLabel);
|
this.groupBox1.Controls.Add(this.versionLabel);
|
||||||
@ -428,6 +436,50 @@
|
|||||||
this.smallAlbumPicture.TabIndex = 5;
|
this.smallAlbumPicture.TabIndex = 5;
|
||||||
this.smallAlbumPicture.TabStop = false;
|
this.smallAlbumPicture.TabStop = false;
|
||||||
//
|
//
|
||||||
|
// volumeDownBtn
|
||||||
|
//
|
||||||
|
this.volumeDownBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.volumeDownBtn.Location = new System.Drawing.Point(247, 134);
|
||||||
|
this.volumeDownBtn.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.volumeDownBtn.Name = "volumeDownBtn";
|
||||||
|
this.volumeDownBtn.Size = new System.Drawing.Size(65, 24);
|
||||||
|
this.volumeDownBtn.TabIndex = 32;
|
||||||
|
this.volumeDownBtn.Text = "Volume-";
|
||||||
|
this.volumeDownBtn.UseVisualStyleBackColor = true;
|
||||||
|
this.volumeDownBtn.Click += new System.EventHandler(this.volumeDownBtn_Click);
|
||||||
|
//
|
||||||
|
// volumeUpBtn
|
||||||
|
//
|
||||||
|
this.volumeUpBtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.volumeUpBtn.Location = new System.Drawing.Point(247, 110);
|
||||||
|
this.volumeUpBtn.Margin = new System.Windows.Forms.Padding(0);
|
||||||
|
this.volumeUpBtn.Name = "volumeUpBtn";
|
||||||
|
this.volumeUpBtn.Size = new System.Drawing.Size(65, 24);
|
||||||
|
this.volumeUpBtn.TabIndex = 33;
|
||||||
|
this.volumeUpBtn.Text = "Volume+";
|
||||||
|
this.volumeUpBtn.UseVisualStyleBackColor = true;
|
||||||
|
this.volumeUpBtn.Click += new System.EventHandler(this.volumeUpBtn_Click);
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.label9.Location = new System.Drawing.Point(7, 117);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(155, 17);
|
||||||
|
this.label9.TabIndex = 34;
|
||||||
|
this.label9.Text = "Volume Mixer\'s volume:";
|
||||||
|
//
|
||||||
|
// volumeMixerLabel
|
||||||
|
//
|
||||||
|
this.volumeMixerLabel.AutoSize = true;
|
||||||
|
this.volumeMixerLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.volumeMixerLabel.Location = new System.Drawing.Point(168, 117);
|
||||||
|
this.volumeMixerLabel.Name = "volumeMixerLabel";
|
||||||
|
this.volumeMixerLabel.Size = new System.Drawing.Size(13, 17);
|
||||||
|
this.volumeMixerLabel.TabIndex = 35;
|
||||||
|
this.volumeMixerLabel.Text = "-";
|
||||||
|
//
|
||||||
// LocalControl
|
// LocalControl
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
@ -483,5 +535,9 @@
|
|||||||
private System.Windows.Forms.Label label6;
|
private System.Windows.Forms.Label label6;
|
||||||
private System.Windows.Forms.Label repeatShuffleLabel;
|
private System.Windows.Forms.Label repeatShuffleLabel;
|
||||||
private System.Windows.Forms.Label advertLabel;
|
private System.Windows.Forms.Label advertLabel;
|
||||||
|
private System.Windows.Forms.Button volumeUpBtn;
|
||||||
|
private System.Windows.Forms.Button volumeDownBtn;
|
||||||
|
private System.Windows.Forms.Label volumeMixerLabel;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,8 @@ namespace SpotifyAPI.Example
|
|||||||
|
|
||||||
if (status.Track != null) //Update track infos
|
if (status.Track != null) //Update track infos
|
||||||
UpdateTrack(status.Track);
|
UpdateTrack(status.Track);
|
||||||
|
|
||||||
|
RefreshVolumeMixerVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void UpdateTrack(Track track)
|
public async void UpdateTrack(Track track)
|
||||||
@ -106,6 +108,11 @@ namespace SpotifyAPI.Example
|
|||||||
isPlayingLabel.Text = playing.ToString();
|
isPlayingLabel.Text = playing.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RefreshVolumeMixerVolume()
|
||||||
|
{
|
||||||
|
volumeMixerLabel.Text = _spotify.GetSpotifyVolume().ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
private void _spotify_OnVolumeChange(object sender, VolumeChangeEventArgs e)
|
private void _spotify_OnVolumeChange(object sender, VolumeChangeEventArgs e)
|
||||||
{
|
{
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
@ -178,6 +185,24 @@ namespace SpotifyAPI.Example
|
|||||||
_spotify.Skip();
|
_spotify.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void volumeUpBtn_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
float currentVolume = _spotify.GetSpotifyVolume();
|
||||||
|
float newVolume = currentVolume + 2.0f;
|
||||||
|
_spotify.SetSpotifyVolume(newVolume >= 100.0f ? 100.0f : newVolume);
|
||||||
|
|
||||||
|
RefreshVolumeMixerVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void volumeDownBtn_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
float currentVolume = _spotify.GetSpotifyVolume();
|
||||||
|
float newVolume = currentVolume - 2.0f;
|
||||||
|
_spotify.SetSpotifyVolume(newVolume <= 0.0f ? 0.0f : newVolume);
|
||||||
|
|
||||||
|
RefreshVolumeMixerVolume();
|
||||||
|
}
|
||||||
|
|
||||||
private static String FormatTime(double sec)
|
private static String FormatTime(double sec)
|
||||||
{
|
{
|
||||||
TimeSpan span = TimeSpan.FromSeconds(sec);
|
TimeSpan span = TimeSpan.FromSeconds(sec);
|
||||||
|
@ -67,11 +67,13 @@ namespace SpotifyAPI.Local
|
|||||||
Marshal.ReleaseComObject(volume);
|
Marshal.ReleaseComObject(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ISimpleAudioVolume GetSpotifyVolumeObject() {
|
private static ISimpleAudioVolume GetSpotifyVolumeObject()
|
||||||
return (from p in Process.GetProcessesByName(SpotifyProcessName)
|
{
|
||||||
|
var audioVolumeObjects = from p in Process.GetProcessesByName(SpotifyProcessName)
|
||||||
let vol = GetVolumeObject(p.Id)
|
let vol = GetVolumeObject(p.Id)
|
||||||
where vol != null
|
where vol != null
|
||||||
select vol).FirstOrDefault();
|
select vol;
|
||||||
|
return audioVolumeObjects.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ISimpleAudioVolume GetVolumeObject(int pid)
|
private static ISimpleAudioVolume GetVolumeObject(int pid)
|
||||||
@ -81,10 +83,59 @@ namespace SpotifyAPI.Local
|
|||||||
IMmDevice speakers;
|
IMmDevice speakers;
|
||||||
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.ERender, ERole.EMultimedia, out speakers);
|
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.ERender, ERole.EMultimedia, out speakers);
|
||||||
|
|
||||||
|
string defaultDeviceId;
|
||||||
|
speakers.GetId(out defaultDeviceId);
|
||||||
|
|
||||||
|
ISimpleAudioVolume volumeControl = GetVolumeObject(pid, speakers);
|
||||||
|
Marshal.ReleaseComObject(speakers);
|
||||||
|
|
||||||
|
if (volumeControl == null)
|
||||||
|
{
|
||||||
|
// If volumeControl is null, then the process's volume object might be on a different device.
|
||||||
|
// This happens if the process doesn't use the default device.
|
||||||
|
//
|
||||||
|
// As far as Spotify is concerned, if using the "--enable-audio-graph" command line argument,
|
||||||
|
// a new option becomes available in the Settings that makes it possible to change the playback device.
|
||||||
|
|
||||||
|
IMmDeviceCollection deviceCollection;
|
||||||
|
deviceEnumerator.EnumAudioEndpoints(EDataFlow.ERender, EDeviceState.Active, out deviceCollection);
|
||||||
|
|
||||||
|
int count;
|
||||||
|
deviceCollection.GetCount(out count);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
IMmDevice device;
|
||||||
|
deviceCollection.Item(i, out device);
|
||||||
|
|
||||||
|
string deviceId;
|
||||||
|
device.GetId(out deviceId);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (deviceId == defaultDeviceId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
volumeControl = GetVolumeObject(pid, device);
|
||||||
|
if (volumeControl != null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.ReleaseComObject(deviceEnumerator);
|
||||||
|
return volumeControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ISimpleAudioVolume GetVolumeObject(int pid, IMmDevice device)
|
||||||
|
{
|
||||||
// activate the session manager. we need the enumerator
|
// activate the session manager. we need the enumerator
|
||||||
Guid iidIAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
|
Guid iidIAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
|
||||||
object o;
|
object o;
|
||||||
speakers.Activate(ref iidIAudioSessionManager2, 0, IntPtr.Zero, out o);
|
device.Activate(ref iidIAudioSessionManager2, 0, IntPtr.Zero, out o);
|
||||||
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
|
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
|
||||||
|
|
||||||
// enumerate sessions for on this device
|
// enumerate sessions for on this device
|
||||||
@ -112,8 +163,6 @@ namespace SpotifyAPI.Local
|
|||||||
}
|
}
|
||||||
Marshal.ReleaseComObject(sessionEnumerator);
|
Marshal.ReleaseComObject(sessionEnumerator);
|
||||||
Marshal.ReleaseComObject(mgr);
|
Marshal.ReleaseComObject(mgr);
|
||||||
Marshal.ReleaseComObject(speakers);
|
|
||||||
Marshal.ReleaseComObject(deviceEnumerator);
|
|
||||||
return volumeControl;
|
return volumeControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +170,6 @@ namespace SpotifyAPI.Local
|
|||||||
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
|
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
|
||||||
private class MMDeviceEnumerator
|
private class MMDeviceEnumerator
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum EDataFlow
|
private enum EDataFlow
|
||||||
@ -140,10 +188,21 @@ namespace SpotifyAPI.Local
|
|||||||
ERoleEnumCount
|
ERoleEnumCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum EDeviceState
|
||||||
|
{
|
||||||
|
Active = 0x00000001,
|
||||||
|
Disabled = 0x00000002,
|
||||||
|
NotPresent = 0x00000004,
|
||||||
|
UnPlugged = 0x00000008,
|
||||||
|
All = 0x0000000F
|
||||||
|
}
|
||||||
|
|
||||||
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
private interface IMmDeviceEnumerator
|
private interface IMmDeviceEnumerator
|
||||||
{
|
{
|
||||||
int NotImpl1();
|
[PreserveSig]
|
||||||
|
int EnumAudioEndpoints(EDataFlow dataFlow, EDeviceState stateMask, [Out] out IMmDeviceCollection deviceCollection);
|
||||||
|
|
||||||
[PreserveSig]
|
[PreserveSig]
|
||||||
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMmDevice ppDevice);
|
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMmDevice ppDevice);
|
||||||
@ -154,6 +213,21 @@ namespace SpotifyAPI.Local
|
|||||||
{
|
{
|
||||||
[PreserveSig]
|
[PreserveSig]
|
||||||
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
|
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
|
||||||
|
|
||||||
|
int OpenPropertyStore_NotImpl();
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int GetId([Out, MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
private interface IMmDeviceCollection
|
||||||
|
{
|
||||||
|
[PreserveSig]
|
||||||
|
int GetCount(out int deviceCount);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int Item(int deviceIndex, [Out] out IMmDevice device);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
Loading…
Reference in New Issue
Block a user