1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-06-01 11:34:04 +02:00

Rewrite audio library & add notification volume option for WMP impl

This commit is contained in:
chylex 2017-08-28 18:16:13 +02:00
parent 064627961e
commit 625227d0ce
10 changed files with 125 additions and 168 deletions

View File

@ -55,8 +55,8 @@ static UserConfig(){
private int _zoomLevel = 100; private int _zoomLevel = 100;
private bool _muteNotifications; private bool _muteNotifications;
private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled; private TrayIcon.Behavior _trayBehavior = TrayIcon.Behavior.Disabled;
public bool EnableTrayHighlight { get; set; } = true; public bool EnableTrayHighlight { get; set; } = true;
public bool EnableUpdateCheck { get; set; } = true; public bool EnableUpdateCheck { get; set; } = true;
public string DismissedUpdate { get; set; } = null; public string DismissedUpdate { get; set; } = null;
@ -80,6 +80,7 @@ static UserConfig(){
public Size CustomNotificationSize { get; set; } = Size.Empty; public Size CustomNotificationSize { get; set; } = Size.Empty;
public int NotificationScrollSpeed { get; set; } = 10; public int NotificationScrollSpeed { get; set; } = 10;
public int NotificationSoundVolume { get; set; } = 100;
private string _notificationSoundPath; private string _notificationSoundPath;
public string CustomCefArgs { get; set; } = null; public string CustomCefArgs { get; set; } = null;

View File

@ -508,6 +508,7 @@ public void PlayNotificationSound(){
soundNotification.PlaybackError += soundNotification_PlaybackError; soundNotification.PlaybackError += soundNotification_PlaybackError;
} }
soundNotification.SetVolume(Config.NotificationSoundVolume);
soundNotification.Play(Config.NotificationSoundPath); soundNotification.Play(Config.NotificationSoundPath);
} }

View File

@ -17,6 +17,10 @@ public void Play(string file){
player.Play(file); player.Play(file);
} }
public bool SetVolume(int volume){
return player.SetVolume(volume);
}
private void Player_PlaybackError(object sender, PlaybackErrorEventArgs e){ private void Player_PlaybackError(object sender, PlaybackErrorEventArgs e){
PlaybackError?.Invoke(this, e); PlaybackError?.Invoke(this, e);
} }

View File

