最近在寫音頻播放器,不過有點懶散,開發進度很慢,一天只做了一點點東西。其實就是讓程序能播放音頻。這個在我大二學winform程序開發時書上有說,那是書上教的是用media player的COM組件,而且當時什么也不會,寫出來的東西只能播放單個音頻。要播放完整個播放表的所有歌曲,必須得在播放完一個音頻時點擊播放下一個音頻,也就是不懂得自動切換音頻。當時也有想過,如果能獲取到一個音頻的長度就好了,但是那時候不懂得百度,即使百度了也不懂得那些Thread啊什么的。
現在對Thread有了一些認識,也用過系統的API,感覺寫個播放器完完全全沒問題,而且對一個單純用於聽歌的播放器有點自己的想法。於是上網搜搜相關資料。
不出我的所料,播放音頻能夠通過系統API來實現。其實播放音頻有兩種方式,第一種就是我大二時看書說的用media player的COM組件;第二種就是網上找到的系統API。
這篇文章呢就不是說我怎么怎么寫播放器,而是說說我在使用這個系統API時的一些感想罷了。
用到的API函數有兩個一個是GetShortPathName,另一個是mciSendString,同時還有一些在調用這些函數時用到的字符串遍歷,下面則是函數聲明和字符串變量的聲明
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern int GetShortPathName( string lpszLongPath, string shortFile, int cchBuffer ); [DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)] public static extern int mciSendString( string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback ); //定義API函數使用的字符串變量 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string Name = ""; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string durLength = ""; [MarshalAs(UnmanagedType.LPTStr, SizeConst = 128)] public string TemStr = "";
GetShortPathName方法主要是在載入音頻文件時用得到,其他地方沒發現用得着它。主要是用mciSendString,這些函數在MSDN上都能找到詳細的介紹,經發現其實用micSendString播放音樂就相當於發一系列的命令,由函數的第一個參數名就看出來了,可是MSDN上的那些指令的介紹我還沒看得明白,我所用到的指令都是在網上查回來的,說起來挺笨拙的,開了一個音頻播着,然后就弄個文本框輸入各種各樣的指令,看看這條指令對不對,這個很像我現在從事的工作里的有個操作——串口調試。
好了,既然說是通過指令的,那下面則把用到的指令分門別類地羅列一下
- 載入文件
open "+ 文件名 + " alias media
這里的文件名並不是平時資源管理器中的文件名或者全文件名,而是通過調用GetShortPathName方法得出來的文件名。alias 后面跟着那個media 其實是對當前打開的音頻作一個命名而已。這個命名是不唯一不能重復,但接着播放音樂,暫停、停止等操作都要用到它的。
- 設置格式
set media time format milliseconds
這里就用到上面的那個命名了,這里設成milliseconds(毫秒)是干嘛的呢,我也沒弄清楚,我試過設成seconds都是同樣沒變化的。
播放動作控制
play media //重頭開始播放
pause media //暫停播放
resume media //繼續播放
close media //停止播放
close all //關閉所有
play media FROM N To M //從N毫秒處開始播放到M處毫秒結束,不過這條命令可以不要后面的To M
- 關於時間
status media position //當前音頻的播放進度
status media length //當前音頻的長度
傳這兩個命令的時候,接收值就要用到micSendString方法的第二個參數了。
- 關於音量
setaudio media volume to Number //設置音量大小
這里的Number是0~1000的范圍
setaudio media off //關閉聲音
setaudio media on //開啟聲音
這個呢我只在我自己的系統Win7下試過,XP就沒試過不知怎么,Win7的系統音頻是一個合成器的模式,
每個進程都有它獨立的音量設置,與系統的音量不同,我們平時設置的音量其實是擴音器的音量。因此這里只能設當前進程的音量。並不會影響系統的音量。而且調節了音量在系統音頻合成器是看不到音量的滑塊有變化的,包括靜音。這一點我看了別的播放器,像我上面截圖的KuGoo啊,QQ影音也是這樣子的。其實還有另外的一個API函數可以設置音量的,那個函數就能改變上圖的音量滑塊了,但是仍然改變不了揚聲器的音量大小。我還想到一點,就是QQ影音和有一些視頻網站,它能把聲音調到100%以上,我最初有想過做成那樣子,不過現在沒找到方法,那個估計要對音頻的聲音波形放大的。還有一個就是這個音頻操作只對當前播放的音頻起作用,切換到下一個音頻的時候之前設的音量啊,開閉音量都沒作用的。
現在命令介紹完了,到說使用那個micSendString的狀況了。
我曾經嘗試開多線程去播放音樂,就是一條線程就載入一個音頻,播放這樣子。結果呢,一首歌沒播完,然后播另一首歌時,兩首歌同時響起,用了close all,stop這些命令都沒效果,后來發現了這個與調用micSendString方法時傳進去的第二個參數有關系,也就是說播放一個音頻的過程中發送的所有命令通通都用同一個lpstrReturnString對象做參數好了。
上面一段說到播放一個音頻就用同一個lpstrReturnString對象,要做到這個才能正常操作,而且也很節省資源,不用每次都構造一個新的對象。但也不能省過頭,我試過播放多個音頻都用了同一個lpstrReturnString對象,結果到有時候就發送命令失效了,要想得到音頻的長度獲取不到,要想播放音頻,沒播放。
以上的兩個問題我都找到了解決的辦法。但是下面這個我就想不明白是什么回事了。用winform程序去調用micSendString能成功調用,能播放到,但是同樣的代碼放到一個控制台里面就不一定能調用成功了,會播放不了的。為什么說不一定呢,當我建項目時選控制台類型,生成的exe它是播不了的,當我建項目是winform類型,生成把它改成控制台類型,生成的控制台又能成功播放了。網上有種說法是說“那個micSendString是跟窗體關聯的,控制台調用的話就播放不了的。”但我覺得還是解釋不了我這個奇怪的現象。呵呵!這個還要等各位園友來指教啊!
雖然對micSendString接觸了幾天,但我知道還是理解不透徹的,以上有什么說錯的還得請各位園友批評指正。謝謝!