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 <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-02-13 03:26:59 -08:00
parent 96a79d3ff2
commit c48a52cda3
5 changed files with 12 additions and 8 deletions

View file

@ -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;
}
}

View file

@ -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];

View file

@ -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) {

View file

@ -63,7 +63,7 @@
double delta = seconds - amountPlayed;
if(delta > 0.0 && delta < 5.0) {
[self incrementAmountPlayed:delta];
} else {
} else if(delta) {
amountPlayed = seconds;
}
}

View file

@ -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];