[Audio Output] Synchronize access, report latency
Report resampler latency properly, and synchronize access to the resampler objects. Signed-off-by: Christopher Snowhill <kode54@gmail.com>swiftingly
parent
26a63e85b7
commit
438b142558
|
@ -93,19 +93,19 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
||||||
formatClipped = YES;
|
formatClipped = YES;
|
||||||
}
|
}
|
||||||
if(!streamFormatStarted || config != streamChannelConfig || memcmp(&newFormat, &format, sizeof(format)) != 0) {
|
if(!streamFormatStarted || config != streamChannelConfig || memcmp(&newFormat, &format, sizeof(format)) != 0) {
|
||||||
|
[currentPtsLock lock];
|
||||||
if(formatClipped) {
|
if(formatClipped) {
|
||||||
ALog(@"Sample rate clipped to no more than %f Hz!", maxSampleRate);
|
ALog(@"Sample rate clipped to no more than %f Hz!", maxSampleRate);
|
||||||
if(r8bstate) {
|
if(r8bstate) {
|
||||||
r8bold = r8bstate;
|
r8bold = r8bstate;
|
||||||
r8bstate = NULL;
|
r8bstate = NULL;
|
||||||
r8bFlushing = YES;
|
|
||||||
}
|
}
|
||||||
r8bstate = r8bstate_new(format.mChannelsPerFrame, 1024, srcRate, dstRate);
|
r8bstate = r8bstate_new(format.mChannelsPerFrame, 1024, srcRate, dstRate);
|
||||||
} else if(r8bstate) {
|
} else if(r8bstate) {
|
||||||
r8bold = r8bstate;
|
r8bold = r8bstate;
|
||||||
r8bstate = NULL;
|
r8bstate = NULL;
|
||||||
r8bFlushing = YES;
|
|
||||||
}
|
}
|
||||||
|
[currentPtsLock unlock];
|
||||||
newFormat = format;
|
newFormat = format;
|
||||||
streamChannelConfig = config;
|
streamChannelConfig = config;
|
||||||
streamFormatStarted = YES;
|
streamFormatStarted = YES;
|
||||||
|
@ -135,7 +135,9 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
||||||
const float *outputPtr = (const float *)[samples bytes];
|
const float *outputPtr = (const float *)[samples bytes];
|
||||||
if(r8bstate) {
|
if(r8bstate) {
|
||||||
size_t inDone = 0;
|
size_t inDone = 0;
|
||||||
|
[currentPtsLock lock];
|
||||||
size_t framesDone = r8bstate_resample(r8bstate, outputPtr, frameCount, &inDone, &outputBuffer[0], 2048);
|
size_t framesDone = r8bstate_resample(r8bstate, outputPtr, frameCount, &inDone, &outputBuffer[0], 2048);
|
||||||
|
[currentPtsLock unlock];
|
||||||
if(!framesDone) return 0;
|
if(!framesDone) return 0;
|
||||||
frameCount = (int)framesDone;
|
frameCount = (int)framesDone;
|
||||||
outputPtr = &outputBuffer[0];
|
outputPtr = &outputBuffer[0];
|
||||||
|
@ -246,6 +248,8 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
||||||
|
|
||||||
secondsHdcdSustained = 0;
|
secondsHdcdSustained = 0;
|
||||||
|
|
||||||
|
currentPtsLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
#ifdef OUTPUT_LOG
|
#ifdef OUTPUT_LOG
|
||||||
_logFile = fopen("/tmp/CogAudioLog.raw", "wb");
|
_logFile = fopen("/tmp/CogAudioLog.raw", "wb");
|
||||||
#endif
|
#endif
|
||||||
|
@ -696,7 +700,9 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
[currentPtsLock lock];
|
||||||
samplesRendered = r8bstate_flush(r8bold, &tempBuffer[0], 2048);
|
samplesRendered = r8bstate_flush(r8bold, &tempBuffer[0], 2048);
|
||||||
|
[currentPtsLock unlock];
|
||||||
if(!samplesRendered) {
|
if(!samplesRendered) {
|
||||||
r8bstate_delete(r8bold);
|
r8bstate_delete(r8bold);
|
||||||
r8bold = NULL;
|
r8bold = NULL;
|
||||||
|
@ -915,14 +921,16 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)synchronizerBlock {
|
- (void)synchronizerBlock {
|
||||||
__block NSLock *lock = [[NSLock alloc] init];
|
NSLock *lock = currentPtsLock;
|
||||||
currentPtsLock = lock;
|
|
||||||
CMTime interval = CMTimeMakeWithSeconds(1.0 / 60.0, 1000000000);
|
CMTime interval = CMTimeMakeWithSeconds(1.0 / 60.0, 1000000000);
|
||||||
CMTime *lastPts = &self->lastPts;
|
CMTime *lastPts = &self->lastPts;
|
||||||
CMTime *outputPts = &self->outputPts;
|
CMTime *outputPts = &self->outputPts;
|
||||||
OutputNode *outputController = self->outputController;
|
OutputNode *outputController = self->outputController;
|
||||||
double *latencySecondsOut = &self->secondsLatency;
|
double *latencySecondsOut = &self->secondsLatency;
|
||||||
VisualizationController *visController = self->visController;
|
VisualizationController *visController = self->visController;
|
||||||
|
void **r8bstate = &self->r8bstate;
|
||||||
|
void **r8bold = &self->r8bold;
|
||||||
|
void **r8bvis = &self->r8bvis;
|
||||||
currentPtsObserver = [renderSynchronizer addPeriodicTimeObserverForInterval:interval
|
currentPtsObserver = [renderSynchronizer addPeriodicTimeObserverForInterval:interval
|
||||||
queue:NULL
|
queue:NULL
|
||||||
usingBlock:^(CMTime time) {
|
usingBlock:^(CMTime time) {
|
||||||
|
@ -938,10 +946,25 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
||||||
|
|
||||||
CMTime latencyTime = CMTimeSubtract(*outputPts, time);
|
CMTime latencyTime = CMTimeSubtract(*outputPts, time);
|
||||||
double latencySeconds = CMTimeGetSeconds(latencyTime);
|
double latencySeconds = CMTimeGetSeconds(latencyTime);
|
||||||
|
double latencyVis = 0.0;
|
||||||
|
[lock lock];
|
||||||
|
if(*r8bstate) {
|
||||||
|
latencySeconds += r8bstate_latency(*r8bstate);
|
||||||
|
}
|
||||||
|
if(*r8bold) {
|
||||||
|
latencySeconds += r8bstate_latency(*r8bold);
|
||||||
|
}
|
||||||
|
if(*r8bvis) {
|
||||||
|
latencyVis = r8bstate_latency(*r8bvis);
|
||||||
|
}
|
||||||
|
[lock unlock];
|
||||||
if(latencySeconds < 0)
|
if(latencySeconds < 0)
|
||||||
latencySeconds = 0;
|
latencySeconds = 0;
|
||||||
|
latencyVis = latencySeconds - latencyVis;
|
||||||
|
if(latencyVis < 0)
|
||||||
|
latencyVis = 0;
|
||||||
*latencySecondsOut = latencySeconds;
|
*latencySecondsOut = latencySeconds;
|
||||||
[visController postLatency:latencySeconds];
|
[visController postLatency:latencyVis];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue