大佬教程收集整理的这篇文章主要介绍了菜鸟也能学cocos2dx 3.3 AudioCache,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
最新的3.3cocos将openal也进行了引入,作为一个引擎使用者,当然是相当的开心!~ 那么我们首先来看一看~
#include "platform/CCPlatformConfig.h" #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #ifndef __AUDIO_CACHE_H_ #define __AUDIO_CACHE_H_ #include <String> #include <mutex> #include <vector> #include "CCPlatformMacros.h" #include "AL/al.h" #define QUEUEBUFFER_NUM 3 #define QUEUEBUFFER_TIME_STEP 0.1f NS_CC_BEGIN namespace experimental{ //前向声明 class AudioENGIneImpl; class AudioPlayer; class CC_DLL AudioCache{ public: //文件类型枚举 enum class FileFormat { UNKNOWN,//未知格式 OGG,// ogg格式音频,常用于android平台 MP3 // mp3格式音频,ios,android都较为常用 }; AudioCache();//构造函数 AudioCache(AudioCache&);//拷贝构造函数,值传递和用一个AudioCache去初始化另一个AudioCache的时候使用,尽量避免。 ~AudioCache();//析构函数 void addCallBACks(const std::function<void()> &callBACk);//添加回调,参数为函数指针(形如void XXX()) protected: void readDataTask(); //读数据任务 void invokingCallBACks();//请求回调 std::string _fileFullPath; FileFormat _fileFormat; //pcm data related stuff size_t _pcmDataSize; ALenum _alBufferFormat;//等于int32_t int _chAnnels; ALuint _sampleRate; //等于uint32_t size_t _bytesPerFrame; float _duration; /*Cache related stuff; * Cache pcm data when sizeInBytes less than PCMDATA_CACHEMAXSIZE */ ALuint _alBufferId;//等于uint32_t void* _pcmData; size_t _bytesOfRead; /*Queue buffer related stuff * Streaming in OpenAL when sizeInBytes greater then PCMDATA_CACHEMAXSIZE */ char* _queBuffers[QUEUEBUFFER_NUM]; ALsizei _queBufferSize[QUEUEBUFFER_NUM]; int _queBufferFrames; int _queBufferBytes; bool _alBufferReady; std::mutex _callBACkMutex; //c11的互斥锁 std::vector< std::function<void()> > _callBACks;//vector存放函数指针 std::mutex _readDataTaskMutex; int _mp3Encoding; friend class AudioENGIneImpl;//声明友元 friend class AudioPlayer; } ; } NS_CC_END #endif // __AUDIO_CACHE_H_ #endif
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 #include "AudioCache.h" #include <thread> #include <algorithm> #include "base/CCConsole.h" #include "mpg123.h" #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" #include "base/ccUtils.h" #define PCMDATA_CACHEMAXSIZE 2621440 using namespace cocos2d::experimental; //列表初始化 AudioCache::AudioCache() : _pcmData(nullptr),_pcmDataSize(0),_bytesOfRead(0),_alBufferReady(false),_fileFormat(FileFormat::UNKNOWN),_queBufferFrames(0),_queBufferBytes(0),_mp3Encoding(0) { //在这里其实就属于赋值了,不是初始化 } //拷贝构造 AudioCache::AudioCache(AudioCache& cachE) { _pcmData = cache._pcmData; _pcmDataSize = cache._pcmDataSize; _bytesOfRead = cache._bytesOfRead; _alBufferReady = cache._alBufferReady; _fileFormat = cache._fileFormat; _queBufferFrames = cache._queBufferFrames; _queBufferBytes = cache._queBufferBytes; _mp3Encoding = cache._mp3Encoding; } AudioCache::~AudioCache() { if(_pcmData){ if (_alBufferReady){ aldeleteBuffers(1,&_alBufferId);//释放缓存ID } //wait for the 'readDataTask' task to exit _readDataTaskMutex.lock();//上锁,等待读取数据任务离开 _readDataTaskMutex.unlock();//解锁 free(_pcmData);//释放指针,free接受参数为void* } if (_queBufferFrames > 0) {//有缓存帧数,则释放 for (int index = 0; index < QUEUEBUFFER_NUM; ++indeX) { free(_queBuffers[index]); } } } void AudioCache::readDataTask() { _readDataTaskMutex.lock();//上任务锁 OggVorbis_File* vf = nullptr;//定义一个ogg数据结构体指针 mpg123_handle* mpg123handle = nullptr;//定义一个MP3数据的结构体指针 long @R_321_10586@lFrames = 0; switch (_fileFormat) { case FileFormat::OGG: { vf = new OggVorbis_File;//申请一块新的内存,并调用OggVorbis_File的构造,初始化,vf指向内存首地址 if (ov_fopen(_fileFullPath.c_str(),vf)){//类似于fopen,开始读取数据,将数据存放在vf所在的内存地址 log("Input does not appear to be an Ogg bitstream.\n"); goto ExitThread;//不喜欢goto!除非跳多重循环! 这里表示直接跳到ExitThread所在代码段 } auto vi = ov_info(vf,-1);////得到文件信息 @R_321_10586@lFrames = (long)ov_pcm_@R_321_10586@l(vf,-1);//样本数 _bytesPerFrame = vi->chAnnels * 2;//声道数*2 =每个字节帧 _alBufferFormat = (vi->chAnnels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;//缓存模式设置 _sampleRate = vi->rate;//采样率 _pcmDataSize = @R_321_10586@lFrames * _bytesPerFrame; //扩展pcmdata的容量至指定大小 _duration = 1.0f * @R_321_10586@lFrames / _sampleRate;//持续时间 } break; case FileFormat::MP3: { long rate = 0; int error = MPG123_OK; mpg123handle = mpg123_new(nullptr,&error);//初始化,并且因为传入引用,可从error,获取成功或者失败信息 if (!mpg123handlE){ log("Basic setup goes wrong: %s",mpg123_plain_strerror(error)); goto ExitThread;//失败跳转,输出错误信息 } if (mpg123_open(mpg123handle,_fileFullPath.c_str()) != MPG123_OK || mpg123_getformat(mpg123handle,&rate,&_chAnnels,&_mp3Encoding) != MPG123_OK) { log("Trouble with mpg123: %s\n",mpg123_strerror(mpg123handlE) ); goto ExitThread; }//开始读取,并设置信息,如果失败,则跳转 if (_mp3Encoding == MPG123_ENC_SIGNED_16){ _bytesPerFrame = 2 * _chAnnels; } else if (_mp3Encoding == MPG123_ENC_FLOAT_32){ _bytesPerFrame = 4 * _chAnnels; } else{ log("Bad encoding: 0x%x!\n",_mp3Encoding); goto ExitThread; }//设置声道数量,根据不同的格式 _alBufferFormat = (_chAnnels > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; _sampleRate = rate;//同上 /* Ensure that this output format will not change (it could,when we allow it). */ mpg123_format_none(mpg123handlE); mpg123_format(mpg123handle,rate,_chAnnels,_mp3Encoding); /* Ensure that we can get accurate length by call mpg123_length */ mpg123_scan(mpg123handlE);//各个参数设置 auto framesLength = mpg123_length(mpg123handlE);//帧长度 @R_321_10586@lFrames = framesLength; _pcmDataSize = @R_321_10586@lFrames * _bytesPerFrame; _duration = 1.0f * @R_321_10586@lFrames / _sampleRate;//同上 } break; case FileFormat::UNKNOWN: default: break; } if (_pcmDataSize <= PCMDATA_CACHEMAXSIZE) { _pcmData = malloc(_pcmDataSizE);//不超过限制内存长度下,申请内存 auto alError = alGetError();//获得错误信息 alGenBuffers(1,&_alBufferId);//申请一个al缓存 alError = alGetError();//得到错误信息 if (alError != AL_NO_ERROR) { log("%s: attaching audio to buffer fail: %x\n",__FUNCTION__,alError); goto ExitThread; } switch (_fileFormat) { case FileFormat::OGG: { int current_section; unsigned int currPos = 0; long readRet = 0; do { readRet = ov_read(vf,(char*)_pcmData + _bytesOfRead,4096,2,1,¤t_section);//进行解码 if (readRet > 0){//readRet可能小于等于0,表示文件流中发生不明错误 _bytesOfRead += readRet; } } while (_bytesOfRead < _pcmDataSizE);//确保有读取到数据,有疑问!如果异常,陷入死循环? _alBufferReady = true; _bytesOfRead = _pcmDataSize; break; } case FileFormat::MP3: { size_t done = 0; auto err = mpg123_read(mpg123handle,(unsigned char*)_pcmData,_pcmDataSize,&donE);//mp3解码 if (err == MPG123_ERR){ log("Trouble with mpg123: %s\n",mpg123_strerror(mpg123handlE) ); goto ExitThread; } if (err == MPG123_DONE || err == MPG123_OK){//错误处理 _alBufferReady = true; _pcmDataSize = done; _bytesOfRead = done; } } break; case FileFormat::UNKNOWN: default: break; } alBufferData(_alBufferId,_alBufferFormat,_pcmData,_sampleRatE);//将数据放入缓存 } else{//数据量很大时 _queBufferFrames = _sampleRate * QUEUEBUFFER_TIME_STEP; _queBufferBytes = _queBufferFrames * _bytesPerFrame; for (int index = 0; index < QUEUEBUFFER_NUM; ++indeX) { _queBuffers[index] = (char*)malloc(_queBufferBytes);//3段申请内存 switch (_fileFormat){ case FileFormat::MP3: { size_t done = 0; mpg123_read(mpg123handle,(unsigned char*)_queBuffers[index],_queBufferBytes,&donE);//解码 _queBufferSize[index] = done; _bytesOfRead += done; } break; case FileFormat::OGG: { int current_section; auto readRet = ov_read(vf,_queBuffers[index],¤t_section);//解码 _queBufferSize[index] = readRet; } break; } } } //goto的目的代码段 ExitThread: switch (_fileFormat) { case FileFormat::OGG: ov_clear(vf);//字节流清空,该函数中已调用了fclose函数 delete vf; break; case FileFormat::MP3: mpg123_close(mpg123handlE); mpg123_delete(mpg123handlE);//关闭释放内存,数据都已存放到缓存中 break; case FileFormat::UNKNOWN: default: break; } _readDataTaskMutex.unlock();//读取数据完毕,解锁 if (_queBufferFrames > 0) _alBufferReady = true; invokingCallBACks(); } void AudioCache::invokingCallBACks() { _callBACkMutex.lock();//回调处理上锁 auto count = _callBACks.size(); for (size_t index = 0; index < count; ++indeX) { _callBACks[index]();//依次执行回调函数 } _callBACks.clear(); _callBACkMutex.unlock();//回调处理解锁 } void AudioCache::addCallBACks(const std::function<void ()> &callBACk) { _callBACkMutex.lock();//上锁 if (_alBufferReady) {//当数据已经在缓存中,直接执行回调 callBACk(); } else { _callBACks.push_BACk(callBACk);//否则,等待执行 } _callBACkMutex.unlock();//解锁 } #endif鉴于时间,不便多说,求指点!~~ T T
以上是大佬教程为你收集整理的菜鸟也能学cocos2dx 3.3 AudioCache全部内容,希望文章能够帮你解决菜鸟也能学cocos2dx 3.3 AudioCache所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。