Skip to content

Commit

Permalink
Bug Fix: Greatly improve seeking operations
Browse files Browse the repository at this point in the history
Seeking now mutes properly, and will not leave the audio muted across
other operations. Audio output changes should also mute and destroy the
buffers of the input chain, so that the audio resets properly.

Signed-off-by: Christopher Snowhill <[email protected]>
  • Loading branch information
kode54 committed Feb 24, 2025
1 parent 7c169f9 commit fa34d46
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Audio/AudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
BufferChain *bufferChain;
OutputNode *output;

BOOL muted;
double volume;
double pitch;
double tempo;
Expand Down Expand Up @@ -76,6 +77,9 @@
- (double)volumeUp:(double)amount;
- (double)volumeDown:(double)amount;

- (void)mute;
- (void)unmute;

- (double)amountPlayed;
- (double)amountPlayedInterval;

Expand Down
23 changes: 22 additions & 1 deletion Audio/AudioPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ - (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)r
output = [[OutputNode alloc] initWithController:self previous:nil];
}
[output setup];
[output setVolume:volume];
if(muted) {
[output mute];
}
@synchronized(chainQueue) {
for(id anObject in chainQueue) {
[anObject setShouldContinue:NO];
Expand Down Expand Up @@ -177,13 +179,18 @@ - (void)resume {
[output resume];

[self setPlaybackStatus:CogStatusPlaying waitUntilDone:YES];

if(muted) {
[self unmute];
}
}

- (void)seekToTimeBG:(NSNumber *)time {
[self seekToTime:[time doubleValue]];
}

- (void)seekToTime:(double)time {
[self mute];
if(endOfInputReached) {
// This is a dirty hack in case the playback has finished with the track
// that the user thinks they're seeking into
Expand Down Expand Up @@ -218,6 +225,20 @@ - (double)volume {
return volume;
}

- (void)mute {
if(!muted) {
[output mute];
muted = YES;
}
}

- (void)unmute {
if(muted) {
[output unmute];
muted = NO;
}
}

// This is called by the delegate DURING a requestNextStream request.
- (void)setNextStream:(NSURL *)url {
[self setNextStream:url withUserInfo:nil withRGInfo:nil];
Expand Down
5 changes: 1 addition & 4 deletions Audio/Chain/BufferChain.m
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ - (void)seek:(double)time {
AudioPlayer * audioPlayer = controller;
OutputNode *outputNode = [audioPlayer output];

[inputNode setLastVolume:[outputNode volume]];
[audioPlayer mute];
[inputNode seek:frame];
}

Expand Down Expand Up @@ -371,9 +371,6 @@ - (void)setVolume:(double)v {
[outputNode setVolume:v];
}
}
if(inputNode) {
[inputNode setLastVolume:v];
}
}

@end
4 changes: 0 additions & 4 deletions Audio/Chain/InputNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
BOOL shouldSeek;
long seekFrame;

double lastVolume;

BOOL observersAdded;

Semaphore *exitAtTheEndOfTheStream;
Expand All @@ -53,6 +51,4 @@

- (id<CogDecoder>_Nonnull)decoder;

- (void)setLastVolume:(double)v;

@end
13 changes: 6 additions & 7 deletions Audio/Chain/InputNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ - (id)initWithController:(id)c previous:(id)p {
if(self) {
exitAtTheEndOfTheStream = [[Semaphore alloc] init];
threadExited = NO;
lastVolume = 1.0;
}

return self;
Expand Down Expand Up @@ -161,7 +160,10 @@ - (void)process {
while([self shouldContinue] == YES && [self endOfStream] == NO) {
if(shouldSeek == YES) {
BufferChain *bufferChain = controller;
[bufferChain setVolume:0.0];
AudioPlayer *audioPlayer = [controller controller];
[audioPlayer mute];
OutputNode *outputNode = [audioPlayer output];
[outputNode resetBuffer];

ConverterNode *converter = [bufferChain converter];
DSPRubberbandNode *rubberband = [bufferChain rubberband];
Expand Down Expand Up @@ -198,7 +200,7 @@ - (void)process {
[controller setError:YES];
}

[bufferChain setVolume:lastVolume];
[audioPlayer unmute];
}

AudioChunk *chunk;
Expand Down Expand Up @@ -251,6 +253,7 @@ - (void)seek:(long)frame {
seekFrame = frame;
shouldSeek = YES;
DLog(@"Should seek!");
[self resetBuffer];
[writeSemaphore signal];

if(endOfStream) {
Expand Down Expand Up @@ -300,8 +303,4 @@ - (double)secondsBuffered {
return [buffer listDuration];
}

- (void)setLastVolume:(double)v {
lastVolume = v;
}

@end
3 changes: 3 additions & 0 deletions Audio/Chain/OutputNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@
- (double)volume;
- (void)setVolume:(double)v;

- (void)mute;
- (void)unmute;

- (void)setShouldContinue:(BOOL)s;

- (void)setShouldPlayOutBuffer:(BOOL)s;
Expand Down
16 changes: 11 additions & 5 deletions Audio/Chain/OutputNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ - (void)resume {
[output resume];
}

- (void)mute {
[output mute];
}

- (void)unmute {
[output unmute];
}

- (void)incrementAmountPlayed:(double)seconds {
amountPlayed += seconds;
amountPlayedInterval += seconds;
Expand Down Expand Up @@ -156,7 +164,8 @@ - (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)chann
config = channelConfig;
// Calculate a ratio and add to double(seconds) instead, as format may change
// double oldSampleRatio = sampleRatio;
BufferChain *bufferChain = [controller bufferChain];
AudioPlayer *audioPlayer = controller;
BufferChain *bufferChain = [audioPlayer bufferChain];
if(bufferChain) {
ConverterNode *converter = [bufferChain converter];
DSPDownmixNode *downmix = [bufferChain downmix];
Expand All @@ -180,11 +189,8 @@ - (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)chann
}
}
if(formatChanged) {
[audioPlayer mute];
InputNode *inputNode = [bufferChain inputNode];
if(inputNode) {
[inputNode setLastVolume:[output volume]];
[output setVolume:0.0];
}
if(converter) {
[converter setOutputFormat:format];
}
Expand Down
4 changes: 4 additions & 0 deletions Audio/Output/OutputCoreAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ using std::atomic_long;
float tempBuffer[512 * 32];
float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count

BOOL muted;
#ifdef OUTPUT_LOG
FILE *_logFile;
#endif
Expand All @@ -125,6 +126,9 @@ using std::atomic_long;
- (double)volume;
- (void)setVolume:(double)v;

- (void)mute;
- (void)unmute;

- (void)setShouldPlayOutBuffer:(BOOL)enabled;

- (void)sustainHDCD;
Expand Down
17 changes: 17 additions & 0 deletions Audio/Output/OutputCoreAudio.m
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,12 @@ - (void)audioOutputBlock {

@autoreleasepool {
while(renderedSamples < frameCount) {
if(_self->muted) {
inputData->mBuffers[0].mDataByteSize = frameCount * format->mBytesPerPacket;
inputData->mBuffers[0].mNumberChannels = channels;
bzero(inputData->mBuffers[0].mData, inputData->mBuffers[0].mDataByteSize);
return 0;
}
int inputRemain = _self->inputRemain;
while(!inputRemain) {
inputRemain = [_self renderAndConvert];
Expand Down Expand Up @@ -740,6 +746,17 @@ - (void)setVolume:(double)v {
volume = v * 0.01f;
}

- (void)mute {
if(!muted) {
muted = YES;
inputRemain = 0;
}
}

- (void)unmute {
muted = NO;
}

- (double)latency {
return 0.0;
}
Expand Down

0 comments on commit fa34d46

Please sign in to comment.