MP3播放-基於MCI-API接口

今天整理到音頻播放的部分,原本就想抽取一個簡單的接口方便之後可能會用到,然而不知不覺就把經常使用的功能都給一塊兒封裝好了,核心其實就是調用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
}
View Code

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、參考資料

相關文章
相關標籤/搜索