[vlc-commits] [Git][videolan/vlc][3.0.x] 3 commits: macosx: add support for the Touch Bar in current MacBooks

Jean-Baptiste Kempf gitlab at videolan.org
Tue Jun 15 14:07:06 UTC 2021



Jean-Baptiste Kempf pushed to branch 3.0.x at VideoLAN / VLC


Commits:
b5b55004 by Felix Paul Kühne at 2021-06-15T12:24:09+00:00
macosx: add support for the Touch Bar in current MacBooks

This implements playback control via touch bar and the activity widgets.
It also exposes related playback meta data. It is a manual backport of
the respective code on the master branch and fixes #25744.

- - - - -
8fd31abc by Felix Paul Kühne at 2021-06-15T12:24:09+00:00
macosx: do not try to seek unseekable content

Previously, external apps such as the Touchbar and AppleScript bindings
could attempt to seek non-seekable content leading to persistent silence
until playback was restarted.

- - - - -
d9de9c3e by Felix Paul Kühne at 2021-06-15T12:24:09+00:00
macosx: disable SPMediaKeyTap on macOS Sierra and later

On later releases, we will use the public API.

- - - - -


8 changed files:

- extras/package/macosx/vlc.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- modules/gui/macosx/VLCCoreInteraction.h
- modules/gui/macosx/VLCCoreInteraction.m
- modules/gui/macosx/VLCInputManager.h
- modules/gui/macosx/VLCInputManager.m
- + modules/gui/macosx/VLCRemoteControlService.h
- + modules/gui/macosx/VLCRemoteControlService.m


Changes:

=====================================
extras/package/macosx/vlc.xcodeproj/project.pbxproj
=====================================
@@ -106,6 +106,7 @@
 		6BF5C5011EFE03CF008A9C12 /* VLCHUDStepperCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF5C5001EFE03CF008A9C12 /* VLCHUDStepperCell.m */; };
 		6BF5C5041EFE66EF008A9C12 /* VLCHUDTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF5C5031EFE66EF008A9C12 /* VLCHUDTableView.m */; };
 		6BF5C5071EFE7E58008A9C12 /* VLCTintedImageButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BF5C5061EFE7E58008A9C12 /* VLCTintedImageButtonCell.m */; };
+		7D51CC072675FEF100EE18C2 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D51CC062675FEF100EE18C2 /* VLCRemoteControlService.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -681,6 +682,8 @@
 		6BF5C5031EFE66EF008A9C12 /* VLCHUDTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCHUDTableView.m; sourceTree = "<group>"; };
 		6BF5C5051EFE7E58008A9C12 /* VLCTintedImageButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCTintedImageButtonCell.h; sourceTree = "<group>"; };
 		6BF5C5061EFE7E58008A9C12 /* VLCTintedImageButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCTintedImageButtonCell.m; sourceTree = "<group>"; };
+		7D51CC052675FEF100EE18C2 /* VLCRemoteControlService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCRemoteControlService.h; sourceTree = "<group>"; };
+		7D51CC062675FEF100EE18C2 /* VLCRemoteControlService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCRemoteControlService.m; sourceTree = "<group>"; };
 		7D5678EB1D5BA1DC002698F3 /* VLCApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCApplication.h; sourceTree = "<group>"; };
 		7D5678EC1D5BA1DC002698F3 /* VLCApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCApplication.m; sourceTree = "<group>"; };
 		7D5678EE1D5BA397002698F3 /* VLCMainWindowControlsBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCMainWindowControlsBar.h; sourceTree = "<group>"; };
@@ -931,6 +934,8 @@
 				7DF812F41B5599E40052293C /* VLCPLModel.m */,
 				1C7CB91A1D787E7600388902 /* VLCPopupPanelController.h */,
 				1C7CB91B1D787E7600388902 /* VLCPopupPanelController.m */,
+				7D51CC052675FEF100EE18C2 /* VLCRemoteControlService.h */,
+				7D51CC062675FEF100EE18C2 /* VLCRemoteControlService.m */,
 				633121CA1B51122700E636DA /* VLCResumeDialogController.h */,
 				633121CB1B51122700E636DA /* VLCResumeDialogController.m */,
 				6B13E2A61BC67678001AD24A /* VLCScrollingClipView.h */,
@@ -1822,6 +1827,7 @@
 				1C3113A71E508C6900D4DD76 /* VLCLogWindowController.m in Sources */,
 				6BF5C5071EFE7E58008A9C12 /* VLCTintedImageButtonCell.m in Sources */,
 				1C3113A91E508C6900D4DD76 /* VLCDocumentController.m in Sources */,
+				7D51CC072675FEF100EE18C2 /* VLCRemoteControlService.m in Sources */,
 				1C3113AB1E508C6900D4DD76 /* VLCExtensionsDialogProvider.m in Sources */,
 				1C3113AD1E508C6900D4DD76 /* VLCExtensionsManager.m in Sources */,
 				1C3113AF1E508C6900D4DD76 /* VLCFSPanelController.m in Sources */,


=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -6,7 +6,7 @@ libmacosx_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(guidir)' \
 	-Wl,-framework,AVFoundation -Wl,-framework,CoreMedia -Wl,-framework,IOKit \
 	-Wl,-framework,AddressBook -Wl,-framework,WebKit -Wl,-framework,CoreAudio \
 	-Wl,-framework,SystemConfiguration -Wl,-framework,ScriptingBridge \
-	-Wl,-framework,QuartzCore
+	-Wl,-framework,QuartzCore -Wl,-weak_framework,MediaPlayer
 
 if HAVE_SPARKLE
 libmacosx_plugin_la_LDFLAGS += -Wl,-framework,Sparkle
@@ -106,7 +106,8 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/VLCSliderCell.h gui/macosx/VLCSliderCell.m \
 	gui/macosx/VLCVolumeSlider.h gui/macosx/VLCVolumeSlider.m \
 	gui/macosx/VLCVolumeSliderCell.h gui/macosx/VLCVolumeSliderCell.m \
-	gui/macosx/VLCWrappableTextField.h gui/macosx/VLCWrappableTextField.m
+	gui/macosx/VLCWrappableTextField.h gui/macosx/VLCWrappableTextField.m \
+	gui/macosx/VLCRemoteControlService.h gui/macosx/VLCRemoteControlService.m
 
 # PXSourceList sources
 libmacosx_plugin_la_SOURCES += \


=====================================
modules/gui/macosx/VLCCoreInteraction.h
=====================================
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * CoreInteraction.h: MacOS X interface module
  *****************************************************************************
- * Copyright (C) 2011-2015 Felix Paul Kühne
+ * Copyright (C) 2011-2021 Felix Paul Kühne
  * $Id$
  *
  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
@@ -30,13 +30,17 @@
 @property (readwrite) int volume;
 @property (readonly, nonatomic) float maxVolume;
 @property (readwrite) int playbackRate;
+ at property (readonly) float internalPlaybackRate;
 @property (nonatomic, readwrite) BOOL aspectRatioIsLocked;
 @property (readonly) int durationOfCurrentPlaylistItem;
 @property (readonly) NSURL * URLOfCurrentPlaylistItem;
 @property (readonly) NSString * nameOfCurrentPlaylistItem;
 @property (nonatomic, readwrite) BOOL mute;
+ at property (readonly) float currentPlaybackPosition;
+ at property (readonly) long long currentPlaybackTimeInSeconds;
 
 - (void)playOrPause;
+- (void)play;
 - (void)pause;
 - (void)stop;
 - (void)faster;
@@ -55,6 +59,7 @@
 - (void)backwardMedium;
 - (void)forwardLong;
 - (void)backwardLong;
+- (BOOL)seekToTime:(mtime_t)time;
 
 - (void)repeatOne;
 - (void)repeatAll;


=====================================
modules/gui/macosx/VLCCoreInteraction.m
=====================================
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * CoreInteraction.m: MacOS X interface module
  *****************************************************************************
- * Copyright (C) 2011-2015 Felix Paul Kühne
+ * Copyright (C) 2011-2021 Felix Paul Kühne
  * $Id$
  *
  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
