Ver código fonte

VLCRemoteControlService: remove < iOS 9 code and Decouple the remotecontrolEvents from the playbackController

Carola Nitz 7 anos atrás
pai
commit
ce03cb9c3f

+ 37 - 0
SharedSources/VLCRemoteControlService.h

@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * VLCRemoteControlService.h
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2017 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Carola Nitz <nitz.carola # gmail.com>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+@class VLCRemoteControlService;
+
+@protocol VLCRemoteControlServiceDelegate
+
+- (void)remoteControlServiceHitPlay:(VLCRemoteControlService *)rcs;
+- (void)remoteControlServiceHitPause:(VLCRemoteControlService *)rcs;
+- (void)remoteControlServiceTogglePlayPause:(VLCRemoteControlService *)rcs;
+- (void)remoteControlServiceHitStop:(VLCRemoteControlService *)rcs;
+- (BOOL)remoteControlServiceHitPlayNextIfPossible:(VLCRemoteControlService *)rcs;
+- (BOOL)remoteControlServiceHitPlayPreviousIfPossible:(VLCRemoteControlService *)rcs;
+- (void)remoteControlService:(VLCRemoteControlService *)rcs jumpForwardInSeconds:(NSTimeInterval)seconds;
+- (void)remoteControlService:(VLCRemoteControlService *)rcs jumpBackwardInSeconds:(NSTimeInterval)seconds;
+- (NSInteger)remoteControlServiceNumberOfMediaItemsinList:(VLCRemoteControlService *)rcs;
+- (void)remoteControlService:(VLCRemoteControlService *)rcs setPlaybackRate:(CGFloat)playbackRate;
+
+@end
+
+@interface VLCRemoteControlService : NSObject
+
+@property (nonatomic, weak) id<VLCRemoteControlServiceDelegate> remoteControlServiceDelegate;
+
+- (void)subscribeToRemoteCommands;
+- (void)unsubscribeFromRemoteCommands;
+
+@end

+ 134 - 0
SharedSources/VLCRemoteControlService.m

@@ -0,0 +1,134 @@
+/*****************************************************************************
+ * VLCRemoteControlService.m
+ * VLC for iOS
+ *****************************************************************************
+ * Copyright (c) 2017 VideoLAN. All rights reserved.
+ * $Id$
+ *
+ * Authors: Carola Nitz <nitz.carola # gmail.com>
+ *
+ * Refer to the COPYING file of the official project for license.
+ *****************************************************************************/
+
+#import "VLCRemoteControlService.h"
+#import <MediaPlayer/MediaPlayer.h>
+
+@implementation VLCRemoteControlService
+
+static inline NSArray * RemoteCommandCenterCommandsToHandle()
+{
+    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
+    return @[cc.pauseCommand,
+             cc.playCommand,
+             cc.stopCommand,
+             cc.togglePlayPauseCommand,
+             cc.nextTrackCommand,
+             cc.previousTrackCommand,
+             cc.skipForwardCommand,
+             cc.skipBackwardCommand,
+             cc.changePlaybackRateCommand,
+             ];
+}
+
+- (void)subscribeToRemoteCommands
+{
+    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
+
+    /* Since the control center and lockscreen shows only either skipForward/Backward
+     * or next/previousTrack buttons but prefers skip buttons,
+     * we only enable skip buttons if we have no medialist
+     */
+    BOOL enableSkip = NO;
+    if (_remoteControlServiceDelegate) {
+        enableSkip = [_remoteControlServiceDelegate remoteControlServiceNumberOfMediaItemsinList:self] <= 1;
+    }
+    commandCenter.skipForwardCommand.enabled = enableSkip;
+    commandCenter.skipBackwardCommand.enabled = enableSkip;
+
+    //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.changeRepeatModeCommand.enabled = NO;
+    commandCenter.changeShuffleModeCommand.enabled = NO;
+    commandCenter.seekForwardCommand.enabled = NO;
+    commandCenter.seekBackwardCommand.enabled = NO;
+    commandCenter.changePlaybackPositionCommand.enabled = NO;
+
+    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+    NSNumber *forwardSkip = [defaults valueForKey:kVLCSettingPlaybackForwardSkipLength];
+    commandCenter.skipForwardCommand.preferredIntervals = @[forwardSkip];
+    NSNumber *backwardSkip = [defaults valueForKey:kVLCSettingPlaybackBackwardSkipLength];
+    commandCenter.skipBackwardCommand.preferredIntervals = @[backwardSkip];
+
+    commandCenter.changePlaybackRateCommand.supportedPlaybackRates = @[@(0.5),@(0.75),@(1.0),@(1.25),@(1.5),@(1.75),@(2.0)];
+
+    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
+{
+    if (!_remoteControlServiceDelegate) return MPRemoteCommandHandlerStatusCommandFailed;
+
+    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
+
+    if (event.command == cc.pauseCommand) {
+        [_remoteControlServiceDelegate remoteControlServiceHitPause:self];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.playCommand) {
+        [_remoteControlServiceDelegate remoteControlServiceHitPlay:self];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.stopCommand) {
+        [_remoteControlServiceDelegate remoteControlServiceHitStop:self];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.togglePlayPauseCommand) {
+        [_remoteControlServiceDelegate remoteControlServiceTogglePlayPause:self];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.nextTrackCommand) {
+        BOOL success = [_remoteControlServiceDelegate remoteControlServiceHitPlayNextIfPossible:self];
+        return success ? MPRemoteCommandHandlerStatusSuccess : MPRemoteCommandHandlerStatusNoSuchContent;
+    }
+    if (event.command == cc.previousTrackCommand) {
+        BOOL success = [_remoteControlServiceDelegate remoteControlServiceHitPlayPreviousIfPossible:self];
+        return success ? MPRemoteCommandHandlerStatusSuccess : MPRemoteCommandHandlerStatusNoSuchContent;
+    }
+    if (event.command == cc.skipForwardCommand) {
+        MPSkipIntervalCommandEvent *skipEvent = (MPSkipIntervalCommandEvent *)event;
+        [_remoteControlServiceDelegate remoteControlService:self jumpForwardInSeconds:skipEvent.interval];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.skipBackwardCommand) {
+        MPSkipIntervalCommandEvent *skipEvent = (MPSkipIntervalCommandEvent *)event;
+        [_remoteControlServiceDelegate remoteControlService:self jumpBackwardInSeconds:skipEvent.interval];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    if (event.command == cc.changePlaybackRateCommand) {
+        MPChangePlaybackRateCommandEvent *rateEvent = (MPChangePlaybackRateCommandEvent *)event;
+        [_remoteControlServiceDelegate remoteControlService:self setPlaybackRate:rateEvent.playbackRate];
+        return MPRemoteCommandHandlerStatusSuccess;
+    }
+    NSAssert(NO, @"remote control event not handled");
+    APLog(@"%s Wasn't able to handle remote control event: %@",__PRETTY_FUNCTION__,event);
+    return MPRemoteCommandHandlerStatusCommandFailed;
+
+}
+
+@end

+ 0 - 6
Sources/VLCAppDelegate.m

@@ -494,12 +494,6 @@ didFailToContinueUserActivityWithType:(NSString *)userActivityType
                                                  scrollPosition:UITableViewScrollPositionNone];
 }
 
-#pragma mark - remote events pre 7.1
-
-- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
-    [[VLCPlaybackController sharedInstance] remoteControlReceivedWithEvent:event];
-}
-
 #pragma mark - watch stuff
 - (void)application:(UIApplication *)application
 handleWatchKitExtensionRequest:(NSDictionary *)userInfo

+ 0 - 1
Sources/VLCPlaybackController.h

@@ -103,6 +103,5 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
 - (void)playMediaList:(VLCMediaList *)mediaList firstIndex:(NSInteger)index;
 - (void)playURL:(NSURL *)url successCallback:(NSURL*)successCallback errorCallback:(NSURL *)errorCallback;
 - (void)playURL:(NSURL *)url subtitlesFilePath:(NSString *)subsFilePath;
-- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
 
 @end

+ 66 - 159
Sources/VLCPlaybackController.m

@@ -23,6 +23,7 @@
 #import <MediaPlayer/MediaPlayer.h>
 #import "VLCPlayerDisplayController.h"
 #import "VLCConstants.h"
+#import "VLCRemoteControlService.h"
 
 #if TARGET_OS_IOS
 #import "VLCKeychainCoordinator.h"
@@ -51,8 +52,9 @@ typedef NS_ENUM(NSUInteger, VLCAspectRatio) {
 #if TARGET_OS_IOS
 AVAudioSessionDelegate,
 #endif
-VLCMediaDelegate>
+VLCMediaDelegate, VLCRemoteControlServiceDelegate>
 {
+    VLCRemoteControlService *_remoteControlService;
     BOOL _playerIsSetup;
     BOOL _playbackFailed;
     BOOL _shouldResumePlaying;
@@ -134,6 +136,14 @@ VLCMediaDelegate>
     return self;
 }
 
+- (VLCRemoteControlService *)remoteControlService
+{
+    if (!_remoteControlService) {
+        _remoteControlService = [[VLCRemoteControlService alloc] init];
+        _remoteControlService.remoteControlServiceDelegate = self;
+    }
+    return _remoteControlService;
+}
 #pragma mark - playback management
 
 - (void)playMediaList:(VLCMediaList *)mediaList firstIndex:(NSInteger)index
@@ -292,7 +302,7 @@ VLCMediaDelegate>
     _mediaPlayer.videoAspectRatio = NULL;
     _mediaPlayer.scaleFactor = 0;
 
-    [self subscribeRemoteCommands];
+    [[self remoteControlService] subscribeToRemoteCommands];
 
     _playerIsSetup = YES;
 
@@ -349,8 +359,7 @@ VLCMediaDelegate>
     else if (self.successCallback && !_sessionWillRestart)
         [[UIApplication sharedApplication] openURL:self.successCallback];
 
-    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nil;
-    [self unsubscribeFromRemoteCommand];
+    [[self remoteControlService] unsubscribeFromRemoteCommands];
     _activeSession = NO;
 
     [_playbackSessionManagementLock unlock];
@@ -1120,161 +1129,6 @@ setstuff:
     _sleepTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(stopPlayback) userInfo:nil repeats:NO];
 }
 