@ -25,15 +25,40 @@ protected override void Dispose(bool disposing) {
private void InitializeComponent() { private void InitializeComponent() {
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.tbCustomSound = new System.Windows.Forms.TextBox();
this.labelVolumeValue = new System.Windows.Forms.Label();
this.btnPlaySound = new System.Windows.Forms.Button(); this.btnPlaySound = new System.Windows.Forms.Button();
this.btnResetSound = new System.Windows.Forms.Button(); this.btnResetSound = new System.Windows.Forms.Button();
this.btnBrowseSound = new System.Windows.Forms.Button(); this.btnBrowseSound = new System.Windows.Forms.Button();
this.tbCustomSound = new System.Windows.Forms.TextBox();
this.labelSoundNotification = new System.Windows.Forms.Label(); this.labelSoundNotification = new System.Windows.Forms.Label();
this.panelSoundNotification = new System.Windows.Forms.Panel(); this.panelSoundNotification = new System.Windows.Forms.Panel();
this.labelVolume = new System.Windows.Forms.Label();
this.trackBarVolume = new System.Windows.Forms.TrackBar();
this.panelSoundNotification.SuspendLayout(); this.panelSoundNotification.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// tbCustomSound
//
this.tbCustomSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbCustomSound.Location = new System.Drawing.Point(3, 3);
this.tbCustomSound.Name = "tbCustomSound";
this.tbCustomSound.Size = new System.Drawing.Size(316, 20);
this.tbCustomSound.TabIndex = 0;
this.toolTip.SetToolTip(this.tbCustomSound, "When empty, the default TweetDeck sound notification is used.");
//
// labelVolumeValue
//
this.labelVolumeValue.BackColor = System.Drawing.Color.Transparent;
this.labelVolumeValue.Location = new System.Drawing.Point(147, 84);
this.labelVolumeValue.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
this.labelVolumeValue.Name = "labelVolumeValue";
this.labelVolumeValue.Size = new System.Drawing.Size(38, 13);
this.labelVolumeValue.TabIndex = 6;
this.labelVolumeValue.Text = "100%";
this.labelVolumeValue.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// btnPlaySound // btnPlaySound
// //
this.btnPlaySound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnPlaySound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@ -69,16 +94,6 @@ private void InitializeComponent() {
this.btnBrowseSound.Text = "Browse..."; this.btnBrowseSound.Text = "Browse...";
this.btnBrowseSound.UseVisualStyleBackColor = true; this.btnBrowseSound.UseVisualStyleBackColor = true;
// //
// tbCustomSound
//
this.tbCustomSound.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbCustomSound.Location = new System.Drawing.Point(3, 3);
this.tbCustomSound.Name = "tbCustomSound";
this.tbCustomSound.Size = new System.Drawing.Size(316, 20);
this.tbCustomSound.TabIndex = 0;
this.toolTip.SetToolTip(this.tbCustomSound, "When empty, the default TweetDeck sound notification is used.");
//
// labelSoundNotification // labelSoundNotification
// //
this.labelSoundNotification.AutoSize = true; this.labelSoundNotification.AutoSize = true;
@ -94,15 +109,42 @@ private void InitializeComponent() {
// //
this.panelSoundNotification.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.panelSoundNotification.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.panelSoundNotification.Controls.Add(this.labelVolume);
this.panelSoundNotification.Controls.Add(this.labelVolumeValue);
this.panelSoundNotification.Controls.Add(this.trackBarVolume);
this.panelSoundNotification.Controls.Add(this.btnPlaySound); this.panelSoundNotification.Controls.Add(this.btnPlaySound);
this.panelSoundNotification.Controls.Add(this.tbCustomSound); this.panelSoundNotification.Controls.Add(this.tbCustomSound);
this.panelSoundNotification.Controls.Add(this.btnResetSound); this.panelSoundNotification.Controls.Add(this.btnResetSound);
this.panelSoundNotification.Controls.Add(this.btnBrowseSound); this.panelSoundNotification.Controls.Add(this.btnBrowseSound);
this.panelSoundNotification.Location = new System.Drawing.Point(9, 31); this.panelSoundNotification.Location = new System.Drawing.Point(9, 31);
this.panelSoundNotification.Name = "panelSoundNotification"; this.panelSoundNotification.Name = "panelSoundNotification";
this.panelSoundNotification.Size = new System.Drawing.Size(322, 56); this.panelSoundNotification.Size = new System.Drawing.Size(322, 119);
this.panelSoundNotification.TabIndex = 2; this.panelSoundNotification.TabIndex = 2;
// //
// labelVolume
//
this.labelVolume.AutoSize = true;
this.labelVolume.Location = new System.Drawing.Point(3, 67);
this.labelVolume.Margin = new System.Windows.Forms.Padding(3, 12, 3, 0);
this.labelVolume.Name = "labelVolume";
this.labelVolume.Size = new System.Drawing.Size(42, 13);
this.labelVolume.TabIndex = 4;
this.labelVolume.Text = "Volume";
//
// trackBarVolume
//
this.trackBarVolume.AutoSize = false;
this.trackBarVolume.BackColor = System.Drawing.SystemColors.Control;
this.trackBarVolume.Location = new System.Drawing.Point(3, 83);
this.trackBarVolume.Maximum = 100;
this.trackBarVolume.Name = "trackBarVolume";
this.trackBarVolume.Size = new System.Drawing.Size(148, 30);
this.trackBarVolume.SmallChange = 5;
this.trackBarVolume.TabIndex = 5;
this.trackBarVolume.TickFrequency = 10;
this.trackBarVolume.Value = 100;
this.trackBarVolume.ValueChanged += new System.EventHandler(this.trackBarVolume_ValueChanged);
//
// TabSettingsSounds // TabSettingsSounds
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -110,9 +152,10 @@ private void InitializeComponent() {
this.Controls.Add(this.panelSoundNotification); this.Controls.Add(this.panelSoundNotification);
this.Controls.Add(this.labelSoundNotification); this.Controls.Add(this.labelSoundNotification);
this.Name = "TabSettingsSounds"; this.Name = "TabSettingsSounds";
this.Size = new System.Drawing.Size(340, 97); this.Size = new System.Drawing.Size(340, 160);
this.panelSoundNotification.ResumeLayout(false); this.panelSoundNotification.ResumeLayout(false);
this.panelSoundNotification.PerformLayout(); this.panelSoundNotification.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBarVolume)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@ -127,5 +170,8 @@ private void InitializeComponent() {
private System.Windows.Forms.Button btnPlaySound; private System.Windows.Forms.Button btnPlaySound;
private System.Windows.Forms.Label labelSoundNotification; private System.Windows.Forms.Label labelSoundNotification;
private System.Windows.Forms.Panel panelSoundNotification; private System.Windows.Forms.Panel panelSoundNotification;
private System.Windows.Forms.Label labelVolume;
private System.Windows.Forms.Label labelVolumeValue;
private System.Windows.Forms.TrackBar trackBarVolume;
} }
} }

View File

@ -2,18 +2,26 @@
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetLib.Audio; using TweetLib.Audio;
namespace TweetDuck.Core.Other.Settings{ namespace TweetDuck.Core.Other.Settings{
partial class TabSettingsSounds : BaseTabSettings{ partial class TabSettingsSounds : BaseTabSettings{
private readonly SoundNotification soundNotification; private readonly SoundNotification soundNotification;
private readonly bool supportsChangingVolume;
public TabSettingsSounds(){ public TabSettingsSounds(){
InitializeComponent(); InitializeComponent();
soundNotification = new SoundNotification(); soundNotification = new SoundNotification();
soundNotification.PlaybackError += sound_PlaybackError; soundNotification.PlaybackError += sound_PlaybackError;
supportsChangingVolume = soundNotification.SetVolume(Config.NotificationSoundVolume);
trackBarVolume.Enabled = supportsChangingVolume && !string.IsNullOrEmpty(Config.NotificationSoundPath);
trackBarVolume.SetValueSafe(Config.NotificationSoundVolume);
labelVolumeValue.Text = trackBarVolume.Value+"%";
tbCustomSound.Text = Config.NotificationSoundPath; tbCustomSound.Text = Config.NotificationSoundPath;
tbCustomSound_TextChanged(tbCustomSound, new EventArgs()); tbCustomSound_TextChanged(tbCustomSound, new EventArgs());
@ -37,6 +45,7 @@ private void tbCustomSound_TextChanged(object sender, EventArgs e){
tbCustomSound.ForeColor = isEmpty || File.Exists(tbCustomSound.Text) ? SystemColors.WindowText : Color.Red; tbCustomSound.ForeColor = isEmpty || File.Exists(tbCustomSound.Text) ? SystemColors.WindowText : Color.Red;
btnPlaySound.Enabled = !isEmpty; btnPlaySound.Enabled = !isEmpty;
btnResetSound.Enabled = !isEmpty; btnResetSound.Enabled = !isEmpty;
trackBarVolume.Enabled = supportsChangingVolume && !isEmpty;
} }
private void btnPlaySound_Click(object sender, EventArgs e){ private void btnPlaySound_Click(object sender, EventArgs e){
@ -63,5 +72,11 @@ private void btnBrowseSound_Click(object sender, EventArgs e){
private void btnResetSound_Click(object sender, EventArgs e){ private void btnResetSound_Click(object sender, EventArgs e){
tbCustomSound.Text = string.Empty; tbCustomSound.Text = string.Empty;
} }
private void trackBarVolume_ValueChanged(object sender, EventArgs e){
Config.NotificationSoundVolume = trackBarVolume.Value;
soundNotification.SetVolume(Config.NotificationSoundVolume);
labelVolumeValue.Text = Config.NotificationSoundVolume+"%";
}
} }
} }

View File

@ -30,7 +30,7 @@ public static AudioPlayer New(){
public abstract event EventHandler<PlaybackErrorEventArgs> PlaybackError; public abstract event EventHandler<PlaybackErrorEventArgs> PlaybackError;
public abstract void Play(string file); public abstract void Play(string file);
public abstract void Stop(); public abstract bool SetVolume(int volume);
protected abstract void Dispose(bool disposing); protected abstract void Dispose(bool disposing);
public void Dispose(){ public void Dispose(){

View File

@ -34,8 +34,8 @@ public override void Play(string file){
} }
} }
public override void Stop(){ public override bool SetVolume(int volume){
player.Stop(); return false;
} }
protected override void Dispose(bool disposing){ protected override void Dispose(bool disposing){

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using TweetLib.Audio.Utils; using System.Windows.Forms;
using WMPLib; using WMPLib;
namespace TweetLib.Audio.Impl{ namespace TweetLib.Audio.Impl{
@ -9,10 +9,13 @@ sealed class SoundPlayerImplWMP : AudioPlayer{
public override event EventHandler<PlaybackErrorEventArgs> PlaybackError; public override event EventHandler<PlaybackErrorEventArgs> PlaybackError;
private readonly WindowsMediaPlayer player; private readonly Form owner;
private readonly ControlWMP wmp;
private bool wasTryingToPlay; private bool wasTryingToPlay;
private bool ignorePlaybackError; private bool ignorePlaybackError;
private WindowsMediaPlayer Player => wmp.Ocx;
// changing the player volume also affects the value in the Windows mixer // changing the player volume also affects the value in the Windows mixer
// however, the initial value is always 50 or some other stupid shit // however, the initial value is always 50 or some other stupid shit
// so we have to tell the player to set its volume to whatever the mixer is set to // so we have to tell the player to set its volume to whatever the mixer is set to
@ -20,45 +23,48 @@ sealed class SoundPlayerImplWMP : AudioPlayer{
// thanks, Microsoft // thanks, Microsoft
public SoundPlayerImplWMP(){ public SoundPlayerImplWMP(){
player = new WindowsMediaPlayer(); owner = new Form();
player.settings.autoStart = false; wmp = new ControlWMP();
player.settings.enableErrorDialogs = false; wmp.BeginInit();
player.settings.invokeURLs = false; owner.Controls.Add(wmp);
player.settings.volume = (int)Math.Floor(100.0*NativeCoreAudio.GetMixerVolumeForCurrentProcess()); wmp.EndInit();
player.MediaChange += player_MediaChange;
player.MediaError += player_MediaError; Player.uiMode = "none";
Player.settings.autoStart = false;
Player.settings.enableErrorDialogs = false;
Player.settings.invokeURLs = false;
Player.settings.volume = 0;
Player.MediaChange += player_MediaChange;
Player.MediaError += player_MediaError;
} }
public override void Play(string file){ public override void Play(string file){
wasTryingToPlay = true; wasTryingToPlay = true;
try{ try{
if (player.URL != file){ if (Player.URL != file){
player.close(); Player.close();
player.URL = file; Player.URL = file;
ignorePlaybackError = false; ignorePlaybackError = false;
} }
else{ else{
player.controls.stop(); Player.controls.stop();
} }
player.controls.play(); Player.controls.play();
}catch(Exception e){ }catch(Exception e){
OnNotificationSoundError("An error occurred in Windows Media Player: "+e.Message); OnNotificationSoundError("An error occurred in Windows Media Player: "+e.Message);
} }
} }
public override void Stop(){ public override bool SetVolume(int volume){
try{ Player.settings.volume = volume;
player.controls.stop(); return true;
}catch{
// ignore
}
} }
protected override void Dispose(bool disposing){ protected override void Dispose(bool disposing){
player.close(); wmp.Dispose();
Marshal.ReleaseComObject(player); owner.Dispose();
} }
private void player_MediaChange(object item){ private void player_MediaChange(object item){
@ -109,5 +115,16 @@ private void OnNotificationSoundError(string message){
} }
} }
} }
[Clsid("{6bf52a52-394a-11d3-b153-00c04f79faa6}")]
private sealed class ControlWMP : AxHost{
public WindowsMediaPlayer Ocx { get; private set; }
public ControlWMP() : base("6bf52a52-394a-11d3-b153-00c04f79faa6"){}
protected override void AttachInterfaces(){
Ocx = (WindowsMediaPlayer)GetOcx();
}
}
} }
} }

View File

@ -26,10 +26,10 @@
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AudioPlayer.cs" /> <Compile Include="AudioPlayer.cs" />
<Compile Include="Utils\NativeCoreAudio.cs" />
<Compile Include="PlaybackErrorEventArgs.cs" /> <Compile Include="PlaybackErrorEventArgs.cs" />
<Compile Include="Impl\SoundPlayerImplFallback.cs" /> <Compile Include="Impl\SoundPlayerImplFallback.cs" />
<Compile Include="Impl\SoundPlayerImplWMP.cs" /> <Compile Include="Impl\SoundPlayerImplWMP.cs" />

View File

@ -1,127 +0,0 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
namespace TweetLib.Audio.Utils{
static class NativeCoreAudio{
private const int EDATAFLOW_RENDER = 0;
private const int EROLE_MULTIMEDIA = 1;
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
private class MMDeviceEnumerator{}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDeviceEnumerator{
int Unimpl_EnumAudioEndpoints();
IMMDevice GetDefaultAudioEndpoint(int dataFlow, int role);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDevice{
[return:MarshalAs(UnmanagedType.IUnknown)]
object Activate(ref Guid id, int clsCtx, IntPtr activationParams);
}
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAudioSessionManager2{
int Unimpl_FindWillToLive();
int Unimpl_HelloDarknessMyOldFriend();
IAudioSessionEnumerator GetSessionEnumerator();
}
[Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAudioSessionEnumerator{
int GetCount();
IAudioSessionControl GetSession(int sessionIndex);
}
[Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAudioSessionControl{}
[Guid("BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IAudioSessionControl2{
int Unimpl_GetState();
int Unimpl_GetDisplayName();
int Unimpl_SetDisplayName();
int Unimpl_GetIconPath();
int Unimpl_SetIconPath();
int Unimpl_GetGroupingParam();
int Unimpl_SetGroupingParam();
int Unimpl_RegisterAudioSessionNotification();
int Unimpl_UnregisterAudioSessionNotification();
[return:MarshalAs(UnmanagedType.LPWStr)]
string GetSessionIdentifier();
}
[Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface ISimpleAudioVolume{
void SetMasterVolume(float level, ref Guid eventContext);
float GetMasterVolume();
}
[SuppressMessage("ReSharper", "SuspiciousTypeConversion.Global")]
private static ISimpleAudioVolume GetVolumeObject(string name){
IMMDeviceEnumerator devices = (IMMDeviceEnumerator)new MMDeviceEnumerator();
IMMDevice device = devices.GetDefaultAudioEndpoint(EDATAFLOW_RENDER, EROLE_MULTIMEDIA);
Guid sessionManagerGUID = typeof(IAudioSessionManager2).GUID;
IAudioSessionManager2 manager = (IAudioSessionManager2)device.Activate(ref sessionManagerGUID, 0, IntPtr.Zero);
IAudioSessionEnumerator sessions = manager.GetSessionEnumerator();
ISimpleAudioVolume volumeObj = null;
for(int index = sessions.GetCount()-1; index >= 0; index--){
if (sessions.GetSession(index) is IAudioSessionControl2 ctl){
string identifier = ctl.GetSessionIdentifier();
if (identifier != null && identifier.Contains(name)){
volumeObj = ctl as ISimpleAudioVolume;
break;
}
Marshal.ReleaseComObject(ctl);
}
}
Marshal.ReleaseComObject(devices);
Marshal.ReleaseComObject(device);
Marshal.ReleaseComObject(manager);
Marshal.ReleaseComObject(sessions);
return volumeObj;
}
public static double GetMixerVolume(string appPath){
ISimpleAudioVolume obj = GetVolumeObject(appPath);
float level = 1F;
if (obj != null){
level = obj.GetMasterVolume();
Marshal.ReleaseComObject(obj);
}
return Math.Round(level, 2);
}
public static double GetMixerVolumeForCurrentProcess(){
string path;
using(Process process = Process.GetCurrentProcess()){
path = process.MainModule.FileName;
path = path.Substring(Path.GetPathRoot(path).Length);
}
return GetMixerVolume(path);
}
}
}