Audio Output: Take a more nuclear approach to output resetting when seeking

CQTexperiment
Christopher Snowhill 2021-12-25 23:41:45 -08:00
parent 1278b64afd
commit d22ee14a36
9 changed files with 101 additions and 37 deletions

View File

@ -15,6 +15,8 @@
@interface BufferChain : NSObject {
InputNode *inputNode;
ConverterNode *converterNode;
AudioStreamBasicDescription _inputFormat;
NSURL *streamURL;
id userInfo;
@ -63,4 +65,7 @@
- (id)controller;
- (ConverterNode *)converter;
- (AudioStreamBasicDescription)inputFormat;
@end

View File

@ -63,7 +63,7 @@
if (![inputNode openWithSource:source])
return NO;
if (![converterNode setupWithInputFormat:propertiesToASBD([inputNode properties]) outputFormat:outputFormat])
if (![converterNode setupWithInputFormat:(_inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat])
return NO;
[self setRGInfo:rgi];
@ -82,7 +82,7 @@
return NO;
DLog(@"Input Properties: %@", [inputNode properties]);
if (![converterNode setupWithInputFormat:propertiesToASBD([inputNode properties]) outputFormat:outputFormat])
if (![converterNode setupWithInputFormat:(_inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat])
return NO;
[self setRGInfo:rgi];
@ -199,4 +199,14 @@
return controller;
}
- (ConverterNode *)converter
{
return converterNode;
}
- (AudioStreamBasicDescription)inputFormat
{
return _inputFormat;
}
@end

View File

@ -22,6 +22,11 @@
void *callbackBuffer;
size_t callbackBufferSize;
BOOL stopping;
BOOL convertEntered;
BOOL ACInputEntered;
BOOL ACFloatEntered;
float sampleRatio;
float volumeScale;

View File

@ -43,6 +43,11 @@ void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
floatBufferSize = 0;
callbackBuffer = NULL;
callbackBufferSize = 0;
stopping = NO;
convertEntered = NO;
ACInputEntered = NO;
ACFloatEntered = NO;
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
}
@ -169,14 +174,16 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
OSStatus err = noErr;
int amountToWrite;
int amountRead;
if ([converter shouldContinue] == NO || [converter endOfStream] == YES)
if (converter->stopping || [converter shouldContinue] == NO || [converter endOfStream] == YES)
{
ioData->mBuffers[0].mDataByteSize = 0;
*ioNumberDataPackets = 0;
return noErr;
}
converter->ACInputEntered = YES;
amountToWrite = (*ioNumberDataPackets)*(converter->inputFormat.mBytesPerPacket);
@ -188,6 +195,8 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
{
ioData->mBuffers[0].mDataByteSize = 0;
*ioNumberDataPackets = 0;
converter->ACInputEntered = NO;
return 100; //Keep asking for data
}
@ -196,7 +205,9 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
ioData->mBuffers[0].mDataByteSize = amountRead;
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
ioData->mNumberBuffers = 1;
converter->ACInputEntered = NO;
return err;
}
@ -210,13 +221,15 @@ static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
OSStatus err = noErr;
int amountToWrite;
if ([converter shouldContinue] == NO)
if (converter->stopping || [converter shouldContinue] == NO)
{
ioData->mBuffers[0].mDataByteSize = 0;
*ioNumberDataPackets = 0;
return noErr;
}
converter->ACFloatEntered = YES;
amountToWrite = (*ioNumberDataPackets) * (converter->dmFloatFormat.mBytesPerPacket);
@ -232,10 +245,15 @@ static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
ioData->mNumberBuffers = 1;
if (amountToWrite == 0)
{
converter->ACFloatEntered = NO;
return 100;
}
converter->floatOffset += amountToWrite;
converter->ACFloatEntered = NO;
return err;
}
@ -258,9 +276,15 @@ static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
int amountReadFromFC;
int amountRead = 0;
if (stopping)
return 0;
convertEntered = YES;
tryagain2:
if ([self shouldContinue] == NO || [self endOfStream] == YES)
if (stopping || [self shouldContinue] == NO || [self endOfStream] == YES)
{
convertEntered = NO;
return amountRead;
}
@ -287,6 +311,12 @@ tryagain2:
ioData.mNumberBuffers = 1;
tryagain:
if (stopping)
{
convertEntered = NO;
return 0;
}
err = AudioConverterFillComplexBuffer(converterFloat, ACInputProc, (__bridge void * _Nullable)(self), &ioNumberPackets, &ioData, NULL);
amountReadFromFC += ioNumberPackets * floatFormat.mBytesPerPacket;
if (err == 100)
@ -301,6 +331,7 @@ tryagain2:
else if (err != noErr && err != kAudioConverterErr_InvalidInputSize)
{
DLog(@"Error: %i", err);
convertEntered = NO;
return amountRead;
}
@ -335,6 +366,12 @@ tryagain2:
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
ioData.mNumberBuffers = 1;
if (stopping)
{
convertEntered = NO;
return 0;
}
err = AudioConverterFillComplexBuffer(converter, ACFloatProc, (__bridge void *)(self), &ioNumberPackets, &ioData, NULL);
amountRead += ioNumberPackets * outputFormat.mBytesPerPacket;
if (err == 100)
@ -345,7 +382,8 @@ tryagain2:
{
DLog(@"Error: %i", err);
}
convertEntered = NO;
return amountRead;
}
@ -414,6 +452,11 @@ static float db_to_scale(float db)
{
//Make the converter
OSStatus stat = noErr;
stopping = NO;
convertEntered = NO;
ACInputEntered = NO;
ACFloatEntered = NO;
inputFormat = inf;
outputFormat = outf;
@ -514,6 +557,11 @@ static float db_to_scale(float db)
- (void)inputFormatDidChange:(AudioStreamBasicDescription)format
{
DLog(@"FORMAT CHANGED");
stopping = YES;
while (convertEntered || ACInputEntered || ACFloatEntered)
{
usleep(500);
}
[self cleanUp];
[self setupWithInputFormat:format outputFormat:outputFormat];
}

View File

@ -122,17 +122,21 @@
if (shouldSeek == YES)
{
OutputNode *output = [[controller controller] output];
BOOL isPaused = [output isPaused];
if ( !isPaused ) [output pause];
DLog(@"SEEKING!");
seekError = [decoder seek:seekFrame] < 0;
if ( !isPaused ) [output resumeWithFade];
ConverterNode *converter = [[[controller controller] bufferChain] converter];
DLog(@"SEEKING! Resetting Buffer");
[self resetBuffer];
[output reset];
[converter resetBuffer];
[converter inputFormatDidChange:[[[controller controller] bufferChain] inputFormat]];
DLog(@"Reset buffer!");
DLog(@"SEEKING!");
seekError = [decoder seek:seekFrame] < 0;
shouldSeek = NO;
DLog(@"Seeked! Resetting Buffer");
[self resetBuffer];
DLog(@"Reset buffer!");
initialBufferFilled = NO;
}

View File

@ -30,6 +30,7 @@
- (void)process;
- (void)close;
- (void)seek:(double)time;
- (void)reset;
- (int)readData:(void *)ptr amount:(int)amount;
@ -42,7 +43,6 @@
- (void)pause;
- (void)resume;
- (void)resumeWithFade;
- (BOOL)isPaused;

View File

@ -51,10 +51,11 @@
[output resume];
}
- (void)resumeWithFade
- (void)reset
{
paused = NO;
[output resumeWithFade];
[output setup];
if (!paused)
[output start];
}
- (int)readData:(void *)ptr amount:(int)amount

