285 lines
5.4 KiB
Objective-C
285 lines
5.4 KiB
Objective-C
//
|
|
// AudioController.m
|
|
// Cog
|
|
//
|
|
// Created by Vincent Spader on 8/7/05.
|
|
// Copyright 2005 Vincent Spader. All rights reserved.
|
|
//
|
|
|
|
#import "AudioPlayer.h"
|
|
#import "BufferChain.h"
|
|
#import "OutputNode.h"
|
|
#import "Status.h"
|
|
|
|
|
|
|
|
@implementation AudioPlayer
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self)
|
|
{
|
|
output = NULL;
|
|
bufferChain = NULL;
|
|
|
|
chainQueue = [[NSMutableArray alloc] init];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)setDelegate:(id)d
|
|
{
|
|
delegate = d;
|
|
}
|
|
|
|
- (id)delegate {
|
|
return delegate;
|
|
}
|
|
|
|
- (void)play:(NSURL *)url
|
|
{
|
|
[self play:url withUserInfo:nil];
|
|
}
|
|
|
|
|
|
- (void)play:(NSURL *)url withUserInfo:(id)userInfo
|
|
{
|
|
if (output)
|
|
{
|
|
[output release];
|
|
}
|
|
output = [[OutputNode alloc] initWithController:self previous:nil];
|
|
[output setup];
|
|
|
|
NSEnumerator *enumerator = [chainQueue objectEnumerator];
|
|
id anObject;
|
|
while (anObject = [enumerator nextObject])
|
|
{
|
|
[anObject setShouldContinue:NO];
|
|
}
|
|
[chainQueue removeAllObjects];
|
|
|
|
if (bufferChain)
|
|
{
|
|
[bufferChain setShouldContinue:NO];
|
|
|
|
[bufferChain release];
|
|
}
|
|
bufferChain = [[BufferChain alloc] initWithController:self];
|
|
|
|
while (![bufferChain open:url withOutputFormat:[output format]])
|
|
{
|
|
[bufferChain release];
|
|
|
|
[self requestNextStream: userInfo];
|
|
|
|
url = nextStream;
|
|
if (url == nil)
|
|
{
|
|
return;
|
|
}
|
|
|
|
userInfo = nextStreamUserInfo;
|
|
|
|
[self notifyStreamChanged:userInfo];
|
|
|
|
bufferChain = [[BufferChain alloc] initWithController:self];
|
|
}
|
|
|
|
[bufferChain setUserInfo:userInfo];
|
|
|
|
[self setShouldContinue:YES];
|
|
DBLog(@"DETACHING THREADS");
|
|
|
|
[output launchThread];
|
|
[bufferChain launchThreads];
|
|
|
|
[self setPlaybackStatus:kCogStatusPlaying];
|
|
}
|
|
|
|
- (void)stop
|
|
{
|
|
//Set shouldoContinue to NO on allll things
|
|
[self setShouldContinue:NO];
|
|
[self setPlaybackStatus:kCogStatusStopped];
|
|
}
|
|
|
|
- (void)pause
|
|
{
|
|
[output pause];
|
|
|
|
[self setPlaybackStatus:kCogStatusPaused];
|
|
}
|
|
|
|
- (void)resume
|
|
{
|
|
[output resume];
|
|
|
|
[self setPlaybackStatus:kCogStatusPlaying];
|
|
}
|
|
|
|
- (void)seekToTime:(double)time
|
|
{
|
|
//Need to reset everything's buffers, and then seek?
|
|
/*HACK TO TEST HOW WELL THIS WOULD WORK*/
|
|
[bufferChain seek:time];
|
|
[output seek:time];
|
|
|
|
|
|
/*END HACK*/
|
|
}
|
|
|
|
- (void)setVolume:(double)v
|
|
{
|
|
[output setVolume:v];
|
|
}
|
|
|
|
- (void)setNextStream:(NSURL *)url
|
|
{
|
|
[self setNextStream:url withUserInfo:nil];
|
|
}
|
|
|
|
- (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo
|
|
{
|
|
[url retain];
|
|
[nextStream release];
|
|
nextStream = url;
|
|
|
|
[userInfo retain];
|
|
[nextStreamUserInfo release];
|
|
nextStreamUserInfo = userInfo;
|
|
|
|
}
|
|
|
|
|
|
- (void)setShouldContinue:(BOOL)s
|
|
{
|
|
[bufferChain setShouldContinue:s];
|
|
[output setShouldContinue:s];
|
|
}
|
|
|
|
- (double)amountPlayed
|
|
{
|
|
return [output amountPlayed];
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)requestNextStream:(id)userInfo
|
|
{
|
|
[self sendDelegateMethod:@selector(audioPlayer:requestNextStream:) withObject:userInfo waitUntilDone:YES];
|
|
}
|
|
|
|
- (void)notifyStreamChanged:(id)userInfo
|
|
{
|
|
[self sendDelegateMethod:@selector(audioPlayer:streamChanged:) withObject:userInfo waitUntilDone:NO];
|
|
}
|
|
|
|
|
|
|
|
- (void)endOfInputReached:(BufferChain *)sender //Sender is a BufferChain
|
|
{
|
|
BufferChain *newChain = nil;
|
|
|
|
nextStreamUserInfo = [sender userInfo];
|
|
[nextStreamUserInfo retain]; //Retained because when setNextStream is called, it will be released!!!
|
|
|
|
do {
|
|
[newChain release];
|
|
[self requestNextStream: nextStreamUserInfo];
|
|
|
|
if (nextStream == nil)
|
|
{
|
|
return;
|
|
}
|
|
|
|
newChain = [[BufferChain alloc] initWithController:self];
|
|
} while (![newChain open:nextStream withOutputFormat:[output format]]);
|
|
|
|
[newChain setUserInfo: nextStreamUserInfo];
|
|
|
|
[newChain setShouldContinue:YES];
|
|
[newChain launchThreads];
|
|
|
|
[chainQueue insertObject:newChain atIndex:[chainQueue count]];
|
|
|
|
[newChain release];
|
|
}
|
|
|
|
- (void)endOfInputPlayed
|
|
{
|
|
if ([chainQueue count] <= 0)
|
|
{
|
|
//End of playlist
|
|
DBLog(@"STOPPED");
|
|
[self stop];
|
|
|
|
return;
|
|
}
|
|
// NSLog(@"SWAPPING BUFFERS");
|
|
[bufferChain release];
|
|
|
|
DBLog(@"END OF INPUT PLAYED");
|
|
bufferChain = [chainQueue objectAtIndex:0];
|
|
[bufferChain retain];
|
|
|
|
[chainQueue removeObjectAtIndex:0];
|
|
|
|
[self notifyStreamChanged:[bufferChain userInfo]];
|
|
[output setEndOfStream:NO];
|
|
}
|
|
|
|
- (void)sendDelegateMethod:(SEL)selector withObject:(id)obj waitUntilDone:(BOOL)wait
|
|
{
|
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[delegate methodSignatureForSelector:selector]];
|
|
[invocation setSelector:selector];
|
|
[invocation setArgument:&self atIndex:2]; //Indexes start at 2, the first being self, the second being command.
|
|
[invocation setArgument:&obj atIndex:3];
|
|
|
|
[self performSelectorOnMainThread:@selector(sendDelegateMethodMainThread:) withObject:invocation waitUntilDone:wait];
|
|
}
|
|
|
|
|
|
- (void)sendDelegateMethodMainThread:(id)invocation
|
|
{
|
|
[invocation invokeWithTarget:delegate];
|
|
}
|
|
|
|
- (void)setPlaybackStatus:(int)status
|
|
{
|
|
[self sendDelegateMethod:@selector(audioPlayer:statusChanged:) withObject:[NSNumber numberWithInt:status] waitUntilDone:NO];
|
|
}
|
|
|
|
- (BufferChain *)bufferChain
|
|
{
|
|
return bufferChain;
|
|
}
|
|
|
|
- (OutputNode *) output
|
|
{
|
|
return output;
|
|
}
|
|
|
|
+ (NSArray *)fileTypes
|
|
{
|
|
PluginController *pluginController = [PluginController sharedPluginController];
|
|
|
|
NSArray *decoderTypes = [[pluginController decoders] allKeys];
|
|
NSArray *metdataReaderTypes = [[pluginController metadataReaders] allKeys];
|
|
NSArray *propertiesReaderTypes = [[pluginController propertiesReaders] allKeys];
|
|
|
|
NSMutableSet *types = [NSMutableSet set];
|
|
|
|
[types addObjectsFromArray:decoderTypes];
|
|
[types addObjectsFromArray:metdataReaderTypes];
|
|
[types addObjectsFromArray:propertiesReaderTypes];
|
|
|
|
return [types allObjects];
|
|
}
|
|
|
|
|
|
@end
|