直接上代碼。假設有需要可以直接建一個win32控制檯程序而後將代碼拷過去改個文件名稱就可以用了(注意將聲道和頻率與你本身的文件相應)。固然我本身也用VS2008寫了個樣例上傳了,假設有需要下載地址例如如下:點擊打開連接。緩存
這份代碼是打開文件截取一段數據而後播放的,可以輕鬆的通過加一條線程的方式改爲網絡傳輸的形式,但通過本人測試,因爲沒有緩存機制會有「噠噠」的噪聲,也就是說這份代碼在網絡實時音頻上的表現並不太好。爲了解決問題,可以加上緩存機制,本人因爲一開始用的是事件響應方式。因此一直困在這個框架裏,不能很是好的利用緩存的機制解決上面提到的問題,後來嘗試了用回調函數的方式來響應數據播放完畢的消息。問題就輕鬆的攻克了。網絡
那部分的代碼會在稍候放上去。框架
#include "stdafx.h" #include <stdio.h> #include <Windows.h> #pragma comment(lib, "winmm.lib") char buf[1024 * 1024 * 4]; int _tmain(int argc, _TCHAR* argv[]) { FILE* thbgm;//文件 int cnt; HWAVEOUT hwo; WAVEHDR wh; WAVEFORMATEX wfx; HANDLE wait; wfx.wFormatTag = WAVE_FORMAT_PCM;//設置波形聲音的格式 wfx.nChannels = 1;//設置音頻文件的通道數量 wfx.nSamplesPerSec = 8000;//設置每個聲道播放和記錄時的樣本頻率 wfx.nAvgBytesPerSec = 16000;//設置請求的平均傳輸數據率,單位byte/s。這個值對於建立緩衝大小是很是實用的 wfx.nBlockAlign = 2;//以字節爲單位設置塊對齊 wfx.wBitsPerSample = 16; wfx.cbSize = 0;//額外信息的大小 wait = CreateEvent(NULL, 0, 0, NULL); waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);//打開一個給定的波形音頻輸出裝置來進行回放 fopen_s(&thbgm, "paomo.pcm", "rb"); cnt = fread(buf, sizeof(char), 1024 * 1024 * 4, thbgm);//讀取文件4M的數據到內存來進行播放。經過這個部分的改動,添加線程可變成網絡音頻數據的實時傳輸。固然假設但願播放完整的音頻文件,也是要在這裏略微改一改 int dolenght = 0; int playsize = 1024; while (cnt) {//這一部分需要特別注意的是在循環回來以後不能花太長的時間去作讀取數據之類的工做,否則在每個循環的間隙會有「噠噠」的噪音 wh.lpData = buf + dolenght; wh.dwBufferLength = playsize; wh.dwFlags = 0L; wh.dwLoops = 1L; waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));//準備一個波形數據塊用於播放 waveOutWrite(hwo, &wh, sizeof(WAVEHDR));//在音頻媒體中播放第二個函數wh指定的數據 WaitForSingleObject(wait, INFINITE);//用來檢測hHandle事件的信號狀態,在某一線程中調用該函數時,線程臨時掛起,假設在掛起的INFINITE毫秒內。線程所等待的對象變爲有信號狀態。則該函數立刻返回 dolenght = dolenght + playsize; cnt = cnt - playsize; } waveOutClose(hwo); fclose(thbgm); return 0; }
離寫上面部分已通過了快一年。現在回看以前寫的代碼感受略爲坑爹,也許是進步了吧。函數
以前說要把雙緩存的代碼放出來。哪知道後來忙別的項目去了,這部分就丟到一邊,去老項目中提代替碼感受好煩一直沒弄。在這一年中很多人發私信問我關於這部分代碼怎樣寫的事,沒想到現在作音頻的人還真很多呢。Ok。既然挖了坑就要填,今天乘着週末寫了一個雙緩存的Demoproject,代碼例如如下:oop
#include <stdio.h> #include <Windows.h> #pragma comment(lib, "winmm.lib") #define DATASIZE 1024*512 //分次截取數據大小 FILE* pcmfile; //音頻文件 HWAVEOUT hwo; void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD dw1, DWORD dw2)//回調函數 { switch (uMsg) { case WOM_DONE://上次緩存播放完畢,觸發該事件 { LPWAVEHDR pWaveHeader = (LPWAVEHDR)dw1; pWaveHeader->dwBufferLength = fread(pWaveHeader->lpData, 1, DATASIZE, pcmfile);; waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR)); waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR)); break; } } } void main() { int cnt; WAVEHDR wh1; WAVEHDR wh2; WAVEFORMATEX wfx; fopen_s(&pcmfile, "paomo.pcm", "rb");//打開文件 wfx.wFormatTag = WAVE_FORMAT_PCM;//設置波形聲音的格式 wfx.nChannels = 1;//設置音頻文件的通道數量 wfx.nSamplesPerSec = 8000;//設置每個聲道播放和記錄時的樣本頻率 wfx.nAvgBytesPerSec = 16000;//設置請求的平均傳輸數據率,單位byte/s。這個值對於建立緩衝大小是很是實用的 wfx.nBlockAlign = 2;//以字節爲單位設置塊對齊 wfx.wBitsPerSample = 16; wfx.cbSize = 0;//額外信息的大小 waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);//打開一個給定的波形音頻輸出裝置來進行聲音播放,方式爲回調函數方式。假設是對話框程序,可以將第五個參數改成(DWORD)this。操做跟本Demo程序相似 wh1.dwLoops = 0L;//播放區一 wh1.lpData = new char[DATASIZE]; wh1.dwBufferLength = DATASIZE; fread(wh1.lpData, 1, DATASIZE, pcmfile); wh1.dwFlags = 0L; waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));//準備一個波形數據塊用於播放 waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//在音頻媒體中播放第二個參數指定的數據,也至關於開啓一個播放區的意思 wh2.dwLoops = 0L;//播放區二,基本同上 wh2.lpData = new char[DATASIZE]; wh2.dwBufferLength = DATASIZE; fread(wh2.lpData, 1, DATASIZE, pcmfile); wh2.dwFlags = 0L; waveOutPrepareHeader(hwo, &wh2, sizeof(WAVEHDR)); waveOutWrite(hwo, &wh2, sizeof(WAVEHDR)); while (wh1.dwBufferLength != 0 || wh2.dwBufferLength != 0)//假設文件還在沒播放完則等待500ms { Sleep(500); } waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//清理數據 waveOutUnprepareHeader(hwo, &wh2, sizeof(WAVEHDR)); delete []wh1.lpData; delete []wh2.lpData; fclose(pcmfile);//關閉文件 return; }this
只是提醒下,本人已然拋棄了VS2008。直接用VS2013,假設還在用老平臺的話要用仍是要折騰一會的。 spa