waveOutGetNumDevs:返回系统中的输出设备数量(可以不用)
waveOutGetDevCaps:检查指定输出设备特性(可以不用)
waveOutOpen:打开默认的wave设备
waveOutPrepareHeader:准备一个波形数据块用于播放
waveOutWrite:播放WAVEHDR中指定的音频数据
waveOutUnprepareHeader:清除由waveOutPrepareHeader完成的准备
waveOutClose:关闭设备
#include
#include
#include
#include "PlayPcm.h"
#define BLOCK_SIZE 8192
#define BLOCK_COUNT 20
static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD, DWORD, DWORD);
static WAVEHDR* allocateBlocks(int size, int count);
static void freeBlocks(WAVEHDR* blockArray);
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size);
static void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh, DWORD nSampleRate, WORD BitsPerSample);
static CRITICAL_SECTION waveCriticalSection;
static WAVEHDR* waveBlocks;
static volatile int waveFreeBlockCount;
static int waveCurrentBlock;
static BOOL waveOutFlag = FALSE;
static HWAVEOUT hWaveOut; /* device handle */
//int PlayPcm(int argc, char* argv[])
int PlayPcmInit()
{
//返回系统中的输出设备数量
int count = waveOutGetNumDevs();
printf("\n音频输出数量:%d\n", count);
if (count == 0)
{
return 0;
}
//检查指定输出设备特性 参数:输出设备标识/句柄;结构体指针;结构体大小
WAVEOUTCAPS waveOutcaps;
MMRESULT mmResult = waveOutGetDevCaps(0, &waveOutcaps, sizeof(WAVEOUTCAPS));
//WAVEOUTCAPS 结构体参数:wMid驱动程序标识、wPid输出设备产品标识、vDriverVersion驱动程序版本号、szPname[MAXPNAMELEN]制造商名称、dwFormats支持的格式、wChannels支持的声道数
printf("\n音频输出设备:%s\n", waveOutcaps.szPname);
if (MMSYSERR_NOERROR == mmResult)
{
WAVEFORMATEX wfx;
char buffer[1024];
int i;
/*
* 初始化模块变量
*/
waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
waveFreeBlockCount = BLOCK_COUNT;
waveCurrentBlock = 0;
InitializeCriticalSection(&waveCriticalSection);
/*
*设置WAVEFORMATEX结构。
*/
WaveInitFormat(&wfx, 1, 16000, 16);
/*
* 尝试打开默认的wave设备,WAVE_MAPPER是mmsystem.h中定义的常量,它总是指向系统上默认的wave设备
*/
if (waveOutOpen(
&hWaveOut,
WAVE_MAPPER,
&wfx,
(DWORD_PTR)waveOutProc,
(DWORD_PTR)&waveFreeBlockCount,
CALLBACK_FUNCTION
) != MMSYSERR_NOERROR)
{
return 0;
ExitProcess(1);
}
else
{
waveOutFlag = TRUE;
}
return 1;
}
else
{
return 0;
}
}
int PlayPcm(LPSTR buffer,int len)
{
if (waveOutFlag) {
if (buffer == NULL)
return 0;
if(1< sizeof(buffer))
{
writeAudio(hWaveOut, buffer, len);
}
return 1;
}
else
return 0;
}
int PlayPcmEnd()
{
int i;
for (i = 0; i < waveFreeBlockCount; i++)
if (waveBlocks[i].dwFlags & WHDR_PREPARED)
{
waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
}
DeleteCriticalSection(&waveCriticalSection);
freeBlocks(waveBlocks);
waveOutClose(hWaveOut);
return 1;
}
void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size)
{
WAVEHDR* current;
int remain;
current = &waveBlocks[waveCurrentBlock];
while (size > 0) {
/*
* 首先确保我们要使用的头是准备好的
*/
if (current->dwFlags & WHDR_PREPARED)
waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
if (size < (int)(BLOCK_SIZE - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, size);
current->dwUser += size;
break;
}
remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
size -= remain;
data += remain;
current->dwBufferLength = BLOCK_SIZE;
waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
EnterCriticalSection(&waveCriticalSection);
waveFreeBlockCount--;
LeaveCriticalSection(&waveCriticalSection);
/*
* 等待一个块释放
*/
while (!waveFreeBlockCount)
Sleep(10);
/*
* 指向下一个区
*/
waveCurrentBlock++;
waveCurrentBlock %= BLOCK_COUNT;
current = &waveBlocks[waveCurrentBlock];
current->dwUser = 0;
}
}
WAVEHDR* allocateBlocks(int size, int count)
{
unsigned char* buffer;
int i;
WAVEHDR* blocks;
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
/*
* 一次性为整个内存集分配内存
*/
if ((buffer = HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
totalBufferSize
)) == NULL)
{
fprintf(stderr, "Memory allocation error\n");
ExitProcess(1);
}
/*
* 并设置指向每一位的指针
*/
blocks = (WAVEHDR*)buffer;
buffer += sizeof(WAVEHDR) * count;
for (i = 0; i < count; i++) {
blocks[i].dwBufferLength = size;
blocks[i].lpData = buffer;
buffer += size;
}
return blocks;
}
void freeBlocks(WAVEHDR* blockArray)
{
HeapFree(GetProcessHeap(), 0, blockArray);
}
static void CALLBACK waveOutProc(
HWAVEOUT hWaveOut,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
/*
* 指向空闲块计数器的指针
*/
int* freeBlockCounter = (int*)dwInstance;
/*
* 忽略由于打开和关闭设备而发生的调用
*/
if (uMsg != WOM_DONE)
return;
EnterCriticalSection(&waveCriticalSection);
(*freeBlockCounter)++;
LeaveCriticalSection(&waveCriticalSection);
}
void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh, DWORD nSampleRate, WORD BitsPerSample)
{
m_WaveFormat->wFormatTag = WAVE_FORMAT_PCM;
m_WaveFormat->nChannels = nCh;//声道数,单声道一个,立体声两个
m_WaveFormat->nSamplesPerSec = nSampleRate;//采样率 8000、11025、22050、44100Hz
m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample / 8;//每秒平均数据传输速率
m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample / 8;//单帧数据量
m_WaveFormat->wBitsPerSample = BitsPerSample;//采样精度
m_WaveFormat->cbSize = 0;//保留
}
本文参考了:https://blog.csdn.net/zhangxizhicn/article/details/6843589