-#pragma mark - remote events
-
-static inline NSArray * RemoteCommandCenterCommandsToHandle(MPRemoteCommandCenter *cc)
-{
-    /* commmented out other available commands which we don't support now but may
-     * support at some point in the future */
-    return @[cc.pauseCommand, cc.playCommand, cc.stopCommand, cc.togglePlayPauseCommand,
-             cc.nextTrackCommand, cc.previousTrackCommand,
-             cc.skipForwardCommand, cc.skipBackwardCommand,
-             //             cc.seekForwardCommand, cc.seekBackwardCommand,
-             //             cc.ratingCommand,
-             cc.changePlaybackRateCommand,
-             //             cc.likeCommand,cc.dislikeCommand,cc.bookmarkCommand,
-             ];
-}
-
-- (void)subscribeRemoteCommands
-{
-    /* pre iOS 7.1 */
-    if (![MPRemoteCommandCenter class]) {
-        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
-        return;
-    }
-    /* for iOS 7.1 and above: */
-
-    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
-
-    /*
-     * since the control center and lockscreen shows only either skipForward/Backward
-     * or next/previousTrack buttons but prefers skip buttons,
-     * we only enable skip buttons if we have a no medialist
-     */
-    BOOL enableSkip = [VLCPlaybackController sharedInstance].mediaList.count <= 1;
-    commandCenter.skipForwardCommand.enabled = enableSkip;
-    commandCenter.skipBackwardCommand.enabled = enableSkip;
-
-    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    NSNumber *forwardSkip = [defaults valueForKey:kVLCSettingPlaybackForwardSkipLength];
-    commandCenter.skipForwardCommand.preferredIntervals = @[forwardSkip];
-    NSNumber *backwardSkip = [defaults valueForKey:kVLCSettingPlaybackBackwardSkipLength];
-    commandCenter.skipBackwardCommand.preferredIntervals = @[backwardSkip];
-
-    NSArray *supportedPlaybackRates = @[@(0.5),@(0.75),@(1.0),@(1.25),@(1.5),@(1.75),@(2.0)];
-    commandCenter.changePlaybackRateCommand.supportedPlaybackRates = supportedPlaybackRates;
-
-    NSArray *commandsToSubscribe = RemoteCommandCenterCommandsToHandle(commandCenter);
-    for (MPRemoteCommand *command in commandsToSubscribe) {
-        [command addTarget:self action:@selector(remoteCommandEvent:)];
-    }
-}
-
-- (void)unsubscribeFromRemoteCommand
-{
-    /* pre iOS 7.1 */
-    if (![MPRemoteCommandCenter class]) {
-        [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
-        return;
-    }
-
-    /* for iOS 7.1 and above: */
-    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
-    NSArray *commmandsToRemoveFrom = RemoteCommandCenterCommandsToHandle(cc);
-    for (MPRemoteCommand *command in commmandsToRemoveFrom) {
-        [command removeTarget:self];
-    }
-}
-
-- (MPRemoteCommandHandlerStatus )remoteCommandEvent:(MPRemoteCommandEvent *)event
-{
-    MPRemoteCommandCenter *cc = [MPRemoteCommandCenter sharedCommandCenter];
-    MPRemoteCommandHandlerStatus result = MPRemoteCommandHandlerStatusSuccess;
-
-    if (event.command == cc.pauseCommand) {
-        [_listPlayer pause];
-    } else if (event.command == cc.playCommand) {
-        [_listPlayer play];
-    } else if (event.command == cc.stopCommand) {
-        [_listPlayer stop];
-    } else if (event.command == cc.togglePlayPauseCommand) {
-        [self playPause];
-    } else if (event.command == cc.nextTrackCommand) {
-        result = [_listPlayer next] ? MPRemoteCommandHandlerStatusSuccess : MPRemoteCommandHandlerStatusNoSuchContent;
-    } else if (event.command == cc.previousTrackCommand) {
-        result = [_listPlayer previous] ? MPRemoteCommandHandlerStatusSuccess : MPRemoteCommandHandlerStatusNoSuchContent;
-    } else if (event.command == cc.skipForwardCommand) {
-        if ([event isKindOfClass:[MPSkipIntervalCommandEvent class]]) {
-            MPSkipIntervalCommandEvent *skipEvent = (MPSkipIntervalCommandEvent *)event;
-            [_mediaPlayer jumpForward:skipEvent.interval];
-        } else {
-            result = MPRemoteCommandHandlerStatusCommandFailed;
-        }
-    } else if (event.command == cc.skipBackwardCommand) {
-        if ([event isKindOfClass:[MPSkipIntervalCommandEvent class]]) {
-            MPSkipIntervalCommandEvent *skipEvent = (MPSkipIntervalCommandEvent *)event;
-            [_mediaPlayer jumpBackward:skipEvent.interval];
-        } else {
-            result = MPRemoteCommandHandlerStatusCommandFailed;
-        }
-    } else if (event.command == cc.changePlaybackRateCommand) {
-        if ([event isKindOfClass:[MPChangePlaybackRateCommandEvent class]]) {
-            MPChangePlaybackRateCommandEvent *rateEvent = (MPChangePlaybackRateCommandEvent *)event;
-            [_mediaPlayer setRate:rateEvent.playbackRate];
-        } else {
-            result = MPRemoteCommandHandlerStatusCommandFailed;
-        }
-        /* stubs for when we want to support the other available commands */
-        //    } else if (event.command == cc.seekForwardCommand) {
-        //    } else if (event.command == cc.seekBackwardCommand) {
-        //    } else if (event.command == cc.ratingCommand) {
-        //    } else if (event.command == cc.likeCommand) {
-        //    } else if (event.command == cc.dislikeCommand) {
-        //    } else if (event.command == cc.bookmarkCommand) {
-    } else {
-        APLog(@"%s Unsupported remote control event: %@",__PRETTY_FUNCTION__,event);
-        result = MPRemoteCommandHandlerStatusCommandFailed;
-    }
-
-    if (result == MPRemoteCommandHandlerStatusCommandFailed)
-        APLog(@"%s Wasn't able to handle remote control event: %@",__PRETTY_FUNCTION__,event);
-
-    return result;
-}
-
-- (void)remoteControlReceivedWithEvent:(UIEvent *)event
-{
-    switch (event.subtype) {
-        case UIEventSubtypeRemoteControlPlay:
-            [_listPlayer play];
-            break;
-
-        case UIEventSubtypeRemoteControlPause:
-            [_listPlayer pause];
-            break;
-
-        case UIEventSubtypeRemoteControlTogglePlayPause:
-            [self playPause];
-            break;
-
-        case UIEventSubtypeRemoteControlNextTrack:
-            [self forward];
-            break;
-
-        case UIEventSubtypeRemoteControlPreviousTrack:
-            [self backward];
-            break;
-
-        case UIEventSubtypeRemoteControlStop:
-            [self stopPlayback];
-            break;
-
-        default:
-            break;
-    }
-}
-
 #pragma mark - background interaction
 
 - (void)applicationWillResignActive:(NSNotification *)aNotification
@@ -1313,7 +1167,60 @@ static inline NSArray * RemoteCommandCenterCommandsToHandle(MPRemoteCommandCente
         [_listPlayer play];
     }
 }
