Bug Fix: Greatly improve seeking operations
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 <kode54@gmail.com>
This commit is contained in:
parent
7c169f9ef1
commit
fa34d469df
9 changed files with 68 additions and 21 deletions
|
@ -25,6 +25,7 @@
|
||||||
BufferChain *bufferChain;
|
BufferChain *bufferChain;
|
||||||
OutputNode *output;
|
OutputNode *output;
|
||||||
|
|
||||||
|
BOOL muted;
|
||||||
double volume;
|
double volume;
|
||||||
double pitch;
|
double pitch;
|
||||||
double tempo;
|
double tempo;
|
||||||
|
@ -76,6 +77,9 @@
|
||||||
- (double)volumeUp:(double)amount;
|
- (double)volumeUp:(double)amount;
|
||||||
- (double)volumeDown:(double)amount;
|
- (double)volumeDown:(double)amount;
|
||||||
|
|
||||||
|
- (void)mute;
|
||||||
|
- (void)unmute;
|
||||||
|
|
||||||
- (double)amountPlayed;
|
- (double)amountPlayed;
|
||||||
- (double)amountPlayedInterval;
|
- (double)amountPlayedInterval;
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,9 @@
|
||||||
output = [[OutputNode alloc] initWithController:self previous:nil];
|
output = [[OutputNode alloc] initWithController:self previous:nil];
|
||||||
}
|
}
|
||||||
[output setup];
|
[output setup];
|
||||||
[output setVolume:volume];
|
if(muted) {
|
||||||
|
[output mute];
|
||||||
|
}
|
||||||
@synchronized(chainQueue) {
|
@synchronized(chainQueue) {
|
||||||
for(id anObject in chainQueue) {
|
for(id anObject in chainQueue) {
|
||||||
[anObject setShouldContinue:NO];
|
[anObject setShouldContinue:NO];
|
||||||
|
@ -177,6 +179,10 @@
|
||||||
[output resume];
|
[output resume];
|
||||||
|
|
||||||
[self setPlaybackStatus:CogStatusPlaying waitUntilDone:YES];
|
[self setPlaybackStatus:CogStatusPlaying waitUntilDone:YES];
|
||||||
|
|
||||||
|
if(muted) {
|
||||||
|
[self unmute];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)seekToTimeBG:(NSNumber *)time {
|
- (void)seekToTimeBG:(NSNumber *)time {
|
||||||
|
@ -184,6 +190,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)seekToTime:(double)time {
|
- (void)seekToTime:(double)time {
|
||||||
|
[self mute];
|
||||||
if(endOfInputReached) {
|
if(endOfInputReached) {
|
||||||
// This is a dirty hack in case the playback has finished with the track
|
// This is a dirty hack in case the playback has finished with the track
|
||||||
// that the user thinks they're seeking into
|
// that the user thinks they're seeking into
|
||||||
|
@ -218,6 +225,20 @@
|
||||||
return 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.
|
// This is called by the delegate DURING a requestNextStream request.
|
||||||
- (void)setNextStream:(NSURL *)url {
|
- (void)setNextStream:(NSURL *)url {
|
||||||
[self setNextStream:url withUserInfo:nil withRGInfo:nil];
|
[self setNextStream:url withUserInfo:nil withRGInfo:nil];
|
||||||
|
|
|
@ -230,7 +230,7 @@
|
||||||
AudioPlayer * audioPlayer = controller;
|
AudioPlayer * audioPlayer = controller;
|
||||||
OutputNode *outputNode = [audioPlayer output];
|
OutputNode *outputNode = [audioPlayer output];
|
||||||
|
|
||||||
[inputNode setLastVolume:[outputNode volume]];
|
[audioPlayer mute];
|
||||||
[inputNode seek:frame];
|
[inputNode seek:frame];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,9 +371,6 @@
|
||||||
[outputNode setVolume:v];
|
[outputNode setVolume:v];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(inputNode) {
|
|
||||||
[inputNode setLastVolume:v];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -29,8 +29,6 @@
|
||||||
BOOL shouldSeek;
|
BOOL shouldSeek;
|
||||||
long seekFrame;
|
long seekFrame;
|
||||||
|
|
||||||
double lastVolume;
|
|
||||||
|
|
||||||
BOOL observersAdded;
|
BOOL observersAdded;
|
||||||
|
|
||||||
Semaphore *exitAtTheEndOfTheStream;
|
Semaphore *exitAtTheEndOfTheStream;
|
||||||
|
@ -53,6 +51,4 @@
|
||||||
|
|
||||||
- (id<CogDecoder>_Nonnull)decoder;
|
- (id<CogDecoder>_Nonnull)decoder;
|
||||||
|
|
||||||
- (void)setLastVolume:(double)v;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -29,7 +29,6 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
if(self) {
|
if(self) {
|
||||||
exitAtTheEndOfTheStream = [[Semaphore alloc] init];
|
exitAtTheEndOfTheStream = [[Semaphore alloc] init];
|
||||||
threadExited = NO;
|
threadExited = NO;
|
||||||
lastVolume = 1.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -161,7 +160,10 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
while([self shouldContinue] == YES && [self endOfStream] == NO) {
|
while([self shouldContinue] == YES && [self endOfStream] == NO) {
|
||||||
if(shouldSeek == YES) {
|
if(shouldSeek == YES) {
|
||||||
BufferChain *bufferChain = controller;
|
BufferChain *bufferChain = controller;
|
||||||
[bufferChain setVolume:0.0];
|
AudioPlayer *audioPlayer = [controller controller];
|
||||||
|
[audioPlayer mute];
|
||||||
|
OutputNode *outputNode = [audioPlayer output];
|
||||||
|
[outputNode resetBuffer];
|
||||||
|
|
||||||
ConverterNode *converter = [bufferChain converter];
|
ConverterNode *converter = [bufferChain converter];
|
||||||
DSPRubberbandNode *rubberband = [bufferChain rubberband];
|
DSPRubberbandNode *rubberband = [bufferChain rubberband];
|
||||||
|
@ -198,7 +200,7 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
[controller setError:YES];
|
[controller setError:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
[bufferChain setVolume:lastVolume];
|
[audioPlayer unmute];
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioChunk *chunk;
|
AudioChunk *chunk;
|
||||||
|
@ -251,6 +253,7 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
seekFrame = frame;
|
seekFrame = frame;
|
||||||
shouldSeek = YES;
|
shouldSeek = YES;
|
||||||
DLog(@"Should seek!");
|
DLog(@"Should seek!");
|
||||||
|
[self resetBuffer];
|
||||||
[writeSemaphore signal];
|
[writeSemaphore signal];
|
||||||
|
|
||||||
if(endOfStream) {
|
if(endOfStream) {
|
||||||
|
@ -300,8 +303,4 @@ static void *kInputNodeContext = &kInputNodeContext;
|
||||||
return [buffer listDuration];
|
return [buffer listDuration];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLastVolume:(double)v {
|
|
||||||
lastVolume = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -62,6 +62,9 @@
|
||||||
- (double)volume;
|
- (double)volume;
|
||||||
- (void)setVolume:(double)v;
|
- (void)setVolume:(double)v;
|
||||||
|
|
||||||
|
- (void)mute;
|
||||||
|
- (void)unmute;
|
||||||
|
|
||||||
- (void)setShouldContinue:(BOOL)s;
|
- (void)setShouldContinue:(BOOL)s;
|
||||||
|
|
||||||
- (void)setShouldPlayOutBuffer:(BOOL)s;
|
- (void)setShouldPlayOutBuffer:(BOOL)s;
|
||||||
|
|
|
@ -50,6 +50,14 @@
|
||||||
[output resume];
|
[output resume];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)mute {
|
||||||
|
[output mute];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unmute {
|
||||||
|
[output unmute];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)incrementAmountPlayed:(double)seconds {
|
- (void)incrementAmountPlayed:(double)seconds {
|
||||||
amountPlayed += seconds;
|
amountPlayed += seconds;
|
||||||
amountPlayedInterval += seconds;
|
amountPlayedInterval += seconds;
|
||||||
|
@ -156,7 +164,8 @@
|
||||||
config = channelConfig;
|
config = channelConfig;
|
||||||
// Calculate a ratio and add to double(seconds) instead, as format may change
|
// Calculate a ratio and add to double(seconds) instead, as format may change
|
||||||
// double oldSampleRatio = sampleRatio;
|
// double oldSampleRatio = sampleRatio;
|
||||||
BufferChain *bufferChain = [controller bufferChain];
|
AudioPlayer *audioPlayer = controller;
|
||||||
|
BufferChain *bufferChain = [audioPlayer bufferChain];
|
||||||
if(bufferChain) {
|
if(bufferChain) {
|
||||||
ConverterNode *converter = [bufferChain converter];
|
ConverterNode *converter = [bufferChain converter];
|
||||||
DSPDownmixNode *downmix = [bufferChain downmix];
|
DSPDownmixNode *downmix = [bufferChain downmix];
|
||||||
|
@ -180,11 +189,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(formatChanged) {
|
if(formatChanged) {
|
||||||
|
[audioPlayer mute];
|
||||||
InputNode *inputNode = [bufferChain inputNode];
|
InputNode *inputNode = [bufferChain inputNode];
|
||||||
if(inputNode) {
|
|
||||||
[inputNode setLastVolume:[output volume]];
|
|
||||||
[output setVolume:0.0];
|
|
||||||
}
|
|
||||||
if(converter) {
|
if(converter) {
|
||||||
[converter setOutputFormat:format];
|
[converter setOutputFormat:format];
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,7 @@ using std::atomic_long;
|
||||||
float tempBuffer[512 * 32];
|
float tempBuffer[512 * 32];
|
||||||
float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count
|
float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count
|
||||||
|
|
||||||
|
BOOL muted;
|
||||||
#ifdef OUTPUT_LOG
|
#ifdef OUTPUT_LOG
|
||||||
FILE *_logFile;
|
FILE *_logFile;
|
||||||
#endif
|
#endif
|
||||||
|
@ -125,6 +126,9 @@ using std::atomic_long;
|
||||||
- (double)volume;
|
- (double)volume;
|
||||||
- (void)setVolume:(double)v;
|
- (void)setVolume:(double)v;
|
||||||
|
|
||||||
|
- (void)mute;
|
||||||
|
- (void)unmute;
|
||||||
|
|
||||||
- (void)setShouldPlayOutBuffer:(BOOL)enabled;
|
- (void)setShouldPlayOutBuffer:(BOOL)enabled;
|
||||||
|
|
||||||
- (void)sustainHDCD;
|
- (void)sustainHDCD;
|
||||||
|
|
|
@ -618,6 +618,12 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
while(renderedSamples < frameCount) {
|
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;
|
int inputRemain = _self->inputRemain;
|
||||||
while(!inputRemain) {
|
while(!inputRemain) {
|
||||||
inputRemain = [_self renderAndConvert];
|
inputRemain = [_self renderAndConvert];
|
||||||
|
@ -740,6 +746,17 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
||||||
volume = v * 0.01f;
|
volume = v * 0.01f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)mute {
|
||||||
|
if(!muted) {
|
||||||
|
muted = YES;
|
||||||
|
inputRemain = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unmute {
|
||||||
|
muted = NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (double)latency {
|
- (double)latency {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue