diff --git a/Application/AppController.h b/Application/AppController.h index 7814d98f0..5ba197a82 100644 --- a/Application/AppController.h +++ b/Application/AppController.h @@ -49,6 +49,8 @@ AppleRemote *remote; BOOL remoteButtonHeld; /* true as long as the user holds the left,right,plus or minus on the remote control */ + + NSOperationQueue *queue; // Since we are the app delegate, we take care of the op queue } - (IBAction)openURL:(id)sender; @@ -82,5 +84,7 @@ OSStatus handleHotKey(EventHandlerCallRef nextHandler,EventRef theEvent,void *us - (IBAction)decreaseFontSize:(id)sender; - (void)changeFontSize:(float)size; +// return the operation queue +- (NSOperationQueue *)sharedOperationQueue; @end diff --git a/Application/AppController.m b/Application/AppController.m index 3358e5554..024a1875a 100644 --- a/Application/AppController.m +++ b/Application/AppController.m @@ -35,11 +35,19 @@ remote = [[AppleRemote alloc] init]; [remote setDelegate: self]; + + queue = [[NSOperationQueue alloc]init]; } return self; } +- (void)dealloc +{ + [queue release]; + [super dealloc]; +} + // Listen to the remote in exclusive mode, only when Cog is the active application - (void)applicationDidBecomeActive:(NSNotification *)notification { @@ -462,4 +470,9 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ [self changeFontSize:-1]; } + +- (NSOperationQueue *)sharedOperationQueue +{ + return queue; +} @end diff --git a/Playlist/PlaylistEntry.h b/Playlist/PlaylistEntry.h index b2baff7a3..da160ef45 100644 --- a/Playlist/PlaylistEntry.h +++ b/Playlist/PlaylistEntry.h @@ -50,10 +50,6 @@ + (NSSet *)keyPathsForValuesAffectingStatus; + (NSSet *)keyPathsForValuesAffectingStatusMessage; -- (void)setProperties:(NSDictionary *)properties; -- (void)readPropertiesThread; -- (void)readMetadataThread; - @property(readonly) NSString *display; @property(retain, readonly) NSNumber *length; @property(readonly) NSString *path; diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index d46acccad..0b1524f41 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -7,8 +7,6 @@ // #import "PlaylistEntry.h" -#import "CogAudio/AudioPropertiesReader.h" -#import "CogAudio/AudioMetadataReader.h" @implementation PlaylistEntry @@ -76,34 +74,6 @@ return [NSSet setWithObjects:@"current", @"queued", @"queuePosition", @"error", @"errorMessage", @"stopAfter", nil]; } -- (void)setProperties:(NSDictionary *)properties -{ - if (properties == nil) - { - self.error = YES; - self.errorMessage = @"Unable to retrieve properties."; - - return; - } - - [self setValuesForKeysWithDictionary:properties]; -} - -- (void)readPropertiesThread -{ - NSDictionary *properties = [AudioPropertiesReader propertiesForURL:self.URL]; - - [self performSelectorOnMainThread:@selector(setProperties:) withObject:properties waitUntilDone:YES]; -} - -- (void)readMetadataThread -{ - NSDictionary *metadata = [AudioMetadataReader metadataForURL:self.URL]; - - [self performSelectorOnMainThread:@selector(setValuesForKeysWithDictionary:) withObject:metadata waitUntilDone:YES]; - -} - - (NSString *)description { return [NSString stringWithFormat:@"PlaylistEntry %i:(%@)", self.index, self.URL]; diff --git a/Playlist/PlaylistLoader.h b/Playlist/PlaylistLoader.h index e3e33eab2..b58087dec 100755 --- a/Playlist/PlaylistLoader.h +++ b/Playlist/PlaylistLoader.h @@ -9,6 +9,7 @@ #import @class PlaylistController; +@class PlaylistEntry; typedef enum { kPlaylistM3u, @@ -30,6 +31,9 @@ typedef enum { - (BOOL)saveM3u:(NSString *)filename; - (BOOL)savePls:(NSString *)filename; +//read info for a playlist entry +- (NSDictionary *)readEntryInfo:(PlaylistEntry *)pe; + - (NSArray *)acceptableFileTypes; - (NSArray *)acceptablePlaylistTypes; //Only m3u and pls saving - (NSArray *)acceptableContainerTypes; diff --git a/Playlist/PlaylistLoader.m b/Playlist/PlaylistLoader.m index 9a9b9badf..44eae2f59 100755 --- a/Playlist/PlaylistLoader.m +++ b/Playlist/PlaylistLoader.m @@ -9,11 +9,14 @@ #import "PlaylistLoader.h" #import "PlaylistController.h" #import "PlaylistEntry.h" +#import "AppController.h" #import "NSFileHandle+CreateFile.h" #import "CogAudio/AudioPlayer.h" #import "CogAudio/AudioContainer.h" +#import "CogAudio/AudioPropertiesReader.h" +#import "CogAudio/AudioMetadataReader.h" @implementation PlaylistLoader @@ -265,32 +268,77 @@ //Select the first entry in the group that was just added [playlistController setSelectionIndex:index]; - //Other thread for reading things... - [self performSelectorInBackground:@selector(readEntriesInfoThread:) withObject:entries]; - + NSOperationQueue *queue; + queue = [[[NSApplication sharedApplication] delegate] sharedOperationQueue]; + + NSInvocationOperation *oldReadEntryInfoOperation = Nil; + for (PlaylistEntry *pe in entries) + { + NSInvocationOperation *readEntryInfoOperation; + readEntryInfoOperation = [[[NSInvocationOperation alloc] + initWithTarget:self + selector:@selector(readEntryInfo:) + object:pe] autorelease]; + if (oldReadEntryInfoOperation) + { + [readEntryInfoOperation addDependency:oldReadEntryInfoOperation]; + [oldReadEntryInfoOperation release]; + } + [readEntryInfoOperation addObserver:self + forKeyPath:@"isFinished" + options:NSKeyValueObservingOptionNew + context:NULL]; + [queue addOperation:readEntryInfoOperation]; + oldReadEntryInfoOperation = [readEntryInfoOperation retain]; + } return; } -- (void)readEntriesInfoThread:(NSArray *)entries +- (NSDictionary *)readEntryInfo:(PlaylistEntry *)pe { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + // Just setting this to 30 for now... + NSMutableDictionary *entryInfo = [NSMutableDictionary dictionaryWithCapacity:30]; + NSDictionary *entryProperties; + entryProperties = [AudioPropertiesReader propertiesForURL:pe.URL]; + if (entryProperties == nil) + return nil; + + [entryInfo addEntriesFromDictionary:entryProperties]; + [entryInfo addEntriesFromDictionary:[AudioMetadataReader metadataForURL:pe.URL]]; + return entryInfo; +} - PlaylistEntry *pe; - for (pe in entries) - { - [pe readPropertiesThread]; - - [pe readMetadataThread]; - - //Hack so the display gets updated - if (pe == [playlistController currentEntry]) - [playlistController performSelectorOnMainThread:@selector(setCurrentEntry:) withObject:[playlistController currentEntry] waitUntilDone:YES]; - } - - - [playlistController performSelectorOnMainThread:@selector(updateTotalTime) withObject:nil waitUntilDone:NO]; - - [pool release]; +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + // We finished reading the info for a playlist entry + if ([keyPath isEqualToString:@"isFinished"] && [object isFinished]) + { + // get the results + NSDictionary *entryInfo = [object result]; + // get the playlist entry that the thread was inspecting + PlaylistEntry *pe; + [[object invocation]getArgument:&pe atIndex:2]; + + if (entryInfo == nil) + { + pe.error = YES; + pe.errorMessage = @"Unable to retrieve properties."; + } + else + { + [pe setValuesForKeysWithDictionary:entryInfo]; + [playlistController updateTotalTime]; + } + + //Hack so the display gets updated + if (pe == [playlistController currentEntry]) + [playlistController setCurrentEntry:[playlistController currentEntry]]; + // stop observing + [object removeObserver:self forKeyPath:keyPath]; + } } - (void)addURLs:(NSArray *)urls sort:(BOOL)sort