+#pragma mark - remoteControlDelegate
+
+- (void)remoteControlServiceHitPause:(VLCRemoteControlService *)rcs
+{
+    [_listPlayer pause];
+}
+
+- (void)remoteControlServiceHitPlay:(VLCRemoteControlService *)rcs
+{
+    [_listPlayer play];
+}
+
+- (void)remoteControlServiceTogglePlayPause:(VLCRemoteControlService *)rcs
+{
+    [self playPause];
+}
 
+- (void)remoteControlServiceHitStop:(VLCRemoteControlService *)rcs
+{
+    //TODO handle stop playback entirely
+    [_listPlayer stop];
+}
+
+- (BOOL)remoteControlServiceHitPlayNextIfPossible:(VLCRemoteControlService *)rcs
+{
+    //TODO This doesn't handle shuffle or repeat yet
+    return [_listPlayer next];
+}
+
+- (BOOL)remoteControlServiceHitPlayPreviousIfPossible:(VLCRemoteControlService *)rcs
+{
+    //TODO This doesn't handle shuffle or repeat yet
+    return [_listPlayer previous];
+}
+
+- (void)remoteControlService:(VLCRemoteControlService *)rcs jumpForwardInSeconds:(NSTimeInterval)seconds
+{
+    [_mediaPlayer jumpForward:seconds];
+}
+
+- (void)remoteControlService:(VLCRemoteControlService *)rcs jumpBackwardInSeconds:(NSTimeInterval)seconds
+{
+    [_mediaPlayer jumpBackward:seconds];
+}
+
+- (NSInteger)remoteControlServiceNumberOfMediaItemsinList:(VLCRemoteControlService *)rcs
+{
+    return _mediaList.count;
+}
+
+- (void)remoteControlService:(VLCRemoteControlService *)rcs setPlaybackRate:(CGFloat)playbackRate
+{
+    self.playbackRate = playbackRate;
+}
 #pragma mark - helpers
 
 - (NSDictionary *)mediaOptionsDictionary

