基于OpenAL的播放封装类.
头文件:
//
// TKAudioPlayer.h
// FLVPlayer
//
// Created by administrator on 14-7-11.
// Copyright (c) 2014年 trustsky. All rights reserved.
//
#include
#include "al.h"
#include "alc.h"
#define TK_OPENAL_BUFFER_LENGTH 4096
class TKAudioPlayer
{
public:
bool create(uint32_t channels, uint32_t sample_rate, uint32_t sample_bits) ;
bool destory();
bool start(bool pause) ;
bool stop();
bool update(uint8_t* buf, uint32_t len) ;
private:
void fillbuffer(ALuint bid, uint8_t* buf, uint32_t len);
uint32_t _channels ;
uint32_t _smplrate ;
uint32_t _smplbits ;
ALCdevice* _device ;
ALCcontext* _context ;
ALuint _source ;
ALuint _buffer[4] ;
uint8_t _boxbuf[TK_OPENAL_BUFFER_LENGTH] ;//由于音频数据的特性,来源可能不定长,但是播放时需要定长的数据,所以需要一个box用来整理。
uint32_t _uselen ;
};
实现文件:
#include "stdafx.h"
#include "TKAudioPlayer.h"
#pragma comment(lib, "OpenAL32.lib")
bool TKAudioPlayer::create(uint32_t channels, uint32_t sample_rate, uint32_t sample_bits)
{
_channels = channels ;
_smplrate = sample_rate ;
_smplbits = sample_bits ;
_device = alcOpenDevice(NULL) ;
if(_device)
{
_context = alcCreateContext(_device, NULL);
if(_context)
alcMakeContextCurrent(_context);
}
if(_device == NULL || _context == NULL)
{
if(_device)
alcCloseDevice(_device);
if(_context)
alcDestroyContext(_context);
_device = NULL ;
_context = NULL ;
return false ;
}
ALuint bufCount = sizeof(_buffer)/sizeof(ALuint) ;
alGenSources(1, &_source) ;//创建播放源。
alGenBuffers(bufCount, _buffer); //创建播放缓存。
alSourcei(_source, AL_LOOPING, AL_FALSE); //多个缓存播放 ,不能循环
memset(_boxbuf, 0, TK_OPENAL_BUFFER_LENGTH);
_uselen = 0 ;
//设置音频格式
for(ALuint idx=0; idxfillbuffer(_buffer[idx], _boxbuf ,TK_OPENAL_BUFFER_LENGTH);
//先填充空白数据
}
//将多个缓存添加到播放源
alSourceQueueBuffers(_source, bufCount, _buffer);
return true ;
}
void TKAudioPlayer::fillbuffer(ALuint bid, uint8_t* buf, uint32_t len)
{
if(_channels == 1)
{
if(_smplbits == 8)
alBufferData(bid, AL_FORMAT_MONO8, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
else if(_smplbits == 16)
alBufferData(bid, AL_FORMAT_MONO16, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
}
else if(_channels == 2)
{
if(_smplbits == 8)
alBufferData(bid, AL_FORMAT_STEREO8, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
else if(_smplbits == 16)
alBufferData(bid, AL_FORMAT_STEREO16, _boxbuf, TK_OPENAL_BUFFER_LENGTH, _smplrate);
}
}
bool TKAudioPlayer::destory()
{
this->stop();
ALuint bufCount = sizeof(_buffer)/sizeof(ALuint) ;
alDeleteBuffers(bufCount, _buffer);
alDeleteSources(1, &_source);
alcDestroyContext(_context);
alcCloseDevice(_device);
_device = NULL ;
_context = NULL ;
_source = 0 ;
memset(_buffer, 0, bufCount*sizeof(ALuint));
_channels = 0 ;
_smplrate = 0 ;
_smplbits = 0 ;
return false ;
}
bool TKAudioPlayer::start(bool pause)
{
if(pause)
alSourcePause(_source);
else
alSourcePlay(_source);
return true ;
}
bool TKAudioPlayer::stop()
{
alSourceStop(_source);
return true ;
}
bool TKAudioPlayer::update(uint8_t* buf, uint32_t len)
{
uint32_t bufempt = TK_OPENAL_BUFFER_LENGTH - _uselen ;
uint32_t usedLen = len < bufempt ? len : bufempt ;
memcpy(_boxbuf + _uselen , buf, usedLen);
_uselen += usedLen ;
if(_uselen == TK_OPENAL_BUFFER_LENGTH)
{//box 已经填满
int processed = 0 ;
ALuint buffer = 0 ;
do
{
alGetSourcei(_source, AL_BUFFERS_PROCESSED, &processed);
if(processed > 0)
{
alSourceUnqueueBuffers(_source, 1, &buffer);
this->fillbuffer(buffer, _boxbuf, TK_OPENAL_BUFFER_LENGTH);
_uselen = 0 ;
alSourceQueueBuffers(_source, 1, &buffer);
}
if(processed == 0)
Sleep(1);
}
while (processed == 0) ;
}
if(len > usedLen) //这一次的数据没使用完
this->update(buf+usedLen,len-usedLen); //递归
return true ;
}
使用演示:
typedef struct SMFKWaveFileFormat
{
uint32_t smfkSize ; /* the count in bytes of the size of */
uint16_t smfkFormatTag ; /* format type */
uint16_t smfkChannels ; /* number of channels (i.e. mono, stereo...) */
uint32_t smfkSamplesPerSec ; /* sample rate */
uint32_t smfkAvgBytesPerSec ; /* for buffer estimation */
uint16_t smfkBlockAlign ; /* block size of data */
uint16_t smfkBitsPerSample ; /* number of bits per sample of mono data */
}SMFKWaveFileFormat;
typedef struct SMFKWAVFileHeader
{
char rFlag[4] ;
uint32_t rLen ;
char wFlag[4] ;
char fFlag[4] ;
SMFKWaveFileFormat wavFormat ;
}SMFKWAVFileHeader;
typedef struct SMFKWavDataHeader
{
char dFlag[4] ;
uint32_t dLen ;
} SMFKWavDataHeader;
FILE* file = _wfopen(L"E:/测试素材/gala-追梦赤子心.wav", L"rb");
SMFKWAVFileHeader wavFileHeader ;
SMFKWavDataHeader wavDataHeader ;
fread(&wavFileHeader, 1, sizeof(SMFKWAVFileHeader), file);
fread(&wavDataHeader, 1, sizeof(SMFKWavDataHeader), file);
TKAudioPlayer player ;
player.create(wavFileHeader.wavFormat.smfkChannels, wavFileHeader.wavFormat.smfkSamplesPerSec,wavFileHeader.wavFormat.smfkBitsPerSample);
player.start(false);
uint8_t buffer[4000] ;
uint32_t readlen = 0 ;
while((readlen = fread(buffer, 1, 4000, file)))
player.update(buffer, readlen);
player.stop();
player.destory();