@@ -40,6 +40,7 @@
 #import "SPMediaKeyTap.h"
 #import "AppleRemote.h"
 #import "VLCInputManager.h"
+#import "CompatibilityFixes.h"
 
 #import "NSSound+VLCAdditions.h"
 
@@ -98,15 +99,18 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
     if (self) {
         intf_thread_t *p_intf = getIntf();
 
-        /* init media key support */
-        b_mediaKeySupport = var_InheritBool(p_intf, "macosx-mediakeys");
-        if (b_mediaKeySupport) {
-            _mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
+        /* init media key support on earlier macOS versions
+         * this feature is covered by VLCRemoteControlService in later releases */
+        if (!OSX_SIERRA_AND_HIGHER) {
+            b_mediaKeySupport = var_InheritBool(p_intf, "macosx-mediakeys");
+            if (b_mediaKeySupport) {
+                _mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
+            }
+            [[NSNotificationCenter defaultCenter] addObserver:self
+                                                     selector:@selector(coreChangedMediaKeySupportSetting:)
+                                                         name:VLCMediaKeySupportSettingChangedNotification
+                                                       object:nil];
         }
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(coreChangedMediaKeySupportSetting:)
-                                                     name:VLCMediaKeySupportSettingChangedNotification
-                                                   object:nil];
 
         /* init Apple Remote support */
         _remote = [[AppleRemote alloc] init];
@@ -128,6 +132,12 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
 
 #pragma mark - Playback Controls
 
+- (void)play
+{
+    playlist_t *p_playlist = pl_Get(getIntf());
+    playlist_Play(p_playlist);
+}
+
 - (void)playOrPause
 {
     input_thread_t *p_input = pl_CurrentInput(getIntf());
@@ -230,6 +240,19 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
     return returnValue;
 }
 
+- (float)internalPlaybackRate
+{
+    input_thread_t *p_input_thread = pl_CurrentInput(getIntf());
+    float rate = 0.;
+
+    if (p_input_thread) {
+        rate = var_GetFloat(p_input_thread, "rate");
+        vlc_object_release(p_input_thread);
+    }
+
+    return rate;
+}
+
 - (void)previous
 {
     playlist_Prev(pl_Get(getIntf()));
@@ -331,6 +354,33 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
     return o_name;
 }
 
+- (long long)currentPlaybackTimeInSeconds
+{
+    input_thread_t *p_input_thread = pl_CurrentInput(getIntf());
+    long long timeInSeconds = 0;
+
+    if (p_input_thread) {
+        int64_t time = var_GetInteger(p_input_thread, "time");
+        timeInSeconds = time / CLOCK_FREQ;
+        vlc_object_release(p_input_thread);
+    }
+
+    return timeInSeconds;
+}
+
+- (float)currentPlaybackPosition
+{
+    input_thread_t * p_input_thread = pl_CurrentInput(getIntf());
+    float position = 0.;
+
+    if (p_input_thread) {
+        position = var_GetFloat(p_input_thread, "position");
+        vlc_object_release(p_input_thread);
+    }
+
+    return position;
+}
+
 - (void)forward
 {
     //LEGACY SUPPORT
@@ -349,12 +399,15 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
     if (!p_input)
         return;
 
-    int i_interval = var_InheritInteger( p_input, p_value );
-    if (i_interval > 0) {
-        mtime_t val = CLOCK_FREQ * i_interval;
-        if (!b_value)
-            val = val * -1;
-        var_SetInteger( p_input, "time-offset", val );
+    bool b_seekable = var_GetBool(p_input, "can-seek");
+    if (b_seekable) {
+        long long i_interval = var_InheritInteger( p_input, p_value );
+        if (i_interval > 0) {
+            mtime_t val = CLOCK_FREQ * i_interval;
+            if (!b_value)
+                val = val * -1;
+            var_SetInteger( p_input, "time-offset", val );
+        }
     }
     vlc_object_release(p_input);
 }
@@ -399,6 +452,21 @@ static int BossCallback(vlc_object_t *p_this, const char *psz_var,
     [self jumpWithValue:"long-jump-size" forward:NO];
 }
 
+- (BOOL)seekToTime:(mtime_t)time
+{
+    input_thread_t * p_input_thread = pl_CurrentInput(getIntf());
+    if (p_input_thread) {
+        bool b_seekable = var_GetBool(p_input_thread, "can-seek");
+        if (b_seekable) {
+            var_SetInteger(p_input_thread, "time", time);
+            vlc_object_release(p_input_thread);
+            return YES;
+        }
+        vlc_object_release(p_input_thread);
+    }
+    return NO;
+}
+
 - (void)shuffle
 {
     intf_thread_t *p_intf = getIntf();


=====================================
modules/gui/macosx/VLCInputManager.h
=====================================
@@ -26,9 +26,10 @@
 
 #import <IOKit/pwr_mgt/IOPMLib.h>           /* for sleep prevention */
 
-
 @class VLCMain;
 
+extern NSString *VLCPlayerRateChanged;
+
 @interface VLCInputManager : NSObject
 
 - (id)initWithMain:(VLCMain *)o_mainObj;


=====================================
modules/gui/macosx/VLCInputManager.m
=====================================
@@ -34,10 +34,13 @@
 #import "VLCResumeDialogController.h"
 #import "VLCTrackSynchronizationWindowController.h"
 #import "VLCVoutView.h"
+#import "VLCRemoteControlService.h"
 
 #import "iTunes.h"
 #import "Spotify.h"
 
+NSString *VLCPlayerRateChanged = @"VLCPlayerRateChanged";
+
 @interface VLCInputManager()
 - (void)updateMainMenu;
 - (void)updateMainWindow;
@@ -72,6 +75,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
                 break;
             case INPUT_EVENT_RATE:
                 [[[VLCMain sharedInstance] mainMenu] performSelectorOnMainThread:@selector(updatePlaybackRate) withObject: nil waitUntilDone:NO];
+                [[NSNotificationCenter defaultCenter] postNotificationName:VLCPlayerRateChanged object:nil];
                 break;
             case INPUT_EVENT_POSITION:
 
@@ -164,6 +168,8 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
     BOOL b_has_spotify_paused;
 
     NSTimer *hasEndedTimer;
+
+    VLCRemoteControlService *_remoteControlService;
 }
 @end
 
@@ -190,6 +196,10 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
 
         informInputChangedQueue = dispatch_queue_create("org.videolan.vlc.inputChangedQueue", DISPATCH_QUEUE_SERIAL);
 
+        if (@available(macOS 10.12.2, *)) {
+            _remoteControlService = [[VLCRemoteControlService alloc] init];
+            [_remoteControlService subscribeToRemoteCommands];
+        }
     }
     return self;
 }
