利用waveXXX系列函数编写播放声音程序,采用双缓冲技术

最近搞了一个用于播放网络上传来的PCM数据的网络播放声音的东东,这里是主要是想说明一下如何使用waveXXX系列函数编写声音播放程序,同时要注意的就是为了保持声音播放的连续性采用了双缓冲的方式,可以先试单缓冲播放时听听效果,一播一卡一播一卡,采用了双缓冲以后声音马上连续播放了。


下面符上代码,直接在win32控制台程序下就可以运行:


// vc console
#include
#include
#include
#include
#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");
}



你可能感兴趣的:(Windows编程)