利用waveXXX系列函數編寫播放聲音程式,採用雙緩衝技術

來源:互聯網
上載者:User

最近搞了一個用於播放網路上傳來的PCM資料的網路播放聲音的東東,這裡是主要是想說明一下如何使用waveXXX系列函數編寫聲音播放程式,同時要注意的就是為了保持聲音播放的連續性採用了雙緩衝的方式,可以先試單緩衝播放時聽聽效果,一播一卡一播一卡,採用了雙緩衝以後聲音馬上連續播放了。

下面符上代碼,直接在win32控制台程式下就可以運行:

// vc console
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#include <mmreg.h>
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Ws2_32.lib")

#define IP "192.168.1.131"

int _tmain(int argc, _TCHAR* argv[])
{
    //初始化網路
    WSADATA wsa;
    DWORD nResult = WSAStartup( MAKEWORD(2,2), &wsa );
    if( nResult != 0 )
    {
        printf("WSAStartup初始化網路失敗! 錯誤號碼: %d\n", WSAGetLastError());
        return 0;
    }
    else
    {
        printf("WSAStartup初始化網路成功!\n");
    }

    //建立SOCKET通訊端
    SOCKET ClientSock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if( ClientSock == INVALID_SOCKET )
    {
        printf( "socket建立失敗! 錯誤號碼: %d\n", WSAGetLastError() );
        return 0;
    }
    else
    {
        printf( "socket建立成功!\n" );
    }

    //定義地址
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_port = 8000;
    addr.sin_addr.S_un.S_addr = inet_addr( IP );    // INADDR_ANY

    //綁定地址
    if ( SOCKET_ERROR == connect( ClientSock, (sockaddr*)&addr, sizeof(addr) ) )
    {
        printf( "connect函數連結地址失敗! 錯誤號碼: %d\n", WSAGetLastError() );
        return 0;
    }
    else
    {
        printf( "connect函數連結地址成功!\n" );
    }

    //----------------------------------------------------------------------------

    HWAVEOUT hWaveOut; //波形音訊輸出控制代碼

    WAVEFORMATEX waveformat;
    memset(&waveformat, 0x00, sizeof(WAVEFORMATEX));

    // 典型參數設定方法
    waveformat.nSamplesPerSec  = 44100;  /* sample rate */  
    waveformat.wBitsPerSample  = 16;     /* sample size */  
    waveformat.nChannels       = 2;      /* channels    */  
    waveformat.cbSize          = 0;      /* size of _extra_ info */  
    waveformat.wFormatTag      = WAVE_FORMAT_PCM;//WAVE_FORMAT_PCM;  
    waveformat.nBlockAlign     = (waveformat.wBitsPerSample * waveformat.nChannels) >> 3;  
    waveformat.nAvgBytesPerSec = waveformat.nBlockAlign * waveformat.nSamplesPerSec;  

    waveOutOpen (&hWaveOut, WAVE_MAPPER,&waveformat,0, 0, CALLBACK_NULL);

    /*
    這裡要注意的就是對於音頻要採用雙緩衝技術來保證聲音的連續性,
    所謂雙緩衝就是使用兩個WAVEHDR結構體與HWAVEOUT進行綁定,綁定
    就是通過waveOutPrepareHeader (hWaveOut, waveHdr[i], sizeof (WAVEHDR));實現的,
    然後在播放的時候分別播放兩個waveOutWrite (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
    */
    LPBYTE    lpData[2]; // = { 0x80 };
    LPWAVEHDR waveHdr[2];    //音頻資料資訊頭
    
    //這裡是分配記憶體
    for(int i=0; i<2; i++)
    {
        lpData[i] = new BYTE[65536];
        memset(lpData[i], 0x80, 65536);    //在音頻資料中0x80代表靜音符號

        waveHdr[i] = new WAVEHDR;
        memset(waveHdr[i], 0x00, sizeof(WAVEHDR));
    }

    //這裡是對上面的資料進行初始化
    for(int i=0; i<2; i++)
    {
        waveHdr[i]->lpData = (LPSTR)lpData[i] ;
        waveHdr[i]->dwBufferLength = 65536;
        waveHdr[i]->dwFlags = WHDR_PREPARED; //#define WHDR_PREPARED   0x00000002  /* set if this header has been prepared */
        waveHdr[i]->dwLoops = 0;

        //準備資訊頭
        waveOutPrepareHeader (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
    }

    while(1)
    {
        for(int i=0; i<2; i++)
        {
            if(SOCKET_ERROR == recv(ClientSock, (char*)lpData[i], 65536, 0))
                break;
            waveOutWrite (hWaveOut, waveHdr[i], sizeof (WAVEHDR));
        }
    }

    printf("播放完成!\n");
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.