From c48a52cda3e8ec612f1e27a9655b3537a9c58acd Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Thu, 13 Feb 2025 03:26:59 -0800 Subject: [PATCH] Bug Fixes: Fix monotonically increasing timestamps Fixes timestamps in several cases where they were being processed incorrectly, which was causing some chunked audio files to mis-report timestamps into the past or the future, which caused the seekbar to jump around in an unpredictable way. Signed-off-by: Christopher Snowhill --- Audio/Chain/AudioChunk.m | 4 ++-- Audio/Chain/ChunkList.m | 6 ++++-- Audio/Chain/ConverterNode.m | 5 ++++- Audio/Chain/OutputNode.m | 2 +- Audio/Output/OutputCoreAudio.m | 3 +-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Audio/Chain/AudioChunk.m b/Audio/Chain/AudioChunk.m index cd49722a3..0cfee6bf2 100644 --- a/Audio/Chain/AudioChunk.m +++ b/Audio/Chain/AudioChunk.m @@ -173,12 +173,12 @@ static const uint32_t AudioChannelConfigTable[] = { - (NSData *)removeSamples:(size_t)frameCount { if(formatAssigned) { @autoreleasepool { - const double framesDuration = (double)(frameCount) / format.mSampleRate; + const double secondsDuration = (double)(frameCount) / format.mSampleRate; const size_t bytesPerPacket = format.mBytesPerPacket; const size_t byteCount = bytesPerPacket * frameCount; NSData *ret = [chunkData subdataWithRange:NSMakeRange(0, byteCount)]; [chunkData replaceBytesInRange:NSMakeRange(0, byteCount) withBytes:NULL length:0]; - streamTimestamp += framesDuration * streamTimeRatio; + streamTimestamp += secondsDuration * streamTimeRatio; return ret; } } diff --git a/Audio/Chain/ChunkList.m b/Audio/Chain/ChunkList.m index c0fa3e08f..6d8bfd91e 100644 --- a/Audio/Chain/ChunkList.m +++ b/Audio/Chain/ChunkList.m @@ -495,12 +495,13 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes inRemover = NO; return chunk; } + double streamTimestamp = [chunk streamTimestamp]; NSData *removedData = [chunk removeSamples:maxFrameCount]; AudioChunk *ret = [[AudioChunk alloc] init]; [ret setFormat:[chunk format]]; [ret setChannelConfig:[chunk channelConfig]]; [ret setLossless:[chunk lossless]]; - [ret setStreamTimestamp:[chunk streamTimestamp]]; + [ret setStreamTimestamp:streamTimestamp]; [ret setStreamTimeRatio:[chunk streamTimeRatio]]; [ret assignData:removedData]; listDuration -= [ret duration]; @@ -535,12 +536,13 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes inRemover = NO; return [self convertChunk:chunk]; } + double streamTimestamp = [chunk streamTimestamp]; NSData *removedData = [chunk removeSamples:maxFrameCount]; AudioChunk *ret = [[AudioChunk alloc] init]; [ret setFormat:[chunk format]]; [ret setChannelConfig:[chunk channelConfig]]; [ret setLossless:[chunk lossless]]; - [ret setStreamTimestamp:[chunk streamTimestamp]]; + [ret setStreamTimestamp:streamTimestamp]; [ret setStreamTimeRatio:[chunk streamTimeRatio]]; [ret assignData:removedData]; listDuration -= [ret duration]; diff --git a/Audio/Chain/ConverterNode.m b/Audio/Chain/ConverterNode.m index 754549bdc..27970a34c 100644 --- a/Audio/Chain/ConverterNode.m +++ b/Audio/Chain/ConverterNode.m @@ -137,7 +137,10 @@ void scale_by_volume(float *buffer, size_t count, float volume) { if(inpOffset == inpSize) { streamTimestamp = 0.0; streamTimeRatio = 1.0; - [self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]; + if(![self peekTimestamp:&streamTimestamp timeRatio:&streamTimeRatio]) { + convertEntered = NO; + return nil; + } } while(inpOffset == inpSize) { diff --git a/Audio/Chain/OutputNode.m b/Audio/Chain/OutputNode.m index c41224f95..52835421f 100644 --- a/Audio/Chain/OutputNode.m +++ b/Audio/Chain/OutputNode.m @@ -63,7 +63,7 @@ double delta = seconds - amountPlayed; if(delta > 0.0 && delta < 5.0) { [self incrementAmountPlayed:delta]; - } else { + } else if(delta) { amountPlayed = seconds; } } diff --git a/Audio/Output/OutputCoreAudio.m b/Audio/Output/OutputCoreAudio.m index f25dc818f..ae860d977 100644 --- a/Audio/Output/OutputCoreAudio.m +++ b/Audio/Output/OutputCoreAudio.m @@ -67,6 +67,7 @@ static void *kOutputCoreAudioContext = &kOutputCoreAudioContext; if(!chunkRemain) { chunk = [outputController readChunk:amountToRead]; + streamTimestamp = [chunk streamTimestamp]; } else { chunk = chunkRemain; chunkRemain = nil; @@ -77,8 +78,6 @@ static void *kOutputCoreAudioContext = &kOutputCoreAudioContext; config = [chunk channelConfig]; double chunkDuration = 0; - streamTimestamp = [chunk streamTimestamp] + [chunk durationRatioed]; - if(frameCount) { chunkDuration = [chunk duration];