fixed #17800: [iOS] Streaming audio (normally a background music) maybe cut and may not be looped. (#17947)

* fixed #17800: [iOS] Streaming audio (normally a background music) may be cut and may not be looped.

* Updates including.
This commit is contained in:
James Chen 2017-06-19 20:04:04 -05:00 committed by minggo
parent a23924c95b
commit 567fa5b0a7
4 changed files with 64 additions and 10 deletions

View File

@ -66,6 +66,7 @@ public:
private:
void _play2d(AudioCache *cache, int audioID);
static ALvoid myAlSourceNotificationCallback(ALuint sid, ALuint notificationID, ALvoid* userData);
ALuint _alSources[MAX_AUDIOINSTANCES];

View File

@ -41,8 +41,27 @@
using namespace cocos2d;
using namespace cocos2d::experimental;
static ALCdevice *s_ALDevice = nullptr;
static ALCcontext *s_ALContext = nullptr;
static ALCdevice* s_ALDevice = nullptr;
static ALCcontext* s_ALContext = nullptr;
static AudioEngineImpl* s_instance = nullptr;
typedef ALvoid (*alSourceNotificationProc)(ALuint sid, ALuint notificationID, ALvoid* userData);
typedef ALenum (*alSourceAddNotificationProcPtr)(ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData);
static ALenum alSourceAddNotificationExt(ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData)
{
static alSourceAddNotificationProcPtr proc = nullptr;
if (proc == nullptr)
{
proc = (alSourceAddNotificationProcPtr)alcGetProcAddress(nullptr, "alSourceAddNotification");
}
if (proc)
{
return proc(sid, notificationID, notifyProc, userData);
}
return AL_INVALID_VALUE;
}
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
@interface AudioEngineSessionHandler : NSObject
@ -189,12 +208,29 @@ void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruptio
static id s_AudioEngineSessionHandler = nullptr;
#endif
ALvoid AudioEngineImpl::myAlSourceNotificationCallback(ALuint sid, ALuint notificationID, ALvoid* userData)
{
// Currently, we only care about AL_BUFFERS_PROCESSED event
if (notificationID != AL_BUFFERS_PROCESSED)
return;
AudioPlayer* player = nullptr;
for (const auto& e : s_instance->_audioPlayers)
{
player = e.second;
if (player->_alSource == sid && player->_streamingSource)
{
player->wakeupRotateThread();
}
}
}
AudioEngineImpl::AudioEngineImpl()
: _lazyInitLoop(true)
, _currentAudioID(0)
, _scheduler(nullptr)
{
s_instance = this;
}
AudioEngineImpl::~AudioEngineImpl()
@ -219,6 +255,7 @@ AudioEngineImpl::~AudioEngineImpl()
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
[s_AudioEngineSessionHandler release];
#endif
s_instance = nullptr;
}
bool AudioEngineImpl::init()
@ -245,6 +282,7 @@ bool AudioEngineImpl::init()
for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) {
_alSourceUsed[_alSources[i]] = false;
alSourceAddNotificationExt(_alSources[i], AL_BUFFERS_PROCESSED, myAlSourceNotificationCallback, nullptr);
}
// fixed #16170: Random crash in alGenBuffers(AudioCache::readDataTask) at startup
@ -308,7 +346,6 @@ bool AudioEngineImpl::init()
// ================ Workaround end ================ //
_scheduler = Director::getInstance()->getScheduler();
ret = true;
ALOGI("OpenAL was initialized successfully!");

View File

@ -27,12 +27,14 @@
#include "platform/CCPlatformConfig.h"
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC
#include "platform/CCPlatformMacros.h"
#include "audio/apple/AudioMacros.h"
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
#import <OpenAL/al.h>
#include "platform/CCPlatformMacros.h"
#include <OpenAL/al.h>
NS_CC_BEGIN
namespace experimental{
@ -57,6 +59,7 @@ protected:
void setCache(AudioCache* cache);
void rotateBufferThread(int offsetFrame);
bool play2d();
void wakeupRotateThread();
AudioCache* _audioCache;
@ -72,12 +75,13 @@ protected:
//play by circular buffer
float _currTime;
bool _streamingSource;
ALuint _bufferIds[3];
ALuint _bufferIds[QUEUEBUFFER_NUM];
std::thread* _rotateBufferThread;
std::condition_variable _sleepCondition;
std::mutex _sleepMutex;
bool _timeDirty;
bool _isRotateThreadExited;
std::atomic_bool _needWakeupRotateThread;
std::mutex _play2dMutex;

View File

@ -59,6 +59,7 @@ AudioPlayer::AudioPlayer()
, _rotateBufferThread(nullptr)
, _timeDirty(false)
, _isRotateThreadExited(false)
, _needWakeupRotateThread(false)
, _id(++__idIndex)
{
memset(_bufferIds, 0, sizeof(_bufferIds));
@ -71,7 +72,7 @@ AudioPlayer::~AudioPlayer()
if (_streamingSource)
{
alDeleteBuffers(3, _bufferIds);
alDeleteBuffers(QUEUEBUFFER_NUM, _bufferIds);
}
}
@ -172,7 +173,7 @@ bool AudioPlayer::play2d()
}
else
{
alGenBuffers(3, _bufferIds);
alGenBuffers(QUEUEBUFFER_NUM, _bufferIds);
auto alError = alGetError();
if (alError == AL_NO_ERROR)
@ -302,7 +303,12 @@ void AudioPlayer::rotateBufferThread(int offsetFrame)
break;
}
_sleepCondition.wait_for(lk,std::chrono::milliseconds(75));
if (!_needWakeupRotateThread)
{
_sleepCondition.wait_for(lk,std::chrono::milliseconds(75));
}
_needWakeupRotateThread = false;
}
} while(false);
@ -313,6 +319,12 @@ void AudioPlayer::rotateBufferThread(int offsetFrame)
_isRotateThreadExited = true;
}
void AudioPlayer::wakeupRotateThread()
{
_needWakeupRotateThread = true;
_sleepCondition.notify_all();
}
bool AudioPlayer::setLoop(bool loop)
{
if (!_isDestroyed ) {