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: private:
void _play2d(AudioCache *cache, int audioID); void _play2d(AudioCache *cache, int audioID);
static ALvoid myAlSourceNotificationCallback(ALuint sid, ALuint notificationID, ALvoid* userData);
ALuint _alSources[MAX_AUDIOINSTANCES]; ALuint _alSources[MAX_AUDIOINSTANCES];

View File

@ -41,8 +41,27 @@
using namespace cocos2d; using namespace cocos2d;
using namespace cocos2d::experimental; using namespace cocos2d::experimental;
static ALCdevice *s_ALDevice = nullptr; static ALCdevice* s_ALDevice = nullptr;
static ALCcontext *s_ALContext = 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 #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
@interface AudioEngineSessionHandler : NSObject @interface AudioEngineSessionHandler : NSObject
@ -189,12 +208,29 @@ void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruptio
static id s_AudioEngineSessionHandler = nullptr; static id s_AudioEngineSessionHandler = nullptr;
#endif #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() AudioEngineImpl::AudioEngineImpl()
: _lazyInitLoop(true) : _lazyInitLoop(true)
, _currentAudioID(0) , _currentAudioID(0)
, _scheduler(nullptr) , _scheduler(nullptr)
{ {
s_instance = this;
} }
AudioEngineImpl::~AudioEngineImpl() AudioEngineImpl::~AudioEngineImpl()
@ -219,6 +255,7 @@ AudioEngineImpl::~AudioEngineImpl()
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
[s_AudioEngineSessionHandler release]; [s_AudioEngineSessionHandler release];
#endif #endif
s_instance = nullptr;
} }
bool AudioEngineImpl::init() bool AudioEngineImpl::init()
@ -245,6 +282,7 @@ bool AudioEngineImpl::init()
for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) {
_alSourceUsed[_alSources[i]] = false; _alSourceUsed[_alSources[i]] = false;
alSourceAddNotificationExt(_alSources[i], AL_BUFFERS_PROCESSED, myAlSourceNotificationCallback, nullptr);
} }
// fixed #16170: Random crash in alGenBuffers(AudioCache::readDataTask) at startup // fixed #16170: Random crash in alGenBuffers(AudioCache::readDataTask) at startup
@ -308,7 +346,6 @@ bool AudioEngineImpl::init()
// ================ Workaround end ================ // // ================ Workaround end ================ //
_scheduler = Director::getInstance()->getScheduler(); _scheduler = Director::getInstance()->getScheduler();
ret = true; ret = true;
ALOGI("OpenAL was initialized successfully!"); ALOGI("OpenAL was initialized successfully!");

View File

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

View File

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