Seeking now takes the true nuclear approach to output, and should no longer have glitches
parent
d22ee14a36
commit
dfeca7aa97
|
@ -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<CogDecoder>)decoder startPaused:(BOOL)paused;
|
||||
|
||||
- (void)stop;
|
||||
- (void)pause;
|
||||
|
|
|
@ -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<CogDecoder>)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*/
|
||||
|
|
|
@ -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<CogDecoder>)decoder
|
||||
withOutputFormat:(AudioStreamBasicDescription)outputFormat
|
||||
withRGInfo:(NSDictionary*)rgi;
|
||||
|
||||
- (void)seek:(double)time;
|
||||
|
||||
- (void)launchThreads;
|
||||
|
||||
- (InputNode *)inputNode;
|
||||
- (InputNode *)stealInputNode;
|
||||
|
||||
- (id)finalNode;
|
||||
|
||||
|
|
|
@ -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<CogDecoder>)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
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
- (BOOL)openWithSource:(id<CogSource>)source;
|
||||
- (BOOL)openWithDecoder:(id<CogDecoder>) d;
|
||||
|
||||
- (id<CogDecoder>)stealDecoder;
|
||||
|
||||
- (void)process;
|
||||
- (NSDictionary *) properties;
|
||||
- (void)seek:(long)frame;
|
||||
|
|
|
@ -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<CogDecoder>) stealDecoder
|
||||
{
|
||||
[self removeObservers];
|
||||
id<CogDecoder> decoder = self->decoder;
|
||||
self->decoder = [[NSClassFromString(@"SilenceDecoder") alloc] init];
|
||||
[self registerObservers];
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue