@@ 8,6 8,7 @@
#import "ZANStreamPlayer.h"
#import <AudioToolbox/AudioToolbox.h>
+#import <pthread.h>
#if !__has_feature(objc_arc)
#error ARC is required for this file
@@ 45,7 46,9 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
AudioStreamPacketDescription _packetDescriptions[MAX_PACKET_DESCRIPTIONS];
NSOperationQueue *_inputQueue;
- NSUInteger _buffersEnqueued;
+ BOOL _queueBuffersUsageStates[AUDIO_QUEUE_BUFFERS_COUNT];
+ pthread_mutex_t _queueBuffersMutex;
+ pthread_cond_t _queueBufferReadyCondition;
NSUInteger _dataOffset;
NSUInteger _packetBufferSize;
@@ 65,6 68,9 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
_inputQueue = [[NSOperationQueue alloc] init];
_inputQueue.maxConcurrentOperationCount = 1;
+ pthread_mutex_init(&_queueBuffersMutex, NULL);
+ pthread_cond_init(&_queueBufferReadyCondition, NULL);
+
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
_urlSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:_inputQueue];
}
@@ 76,6 82,11 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
[self _closeReadStream];
[self _closeAudioStream];
[self _destroyAudioOutputQueue];
+
+ pthread_mutex_destroy(&_queueBuffersMutex);
+ pthread_cond_destroy(&_queueBufferReadyCondition);
+
+ [_urlSession invalidateAndCancel];
}
#pragma mark - API
@@ 277,6 288,11 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
OSStatus status = noErr;
do {
+ // mark that this buffer is in use
+ pthread_mutex_lock(&_queueBuffersMutex);
+ _queueBuffersUsageStates[_currentBufferIndex] = YES;
+ pthread_mutex_unlock(&_queueBuffersMutex);
+
// fill in bytes used
AudioQueueBufferRef buffer = _audioQueueBuffers[_currentBufferIndex];
buffer->mAudioDataByteSize = (UInt32)_bytesFilled;
@@ 299,7 315,6 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
_currentBufferIndex = (_currentBufferIndex + 1) % AUDIO_QUEUE_BUFFERS_COUNT;
_bytesFilled = 0;
_packetsFilled = 0;
- ++_buffersEnqueued;
} while (0);
}
@@ 406,6 421,13 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
[self _enqueueAudioBuffer];
}
+ // wait until the current buffer is available
+ pthread_mutex_lock(&_queueBuffersMutex);
+ while (_queueBuffersUsageStates[_currentBufferIndex]) {
+ pthread_cond_wait(&_queueBufferReadyCondition, &_queueBuffersMutex);
+ }
+ pthread_mutex_unlock(&_queueBuffersMutex);
+
// copy audio data into buffer
AudioQueueBufferRef buffer = _audioQueueBuffers[_currentBufferIndex];
memcpy(buffer->mAudioData + _bytesFilled, audioData.bytes + packetOffset, packetSize);
@@ 433,7 455,20 @@ static void _ZANAudioQueueOutputCallback(void *clientData,
- (void)_handleBufferCompleteFromQueue:(AudioQueueRef)queue buffer:(AudioQueueBufferRef)buffer
{
- --_buffersEnqueued;
+ NSInteger bufferIdx = NSNotFound;
+ for (unsigned i = 0; i < AUDIO_QUEUE_BUFFERS_COUNT; ++i) {
+ if (buffer == _audioQueueBuffers[i]) {
+ bufferIdx = i;
+ break;
+ }
+ }
+
+ NSAssert(bufferIdx != NSNotFound, @"An unknown audio buffer was completed");
+
+ pthread_mutex_lock(&_queueBuffersMutex);
+ _queueBuffersUsageStates[bufferIdx] = NO;
+ pthread_cond_signal(&_queueBufferReadyCondition);
+ pthread_mutex_unlock(&_queueBuffersMutex);
}
- (NSError *)_errorFromOSStatus:(OSStatus)status