+ 14 - 0
VLC.xcodeproj/project.pbxproj

@@ -25,6 +25,7 @@
 		4171D35018A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 4171D34F18A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.m */; };
 		417CDA231A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 417CDA211A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.m */; };
 		417CDA241A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 417CDA221A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.xib */; };
+		417D7F601F7BA26200DDF36A /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
 		417E68691F307D8F00DB9BB2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 417E68711F307D8F00DB9BB2 /* InfoPlist.strings */; };
 		417E686A1F307D8F00DB9BB2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 417E68711F307D8F00DB9BB2 /* InfoPlist.strings */; };
 		417E686B1F307D8F00DB9BB2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 417E68711F307D8F00DB9BB2 /* InfoPlist.strings */; };
@@ -52,6 +53,10 @@
 		41B93C081A53853B00102E8B /* VLCCloudServiceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41B93C071A53853B00102E8B /* VLCCloudServiceCell.xib */; };
 		41CD695C1A29D72600E60BCE /* VLCBoxController.m in Sources */ = {isa = PBXBuildFile; fileRef = 41CD69591A29D72600E60BCE /* VLCBoxController.m */; };
 		41CD695D1A29D72600E60BCE /* VLCBoxTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 41CD695B1A29D72600E60BCE /* VLCBoxTableViewController.m */; };
+		41EB91D71F7BE6F500821AA5 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
+		41EB91D81F7BE6F700821AA5 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
+		41EB91D91F7BE6F900821AA5 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
+		41EB91DA1F7BE6F900821AA5 /* VLCRemoteControlService.m in Sources */ = {isa = PBXBuildFile; fileRef = 417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */; };
 		41F5C0781F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 41F5C0771F41ED55005EB9CB /* VLCLibrarySearchDisplayDataSource.m */; };
 		41F5C07B1F42E567005EB9CB /* VLCMediaDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 41F5C07A1F42E567005EB9CB /* VLCMediaDataSource.m */; };
 		41F5C07C1F42E567005EB9CB /* VLCMediaDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 41F5C07A1F42E567005EB9CB /* VLCMediaDataSource.m */; };
@@ -1117,6 +1122,8 @@
 		417CDA201A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCCloudServicesTableViewController.h; path = Sources/VLCCloudServicesTableViewController.h; sourceTree = SOURCE_ROOT; };
 		417CDA211A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCCloudServicesTableViewController.m; path = Sources/VLCCloudServicesTableViewController.m; sourceTree = SOURCE_ROOT; };
 		417CDA221A48D1F300D9ACE7 /* VLCCloudServicesTableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCCloudServicesTableViewController.xib; path = Resources/VLCCloudServicesTableViewController.xib; sourceTree = SOURCE_ROOT; };
+		417D7F5E1F7BA26200DDF36A /* VLCRemoteControlService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCRemoteControlService.h; sourceTree = "<group>"; };
+		417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCRemoteControlService.m; sourceTree = "<group>"; };
 		417E68701F307D8F00DB9BB2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		417E68721F307DA900DB9BB2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		417E68731F307DAA00DB9BB2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -2695,6 +2702,8 @@
 				7DE56C191AD93F9100E8CA00 /* VLCPlaybackController.m */,
 				DD510B6E1B14E564003BA71C /* VLCPlayerDisplayController.h */,
 				DD510B6F1B14E564003BA71C /* VLCPlayerDisplayController.m */,
+				417D7F5E1F7BA26200DDF36A /* VLCRemoteControlService.h */,
+				417D7F5F1F7BA26200DDF36A /* VLCRemoteControlService.m */,
 			);
 			name = Playback;
 			sourceTree = "<group>";
