Compare commits

...
178 Commits
Author SHA1 Message Date
Diego Waxemberg eac2d985e2 Created build v1.1.4 and removed empty icon sets 2016-12-14 22:05:47 -08:00
Cameron Gutman 61ea7f3f1c Update moonlight-common-c with support for GFE 3.2 2016-12-13 21:29:03 -08:00
Cameron Gutman 40f7faa1b1 Update moonlight-common-c project to recommended settings on Xcode 8.1 2016-10-29 19:55:22 -07:00
Diego Waxemberg 9e18b8021b Bumping app version for v1.1.3 2016-10-26 19:08:33 -07:00
Cameron Gutman ce95f2c153 Fix some pairing glitches and add a cancel button 2016-10-21 12:07:29 -07:00
Cameron Gutman fd50b71b16 Fix detection of running apps on GFE 3.1 2016-10-21 11:41:42 -07:00
Diego Waxemberg 39ab472cf6 Updated to use swift 3 2016-10-05 23:45:48 -07:00
Diego Waxemberg 48ba7eb2dc Bump version for v1.1.2 2016-10-05 23:00:46 -07:00
Diego Waxemberg 42edaa1bad Added DerivedData to gitignore 2016-10-05 22:58:38 -07:00
Diego Waxemberg 955fb59156 Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2016-10-05 22:57:43 -07:00
Diego Waxemberg 2fbc67ef00 Bumped version for v1.1.1 2016-10-05 22:56:40 -07:00
Cameron Gutman 23564a3028 Add support for GFE 3.0.7 2016-10-05 17:32:30 -07:00
Cameron Gutman 9a07d5a33a Display an error if attempting to close another session's app rather than silently failing 2016-09-24 21:26:50 -07:00
Cameron Gutman 84c037f235 Move the pull arrow up to the top of the left side and make it clickable on the PC view page 2016-09-24 20:39:43 -07:00
Cameron Gutman c13df82f5b Update common-c to fix Gen 3 servers 2016-09-24 19:09:21 -07:00
Cameron Gutman b15d61a5bf Allow existing host to be updated via the Add PC dialog 2016-09-24 18:53:52 -07:00
Cameron Gutman 5aff719984 Add message to enable GameStream for GFE 3.0 2016-09-24 18:51:55 -07:00
Cameron Gutman b0c2978405 Update common-c submodule with const char * change 2016-07-31 17:10:32 -07:00
Cameron Gutman 91dcb505de Fix displaying names of custom added apps on GFE 3.0 2016-07-31 14:40:08 -07:00
Cameron Gutman d1f35d938b Apply Xcode 8 recommended project settings 2016-07-31 12:02:35 -07:00
Cameron Gutman 359b822951 Migrate to Swift 2.3 for Xcode 8 2016-07-31 12:00:09 -07:00
Cameron Gutman 39580e4352 Fix wiki link 2016-05-30 12:23:41 -05:00
Cameron Gutman 7b3d099449 Use the same Controller object for player 0 and the on-screen controls so tapping on-screen buttons doesn't reset all physical controller input to 0. Fixes pressing L3 to run in some games. 2016-05-22 17:11:30 -05:00
Cameron Gutman b17c45e9ca Update common-c to include MTU fix for LTE streaming 2016-05-21 21:32:36 -05:00
Cameron Gutman 4c7a2cecdd Allow the user to slide between directions on the d-pad. This closes #222 2016-05-08 15:42:08 -04:00
Cameron Gutman 175074ece8 Tweaks to dragging behavior to match Moonlight Android 2016-05-08 15:09:43 -04:00
Cameron Gutman 8a5ec513bf Update common-c 2016-05-08 14:59:08 -04:00
Cameron Gutman 7cfb7f73a2 Fix some WOL issues including crashes and broken functionality with DNS names 2016-05-08 14:56:22 -04:00
Cameron Gutman c608685737 Update common-c with bugfixes 2016-04-27 02:24:54 -04:00
Cameron Gutman 3beca2fc72 Update moonlight-common-c to fix a couple crashing bugs 2016-04-18 16:46:59 -04:00
Cameron Gutman c59aafb4bb Merge pull request #215 from Mimiste/master
Drag and drop
2016-04-18 14:02:07 -04:00
Mimiste 256e40acdc 1 Second touch for the drag and drop
Changed the timer duration to 1 second to initiate the drag and drop
2016-04-18 19:44:00 +02:00
Mimiste 39b1b65e16 Merge remote-tracking branch 'moonlight-stream/master' 2016-04-16 18:56:02 +02:00
Cameron Gutman 1783abec13 Lock around LiStartConnection() and LiStopConnection() to fix thread-safety issues. This will hopefully address the crashes seen in 1.0.3 and 1.0.4. 2016-04-12 00:50:59 -04:00
David 983c65d399 Rewrote the Controller class in Swift (#216)
* Enabled Defines Modules for swift code

* Created bridge header, created swift Controller

-  Created Controller.swift
-  Created bridge header for use of objc in swift

* Finished porting Controller files to swift

* Added comments, created MoonlightUnitTest

-  Added comments for Controller.swift
-  Created MoonlightUnitTest for testing new class

* Started writing tests for ControllerUnitTests

-  General formatting
-  Wrote helper functions
-  Wrote tests for first four properties

* Finished writing Controller tests

* Removed commented out lines
2016-04-11 20:44:02 -07:00
Mimiste 4caa9672c9 Drag and drop
The drag and drop is now enabled only if touching with one finger.
The tap to drop does not fire another timer
2016-04-10 13:02:00 +02:00
Mimiste 15be6a3f75 Merge remote-tracking branch 'moonlight-stream/master' 2016-04-10 11:48:30 +02:00
Michelle Bergeron d38eb0a3ba s/current/currently 2016-04-09 23:12:59 -07:00
Mimiste e8ea942ad2 Drag and drop
Possibility to initiate a drag and drop

- Touch for 2 second to initiate a drag
- Move the cursor as usual
- Tap top drop
2016-04-08 00:12:59 +02:00
Diego Waxemberg cb68b10475 Removed "Headers" build phase from common and created v1.0.4 2016-03-31 20:36:07 -07:00
Cameron Gutman 11c854ce44 Update common-c to support Gen 7 2016-03-31 11:27:02 -04:00
Cameron Gutman 9636f4742b Implement pairing for Gen 7 servers 2016-03-31 11:20:18 -04:00
Cameron Gutman 5867317526 Move the submodule and subproject to their new locations 2016-03-31 07:59:35 -04:00
Cameron Gutman 8a8f7b6903 Remove old submodule 2016-03-31 07:23:37 -04:00
Diego Waxemberg 61b6e25a91 Bumping app version for 1.0.3 2016-03-08 22:35:06 -08:00
Diego Waxemberg 50cff820de Added app icon for ipad pro 2016-03-08 22:34:15 -08:00
Cameron Gutman 4e586a28c8 Update common-c to fix RTSP timeout issue 2016-03-08 13:15:33 -08:00
Cameron Gutman 0702b4ed57 Fix a performance regression in handling the applist response 2016-03-07 16:12:10 -08:00
Cameron Gutman 4a2132a682 Update common-c to support GFE 2.11 2016-03-07 14:45:05 -08:00
Diego Waxemberg ba81d1d6a9 Bumping version and creating build 1.0.2 2016-02-19 13:08:01 -08:00
Cameron Gutman 402ce4b3ec Update common-c to support Gen 5 servers 2016-02-19 15:09:37 -05:00
Cameron Gutman fc713453ad Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2016-02-16 10:38:25 -05:00
Cameron Gutman b222ccffbb Fix analysis warning 2016-02-16 10:37:59 -05:00
Michelle Bergeron 56ce7329d2 Point to website, add wiki link. 2016-02-15 22:39:32 -08:00
Michelle Bergeron 99ab6db557 Added note about Apple TV in effort to stave off some emails 2016-02-07 21:53:55 -08:00
Cameron Gutman d7adf96f3a Newer GFE versions don't mind resuming another device's stream 2016-02-06 23:10:36 -05:00
Cameron Gutman 0ae58c61a9 Remove apps from the database when they are removed from the app list 2016-01-21 16:24:02 -05:00
Cameron Gutman 2ec7d1d2f1 Use the main queue for the managed object context as a hack to prevent merge conflicts 2016-01-21 16:17:05 -05:00
Cameron Gutman ad1b9059ee Ensure the host matches for app entries 2016-01-21 15:01:15 -05:00
Cameron Gutman 4439c7cce6 Fix initial app list loading after pairing 2016-01-21 14:14:29 -05:00
Cameron Gutman b8a4093c75 Preserve app art when updating the app list 2016-01-21 14:03:07 -05:00
Cameron Gutman ec3748b26e Implement hash and isEqual for TemporaryApp and TemporaryHost 2016-01-21 13:34:34 -05:00
Cameron Gutman 1c1f22e047 Update the database on each server info poll 2016-01-21 12:09:49 -05:00
Cameron Gutman 9aa9b0fc5a Copy the pair state into the temporary host 2016-01-21 11:42:19 -05:00
Cameron Gutman f8e2ca8500 We can't hold onto managed objects in our temporary objects because they can disappear from under us, so do the lookup when we propagate values 2016-01-21 11:29:17 -05:00
Cameron Gutman 3076e29335 Basic database access is working 2015-12-02 00:25:38 -08:00
Cameron Gutman fe616d86c5 Reduce usage of DataManager 2015-12-01 20:56:08 -08:00
Cameron Gutman bfa4856bbe Move non-CoreData backed fields out of CoreData objects 2015-12-01 20:36:08 -08:00
Cameron Gutman 5ea92a7b48 Stop using CoreData-backed objects in any non-DataManager code 2015-12-01 20:31:24 -08:00
Diego Waxemberg 4ba71db7b2 bumped build version 2015-11-14 13:07:31 -08:00
Diego Waxemberg c1e6aeb43c Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-11-14 12:33:44 -08:00
Diego Waxemberg e3ffb66ef0 bumping version code 2015-11-14 12:33:41 -08:00
Cameron Gutman 5daa82b0ba Show the hosts in alphabetical order rather than in an undefined order 2015-11-13 19:55:18 -08:00
Cameron Gutman a8bcc6afba Split the work into 2 jobs per computer to retrieve assets faster 2015-11-13 19:52:35 -08:00
Cameron Gutman e6aa16ad01 Revert "Fix concurrent modification crash in app asset caching code"
This reverts commit ad0705d126.
2015-11-13 19:07:15 -08:00
Cameron Gutman ad0705d126 Fix concurrent modification crash in app asset caching code 2015-11-13 18:30:12 -08:00
Cameron Gutman 2f31f93bf8 Add support for GFE 2.8 2015-11-11 18:24:36 -08:00
Cameron Gutman ea3be613c5 Try 5 times to get the app list before failing 2015-11-11 18:14:59 -08:00
Cameron Gutman b495246f34 Only mark a PC offline if server info failed after 3 straight tries 2015-11-11 18:14:04 -08:00
Cameron Gutman 814470f4bf Set the default bitrate based on the selected resolution and FPS combo 2015-11-11 18:11:33 -08:00
Cameron Gutman 82293a08b6 Increase the request timeout to 7 seconds to give a bit more time for slow app lists to come in 2015-11-11 17:53:13 -08:00
Cameron Gutman 20d66336a7 Cache decoded UIImage objects for the scroll view to fix janky scrolling 2015-11-10 21:23:00 -08:00
Cameron Gutman c8441ec9fa Rasterize the cell layer to increase scrolling performance 2015-11-10 20:48:39 -08:00
Cameron Gutman f72135c227 Mark collection cells opaque for better performance 2015-11-10 20:47:09 -08:00
Michelle Bergeron 100e6e4ce8 Remove info about the beta 2015-11-09 21:53:58 -08:00
Michelle Bergeron ec8be20d62 Download link 2015-11-09 21:53:24 -08:00
Diego Waxemberg 55d48101ef Bumped build version
This is the first attempt at submission to the App Store
2015-11-01 00:12:39 -07:00
Cameron Gutman c36f4c5f84 Remove abort calls 2015-10-31 23:45:37 -07:00
Diego Waxemberg 06289ac4d2 No longer use IDFA, now generate UUID and persist in Core Data. Bumped version to 1.0.0 2015-10-31 23:04:32 -07:00
Cameron Gutman e6a2d5d425 Update project file after Xcode 7.1 2015-10-31 19:00:44 -07:00
Cameron Gutman ea8db9c4ea Update common with new bitrate logic 2015-10-31 19:00:05 -07:00
Cameron Gutman 3773e841d1 Update common to support GFE 2.7 2015-10-25 13:28:24 -07:00
Diego Waxemberg ad1ddd04f3 no longer allow multiple apps to be selected at the same time 2015-10-18 16:52:14 -07:00
Diego Waxemberg 67a8b232b9 added pull arrow to side of screen 2015-10-17 16:16:13 -07:00
Diego Waxemberg 5293c07fc0 fixed issue where we wouldn't terminate the stream on failure 2015-10-17 03:46:09 -07:00
Diego Waxemberg e3a42db007 On-screen controls revamp
- controls are bigger
- dead zone around buttons to avoid accidental mouse clicks and movement
- finished implementing control setup for AutoGCGamepad
- swiping to close stream requires swipe to 1/4 the screen width
- no longer send mouse movement if delta is too small
2015-10-17 03:02:55 -07:00
Diego Waxemberg 3b1462af22 removed support for native resolution stream 2015-10-16 23:38:14 -07:00
Cameron Gutman 74a0c5b1cd Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-30 20:44:26 -07:00
Cameron Gutman 05a5e4fa64 Fix a crash when apps are removed from GFE 2015-09-30 20:44:14 -07:00
Cameron Gutman b6445295a7 Use a temporary app object and database lock to avoid saving while the database is not in a consistent state 2015-09-30 20:34:52 -07:00
Diego Waxemberg 391605ef36 ignored the new xcsmblueprint files 2015-09-30 19:18:21 -07:00
Diego Waxemberg 695499dea9 host and app buttons now have feedback when tapped 2015-09-30 19:13:37 -07:00
Cameron Gutman 9ba7f35444 Require full-screen since the streaming game will be the primary interaction for the device 2015-09-30 18:00:52 -07:00
Cameron Gutman 37dc00735b Enabling bit code is causing linker errors when deploying to real devices for some reason. Turning it back off. 2015-09-29 00:06:27 -07:00
Cameron Gutman 920cbadc91 Add a workaround/hack to fix duplicating machines 2015-09-29 00:04:40 -07:00
Cameron Gutman bc53b4dc32 First stab at fixing on screen controls on various devices 2015-09-28 23:20:27 -07:00
Cameron Gutman 6015c38d17 Only display the native resolution dialog if the user has just chosen native resolution. Make the dialog a little nicer too. 2015-09-28 22:50:54 -07:00
Cameron Gutman 4ea8694a7d Fix status bar hiding while streaming on iPad 2015-09-28 21:49:46 -07:00
Cameron Gutman 00f01196fb Update placeholder app images to be the correct aspect ratio and invert the colors to better show against the new background 2015-09-28 21:40:10 -07:00
Diego Waxemberg 543639c93e Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-28 21:19:18 -07:00
Diego Waxemberg 1da877fed7 Changed theme to light/dark gray and updated launch screen. Also added a border and drop shadow to app icons 2015-09-28 21:18:35 -07:00
Cameron Gutman 396b5fc156 Update common 2015-09-28 19:22:28 -07:00
Cameron Gutman 297dfd4159 Update project file
- Change organization name
- Enable bit code
- Update Xcode compatibility version
2015-09-28 19:09:49 -07:00
Cameron Gutman 23e9d48b0d Update common-c and use the new LiInitializeXXX() functions 2015-08-16 12:27:21 -07:00
Cameron Gutman 9ec650a84f Zero audio renderer callbacks before populating 2015-08-12 01:18:22 -07:00
Cameron Gutman 90bdbc4ae0 Update common library 2015-08-12 01:11:38 -07:00
Cameron Gutman dd5f06723b Update common library to get assertions and a GFE 2.5.11 fix 2015-07-20 17:37:13 -07:00
Michelle Bergeron 55b2871b83 Update about beta program 2015-07-16 16:14:28 -07:00
Diego Waxemberg c8b13126d0 Adding build 0.9.2 2015-07-15 20:24:13 -07:00
Diego Waxemberg 96cfe0b70d bumping build number for new beta 2015-07-15 20:21:29 -07:00
Cameron Gutman 6dbb938368 Speed up app icon load time by 2 seconds by only waiting if it failed 2015-07-12 00:43:20 -07:00
Cameron Gutman 46fe7a8aed Don't show error messages if the PC isn't selected anymore 2015-07-12 00:30:44 -07:00
Cameron Gutman 3151ac6bf0 Remove hosts from discovery while they're handling operations the for UI. Sometimes these operations take a while and block the server from responding to our serverinfo queries that determine its online status. 2015-07-12 00:23:48 -07:00
Cameron Gutman dc5210f691 Propagate the running flag to the applist cache 2015-07-12 00:12:53 -07:00
Cameron Gutman 1f02265003 Fix a race condition that could cause an app to be populated with a null host 2015-07-11 23:59:09 -07:00
Cameron Gutman e4af9032e2 Implement a fast path to the app grid for online, paired machines with cached app lists. 2015-07-11 21:59:41 -07:00
Cameron Gutman e8650b2420 Don't use lightweight generics for Xcode 6 compatibility 2015-07-11 21:59:01 -07:00
Diego Waxemberg 9c6b718be2 fixed issue with apps duplicating in app list 2015-07-11 18:47:05 -07:00
Cameron Gutman 8f12114a56 Merge branch 'master' into persist-app-list 2015-07-11 01:38:30 -07:00
Cameron Gutman dc6ebffab1 Allow unpaired computer to be deleted. Remove the unpairing option since it hasn't worked for ages. 2015-07-11 01:29:28 -07:00
Cameron Gutman 13e894e9a3 Refactor app list to be non-static and sorted in alphabetical order 2015-07-11 01:28:52 -07:00
Cameron Gutman 4c95773131 Long clicking hosts that aren't paired doesn't bring up any useful options, so disable it 2015-07-11 00:13:58 -07:00
Cameron Gutman 38776a01e4 Only create an app if an app ID was found 2015-07-11 00:10:13 -07:00
Cameron Gutman b2563e534d Null terminate strings before passing them to BIO_puts 2015-07-10 22:33:09 -07:00
Diego Waxemberg 37f25c1f97 fixed some bugs with saving app list to database 2015-07-10 22:19:25 -07:00
Diego Waxemberg 642085ca32 App lists are now persisted in the database 2015-07-10 21:22:57 -07:00
Cameron Gutman 5dee29a21c Add a play indicator for running apps 2015-07-10 18:09:12 -07:00
Cameron Gutman b01d13976b Improve speed and reliability of host detection 2015-07-10 12:18:09 -07:00
Cameron Gutman ae1c83a011 Fix returning to the host selection screen after a failure 2015-07-10 11:52:27 -07:00
Cameron Gutman e5f962dc3f Perform stricter status checks during pairing to fix a crash when paired=3 2015-07-10 11:43:47 -07:00
Cameron Gutman 54dd79d2dd Remove OK button from pairing PIN dialog, since it dismisses automatically 2015-07-10 11:37:32 -07:00
Cameron Gutman 935fb6ffe3 Fix streaming over the external IP address when discovered via mDNS 2015-07-10 00:28:51 -07:00
Cameron Gutman 48d1c1a080 Commit host removals immediately so they remain if the app is unexpectedly terminated 2015-07-09 23:52:05 -07:00
Cameron Gutman 2d02ce2a1b Change the PC status to offline and return to the host selection screen if server info or applist is unavailable 2015-07-09 23:48:18 -07:00
Cameron Gutman 29fda59a72 Add applist and server info fetching error dialogs. Open the options menu when a user taps an offline PC. 2015-07-09 21:15:52 -07:00
Cameron Gutman 05f0dfd4f5 Replace dispatch_sync with dispatch_async in pairing 2015-07-09 21:02:19 -07:00
Cameron Gutman 0bdc5a83f1 Go directly to the app list after pairing like Android 2015-07-09 20:39:15 -07:00
Cameron Gutman 8688bf1210 Add failure handling for quitting apps 2015-07-09 20:33:23 -07:00
Cameron Gutman bf0858d57e Fix spelling mistake 2015-07-09 20:32:03 -07:00
Cameron Gutman 8d4d391310 For real this time - Update common to pickup Xcode 7 changes 2015-07-08 23:49:34 -07:00
Cameron Gutman 8fb15336c4 Update common to pickup Xcode 7 changes 2015-07-08 23:45:20 -07:00
Cameron Gutman 883385c42b Merge branch 'xcode-7.0' 2015-07-08 23:43:03 -07:00
Cameron Gutman 6d1139796e Cherry pick e58eb5f - Removing LimelightTests target 2015-07-08 23:25:37 -07:00
Cameron Gutman e58eb5f56a Remove LimelightTests target since it's old and unused 2015-07-08 23:21:05 -07:00
Cameron Gutman 2b0ce49646 Merge branch 'master' into xcode-7.0
Conflicts:
	limelight-common-c
2015-07-08 23:13:55 -07:00
Cameron Gutman 73364127d2 Fix pairing with GFE 2.4.5.57+ 2015-07-08 23:03:23 -07:00
Cameron Gutman 84a986bc88 Switch from deprecated NSURLConnection to NSURLSession 2015-07-08 22:35:25 -07:00
Cameron Gutman f13051aa31 Prepare for HTTP requests 2015-07-08 21:31:47 -07:00
Cameron Gutman 6bb559303b Remove executeRequest from HttpManager. It has some show-stopping bugs, like leaking semaphore counts (since it never waited) and being generally thread-unsafe. Implementing it in a way that would be asynchronous and thread-safe is a non-trivial task, so I've opted to remove it and change callers to use executeRequestSynchronously. 2015-07-08 21:26:01 -07:00
Cameron Gutman b7324f9a44 Remove a parameter from LiStartConnection 2015-07-08 19:17:58 -07:00
Cameron Gutman c0b2bbe552 Remove a parameter from LiStartConnection 2015-07-08 19:16:48 -07:00
Cameron Gutman 8c36cf40fd Update common for a leak fix and other minor bugs 2015-07-08 19:16:17 -07:00
Diego Waxemberg 717296269f updating common to xcode 7.0 settings 2015-07-04 11:23:31 -07:00
Diego Waxemberg 4be29abede updated project settings for xcode 7.0 2015-07-04 11:13:05 -07:00
Cameron Gutman 528af9684e Update common-c to fix scrolling issues 2015-06-25 21:54:39 -07:00
Cameron Gutman ff7a4ef190 Update common with better error messages 2015-06-25 00:11:09 -07:00
Cameron Gutman 99a2dbb956 Switch from deprecated UIAlertView to UIAlertController for pairing 2015-06-23 22:23:12 -07:00
Cameron Gutman 280341791a Use non-deprecated NSManagedObjectContext initializer 2015-06-23 22:09:08 -07:00
Cameron Gutman 1759565920 Removed supportedInterfaceOrientations since it didn't do anything and caused a warning on iOS 9 because the prototype seems to have changed 2015-06-23 22:01:59 -07:00
Cameron Gutman f57fa678f6 Escaping the URL strings is not required because no reserved characters are ever sent. Plus it's deprecated in iOS 9. 2015-06-23 21:58:32 -07:00
Cameron Gutman f8b5b16109 Create alert dialogs on the main thread 2015-06-23 21:46:58 -07:00
Cameron Gutman 005a678089 Disable App Transport Security since we need to make requests over HTTP and HTTPS to servers with self-signed certificates 2015-06-20 13:11:49 -07:00
Cameron Gutman 315dd53dcb Disable bitcode until native libraries are rebuilt for it 2015-06-20 13:06:02 -07:00
Cameron Gutman bb24495b3f Warning fix (char* -> const char*) 2015-06-19 20:53:14 -07:00
Cameron Gutman b9f2764990 Update common 2015-06-17 23:48:58 -07:00
Cameron Gutman a9a00629b1 Use API 1.1 common in preparation for IPv6 requirement 2015-06-17 23:32:00 -07:00
Diego Waxemberg 1223a9013f updated libopus and Opus build scrips 2015-06-01 22:25:56 -07:00
Diego Waxemberg ab019eef0f got rid of dumb compiler warnings 2015-06-01 00:36:21 -07:00
128 changed files with 3511 additions and 1205 deletions

No files matched your search

+2
View File
@@ -1,2 +1,4 @@
**/xcuserdata/ **/xcuserdata/
**/Moonlight.xcscmblueprint
Build Build
DerivedData
+3 -3
View File
@@ -1,3 +1,3 @@
[submodule "limelight-common-c"] [submodule "moonlight-common/moonlight-common-c"]
path = limelight-common-c path = moonlight-common/moonlight-common-c
url = git@github.com:limelight-stream/limelight-common-c.git url = https://github.com/moonlight-stream/moonlight-common-c.git
+27 -11
View File
@@ -31,43 +31,44 @@ do
exit 1 exit 1
fi fi
echo "Compiling source for $ARCH in directory $OPUS_DIR" echo "Compiling source for $ARCH in directory $OPUS_DIR"
echo "cd $OPUS_DIR"
cd $OPUS_DIR cd $OPUS_DIR
DIST_DIR=$DIST_DIR_BASE-$ARCH DIST_DIR=$DIST_DIR_BASE-$ARCH
echo "mkdir -p $DIST_DIR"
mkdir -p $DIST_DIR mkdir -p $DIST_DIR
CFLAGS_ARCH=$ARCH CFLAGS_ARCH=$ARCH
case $ARCH in case $ARCH in
armv7) armv7)
EXTRA_FLAGS="--with-pic --enable-fixed-point" EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-mcpu=cortex-a8 -mfpu=neon" EXTRA_CFLAGS="-mcpu=cortex-a8 -mfpu=neon -miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform" PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS${IOSSDK_VER} IOSSDK=iPhoneOS
;; ;;
armv7s) armv7s)
EXTRA_FLAGS="--with-pic --enable-fixed-point" EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-mcpu=cortex-a9 -mfpu=neon -miphoneos-version-min=6.0" EXTRA_CFLAGS="-mcpu=cortex-a9 -mfpu=neon -miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform" PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS${IOSSDK_VER} IOSSDK=iPhoneOS
;; ;;
aarch64) aarch64)
CFLAGS_ARCH="arm64" CFLAGS_ARCH="arm64"
EXTRA_FLAGS="--with-pic --enable-fixed-point" EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-miphoneos-version-min=7.1" EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform" PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS${IOSSDK_VER} IOSSDK=iPhoneOS
;; ;;
x86_64) x86_64)
EXTRA_FLAGS="--with-pic" EXTRA_FLAGS="--with-pic"
EXTRA_CFLAGS="-miphoneos-version-min=7.1" EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform" PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
IOSSDK=iPhoneSimulator${IOSSDK_VER} IOSSDK=iPhoneSimulator
;; ;;
i386) i386)
EXTRA_FLAGS="--with-pic" EXTRA_FLAGS="--with-pic"
EXTRA_CFLAGS="-miphoneos-version-min=7.1" EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform" PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
IOSSDK=iPhoneSimulator${IOSSDK_VER} IOSSDK=iPhoneSimulator
;; ;;
*) *)
echo "Unsupported architecture ${ARCH}" echo "Unsupported architecture ${ARCH}"
@@ -76,7 +77,7 @@ do
esac esac
echo "Configuring opus for $ARCH..." echo "Configuring opus for $ARCH..."
echo "./autogen.sh"
./autogen.sh ./autogen.sh
CFLAGS="-g -O2 -pipe -arch ${CFLAGS_ARCH} \ CFLAGS="-g -O2 -pipe -arch ${CFLAGS_ARCH} \
@@ -86,7 +87,10 @@ do
LDFLAGS="-arch ${CFLAGS_ARCH} \ LDFLAGS="-arch ${CFLAGS_ARCH} \
-isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \ -isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
-L${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/lib" -L${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/lib"
echo "CFLAGS=$CFLAGS"
echo "LDFLAGS=$LDFLAGS"
export CFLAGS export CFLAGS
export LDFLAGS export LDFLAGS
@@ -100,7 +104,15 @@ do
export NM="/usr/bin/nm" export NM="/usr/bin/nm"
export RANLIB="/usr/bin/ranlib" export RANLIB="/usr/bin/ranlib"
export STRIP="/usr/bin/strip" export STRIP="/usr/bin/strip"
echo "./configure \
--prefix=$DIST_DIR \
--host=${ARCH}-apple-darwin \
--with-sysroot=${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
--enable-static=yes \
--enable-shared=no \
--disable-doc \
${EXTRA_FLAGS}"
./configure \ ./configure \
--prefix=$DIST_DIR \ --prefix=$DIST_DIR \
--host=${ARCH}-apple-darwin \ --host=${ARCH}-apple-darwin \
@@ -111,10 +123,14 @@ do
${EXTRA_FLAGS} ${EXTRA_FLAGS}
echo "Installing opus for $ARCH..." echo "Installing opus for $ARCH..."
echo "make clean"
make clean make clean
echo "make -j$NJOB V=1"
make -j$NJOB V=1 make -j$NJOB V=1
echo "make install"
make install make install
echo "cd $SCRIPT_DIR"
cd $SCRIPT_DIR cd $SCRIPT_DIR
if [ -d $DIST_DIR/bin ] if [ -d $DIST_DIR/bin ]
-1
View File
@@ -7,7 +7,6 @@ source config.sh
SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) ) SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) )
DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"} DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"}
git submodule update --init opus
cd opus cd opus
git checkout master git checkout master
git pull origin master git pull origin master
Binary file not shown.
+43 -25
View File
@@ -1,33 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A279b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB"> <navigationController id="vV9-32-ww6">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/> <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
<subviews> <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Moonlight Stream. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye"> <autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="19" y="439" width="444" height="21"/> <animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </navigationBar>
<nil key="highlightedColor"/> <viewControllers>
<variation key="widthClass=compact"> <viewController id="l6V-ue-5Om">
<fontDescription key="fontDescription" type="system" pointSize="11"/> <layoutGuides>
</variation> <viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
</label> <viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
</subviews> </layoutGuides>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
<constraints> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/> <animations/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/> <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</constraints> </view>
<nil key="simulatedStatusBarMetrics"/> <navigationItem key="navigationItem" id="rW0-BH-s7l">
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
<point key="canvasLocation" x="404" y="445"/> <button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
</view> <rect key="frame" x="-23" y="-15" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</state>
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
</button>
</barButtonItem>
</navigationItem>
</viewController>
</viewControllers>
</navigationController>
</objects> </objects>
<resources>
<image name="Logo" width="32" height="32"/>
</resources>
</document> </document>
-18
View File
@@ -1,18 +0,0 @@
//
// App.h
// Moonlight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface App : NSObject
@property NSString* appId;
@property NSString* appName;
@property UIImage* appImage;
@property BOOL isRunning;
@end
-15
View File
@@ -1,15 +0,0 @@
//
// App.m
// Moonlight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import "App.h"
#import "HttpManager.h"
@implementation App
@synthesize appId, appName, appImage, isRunning;
@end
+13
View File
@@ -0,0 +1,13 @@
//
// AppCollectionView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppCollectionView : UICollectionView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// AppCollectionView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "AppCollectionView.h"
@implementation AppCollectionView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
+11 -31
View File
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext; NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) { if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately. Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
} }
} }
} }
@@ -103,7 +100,7 @@ static NSOperationQueue* mainQueue;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) { if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init]; _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator]; [_managedObjectContext setPersistentStoreCoordinator:coordinator];
} }
return _managedObjectContext; return _managedObjectContext;
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
/* // Log the error
Replace this implementation with code to handle the error appropriately. Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. // Drop the database
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
Typical reasons for an error here include:
* The persistent store is not accessible; // Try again
* The schema for the persistent store is incompatible with current managed object model. return [self persistentStoreCoordinator];
Check the error message to determine what the actual problem was. }
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator; return _persistentStoreCoordinator;
} }
+13
View File
@@ -0,0 +1,13 @@
//
// ComputerScrollView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ComputerScrollView : UIScrollView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// ComputerScrollView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "ComputerScrollView.h"
@implementation ComputerScrollView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
+4 -2
View File
@@ -11,14 +11,16 @@
@interface CryptoManager : NSObject @interface CryptoManager : NSObject
+ (void) generateKeyPairUsingSSl; + (void) generateKeyPairUsingSSl;
+ (NSString*) getUniqueID;
+ (NSData*) readCertFromFile; + (NSData*) readCertFromFile;
+ (NSData*) readKeyFromFile; + (NSData*) readKeyFromFile;
+ (NSData*) readP12FromFile; + (NSData*) readP12FromFile;
+ (NSData*) getSignatureFromCert:(NSData*)cert; + (NSData*) getSignatureFromCert:(NSData*)cert;
+ (NSData*) nullTerminateString:(NSData*)data;
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN; - (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN;
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN;
- (NSData*) SHA1HashData:(NSData*)data; - (NSData*) SHA1HashData:(NSData*)data;
- (NSData*) SHA256HashData:(NSData*)data;
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key; - (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key; - (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert; - (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
+25 -22
View File
@@ -8,7 +8,6 @@
#import "CryptoManager.h" #import "CryptoManager.h"
#import "mkcert.h" #import "mkcert.h"
#import <AdSupport/ASIdentifierManager.h>
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/sha.h> #include <openssl/sha.h>
@@ -17,19 +16,31 @@
#include <openssl/evp.h> #include <openssl/evp.h>
@implementation CryptoManager @implementation CryptoManager
static const int SHA1_DIGEST_LENGTH = 20; static const int SHA1_HASH_LENGTH = 20;
static const int SHA256_HASH_LENGTH = 32;
static NSData* key = nil; static NSData* key = nil;
static NSData* cert = nil; static NSData* cert = nil;
static NSData* p12 = nil; static NSData* p12 = nil;
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN { - (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN {
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)]; return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
} }
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN {
return [[self SHA256HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
}
- (NSData*) SHA1HashData:(NSData*)data { - (NSData*) SHA1HashData:(NSData*)data {
unsigned char sha1[SHA1_DIGEST_LENGTH]; unsigned char sha1[SHA1_HASH_LENGTH];
SHA1([data bytes], [data length], sha1); SHA1([data bytes], [data length], sha1);
NSData* bytes = [NSData dataWithBytes:sha1 length:20]; NSData* bytes = [NSData dataWithBytes:sha1 length:sizeof(sha1)];
return bytes;
}
- (NSData*) SHA256HashData:(NSData*)data {
unsigned char sha256[SHA256_HASH_LENGTH];
SHA256([data bytes], [data length], sha256);
NSData* bytes = [NSData dataWithBytes:sha256 length:sizeof(sha256)];
return bytes; return bytes;
} }
@@ -76,8 +87,14 @@ static NSData* p12 = nil;
return (((int)[data length] + 15) / 16) * 16; return (((int)[data length] + 15) / 16) * 16;
} }
+ (NSData*) nullTerminateString:(NSData*)data {
NSMutableData* mutData = [NSMutableData dataWithData:data];
[mutData appendBytes:"" length:1];
return mutData;
}
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert { - (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert {
const char* buffer = [cert bytes]; const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
X509* x509; X509* x509;
BIO* bio = BIO_new(BIO_s_mem()); BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer); BIO_puts(bio, buffer);
@@ -105,7 +122,7 @@ static NSData* p12 = nil;
} }
- (NSData *)signData:(NSData *)data withKey:(NSData *)key { - (NSData *)signData:(NSData *)data withKey:(NSData *)key {
const char* buffer = [key bytes]; const char* buffer = [[CryptoManager nullTerminateString:key] bytes];
BIO* bio = BIO_new(BIO_s_mem()); BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer); BIO_puts(bio, buffer);
@@ -188,7 +205,7 @@ static NSData* p12 = nil;
} }
+ (NSData *)getSignatureFromCert:(NSData *)cert { + (NSData *)getSignatureFromCert:(NSData *)cert {
const char* buffer = [cert bytes]; const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
X509* x509; X509* x509;
BIO* bio = BIO_new(BIO_s_mem()); BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer); BIO_puts(bio, buffer);
@@ -223,18 +240,4 @@ static NSData* p12 = nil;
}); });
} }
+ (NSString*) getUniqueID {
// generate a UUID
NSUUID* uuid = [ASIdentifierManager sharedManager].advertisingIdentifier;
NSString* idString = [NSString stringWithString:[uuid UUIDString]];
// we need a 16byte hex-string so we take the last 17 characters
// and remove the '-' to get a 16 character string
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
//Log(LOG_D, @"Unique ID: %@", uniqueId);
return [NSString stringWithString:uniqueId];
}
@end @end
+15
View File
@@ -0,0 +1,15 @@
//
// IdManager.h
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IdManager : NSObject
+ (NSString*) getUniqueId;
@end
+32
View File
@@ -0,0 +1,32 @@
//
// IdManager.m
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "IdManager.h"
#import "DataManager.h"
@implementation IdManager
+ (NSString*) getUniqueId {
DataManager* dataMan = [[DataManager alloc] init];
NSString* uniqueId = [dataMan getUniqueId];
if (uniqueId == nil) {
uniqueId = [IdManager generateUniqueId];
[dataMan updateUniqueId:uniqueId];
Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId);
}
return uniqueId;
}
+ (NSString*) generateUniqueId {
UInt64 uuidLong = ((UInt64) arc4random() << 32) | arc4random();
return [NSString stringWithFormat:@"%016llx", uuidLong];
}
@end
-2
View File
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
if (*pkeyp == NULL) { if (*pkeyp == NULL) {
if ((pk=EVP_PKEY_new()) == NULL) { if ((pk=EVP_PKEY_new()) == NULL) {
abort();
return(0); return(0);
} }
} else { } else {
@@ -102,7 +101,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL); rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
if (!EVP_PKEY_assign_RSA(pk, rsa)) { if (!EVP_PKEY_assign_RSA(pk, rsa)) {
abort();
goto err; goto err;
} }
@@ -0,0 +1,25 @@
//
// App+CoreDataProperties.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
// to keep your implementation up to date with your model.
//
#import "App.h"
NS_ASSUME_NONNULL_BEGIN
@interface App (CoreDataProperties)
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) Host *host;
@end
NS_ASSUME_NONNULL_END
+18
View File
@@ -0,0 +1,18 @@
//
// App.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Host;
@interface App : NSManagedObject
@end
#import "App+CoreDataProperties.h"
+13
View File
@@ -0,0 +1,13 @@
//
// App.m
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import "App.h"
@implementation App
@end
+15 -9
View File
@@ -7,19 +7,25 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Settings.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "Host.h" #import "TemporaryHost.h"
#import "TemporaryApp.h"
#import "TemporarySettings.h"
@interface DataManager : NSObject @interface DataManager : NSObject
@property (strong, nonatomic) AppDelegate* appDelegate;
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls; - (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
- (Settings*) retrieveSettings;
- (NSArray*) retrieveHosts; - (NSArray*) getHosts;
- (void) saveHosts; - (void) updateHost:(TemporaryHost*)host;
- (Host*) createHost; - (void) updateAppsForExistingHost:(TemporaryHost *)host;
- (void) removeHost:(Host*)host; - (void) updateIconForExistingApp:(TemporaryApp*)app;
- (void) removeHost:(TemporaryHost*)host;
- (void) removeApp:(TemporaryApp*)app;
- (TemporarySettings*) getSettings;
- (void) updateUniqueId:(NSString*)uniqueId;
- (NSString*) getUniqueId;
@end @end
+171 -32
View File
@@ -7,37 +7,132 @@
// //
#import "DataManager.h" #import "DataManager.h"
#import "TemporaryApp.h"
#import "TemporarySettings.h"
#import "Settings.h"
@implementation DataManager @implementation DataManager {
NSManagedObjectContext *_managedObjectContext;
AppDelegate *_appDelegate;
}
- (id) init { - (id) init {
self = [super init]; self = [super init];
self.appDelegate = [[UIApplication sharedApplication] delegate];
_appDelegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
return self; return self;
} }
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls { - (void) updateUniqueId:(NSString*)uniqueId {
Settings* settingsToSave = [self retrieveSettings]; [_managedObjectContext performBlockAndWait:^{
settingsToSave.framerate = [NSNumber numberWithInteger:framerate]; [self retrieveSettings].uniqueId = uniqueId;
// Bitrate is persisted in kbps [self saveData];
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate]; }];
settingsToSave.height = [NSNumber numberWithInteger:height]; }
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
NSError* error; - (NSString*) getUniqueId {
if (![[self.appDelegate managedObjectContext] save:&error]) { __block NSString *uid;
Log(LOG_E, @"Unable to save settings to database: %@", error);
} [_managedObjectContext performBlockAndWait:^{
[self.appDelegate saveContext]; uid = [self retrieveSettings].uniqueId;
}];
return uid;
}
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
[_managedObjectContext performBlockAndWait:^{
Settings* settingsToSave = [self retrieveSettings];
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
// Bitrate is persisted in kbps
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
settingsToSave.height = [NSNumber numberWithInteger:height];
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
[self saveData];
}];
}
- (void) updateHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
// Add a new persistent managed object if one doesn't exist
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:_managedObjectContext];
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
// Push changes from the temp host to the persistent one
[host propagateChangesToParent:parent];
[self saveData];
}];
}
- (void) updateAppsForExistingHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
// The host must exist to be updated
return;
}
NSMutableSet *applist = [[NSMutableSet alloc] init];
NSArray *appRecords = [self fetchRecords:@"App"];
for (TemporaryApp* app in host.appList) {
// Add a new persistent managed object if one doesn't exist
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:appRecords];
if (parentApp == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:_managedObjectContext];
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
[app propagateChangesToParent:parentApp withHost:parent];
[applist addObject:parentApp];
}
parent.appList = applist;
[self saveData];
}];
}
- (void) updateIconForExistingApp:(TemporaryApp*)app {
[_managedObjectContext performBlockAndWait:^{
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (parentApp == nil) {
// The app must exist to be updated
return;
}
parentApp.image = app.image;
[self saveData];
}];
}
- (TemporarySettings*) getSettings {
__block TemporarySettings *tempSettings;
[_managedObjectContext performBlockAndWait:^{
tempSettings = [[TemporarySettings alloc] initFromSettings:[self retrieveSettings]];
}];
return tempSettings;
} }
- (Settings*) retrieveSettings { - (Settings*) retrieveSettings {
NSArray* fetchedRecords = [self fetchRecords:@"Settings"]; NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
if (fetchedRecords.count == 0) { if (fetchedRecords.count == 0) {
// create a new settings object with the default values // create a new settings object with the default values
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:_managedObjectContext];
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
return settings; return settings;
} else { } else {
@@ -46,40 +141,84 @@
} }
} }
- (Host*) createHost { - (void) removeApp:(TemporaryApp*)app {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]]; [_managedObjectContext performBlockAndWait:^{
Host* host = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
return host; if (managedApp != nil) {
[_managedObjectContext deleteObject:managedApp];
[self saveData];
}
}];
} }
- (void) removeHost:(Host*)host { - (void) removeHost:(TemporaryHost*)host {
[[self.appDelegate managedObjectContext] deleteObject:host]; [_managedObjectContext performBlockAndWait:^{
Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (managedHost != nil) {
[_managedObjectContext deleteObject:managedHost];
[self saveData];
}
}];
} }
- (void) saveHosts { - (void) saveData {
NSError* error; NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) { if (![_managedObjectContext save:&error]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error); Log(LOG_E, @"Unable to save hosts to database: %@", error);
} }
[self.appDelegate saveContext];
[_appDelegate saveContext];
} }
- (NSArray*) retrieveHosts { - (NSArray*) getHosts {
return [self fetchRecords:@"Host"]; __block NSMutableArray *tempHosts = [[NSMutableArray alloc] init];
[_managedObjectContext performBlockAndWait:^{
NSArray *hosts = [self fetchRecords:@"Host"];
for (Host* host in hosts) {
[tempHosts addObject:[[TemporaryHost alloc] initFromHost:host]];
}
}];
return tempHosts;
}
// Only call from within performBlockAndWait!!!
- (Host*) getHostForTemporaryHost:(TemporaryHost*)tempHost withHostRecords:(NSArray*)hosts {
for (Host* host in hosts) {
if ([tempHost.uuid isEqualToString:host.uuid]) {
return host;
}
}
return nil;
}
// Only call from within performBlockAndWait!!!
- (App*) getAppForTemporaryApp:(TemporaryApp*)tempApp withAppRecords:(NSArray*)apps {
for (App* app in apps) {
if ([app.id isEqualToString:tempApp.id] &&
[app.host.uuid isEqualToString:app.host.uuid]) {
return app;
}
}
return nil;
} }
- (NSArray*) fetchRecords:(NSString*)entityName { - (NSArray*) fetchRecords:(NSString*)entityName {
NSArray* fetchedRecords;
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init]; NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity]; [fetchRequest setEntity:entity];
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
NSError* error; NSError* error;
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error]; fetchedRecords = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
//TODO: handle errors //TODO: handle errors
return fetchedRecords; return fetchedRecords;
} }
@end @end
@@ -0,0 +1,38 @@
//
// Host+CoreDataProperties.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
// to keep your implementation up to date with your model.
//
#import "Host.h"
NS_ASSUME_NONNULL_BEGIN
@interface Host (CoreDataProperties)
@property (nullable, nonatomic, retain) NSString *address;
@property (nullable, nonatomic, retain) NSString *externalAddress;
@property (nullable, nonatomic, retain) NSString *localAddress;
@property (nullable, nonatomic, retain) NSString *mac;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) NSNumber *pairState;
@property (nullable, nonatomic, retain) NSString *uuid;
@property (nullable, nonatomic, retain) NSSet *appList;
@end
@interface Host (CoreDataGeneratedAccessors)
- (void)addAppListObject:(NSManagedObject *)value;
- (void)removeAppListObject:(NSManagedObject *)value;
- (void)addAppList:(NSSet *)values;
- (void)removeAppList:(NSSet *)values;
@end
NS_ASSUME_NONNULL_END
+4 -11
View File
@@ -2,8 +2,8 @@
// Host.h // Host.h
// Moonlight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Moonlight Stream. All rights reserved. // Copyright © 2015 Limelight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -12,13 +12,6 @@
@interface Host : NSManagedObject @interface Host : NSManagedObject
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * address;
@property (nonatomic, retain) NSString * localAddress;
@property (nonatomic, retain) NSString * externalAddress;
@property (nonatomic, retain) NSString * uuid;
@property (nonatomic, retain) NSString * mac;
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@end @end
#import "Host+CoreDataProperties.h"
+2 -12
View File
@@ -2,22 +2,12 @@
// Host.m // Host.m
// Moonlight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Moonlight Stream. All rights reserved. // Copyright © 2015 Limelight Stream. All rights reserved.
// //
#import "Host.h" #import "Host.h"
@implementation Host @implementation Host
@dynamic name;
@dynamic address;
@dynamic localAddress;
@dynamic externalAddress;
@dynamic uuid;
@dynamic mac;
@dynamic pairState;
@synthesize online;
@end @end
+1
View File
@@ -17,5 +17,6 @@
@property (nonatomic, retain) NSNumber * height; @property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width; @property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls; @property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@end @end
+1
View File
@@ -16,5 +16,6 @@
@dynamic height; @dynamic height;
@dynamic width; @dynamic width;
@dynamic onscreenControls; @dynamic onscreenControls;
@dynamic uniqueId;
@end @end
+30
View File
@@ -0,0 +1,30 @@
//
// TemporaryApp.h
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TemporaryHost.h"
#import "App.h"
@interface TemporaryApp : NSObject
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) TemporaryHost *host;
NS_ASSUME_NONNULL_BEGIN
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost;
- (NSComparisonResult)compareName:(TemporaryApp *)other;
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host;
NS_ASSUME_NONNULL_END
@end
+52
View File
@@ -0,0 +1,52 @@
//
// TemporaryApp.m
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryApp
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost {
self = [self init];
self.id = app.id;
self.image = app.image;
self.name = app.name;
self.host = tempHost;
return self;
}
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host {
parent.id = self.id;
parent.name = self.name;
parent.host = host;
}
- (NSComparisonResult)compareName:(TemporaryApp *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.host.uuid hash] * 31 + [self.id intValue];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[App class]]) {
return NO;
}
return [self.host.uuid isEqualToString:((App*)object).host.uuid] &&
[self.id isEqualToString:((App*)object).id];
}
@end
+38
View File
@@ -0,0 +1,38 @@
//
// TemporaryHost.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Utils.h"
#import "Host.h"
@interface TemporaryHost : NSObject
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic, nullable) NSString * activeAddress;
@property (nonatomic, nullable) NSString * currentGame;
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, retain) NSString *address;
@property (nonatomic, retain) NSString *externalAddress;
@property (nonatomic, retain) NSString *localAddress;
@property (nonatomic, retain) NSString *mac;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *uuid;
@property (nonatomic, retain) NSMutableSet *appList;
- (id) initFromHost:(Host*)host;
- (NSComparisonResult)compareName:(TemporaryHost *)other;
- (void) propagateChangesToParent:(Host*)host;
NS_ASSUME_NONNULL_END
@end
+78
View File
@@ -0,0 +1,78 @@
//
// TemporaryHost.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "DataManager.h"
#import "TemporaryHost.h"
#import "Host.h"
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryHost
- (id) init {
self = [super init];
self.appList = [[NSMutableSet alloc] init];
self.currentGame = @"0";
return self;
}
- (id) initFromHost:(Host*)host {
self = [self init];
self.address = host.address;
self.externalAddress = host.externalAddress;
self.localAddress = host.localAddress;
self.mac = host.mac;
self.name = host.name;
self.uuid = host.uuid;
self.pairState = [host.pairState intValue];
NSMutableSet *appList = [[NSMutableSet alloc] init];
for (App* app in host.appList) {
TemporaryApp *tempApp = [[TemporaryApp alloc] initFromApp:app withTempHost:self];
[appList addObject:tempApp];
}
self.appList = appList;
return self;
}
- (void) propagateChangesToParent:(Host*)parentHost {
parentHost.address = self.address;
parentHost.externalAddress = self.externalAddress;
parentHost.localAddress = self.localAddress;
parentHost.mac = self.mac;
parentHost.name = self.name;
parentHost.uuid = self.uuid;
parentHost.pairState = [NSNumber numberWithInt:self.pairState];
}
- (NSComparisonResult)compareName:(TemporaryHost *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.uuid hash];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Host class]]) {
return NO;
}
return [self.uuid isEqualToString:((Host*)object).uuid];
}
@end
+25
View File
@@ -0,0 +1,25 @@
//
// TemporarySettings.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Settings.h"
@interface TemporarySettings : NSObject
@property (nonatomic, retain) Settings * parent;
@property (nonatomic, retain) NSNumber * bitrate;
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
- (id) initFromSettings:(Settings*)settings;
@end
+28
View File
@@ -0,0 +1,28 @@
//
// TemporarySettings.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporarySettings.h"
@implementation TemporarySettings
- (id) initFromSettings:(Settings*)settings {
self = [self init];
self.parent = settings;
self.bitrate = settings.bitrate;
self.framerate = settings.framerate;
self.height = settings.height;
self.width = settings.width;
self.onscreenControls = settings.onscreenControls;
self.uniqueId = settings.uniqueId;
return self;
}
@end
+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "a_button_80x80@2x.png",
"filename" : "a_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "a_button_120x120@3x.png",
"filename" : "a_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "a_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -71,6 +71,12 @@
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_152x152_@2x.png", "filename" : "app_icon_152x152_@2x.png",
"scale" : "2x" "scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "app_icon_167x167_@2x.png",
"scale" : "2x"
} }
], ],
"info" : { "info" : {
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "b_button_80x80@2x.png",
"filename" : "b_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "b_button_120x120@3x.png",
"filename" : "b_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "b_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "down_61x75@2x.png",
"filename" : "down_31x38@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "down_93x114@3x.png",
"filename" : "down_61x75@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "down_93x114@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "left_76x61@2x.png",
"filename" : "left_38x31@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "left_114x92@3x.png",
"filename" : "left_76x61@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "left_114x92@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+21
View File
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "play.png"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "pull-arrow-light-14x31@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-28x61@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-42x92@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "right_75x61@2x.png",
"filename" : "right_38x31@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "right_114x93@3x.png",
"filename" : "right_75x61@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "right_114x93@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "up_61x76@2x.png",
"filename" : "up_31x39@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "up_93x116@3x.png",
"filename" : "up_61x76@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "up_93x116@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "x_button_80x80@2x.png",
"filename" : "x_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "x_button_120x120@3x.png",
"filename" : "x_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "x_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "filename" : "y_button_80x80@2x.png",
"filename" : "y_button_40x40@1x.png" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "filename" : "y_button_120x120@3x.png",
"filename" : "y_button_80x80@2x.png" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x"
"filename" : "y_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

-23
View File
@@ -1,23 +0,0 @@
//
// Controller.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Controller : NSObject
@property (nonatomic) int playerIndex;
@property (nonatomic) int lastButtonFlags;
@property (nonatomic) int emulatingButtonFlags;
@property (nonatomic) char lastLeftTrigger;
@property (nonatomic) char lastRightTrigger;
@property (nonatomic) short lastLeftStickX;
@property (nonatomic) short lastLeftStickY;
@property (nonatomic) short lastRightStickX;
@property (nonatomic) short lastRightStickY;
@end
-15
View File
@@ -1,15 +0,0 @@
//
// Controller.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "Controller.h"
@implementation Controller
@synthesize playerIndex;
@synthesize lastButtonFlags, emulatingButtonFlags, lastLeftTrigger, lastRightTrigger;
@synthesize lastLeftStickX, lastLeftStickY, lastRightStickX, lastRightStickY;
@end
+26
View File
@@ -0,0 +1,26 @@
//
// Controller.swift
// Moonlight
//
// Created by David Aghassi on 4/11/16.
// Copyright © 2016 Moonlight Stream. All rights reserved.
//
import Foundation
@objc
/**
Defines a controller layout
*/
class Controller: NSObject {
// Swift requires initial properties
var playerIndex: CInt = 0 // Controller number (e.g. 1, 2 ,3 etc)
var lastButtonFlags: CInt = 0
var emulatingButtonFlags: CInt = 0
var lastLeftTrigger: CChar = 0 // Last left trigger pressed
var lastRightTrigger: CChar = 0 // Last right trigger pressed
var lastLeftStickX: CShort = 0 // Last X direction the left joystick went
var lastLeftStickY: CShort = 0 // Last Y direction the left joystick went
var lastRightStickX: CShort = 0 // Last X direction the right joystick went
var lastRightStickY: CShort = 0 // Last Y direction the right joystick went
}
+5 -1
View File
@@ -7,7 +7,10 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Controller.h"
// Swift
#import "Moonlight-Swift.h"
@class Controller;
@class OnScreenControls; @class OnScreenControls;
@@ -29,6 +32,7 @@
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags; -(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
-(void) updateFinished:(Controller*)controller; -(void) updateFinished:(Controller*)controller;
-(Controller*) getOscController;
@property (nonatomic, strong) id connectObserver; @property (nonatomic, strong) id connectObserver;
@property (nonatomic, strong) id disconnectObserver; @property (nonatomic, strong) id disconnectObserver;
+24 -3
View File
@@ -8,9 +8,12 @@
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
// Swift
#import "Moonlight-Swift.h"
@class Controller;
@import GameController; @import GameController;
@implementation ControllerSupport { @implementation ControllerSupport {
@@ -19,6 +22,10 @@
OnScreenControls *_osc; OnScreenControls *_osc;
// This controller object is shared between on-screen controls
// and player 0
Controller *_player0osc;
char _controllerNumbers; char _controllerNumbers;
#define EMULATING_SELECT 0x1 #define EMULATING_SELECT 0x1
@@ -272,9 +279,17 @@
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (!(_controllerNumbers & (1 << i))) { if (!(_controllerNumbers & (1 << i))) {
_controllerNumbers |= (1 << i); _controllerNumbers |= (1 << i);
Controller* limeController = [[Controller alloc] init];
controller.playerIndex = i; controller.playerIndex = i;
limeController.playerIndex = i;
Controller* limeController;
if (i == 0) {
// Player 0 shares a controller object with the on-screen controls
limeController = _player0osc;
} else {
limeController = [[Controller alloc] init];
limeController.playerIndex = i;
}
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]]; [_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
Log(LOG_I, @"Assigning controller index: %d", i); Log(LOG_I, @"Assigning controller index: %d", i);
@@ -283,6 +298,10 @@
} }
} }
-(Controller*) getOscController {
return _player0osc;
}
-(id) init -(id) init
{ {
self = [super init]; self = [super init];
@@ -290,6 +309,8 @@
_controllerStreamLock = [[NSLock alloc] init]; _controllerStreamLock = [[NSLock alloc] init];
_controllers = [[NSMutableDictionary alloc] init]; _controllers = [[NSMutableDictionary alloc] init];
_controllerNumbers = 0; _controllerNumbers = 0;
_player0osc = [[Controller alloc] init];
_player0osc.playerIndex = 0;
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]); Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
for (GCController* controller in [GCController controllers]) { for (GCController* controller in [GCController controllers]) {
@@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
+278 -95
View File
@@ -8,9 +8,12 @@
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "Controller.h" //#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
#import "Moonlight-Swift.h"
@class Controller;
#define UPDATE_BUTTON(x, y) (buttonFlags = \ #define UPDATE_BUTTON(x, y) (buttonFlags = \
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x))) (y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
@@ -41,10 +44,7 @@
UITouch* _bTouch; UITouch* _bTouch;
UITouch* _xTouch; UITouch* _xTouch;
UITouch* _yTouch; UITouch* _yTouch;
UITouch* _upTouch; UITouch* _dpadTouch;
UITouch* _downTouch;
UITouch* _leftTouch;
UITouch* _rightTouch;
UITouch* _lsTouch; UITouch* _lsTouch;
UITouch* _rsTouch; UITouch* _rsTouch;
UITouch* _startTouch; UITouch* _startTouch;
@@ -63,25 +63,30 @@
BOOL l3Set; BOOL l3Set;
BOOL r3Set; BOOL r3Set;
BOOL _iPad;
CGRect _controlArea;
UIView* _view; UIView* _view;
OnScreenControlsLevel _level; OnScreenControlsLevel _level;
ControllerSupport *_controllerSupport; ControllerSupport *_controllerSupport;
Controller *_controller; Controller *_controller;
id<EdgeDetectionDelegate> _edgeDelegate; id<EdgeDetectionDelegate> _edgeDelegate;
NSMutableArray* _deadTouches;
} }
static const float EDGE_WIDTH = .1; static const float EDGE_WIDTH = .05;
//static const float BUTTON_SIZE = 50; //static const float BUTTON_SIZE = 50;
static const float BUTTON_DIST = 20; static const float BUTTON_DIST = 20;
static float BUTTON_CENTER_X; static float BUTTON_CENTER_X;
static float BUTTON_CENTER_Y; static float BUTTON_CENTER_Y;
static const float D_PAD_DIST = 15; static const float D_PAD_DIST = 10;
static float D_PAD_CENTER_X; static float D_PAD_CENTER_X;
static float D_PAD_CENTER_Y; static float D_PAD_CENTER_Y;
static const float DEAD_ZONE_PADDING = 15;
static const double STICK_CLICK_RATE = 100; static const double STICK_CLICK_RATE = 100;
static const float STICK_DEAD_ZONE = .1; static const float STICK_DEAD_ZONE = .1;
static float STICK_INNER_SIZE; static float STICK_INNER_SIZE;
@@ -114,9 +119,23 @@ static float L3_Y;
self = [self init]; self = [self init];
_view = view; _view = view;
_controllerSupport = controllerSupport; _controllerSupport = controllerSupport;
_controller = [[Controller alloc] init]; _controller = [controllerSupport getOscController];
_controller.playerIndex = 0;
_edgeDelegate = swipeDelegate; _edgeDelegate = swipeDelegate;
_deadTouches = [[NSMutableArray alloc] init];
_iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
_controlArea = CGRectMake(0, 0, _view.frame.size.width, _view.frame.size.height);
if (_iPad)
{
// Cut down the control area on an iPad so the controls are more reachable
_controlArea.size.height = _view.frame.size.height / 2.0;
_controlArea.origin.y = _view.frame.size.height - _controlArea.size.height;
}
else
{
_controlArea.origin.x = _controlArea.size.width * EDGE_WIDTH;
_controlArea.size.width -= _controlArea.origin.x * 2;
}
_aButton = [CALayer layer]; _aButton = [CALayer layer];
_bButton = [CALayer layer]; _bButton = [CALayer layer];
@@ -139,7 +158,7 @@ static float L3_Y;
_leftStick = [CALayer layer]; _leftStick = [CALayer layer];
_rightStick = [CALayer layer]; _rightStick = [CALayer layer];
_edge = [CALayer layer]; _edge = [CALayer layer];
[self setupEdgeDetection]; [self setupEdgeDetection];
return self; return self;
@@ -167,10 +186,10 @@ static float L3_Y;
[self hideButtons]; [self hideButtons];
[self hideBumpers]; [self hideBumpers];
[self hideL3R3];
[self drawTriggers]; [self drawTriggers];
[self drawStartSelect]; [self drawStartSelect];
[self drawSticks]; [self drawSticks];
[self drawL3R3];
break; break;
case OnScreenControlsLevelAutoGCExtendedGamepad: case OnScreenControlsLevelAutoGCExtendedGamepad:
// GCExtendedGamepad is missing R3, L3, and select // GCExtendedGamepad is missing R3, L3, and select
@@ -219,8 +238,8 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
START_Y = _view.frame.size.height * .9; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_Y = _view.frame.size.height * .9; SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
} }
// For GCGamepad controls we move triggers, start, and select // For GCGamepad controls we move triggers, start, and select
@@ -229,7 +248,42 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
// TODO START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
if (_iPad) {
START_X = _controlArea.size.width * .75 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .25 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
// The analog sticks are kept closer to the sides on iPad
LS_CENTER_X = _controlArea.size.width * .18 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .82 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
} else {
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
LS_CENTER_X = _controlArea.size.width * .25 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .75 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
} }
// For simple controls we move the triggers and buttons to the bottom // For simple controls we move the triggers and buttons to the bottom
@@ -237,46 +291,59 @@ static float L3_Y;
// Start with the default complex layout // Start with the default complex layout
[self setupComplexControls]; [self setupComplexControls];
START_Y = _view.frame.size.height * .9; START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
SELECT_Y = _view.frame.size.height * .9; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _view.frame.size.height * .7; R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _view.frame.size.height * .9; R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
L2_X = _view.frame.size.width * .1;
R1_Y = _view.frame.size.height * .7;
R2_Y = _view.frame.size.height * .9;
R2_X = _view.frame.size.width * .9;
} }
- (void) setupComplexControls - (void) setupComplexControls
{ {
D_PAD_CENTER_X = _view.frame.size.width * .15; D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
D_PAD_CENTER_Y = _view.frame.size.height * .55; D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
BUTTON_CENTER_X = _view.frame.size.width * .85; BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
BUTTON_CENTER_Y = _view.frame.size.height * .55; BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
LS_CENTER_X = _view.frame.size.width * .35; if (_iPad)
LS_CENTER_Y = _view.frame.size.height * .75; {
RS_CENTER_X = _view.frame.size.width * .65; // The analog sticks are kept closer to the sides on iPad
RS_CENTER_Y = _view.frame.size.height * .75; LS_CENTER_X = _controlArea.size.width * .22 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .77 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
else
{
LS_CENTER_X = _controlArea.size.width * .35 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .65 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
START_X = _view.frame.size.width * .6; START_X = _controlArea.size.width * .9 + _controlArea.origin.x;
START_Y = _view.frame.size.height * .1; START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _view.frame.size.width * .4; SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
SELECT_Y = _view.frame.size.height * .1; SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L1_X = _view.frame.size.width * .15; L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _view.frame.size.height * .27; L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
L2_X = _view.frame.size.width * .15; L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L2_Y = _view.frame.size.height * .1; L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
R1_X = _view.frame.size.width * .85; R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R1_Y = _view.frame.size.height * .27; R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
R2_X = _view.frame.size.width * .85; R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R2_Y = _view.frame.size.height * .1; R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
L3_X = _view.frame.size.width * .25; L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
L3_Y = _view.frame.size.height * .75; L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
R3_X = _view.frame.size.width * .75; R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
R3_Y = _view.frame.size.height * .75; R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
} }
- (void) drawButtons { - (void) drawButtons {
@@ -285,43 +352,43 @@ static float L3_Y;
_aButton.contents = (id) aButtonImage.CGImage; _aButton.contents = (id) aButtonImage.CGImage;
_aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height); _aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height);
[_view.layer addSublayer:_aButton]; [_view.layer addSublayer:_aButton];
// create B button // create B button
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"]; UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height); _bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height);
_bButton.contents = (id) bButtonImage.CGImage; _bButton.contents = (id) bButtonImage.CGImage;
[_view.layer addSublayer:_bButton]; [_view.layer addSublayer:_bButton];
// create X Button // create X Button
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"]; UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height); _xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height);
_xButton.contents = (id) xButtonImage.CGImage; _xButton.contents = (id) xButtonImage.CGImage;
[_view.layer addSublayer:_xButton]; [_view.layer addSublayer:_xButton];
// create Y Button // create Y Button
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"]; UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
_yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height); _yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height);
_yButton.contents = (id) yButtonImage.CGImage; _yButton.contents = (id) yButtonImage.CGImage;
[_view.layer addSublayer:_yButton]; [_view.layer addSublayer:_yButton];
// create Down button // create Down button
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"]; UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
_downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height); _downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height);
_downButton.contents = (id) downButtonImage.CGImage; _downButton.contents = (id) downButtonImage.CGImage;
[_view.layer addSublayer:_downButton]; [_view.layer addSublayer:_downButton];
// create Right button // create Right button
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"]; UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height); _rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height);
_rightButton.contents = (id) rightButtonImage.CGImage; _rightButton.contents = (id) rightButtonImage.CGImage;
[_view.layer addSublayer:_rightButton]; [_view.layer addSublayer:_rightButton];
// create Up button // create Up button
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"]; UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
_upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height); _upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height);
_upButton.contents = (id) upButtonImage.CGImage; _upButton.contents = (id) upButtonImage.CGImage;
[_view.layer addSublayer:_upButton]; [_view.layer addSublayer:_upButton];
// create Left button // create Left button
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"]; UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height); _leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height);
@@ -335,7 +402,7 @@ static float L3_Y;
_startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height); _startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height);
_startButton.contents = (id) startButtonImage.CGImage; _startButton.contents = (id) startButtonImage.CGImage;
[_view.layer addSublayer:_startButton]; [_view.layer addSublayer:_startButton];
// create Select button // create Select button
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"]; UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
_selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height); _selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
@@ -382,7 +449,7 @@ static float L3_Y;
_leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height); _leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height);
_leftStick.contents = (id) leftStickImage.CGImage; _leftStick.contents = (id) leftStickImage.CGImage;
[_view.layer addSublayer:_leftStick]; [_view.layer addSublayer:_leftStick];
// create right analog stick // create right analog stick
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"]; UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height); _rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
@@ -463,7 +530,7 @@ static float L3_Y;
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2; float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2; float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2; float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInView:_view]; CGPoint touchLocation = [touch locationInView:_view];
float xLoc = touchLocation.x; float xLoc = touchLocation.x;
@@ -473,35 +540,55 @@ static float L3_Y;
if (xLoc < lsMinX) xLoc = lsMinX; if (xLoc < lsMinX) xLoc = lsMinX;
if (yLoc > lsMaxY) yLoc = lsMaxY; if (yLoc > lsMaxY) yLoc = lsMaxY;
if (yLoc < lsMinY) yLoc = lsMinY; if (yLoc < lsMinY) yLoc = lsMinY;
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X); float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y); float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; [_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true; updated = true;
} else if (touch == _rsTouch) { } else if (touch == _rsTouch) {
if (xLoc > rsMaxX) xLoc = rsMaxX; if (xLoc > rsMaxX) xLoc = rsMaxX;
if (xLoc < rsMinX) xLoc = rsMinX; if (xLoc < rsMinX) xLoc = rsMinX;
if (yLoc > rsMaxY) yLoc = rsMaxY; if (yLoc > rsMaxY) yLoc = rsMaxY;
if (yLoc < rsMinY) yLoc = rsMinY; if (yLoc < rsMinY) yLoc = rsMinY;
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X); float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y); float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0; if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0; if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; [_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true; updated = true;
} else if (touch == _dpadTouch) {
[_controllerSupport clearButtonFlag:_controller
flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
// Allow the user to slide their finger to another d-pad button
if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
updated = true;
}
buttonTouch = true;
} else if (touch == _aTouch) { } else if (touch == _aTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _bTouch) { } else if (touch == _bTouch) {
@@ -510,14 +597,6 @@ static float L3_Y;
buttonTouch = true; buttonTouch = true;
} else if (touch == _yTouch) { } else if (touch == _yTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _upTouch) {
buttonTouch = true;
} else if (touch == _downTouch) {
buttonTouch = true;
} else if (touch == _leftTouch) {
buttonTouch = true;
} else if (touch == _rightTouch) {
buttonTouch = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
buttonTouch = true; buttonTouch = true;
} else if (touch == _selectTouch) { } else if (touch == _selectTouch) {
@@ -535,11 +614,14 @@ static float L3_Y;
} else if (touch == _r3Touch) { } else if (touch == _r3Touch) {
buttonTouch = true; buttonTouch = true;
} }
if ([_deadTouches containsObject:touch]) {
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
} }
return updated || buttonTouch; return updated || buttonTouch;
} }
- (BOOL)handleTouchDownEvent:touches { - (BOOL)handleTouchDownEvent:touches {
@@ -566,19 +648,19 @@ static float L3_Y;
updated = true; updated = true;
} else if ([_upButton.presentationLayer hitTest:touchLocation]) { } else if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
_upTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) { } else if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG]; [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) { } else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) { } else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = touch; _dpadTouch = touch;
updated = true; updated = true;
} else if ([_startButton.presentationLayer hitTest:touchLocation]) { } else if ([_startButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG]; [_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
@@ -653,6 +735,10 @@ static float L3_Y;
} else if ([_edge.presentationLayer hitTest:touchLocation]) { } else if ([_edge.presentationLayer hitTest:touchLocation]) {
_edgeTouch = touch; _edgeTouch = touch;
} }
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
[_deadTouches addObject:touch];
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
@@ -680,21 +766,10 @@ static float L3_Y;
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
_yTouch = nil; _yTouch = nil;
updated = true; updated = true;
} else if (touch == _upTouch) { } else if (touch == _dpadTouch) {
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG]; [_controllerSupport clearButtonFlag:_controller
_upTouch = nil; flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
updated = true; _dpadTouch = nil;
} else if (touch == _downTouch) {
[_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = nil;
updated = true;
} else if (touch == _leftTouch) {
[_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = nil;
updated = true;
} else if (touch == _rightTouch) {
[_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = nil;
updated = true; updated = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
@@ -744,15 +819,123 @@ static float L3_Y;
touched = true; touched = true;
} else if (touch == _edgeTouch) { } else if (touch == _edgeTouch) {
_edgeTouch = nil; _edgeTouch = nil;
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) { if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
[_edgeDelegate edgeSwiped]; [_edgeDelegate edgeSwiped];
} }
} }
if ([_deadTouches containsObject:touch]) {
[_deadTouches removeObject:touch];
updated = true;
}
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished:_controller]; [_controllerSupport updateFinished:_controller];
} }
return updated || touched; return updated || touched;
} }
- (BOOL) isInDeadZone:(UITouch*) touch {
switch (_level) {
case OnScreenControlsLevelFull:
return [self isDpadDeadZone:touch]
|| [self isAbxyDeadZone:touch]
|| [self isTriggerDeadZone:touch]
|| [self isBumperDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelSimple:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch]
|| [self isL3R3DeadZone:touch];
case OnScreenControlsLevelAutoGCExtendedGamepad:
return [self isL3R3DeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelAutoGCGamepad:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
default:
return false;
}
}
- (BOOL) isDpadDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_upButton.frame.origin.y
endX:_rightButton.frame.origin.x + _rightButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isAbxyDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_xButton.frame.origin.x
startY:_yButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isBumperDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y + _l2Button.frame.size.height
endX:_l1Button.frame.origin.x + _l1Button.frame.size.width
endY:_upButton.frame.origin.y]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y + _r2Button.frame.size.height
endX:_view.frame.origin.x + _view.frame.size.width
endY:_yButton.frame.origin.y];
}
- (BOOL) isTriggerDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y
endX:_l2Button.frame.origin.x + _l2Button.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isL3R3DeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l3Button.frame.origin.y
endX:_view.frame.origin.x
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r3Button.frame.origin.x
startY:_r3Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isStartSelectDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_startButton.frame.origin.x
startY:_startButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_selectButton.frame.origin.y
endX:_selectButton.frame.origin.x + _selectButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isDeadZone:(UITouch*) touch startX:(float)deadZoneStartX startY:(float)deadZoneStartY endX:(float)deadZoneEndX endY:(float)deadZoneEndY {
deadZoneStartX -= DEAD_ZONE_PADDING;
deadZoneStartY -= DEAD_ZONE_PADDING;
deadZoneEndX += DEAD_ZONE_PADDING;
deadZoneEndY += DEAD_ZONE_PADDING;
CGPoint touchLocation = [touch locationInView:_view];
return (touchLocation.x > deadZoneStartX && touchLocation.x < deadZoneEndX
&& touchLocation.y > deadZoneStartY && touchLocation.y < deadZoneEndY);
}
@end @end
+44 -18
View File
@@ -17,6 +17,9 @@
BOOL touchMoved; BOOL touchMoved;
OnScreenControls* onScreenControls; OnScreenControls* onScreenControls;
BOOL isDragging;
NSTimer* dragTimer;
float xDeltaFactor; float xDeltaFactor;
float yDeltaFactor; float yDeltaFactor;
float screenFactor; float screenFactor;
@@ -32,7 +35,7 @@
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate { - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate]; onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue]; OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue];
if (level == OnScreenControlsLevelAuto) { if (level == OnScreenControlsLevelAuto) {
[controllerSupport initAutoOnScreenControlMode:onScreenControls]; [controllerSupport initAutoOnScreenControlMode:onScreenControls];
@@ -49,11 +52,27 @@
UITouch *touch = [[event allTouches] anyObject]; UITouch *touch = [[event allTouches] anyObject];
touchLocation = [touch locationInView:self]; touchLocation = [touch locationInView:self];
touchMoved = false; touchMoved = false;
if ([[event allTouches] count] == 1 && !isDragging) {
dragTimer = [NSTimer scheduledTimerWithTimeInterval:0.650
target:self
selector:@selector(onDragStart:)
userInfo:nil
repeats:NO];
}
}
}
- (void)onDragStart:(NSTimer*)timer {
if (!touchMoved && !isDragging){
isDragging = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} }
} }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (![onScreenControls handleTouchMovedEvent:touches]) { if (![onScreenControls handleTouchMovedEvent:touches]) {
[dragTimer invalidate];
dragTimer = nil;
if ([[event allTouches] count] == 1) { if ([[event allTouches] count] == 1) {
UITouch *touch = [[event allTouches] anyObject]; UITouch *touch = [[event allTouches] anyObject];
CGPoint currentLocation = [touch locationInView:self]; CGPoint currentLocation = [touch locationInView:self];
@@ -67,15 +86,16 @@
deltaX *= xDeltaFactor * screenFactor; deltaX *= xDeltaFactor * screenFactor;
deltaY *= yDeltaFactor * screenFactor; deltaY *= yDeltaFactor * screenFactor;
LiSendMouseMoveEvent(deltaX, deltaY); if (deltaX != 0 || deltaY != 0) {
LiSendMouseMoveEvent(deltaX, deltaY);
touchMoved = true; touchMoved = true;
touchLocation = currentLocation; touchLocation = currentLocation;
}
} }
} else if ([[event allTouches] count] == 2) { } else if ([[event allTouches] count] == 2) {
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self]; CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self]; CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2); CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
if (touchLocation.y != avgLocation.y) { if (touchLocation.y != avgLocation.y) {
LiSendScrollEvent(avgLocation.y - touchLocation.y); LiSendScrollEvent(avgLocation.y - touchLocation.y);
@@ -90,29 +110,35 @@
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
Log(LOG_D, @"Touch up"); Log(LOG_D, @"Touch up");
if (![onScreenControls handleTouchUpEvent:touches]) { if (![onScreenControls handleTouchUpEvent:touches]) {
[dragTimer invalidate];
dragTimer = nil;
if (!touchMoved) { if (!touchMoved) {
if ([[event allTouches] count] == 2) { if ([[event allTouches] count] == 2) {
Log(LOG_D, @"Sending right mouse button press"); Log(LOG_D, @"Sending right mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
// Wait 100 ms to simulate a real button press // Wait 100 ms to simulate a real button press
usleep(100 * 1000); usleep(100 * 1000);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
} else { } else {
Log(LOG_D, @"Sending left mouse button press"); if (!isDragging){
Log(LOG_D, @"Sending left mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
// Wait 100 ms to simulate a real button press
usleep(100 * 1000); // Wait 100 ms to simulate a real button press
usleep(100 * 1000);
}
isDragging = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} }
} }
else if (isDragging) {
isDragging = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
} }
} }
+11 -4
View File
@@ -9,7 +9,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string> <string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.9.1</string> <string>1.1.4</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
@@ -26,6 +26,11 @@
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIAppFonts</key> <key>UIAppFonts</key>
<array> <array>
<string>Roboto-Black.ttf</string> <string>Roboto-Black.ttf</string>
@@ -45,9 +50,9 @@
<array> <array>
<string>armv7</string> <string>armv7</string>
</array> </array>
<key>UIStatusBarHidden</key> <key>UIRequiresFullScreen</key>
<true/> <true/>
<key>UIStatusBarHidden~ipad</key> <key>UIStatusBarHidden</key>
<true/> <true/>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
@@ -59,5 +64,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict> </dict>
</plist> </plist>
@@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>_XCCurrentVersionName</key> <key>_XCCurrentVersionName</key>
<string>Limelight 0.3.1.xcdatamodel</string> <string>Moonlight v1.0-2.xcdatamodel</string>
</dict> </dict>
</plist> </plist>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
</entity>
<entity name="Host" representedClassName="Host" syncable="YES">
<attribute name="address" attributeType="String" syncable="YES"/>
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="localAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="mac" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="pairState" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="uuid" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="appList" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="App" inverseName="host" inverseEntity="App" syncable="YES"/>
</entity>
<entity name="Settings" representedClassName="Settings" syncable="YES">
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" syncable="YES"/>
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity>
<elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements>
</model>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
</entity>
<entity name="Host" representedClassName="Host" syncable="YES">
<attribute name="address" attributeType="String" syncable="YES"/>
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="localAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="mac" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="pairState" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="uuid" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="appList" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="App" inverseName="host" inverseEntity="App" syncable="YES"/>
</entity>
<entity name="Settings" representedClassName="Settings" syncable="YES">
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" syncable="YES"/>
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity>
<elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements>
</model>
+4 -4
View File
@@ -7,20 +7,20 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "App.h" #import "TemporaryApp.h"
#import "HttpManager.h" #import "HttpManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol AppAssetCallback <NSObject> @protocol AppAssetCallback <NSObject>
- (void) receivedAssetForApp:(App*)app; - (void) receivedAssetForApp:(TemporaryApp*)app;
@end @end
@interface AppAssetManager : NSObject @interface AppAssetManager : NSObject
- (id) initWithCallback:(id<AppAssetCallback>)callback; - (id) initWithCallback:(id<AppAssetCallback>)callback;
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host; - (void) retrieveAssetsFromHost:(TemporaryHost*)host;
- (void) stopRetrieving; - (void) stopRetrieving;
@end @end
+12 -21
View File
@@ -15,8 +15,6 @@
@implementation AppAssetManager { @implementation AppAssetManager {
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
id<AppAssetCallback> _callback; id<AppAssetCallback> _callback;
Host* _host;
NSMutableDictionary* _imageCache;
} }
static const int MAX_REQUEST_COUNT = 4; static const int MAX_REQUEST_COUNT = 4;
@@ -24,29 +22,22 @@ static const int MAX_REQUEST_COUNT = 4;
- (id) initWithCallback:(id<AppAssetCallback>)callback { - (id) initWithCallback:(id<AppAssetCallback>)callback {
self = [super init]; self = [super init];
_callback = callback; _callback = callback;
_imageCache = [[NSMutableDictionary alloc] init];
_opQueue = [[NSOperationQueue alloc] init]; _opQueue = [[NSOperationQueue alloc] init];
[_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT]; [_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT];
return self; return self;
} }
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host { - (void) retrieveAssetsFromHost:(TemporaryHost*)host {
Host* oldHost = _host; for (TemporaryApp* app in host.appList) {
_host = host; if (app.image == nil) {
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid]; AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
Log(LOG_I, @"Using cached app images: %d", useCache); retriever.app = app;
if (!useCache) { retriever.host = host;
[_imageCache removeAllObjects]; retriever.callback = _callback;
}
for (App* app in appList) { [_opQueue addOperation:retriever];
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init]; }
retriever.app = app;
retriever.host = _host;
retriever.callback = _callback;
retriever.cache = _imageCache;
retriever.useCache = useCache;
[_opQueue addOperation:retriever];
} }
} }
@@ -54,7 +45,7 @@ static const int MAX_REQUEST_COUNT = 4;
[_opQueue cancelAllOperations]; [_opQueue cancelAllOperations];
} }
- (void) sendCallBackForApp:(App*)app { - (void) sendCallBackForApp:(TemporaryApp*)app {
[_callback receivedAssetForApp:app]; [_callback receivedAssetForApp:app];
} }
+4 -6
View File
@@ -7,16 +7,14 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
#import "App.h" #import "TemporaryApp.h"
#import "AppAssetManager.h" #import "AppAssetManager.h"
@interface AppAssetRetriever : NSOperation @interface AppAssetRetriever : NSOperation
@property (nonatomic) Host* host; @property (nonatomic) TemporaryHost* host;
@property (nonatomic) App* app; @property (nonatomic) TemporaryApp* app;
@property (nonatomic) NSMutableDictionary* cache;
@property (nonatomic) id<AppAssetCallback> callback; @property (nonatomic) id<AppAssetCallback> callback;
@property (nonatomic) BOOL useCache;
@end @end
+12 -25
View File
@@ -11,45 +11,32 @@
#import "CryptoManager.h" #import "CryptoManager.h"
#import "AppAssetResponse.h" #import "AppAssetResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "IdManager.h"
@implementation AppAssetRetriever @implementation AppAssetRetriever
static const double RETRY_DELAY = 2; // seconds static const double RETRY_DELAY = 2; // seconds
static const int MAX_ATTEMPTS = 5; static const int MAX_ATTEMPTS = 5;
- (void) main { - (void) main {
UIImage* appImage = nil; UIImage* appImage = nil;
int attempts = 0; int attempts = 0;
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) { while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
if (self.useCache) {
@synchronized(self.cache) { HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
UIImage* cachedImage = [self.cache objectForKey:self.app.appId]; AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
if (cachedImage != nil) { [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
appImage = cachedImage;
self.app.appImage = appImage; appImage = [UIImage imageWithData:appAssetResp.data];
} self.app.image = UIImagePNGRepresentation(appImage);
}
if (![self isCancelled] && appImage == nil) {
[NSThread sleepForTimeInterval:RETRY_DELAY];
} }
if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]];
appImage = [UIImage imageWithData:appAssetResp.data];
self.app.appImage = appImage;
if (appImage != nil) {
@synchronized(self.cache) {
[self.cache setObject:appImage forKey:self.app.appId];
}
}
}
[NSThread sleepForTimeInterval:RETRY_DELAY];
} }
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
} }
- (void) sendCallbackForApp:(App*)app { - (void) sendCallbackForApp:(TemporaryApp*)app {
[self.callback receivedAssetForApp:app]; [self.callback receivedAssetForApp:app];
} }
+1 -1
View File
@@ -11,7 +11,7 @@
@interface AppListResponse : NSObject <Response> @interface AppListResponse : NSObject <Response>
- (void)populateWithData:(NSData *)data; - (void)populateWithData:(NSData *)data;
- (NSArray*) getAppList; - (NSSet*) getAppList;
- (BOOL) isStatusOk; - (BOOL) isStatusOk;
@end @end
+11 -21
View File
@@ -7,22 +7,22 @@
// //
#import "AppListResponse.h" #import "AppListResponse.h"
#import "App.h" #import "TemporaryApp.h"
#import "DataManager.h"
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse { @implementation AppListResponse {
NSMutableArray* _appList; NSMutableSet* _appList;
} }
@synthesize data, statusCode, statusMessage; @synthesize data, statusCode, statusMessage;
static const char* TAG_APP = "App"; static const char* TAG_APP = "App";
static const char* TAG_APP_TITLE = "AppTitle"; static const char* TAG_APP_TITLE = "AppTitle";
static const char* TAG_APP_ID = "ID"; static const char* TAG_APP_ID = "ID";
static const char* TAG_APP_IS_RUNNING = "IsRunning";
- (void)populateWithData:(NSData *)xml { - (void)populateWithData:(NSData *)xml {
self.data = xml; self.data = xml;
_appList = [[NSMutableArray alloc] init]; _appList = [[NSMutableSet alloc] init];
[self parseData]; [self parseData];
} }
@@ -64,9 +64,8 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
//Log(LOG_D, @"node: %s", node->name); //Log(LOG_D, @"node: %s", node->name);
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) { if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
xmlNodePtr appInfoNode = node->xmlChildrenNode; xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName; NSString* appName = @"";
NSString* appId; NSString* appId = nil;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) { while (appInfoNode != NULL) {
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) { if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1); xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
@@ -82,22 +81,13 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding]; appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal); xmlFree(nodeVal);
} }
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
if (nodeVal != NULL) {
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
} else {
appIsRunning = NO;
}
} }
appInfoNode = appInfoNode->next; appInfoNode = appInfoNode->next;
} }
App* app = [[App alloc] init]; if (appId != nil) {
app.appName = appName; TemporaryApp* app = [[TemporaryApp alloc] init];
app.appId = appId; app.name = appName;
app.isRunning = appIsRunning; app.id = appId;
if (app.appId != nil) {
[_appList addObject:app]; [_appList addObject:app];
} }
} }
@@ -107,7 +97,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
xmlFreeDoc(docPtr); xmlFreeDoc(docPtr);
} }
- (NSArray*) getAppList { - (NSSet*) getAppList {
return _appList; return _appList;
} }
+4 -4
View File
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MDNSManager.h" #import "MDNSManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol DiscoveryCallback <NSObject> @protocol DiscoveryCallback <NSObject>
@@ -22,8 +22,8 @@
- (void) startDiscovery; - (void) startDiscovery;
- (void) stopDiscovery; - (void) stopDiscovery;
- (void) stopDiscoveryBlocking; - (void) stopDiscoveryBlocking;
- (BOOL) addHostToDiscovery:(Host*)host; - (BOOL) addHostToDiscovery:(TemporaryHost*)host;
- (void) removeHostFromDiscovery:(Host*)host; - (void) removeHostFromDiscovery:(TemporaryHost*)host;
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback; - (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(TemporaryHost*, NSString*))callback;
@end @end
+40 -27
View File
@@ -13,10 +13,10 @@
#import "DataManager.h" #import "DataManager.h"
#import "DiscoveryWorker.h" #import "DiscoveryWorker.h"
#import "ServerInfoResponse.h" #import "ServerInfoResponse.h"
#import "IdManager.h"
@implementation DiscoveryManager { @implementation DiscoveryManager {
NSMutableArray* _hostQueue; NSMutableArray* _hostQueue;
NSMutableArray* _discoveredHosts;
id<DiscoveryCallback> _callback; id<DiscoveryCallback> _callback;
MDNSManager* _mdnsMan; MDNSManager* _mdnsMan;
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
@@ -27,37 +27,44 @@
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback { - (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
self = [super init]; self = [super init];
_hostQueue = [NSMutableArray arrayWithArray:hosts];
// Using addHostToDiscovery ensures no duplicates
// will make it into the list from the database
_callback = callback; _callback = callback;
shouldDiscover = NO;
_hostQueue = [NSMutableArray array];
for (TemporaryHost* host in hosts)
{
[self addHostToDiscovery:host];
}
[_callback updateAllHosts:_hostQueue];
_opQueue = [[NSOperationQueue alloc] init]; _opQueue = [[NSOperationQueue alloc] init];
_mdnsMan = [[MDNSManager alloc] initWithCallback:self]; _mdnsMan = [[MDNSManager alloc] initWithCallback:self];
[CryptoManager generateKeyPairUsingSSl]; [CryptoManager generateKeyPairUsingSSl];
_uniqueId = [CryptoManager getUniqueID]; _uniqueId = [IdManager getUniqueId];
_cert = [CryptoManager readCertFromFile]; _cert = [CryptoManager readCertFromFile];
shouldDiscover = NO;
return self; return self;
} }
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback { - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(TemporaryHost *, NSString*))callback {
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
Host* host = nil; TemporaryHost* host = nil;
if ([serverInfoResponse isStatusOk]) { if ([serverInfoResponse isStatusOk]) {
DataManager* dataMan = [[DataManager alloc] init]; host = [[TemporaryHost alloc] init];
host = [dataMan createHost]; host.activeAddress = host.address = hostAddress;
host.address = hostAddress;
host.online = YES; host.online = YES;
[serverInfoResponse populateHost:host]; [serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) { if (![self addHostToDiscovery:host]) {
[dataMan removeHost:host];
callback(nil, @"Host already added"); callback(nil, @"Host already added");
} else { } else {
callback(host, nil); callback(host, nil);
} }
} else { } else {
callback(nil, @"Could not connect to host"); callback(nil, @"Could not connect to host. Ensure GameStream is enabled in GeForce Experience on your PC.");
} }
} }
@@ -66,7 +73,7 @@
Log(LOG_I, @"Starting discovery"); Log(LOG_I, @"Starting discovery");
shouldDiscover = YES; shouldDiscover = YES;
[_mdnsMan searchForHosts]; [_mdnsMan searchForHosts];
for (Host* host in _hostQueue) { for (TemporaryHost* host in _hostQueue) {
[_opQueue addOperation:[self createWorkerForHost:host]]; [_opQueue addOperation:[self createWorkerForHost:host]];
} }
} }
@@ -87,18 +94,27 @@
Log(LOG_I, @"All discovery workers stopped"); Log(LOG_I, @"All discovery workers stopped");
} }
- (BOOL) addHostToDiscovery:(Host *)host { - (BOOL) addHostToDiscovery:(TemporaryHost *)host {
if (host.uuid.length > 0 && ![self isHostInDiscovery:host]) { if (host.uuid.length == 0) {
return NO;
}
TemporaryHost *existingHost = [self getHostInDiscovery:host.uuid];
if (existingHost != nil) {
// Update address of existing host
existingHost.address = existingHost.activeAddress = host.address;
return NO;
}
else {
[_hostQueue addObject:host]; [_hostQueue addObject:host];
if (shouldDiscover) { if (shouldDiscover) {
[_opQueue addOperation:[self createWorkerForHost:host]]; [_opQueue addOperation:[self createWorkerForHost:host]];
} }
return YES; return YES;
} }
return NO;
} }
- (void) removeHostFromDiscovery:(Host *)host { - (void) removeHostFromDiscovery:(TemporaryHost *)host {
for (DiscoveryWorker* worker in [_opQueue operations]) { for (DiscoveryWorker* worker in [_opQueue operations]) {
if ([worker getHost] == host) { if ([worker getHost] == host) {
[worker cancel]; [worker cancel];
@@ -110,9 +126,8 @@
// Override from MDNSCallback // Override from MDNSCallback
- (void)updateHosts:(NSArray *)hosts { - (void)updateHosts:(NSArray *)hosts {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DataManager* dataMan = [[DataManager alloc] init];
// Discover the hosts before adding to eliminate duplicates // Discover the hosts before adding to eliminate duplicates
for (Host* host in hosts) { for (TemporaryHost* host in hosts) {
Log(LOG_I, @"Found host through MDNS: %@:", host.name); Log(LOG_I, @"Found host through MDNS: %@:", host.name);
// Since this is on a background thread, we do not need to use the opQueue // Since this is on a background thread, we do not need to use the opQueue
DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host]; DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host];
@@ -122,24 +137,22 @@
[_callback updateAllHosts:_hostQueue]; [_callback updateAllHosts:_hostQueue];
} else { } else {
Log(LOG_I, @"Not adding host to discovery: %@", host.name); Log(LOG_I, @"Not adding host to discovery: %@", host.name);
[dataMan removeHost:host];
} }
} }
[dataMan saveHosts];
}); });
} }
- (BOOL) isHostInDiscovery:(Host*)host { - (TemporaryHost*) getHostInDiscovery:(NSString*)uuidString {
for (int i = 0; i < _hostQueue.count; i++) { for (int i = 0; i < _hostQueue.count; i++) {
Host* discoveredHost = [_hostQueue objectAtIndex:i]; TemporaryHost* discoveredHost = [_hostQueue objectAtIndex:i];
if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:host.uuid]) { if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:uuidString]) {
return YES; return discoveredHost;
} }
} }
return NO; return nil;
} }
- (NSOperation*) createWorkerForHost:(Host*)host { - (NSOperation*) createWorkerForHost:(TemporaryHost*)host {
DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert]; DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert];
return worker; return worker;
} }
+3 -3
View File
@@ -7,12 +7,12 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
@interface DiscoveryWorker : NSOperation @interface DiscoveryWorker : NSOperation
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert; - (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert;
- (void) discoverHost; - (void) discoverHost;
- (Host*) getHost; - (TemporaryHost*) getHost;
@end @end
+83 -17
View File
@@ -11,16 +11,17 @@
#import "HttpManager.h" #import "HttpManager.h"
#import "ServerInfoResponse.h" #import "ServerInfoResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "DataManager.h"
@implementation DiscoveryWorker { @implementation DiscoveryWorker {
Host* _host; TemporaryHost* _host;
NSString* _uniqueId; NSString* _uniqueId;
NSData* _cert; NSData* _cert;
} }
static const float POLL_RATE = 2.0f; // Poll every 2 seconds static const float POLL_RATE = 2.0f; // Poll every 2 seconds
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert { - (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert {
self = [super init]; self = [super init];
_host = host; _host = host;
_uniqueId = uniqueId; _uniqueId = uniqueId;
@@ -28,7 +29,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
return self; return self;
} }
- (Host*) getHost { - (TemporaryHost*) getHost {
return _host; return _host;
} }
@@ -41,23 +42,88 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
} }
} }
- (NSArray*) getHostAddressList {
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
if (_host.localAddress != nil) {
[array addObject:_host.localAddress];
}
if (_host.externalAddress != nil) {
[array addObject:_host.externalAddress];
}
if (_host.address != nil) {
[array addObject:_host.address];
}
// Remove duplicate addresses from the list.
// This is done using an array rather than a set
// to preserve insertion order of addresses.
for (int i = 0; i < [array count]; i++) {
NSString *addr1 = [array objectAtIndex:i];
for (int j = 1; j < [array count]; j++) {
if (i == j) {
continue;
}
NSString *addr2 = [array objectAtIndex:j];
if ([addr1 isEqualToString:addr2]) {
// Remove the last address
[array removeObjectAtIndex:j];
// Begin searching again from the start
i = -1;
break;
}
}
}
return array;
}
- (void) discoverHost { - (void) discoverHost {
BOOL receivedResponse = NO; BOOL receivedResponse = NO;
if (!self.cancelled && _host.localAddress != nil) { NSArray *addresses = [self getHostAddressList];
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.localAddress];
receivedResponse = [self checkResponse:serverInfoResp]; Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
}
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { // Give the PC 3 tries to respond before declaring it offline
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.externalAddress]; for (int i = 0; i < 3; i++) {
receivedResponse = [self checkResponse:serverInfoResp]; for (NSString *address in addresses) {
} if (self.cancelled) {
if (!self.cancelled && !receivedResponse && _host.address != nil) { // Get out without updating the status because
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.address]; // it might not have finished checking the various
receivedResponse = [self checkResponse:serverInfoResp]; // addresses
return;
}
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
receivedResponse = [self checkResponse:serverInfoResp];
if (receivedResponse) {
[serverInfoResp populateHost:_host];
_host.activeAddress = address;
// Update the database using the response
DataManager *dataManager = [[DataManager alloc] init];
[dataManager updateHost:_host];
break;
}
}
if (receivedResponse) {
Log(LOG_I, @"Received serverinfo response on try %d", i);
break;
}
else {
// Wait for one second then retry
[NSThread sleepForTimeInterval:1];
}
} }
_host.online = receivedResponse; _host.online = receivedResponse;
if (receivedResponse) { if (receivedResponse) {
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online); Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online, _host.activeAddress);
} }
} }
@@ -68,7 +134,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
cert:_cert]; cert:_cert];
ServerInfoResponse* response = [[ServerInfoResponse alloc] init]; ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response [hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
withUrlRequest:[hMan newServerInfoRequest]]]; withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
return response; return response;
} }
@@ -76,7 +143,6 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
if ([response isStatusOk]) { if ([response isStatusOk]) {
// If the response is from a different host then do not update this host // If the response is from a different host then do not update this host
if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) { if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) {
[response populateHost:_host];
return YES; return YES;
} else { } else {
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid); Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
+2 -3
View File
@@ -7,11 +7,10 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h"
#import "HttpResponse.h" #import "HttpResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> @interface HttpManager : NSObject <NSURLSessionDelegate>
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert; - (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
- (NSURLRequest*) newPairRequest:(NSData*)salt; - (NSURLRequest*) newPairRequest:(NSData*)salt;
@@ -22,12 +21,12 @@
- (NSURLRequest*) newPairChallenge; - (NSURLRequest*) newPairChallenge;
- (NSURLRequest*) newAppListRequest; - (NSURLRequest*) newAppListRequest;
- (NSURLRequest*) newServerInfoRequest; - (NSURLRequest*) newServerInfoRequest;
- (NSURLRequest*) newHttpServerInfoRequest;
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid; - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid;
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId; - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
- (NSURLRequest*) newQuitAppRequest; - (NSURLRequest*) newQuitAppRequest;
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId; - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
- (void) executeRequestSynchronously:(HttpRequest*)request; - (void) executeRequestSynchronously:(HttpRequest*)request;
- (void) executeRequest:(HttpRequest*)request;
@end @end
+80 -59
View File
@@ -9,13 +9,15 @@
#import "HttpManager.h" #import "HttpManager.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "App.h" #import "TemporaryApp.h"
#include <libxml2/libxml/xmlreader.h> #include <libxml2/libxml/xmlreader.h>
#include <string.h> #include <string.h>
@implementation HttpManager { @implementation HttpManager {
NSString* _baseURL; NSURLSession* _urlSession;
NSString* _baseHTTPURL;
NSString* _baseHTTPSURL;
NSString* _host; NSString* _host;
NSString* _uniqueId; NSString* _uniqueId;
NSString* _deviceName; NSString* _deviceName;
@@ -27,7 +29,8 @@
BOOL _errorOccurred; BOOL _errorOccurred;
} }
static const NSString* PORT = @"47984"; static const NSString* HTTP_PORT = @"47989";
static const NSString* HTTPS_PORT = @"47984";
+ (NSData*) fixXmlVersion:(NSData*) xmlData { + (NSData*) fixXmlVersion:(NSData*) xmlData {
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]; NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
@@ -42,38 +45,63 @@ static const NSString* PORT = @"47984";
_uniqueId = uniqueId; _uniqueId = uniqueId;
_deviceName = deviceName; _deviceName = deviceName;
_cert = cert; _cert = cert;
_baseURL = [[NSString stringWithFormat:@"https://%@:%@", host, PORT] _baseHTTPURL = [NSString stringWithFormat:@"http://%@:%@", host, HTTP_PORT];
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; _baseHTTPSURL = [NSString stringWithFormat:@"https://%@:%@", host, HTTPS_PORT];
_requestLock = dispatch_semaphore_create(0); _requestLock = dispatch_semaphore_create(0);
_respData = [[NSMutableData alloc] init]; _respData = [[NSMutableData alloc] init];
NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
_urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
return self; return self;
} }
- (void) executeRequestSynchronously:(HttpRequest*)request { - (void) executeRequestSynchronously:(HttpRequest*)request {
Log(LOG_D, @"Making Request: %@", request); Log(LOG_D, @"Making Request: %@", request);
[_respData setLength:0]; [_respData setLength:0];
dispatch_sync(dispatch_get_main_queue(), ^{ [[_urlSession dataTaskWithRequest:request.request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
[NSURLConnection connectionWithRequest:request.request delegate:self];
}); if (error != NULL) {
Log(LOG_D, @"Connection error: %@", error);
_errorOccurred = true;
}
else {
Log(LOG_D, @"Received response: %@", response);
if (data != NULL) {
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[_respData appendData:data];
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
_requestResp = [HttpManager fixXmlVersion:_respData];
} else {
_requestResp = _respData;
}
}
}
dispatch_semaphore_signal(_requestLock);
}] resume];
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
if (!_errorOccurred && request.response) { if (!_errorOccurred && request.response) {
[request.response populateWithData:_requestResp]; [request.response populateWithData:_requestResp];
// If the fallback error code was detected, issue the fallback request
if (request.response.statusCode == request.fallbackError && request.fallbackRequest != NULL) {
Log(LOG_D, @"Request failed with fallback error code: %d", request.fallbackError);
request.request = request.fallbackRequest;
request.fallbackError = 0;
request.fallbackRequest = NULL;
[self executeRequestSynchronously:request];
}
} }
_errorOccurred = false; _errorOccurred = false;
} }
- (void) executeRequest:(HttpRequest*)request {
[NSURLConnection connectionWithRequest:request.request delegate:self];
}
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout { - (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL* url = [[NSURL alloc] initWithString:urlString];
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
if (normalTimeout) { if (normalTimeout) {
// Timeout the request after 5 seconds // Timeout the request after 7 seconds
[request setTimeoutInterval:5]; [request setTimeoutInterval:7];
} }
else { else {
// Timeout the request after 60 seconds // Timeout the request after 60 seconds
@@ -84,67 +112,72 @@ static const NSString* PORT = @"47984";
- (NSURLRequest*) newPairRequest:(NSData*)salt { - (NSURLRequest*) newPairRequest:(NSData*)salt {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
// This call blocks while waiting for the user to input the PIN on the PC // This call blocks while waiting for the user to input the PIN on the PC
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newUnpairRequest { - (NSURLRequest*) newUnpairRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge { - (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp { - (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret { - (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret]; NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPSURL, _uniqueId, _deviceName, clientPairSecret];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newPairChallenge { - (NSURLRequest*) newPairChallenge {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName]; NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseHTTPSURL, _uniqueId, _deviceName];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest *)newAppListRequest { - (NSURLRequest *)newAppListRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest *)newServerInfoRequest { - (NSURLRequest *)newServerInfoRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE];
}
- (NSURLRequest *)newHttpServerInfoRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo", _baseHTTPURL];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid { - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid]; NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
// This blocks while the app is launching // This blocks while the app is launching
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId { - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId]; NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, riKey, riKeyId];
// This blocks while the app is resuming // This blocks while the app is resuming
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newQuitAppRequest { - (NSURLRequest*) newQuitAppRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId { - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId {
NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseURL, _uniqueId, appId]; NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseHTTPSURL, _uniqueId, appId];
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
@@ -157,33 +190,6 @@ static const NSString* PORT = @"47984";
return hex; return hex;
} }
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
Log(LOG_D, @"Received response: %@", response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[_respData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
_requestResp = [HttpManager fixXmlVersion:_respData];
} else {
_requestResp = _respData;
}
dispatch_semaphore_signal(_requestLock);
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
SecIdentityRef identity = [self getClientCertificate];
NSArray *certArray = [self getCertificate:identity];
NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
}
// Returns an array containing the certificate // Returns an array containing the certificate
- (NSArray*)getCertificate:(SecIdentityRef) identity { - (NSArray*)getCertificate:(SecIdentityRef) identity {
SecCertificateRef certificate = nil; SecCertificateRef certificate = nil;
@@ -219,10 +225,25 @@ static const NSString* PORT = @"47984";
return identityApp; return identityApp;
} }
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * __nullable))completionHandler {
Log(LOG_D, @"connection error: %@", error); // Allow untrusted server certificates
_errorOccurred = true; if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
dispatch_semaphore_signal(_requestLock); {
completionHandler(NSURLSessionAuthChallengeUseCredential,
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]);
}
// Respond to client certificate challenge with our certificate
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])
{
SecIdentityRef identity = [self getClientCertificate];
NSArray* certArray = [self getCertificate:identity];
NSURLCredential* newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
}
else
{
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL);
}
} }
@end @end
+3
View File
@@ -13,7 +13,10 @@
@property (nonatomic) id<Response> response; @property (nonatomic) id<Response> response;
@property (nonatomic) NSURLRequest* request; @property (nonatomic) NSURLRequest* request;
@property (nonatomic) int fallbackError;
@property (nonatomic) NSURLRequest* fallbackRequest;
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq;
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req; + (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req; + (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
+9
View File
@@ -25,4 +25,13 @@
return request; return request;
} }
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
request.response = response;
request.fallbackError = error;
request.fallbackRequest = fallbackReq;
return request;
}
@end @end
-1
View File
@@ -7,7 +7,6 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h"
static NSString* TAG_STATUS_CODE = @"status_code"; static NSString* TAG_STATUS_CODE = @"status_code";
static NSString* TAG_STATUS_MESSAGE = @"status_message"; static NSString* TAG_STATUS_MESSAGE = @"status_message";
+1 -1
View File
@@ -7,7 +7,7 @@
// //
#import "HttpResponse.h" #import "HttpResponse.h"
#import "App.h" #import "TemporaryApp.h"
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation HttpResponse { @implementation HttpResponse {
+3 -5
View File
@@ -7,8 +7,7 @@
// //
#import "MDNSManager.h" #import "MDNSManager.h"
#import "Host.h" #import "TemporaryHost.h"
#import "DataManager.h"
@implementation MDNSManager { @implementation MDNSManager {
NSNetServiceBrowser* mDNSBrowser; NSNetServiceBrowser* mDNSBrowser;
@@ -47,11 +46,10 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
- (NSArray*) getFoundHosts { - (NSArray*) getFoundHosts {
NSMutableArray* hosts = [[NSMutableArray alloc] init]; NSMutableArray* hosts = [[NSMutableArray alloc] init];
DataManager* dataMan = [[DataManager alloc] init];
for (NSNetService* service in services) { for (NSNetService* service in services) {
if (service.hostName != nil) { if (service.hostName != nil) {
Host* host = [dataMan createHost]; TemporaryHost* host = [[TemporaryHost alloc] init];
host.address = service.hostName; host.activeAddress = host.address = service.hostName;
host.name = host.address; host.name = host.address;
[hosts addObject:host]; [hosts addObject:host];
} }
+1 -1
View File
@@ -22,6 +22,6 @@
- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id<PairCallback>)callback; - (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id<PairCallback>)callback;
- (NSString*) generatePIN; - (NSString*) generatePIN;
- (NSData*) saltPIN:(NSString*)PIN; - (NSData*) saltPIN:(NSString*)PIN;
- (void) initiatePair; - (void) initiatePair:(int)serverMajorVersion;
@end @end
+58 -22
View File
@@ -31,23 +31,31 @@
- (void) main { - (void) main {
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]
fallbackError:401 fallbackRequest:[_httpManager newHttpServerInfoRequest]]];
if (serverInfoResp == nil) { if (serverInfoResp == nil) {
[_callback pairFailed:@"Unable to connect to PC"]; [_callback pairFailed:@"Unable to connect to PC"];
return; return;
} }
if ([serverInfoResp isStatusOk]) { if ([serverInfoResp isStatusOk]) {
if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) { if (![[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_AVAILABLE"]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."]; [_callback pairFailed:@"You must stop streaming before attempting to pair."];
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) { } else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair]; NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
if (appversion == nil) {
[_callback pairFailed:@"Missing XML element"];
return;
}
[self initiatePair: [[appversion substringToIndex:1] intValue]];
} else { } else {
[_callback alreadyPaired]; [_callback alreadyPaired];
} }
} }
} }
- (void) initiatePair { - (void) initiatePair:(int)serverMajorVersion {
Log(LOG_I, @"Pairing with generation %d server", serverMajorVersion);
NSString* PIN = [self generatePIN]; NSString* PIN = [self generatePIN];
NSData* salt = [self saltPIN:PIN]; NSData* salt = [self saltPIN:PIN];
Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt); Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
@@ -60,15 +68,29 @@
} }
NSInteger pairedStatus; NSInteger pairedStatus;
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing was declined by the target."]; [_callback pairFailed:@"Pairing was declined by the target."];
return; return;
} }
NSString* plainCert = [pairResp getStringTag:@"plaincert"]; NSString* plainCert = [pairResp getStringTag:@"plaincert"];
if ([plainCert length] == 0) {
[_callback pairFailed:@"Another pairing attempt is already in progress."];
return;
}
CryptoManager* cryptoMan = [[CryptoManager alloc] init]; CryptoManager* cryptoMan = [[CryptoManager alloc] init];
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt]; NSData* aesKey;
// Gen 7 servers use SHA256 to get the key
int hashLength;
if (serverMajorVersion >= 7) {
aesKey = [cryptoMan createAESKeyFromSaltSHA256:salt];
hashLength = 32;
}
else {
aesKey = [cryptoMan createAESKeyFromSaltSHA1:salt];
hashLength = 20;
}
NSData* randomChallenge = [Utils randomBytes:16]; NSData* randomChallenge = [Utils randomBytes:16];
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey]; NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
@@ -78,8 +100,8 @@
if (![self verifyResponseStatus:challengeResp]) { if (![self verifyResponseStatus:challengeResp]) {
return; return;
} }
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #2 failed"]; [_callback pairFailed:@"Pairing stage #2 failed"];
return; return;
} }
@@ -87,11 +109,18 @@
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]]; NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]];
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey]; NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)]; NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, hashLength)];
NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(20, 16)]; NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(hashLength, 16)];
NSData* clientSecret = [Utils randomBytes:16]; NSData* clientSecret = [Utils randomBytes:16];
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]]; NSData* challengeRespHashInput = [self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret];
NSData* challengeRespHash;
if (serverMajorVersion >= 7) {
challengeRespHash = [cryptoMan SHA256HashData: challengeRespHashInput];
}
else {
challengeRespHash = [cryptoMan SHA1HashData: challengeRespHashInput];
}
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey]; NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
HttpResponse* secretResp = [[HttpResponse alloc] init]; HttpResponse* secretResp = [[HttpResponse alloc] init];
@@ -99,8 +128,8 @@
if (![self verifyResponseStatus:secretResp]) { if (![self verifyResponseStatus:secretResp]) {
return; return;
} }
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![secretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #3 failed"]; [_callback pairFailed:@"Pairing stage #3 failed"];
return; return;
} }
@@ -110,14 +139,21 @@
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)]; NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) { if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Server certificate invalid"]; [_callback pairFailed:@"Server certificate invalid"];
return; return;
} }
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]]; NSData* serverChallengeRespHashInput = [self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret];
NSData* serverChallengeRespHash;
if (serverMajorVersion >= 7) {
serverChallengeRespHash = [cryptoMan SHA256HashData: serverChallengeRespHashInput];
}
else {
serverChallengeRespHash = [cryptoMan SHA1HashData: serverChallengeRespHashInput];
}
if (![serverChallengeRespHash isEqual:serverResponse]) { if (![serverChallengeRespHash isEqual:serverResponse]) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Incorrect PIN"]; [_callback pairFailed:@"Incorrect PIN"];
return; return;
} }
@@ -128,8 +164,8 @@
if (![self verifyResponseStatus:clientSecretResp]) { if (![self verifyResponseStatus:clientSecretResp]) {
return; return;
} }
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #4 failed"]; [_callback pairFailed:@"Pairing stage #4 failed"];
return; return;
} }
@@ -139,8 +175,8 @@
if (![self verifyResponseStatus:clientPairChallengeResp]) { if (![self verifyResponseStatus:clientPairChallengeResp]) {
return; return;
} }
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #5 failed"]; [_callback pairFailed:@"Pairing stage #5 failed"];
return; return;
} }
@@ -149,11 +185,11 @@
- (BOOL) verifyResponseStatus:(HttpResponse*)resp { - (BOOL) verifyResponseStatus:(HttpResponse*)resp {
if (resp == nil) { if (resp == nil) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Network error occured."]; [_callback pairFailed:@"Network error occured."];
return false; return false;
} else if (![resp isStatusOk]) { } else if (![resp isStatusOk]) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:resp.statusMessage]; [_callback pairFailed:resp.statusMessage];
return false; return false;
} else { } else {
+4 -1
View File
@@ -7,6 +7,7 @@
// //
#import "HttpResponse.h" #import "HttpResponse.h"
#import "TemporaryHost.h"
#define TAG_HOSTNAME @"hostname" #define TAG_HOSTNAME @"hostname"
#define TAG_EXTERNAL_IP @"ExternalIP" #define TAG_EXTERNAL_IP @"ExternalIP"
@@ -14,11 +15,13 @@
#define TAG_UNIQUE_ID @"uniqueid" #define TAG_UNIQUE_ID @"uniqueid"
#define TAG_MAC_ADDRESS @"mac" #define TAG_MAC_ADDRESS @"mac"
#define TAG_PAIR_STATUS @"PairStatus" #define TAG_PAIR_STATUS @"PairStatus"
#define TAG_STATE @"state"
#define TAG_CURRENT_GAME @"currentgame"
@interface ServerInfoResponse : HttpResponse <Response> @interface ServerInfoResponse : HttpResponse <Response>
- (void) populateWithData:(NSData *)data; - (void) populateWithData:(NSData *)data;
- (void) populateHost:(Host*)host; - (void) populateHost:(TemporaryHost*)host;
@end @end
+10 -1
View File
@@ -17,12 +17,21 @@
[super parseData]; [super parseData];
} }
- (void) populateHost:(Host*)host { - (void) populateHost:(TemporaryHost*)host {
host.name = [[self getStringTag:TAG_HOSTNAME] trim]; host.name = [[self getStringTag:TAG_HOSTNAME] trim];
host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim]; host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim];
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim]; host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim]; host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim];
host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim]; host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim];
host.currentGame = [[self getStringTag:TAG_CURRENT_GAME] trim];
NSString *state = [[self getStringTag:TAG_STATE] trim];
if ([state hasSuffix:@"_SERVER_AVAILABLE"]) {
// GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer
// has the semantics that its name would indicate. To contain the effects of this change as much
// as possible, we'll force the current game to zero if the server isn't in a streaming session.
host.currentGame = @"0";
}
NSInteger pairStatus; NSInteger pairStatus;
if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) { if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) {
+2 -2
View File
@@ -7,10 +7,10 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
@interface WakeOnLanManager : NSObject @interface WakeOnLanManager : NSObject
+ (void) wakeHost:(Host*)host; + (void) wakeHost:(TemporaryHost*)host;
@end @end
+70 -35
View File
@@ -12,51 +12,86 @@
#import <sys/socket.h> #import <sys/socket.h>
#import <netinet/in.h> #import <netinet/in.h>
#import <arpa/inet.h> #import <arpa/inet.h>
#import <netdb.h>
@implementation WakeOnLanManager @implementation WakeOnLanManager
static const int numPorts = 5; static const int numPorts = 5;
static const int ports[numPorts] = {7, 9, 47998, 47999, 48000}; static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
+ (void) wakeHost:(Host*)host { + (void) populateAddress:(struct sockaddr_storage*)addr withPort:(unsigned short)port {
NSData* wolPayload = [WakeOnLanManager createPayload:host]; if (addr->ss_family == AF_INET) {
CFDataRef dataPayload = CFDataCreate(kCFAllocatorDefault, [wolPayload bytes], [wolPayload length]); struct sockaddr_in *sin = (struct sockaddr_in*)addr;
CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL); sin->sin_port = htons(port);
if (!wolSocket) {
CFRelease(dataPayload);
Log(LOG_E, @"Failed to create WOL socket");
return;
} }
Log(LOG_I, @"WOL socket created"); else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
struct sockaddr_in addr; sin6->sin6_port = htons(port);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_len = sizeof(addr);
for (int i = 0; i < 2; i++) {
// try all ip addresses
if (i == 0) {
inet_aton([host.localAddress UTF8String], &addr.sin_addr);
} else {
inet_aton([host.externalAddress UTF8String], &addr.sin_addr);
}
CFDataRef dataAddress = CFDataCreate(kCFAllocatorDefault, (unsigned char*)&addr, sizeof(addr));
// try all ports
for (int j = 0; j < numPorts; j++) {
addr.sin_port = htons(ports[j]);
Log(LOG_I, @"Sending WOL packet");
CFSocketSendData(wolSocket, dataAddress, dataPayload, 0);
}
CFRelease(dataAddress);
} }
CFRelease(dataPayload);
} }
+ (NSData*) createPayload:(Host*)host { + (void) wakeHost:(TemporaryHost*)host {
NSData* wolPayload = [WakeOnLanManager createPayload:host];
for (int i = 0; i < 3; i++) {
const char* address;
struct addrinfo hints, *res, *curr;
// try all ip addresses
if (i == 0 && host.localAddress != nil) {
address = [host.localAddress UTF8String];
} else if (i == 1 && host.externalAddress != nil) {
address = [host.externalAddress UTF8String];
} else if (i == 2 && host.address != nil) {
address = [host.address UTF8String];
} else {
// Requested address wasn't present
continue;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
if (getaddrinfo(address, NULL, &hints, &res) != 0 || res == NULL) {
// Failed to resolve address
Log(LOG_E, @"Failed to resolve WOL address");
continue;
}
// Try all addresses that this DNS name resolves to. We have
// to create a new socket each time because the addresses
// may be different address families.
for (curr = res; curr != NULL; curr = curr->ai_next) {
int wolSocket;
wolSocket = socket(curr->ai_family, SOCK_DGRAM, IPPROTO_UDP);
if (wolSocket < 0) {
Log(LOG_E, @"Failed to create WOL socket");
continue;
}
struct sockaddr_storage addr;
memset(&addr, 0, sizeof(addr));
memcpy(&addr, curr->ai_addr, curr->ai_addrlen);
for (int j = 0; j < numPorts; j++) {
[WakeOnLanManager populateAddress:&addr withPort:ports[j]];
long err = sendto(wolSocket,
[wolPayload bytes],
[wolPayload length],
0,
(struct sockaddr*)&addr,
curr->ai_addrlen);
Log(LOG_I, @"Sending WOL packet returned: %ld", err);
}
close(wolSocket);
}
freeaddrinfo(res);
}
}
+ (NSData*) createPayload:(TemporaryHost*)host {
NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102]; NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102];
// 6 bytes of FF // 6 bytes of FF
+6 -7
View File
@@ -14,20 +14,19 @@
- (void) connectionStarted; - (void) connectionStarted;
- (void) connectionTerminated:(long)errorCode; - (void) connectionTerminated:(long)errorCode;
- (void) stageStarting:(char*)stageName; - (void) stageStarting:(const char*)stageName;
- (void) stageComplete:(char*)stageName; - (void) stageComplete:(const char*)stageName;
- (void) stageFailed:(char*)stageName withError:(long)errorCode; - (void) stageFailed:(const char*)stageName withError:(long)errorCode;
- (void) launchFailed:(NSString*)message; - (void) launchFailed:(NSString*)message;
- (void) displayMessage:(char*)message; - (void) displayMessage:(const char*)message;
- (void) displayTransientMessage:(char*)message; - (void) displayTransientMessage:(const char*)message;
@end @end
@interface Connection : NSOperation <NSStreamDelegate> @interface Connection : NSOperation <NSStreamDelegate>
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion; -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks;
-(void) terminate; -(void) terminate;
-(void) terminateInternal;
-(void) main; -(void) main;
@end @end
+61 -55
View File
@@ -15,14 +15,14 @@
#include "opus.h" #include "opus.h"
@implementation Connection { @implementation Connection {
IP_ADDRESS _host; SERVER_INFORMATION _serverInfo;
STREAM_CONFIGURATION _streamConfig; STREAM_CONFIGURATION _streamConfig;
CONNECTION_LISTENER_CALLBACKS _clCallbacks; CONNECTION_LISTENER_CALLBACKS _clCallbacks;
DECODER_RENDERER_CALLBACKS _drCallbacks; DECODER_RENDERER_CALLBACKS _drCallbacks;
AUDIO_RENDERER_CALLBACKS _arCallbacks; AUDIO_RENDERER_CALLBACKS _arCallbacks;
int _serverMajorVersion;
} }
static NSLock* initLock;
static OpusDecoder *opusDecoder; static OpusDecoder *opusDecoder;
static id<ConnectionCallbacks> _callbacks; static id<ConnectionCallbacks> _callbacks;
@@ -65,11 +65,16 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength]; return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
} }
void ArInit(void) void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
{ {
int err; int err;
opusDecoder = opus_decoder_create(48000, 2, &err); // We only support stereo for now
assert(audioConfiguration == AUDIO_CONFIGURATION_STEREO);
opusDecoder = opus_decoder_create(opusConfig->sampleRate,
opusConfig->channelCount,
&err);
audioLock = [[NSLock alloc] init]; audioLock = [[NSLock alloc] init];
@@ -77,9 +82,9 @@ void ArInit(void)
NSError *audioSessionError = nil; NSError *audioSessionError = nil;
AVAudioSession* audioSession = [AVAudioSession sharedInstance]; AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError]; [audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError]; [audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
[audioSession setPreferredOutputNumberOfChannels:2 error:&audioSessionError]; [audioSession setPreferredOutputNumberOfChannels:opusConfig->channelCount error:&audioSessionError];
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError]; [audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
[audioSession setActive: YES error: &audioSessionError]; [audioSession setActive: YES error: &audioSessionError];
@@ -99,11 +104,11 @@ void ArInit(void)
} }
AudioStreamBasicDescription audioFormat = {0}; AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = 48000; audioFormat.mSampleRate = opusConfig->sampleRate;
audioFormat.mBitsPerChannel = 16; audioFormat.mBitsPerChannel = 16;
audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = 2; audioFormat.mChannelsPerFrame = opusConfig->channelCount;
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8); audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame; audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame; audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
@@ -137,16 +142,26 @@ void ArInit(void)
if (status) { if (status) {
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status); Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
} }
status = AudioOutputUnitStart(audioUnit);
if (status) {
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
}
} }
void ArRelease(void) void ArCleanup(void)
{ {
if (opusDecoder != NULL) { if (opusDecoder != NULL) {
opus_decoder_destroy(opusDecoder); opus_decoder_destroy(opusDecoder);
opusDecoder = NULL; opusDecoder = NULL;
} }
OSStatus status = AudioUnitUninitialize(audioUnit); OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
}
status = AudioUnitUninitialize(audioUnit);
if (status) { if (status) {
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status); Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
} }
@@ -166,22 +181,6 @@ void ArRelease(void)
} }
} }
void ArStart(void)
{
OSStatus status = AudioOutputUnitStart(audioUnit);
if (status) {
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
}
}
void ArStop(void)
{
OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
}
}
void ArDecodeAndPlaySample(char* sampleData, int sampleLength) void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
{ {
int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0); int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0);
@@ -229,17 +228,17 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
void ClStageStarting(int stage) void ClStageStarting(int stage)
{ {
[_callbacks stageStarting:(char*)LiGetStageName(stage)]; [_callbacks stageStarting:LiGetStageName(stage)];
} }
void ClStageComplete(int stage) void ClStageComplete(int stage)
{ {
[_callbacks stageComplete:(char*)LiGetStageName(stage)]; [_callbacks stageComplete:LiGetStageName(stage)];
} }
void ClStageFailed(int stage, long errorCode) void ClStageFailed(int stage, long errorCode)
{ {
[_callbacks stageFailed:(char*)LiGetStageName(stage) withError:errorCode]; [_callbacks stageFailed:LiGetStageName(stage) withError:errorCode];
} }
void ClConnectionStarted(void) void ClConnectionStarted(void)
@@ -252,40 +251,49 @@ void ClConnectionTerminated(long errorCode)
[_callbacks connectionTerminated: errorCode]; [_callbacks connectionTerminated: errorCode];
} }
void ClDisplayMessage(char* message) void ClDisplayMessage(const char* message)
{ {
[_callbacks displayMessage: message]; [_callbacks displayMessage: message];
} }
void ClDisplayTransientMessage(char* message) void ClDisplayTransientMessage(const char* message)
{ {
[_callbacks displayTransientMessage: message]; [_callbacks displayTransientMessage: message];
} }
-(void) terminateInternal -(void) terminate
{ {
// We dispatch this async to get out because this can be invoked // We dispatch this async to get out because this can be invoked
// on a thread inside common and we don't want to deadlock // on a thread inside common and we don't want to deadlock. It also avoids
dispatch_async(dispatch_get_main_queue(), ^{ // blocking on the caller's thread waiting to acquire initLock.
// This is safe to call even before LiStartConnection dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[initLock lock];
LiStopConnection(); LiStopConnection();
[initLock unlock];
}); });
} }
-(void) terminate -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks
{
// We're guaranteed to not be on a moonlight-common thread
// here so it's safe to call stop directly
LiStopConnection();
}
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
{ {
self = [super init]; self = [super init];
_host = config.hostAddr;
// Use a lock to ensure that only one thread is initializing
// or deinitializing a connection at a time.
if (initLock == nil) {
initLock = [[NSLock alloc] init];
}
LiInitializeServerInformation(&_serverInfo);
_serverInfo.address = [config.host cStringUsingEncoding:NSUTF8StringEncoding];
_serverInfo.serverInfoAppVersion = [config.appVersion cStringUsingEncoding:NSUTF8StringEncoding];
if (config.gfeVersion != nil) {
_serverInfo.serverInfoGfeVersion = [config.gfeVersion cStringUsingEncoding:NSUTF8StringEncoding];
}
renderer = myRenderer; renderer = myRenderer;
_callbacks = callbacks; _callbacks = callbacks;
_serverMajorVersion = serverMajorVersion;
LiInitializeStreamConfiguration(&_streamConfig);
_streamConfig.width = config.width; _streamConfig.width = config.width;
_streamConfig.height = config.height; _streamConfig.height = config.height;
_streamConfig.fps = config.frameRate; _streamConfig.fps = config.frameRate;
@@ -299,18 +307,15 @@ void ClDisplayTransientMessage(char* message)
int riKeyId = htonl(config.riKeyId); int riKeyId = htonl(config.riKeyId);
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId)); memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
_drCallbacks.setup = NULL; LiInitializeVideoCallbacks(&_drCallbacks);
_drCallbacks.start = NULL;
_drCallbacks.stop = NULL;
_drCallbacks.release = NULL;
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit; _drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
LiInitializeAudioCallbacks(&_arCallbacks);
_arCallbacks.init = ArInit; _arCallbacks.init = ArInit;
_arCallbacks.start = ArStart; _arCallbacks.cleanup = ArCleanup;
_arCallbacks.stop = ArStop;
_arCallbacks.release = ArRelease;
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample; _arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
LiInitializeConnectionCallbacks(&_clCallbacks);
_clCallbacks.stageStarting = ClStageStarting; _clCallbacks.stageStarting = ClStageStarting;
_clCallbacks.stageComplete = ClStageComplete; _clCallbacks.stageComplete = ClStageComplete;
_clCallbacks.stageFailed = ClStageFailed; _clCallbacks.stageFailed = ClStageFailed;
@@ -405,13 +410,14 @@ static OSStatus playbackCallback(void *inRefCon,
-(void) main -(void) main
{ {
LiStartConnection(_host, [initLock lock];
LiStartConnection(&_serverInfo,
&_streamConfig, &_streamConfig,
&_clCallbacks, &_clCallbacks,
&_drCallbacks, &_drCallbacks,
&_arCallbacks, &_arCallbacks,
NULL, NULL, 0);
NULL, 0, _serverMajorVersion); [initLock unlock];
} }
@end @end
+2 -1
View File
@@ -11,8 +11,9 @@
@interface StreamConfiguration : NSObject @interface StreamConfiguration : NSObject
@property NSString* host; @property NSString* host;
@property NSString* appVersion;
@property NSString* gfeVersion;
@property NSString* appID; @property NSString* appID;
@property int hostAddr;
@property int width; @property int width;
@property int height; @property int height;
@property int frameRate; @property int frameRate;
Loaded 100 of 128 files, more files were not shown because too many files have changed in this diff. Show more