diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a3c9643..cd226a7d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -369,6 +369,7 @@ if(APPLE) PRIVATE "-framework OpenGL" PRIVATE "-framework OpenCL" PRIVATE "-framework Cocoa" + PRIVATE "-weak_framework MediaRemote -F /System/Library/PrivateFrameworks" ) endif() diff --git a/src/detection/media/media_apple.m b/src/detection/media/media_apple.m index 99f43ca49..4c4da1b54 100644 --- a/src/detection/media/media_apple.m +++ b/src/detection/media/media_apple.m @@ -2,27 +2,58 @@ #include "detection/media/media.h" #include "common/library.h" #include "util/apple/cf_helpers.h" +#include "util/apple/osascript.h" #import #import -void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)); +extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import)); +extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import)); +extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import)); +extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import)); static const char* getMedia(FFMediaResult* result) { - FF_LIBRARY_LOAD(MediaRemote, NULL, "dlopen MediaRemote failed", "/System/Library/PrivateFrameworks/MediaRemote.framework/MediaRemote", -1); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(MediaRemote, MRMediaRemoteGetNowPlayingInfo); + #define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available" + FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo); + FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient); + FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier); + FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier); + #undef FF_TEST_FN_EXISTANCE - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - ffMRMediaRemoteGetNowPlayingInfo(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(_Nullable CFDictionaryRef info) { + dispatch_group_t group = dispatch_group_create(); + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); + + dispatch_group_enter(group); + MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) { if(info != nil) { ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song); ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist); ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album); } - dispatch_semaphore_signal(semaphore); + dispatch_group_leave(group); }); - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + dispatch_group_enter(group); + MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) { + if (clientObj != nil) { + CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj); + if (identifier == nil) + identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj); + if (identifier != nil) + ffCfStrGetString(identifier, &result->busNameShort); + } + dispatch_group_leave(group); + }); + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + if(result->busNameShort.length > 0) + { + char buf[128]; + snprintf(buf, sizeof(buf), "name of app id \"%s\"", result->busNameShort.chars); + ffOsascript(buf, &result->player); + } if(result->song.length > 0) return NULL; @@ -35,9 +66,4 @@ void ffDetectMediaImpl(const FFinstance* instance, FFMediaResult* media) FF_UNUSED(instance) const char* error = getMedia(media); ffStrbufAppendS(&media->error, error); - - //TODO: proper detection - //I already set it here, because the player module expects it to be set if the error is not set - if(error == NULL) - ffStrbufAppendS(&media->player, "Media Player"); }