diff --git a/Sources/DeviceMotion.swift b/Sources/DeviceMotion.swift new file mode 100644 index 0000000000000000000000000000000000000000..4666801f676fec46e39d90ea5884caa24645028b --- /dev/null +++ b/Sources/DeviceMotion.swift @@ -0,0 +1,66 @@ +/***************************************************************************** + * DeviceMotion.swift + * VLC for iOS + ***************************************************************************** + * Copyright (c) 2018 VideoLAN. All rights reserved. + * $Id$ + * + * Authors: Carola Nitz <caro # videolan.org> + * + * + * Refer to the COPYING file of the official project for license. + *****************************************************************************/ + +import Foundation +import CoreMotion + +@objc(VLCDeviceMotionDelegate) +protocol DeviceMotionDelegate:NSObjectProtocol { + + func deviceMotionHasAttitude(deviceMotion:DeviceMotion, pitch:Double, yaw:Double, roll:Double) + +} + +@objc(VLCDeviceMotion) +class DeviceMotion:NSObject { + + let motion = CMMotionManager() + var referenceAttitude:CMAttitude? = nil + @objc weak var delegate: DeviceMotionDelegate? = nil + + @objc func startDeviceMotion() { + + if motion.isDeviceMotionAvailable { + motion.gyroUpdateInterval = 1.0 / 60.0 // 60 Hz + motion.startDeviceMotionUpdates(using: .xTrueNorthZVertical, to: .main) { + [weak self] (data, error) in + guard let strongSelf = self, let data = data else { + return + } + + //We're using the initial angle of phone as 0.0.0 reference for all axis + //we need to create a copy here, otherwise we just have a reference which is being changed in the next line + if strongSelf.referenceAttitude == nil { + strongSelf.referenceAttitude = data.attitude.copy() as? CMAttitude + } + // this line basically substracts the reference attitude so that we have yaw, pitch and roll changes in + // relation to the very first angle + data.attitude.multiply(byInverseOf: strongSelf.referenceAttitude!) + + let pitch = -(180/Double.pi)*data.attitude.pitch // -90; 90 + let yaw = -(180/Double.pi)*data.attitude.yaw // -180; 180 + let roll = -(180/Double.pi)*data.attitude.roll// -180; 180 + + //print(pitch,yaw,roll) + strongSelf.delegate?.deviceMotionHasAttitude(deviceMotion:strongSelf, pitch:pitch, yaw:yaw, roll:roll) + } + } + } + + @objc func stopDeviceMotion() { + if motion.isDeviceMotionActive { + motion.stopDeviceMotionUpdates() + self.referenceAttitude = nil + } + } +} diff --git a/Sources/VLCMovieViewController.m b/Sources/VLCMovieViewController.m index 444e9f73a4799cb2edd00976eb1d7eee66d59bc1..eea221168263aea60bf56962e3a3139ed6e7d2c3 100644 --- a/Sources/VLCMovieViewController.m +++ b/Sources/VLCMovieViewController.m @@ -36,6 +36,7 @@ #import "VLCTrackSelectorView.h" #import "VLCMetadata.h" #import "UIDevice+VLC.h" +#import "VLC_iOS-Swift.h" #define FORWARD_SWIPE_DURATION 30 #define BACKWARD_SWIPE_DURATION 10 @@ -54,7 +55,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { VLCPanTypeProjection }; -@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate> +@interface VLCMovieViewController () <UIGestureRecognizerDelegate, VLCMultiSelectionViewDelegate, VLCEqualizerViewUIDelegate, VLCPlaybackControllerDelegate, VLCDeviceMotionDelegate> { BOOL _controlsHidden; BOOL _videoFiltersHidden; @@ -78,7 +79,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) { BOOL _seekGestureEnabled; BOOL _closeGestureEnabled; BOOL _variableJumpDurationEnabled; - BOOL _mediaHasProjection; BOOL _playbackWillClose; BOOL _isTapSeeking; VLCMovieJumpState _previousJumpState; @@ -111,6 +111,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { NSInteger _mediaDuration; NSInteger _numberOfTapSeek; + VLCDeviceMotion *_deviceMotion; CGFloat _fov; CGPoint _saveLocation; CGSize _screenSizePixel; @@ -415,8 +416,6 @@ typedef NS_ENUM(NSInteger, VLCPanType) { [self updateDefaults]; - //Disabling video gestures, media not init in the player yet. - [self enableNormalVideoGestures:NO]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDefaults) name:NSUserDefaultsDidChangeNotification object:nil]; } @@ -433,14 +432,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { _multiSelectionView.shuffleMode = _vpc.isShuffleMode; //Media is loaded in the media player, checking the projection type and configuring accordingly. - _fov = 0.f; - _mediaHasProjection = NO; - if ([_vpc currentMediaProjection] == VLCMediaProjectionEquiRectangular) { - _fov = DEFAULT_FOV; - _mediaHasProjection = YES; - } - - [self enableNormalVideoGestures:!_mediaHasProjection]; + [self setupForMediaProjection]; } - (void)viewDidLayoutSubviews @@ -512,6 +504,12 @@ typedef NS_ENUM(NSInteger, VLCPanType) { [[NSUserDefaults standardUserDefaults] setBool:_displayRemainingTime forKey:kVLCShowRemainingTime]; } +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + [self.deviceMotion stopDeviceMotion]; +} + - (BOOL)canBecomeFirstResponder { return YES; @@ -650,7 +648,7 @@ typedef NS_ENUM(NSInteger, VLCPanType) { CGFloat diff = DEFAULT_FOV * -(ZOOM_SENSITIVITY * recognizer.velocity / _screenSizePixel.width); - if (_mediaHasProjection) { + if ([_vpc currentMediaProjection] == VLCMediaProjectionEquiRectangular) { if ([_vpc updateViewpoint:0 pitch:0 roll:0 fov:diff absolute:NO]) { //Checking for fov value in case of _fov = MAX(MIN(_fov + diff, MAX_FOV), MIN_FOV); @@ -838,15 +836,35 @@ typedef NS_ENUM(NSInteger, VLCPanType) { return [super nextResponder]; } -- (void)enableNormalVideoGestures:(BOOL)enable +- (VLCDeviceMotion *)deviceMotion { - [_tapRecognizer setEnabled:enable]; - [_swipeRecognizerUp setEnabled:enable]; - [_swipeRecognizerDown setEnabled:enable]; - [_swipeRecognizerLeft setEnabled:enable]; - [_swipeRecognizerRight setEnabled:enable]; + if (!_deviceMotion) { + _deviceMotion = [VLCDeviceMotion new]; + _deviceMotion.delegate = self; + } + return _deviceMotion; } +- (void)setupForMediaProjection +{ + BOOL mediaHasProjection = [_vpc currentMediaProjection] == VLCMediaProjectionEquiRectangular; + _fov = mediaHasProjection ? DEFAULT_FOV : 0.f; + + [_panRecognizer setEnabled:mediaHasProjection]; + [_swipeRecognizerUp setEnabled:!mediaHasProjection]; + [_swipeRecognizerDown setEnabled:!mediaHasProjection]; + [_swipeRecognizerLeft setEnabled:!mediaHasProjection]; + [_swipeRecognizerRight setEnabled:!mediaHasProjection]; + + if (mediaHasProjection) { + [self.deviceMotion startDeviceMotion]; + } +} + +- (void)deviceMotionHasAttitudeWithDeviceMotion:(VLCDeviceMotion *)deviceMotion pitch:(double)pitch yaw:(double)yaw roll:(double)roll +{ + [_vpc updateViewpoint:yaw pitch:pitch roll:roll fov:_fov absolute:YES]; +} #pragma mark - controls - (IBAction)closePlayback:(id)sender @@ -1318,12 +1336,15 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom panType = VLCPanTypeBrightness; // only check for seeking gesture if on iPad , will overwrite last statements if true - if ([deviceType isEqualToString:@"iPad"]) { - if (location.y < 110) + if ([deviceType isEqualToString:@"iPad"] && location.y < 110) { panType = VLCPanTypeSeek; } - return panType; + if ([_vpc currentMediaProjection] == VLCMediaProjectionEquiRectangular) { + panType = VLCPanTypeProjection; + } + + return panType; } - (void)panRecognized:(UIPanGestureRecognizer*)panRecognizer @@ -1331,10 +1352,6 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom CGFloat panDirectionX = [panRecognizer velocityInView:self.view].x; CGFloat panDirectionY = [panRecognizer velocityInView:self.view].y; - if (panRecognizer.state == UIGestureRecognizerStateBegan) { - _currentPanType = _mediaHasProjection ? VLCPanTypeProjection : [self detectPanTypeForPan:panRecognizer]; - } - if (_currentPanType == VLCPanTypeSeek) { if (!_seekGestureEnabled) return; @@ -1405,7 +1422,7 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom _currentPanType = VLCPanTypeNone; //Invalidate saved location when the gesture is ended - if (_mediaHasProjection) + if ([_vpc currentMediaProjection] == VLCMediaProjectionEquiRectangular) _saveLocation = CGPointMake(-1.f, -1.f); } } diff --git a/VLC.xcodeproj/project.pbxproj b/VLC.xcodeproj/project.pbxproj index 6be8911ffec99d857a00e552928ec3d1a6462061..4d77843db7e9d50f120f1159f15f14376b390a20 100644 --- a/VLC.xcodeproj/project.pbxproj +++ b/VLC.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 4152F1621FEF19BD00F1908B /* KeychainCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4152F1611FEF19BD00F1908B /* KeychainCoordinator.swift */; }; 416DEFF61FEEA76A00F4FC59 /* LayoutAnchorContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416DEFF51FEEA76A00F4FC59 /* LayoutAnchorContainer.swift */; }; 4171D35018A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 4171D34F18A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.m */; }; + 416443862048419E00CAC646 /* DeviceMotion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 416443852048419E00CAC646 /* DeviceMotion.swift */; }; 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 */; }; @@ -742,6 +743,7 @@ 41273A3B1A955C4100A2EF77 /* VLCMigrationViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = VLCMigrationViewController.xib; path = Sources/VLCMigrationViewController.xib; sourceTree = SOURCE_ROOT; }; 412BE7521FC4947400ACCC42 /* VLCMediaData+VLCDragAndDrop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "VLCMediaData+VLCDragAndDrop.swift"; path = "Sources/VLCMediaData+VLCDragAndDrop.swift"; sourceTree = SOURCE_ROOT; }; 4152F1611FEF19BD00F1908B /* KeychainCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = KeychainCoordinator.swift; path = Sources/KeychainCoordinator.swift; sourceTree = "<group>"; }; + 416443852048419E00CAC646 /* DeviceMotion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceMotion.swift; path = Sources/DeviceMotion.swift; sourceTree = "<group>"; }; 416DEFF51FEEA76A00F4FC59 /* LayoutAnchorContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LayoutAnchorContainer.swift; path = Sources/LayoutAnchorContainer.swift; sourceTree = "<group>"; }; 4171D34E18A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCFolderCollectionViewFlowLayout.h; path = Sources/VLCFolderCollectionViewFlowLayout.h; sourceTree = SOURCE_ROOT; }; 4171D34F18A2C19000A16EF9 /* VLCFolderCollectionViewFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCFolderCollectionViewFlowLayout.m; path = Sources/VLCFolderCollectionViewFlowLayout.m; sourceTree = SOURCE_ROOT; }; @@ -1888,6 +1890,7 @@ 7D5F7AB9175265B2006CCCFA /* Playback */ = { isa = PBXGroup; children = ( + 416443852048419E00CAC646 /* DeviceMotion.swift */, DD8F842F1B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.h */, DD8F84301B00EB3B0009138A /* VLCPlaybackController+MediaLibrary.m */, 7D37848D183A98B6009EE944 /* VLCMovieViewController.h */, @@ -2934,7 +2937,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = VLC; - LastSwiftUpdateCheck = 0720; + LastSwiftUpdateCheck = 0930; LastUpgradeCheck = 0710; ORGANIZATIONNAME = VideoLAN; TargetAttributes = { @@ -3862,6 +3865,7 @@ 7DC19B0C1868D21800810BF7 /* VLCFirstStepsSixthPageViewController.m in Sources */, DD3EFEED1BDEBA3800B68579 /* VLCNetworkServerBrowserViewController.m in Sources */, DD3EABFC1BE14C4B003668DA /* UIViewController+VLCAlert.m in Sources */, + 416443862048419E00CAC646 /* DeviceMotion.swift in Sources */, 7D9289751877459B009108FD /* VLCFirstStepsThirdPageViewController.m in Sources */, 7D95610B1AF3E9E800779745 /* VLCMiniPlaybackView.m in Sources */, DD3EFF451BDEBCE500B68579 /* VLCLocalNetworkServiceBrowserManualConnect.m in Sources */,