mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-04-12 15:15:45 +02:00
Add a fallback sound notification impl if WMP is unavailable
This commit is contained in:
parent
8ce92df87a
commit
33d5638bb0
@ -18,6 +18,7 @@
|
||||
using TweetDck.Core.Notification.Screenshot;
|
||||
using TweetDck.Updates.Events;
|
||||
using System.Diagnostics;
|
||||
using TweetDck.Core.Notification.Sound;
|
||||
|
||||
namespace TweetDck.Core{
|
||||
sealed partial class FormBrowser : Form{
|
||||
@ -43,7 +44,7 @@ private static UserConfig Config{
|
||||
private FormWindowState prevState;
|
||||
|
||||
private TweetScreenshotManager notificationScreenshotManager;
|
||||
private SoundNotification soundNotification;
|
||||
private ISoundNotificationPlayer soundNotification;
|
||||
|
||||
public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){
|
||||
InitializeComponent();
|
||||
@ -273,7 +274,7 @@ private void updates_UpdateDismissed(object sender, UpdateDismissedEventArgs e){
|
||||
Config.Save();
|
||||
}
|
||||
|
||||
private void soundNotification_PlaybackError(object sender, SoundNotification.PlaybackErrorEventArgs e){
|
||||
private void soundNotification_PlaybackError(object sender, PlaybackErrorEventArgs e){
|
||||
e.Ignore = true;
|
||||
|
||||
using(FormMessage form = new FormMessage("Notification Sound Error", "Could not play custom notification sound."+Environment.NewLine+e.Message, MessageBoxIcon.Error)){
|
||||
@ -408,7 +409,7 @@ public void PlayNotificationSound(){
|
||||
}
|
||||
|
||||
if (soundNotification == null){
|
||||
soundNotification = new SoundNotification();
|
||||
soundNotification = SoundNotification.New();
|
||||
soundNotification.PlaybackError += soundNotification_PlaybackError;
|
||||
}
|
||||
|
||||
|
12
Core/Notification/Sound/ISoundNotificationPlayer.cs
Normal file
12
Core/Notification/Sound/ISoundNotificationPlayer.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace TweetDck.Core.Notification.Sound{
|
||||
interface ISoundNotificationPlayer : IDisposable{
|
||||
string SupportedFormats { get; }
|
||||
|
||||
event EventHandler<PlaybackErrorEventArgs> PlaybackError;
|
||||
|
||||
void Play(string file);
|
||||
void Stop();
|
||||
}
|
||||
}
|
13
Core/Notification/Sound/PlaybackErrorEventArgs.cs
Normal file
13
Core/Notification/Sound/PlaybackErrorEventArgs.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace TweetDck.Core.Notification.Sound{
|
||||
sealed class PlaybackErrorEventArgs : EventArgs{
|
||||
public string Message { get; private set; }
|
||||
public bool Ignore { get; set; }
|
||||
|
||||
public PlaybackErrorEventArgs(string message){
|
||||
this.Message = message;
|
||||
this.Ignore = false;
|
||||
}
|
||||
}
|
||||
}
|
57
Core/Notification/Sound/SoundPlayerImplFallback.cs
Normal file
57
Core/Notification/Sound/SoundPlayerImplFallback.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Media;
|
||||
|
||||
namespace TweetDck.Core.Notification.Sound{
|
||||
sealed class SoundPlayerImplFallback : ISoundNotificationPlayer{
|
||||
string ISoundNotificationPlayer.SupportedFormats{
|
||||
get{
|
||||
return "*.wav";
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<PlaybackErrorEventArgs> PlaybackError;
|
||||
|
||||
private readonly SoundPlayer player;
|
||||
private bool ignorePlaybackError;
|
||||
|
||||
public SoundPlayerImplFallback(){
|
||||
player = new SoundPlayer{
|
||||
LoadTimeout = 5000
|
||||
};
|
||||
}
|
||||
|
||||
void ISoundNotificationPlayer.Play(string file){
|
||||
if (player.SoundLocation != file){
|
||||
player.SoundLocation = file;
|
||||
ignorePlaybackError = false;
|
||||
}
|
||||
|
||||
try{
|
||||
player.Play();
|
||||
}catch(FileNotFoundException e){
|
||||
OnNotificationSoundError("File not found: "+e.FileName);
|
||||
}catch(InvalidOperationException){
|
||||
OnNotificationSoundError("File format was not recognized.");
|
||||
}catch(TimeoutException){
|
||||
OnNotificationSoundError("File took too long to load.");
|
||||
}
|
||||
}
|
||||
|
||||
void ISoundNotificationPlayer.Stop(){
|
||||
player.Stop();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose(){
|
||||
player.Dispose();
|
||||
}
|
||||
|
||||
private void OnNotificationSoundError(string message){
|
||||
if (!ignorePlaybackError && PlaybackError != null){
|
||||
PlaybackErrorEventArgs args = new PlaybackErrorEventArgs(message);
|
||||
PlaybackError(this, args);
|
||||
ignorePlaybackError = args.Ignore;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
109
Core/Notification/Sound/SoundPlayerImplWMP.cs
Normal file
109
Core/Notification/Sound/SoundPlayerImplWMP.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using TweetDck.Core.Utils;
|
||||
using WMPLib;
|
||||
|
||||
namespace TweetDck.Core.Notification.Sound{
|
||||
sealed class SoundPlayerImplWMP : ISoundNotificationPlayer{
|
||||
string ISoundNotificationPlayer.SupportedFormats{
|
||||
get{
|
||||
return "*.wav;*.mp3;*.mp2;*.m4a;*.mid;*.midi;*.rmi;*.wma;*.aif;*.aifc;*.aiff;*.snd;*.au";
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<PlaybackErrorEventArgs> PlaybackError;
|
||||
|
||||
private readonly WindowsMediaPlayer player;
|
||||
private bool wasTryingToPlay;
|
||||
private bool ignorePlaybackError;
|
||||
|
||||
// changing the player volume also affects the value in the Windows mixer
|
||||
// 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
|
||||
// using the most code required for the least functionality with a sorry excuse for an API
|
||||
// thanks, Microsoft
|
||||
|
||||
public SoundPlayerImplWMP(){
|
||||
player = new WindowsMediaPlayer();
|
||||
player.settings.autoStart = false;
|
||||
player.settings.enableErrorDialogs = false;
|
||||
player.settings.invokeURLs = false;
|
||||
player.settings.volume = (int)Math.Floor(100.0*NativeCoreAudio.GetMixerVolumeForCurrentProcess());
|
||||
player.MediaChange += player_MediaChange;
|
||||
player.MediaError += player_MediaError;
|
||||
}
|
||||
|
||||
void ISoundNotificationPlayer.Play(string file){
|
||||
wasTryingToPlay = true;
|
||||
|
||||
if (player.URL != file){
|
||||
player.close();
|
||||
player.URL = file;
|
||||
ignorePlaybackError = false;
|
||||
}
|
||||
else{
|
||||
player.controls.stop();
|
||||
}
|
||||
|
||||
player.controls.play();
|
||||
}
|
||||
|
||||
void ISoundNotificationPlayer.Stop(){
|
||||
player.controls.stop();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose(){
|
||||
player.close();
|
||||
Marshal.ReleaseComObject(player);
|
||||
}
|
||||
|
||||
private void player_MediaChange(object item){
|
||||
IWMPMedia2 media = item as IWMPMedia2;
|
||||
|
||||
if (media == null){
|
||||
OnNotificationSoundError("Unknown error.");
|
||||
return;
|
||||
}
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
else if (media.Error == null && media.duration == 0.0){
|
||||
OnNotificationSoundError("File does not contain an audio track.");
|
||||
}
|
||||
else if (media.Error != null){
|
||||
OnNotificationSoundError(media.Error);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(media);
|
||||
}
|
||||
|
||||
private void player_MediaError(object pMediaObject){
|
||||
IWMPMedia2 media = pMediaObject as IWMPMedia2;
|
||||
|
||||
if (media == null){
|
||||
OnNotificationSoundError("Unknown error.");
|
||||
return;
|
||||
}
|
||||
else if (media.Error != null){
|
||||
OnNotificationSoundError(media.Error);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(media);
|
||||
}
|
||||
|
||||
private void OnNotificationSoundError(IWMPErrorItem error){
|
||||
OnNotificationSoundError(error.errorCode == -1072885353 ? "Invalid media file." : error.errorDescription);
|
||||
Marshal.ReleaseComObject(error);
|
||||
}
|
||||
|
||||
private void OnNotificationSoundError(string message){
|
||||
if (wasTryingToPlay){
|
||||
wasTryingToPlay = false;
|
||||
|
||||
if (!ignorePlaybackError && PlaybackError != null){
|
||||
PlaybackErrorEventArgs args = new PlaybackErrorEventArgs(message);
|
||||
PlaybackError(this, args);
|
||||
ignorePlaybackError = args.Ignore;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,114 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using TweetDck.Core.Utils;
|
||||
using WMPLib;
|
||||
using System.Runtime.InteropServices;
|
||||
using TweetDck.Core.Notification.Sound;
|
||||
|
||||
namespace TweetDck.Core.Notification{
|
||||
sealed class SoundNotification : IDisposable{ // TODO test on windows server
|
||||
public const string SupportedFormats = "*.wav;*.mp3;*.mp2;*.m4a;*.mid;*.midi;*.rmi;*.wma;*.aif;*.aifc;*.aiff;*.snd;*.au";
|
||||
static class SoundNotification{
|
||||
private static bool? IsWMPAvailable;
|
||||
|
||||
public event EventHandler<PlaybackErrorEventArgs> PlaybackError;
|
||||
|
||||
private readonly WindowsMediaPlayer player;
|
||||
private bool wasTryingToPlay;
|
||||
private bool ignorePlaybackError;
|
||||
|
||||
// changing the player volume also affects the value in the Windows mixer
|
||||
// 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
|
||||
// using the most code required for the least functionality with a sorry excuse for an API
|
||||
// thanks, Microsoft
|
||||
|
||||
public SoundNotification(){
|
||||
player = new WindowsMediaPlayer();
|
||||
player.settings.autoStart = false;
|
||||
player.settings.enableErrorDialogs = false;
|
||||
player.settings.invokeURLs = false;
|
||||
player.settings.volume = (int)Math.Floor(100.0*NativeCoreAudio.GetMixerVolumeForCurrentProcess());
|
||||
player.MediaChange += player_MediaChange;
|
||||
player.MediaError += player_MediaError;
|
||||
}
|
||||
|
||||
public void Play(string file){
|
||||
wasTryingToPlay = true;
|
||||
|
||||
if (player.URL != file){
|
||||
player.close();
|
||||
player.URL = file;
|
||||
ignorePlaybackError = false;
|
||||
}
|
||||
else{
|
||||
player.controls.stop();
|
||||
}
|
||||
|
||||
player.controls.play();
|
||||
}
|
||||
|
||||
public void Stop(){
|
||||
player.controls.stop();
|
||||
}
|
||||
|
||||
private void player_MediaChange(object item){
|
||||
IWMPMedia2 media = item as IWMPMedia2;
|
||||
|
||||
if (media == null){
|
||||
OnNotificationSoundError("Unknown error.");
|
||||
return;
|
||||
}
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
else if (media.Error == null && media.duration == 0.0){
|
||||
OnNotificationSoundError("File does not contain an audio track.");
|
||||
}
|
||||
else if (media.Error != null){
|
||||
OnNotificationSoundError(media.Error);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(media);
|
||||
}
|
||||
|
||||
private void player_MediaError(object pMediaObject){
|
||||
IWMPMedia2 media = pMediaObject as IWMPMedia2;
|
||||
|
||||
if (media == null){
|
||||
OnNotificationSoundError("Unknown error.");
|
||||
return;
|
||||
}
|
||||
else if (media.Error != null){
|
||||
OnNotificationSoundError(media.Error);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(media);
|
||||
}
|
||||
|
||||
private void OnNotificationSoundError(IWMPErrorItem error){
|
||||
OnNotificationSoundError(error.errorCode == -1072885353 ? "Invalid media file." : error.errorDescription);
|
||||
Marshal.ReleaseComObject(error);
|
||||
}
|
||||
|
||||
private void OnNotificationSoundError(string message){
|
||||
if (wasTryingToPlay){
|
||||
wasTryingToPlay = false;
|
||||
|
||||
if (!ignorePlaybackError && PlaybackError != null){
|
||||
PlaybackErrorEventArgs args = new PlaybackErrorEventArgs(message);
|
||||
PlaybackError(this, args);
|
||||
ignorePlaybackError = args.Ignore;
|
||||
public static ISoundNotificationPlayer New(){
|
||||
if (IsWMPAvailable.HasValue){
|
||||
if (IsWMPAvailable.Value){
|
||||
return new SoundPlayerImplWMP();
|
||||
}
|
||||
else{
|
||||
return new SoundPlayerImplFallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose(){
|
||||
player.close();
|
||||
Marshal.ReleaseComObject(player);
|
||||
}
|
||||
|
||||
public class PlaybackErrorEventArgs : EventArgs{
|
||||
public string Message { get; private set; }
|
||||
public bool Ignore { get; set; }
|
||||
|
||||
public PlaybackErrorEventArgs(string message){
|
||||
this.Message = message;
|
||||
this.Ignore = false;
|
||||
try{
|
||||
SoundPlayerImplWMP implWMP = new SoundPlayerImplWMP();
|
||||
IsWMPAvailable = true;
|
||||
return implWMP;
|
||||
}catch(COMException){
|
||||
IsWMPAvailable = false;
|
||||
return new SoundPlayerImplFallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,16 @@
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using TweetDck.Core.Notification;
|
||||
using TweetDck.Core.Notification.Sound;
|
||||
|
||||
namespace TweetDck.Core.Other.Settings{
|
||||
partial class TabSettingsSounds : BaseTabSettings{
|
||||
private readonly SoundNotification soundNotification;
|
||||
private readonly ISoundNotificationPlayer soundNotification;
|
||||
|
||||
public TabSettingsSounds(){
|
||||
InitializeComponent();
|
||||
|
||||
soundNotification = new SoundNotification();
|
||||
soundNotification = SoundNotification.New();
|
||||
soundNotification.PlaybackError += sound_PlaybackError;
|
||||
|
||||
tbCustomSound.Text = Config.NotificationSoundPath;
|
||||
@ -42,7 +43,7 @@ private void btnPlaySound_Click(object sender, EventArgs e){
|
||||
soundNotification.Play(tbCustomSound.Text);
|
||||
}
|
||||
|
||||
private void sound_PlaybackError(object sender, SoundNotification.PlaybackErrorEventArgs e){
|
||||
private void sound_PlaybackError(object sender, PlaybackErrorEventArgs e){
|
||||
MessageBox.Show("Could not play custom notification sound."+Environment.NewLine+e.Message, "Notification Sound Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
@ -51,7 +52,7 @@ private void btnBrowseSound_Click(object sender, EventArgs e){
|
||||
AutoUpgradeEnabled = true,
|
||||
DereferenceLinks = true,
|
||||
Title = "Custom Notification Sound",
|
||||
Filter = "Sound file ("+SoundNotification.SupportedFormats+")|"+SoundNotification.SupportedFormats+"|All files (*.*)|*.*"
|
||||
Filter = "Sound file ("+soundNotification.SupportedFormats+")|"+soundNotification.SupportedFormats+"|All files (*.*)|*.*"
|
||||
}){
|
||||
if (dialog.ShowDialog() == DialogResult.OK){
|
||||
tbCustomSound.Text = dialog.FileName;
|
||||
|
@ -123,6 +123,10 @@
|
||||
<DependentUpon>FormNotificationTweet.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Core\Notification\SoundNotification.cs" />
|
||||
<Compile Include="Core\Notification\Sound\SoundPlayerImplFallback.cs" />
|
||||
<Compile Include="Core\Notification\Sound\SoundPlayerImplWMP.cs" />
|
||||
<Compile Include="Core\Notification\Sound\ISoundNotificationPlayer.cs" />
|
||||
<Compile Include="Core\Notification\Sound\PlaybackErrorEventArgs.cs" />
|
||||
<Compile Include="Core\Notification\TweetNotification.cs" />
|
||||
<Compile Include="Core\Other\FormAbout.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
Loading…
Reference in New Issue
Block a user