Ok wrote a different style of Circular buffer that seems to have done the trick, very similar latency and no glitching. I still don't fully understand why this is better, any one with experience in this please share.
Due to very little of this stuff being posted on by apple, below is my Circular buffer implementation that works well with my VOIP setup, feel free to use it, any suggestions are welcome, just don't come after me if it doesn't work for you. This time its an objective-c class.
Please note that this was designed to use with ALAW format not linearPCM, "0xd5" is a byte of silence in ALAW, unsure what this will be in PCM but would expect it to be noise.
CircularBuffer.h:
//
// CircularBuffer.h
// clevercall
//
// Created by Simon Mcloughlin on 10/1/2013.
//
//
#import <Foundation/Foundation.h>
@interface CircularBuffer : NSObject
-(int) availableBytes;
-(id) initWithLength:(int)length;
-(void) produceToBuffer:(const void*)data ofLength:(int)length;
-(void) consumeBytesTo:(void *)buf OfLength:(int)length;
@end
CircularBuffer.m:
//
// CircularBuffer.m
// clevercall
//
// Created by Simon Mcloughlin on 10/1/2013.
//
//
#import "CircularBuffer.h"
@implementation CircularBuffer
{
unsigned int gBufferLength;
unsigned int gAvailableBytes;
unsigned int gHead;
unsigned int gTail;
void *gBuffer;
}
// Init instance with a certain length and alloc the space
-(id)initWithLength:(int)length
{
self = [super init];
if (self != nil)
{
gBufferLength = length;
gBuffer = malloc(length);
memset(gBuffer, 0xd5, length);
gAvailableBytes = 0;
gHead = 0;
gTail = 0;
}
return self;
}
// return the number of bytes stored in the buffer
-(int) availableBytes
{
return gAvailableBytes;
}
-(void) produceToBuffer:(const void*)data ofLength:(int)length
{
// if the number of bytes to add to the buffer will go past the end.
// copy enough to fill to the end
// go back to the start
// fill the remaining
if((gHead + length) > gBufferLength-1)
{
int remainder = ((gBufferLength-1) - gHead);
memcpy(gBuffer + gHead, data, remainder);
gHead = 0;
memcpy(gBuffer + gHead, data + remainder, (length - remainder));
gHead += (length - remainder);
gAvailableBytes += length;
}
// if there is room in the buffer for these bytes add them
else if((gAvailableBytes + length) <= gBufferLength-1)
{
memcpy(gBuffer + gHead, data, length);
gAvailableBytes += length;
gHead += length;
}
else
{
//NSLog(@"--- Discarded ---");
}
}
-(void) consumeBytesTo:(void *)buf OfLength:(int)length
{
// if the tail is at a point where there is not enough between it and the end to fill the buffer.
// copy out whats left
// move back to the start
// copy out the rest
if((gTail + length) > gBufferLength-1 && length <= gAvailableBytes)
{
int remainder = ((gBufferLength-1) - gTail);
memcpy(buf, gBuffer + gTail, remainder);
gTail = 0;
memcpy(buf + remainder, gBuffer, (length -remainder));
gAvailableBytes-=length;
gTail += (length -remainder);
}
// if there is enough bytes in the buffer
else if(length <= gAvailableBytes)
{
memcpy(buf, gBuffer + gTail, length);
gAvailableBytes-=length;
gTail+=length;
}
// else play silence
else
{
memset(buf, 0xd5, length);
}
}
@end