標準元件(如 `SoundPlayer`、`MediaPlayer`)初始化緩衝會造成明顯延遲。對遊戲音效、即時提示等低延遲場景,直接 P/Invoke `winmm.dll` 是最佳選擇。
using System.Runtime.InteropServices;
public class AudioPlayer {
[DllImport("winmm.dll")]
private static extern long mciSendString(string command, StringBuilder returnString, int returnLength, IntPtr callback);
private string _alias = "MediaFile";
public void Play(string filePath) {
_alias = "\"" + filePath + "\"";
mciSendString($"close {_alias}", null, 0, IntPtr.Zero);
mciSendString($"open {_alias} type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
mciSendString("play MediaFile", null, 0, IntPtr.Zero);
}
public void Stop() {
mciSendString("close MediaFile", null, 0, IntPtr.Zero);
}
}
關鍵點:路徑含空白需雙引號包裹;`type mpegvideo` 讓 MCI 自動選擇解碼器;`alias` 避免重複開啟衝突。
public class MemoryWavPlayer {
private const int SND_ASYNC = 0x0001;
private const int SND_MEMORY = 0x0004;
[DllImport("winmm.dll", EntryPoint = "sndPlaySoundA")]
private static extern int sndPlaySound(byte[] sound, int flags);
private byte[] _wavBuffer;
public MemoryWavPlayer(string embeddedResourceName) {
var asm = Assembly.GetExecutingAssembly();
using (var stream = asm.GetManifestResourceStream(embeddedResourceName)) {
_wavBuffer = new byte[stream.Length];
stream.Read(_wavBuffer, 0, _wavBuffer.Length);
}
}
public void Play() {
sndPlaySound(_wavBuffer, SND_ASYNC | SND_MEMORY);
}
}
MCI / sndPlaySound 單一別名/緩衝不支援疊加。需求多聲道混音請改用:
| 問題 | 原因 | 解決 |
|---|---|---|
| 播放無聲 | 檔案路徑錯誤、別名衝突、格式不支援 | 檢查 `mciSendString` 回傳碼(非 0 為失敗),用 `mciGetErrorString` 取得錯誤訊息 |
| 中文路徑亂碼 | MCI 命令字串編碼 | 確保命令字串為 ANSI(`Encoding.Default`)或使用短路徑 `GetShortPathName` |
| 記憶體 WAV 播放失敗 | 資源名稱錯誤、非標準 PCM WAV | 驗證 `GetManifestResourceStream` 不為 null;WAV 必須為 PCM 格式 |
| 重複播放卡頓 | MCI 單實例限制 | 每次播放用唯一 alias(Guid),播放完 close 釋放 |
簡單提示音:嵌入 WAV + sndPlaySound(SND_MEMORY) 最輕量、延遲最低。
背景音樂/長音訊:MCI 命令 免安裝解碼器。
專業音訊應用:請直接引入 NAudio 或遊戲音訊中介軟體。