mirror of https://github.com/axmolengine/axmol.git
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:
parent
a23924c95b
commit
567fa5b0a7
|
@ -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];
|
||||||
|
|
||||||
|
|
|
@ -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!");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 ) {
|
||||||
|
|
Loading…
Reference in New Issue