mirror of
https://github.com/clangen/musikcube.git
synced 2024-11-19 20:13:36 +00:00
Added CoreAudioOut gapless playback support.
This commit is contained in:
parent
a8f8425f91
commit
32965dd2af
@ -6,29 +6,51 @@
|
|||||||
|
|
||||||
using namespace musik::core::audio;
|
using namespace musik::core::audio;
|
||||||
|
|
||||||
void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer)
|
void audioCallback(void *customData, AudioQueueRef queue, AudioQueueBufferRef buffer) {
|
||||||
{
|
CoreAudioOut* output = (CoreAudioOut *) customData;
|
||||||
|
CoreAudioOut::BufferContext* context = (CoreAudioOut::BufferContext *) buffer->mUserData;
|
||||||
|
|
||||||
OSStatus result = AudioQueueFreeBuffer(queue, buffer);
|
OSStatus result = AudioQueueFreeBuffer(queue, buffer);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
|
std::cerr << "AudioQueueFreeBuffer failed: " << result << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreAudioOut* output = (CoreAudioOut *) customData;
|
output->NotifyBufferCompleted(context);
|
||||||
IBuffer* coreBuffer = (IBuffer *) buffer->mUserData;
|
|
||||||
output->NotifyBufferCompleted(coreBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreAudioOut::NotifyBufferCompleted(IBuffer *buffer) {
|
size_t countBuffersWithProvider(
|
||||||
|
const std::list<CoreAudioOut::BufferContext*>& buffers,
|
||||||
|
const IBufferProvider* provider)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
auto it = buffers.begin();
|
||||||
|
while (it != buffers.end()) {
|
||||||
|
if ((*it)->provider == provider) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreAudioOut::NotifyBufferCompleted(BufferContext *context) {
|
||||||
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
--bufferCount;
|
|
||||||
this->bufferProvider->OnBufferProcessed(buffer);
|
auto it = this->buffers.begin();
|
||||||
|
while (it != this->buffers.end()) {
|
||||||
|
if (*it == context) {
|
||||||
|
this->buffers.erase(it);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->provider->OnBufferProcessed(context->buffer);
|
||||||
|
delete context;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreAudioOut::CoreAudioOut() {
|
CoreAudioOut::CoreAudioOut() {
|
||||||
this->bufferProvider = NULL;
|
|
||||||
this->quit = false;
|
this->quit = false;
|
||||||
this->bufferCount = 0;
|
|
||||||
this->volume = 1.0f;
|
this->volume = 1.0f;
|
||||||
|
|
||||||
this->audioFormat = (AudioStreamBasicDescription) { 0 };
|
this->audioFormat = (AudioStreamBasicDescription) { 0 };
|
||||||
@ -51,7 +73,7 @@ CoreAudioOut::CoreAudioOut() {
|
|||||||
bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
||||||
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||||||
|
|
||||||
if (this->bufferCount >= BUFFER_COUNT) {
|
if (countBuffersWithProvider(this->buffers, provider) >= BUFFER_COUNT) {
|
||||||
/* enough buffers are already in the queue. bail, we'll notify the
|
/* enough buffers are already in the queue. bail, we'll notify the
|
||||||
caller when there's more data available */
|
caller when there's more data available */
|
||||||
return false;
|
return false;
|
||||||
@ -94,20 +116,22 @@ bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->bufferProvider = provider;
|
|
||||||
|
|
||||||
AudioQueueBufferRef audioQueueBuffer = NULL;
|
AudioQueueBufferRef audioQueueBuffer = NULL;
|
||||||
|
|
||||||
size_t bytes = buffer->Bytes();
|
size_t bytes = buffer->Bytes();
|
||||||
|
|
||||||
result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);
|
result = AudioQueueAllocateBuffer(this->audioQueue, bytes, &audioQueueBuffer);
|
||||||
|
|
||||||
|
BufferContext* context = new BufferContext();
|
||||||
|
context->provider = provider;
|
||||||
|
context->buffer = buffer;
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
|
std::cerr << "AudioQueueAllocateBuffer failed: " << result << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioQueueBuffer->mUserData = (void *) buffer;
|
audioQueueBuffer->mUserData = (void *) context;
|
||||||
audioQueueBuffer->mAudioDataByteSize = bytes;
|
audioQueueBuffer->mAudioDataByteSize = bytes;
|
||||||
|
|
||||||
memcpy(
|
memcpy(
|
||||||
@ -120,10 +144,11 @@ bool CoreAudioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
|
|||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
|
std::cerr << "AudioQueueEnqueueBuffer failed: " << result << "\n";
|
||||||
|
delete context;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
++bufferCount;
|
this->buffers.push_back(context);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,11 @@
|
|||||||
|
|
||||||
class CoreAudioOut : public musik::core::audio::IOutput {
|
class CoreAudioOut : public musik::core::audio::IOutput {
|
||||||
public:
|
public:
|
||||||
|
struct BufferContext {
|
||||||
|
musik::core::audio::IBuffer *buffer;
|
||||||
|
musik::core::audio::IBufferProvider *provider;
|
||||||
|
};
|
||||||
|
|
||||||
CoreAudioOut();
|
CoreAudioOut();
|
||||||
virtual ~CoreAudioOut();
|
virtual ~CoreAudioOut();
|
||||||
|
|
||||||
@ -25,14 +30,13 @@ class CoreAudioOut : public musik::core::audio::IOutput {
|
|||||||
musik::core::audio::IBuffer *buffer,
|
musik::core::audio::IBuffer *buffer,
|
||||||
musik::core::audio::IBufferProvider *provider);
|
musik::core::audio::IBufferProvider *provider);
|
||||||
|
|
||||||
void NotifyBufferCompleted(musik::core::audio::IBuffer *buffer);
|
void NotifyBufferCompleted(BufferContext *context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
musik::core::audio::IBufferProvider *bufferProvider;
|
|
||||||
AudioStreamBasicDescription audioFormat;
|
AudioStreamBasicDescription audioFormat;
|
||||||
AudioQueueRef audioQueue;
|
AudioQueueRef audioQueue;
|
||||||
double volume;
|
double volume;
|
||||||
size_t bufferCount;
|
std::list<BufferContext*> buffers;
|
||||||
boost::thread thread;
|
boost::thread thread;
|
||||||
boost::recursive_mutex mutex;
|
boost::recursive_mutex mutex;
|
||||||
bool quit;
|
bool quit;
|
||||||
|
Loading…
Reference in New Issue
Block a user