VLCWatchCommunication.m 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*****************************************************************************
  2. * VLCWatchCommunication.m
  3. * VLC for iOS
  4. *****************************************************************************
  5. * Copyright (c) 2015 VideoLAN. All rights reserved.
  6. * $Id$
  7. *
  8. * Author: Tobias Conradi <videolan # tobias-conradi.de>
  9. *
  10. * Refer to the COPYING file of the official project for license.
  11. *****************************************************************************/
  12. #import "VLCWatchCommunication.h"
  13. #import "VLCWatchMessage.h"
  14. #import "VLCPlaybackController+MediaLibrary.h"
  15. #import <MediaPlayer/MediaPlayer.h>
  16. @implementation VLCWatchCommunication
  17. - (instancetype)init
  18. {
  19. self = [super init];
  20. if (self) {
  21. if ([WCSession isSupported]) {
  22. WCSession *session = [WCSession defaultSession];
  23. session.delegate = self;
  24. [session activateSession];
  25. }
  26. }
  27. return self;
  28. }
  29. - (void)dealloc {
  30. [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];
  31. }
  32. static VLCWatchCommunication *_singeltonInstance = nil;
  33. + (VLCWatchCommunication *)sharedInstance
  34. {
  35. @synchronized(self) {
  36. static dispatch_once_t pred;
  37. dispatch_once(&pred, ^{
  38. _singeltonInstance = [[self alloc] init];
  39. });
  40. }
  41. return _singeltonInstance;
  42. }
  43. - (void)playFileFromWatch:(VLCWatchMessage *)message
  44. {
  45. NSManagedObject *managedObject = nil;
  46. NSString *uriString = (id)message.payload;
  47. if ([uriString isKindOfClass:[NSString class]]) {
  48. NSURL *uriRepresentation = [NSURL URLWithString:uriString];
  49. managedObject = [[MLMediaLibrary sharedMediaLibrary] objectForURIRepresentation:uriRepresentation];
  50. }
  51. if (managedObject == nil) {
  52. APLog(@"%s file not found: %@",__PRETTY_FUNCTION__,message);
  53. return;
  54. }
  55. VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
  56. [vpc playMediaLibraryObject:managedObject];
  57. }
  58. - (NSDictionary *)handleMessage:(nonnull VLCWatchMessage *)message {
  59. UIApplication *application = [UIApplication sharedApplication];
  60. /* dispatch background task */
  61. __block UIBackgroundTaskIdentifier taskIdentifier = [application beginBackgroundTaskWithName:nil
  62. expirationHandler:^{
  63. [application endBackgroundTask:taskIdentifier];
  64. taskIdentifier = UIBackgroundTaskInvalid;
  65. }];
  66. NSString *name = message.name;
  67. NSDictionary *responseDict = @{};
  68. if ([name isEqualToString:VLCWatchMessageNameGetNowPlayingInfo]) {
  69. responseDict = [self nowPlayingResponseDict];
  70. } else if ([name isEqualToString:VLCWatchMessageNamePlayPause]) {
  71. [[VLCPlaybackController sharedInstance] playPause];
  72. responseDict = @{@"playing": @([VLCPlaybackController sharedInstance].isPlaying)};
  73. } else if ([name isEqualToString:VLCWatchMessageNameSkipForward]) {
  74. [[VLCPlaybackController sharedInstance] forward];
  75. } else if ([name isEqualToString:VLCWatchMessageNameSkipBackward]) {
  76. [[VLCPlaybackController sharedInstance] backward];
  77. } else if ([name isEqualToString:VLCWatchMessageNamePlayFile]) {
  78. [self playFileFromWatch:message];
  79. } else if ([name isEqualToString:VLCWatchMessageNameSetVolume]) {
  80. [self setVolumeFromWatch:message];
  81. } else {
  82. APLog(@"Did not handle request from WatchKit Extension: %@",message);
  83. }
  84. return responseDict;
  85. }
  86. - (void)session:(nonnull WCSession *)session didReceiveMessage:(nonnull NSDictionary<NSString *,id> *)userInfo replyHandler:(nonnull void (^)(NSDictionary<NSString *,id> * _Nonnull))replyHandler {
  87. VLCWatchMessage *message = [[VLCWatchMessage alloc] initWithDictionary:userInfo];
  88. NSDictionary *responseDict = [self handleMessage:message];
  89. replyHandler(responseDict);
  90. }
  91. - (void)session:(nonnull WCSession *)session didReceiveMessage:(nonnull NSDictionary<NSString *,id> *)messageDict {
  92. VLCWatchMessage *message = [[VLCWatchMessage alloc] initWithDictionary:messageDict];
  93. [self handleMessage:message];
  94. }
  95. - (void)setVolumeFromWatch:(VLCWatchMessage *)message
  96. {
  97. NSNumber *volume = (id)message.payload;
  98. if ([volume isKindOfClass:[NSNumber class]]) {
  99. /*
  100. * Since WatchKit doesn't provide something like MPVolumeView we use deprecated API.
  101. * rdar://20783803 Feature Request: WatchKit equivalent for MPVolumeView
  102. */
  103. [MPMusicPlayerController applicationMusicPlayer].volume = volume.floatValue;
  104. }
  105. }
  106. - (NSDictionary *)nowPlayingResponseDict {
  107. NSMutableDictionary *response = [NSMutableDictionary new];
  108. NSMutableDictionary *nowPlayingInfo = [[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo mutableCopy];
  109. NSNumber *playbackTime = [VLCPlaybackController sharedInstance].mediaPlayer.time.numberValue;
  110. if (playbackTime) {
  111. nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(playbackTime.floatValue/1000);
  112. }
  113. if (nowPlayingInfo) {
  114. response[@"nowPlayingInfo"] = nowPlayingInfo;
  115. }
  116. MLFile *currentFile = [VLCPlaybackController sharedInstance].currentlyPlayingMediaFile;
  117. NSString *URIString = currentFile.objectID.URIRepresentation.absoluteString;
  118. if (URIString) {
  119. response[@"URIRepresentation"] = URIString;
  120. }
  121. response[@"volume"] = @([MPMusicPlayerController applicationMusicPlayer].volume);
  122. return response;
  123. }
  124. #pragma mark - Notifications
  125. - (void)startRelayingNotificationName:(nullable NSString *)name object:(nullable id)object {
  126. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(relayNotification:) name:name object:object];
  127. }
  128. - (void)stopRelayingNotificationName:(nullable NSString *)name object:(nullable id)object {
  129. [[NSNotificationCenter defaultCenter] removeObserver:self name:name object:object];
  130. }
  131. - (void)relayNotification:(NSNotification *)notification {
  132. NSMutableDictionary *payload = [NSMutableDictionary dictionary];
  133. payload[@"name"] = notification.name;
  134. if (notification.userInfo) {
  135. payload[@"userInfo"] = notification.userInfo;
  136. }
  137. NSDictionary *dict = [VLCWatchMessage messageDictionaryForName:VLCWatchMessageNameNotification
  138. payload:payload];
  139. if ([WCSession isSupported] && [[WCSession defaultSession] isReachable]) {
  140. [[WCSession defaultSession] sendMessage:dict replyHandler:nil errorHandler:nil];
  141. }
  142. }
  143. @end