今天整理到音頻播放的部分,原本就想抽取一個簡單的接口方便之後可能會用到,然而不知不覺就把經常使用的功能都給一塊兒封裝好了,核心其實就是調用MCI的API接口,具體的功能就是變換不一樣的MCI指令來實現。html
========== 原創做品 做者:未聞 出處:博客園 ==========ide
1、常見的音頻播放方式ui
* System.Media.SoundPlayer:播放wavspa
* MCI Command String:播放MP三、AVI等.net
* axWindowsMediaPlayer:COM組件,功能豐富易用code
2、 注意事項orm
* 應用於窗體程序,不能應用於控制檯程序(不知道是否是由於取不到窗體句柄,加Sleep也沒用,知道的不妨留言告知)htm
3、代碼blog
封裝好的類,能夠直接用了,這裏用了單例簡化了用法,其實只要別名不同,還能夠支持同時播放多個音頻。接口
/// <summary> /// MP3播放器(基於MCI-API接口) /// 做者:未聞 /// 時間:2020.02.13 /// /// 詳細的指令介紹 /// https://blog.csdn.net/psongchao/article/details/1487788 /// </summary> public class MP3Player { // 播放標記,MCI接口是基於這個標記來處理,看播放暫停等代碼就能明白,能夠存在多個不一樣Tag的播放器 private const string C_TAG_PLAYER = "MCI_MP3_PLAYER"; #region 單例模式實現 class Nested { public static MP3Player Instance = new MP3Player(); } private MP3Player() { //// 獲取聲道 //mciSendString($"status {C_TAG_PLAYER} source", _temp, _temp.Capacity, 0); //_source = _sourceMap.FirstOrDefault(pair => pair.Value.Equals(_temp.ToString())).Key; //// 音頻狀態,是否靜音 //mciSendString($"status {C_TAG_PLAYER} audio", _temp, _temp.Capacity, 0); //_audioStatus = _audioStatusMap.FirstOrDefault(pair => pair.Value.Equals(_temp.ToString())).Key; } public static MP3Player Instance => Nested.Instance; #endregion #region API定義 [DllImport("winmm.dll")] public static extern int mciSendString(string m_strCmd, StringBuilder m_strReceive, int m_v1, int m_v2); [DllImport("Kernel32", CharSet = CharSet.Auto)] static extern int GetShortPathName(string path, StringBuilder shortPath, int shortPathLength); #endregion private StringBuilder _temp = new StringBuilder(260); private Dictionary<AudioSource, string> _sourceMap = new Dictionary<AudioSource, string> { {AudioSource.H, "stereo"}, {AudioSource.A, "average"}, {AudioSource.L, "left"}, {AudioSource.R, "right"} }; private Dictionary<bool, string> _audioStatusMap = new Dictionary<bool, string> { {true, "on"}, {false, "off"} }; /// <summary> /// 播放 /// </summary> /// <param name="fileName"></param> public void Play(string fileName) { if (Status == PlayerStatus.Playing) { Stop(); } if (string.IsNullOrWhiteSpace(fileName)) return; GetShortPathName(fileName, _temp, _temp.Capacity); var mp3Path = _temp.ToString(); mciSendString($"open \"{mp3Path}\" alias {C_TAG_PLAYER}", null, 0, 0); //打開 mciSendString($"play {C_TAG_PLAYER}", null, 0, 0); Status = PlayerStatus.Playing; // 由於設置靜音後一播放,會變成有聲音,因此這裏要設置一下 AudioStatus = _audioStatus; Source = _source; } /// <summary> /// 中止 /// </summary> public void Stop() { mciSendString($"close {C_TAG_PLAYER}", null, 0, 0); Status = PlayerStatus.Stop; } /// <summary> /// 暫停 /// </summary> public void Pause() { mciSendString($"pause {C_TAG_PLAYER}", null, 0, 0); Status = PlayerStatus.Pause; } /// <summary> /// 播放狀態 /// </summary> public PlayerStatus Status { get; private set; } = PlayerStatus.Stop; private bool _audioStatus = true; /// <summary> /// 音頻狀態(true 開啓,false 靜音) /// </summary> public bool AudioStatus { get => _audioStatus; set { _audioStatus = value; mciSendString($"setaudio {C_TAG_PLAYER} {_audioStatusMap[value]}", null, 0, 0); } } private AudioSource _source = AudioSource.H; /// <summary> /// 播放聲道 /// </summary> public AudioSource Source { get => _source; set { _source = value; mciSendString($"setaudio {C_TAG_PLAYER} source to {_sourceMap[value]}", null, 0, 0); } } private int _vol; /// <summary> /// 音量 /// </summary> public int Volume { get => _vol; set { if (value < 0 || value > 1000) return; _vol = value; mciSendString($"setaudio {C_TAG_PLAYER} volume to {value}", null, 0, 0); } } /// <summary> /// 獲取是否正在播放 /// </summary> public bool IsPlaying => Status == PlayerStatus.Playing; /// <summary> /// 獲取是否已播放結束 /// </summary> public bool IsCompleted => Position >= Length; /// <summary> /// 獲取播放總時長 /// </summary> public int Length { get { mciSendString($"status {C_TAG_PLAYER} length", _temp, _temp.Capacity, 0); return Convert.ToInt32(_temp.ToString()); } } /// <summary> /// 獲取播放總時長(格式:00:00:00) /// </summary> public string LengthString { get { return Len2Time(Length); } } /// <summary> /// 獲取播放進度 /// </summary> public int Position { get { mciSendString($"status {C_TAG_PLAYER} position", _temp, _temp.Capacity, 0); return Convert.ToInt32(_temp.ToString()); } } /// <summary> /// 獲取播放進度(格式:00:00:00) /// </summary> public string PositionString { get { return Len2Time(Position); } } /// <summary> /// 把時長從int類型轉換成格式爲00:00:00的字符串 /// </summary> /// <param name="len"></param> /// <returns></returns> private string Len2Time(int len) { int sec = len / 1000 % 60; int min = len / 60000 % 60; int hour = len / 3600000; return string.Format("{0:D2}:{1:D2}:{2:D2}", hour, min, sec); } } public enum PlayerStatus { /// <summary> /// 中止 /// </summary> Stop = 0, /// <summary> /// 播放中 /// </summary> Playing = 1, /// <summary> /// 暫停 /// </summary> Pause = 2 } public enum AudioSource { /// <summary> /// 立體聲 /// </summary> H = 0, /// <summary> /// 平均聲道 /// </summary> A = 1, /// <summary> /// 左聲道 /// </summary> L = 2, /// <summary> /// 右聲道 /// </summary> R = 3 }
4、調用示例
MP3Player player = MP3Player.Instance; private void btnPlay_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { player.Play(openFileDialog1.FileName); tsslTotal.Text = player.LengthString;// 獲取總時長 tmrTick.Start(); } } private void timer1_Tick(object sender, EventArgs e) { tsslPosition.Text = player.PositionString;// 更新當前播放進度 if (player.IsCompleted) { tmrTick.Stop(); MessageBox.Show("播放結束。"); } }
5、參考資料