diff --git a/Audio Players/SMKAVQueuePlayer.m b/Audio Players/SMKAVQueuePlayer.m index 81d751c..e95bfc1 100644 --- a/Audio Players/SMKAVQueuePlayer.m +++ b/Audio Players/SMKAVQueuePlayer.m @@ -30,7 +30,7 @@ @implementation SMKAVQueuePlayer { - (id)init { if ((self = [super init])) { - self.audioPlayer = [AVQueuePlayer queuePlayerWithItems:nil]; + self.audioPlayer = [AVQueuePlayer queuePlayerWithItems:[NSArray array]]; __weak SMKAVQueuePlayer *weakSelf = self; _timeObserver = [self.audioPlayer addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.f, 1.f) queue:NULL usingBlock:^(CMTime time) { SMKAVQueuePlayer *strongSelf = weakSelf; diff --git a/Audio Players/SMKMPMusicPlayer.m b/Audio Players/SMKMPMusicPlayer.m index 031aa1c..a53ee20 100644 --- a/Audio Players/SMKMPMusicPlayer.m +++ b/Audio Players/SMKMPMusicPlayer.m @@ -8,6 +8,8 @@ #import "SMKMPMusicPlayer.h" #import "SMKMPMediaTrack.h" + +#import "SMKErrorCodes.h" #import "NSError+SMKAdditions.h" @interface SMKMPMusicPlayer () @@ -29,6 +31,7 @@ - (id)init [self.audioPlayer beginGeneratingPlaybackNotifications]; self.audioPlayer.repeatMode = MPMusicRepeatModeNone; self.audioPlayer.shuffleMode = MPMusicShuffleModeOff; + self.seekTimeInterval = SMKPlayerDefaultSeekTimeInterval; } return self; } diff --git a/Audio Players/SMKSpotifyPlayer.m b/Audio Players/SMKSpotifyPlayer.m index 6e13ed6..2b8a55e 100644 --- a/Audio Players/SMKSpotifyPlayer.m +++ b/Audio Players/SMKSpotifyPlayer.m @@ -43,6 +43,9 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N if (self.finishedTrackBlock) self.finishedTrackBlock(self, self.oldCurrentTrack, nil); self.oldCurrentTrack = nil; + if (self.preloadedTrack) { + [self skipToPreloadedTrack]; + } } else { self.preloadedTrack = nil; } @@ -124,7 +127,8 @@ - (void)preloadTrack:(id)track completionHandler:(void(^)(NSError *err - (void)skipToPreloadedTrack { - [self playTrack:self.preloadedTrack completionHandler:nil]; + if (self.preloadedTrack) + [self playTrack:self.preloadedTrack completionHandler:nil]; } #pragma mark - Accessors diff --git a/Common Headers/SMKErrorCodes.h b/Common Headers/SMKErrorCodes.h index 57f395d..e3a3da8 100644 --- a/Common Headers/SMKErrorCodes.h +++ b/Common Headers/SMKErrorCodes.h @@ -9,7 +9,6 @@ extern NSInteger const SMKPlayerErrorFailedToCreateInputSource; extern NSInteger const SMKPlayerErrorFailedToCreateDecoder; extern NSInteger const SMKPlayerErrorFailedToEnqueueTrack; -extern NSInteger const SMKPlayerErrorTrackAlreadyPreloaded; extern NSInteger const SMKPlayerErrorItemAlreadyExists; extern NSInteger const SMKCoreDataErrorDataStoreNotAFolder; diff --git a/Common Headers/SMKErrorCodes.m b/Common Headers/SMKErrorCodes.m index 5ef7103..78730cb 100644 --- a/Common Headers/SMKErrorCodes.m +++ b/Common Headers/SMKErrorCodes.m @@ -11,6 +11,7 @@ NSInteger const SMKPlayerErrorFailedToCreateInputSource = 0; NSInteger const SMKPlayerErrorFailedToCreateDecoder = 1; NSInteger const SMKPlayerErrorItemAlreadyExists = 2; +NSInteger const SMKPlayerErrorFailedToEnqueueTrack = 3; NSInteger const SMKCoreDataErrorDataStoreNotAFolder = 4; NSInteger const SMKCoreDataErrorFailedToInitializeStore = 5; \ No newline at end of file diff --git a/Content Sources/MPMediaLibrary/Data Model/SMKMPMediaTrack.m b/Content Sources/MPMediaLibrary/Data Model/SMKMPMediaTrack.m index cc5cd3f..27501f5 100644 --- a/Content Sources/MPMediaLibrary/Data Model/SMKMPMediaTrack.m +++ b/Content Sources/MPMediaLibrary/Data Model/SMKMPMediaTrack.m @@ -9,6 +9,8 @@ #import "SMKMPMediaTrack.h" #import "SMKMPMediaAlbum.h" #import "SMKMPMediaHelpers.h" +#import "SMKAVQueuePlayer.h" +#import "SMKMPMusicPlayer.h" @interface SMKMPMediaAlbum (SMKInternal) - (id)initWithRepresentedObject:(MPMediaItem*)object contentSource:(id)contentSource; @@ -44,7 +46,7 @@ + (NSSet *)supportedSortKeys - (Class)playerClass { - return NSClassFromString((self.playbackURL != nil) ? @"SMKAVQueuePlayer" : @"SMKMPMusicPlayer"); + return (self.playbackURL != nil) ? [SMKAVQueuePlayer class] : [SMKMPMusicPlayer class]; } #pragma mark - SMKTrack diff --git a/Example Apps/MPMediaLibraryExample/DetailViewController.h b/Example Apps/MPMediaLibraryExample/DetailViewController.h index e0a30d4..8d8ce72 100644 --- a/Example Apps/MPMediaLibraryExample/DetailViewController.h +++ b/Example Apps/MPMediaLibraryExample/DetailViewController.h @@ -13,4 +13,5 @@ @property (strong, nonatomic) id detailItem; @property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel; +- (IBAction)seekForward:(id)sender; @end diff --git a/Example Apps/MPMediaLibraryExample/DetailViewController.m b/Example Apps/MPMediaLibraryExample/DetailViewController.m index e5ce982..eaca82e 100644 --- a/Example Apps/MPMediaLibraryExample/DetailViewController.m +++ b/Example Apps/MPMediaLibraryExample/DetailViewController.m @@ -10,6 +10,7 @@ #import "SNRMusicKitiOS.h" #import "SMKMPMediaContentSource.h" #import "SMKMPMusicPlayer.h" +#import "SMKQueueController.h" @interface DetailViewController () @property (strong, nonatomic) UIPopoverController *masterPopoverController; @@ -18,7 +19,7 @@ - (void)configureView; @end @implementation DetailViewController { - SMKMPMusicPlayer *_player; + SMKQueueController *_controller; } #pragma mark - Managing the detail item @@ -42,7 +43,6 @@ - (void)configureView strongSelf.tracks = tracks; [self.tableView reloadData]; }]; - _player = [SMKMPMusicPlayer new]; } - (void)viewDidLoad @@ -74,11 +74,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - SMKMPMediaTrack *object = self.tracks[indexPath.row]; - NSLog(@"%@", [object playbackURL]); - [_player playTrack:object completionHandler:^(NSError *error) { - NSLog(@"%@", error); - }]; + NSArray *array = [self.tracks subarrayWithRange:NSMakeRange(indexPath.row, [self.tracks count] - indexPath.row)]; + NSLog(@"%@", array); + _controller = [SMKQueueController queueControllerWithTracks:array]; + [_controller play:nil]; } #pragma mark - Split view @@ -97,4 +96,9 @@ - (void)splitViewController:(UISplitViewController *)splitController willShowVie self.masterPopoverController = nil; } +- (IBAction)seekForward:(id)sender +{ + [_controller seekForward:nil]; +} + @end diff --git a/Example Apps/MPMediaLibraryExample/en.lproj/MainStoryboard_iPad.storyboard b/Example Apps/MPMediaLibraryExample/en.lproj/MainStoryboard_iPad.storyboard index 7c3fda4..d5e9db0 100644 --- a/Example Apps/MPMediaLibraryExample/en.lproj/MainStoryboard_iPad.storyboard +++ b/Example Apps/MPMediaLibraryExample/en.lproj/MainStoryboard_iPad.storyboard @@ -56,7 +56,13 @@ - + + + + + + + @@ -143,6 +149,7 @@ + diff --git a/Master API/SMKQueueController.m b/Master API/SMKQueueController.m index 3fa420a..4e9f51a 100644 --- a/Master API/SMKQueueController.m +++ b/Master API/SMKQueueController.m @@ -15,10 +15,10 @@ @interface SMKQueueItem : NSObject @interface SMKQueueController () @property (nonatomic, strong) NSMutableArray *items; @property (nonatomic, strong, readwrite) id currentPlayer; +@property (nonatomic, assign, readwrite) NSUInteger indexOfCurrentTrack; @end @implementation SMKQueueController - - (id)init { if ((self = [super init])) { @@ -73,16 +73,6 @@ - (void)removeTrack:(id)track #pragma mark - Accessors -- (NSUInteger)indexOfCurrentTrack -{ - return [self.items indexOfObject:self.currentTrack]; -} - -+ (NSSet *)keyPathsForValuesAffectingIndexOfCurrentTrack -{ - return [NSSet setWithObject:@"currentTrack"]; -} - - (NSTimeInterval)playbackTime { return [self.currentPlayer playbackTime]; @@ -177,7 +167,15 @@ - (IBAction)playPause:(id)sender - (IBAction)next:(id)sender { - + if ([[self.currentPlayer class] supportsPreloading] && [self.currentPlayer preloadedTrack]) { + [self.currentPlayer skipToPreloadedTrack]; + self.indexOfCurrentTrack++; + } else { + NSUInteger nextIndex = self.indexOfCurrentTrack + 1; + if (nextIndex < [self countOfItems]) + [self _beginPlayingItemAtIndex:nextIndex]; + } + [self _recalculateIndexOfCurrentTrack]; } - (IBAction)previous:(id)sender @@ -187,12 +185,12 @@ - (IBAction)previous:(id)sender - (IBAction)seekForward:(id)sender { - + [self.currentPlayer seekForward]; } - (IBAction)seekBackward:(id)sender { - + [self.currentPlayer seekBackward]; } #pragma mark - Private @@ -223,17 +221,33 @@ - (NSUInteger)_indexOfTrack:(id)track - (void)_beginPlayingItemAtIndex:(NSUInteger)index { id track = [[self.items objectAtIndex:index] track]; - self.currentPlayer = [[track playerClass] new]; + id player = [[track playerClass] new]; + NSLog(@"now playing %@ with %@", [track name], player); + self.currentPlayer = player; __weak SMKQueueController *weakSelf = self; - [self.currentPlayer playTrack:track completionHandler:^(NSError *error) { + [player playTrack:track completionHandler:^(NSError *error) { + SMKQueueController *strongSelf = weakSelf; if (error) { - SMKQueueController *strongSelf = weakSelf; SMKGenericErrorLog([NSString stringWithFormat:@"Error playing track %@", track], error); [strongSelf removeObjectFromItemsAtIndex:index]; strongSelf.currentPlayer = nil; - if (index < [self.items count]) - [self _beginPlayingItemAtIndex:index]; + if (index < [strongSelf countOfItems]) + [strongSelf _beginPlayingItemAtIndex:index]; + } else { + [strongSelf _recalculateIndexOfCurrentTrack]; } }]; + [player setFinishedTrackBlock:^(id player, id track, NSError *error) { + SMKQueueController *strongSelf = weakSelf; + [strongSelf next:nil]; + }]; } + +- (void)_recalculateIndexOfCurrentTrack +{ + self.indexOfCurrentTrack = [self _indexOfTrack:self.currentTrack]; +} +@end + +@implementation SMKQueueItem @end diff --git a/SNRMusicKit.xcodeproj/project.pbxproj b/SNRMusicKit.xcodeproj/project.pbxproj index e0a3b7f..c18e0df 100644 --- a/SNRMusicKit.xcodeproj/project.pbxproj +++ b/SNRMusicKit.xcodeproj/project.pbxproj @@ -118,6 +118,8 @@ 036994CF15E3F3EB003BCCBE /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 036994A615E3F3EB003BCCBE /* UIImageView+AFNetworking.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 036994D015E3F461003BCCBE /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 036991F615E3EAE1003BCCBE /* CoreData.framework */; }; 036994D215E3F475003BCCBE /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 036994D115E3F475003BCCBE /* CoreData.framework */; }; + 036F857515EEC45100DF72B9 /* SMKQueueController.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0371CF9915EDECF200B304CC /* SMKQueueController.h */; }; + 036F857615EEC54500DF72B9 /* SMKAVQueuePlayer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 03FBEC9D15E6E0C100A67DEE /* SMKAVQueuePlayer.h */; }; 0370109C15E5535500FEAF6F /* SMKiTunesSyncOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0370109A15E5535500FEAF6F /* SMKiTunesSyncOperation.h */; }; 0370109D15E5535500FEAF6F /* SMKiTunesSyncOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0370109B15E5535500FEAF6F /* SMKiTunesSyncOperation.m */; }; 037010A015E5630000FEAF6F /* SMKiTunesConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 0370109E15E5630000FEAF6F /* SMKiTunesConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -403,6 +405,8 @@ 0306DB6B15EC199800D6409B /* SMKMPMediaTrack.h in CopyFiles */, 0371CF9515EDE47700B304CC /* SMKMPMediaAlbum.h in CopyFiles */, 0371CF9315EDE44C00B304CC /* SMKMPMusicPlayer.h in CopyFiles */, + 036F857515EEC45100DF72B9 /* SMKQueueController.h in CopyFiles */, + 036F857615EEC54500DF72B9 /* SMKAVQueuePlayer.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SNRMusicKit.xcodeproj/project.xcworkspace/xcuserdata/indragie.xcuserdatad/UserInterfaceState.xcuserstate b/SNRMusicKit.xcodeproj/project.xcworkspace/xcuserdata/indragie.xcuserdatad/UserInterfaceState.xcuserstate index 3afcc37..d325ed6 100644 Binary files a/SNRMusicKit.xcodeproj/project.xcworkspace/xcuserdata/indragie.xcuserdatad/UserInterfaceState.xcuserstate and b/SNRMusicKit.xcodeproj/project.xcworkspace/xcuserdata/indragie.xcuserdatad/UserInterfaceState.xcuserstate differ