天天看點

C++ 播放音頻流(PCM裸流)--改善

#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,既然挖了坑就要填,今天乘着周末寫了一個雙緩存的Demo工程,代碼如下:

#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()   

    WAVEHDR         wh1;  

    WAVEHDR         wh2;  

    fopen_s(&pcmfile, "paomo.pcm", "rb");//打開檔案  

    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;  

from:http://blog.csdn.net/weixinhum/article/details/29943973?utm_source=tuicool&utm_medium=referral

繼續閱讀