Audio Output: Take a more nuclear approach to output resetting when seeking
parent
1278b64afd
commit
d22ee14a36
|
@ -16,6 +16,8 @@
|
|||
InputNode *inputNode;
|
||||
ConverterNode *converterNode;
|
||||
|
||||
AudioStreamBasicDescription _inputFormat;
|
||||
|
||||
NSURL *streamURL;
|
||||
id userInfo;
|
||||
NSDictionary *rgInfo;
|
||||
|
@ -63,4 +65,7 @@
|
|||
|
||||
- (id)controller;
|
||||
|
||||
- (ConverterNode *)converter;
|
||||
- (AudioStreamBasicDescription)inputFormat;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
void *callbackBuffer;
|
||||
size_t callbackBufferSize;
|
||||
|
||||
BOOL stopping;
|
||||
BOOL convertEntered;
|
||||
BOOL ACInputEntered;
|
||||
BOOL ACFloatEntered;
|
||||
|
||||
float sampleRatio;
|
||||
|
||||
float volumeScale;
|
||||
|
|
|
@ -44,6 +44,11 @@ void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
|||
callbackBuffer = NULL;
|
||||
callbackBufferSize = 0;
|
||||
|
||||
stopping = NO;
|
||||
convertEntered = NO;
|
||||
ACInputEntered = NO;
|
||||
ACFloatEntered = NO;
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
|
||||
}
|
||||
|
||||
|
@ -170,7 +175,7 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
|
|||
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;
|
||||
|
@ -178,6 +183,8 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
converter->ACInputEntered = YES;
|
||||
|
||||
amountToWrite = (*ioNumberDataPackets)*(converter->inputFormat.mBytesPerPacket);
|
||||
|
||||
if (!converter->callbackBuffer || converter->callbackBufferSize < amountToWrite)
|
||||
|
@ -189,6 +196,8 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
|
|||
ioData->mBuffers[0].mDataByteSize = 0;
|
||||
*ioNumberDataPackets = 0;
|
||||
|
||||
converter->ACInputEntered = NO;
|
||||
|
||||
return 100; //Keep asking for data
|
||||
}
|
||||
|
||||
|
@ -197,6 +206,8 @@ static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
|
|||
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
|
||||
ioData->mNumberBuffers = 1;
|
||||
|
||||
converter->ACInputEntered = NO;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -210,7 +221,7 @@ 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;
|
||||
|
@ -218,6 +229,8 @@ static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
converter->ACFloatEntered = YES;
|
||||
|
||||
amountToWrite = (*ioNumberDataPackets) * (converter->dmFloatFormat.mBytesPerPacket);
|
||||
|
||||
if ( amountToWrite + converter->floatOffset > converter->floatSize )
|
||||
|
@ -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)
|
||||
|
@ -346,6 +383,7 @@ tryagain2:
|
|||
DLog(@"Error: %i", err);
|
||||
}
|
||||
|
||||
convertEntered = NO;
|
||||
return amountRead;
|
||||
}
|
||||
|
||||
|
@ -415,6 +453,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];
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
shouldSeek = NO;
|
||||
DLog(@"Seeked! Resetting Buffer");
|
||||
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");
|
||||
initialBufferFilled = NO;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
- (void)pause;
|
||||
- (void)resume;
|
||||
- (void)stop;
|
||||
- (void)resumeWithFade;
|
||||
|
||||
- (void)setVolume:(double) v;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -261,6 +257,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
|
||||
|
|
Loading…
Reference in New Issue