mirror of https://github.com/axmolengine/axmol.git
Merge pull request #12742 from WenhaiLin/v3-audioengine-preload
AudioEngine:support preload for audio
This commit is contained in:
commit
db71e073dd
|
@ -23,6 +23,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#include <condition_variable>
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||
|
||||
|
@ -61,8 +62,110 @@ AudioEngine::ProfileHelper* AudioEngine::_defaultProfileHelper = nullptr;
|
|||
std::unordered_map<int, AudioEngine::AudioInfo> AudioEngine::_audioIDInfoMap;
|
||||
AudioEngineImpl* AudioEngine::_audioEngineImpl = nullptr;
|
||||
|
||||
AudioEngine::AudioEngineThreadPool* AudioEngine::s_threadPool = nullptr;
|
||||
|
||||
class AudioEngine::AudioEngineThreadPool
|
||||
{
|
||||
public:
|
||||
AudioEngineThreadPool(bool detach)
|
||||
: _numThread(6)
|
||||
, _detach(detach)
|
||||
{
|
||||
s_threadPool = this;
|
||||
|
||||
_threads.reserve(_numThread);
|
||||
_tasks.reserve(_numThread);
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_tasks.push_back(nullptr);
|
||||
_threads.push_back(std::thread(std::bind(&AudioEngineThreadPool::threadFunc, this, index)));
|
||||
if (_detach)
|
||||
{
|
||||
_threads[index].detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addTask(const std::function<void()> &task){
|
||||
_taskMutex.lock();
|
||||
int targetIndex = -1;
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
if (_tasks[index] == nullptr) {
|
||||
targetIndex = index;
|
||||
_tasks[index] = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetIndex == -1) {
|
||||
_tasks.push_back(task);
|
||||
_threads.push_back(std::thread(std::bind(&AudioEngineThreadPool::threadFunc, this, _numThread)));
|
||||
if (_detach)
|
||||
{
|
||||
_threads[_numThread].detach();
|
||||
}
|
||||
_numThread++;
|
||||
}
|
||||
_taskMutex.unlock();
|
||||
_sleepCondition.notify_all();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(_sleepMutex);
|
||||
_sleepCondition.notify_all();
|
||||
|
||||
if (!_detach)
|
||||
{
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_threads[index].join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::thread> _threads;
|
||||
std::vector< std::function<void()> > _tasks;
|
||||
|
||||
void threadFunc(int index)
|
||||
{
|
||||
while (s_threadPool == this) {
|
||||
std::function<void()> task = nullptr;
|
||||
_taskMutex.lock();
|
||||
task = _tasks[index];
|
||||
_taskMutex.unlock();
|
||||
|
||||
if (nullptr == task)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(_sleepMutex);
|
||||
_sleepCondition.wait(lk);
|
||||
continue;
|
||||
}
|
||||
|
||||
task();
|
||||
|
||||
_taskMutex.lock();
|
||||
_tasks[index] = nullptr;
|
||||
_taskMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int _numThread;
|
||||
|
||||
std::mutex _taskMutex;
|
||||
std::mutex _sleepMutex;
|
||||
std::condition_variable _sleepCondition;
|
||||
bool _detach;
|
||||
};
|
||||
|
||||
void AudioEngine::end()
|
||||
{
|
||||
if (s_threadPool)
|
||||
{
|
||||
s_threadPool->destroy();
|
||||
delete s_threadPool;
|
||||
s_threadPool = nullptr;
|
||||
}
|
||||
|
||||
delete _audioEngineImpl;
|
||||
_audioEngineImpl = nullptr;
|
||||
|
||||
|
@ -82,6 +185,18 @@ bool AudioEngine::lazyInit()
|
|||
}
|
||||
}
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||
if (_audioEngineImpl && s_threadPool == nullptr)
|
||||
{
|
||||
s_threadPool = new (std::nothrow) AudioEngineThreadPool(true);
|
||||
}
|
||||
#elif CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
|
||||
if (_audioEngineImpl && s_threadPool == nullptr)
|
||||
{
|
||||
s_threadPool = new (std::nothrow) AudioEngineThreadPool(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -415,4 +530,28 @@ AudioProfile* AudioEngine::getProfile(const std::string &name)
|
|||
}
|
||||
}
|
||||
|
||||
void AudioEngine::preload(const std::string& filePath)
|
||||
{
|
||||
lazyInit();
|
||||
|
||||
if (_audioEngineImpl)
|
||||
{
|
||||
if (!FileUtils::getInstance()->isFileExist(filePath)){
|
||||
return;
|
||||
}
|
||||
|
||||
_audioEngineImpl->preload(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioEngine::addTask(const std::function<void()> &task)
|
||||
{
|
||||
lazyInit();
|
||||
|
||||
if (_audioEngineImpl && s_threadPool)
|
||||
{
|
||||
s_threadPool->addTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2014 Chukong Technologies Inc.
|
||||
Copyright (c) 2014-2015 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
|
@ -432,4 +432,9 @@ void AudioEngineImpl::setFinishCallback(int audioID, const std::function<void (i
|
|||
_audioPlayers[audioID]._finishCallback = callback;
|
||||
}
|
||||
|
||||
void AudioEngineImpl::preload(const std::string& filePath)
|
||||
{
|
||||
CCLOG("Preload not support on Anroid");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2014 Chukong Technologies Inc.
|
||||
Copyright (c) 2014-2015 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
|
@ -88,6 +88,7 @@ public:
|
|||
|
||||
void uncache(const std::string& filePath){}
|
||||
void uncacheAll(){}
|
||||
void preload(const std::string& filePath);
|
||||
|
||||
void update(float dt);
|
||||
private:
|
||||
|
|
|
@ -38,8 +38,6 @@ NS_CC_BEGIN
|
|||
namespace experimental{
|
||||
#define MAX_AUDIOINSTANCES 24
|
||||
|
||||
class AudioEngineThreadPool;
|
||||
|
||||
class AudioEngineImpl : public cocos2d::Ref
|
||||
{
|
||||
public:
|
||||
|
@ -61,14 +59,12 @@ public:
|
|||
|
||||
void uncache(const std::string& filePath);
|
||||
void uncacheAll();
|
||||
|
||||
AudioCache* preload(const std::string& filePath);
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
void _play2d(AudioCache *cache, int audioID);
|
||||
|
||||
AudioEngineThreadPool* _threadPool;
|
||||
|
||||
ALuint _alSources[MAX_AUDIOINSTANCES];
|
||||
|
||||
//source,used
|
||||
|
|
|
@ -42,93 +42,6 @@ using namespace cocos2d::experimental;
|
|||
static ALCdevice *s_ALDevice = nullptr;
|
||||
static ALCcontext *s_ALContext = nullptr;
|
||||
|
||||
namespace cocos2d {
|
||||
namespace experimental {
|
||||
class AudioEngineThreadPool
|
||||
{
|
||||
public:
|
||||
AudioEngineThreadPool()
|
||||
: _running(true)
|
||||
, _numThread(6)
|
||||
{
|
||||
_threads.reserve(_numThread);
|
||||
_tasks.reserve(_numThread);
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_tasks.push_back(nullptr);
|
||||
_threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,index) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void addTask(const std::function<void()> &task){
|
||||
_taskMutex.lock();
|
||||
int targetIndex = -1;
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
if (_tasks[index] == nullptr) {
|
||||
targetIndex = index;
|
||||
_tasks[index] = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetIndex == -1) {
|
||||
_tasks.push_back(task);
|
||||
_threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,_numThread) ) );
|
||||
|
||||
_numThread++;
|
||||
}
|
||||
_taskMutex.unlock();
|
||||
|
||||
_sleepCondition.notify_all();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
_running = false;
|
||||
_sleepCondition.notify_all();
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_threads[index].join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _running;
|
||||
std::vector<std::thread> _threads;
|
||||
std::vector< std::function<void ()> > _tasks;
|
||||
|
||||
void threadFunc(int index)
|
||||
{
|
||||
while (_running) {
|
||||
std::function<void ()> task = nullptr;
|
||||
_taskMutex.lock();
|
||||
task = _tasks[index];
|
||||
_taskMutex.unlock();
|
||||
|
||||
if (nullptr == task)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(_sleepMutex);
|
||||
_sleepCondition.wait(lk);
|
||||
continue;
|
||||
}
|
||||
|
||||
task();
|
||||
|
||||
_taskMutex.lock();
|
||||
_tasks[index] = nullptr;
|
||||
_taskMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int _numThread;
|
||||
|
||||
std::mutex _taskMutex;
|
||||
std::mutex _sleepMutex;
|
||||
std::condition_variable _sleepCondition;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
|
||||
@interface AudioEngineSessionHandler : NSObject
|
||||
{
|
||||
|
@ -220,8 +133,7 @@ static id s_AudioEngineSessionHandler = nullptr;
|
|||
#endif
|
||||
|
||||
AudioEngineImpl::AudioEngineImpl()
|
||||
: _threadPool(nullptr)
|
||||
, _lazyInitLoop(true)
|
||||
: _lazyInitLoop(true)
|
||||
, _currentAudioID(0)
|
||||
{
|
||||
|
||||
|
@ -240,10 +152,7 @@ AudioEngineImpl::~AudioEngineImpl()
|
|||
if (s_ALDevice) {
|
||||
alcCloseDevice(s_ALDevice);
|
||||
}
|
||||
if (_threadPool) {
|
||||
_threadPool->destroy();
|
||||
delete _threadPool;
|
||||
}
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
|
||||
[s_AudioEngineSessionHandler release];
|
||||
#endif
|
||||
|
@ -275,7 +184,6 @@ bool AudioEngineImpl::init()
|
|||
_alSourceUsed[_alSources[i]] = false;
|
||||
}
|
||||
|
||||
_threadPool = new (std::nothrow) AudioEngineThreadPool();
|
||||
ret = true;
|
||||
}
|
||||
}while (false);
|
||||
|
@ -283,6 +191,24 @@ bool AudioEngineImpl::init()
|
|||
return ret;
|
||||
}
|
||||
|
||||
AudioCache* AudioEngineImpl::preload(const std::string& filePath)
|
||||
{
|
||||
AudioCache* audioCache = nullptr;
|
||||
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it == _audioCaches.end()) {
|
||||
audioCache = &_audioCaches[filePath];
|
||||
audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
|
||||
AudioEngine::addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
}
|
||||
else {
|
||||
audioCache = &it->second;
|
||||
}
|
||||
|
||||
return audioCache;
|
||||
}
|
||||
|
||||
int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume)
|
||||
{
|
||||
if (s_ALDevice == nullptr) {
|
||||
|
@ -303,16 +229,9 @@ int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume
|
|||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
AudioCache* audioCache = nullptr;
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it == _audioCaches.end()) {
|
||||
audioCache = &_audioCaches[filePath];
|
||||
audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
|
||||
_threadPool->addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
}
|
||||
else {
|
||||
audioCache = &it->second;
|
||||
AudioCache* audioCache = preload(filePath);
|
||||
if (audioCache == nullptr) {
|
||||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
auto player = &_audioPlayers[_currentAudioID];
|
||||
|
|
|
@ -281,8 +281,14 @@ public:
|
|||
*/
|
||||
static AudioProfile* getProfile(const std::string &profileName);
|
||||
|
||||
/**
|
||||
* Preload audio file.
|
||||
* @param filePath The file path of an audio.
|
||||
*/
|
||||
static void preload(const std::string& filePath);
|
||||
|
||||
protected:
|
||||
|
||||
static void addTask(const std::function<void()> &task);
|
||||
static void remove(int audioID);
|
||||
|
||||
struct ProfileHelper
|
||||
|
@ -335,6 +341,9 @@ protected:
|
|||
static ProfileHelper* _defaultProfileHelper;
|
||||
|
||||
static AudioEngineImpl* _audioEngineImpl;
|
||||
|
||||
class AudioEngineThreadPool;
|
||||
static AudioEngineThreadPool* s_threadPool;
|
||||
|
||||
friend class AudioEngineImpl;
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||
|
||||
#include "AudioEngine-win32.h"
|
||||
#include <condition_variable>
|
||||
|
||||
#ifdef OPENAL_PLAIN_INCLUDES
|
||||
#include "alc.h"
|
||||
#include "alext.h"
|
||||
|
@ -47,95 +47,9 @@ static ALCdevice *s_ALDevice = nullptr;
|
|||
static ALCcontext *s_ALContext = nullptr;
|
||||
static bool MPG123_LAZYINIT = true;
|
||||
|
||||
namespace cocos2d {
|
||||
namespace experimental {
|
||||
class AudioEngineThreadPool
|
||||
{
|
||||
public:
|
||||
AudioEngineThreadPool()
|
||||
: _running(true)
|
||||
, _numThread(6)
|
||||
{
|
||||
_threads.reserve(_numThread);
|
||||
_tasks.reserve(_numThread);
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_tasks.push_back(nullptr);
|
||||
_threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,index) ) );
|
||||
_threads[index].detach();
|
||||
}
|
||||
}
|
||||
|
||||
void addTask(const std::function<void()> &task){
|
||||
_taskMutex.lock();
|
||||
int targetIndex = -1;
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
if (_tasks[index] == nullptr) {
|
||||
targetIndex = index;
|
||||
_tasks[index] = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetIndex == -1) {
|
||||
_tasks.push_back(task);
|
||||
_threads.push_back( std::thread( std::bind(&AudioEngineThreadPool::threadFunc,this,_numThread) ) );
|
||||
_threads[_numThread].detach();
|
||||
_numThread++;
|
||||
}
|
||||
_taskMutex.unlock();
|
||||
_sleepCondition.notify_all();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
_running = false;
|
||||
_sleepCondition.notify_all();
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_threads[index].join();
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool _running;
|
||||
std::vector<std::thread> _threads;
|
||||
std::vector< std::function<void ()> > _tasks;
|
||||
|
||||
void threadFunc(int index)
|
||||
{
|
||||
while (_running) {
|
||||
std::function<void ()> task = nullptr;
|
||||
_taskMutex.lock();
|
||||
task = _tasks[index];
|
||||
_taskMutex.unlock();
|
||||
|
||||
if (nullptr == task)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(_sleepMutex);
|
||||
_sleepCondition.wait(lk);
|
||||
continue;
|
||||
}
|
||||
|
||||
task();
|
||||
|
||||
_taskMutex.lock();
|
||||
_tasks[index] = nullptr;
|
||||
_taskMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int _numThread;
|
||||
|
||||
std::mutex _taskMutex;
|
||||
std::mutex _sleepMutex;
|
||||
std::condition_variable _sleepCondition;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
AudioEngineImpl::AudioEngineImpl()
|
||||
: _lazyInitLoop(true)
|
||||
, _currentAudioID(0)
|
||||
, _threadPool(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -155,10 +69,6 @@ AudioEngineImpl::~AudioEngineImpl()
|
|||
alcCloseDevice(s_ALDevice);
|
||||
s_ALDevice = nullptr;
|
||||
}
|
||||
if (_threadPool) {
|
||||
_threadPool->destroy();
|
||||
delete _threadPool;
|
||||
}
|
||||
|
||||
mpg123_exit();
|
||||
MPG123_LAZYINIT = true;
|
||||
|
@ -186,7 +96,6 @@ bool AudioEngineImpl::init()
|
|||
_alSourceUsed[_alSources[i]] = false;
|
||||
}
|
||||
|
||||
_threadPool = new (std::nothrow) AudioEngineThreadPool();
|
||||
ret = true;
|
||||
}
|
||||
}while (false);
|
||||
|
@ -194,6 +103,54 @@ bool AudioEngineImpl::init()
|
|||
return ret;
|
||||
}
|
||||
|
||||
AudioCache* AudioEngineImpl::preload(const std::string& filePath)
|
||||
{
|
||||
AudioCache* audioCache = nullptr;
|
||||
|
||||
do
|
||||
{
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it != _audioCaches.end())
|
||||
{
|
||||
audioCache = &it->second;
|
||||
break;
|
||||
}
|
||||
|
||||
auto ext = strchr(filePath.c_str(), '.');
|
||||
AudioCache::FileFormat fileFormat = AudioCache::FileFormat::UNKNOWN;
|
||||
|
||||
if (_stricmp(ext, ".ogg") == 0){
|
||||
fileFormat = AudioCache::FileFormat::OGG;
|
||||
}
|
||||
else if (_stricmp(ext, ".mp3") == 0){
|
||||
fileFormat = AudioCache::FileFormat::MP3;
|
||||
|
||||
if (MPG123_LAZYINIT){
|
||||
auto error = mpg123_init();
|
||||
if (error == MPG123_OK){
|
||||
MPG123_LAZYINIT = false;
|
||||
}
|
||||
else{
|
||||
log("Basic setup goes wrong: %s", mpg123_plain_strerror(error));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
log("unsupported media type:%s\n", ext);
|
||||
break;
|
||||
}
|
||||
|
||||
audioCache = &_audioCaches[filePath];
|
||||
audioCache->_fileFormat = fileFormat;
|
||||
|
||||
audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
AudioEngine::addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
} while (false);
|
||||
|
||||
return audioCache;
|
||||
}
|
||||
|
||||
int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume)
|
||||
{
|
||||
bool availableSourceExist = false;
|
||||
|
@ -209,48 +166,10 @@ int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume
|
|||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
AudioCache* audioCache = nullptr;
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it == _audioCaches.end()) {
|
||||
audioCache = &_audioCaches[filePath];
|
||||
auto ext = strchr(filePath.c_str(), '.');
|
||||
bool eraseCache = true;
|
||||
|
||||
if (_stricmp(ext, ".ogg") == 0){
|
||||
audioCache->_fileFormat = AudioCache::FileFormat::OGG;
|
||||
eraseCache = false;
|
||||
}
|
||||
else if (_stricmp(ext, ".mp3") == 0){
|
||||
audioCache->_fileFormat = AudioCache::FileFormat::MP3;
|
||||
|
||||
if (MPG123_LAZYINIT){
|
||||
auto error = mpg123_init();
|
||||
if(error == MPG123_OK){
|
||||
MPG123_LAZYINIT = false;
|
||||
eraseCache = false;
|
||||
}
|
||||
else{
|
||||
log("Basic setup goes wrong: %s", mpg123_plain_strerror(error));
|
||||
}
|
||||
}
|
||||
else{
|
||||
eraseCache = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
log("unsupported media type:%s\n", ext);
|
||||
}
|
||||
|
||||
if (eraseCache){
|
||||
_audioCaches.erase(filePath);
|
||||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
_threadPool->addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
}
|
||||
else {
|
||||
audioCache = &it->second;
|
||||
AudioCache* audioCache = preload(filePath);
|
||||
if (audioCache == nullptr)
|
||||
{
|
||||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
auto player = &_audioPlayers[_currentAudioID];
|
||||
|
|
|
@ -38,8 +38,6 @@ NS_CC_BEGIN
|
|||
namespace experimental{
|
||||
#define MAX_AUDIOINSTANCES 32
|
||||
|
||||
class AudioEngineThreadPool;
|
||||
|
||||
class CC_DLL AudioEngineImpl : public cocos2d::Ref
|
||||
{
|
||||
public:
|
||||
|
@ -61,14 +59,13 @@ public:
|
|||
|
||||
void uncache(const std::string& filePath);
|
||||
void uncacheAll();
|
||||
AudioCache* preload(const std::string& filePath);
|
||||
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
void _play2d(AudioCache *cache, int audioID);
|
||||
|
||||
AudioEngineThreadPool* _threadPool;
|
||||
|
||||
ALuint _alSources[MAX_AUDIOINSTANCES];
|
||||
|
||||
//source,used
|
||||
|
|
|
@ -21,101 +21,13 @@
|
|||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
|
||||
|
||||
#include "AudioEngine-winrt.h"
|
||||
#include <condition_variable>
|
||||
|
||||
|
||||
using namespace cocos2d;
|
||||
using namespace cocos2d::experimental;
|
||||
|
||||
|
||||
namespace cocos2d {
|
||||
namespace experimental {
|
||||
class AudioEngineThreadPool
|
||||
{
|
||||
public:
|
||||
AudioEngineThreadPool()
|
||||
: _running(true)
|
||||
, _numThread(6)
|
||||
{
|
||||
_threads.reserve(_numThread);
|
||||
_tasks.reserve(_numThread);
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_tasks.push_back(nullptr);
|
||||
_threads.push_back(std::thread(std::bind(&AudioEngineThreadPool::threadFunc, this, index)));
|
||||
}
|
||||
}
|
||||
|
||||
void addTask(const std::function<void()> &task){
|
||||
_taskMutex.lock();
|
||||
int targetIndex = -1;
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
if (_tasks[index] == nullptr) {
|
||||
targetIndex = index;
|
||||
_tasks[index] = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetIndex == -1) {
|
||||
_tasks.push_back(task);
|
||||
_threads.push_back(std::thread(std::bind(&AudioEngineThreadPool::threadFunc, this, _numThread)));
|
||||
|
||||
_numThread++;
|
||||
}
|
||||
_taskMutex.unlock();
|
||||
_sleepCondition.notify_all();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
_running = false;
|
||||
_sleepCondition.notify_all();
|
||||
|
||||
for (int index = 0; index < _numThread; ++index) {
|
||||
_threads[index].join();
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool _running;
|
||||
std::vector<std::thread> _threads;
|
||||
std::vector< std::function<void()> > _tasks;
|
||||
|
||||
void threadFunc(int index)
|
||||
{
|
||||
while (_running) {
|
||||
std::function<void()> task = nullptr;
|
||||
_taskMutex.lock();
|
||||
task = _tasks[index];
|
||||
_taskMutex.unlock();
|
||||
|
||||
if (nullptr == task)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(_sleepMutex);
|
||||
_sleepCondition.wait(lk);
|
||||
continue;
|
||||
}
|
||||
|
||||
task();
|
||||
|
||||
_taskMutex.lock();
|
||||
_tasks[index] = nullptr;
|
||||
_taskMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int _numThread;
|
||||
|
||||
std::mutex _taskMutex;
|
||||
std::mutex _sleepMutex;
|
||||
std::condition_variable _sleepCondition;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
AudioEngineImpl::AudioEngineImpl()
|
||||
: _lazyInitLoop(true)
|
||||
, _currentAudioID(0)
|
||||
, _threadPool(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -123,64 +35,63 @@ AudioEngineImpl::AudioEngineImpl()
|
|||
AudioEngineImpl::~AudioEngineImpl()
|
||||
{
|
||||
_audioCaches.clear();
|
||||
|
||||
if (_threadPool) {
|
||||
_threadPool->destroy();
|
||||
delete _threadPool;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioEngineImpl::init()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (nullptr == _threadPool) {
|
||||
_threadPool = new (std::nothrow) AudioEngineThreadPool();
|
||||
}
|
||||
|
||||
ret = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AudioEngineImpl::play2d(const std::string &filePath, bool loop, float volume)
|
||||
AudioCache* AudioEngineImpl::preload(const std::string& filePath)
|
||||
{
|
||||
AudioCache* audioCache = nullptr;
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it == _audioCaches.end()) {
|
||||
audioCache = &_audioCaches[filePath];
|
||||
do
|
||||
{
|
||||
auto it = _audioCaches.find(filePath);
|
||||
if (it == _audioCaches.end()) {
|
||||
FileFormat fileFormat = FileFormat::UNKNOWN;
|
||||
|
||||
auto ext = filePath.substr(filePath.rfind('.'));
|
||||
transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
auto ext = filePath.substr(filePath.rfind('.'));
|
||||
transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
|
||||
bool eraseCache = true;
|
||||
if (ext.compare(".wav") == 0){
|
||||
fileFormat = FileFormat::WAV;
|
||||
}
|
||||
else if (ext.compare(".ogg") == 0){
|
||||
fileFormat = FileFormat::OGG;
|
||||
}
|
||||
else if (ext.compare(".mp3") == 0){
|
||||
fileFormat = FileFormat::MP3;
|
||||
}
|
||||
else{
|
||||
log("unsupported media type:%s\n", ext.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (ext.compare(".wav") == 0){
|
||||
audioCache->_fileFormat = FileFormat::WAV;
|
||||
eraseCache = false;
|
||||
}
|
||||
else if (ext.compare(".ogg") == 0){
|
||||
audioCache->_fileFormat = FileFormat::OGG;
|
||||
eraseCache = false;
|
||||
}
|
||||
else if (ext.compare(".mp3") == 0){
|
||||
audioCache->_fileFormat = FileFormat::MP3;
|
||||
eraseCache = false;
|
||||
}
|
||||
else{
|
||||
log("unsupported media type:%s\n", ext.c_str());
|
||||
}
|
||||
audioCache = &_audioCaches[filePath];
|
||||
audioCache->_fileFormat = fileFormat;
|
||||
|
||||
if (eraseCache){
|
||||
_audioCaches.erase(filePath);
|
||||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
audioCache->_fileFullPath = fullPath;
|
||||
AudioEngine::addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
}
|
||||
else {
|
||||
audioCache = &it->second;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
|
||||
audioCache->_fileFullPath = fullPath;
|
||||
_threadPool->addTask(std::bind(&AudioCache::readDataTask, audioCache));
|
||||
}
|
||||
else {
|
||||
audioCache = &it->second;
|
||||
return audioCache;
|
||||
}
|
||||
|
||||
int AudioEngineImpl::play2d(const std::string &filePath, bool loop, float volume)
|
||||
{
|
||||
auto audioCache = preload(filePath);
|
||||
if (audioCache == nullptr)
|
||||
{
|
||||
return AudioEngine::INVALID_AUDIO_ID;
|
||||
}
|
||||
|
||||
auto player = &_audioPlayers[_currentAudioID];
|
||||
|
|
|
@ -35,9 +35,6 @@ NS_CC_BEGIN
|
|||
namespace experimental{
|
||||
#define MAX_AUDIOINSTANCES 32
|
||||
|
||||
|
||||
class AudioEngineThreadPool;
|
||||
|
||||
class CC_DLL AudioEngineImpl : public cocos2d::Ref
|
||||
{
|
||||
public:
|
||||
|
@ -58,6 +55,7 @@ NS_CC_BEGIN
|
|||
void setFinishCallback(int audioID, const std::function<void(int, const std::string &)> &callback);
|
||||
void uncache(const std::string& filePath);
|
||||
void uncacheAll();
|
||||
AudioCache* preload(const std::string& filePath);
|
||||
void update(float dt);
|
||||
|
||||
private:
|
||||
|
@ -72,7 +70,6 @@ NS_CC_BEGIN
|
|||
std::vector<int> _toRemoveAudioIDs;
|
||||
bool _lazyInitLoop;
|
||||
int _currentAudioID;
|
||||
AudioEngineThreadPool* _threadPool;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ bool AudioControlTest::init()
|
|||
}
|
||||
});
|
||||
_playItem = playItem;
|
||||
playItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.7f);
|
||||
playItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.8f);
|
||||
addChild(playItem);
|
||||
|
||||
auto stopItem = TextButton::create("stop", [&](TextButton* button){
|
||||
|
@ -314,7 +314,7 @@ bool AudioControlTest::init()
|
|||
((TextButton*)_playItem)->setEnabled(true);
|
||||
}
|
||||
});
|
||||
stopItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.7f);
|
||||
stopItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.8f);
|
||||
addChild(stopItem);
|
||||
|
||||
auto pauseItem = TextButton::create("pause", [&](TextButton* button){
|
||||
|
@ -322,7 +322,7 @@ bool AudioControlTest::init()
|
|||
AudioEngine::pause(_audioID);
|
||||
}
|
||||
});
|
||||
pauseItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.6f);
|
||||
pauseItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.7f);
|
||||
addChild(pauseItem);
|
||||
|
||||
auto resumeItem = TextButton::create("resume", [&](TextButton* button){
|
||||
|
@ -330,32 +330,38 @@ bool AudioControlTest::init()
|
|||
AudioEngine::resume(_audioID);
|
||||
}
|
||||
});
|
||||
resumeItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.6f);
|
||||
resumeItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.7f);
|
||||
addChild(resumeItem);
|
||||
|
||||
auto loopItem = TextButton::create("enable-loop", [&](TextButton* button){
|
||||
_loopEnabled = !_loopEnabled;
|
||||
|
||||
if (_audioID != AudioEngine::INVALID_AUDIO_ID ) {
|
||||
|
||||
if (_audioID != AudioEngine::INVALID_AUDIO_ID) {
|
||||
AudioEngine::setLoop(_audioID, _loopEnabled);
|
||||
}
|
||||
if(_loopEnabled){
|
||||
if (_loopEnabled){
|
||||
button->setString("disable-loop");
|
||||
}
|
||||
else {
|
||||
button->setString("enable-loop");
|
||||
}
|
||||
});
|
||||
loopItem->setPosition(layerSize.width * 0.3f,layerSize.height * 0.5f);
|
||||
loopItem->setPosition(layerSize.width * 0.5f, layerSize.height * 0.5f);
|
||||
addChild(loopItem);
|
||||
|
||||
auto preloadItem = TextButton::create("preload", [&](TextButton* button){
|
||||
AudioEngine::preload("background.mp3");
|
||||
});
|
||||
preloadItem->setPosition(layerSize.width * 0.3f, layerSize.height * 0.6f);
|
||||
addChild(preloadItem);
|
||||
|
||||
auto uncacheItem = TextButton::create("uncache", [&](TextButton* button){
|
||||
AudioEngine::uncache("background.mp3");
|
||||
|
||||
_audioID = AudioEngine::INVALID_AUDIO_ID;
|
||||
((TextButton*)_playItem)->setEnabled(true);
|
||||
});
|
||||
uncacheItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.5f);
|
||||
uncacheItem->setPosition(layerSize.width * 0.7f,layerSize.height * 0.6f);
|
||||
addChild(uncacheItem);
|
||||
|
||||
auto volumeSlider = SliderEx::create();
|
||||
|
|
Loading…
Reference in New Issue