@@ -213,6 +223,10 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
         p_current_input = NULL;
     }
 
+    if (@available(macOS 10.12.2, *)) {
+        [_remoteControlService unsubscribeFromRemoteCommands];
+    }
+
     var_DelCallback(pl_Get(getIntf()), "input-current", InputThreadChanged, (__bridge void *)self);
 
 #if !OS_OBJECT_USE_OBJC
@@ -281,6 +295,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
 {
     [[[VLCMain sharedInstance] mainWindow] updateTimeSlider];
     [[[VLCMain sharedInstance] statusBarIcon] updateProgress];
+    [_remoteControlService playbackPositionUpdated];
 }
 
 - (void)playbackStatusUpdated
@@ -338,6 +353,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
 
     [self updateMainWindow];
     [self sendDistributedNotificationWithUpdatedPlaybackStatus];
+    [_remoteControlService playbackStateChangedTo:state];
 }
 
 // Called when playback has ended and likely no subsequent media will start playing
@@ -514,6 +530,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
 {
     if (!p_current_input) {
         [[[VLCMain sharedInstance] currentMediaInfoPanel] updatePanelWithItem:nil];
+        [_remoteControlService metaDataChangedForCurrentMediaItem:NULL];
         return;
     }
 
@@ -521,6 +538,7 @@ static int InputEvent(vlc_object_t *p_this, const char *psz_var,
 
     [[[o_main playlist] model] updateItem:p_input_item];
     [[[VLCMain sharedInstance] currentMediaInfoPanel] updatePanelWithItem:p_input_item];
+    [_remoteControlService metaDataChangedForCurrentMediaItem:p_input_item];
 }
 
 - (void)updateMainWindow


=====================================
modules/gui/macosx/VLCRemoteControlService.h
=====================================
@@ -0,0 +1,36 @@
+/*****************************************************************************
+ * VLCRemoteControlService.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2017, 2018, 2021 VLC authors and VideoLAN
+ *
+ * Authors: Carola Nitz <nitz.carola # gmail.com>
+ *          Felix Paul Kühne <fkuehne # videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#include <vlc_common.h>
+
+ at interface VLCRemoteControlService : NSObject
+
+- (void)subscribeToRemoteCommands;
+- (void)unsubscribeFromRemoteCommands;
+
+- (void)playbackPositionUpdated;
+- (void)playbackStateChangedTo:(int)state;
+- (void)metaDataChangedForCurrentMediaItem:(input_item_t *)p_input_item;
+
+ at end


=====================================
modules/gui/macosx/VLCRemoteControlService.m
=====================================
@@ -0,0 +1,297 @@
+/*****************************************************************************
+ * VLCRemoteControlService.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2017-2021 VLC authors and VideoLAN
+ *
+ * Authors: Carola Nitz <nitz.carola # gmail.com>
+ *          Felix Paul Kühne <fkuehne # videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <MediaPlayer/MediaPlayer.h>
+
+#import "VLCRemoteControlService.h"
+#import "VLCMain.h"
+#import "CompatibilityFixes.h"
+#import "VLCPlaylist.h"
+#import "VLCCoreInteraction.h"
+#import "VLCInputManager.h"
+
+#define kVLCSettingPlaybackForwardSkipLength @(60)
+#define kVLCSettingPlaybackBackwardSkipLength @(60)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpartial-availability"
+
+ at interface VLCRemoteControlService()
+{
+    VLCCoreInteraction *_coreInteraction;
+}
+ at end
+
+ at implementation VLCRemoteControlService
+
+static inline NSArray * RemoteCommandCenterCommandsToHandle()
+{
+    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
+    NSMutableArray *commands = [NSMutableArray arrayWithObjects:
+                                cc.playCommand,
+                                cc.pauseCommand,
+                                cc.stopCommand,
+                                cc.togglePlayPauseCommand,
+                                cc.nextTrackCommand,
+                                cc.previousTrackCommand,
+                                cc.skipForwardCommand,
+                                cc.skipBackwardCommand,
+                                cc.changePlaybackPositionCommand,
+                                nil];
+    return [commands copy];
+}
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        _coreInteraction = [VLCCoreInteraction sharedInstance];
+
+        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+        [notificationCenter addObserver:self
+                               selector:@selector(playbackRateChanged:)
+                                   name:VLCPlayerRateChanged
+                                 object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)playbackStateChangedTo:(int)state
+{
+    MPNowPlayingInfoCenter *nowPlayingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
+
+    switch (state) {
+        case PLAYING_S:
+            nowPlayingInfoCenter.playbackState = MPNowPlayingPlaybackStatePlaying;
+            break;
+
+        case PAUSE_S:
+            nowPlayingInfoCenter.playbackState = MPNowPlayingPlaybackStatePaused;
+            break;
+
+        case END_S:
+        case -1:
+            nowPlayingInfoCenter.playbackState = MPNowPlayingPlaybackStateStopped;
+            break;
+
+        default:
+            nowPlayingInfoCenter.playbackState = MPNowPlayingPlaybackStateUnknown;
+            break;
+    }
+}
+
+- (void)playbackPositionUpdated
+{
+    MPNowPlayingInfoCenter *nowPlayingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
+
+    NSMutableDictionary *currentlyPlayingTrackInfo = [nowPlayingInfoCenter.nowPlayingInfo mutableCopy];
+    [self setTimeInformationForDictionary:currentlyPlayingTrackInfo];
+
+    nowPlayingInfoCenter.nowPlayingInfo = currentlyPlayingTrackInfo;
+}
+
+- (void)playbackRateChanged:(NSNotification *)aNotification
+{
+    MPNowPlayingInfoCenter *nowPlayingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
+
+    NSMutableDictionary *currentlyPlayingTrackInfo = [nowPlayingInfoCenter.nowPlayingInfo mutableCopy];
+    [self setRateInformationForDictionary:currentlyPlayingTrackInfo];
+
+    nowPlayingInfoCenter.nowPlayingInfo = currentlyPlayingTrackInfo;
+}
+
+- (void)metaDataChangedForCurrentMediaItem:(input_item_t *)p_input_item
+{
+    if (!p_input_item) {
+        [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nil;
+        return;
+    }
+
+    NSMutableDictionary *currentlyPlayingTrackInfo = [NSMutableDictionary dictionary];
+    [self setTimeInformationForDictionary:currentlyPlayingTrackInfo];
+    [self setRateInformationForDictionary:currentlyPlayingTrackInfo];
+
+    /* fill title info */
+    char *psz_title = input_item_GetTitle(p_input_item);
+    if (!psz_title)
+        psz_title = input_item_GetName(p_input_item);
+    [currentlyPlayingTrackInfo setValue:toNSStr(psz_title) forKey:MPMediaItemPropertyTitle];
+    free(psz_title);
+
+    char *psz_artist = input_item_GetArtist(p_input_item);
+    [currentlyPlayingTrackInfo setValue:toNSStr(psz_artist) forKey:MPMediaItemPropertyArtist];
+    free(psz_artist);
+
+    char *psz_albumName = input_item_GetAlbum(p_input_item);
+    [currentlyPlayingTrackInfo setValue:toNSStr(psz_albumName) forKey:MPMediaItemPropertyAlbumTitle];
+    free(psz_albumName);
+
+    char *psz_trackNumber = input_item_GetTrackNumber(p_input_item);
+    [currentlyPlayingTrackInfo setValue:[NSNumber numberWithInt:[toNSStr(psz_trackNumber) intValue]] forKey:MPMediaItemPropertyAlbumTrackNumber];
+    free(psz_trackNumber);
+
+    mtime_t duration = input_item_GetDuration(p_input_item) / 1000000;
+    [currentlyPlayingTrackInfo setValue:[NSNumber numberWithLongLong:duration] forKey:MPMediaItemPropertyPlaybackDuration];
+    if (duration > 0) {
+        [currentlyPlayingTrackInfo setValue:[NSNumber numberWithBool:NO] forKey:MPNowPlayingInfoPropertyIsLiveStream];
+    } else {
+        [currentlyPlayingTrackInfo setValue:[NSNumber numberWithBool:YES] forKey:MPNowPlayingInfoPropertyIsLiveStream];
+    }
+
+    char *psz_artworkURL = input_item_GetArtworkURL(p_input_item);
+    if (psz_artworkURL) {
+        NSString *artworkURL = toNSStr(psz_artworkURL);
+        if (![artworkURL hasPrefix:@"attachment://"]) {
+            NSImage *coverArtImage = [[NSImage alloc] initWithContentsOfURL:[NSURL URLWithString:artworkURL]];
+            if (coverArtImage) {
+                MPMediaItemArtwork *mpartwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:coverArtImage.size
+                                                                                requestHandler:^NSImage* _Nonnull(CGSize size) {
+                    return coverArtImage;
+                }];
+                [currentlyPlayingTrackInfo setValue:mpartwork forKey:MPMediaItemPropertyArtwork];
+            }
+        }
+    }
+    free(psz_artworkURL);
+
+    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = currentlyPlayingTrackInfo;
+}
+
+- (void)setTimeInformationForDictionary:(NSMutableDictionary *)dictionary
+{
+    [dictionary setValue:[NSNumber numberWithLongLong:_coreInteraction.currentPlaybackTimeInSeconds] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
+    [dictionary setValue:[NSNumber numberWithFloat:_coreInteraction.currentPlaybackPosition] forKey:MPNowPlayingInfoPropertyPlaybackProgress];
+}
+
+- (void)setRateInformationForDictionary:(NSMutableDictionary *)dictionary
+{
+    [dictionary setValue:[NSNumber numberWithFloat:_coreInteraction.internalPlaybackRate] forKey:MPNowPlayingInfoPropertyPlaybackRate];
+}
+
+- (void)subscribeToRemoteCommands
+{
+    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
+
+    //Enable when you want to support these
+    commandCenter.ratingCommand.enabled = NO;
+    commandCenter.likeCommand.enabled = NO;
+    commandCenter.dislikeCommand.enabled = NO;
+    commandCenter.bookmarkCommand.enabled = NO;
+    commandCenter.enableLanguageOptionCommand.enabled = NO;
+    commandCenter.disableLanguageOptionCommand.enabled = NO;
+    commandCenter.seekForwardCommand.enabled = NO;
+    commandCenter.seekBackwardCommand.enabled = NO;
+
+    commandCenter.skipForwardCommand.preferredIntervals = @[kVLCSettingPlaybackForwardSkipLength];
+    commandCenter.skipBackwardCommand.preferredIntervals = @[kVLCSettingPlaybackBackwardSkipLength];
+
+    for (MPRemoteCommand *command in RemoteCommandCenterCommandsToHandle()) {
+        [command addTarget:self action:@selector(remoteCommandEvent:)];
+    }
+
+}
+
+- (void)unsubscribeFromRemoteCommands
+{
+    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nil;
+
+    for (MPRemoteCommand *command in RemoteCommandCenterCommandsToHandle()) {
+        [command removeTarget:self];
+    }
+}
+
+- (MPRemoteCommandHandlerStatus)remoteCommandEvent:(MPRemoteCommandEvent *)event
+{
+    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
+
+    if (event.command == cc.playCommand) {
+        [_coreInteraction play];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.pauseCommand) {
+        [_coreInteraction pause];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.stopCommand) {
+        [_coreInteraction stop];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.togglePlayPauseCommand) {
+        [_coreInteraction playOrPause];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.nextTrackCommand) {
+        [_coreInteraction next];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.previousTrackCommand) {
+        [_coreInteraction previous];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.skipForwardCommand) {
+        [_coreInteraction forwardMedium];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.skipBackwardCommand) {
+        [_coreInteraction backwardMedium];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.changePlaybackPositionCommand) {
+        MPChangePlaybackPositionCommandEvent *positionEvent = (MPChangePlaybackPositionCommandEvent *)event;
+        return [_coreInteraction seekToTime:positionEvent.positionTime * 1000000] ? MPRemoteCommandHandlerStatusSuccess : MPRemoteCommandHandlerStatusCommandFailed;
+    }
+    if (event.command == cc.changeRepeatModeCommand) {
+        MPChangeRepeatModeCommandEvent *repeatEvent = (MPChangeRepeatModeCommandEvent *)event;
+        MPRepeatType repeatType = repeatEvent.repeatType;
+        switch (repeatType) {
+            case MPRepeatTypeAll:
+                [_coreInteraction repeatAll];
+                 break;
+
+            case MPRepeatTypeOne:
+                [_coreInteraction repeatOne];
+                break;
+
+            default:
+                [_coreInteraction repeatOff];
+                break;
+        }
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.changeShuffleModeCommand) {
+        [_coreInteraction shuffle];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+
+    msg_Dbg(getIntf(), "%s Wasn't able to handle remote control event: %s",__PRETTY_FUNCTION__,[event.description UTF8String]);
+    return MPRemoteCommandHandlerStatusCommandFailed;
+}
+
+ at end
+
+#pragma clang diagnostic pop



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/627a60fee0325a26672e4f35c771d967ea3e8d6a...d9de9c3e49d3f252943b547de9f86036f2d97b0a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/627a60fee0325a26672e4f35c771d967ea3e8d6a...d9de9c3e49d3f252943b547de9f86036f2d97b0a
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list