2016-01-15 01:33:22 +00:00
|
|
|
//
|
|
|
|
// AudioQueue.m
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 14/01/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "AudioQueue.h"
|
|
|
|
@import AudioToolbox;
|
|
|
|
|
|
|
|
#define AudioQueueNumAudioBuffers 3
|
|
|
|
#define AudioQueueStreamLength 2048
|
|
|
|
#define AudioQueueBufferLength 512
|
|
|
|
|
|
|
|
@implementation AudioQueue
|
|
|
|
{
|
|
|
|
AudioQueueRef _audioQueue;
|
|
|
|
AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers];
|
|
|
|
unsigned int _audioStreamReadPosition, _audioStreamWritePosition, _queuedAudioStreamSegments;
|
|
|
|
int16_t _audioStream[AudioQueueStreamLength];
|
|
|
|
BOOL _isOutputtingAudio;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark AudioQueue callbacks and setup; for pushing audio out
|
|
|
|
|
|
|
|
- (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer
|
|
|
|
{
|
|
|
|
@synchronized(self)
|
|
|
|
{
|
|
|
|
if(_queuedAudioStreamSegments > AudioQueueNumAudioBuffers-1) _isOutputtingAudio = YES;
|
|
|
|
|
|
|
|
if(_isOutputtingAudio && _queuedAudioStreamSegments)
|
|
|
|
{
|
|
|
|
_queuedAudioStreamSegments--;
|
|
|
|
memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition], buffer->mAudioDataByteSize);
|
|
|
|
_audioStreamReadPosition = (_audioStreamReadPosition + AudioQueueBufferLength)%AudioQueueStreamLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset(buffer->mAudioData, 0, buffer->mAudioDataByteSize);
|
|
|
|
_isOutputtingAudio = NO;
|
|
|
|
}
|
|
|
|
AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void audioOutputCallback(
|
|
|
|
void *inUserData,
|
|
|
|
AudioQueueRef inAQ,
|
|
|
|
AudioQueueBufferRef inBuffer)
|
|
|
|
{
|
|
|
|
[(__bridge AudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
|
|
|
|
if(self)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
|
|
|
|
Describe a mono, 16bit, 44.1Khz audio format
|
|
|
|
|
|
|
|
*/
|
|
|
|
AudioStreamBasicDescription outputDescription;
|
|
|
|
|
|
|
|
outputDescription.mSampleRate = 44100;
|
|
|
|
|
|
|
|
outputDescription.mFormatID = kAudioFormatLinearPCM;
|
|
|
|
outputDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
|
|
|
|
|
|
|
outputDescription.mBytesPerPacket = 2;
|
|
|
|
outputDescription.mFramesPerPacket = 1;
|
|
|
|
outputDescription.mBytesPerFrame = 2;
|
|
|
|
outputDescription.mChannelsPerFrame = 1;
|
|
|
|
outputDescription.mBitsPerChannel = 16;
|
|
|
|
|
|
|
|
outputDescription.mReserved = 0;
|
|
|
|
|
|
|
|
// create an audio output queue along those lines
|
|
|
|
if(!AudioQueueNewOutput(
|
|
|
|
&outputDescription,
|
|
|
|
audioOutputCallback,
|
|
|
|
(__bridge void *)(self),
|
|
|
|
NULL,
|
|
|
|
kCFRunLoopCommonModes,
|
|
|
|
0,
|
|
|
|
&_audioQueue))
|
|
|
|
{
|
|
|
|
_audioStreamWritePosition = AudioQueueBufferLength;
|
|
|
|
UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t);
|
|
|
|
|
|
|
|
int c = AudioQueueNumAudioBuffers;
|
|
|
|
while(c--)
|
|
|
|
{
|
|
|
|
AudioQueueAllocateBuffer(_audioQueue, bufferBytes, &_audioBuffers[c]);
|
|
|
|
memset(_audioBuffers[c]->mAudioData, 0, bufferBytes);
|
|
|
|
_audioBuffers[c]->mAudioDataByteSize = bufferBytes;
|
|
|
|
AudioQueueEnqueueBuffer(_audioQueue, _audioBuffers[c], 0, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
AudioQueueStart(_audioQueue, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:35:36 +00:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
|
|
|
if(_audioQueue) AudioQueueDispose(_audioQueue, NO);
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:33:22 +00:00
|
|
|
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(unsigned int)lengthInSamples
|
|
|
|
{
|
|
|
|
@synchronized(self)
|
|
|
|
{
|
|
|
|
memcpy(&_audioStream[_audioStreamWritePosition], buffer, lengthInSamples * sizeof(int16_t));
|
|
|
|
_audioStreamWritePosition = (_audioStreamWritePosition + lengthInSamples)%AudioQueueStreamLength;
|
|
|
|
|
|
|
|
if(_queuedAudioStreamSegments == (AudioQueueStreamLength/AudioQueueBufferLength))
|
|
|
|
{
|
|
|
|
_audioStreamReadPosition = (_audioStreamReadPosition + lengthInSamples)%AudioQueueStreamLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_queuedAudioStreamSegments++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|