@@ -4441,6 +4450,7 @@
 				DD3EFF421BDEBCE500B68579 /* VLCNetworkServerBrowserSharedLibrary.m in Sources */,
 				7D5278E41BD7E37300D0CA0E /* VLCCloudStorageController.m in Sources */,
 				DD490B171BE6BA580010F335 /* VLCIRTVTapGestureRecognizer.m in Sources */,
+				41EB91D71F7BE6F500821AA5 /* VLCRemoteControlService.m in Sources */,
 				7DC5A3EC1BF63F4B00CFEBA8 /* VLCMediaFileDiscoverer.m in Sources */,
 				7D3E528B1BD7B5E100309D15 /* VLCCloudServicesTVViewController.m in Sources */,
 				DD9D8F6B1C01FE5B00B4060F /* VLCPlaybackInfoCollectionViewDataSource.m in Sources */,
@@ -4540,6 +4550,7 @@
 				7D63BBE01D414212003C60D3 /* VLCNetworkServerBrowserSharedLibrary.m in Sources */,
 				7D63BBE11D414212003C60D3 /* VLCCloudStorageController.m in Sources */,
 				7D63BBE21D414212003C60D3 /* VLCIRTVTapGestureRecognizer.m in Sources */,
+				41EB91D81F7BE6F700821AA5 /* VLCRemoteControlService.m in Sources */,
 				7D63BBE31D414212003C60D3 /* VLCMediaFileDiscoverer.m in Sources */,
 				7D63BBE41D414212003C60D3 /* VLCCloudServicesTVViewController.m in Sources */,
 				7D63BBE51D414212003C60D3 /* VLCPlaybackInfoCollectionViewDataSource.m in Sources */,
@@ -4648,6 +4659,7 @@
 				7DE7D2CD1D42900200B3AD27 /* VLCNetworkLoginDataSource.m in Sources */,
 				7D787F761D40FDE70003CFA1 /* VLCFolderCollectionViewFlowLayout.m in Sources */,
 				7D787F771D40FDE70003CFA1 /* VLCLocalNetworkServiceBrowserBonjour.m in Sources */,
+				41EB91DA1F7BE6F900821AA5 /* VLCRemoteControlService.m in Sources */,
 				7D787F781D40FDE70003CFA1 /* VLCDownloadViewController.m in Sources */,
 				7D787F791D40FDE70003CFA1 /* VLCLocalNetworkServiceBrowserSAP.m in Sources */,
 				7D787F7A1D40FDE70003CFA1 /* VLCLocalNetworkServiceBrowserPlex.m in Sources */,
@@ -4803,6 +4815,7 @@
 				7D74177A1AE2D3CE001F1997 /* VLCNavigationController.m in Sources */,
 				7D30F3E2183AB33200FFC021 /* VLCSidebarViewCell.m in Sources */,
 				7D30F3EA183AB34200FFC021 /* VLCGoogleDriveController.m in Sources */,
+				417D7F601F7BA26200DDF36A /* VLCRemoteControlService.m in Sources */,
 				DD510B701B14E564003BA71C /* VLCPlayerDisplayController.m in Sources */,
 				DD3EFF431BDEBCE500B68579 /* VLCSharedLibraryParser.m in Sources */,
 				9B088308183D7BEC004B5C2A /* VLCCloudStorageTableViewController.m in Sources */,
@@ -4886,6 +4899,7 @@
 				7DC54FED1C046615007B4E42 /* VLCPlexParser.m in Sources */,
 				7DC54FEE1C046615007B4E42 /* VLCMenuButton.m in Sources */,
 				7DC54FEF1C046615007B4E42 /* VLCBoxController.m in Sources */,
+				41EB91D91F7BE6F900821AA5 /* VLCRemoteControlService.m in Sources */,
 				7DC54FF01C046615007B4E42 /* VLCSlider.m in Sources */,
 				7DC54FF11C046615007B4E42 /* VLCStatusLabel.m in Sources */,
 				7DC54FF21C046615007B4E42 /* VLCMultiSelectionMenuView.m in Sources */,