前言:
在WPF开发中,需要用到播放某个语音文件的情况。今天实现了MediaPlayer的封装(实现了循环播放、WPF的线程安全),在这做个记录方便查找
实现
1、添加一个MediaPlayerHelper类。提供播放,暂停、停止、循环播放功能
public class MediaPlayerHelper
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private static int _inTimer = 0;
private MediaPlayer mediaPlayer = new MediaPlayer();
private Dispatcher dispatcher;
private bool isLooping = false;
public event EventHandler MediaEnded;
public MediaPlayerHelper()
{
mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
mediaPlayer.MediaFailed += MediaPlayer_MediaFailed;
}
private void MediaPlayer_MediaFailed(object sender, ExceptionEventArgs e)
{
_logger.Error(e.ErrorException.Message);
_logger.Error(e.ErrorException.StackTrace);
}
/// <summary>
///
/// </summary>
/// <param name="uiDispatcher">UI线程的Dispatcher</param>
public MediaPlayerHelper(Dispatcher uiDispatcher = null) : this()
{
dispatcher = uiDispatcher;
}
/// <summary>
///
/// </summary>
/// <param name="fileName">音频文件名,带扩展名</param>
/// <param name="loop">是否循环</param>
/// <exception cref="ArgumentException"></exception>
private void MediaPlay(string fileName, bool loop = false)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentException("Path cannot be null or empty.", nameof(fileName));
try
{
if (Interlocked.Exchange(ref _inTimer, 1) == 0)
{
SetVolume(1);
var path = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Sound", fileName);
if (File.Exists(path))
{
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
isLooping = loop;
mediaPlayer.Open(new Uri(path, UriKind.Absolute));
mediaPlayer.Play();
});
}
else
{
isLooping = loop;
mediaPlayer.Open(new Uri(path, UriKind.Absolute));
mediaPlayer.Play();
}
}
}
}
catch (Exception ex)
{
_logger.Error($"播放语音[{fileName}]失败,{ex.Message}");
_logger.Error(ex.StackTrace);
}
}
/// <summary>
/// 暂停
/// </summary>
public void Pause()
{
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
if (mediaPlayer.CanPause)
{
mediaPlayer.Pause();
}
});
}
else
{
if (mediaPlayer.CanPause)
{
mediaPlayer.Pause();
}
}
}
/// <summary>
/// 停止播放
/// </summary>
public void Stop()
{
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
isLooping = false;
mediaPlayer.Stop();
Interlocked.Exchange(ref _inTimer, 0);
});
}
else
{
isLooping = false;
mediaPlayer.Stop();
Interlocked.Exchange(ref _inTimer, 0);
}
}
/// <summary>
/// 设置音量
/// </summary>
/// <param name="volume"></param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public void SetVolume(double volume)
{
if (volume < 0 || volume > 1)
throw new ArgumentOutOfRangeException(nameof(volume), "Volume must be between 0.0 and 1.0.");
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
mediaPlayer.Volume = volume;
});
}
else
{
mediaPlayer.Volume = volume;
}
}
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
{
if (isLooping)
{
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
mediaPlayer.Position = TimeSpan.Zero;
//mediaPlayer.Play();
});
}
else
{
mediaPlayer.Position = TimeSpan.Zero;
//mediaPlayer.Play();
}
}
Interlocked.Exchange(ref _inTimer, 0);
MediaEnded?.Invoke(this, e);
}
/// <summary>
/// 设置进度
/// </summary>
/// <param name="position"></param>
public void Seek(TimeSpan position)
{
if (dispatcher != null)
{
dispatcher.Invoke(() =>
{
mediaPlayer.Position = position;
});
}
else
{
mediaPlayer.Position = position;
}
}
/// <summary>
/// 播放
/// </summary>
/// <param name="fileName">音频文件名,带扩展名</param>
/// <param name="loop">是否循环</param>
public void Play(string fileName, bool loop = false)
{
MediaPlay(fileName, loop);
}
}
2、调用实例
public partial class MainWindow : Window
{
private static MediaPlayerHelper mediaPlayer = new MediaPlayerHelper(Application.Current.Dispatcher);
public MainWindow()
{
InitializeComponent();
this.Loaded += frm_Loaded;
this.Unloaded += frm_Unloaded;
}
private void frm_Loaded(object sender, RoutedEventArgs e)
{
mediaPlayer.PlayOk(true);
}
private void frm_Unloaded(object sender, RoutedEventArgs e)
{
mediaPlayer.Stop();
}
} 


评论一下吧
取消回复 评论守则