diff --git a/Audio/AudioPlayer.h b/Audio/AudioPlayer.h index bfa1ea0ae..8ee6a3525 100644 --- a/Audio/AudioPlayer.h +++ b/Audio/AudioPlayer.h @@ -10,6 +10,7 @@ @class BufferChain; @class OutputNode; +@protocol CogDecoder; @interface AudioPlayer : NSObject { @@ -19,6 +20,10 @@ double volume; NSMutableArray *chainQueue; + + NSURL *currentStream; + id currentUserInfo; + NSDictionary *currentRGInfo; NSURL *nextStream; id nextStreamUserInfo; @@ -30,6 +35,7 @@ BOOL endOfInputReached; BOOL startedPaused; BOOL initialBufferFilled; + BOOL paused; } - (id)init; @@ -40,6 +46,7 @@ - (void)play:(NSURL *)url; - (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary*)rgi; - (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary*)rgi startPaused:(BOOL)paused; +- (void)play:(id)decoder startPaused:(BOOL)paused; - (void)stop; - (void)pause; diff --git a/Audio/AudioPlayer.m b/Audio/AudioPlayer.m index aeb9b9408..323002e25 100644 --- a/Audio/AudioPlayer.m +++ b/Audio/AudioPlayer.m @@ -55,9 +55,9 @@ - (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused { - output = [[OutputNode alloc] initWithController:self previous:nil]; - [output setup]; - [output setVolume: volume]; + if (output) { + [output close]; + } @synchronized(chainQueue) { for (id anObject in chainQueue) { @@ -72,9 +72,16 @@ bufferChain = nil; } } + output = [[OutputNode alloc] initWithController:self previous:nil]; + [output setup]; + [output setVolume: volume]; bufferChain = [[BufferChain alloc] initWithController:self]; [self notifyStreamChanged:userInfo]; + + currentStream = url; + currentUserInfo = userInfo; + currentRGInfo = rgi; while (![bufferChain open:url withOutputFormat:[output format] withRGInfo:rgi]) { @@ -87,10 +94,14 @@ { return; } - + userInfo = nextStreamUserInfo; rgi = nextStreamRGInfo; + currentStream = url; + currentUserInfo = userInfo; + currentRGInfo = rgi; + [self notifyStreamChanged:userInfo]; bufferChain = [[BufferChain alloc] initWithController:self]; @@ -108,6 +119,78 @@ if (paused) [self setPlaybackStatus:CogStatusPaused waitUntilDone:YES]; + + self->paused = paused; +} + +- (void)play:(id)decoder startPaused:(BOOL)paused +{ + if (output) { + [output close]; + } + @synchronized(chainQueue) { + for (id anObject in chainQueue) + { + [anObject setShouldContinue:NO]; + } + [chainQueue removeAllObjects]; + endOfInputReached = NO; + if (bufferChain) + { + [bufferChain setShouldContinue:NO]; + + bufferChain = nil; + } + } + output = [[OutputNode alloc] initWithController:self previous:nil]; + [output setup]; + [output setVolume: volume]; + + bufferChain = [[BufferChain alloc] initWithController:self]; + [self notifyStreamChanged:currentUserInfo]; + + NSURL *url = currentStream; + id userInfo = currentUserInfo; + NSDictionary *rgi = currentRGInfo; + + while (![bufferChain openWithDecoder:decoder withOutputFormat:[output format] withRGInfo:currentRGInfo]) + { + bufferChain = nil; + + [self requestNextStream: userInfo]; + + url = nextStream; + if (url == nil) + { + return; + } + + userInfo = nextStreamUserInfo; + rgi = nextStreamRGInfo; + + currentStream = url; + currentUserInfo = userInfo; + currentRGInfo = rgi; + + [self notifyStreamChanged:userInfo]; + + bufferChain = [[BufferChain alloc] initWithController:self]; + } + + [bufferChain setUserInfo:userInfo]; + + [self setShouldContinue:YES]; + + outputLaunched = NO; + startedPaused = paused; + initialBufferFilled = NO; + + [bufferChain launchThreads]; + + if (paused) + [self setPlaybackStatus:CogStatusPaused waitUntilDone:YES]; + + self->paused = paused; } - (void)stop @@ -122,6 +205,8 @@ [output pause]; [self setPlaybackStatus:CogStatusPaused waitUntilDone:YES]; + + paused = YES; } - (void)resume @@ -136,12 +221,15 @@ [output resume]; [self setPlaybackStatus:CogStatusPlaying waitUntilDone:YES]; + + paused = NO; } - (void)seekToTime:(double)time { //Need to reset everything's buffers, and then seek? /*HACK TO TEST HOW WELL THIS WOULD WORK*/ + [self play:[[bufferChain inputNode] stealDecoder] startPaused:paused]; [output seek:time]; [bufferChain seek:time]; /*END HACK*/ diff --git a/Audio/Chain/BufferChain.h b/Audio/Chain/BufferChain.h index 123e4e297..0a96c1812 100644 --- a/Audio/Chain/BufferChain.h +++ b/Audio/Chain/BufferChain.h @@ -16,7 +16,7 @@ InputNode *inputNode; ConverterNode *converterNode; - AudioStreamBasicDescription _inputFormat; + AudioStreamBasicDescription inputFormat; NSURL *streamURL; id userInfo; @@ -35,11 +35,17 @@ //Used when changing tracks to reuse the same decoder - (BOOL)openWithInput:(InputNode *)i withOutputFormat:(AudioStreamBasicDescription)outputFormat withRGInfo:(NSDictionary*)rgi; +//Used when resetting the decoder on seek +- (BOOL)openWithDecoder:(id)decoder + withOutputFormat:(AudioStreamBasicDescription)outputFormat + withRGInfo:(NSDictionary*)rgi; + - (void)seek:(double)time; - (void)launchThreads; - (InputNode *)inputNode; +- (InputNode *)stealInputNode; - (id)finalNode; diff --git a/Audio/Chain/BufferChain.m b/Audio/Chain/BufferChain.m index 0533a5e7a..31389aced 100644 --- a/Audio/Chain/BufferChain.m +++ b/Audio/Chain/BufferChain.m @@ -63,7 +63,7 @@ if (![inputNode openWithSource:source]) return NO; - if (![converterNode setupWithInputFormat:(_inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat]) + if (![converterNode setupWithInputFormat:(inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat]) return NO; [self setRGInfo:rgi]; @@ -82,7 +82,7 @@ return NO; DLog(@"Input Properties: %@", [inputNode properties]); - if (![converterNode setupWithInputFormat:(_inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat]) + if (![converterNode setupWithInputFormat:(inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat]) return NO; [self setRGInfo:rgi]; @@ -90,6 +90,25 @@ return YES; } +- (BOOL)openWithDecoder:(id)decoder + withOutputFormat:(AudioStreamBasicDescription)outputFormat + withRGInfo:(NSDictionary*)rgi; +{ + DLog(@"New buffer chain!"); + [self buildChain]; + + if (![inputNode openWithDecoder:decoder]) + return NO; + + DLog(@"Input Properties: %@", [inputNode properties]); + if (![converterNode setupWithInputFormat:(inputFormat = propertiesToASBD([inputNode properties])) outputFormat:outputFormat]) + return NO; + + [self setRGInfo:rgi]; + + return YES; +} + - (void)launchThreads { DLog(@"Properties: %@", [inputNode properties]); @@ -206,7 +225,7 @@ - (AudioStreamBasicDescription)inputFormat { - return _inputFormat; + return inputFormat; } @end diff --git a/Audio/Chain/InputNode.h b/Audio/Chain/InputNode.h index d54d7fe42..9ad81837f 100644 --- a/Audio/Chain/InputNode.h +++ b/Audio/Chain/InputNode.h @@ -36,6 +36,8 @@ - (BOOL)openWithSource:(id)source; - (BOOL)openWithDecoder:(id) d; +- (id)stealDecoder; + - (void)process; - (NSDictionary *) properties; - (void)seek:(long)frame; diff --git a/Audio/Chain/InputNode.m b/Audio/Chain/InputNode.m index c7e4e5722..f93de576c 100644 --- a/Audio/Chain/InputNode.m +++ b/Audio/Chain/InputNode.m @@ -215,11 +215,16 @@ return NO; } +- (void)removeObservers +{ + [decoder removeObserver:self forKeyPath:@"properties"]; + [decoder removeObserver:self forKeyPath:@"metadata"]; +} + - (void)dealloc { DLog(@"Input Node dealloc"); - [decoder removeObserver:self forKeyPath:@"properties"]; - [decoder removeObserver:self forKeyPath:@"metadata"]; + [self removeObservers]; } - (NSDictionary *) properties @@ -232,4 +237,13 @@ return decoder; } +- (id) stealDecoder +{ + [self removeObservers]; + id decoder = self->decoder; + self->decoder = [[NSClassFromString(@"SilenceDecoder") alloc] init]; + [self registerObservers]; + return decoder; +} + @end