From 09777d4554b9011860684640336fff8bd67c63a0 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Wed, 13 Nov 2019 19:13:59 -0800 Subject: [PATCH] Implemented support for MediaPlayer framework, which fixes media key support on newer systems, and also media info reporting --- Application/AppController.h | 3 ++ Application/AppController.m | 15 +++++++ Application/MediaKeysApplication.m | 42 +++++++++++++++---- Application/PlaybackController.h | 3 ++ Application/PlaybackController.m | 66 ++++++++++++++++++++++++++++++ Cog.xcodeproj/project.pbxproj | 5 +++ 6 files changed, 127 insertions(+), 7 deletions(-) diff --git a/Application/AppController.h b/Application/AppController.h index 50610e0dd..07aef37e2 100644 --- a/Application/AppController.h +++ b/Application/AppController.h @@ -92,9 +92,12 @@ OSStatus handleHotKey(EventHandlerCallRef nextHandler,EventRef theEvent,void *us - (void)clickPlay; +- (void)clickPause; +- (void)clickStop; - (void)clickPrev; - (void)clickNext; - (void)clickSpam; +- (void)clickSeek: (NSTimeInterval)position; - (IBAction)increaseFontSize:(id)sender; - (IBAction)decreaseFontSize:(id)sender; diff --git a/Application/AppController.m b/Application/AppController.m index ac5121ea4..a642fc0af 100644 --- a/Application/AppController.m +++ b/Application/AppController.m @@ -521,6 +521,16 @@ [playbackController playPauseResume:self]; } +- (void)clickPause +{ + [playbackController pause:self]; +} + +- (void)clickStop +{ + [playbackController stop:self]; +} + - (void)clickPrev { [playbackController prev:nil]; @@ -536,6 +546,11 @@ [playbackController spam]; } +- (void)clickSeek:(NSTimeInterval)position +{ + [playbackController seek:self toTime:position]; +} + - (void)changeFontSize:(float)size { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; diff --git a/Application/MediaKeysApplication.m b/Application/MediaKeysApplication.m index 03ef8ff9a..c61cbb185 100644 --- a/Application/MediaKeysApplication.m +++ b/Application/MediaKeysApplication.m @@ -11,6 +11,12 @@ #import "SPMediaKeyTap.h" #import "Logging.h" +#import +#import +#import +#import +#import + @implementation MediaKeysApplication +(void)initialize; @@ -25,18 +31,40 @@ - (void)finishLaunching { [super finishLaunching]; - + [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"allowLastfmMediaKeys" options:NSKeyValueObservingOptionNew context:nil]; - - keyTap = [[SPMediaKeyTap alloc] initWithDelegate:self]; - if([SPMediaKeyTap usesGlobalMediaKeyTap]) { - [keyTap startWatchingMediaKeys]; + + MPRemoteCommandCenter *remoteCommandCenter = [MPRemoteCommandCenter sharedCommandCenter]; + + if (remoteCommandCenter) { + [remoteCommandCenter.playCommand setEnabled:YES]; + [remoteCommandCenter.pauseCommand setEnabled:YES]; + [remoteCommandCenter.togglePlayPauseCommand setEnabled:YES]; + [remoteCommandCenter.changePlaybackPositionCommand setEnabled:YES]; + [remoteCommandCenter.nextTrackCommand setEnabled:YES]; + [remoteCommandCenter.previousTrackCommand setEnabled:YES]; + + [[remoteCommandCenter playCommand] addTarget:[self delegate] action:@selector(clickPlay)]; + [[remoteCommandCenter pauseCommand] addTarget:[self delegate] action:@selector(clickPause)]; + [[remoteCommandCenter togglePlayPauseCommand] addTarget:[self delegate] action:@selector(clickPlay)]; + [[remoteCommandCenter changePlaybackPositionCommand] addTarget:self action:@selector(clickSeek:)]; + [[remoteCommandCenter nextTrackCommand] addTarget:[self delegate] action:@selector(clickNext)]; + [[remoteCommandCenter previousTrackCommand] addTarget:[self delegate] action:@selector(clickPrev)]; + } else { + keyTap = [[SPMediaKeyTap alloc] initWithDelegate:self]; + if([SPMediaKeyTap usesGlobalMediaKeyTap]) { + [keyTap startWatchingMediaKeys]; + } + else + ALog(@"Media key monitoring disabled"); } - else - ALog(@"Media key monitoring disabled"); +} + +- (void)clickSeek: (MPChangePlaybackPositionCommandEvent*)event { + [(AppController *)[self delegate] clickSeek:event.positionTime]; } - (void)sendEvent: (NSEvent*)event diff --git a/Application/PlaybackController.h b/Application/PlaybackController.h index 6ad2615f7..814cc8f65 100644 --- a/Application/PlaybackController.h +++ b/Application/PlaybackController.h @@ -59,6 +59,7 @@ extern NSDictionary * makeRGInfo(PlaylistEntry *pe); - (IBAction)next:(id)sender; - (IBAction)prev:(id)sender; - (IBAction)seek:(id)sender; +- (IBAction)seek:(id)sender toTime:(NSTimeInterval)time; - (IBAction)eventSeekForward:(id)sender; - (void)seekForward:(double)sender; - (IBAction)eventSeekBackward:(id)sender; @@ -67,6 +68,8 @@ extern NSDictionary * makeRGInfo(PlaylistEntry *pe); - (IBAction)spam; +- (void)sendMetaData; + - (void)initDefaults; - (void)audioFadeDown:(NSTimer *)audioTimer; - (void)audioFadeUp:(NSTimer *)audioTimer; diff --git a/Application/PlaybackController.m b/Application/PlaybackController.m index aed733205..7a8f39802 100644 --- a/Application/PlaybackController.m +++ b/Application/PlaybackController.m @@ -8,6 +8,12 @@ #import "PlaylistEntry.h" #import "PlaylistLoader.h" +#import +#import +#import +#import +#import + #import "Logging.h" @implementation PlaybackController @@ -75,6 +81,8 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation"; { [self pauseResume:self]; } + + [self sendMetaData]; } - (IBAction)pauseResume:(id)sender @@ -89,6 +97,8 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation"; { [audioPlayer pause]; [self setPlaybackStatus: kCogStatusPaused]; + + [self sendMetaData]; } - (IBAction)resume:(id)sender @@ -100,6 +110,8 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation"; - (IBAction)stop:(id)sender { [audioPlayer stop]; + + [self sendMetaData]; } //called by double-clicking on table @@ -177,6 +189,8 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) [playlistLoader performSelectorInBackground:@selector(loadInfoForEntries:) withObject:entries]; } #endif + + [self sendMetaData]; [audioPlayer play:[pe URL] withUserInfo:pe withRGInfo:makeRGInfo(pe) startPaused:paused]; } @@ -204,6 +218,8 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) [self setPosition:pos]; [[playlistController currentEntry] setCurrentPosition:pos]; + + [self sendMetaData]; } - (IBAction)seek:(id)sender @@ -215,6 +231,19 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) [self setPosition:time]; [[playlistController currentEntry] setCurrentPosition:time]; + + [self sendMetaData]; +} + +- (IBAction)seek:(id)sender toTime:(NSTimeInterval)position +{ + double time = (double)(position); + + [audioPlayer seekToTime:time]; + + [self setPosition:time]; + + [[playlistController currentEntry] setCurrentPosition:time]; } - (IBAction)spam @@ -244,6 +273,8 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) [audioPlayer seekToTime:seekTo]; [self setPosition:seekTo]; } + + [self sendMetaData]; } - (IBAction)eventSeekBackward:(id)sender @@ -260,6 +291,8 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) [audioPlayer seekToTime:seekTo]; [self setPosition:seekTo]; + + [self sendMetaData]; } /* @@ -588,5 +621,38 @@ NSDictionary * makeRGInfo(PlaylistEntry *pe) return seekable && [[playlistController currentEntry] seekable]; } +- (void)sendMetaData { + MPNowPlayingInfoCenter * defaultCenter = [MPNowPlayingInfoCenter defaultCenter]; + + if (defaultCenter) { + PlaylistEntry * entry = [playlistController currentEntry]; + NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init]; + + if (entry) { + if ([entry title]) + [songInfo setObject:[entry title] forKey:MPMediaItemPropertyTitle]; + if ([entry artist]) + [songInfo setObject:[entry artist] forKey:MPMediaItemPropertyArtist]; + if ([entry album]) + [songInfo setObject:[entry album] forKey:MPMediaItemPropertyAlbumTitle]; + [songInfo setObject:[NSNumber numberWithFloat:[entry currentPosition]] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime]; + [songInfo setObject:[entry length] forKey:MPMediaItemPropertyPlaybackDuration]; + [songInfo setObject:[NSNumber numberWithFloat:[entry index]] forKey:MPMediaItemPropertyPersistentID]; + } + + if (playbackStatus == kCogStatusPlaying) { + [MPNowPlayingInfoCenter defaultCenter].playbackState = MPNowPlayingPlaybackStatePlaying; + } else if (playbackStatus == kCogStatusPaused) { + [MPNowPlayingInfoCenter defaultCenter].playbackState = MPNowPlayingPlaybackStatePaused; + } else { + [MPNowPlayingInfoCenter defaultCenter].playbackState = MPNowPlayingPlaybackStateStopped; + } + + [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo]; + } +} + + + @end diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 4bcda0c7f..b645958b4 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -174,6 +174,7 @@ 838491881808593200E7332D /* NDHotKey.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8384917E1808585D00E7332D /* NDHotKey.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8399D4E21805A55000B503B1 /* XmlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399D4E01805A55000B503B1 /* XmlContainer.m */; }; 83A360B220E4E81D00192DAB /* Flac.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8303A30C20E4E3D000951EF8 /* Flac.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 83AB903E237CEFD300A433D5 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83AB9031237CEFD300A433D5 /* MediaPlayer.framework */; }; 83B06704180D579E008E3612 /* MIDI.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83B066A1180D5669008E3612 /* MIDI.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 83BC5AB220E4C87100631CD4 /* DualWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BC5AB020E4C87100631CD4 /* DualWindow.m */; }; 83BC5ABF20E4CE7A00631CD4 /* InfoInspector.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B0D00F6320EA00694C57 /* InfoInspector.xib */; }; @@ -1006,6 +1007,7 @@ 83859520234FEB35004E9946 /* Cog.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Cog.entitlements; sourceTree = ""; }; 8399D4E01805A55000B503B1 /* XmlContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XmlContainer.m; sourceTree = ""; }; 8399D4E11805A55000B503B1 /* XmlContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XmlContainer.h; sourceTree = ""; }; + 83AB9031237CEFD300A433D5 /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 83B0669C180D5668008E3612 /* MIDI.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MIDI.xcodeproj; path = Plugins/MIDI/MIDI.xcodeproj; sourceTree = ""; }; 83BC5AB020E4C87100631CD4 /* DualWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DualWindow.m; path = Window/DualWindow.m; sourceTree = ""; }; 83BC5AB120E4C87100631CD4 /* DualWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DualWindow.h; path = Window/DualWindow.h; sourceTree = ""; }; @@ -1069,6 +1071,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 83AB903E237CEFD300A433D5 /* MediaPlayer.framework in Frameworks */, 83E6B7651816178200D4576D /* Sparkle.framework in Frameworks */, 838491871808591F00E7332D /* NDHotKey.framework in Frameworks */, 8355D6B8180613FB00D05687 /* Security.framework in Frameworks */, @@ -1558,6 +1561,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 83AB9031237CEFD300A433D5 /* MediaPlayer.framework */, 8355D6B7180613FB00D05687 /* Security.framework */, 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, @@ -1959,6 +1963,7 @@ LastUpgradeCheck = 1100; TargetAttributes = { 8D1107260486CEB800E47090 = { + DevelopmentTeam = 4S876G9VCD; ProvisioningStyle = Automatic; }; };