View File

@ -43,7 +43,6 @@
- (void)pause;
- (void)resume;
- (void)stop;
- (void)resumeWithFade;
- (void)setVolume:(double) v;

View File

@ -44,10 +44,6 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
if (output->stopping == YES)
{
// *shrug* At least this will stop it from trying to emit data post-shutdown
memset(readPointer, 0, amountToRead);
buffer->mAudioDataByteSize = amountToRead;
AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
return;
}
@ -260,6 +256,8 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
{
if (outputUnit || audioQueue)
[self stop];
stopping = NO;
AudioComponentDescription desc;
OSStatus err;
@ -375,6 +373,8 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
- (void)start
{
AudioQueueSetParameter(audioQueue, kAudioQueueParam_VolumeRampTime, 0);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume);
AudioQueueStart(audioQueue, NULL);
}
@ -389,6 +389,9 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
}
if (audioQueue && buffers)
{
AudioQueuePause(audioQueue);
AudioQueueStop(audioQueue, true);
for (UInt32 i = 0; i < numberOfBuffers; ++i)
{
if (buffers[i])
@ -414,23 +417,12 @@ static void Sound_Renderer(void *userData, AudioQueueRef queue, AudioQueueBuffer
- (void)pause
{
AudioQueueSetParameter(audioQueue, kAudioQueueParam_VolumeRampTime, 0);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 0);
AudioQueuePause(audioQueue);
}
- (void)resume
{
AudioQueueStart(audioQueue, NULL);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_VolumeRampTime, 0);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume);
}
- (void)resumeWithFade
{
AudioQueueStart(audioQueue, NULL);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_VolumeRampTime, 0.4);
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, volume);
}
@end