Compare commits

...
121 Commits
Author SHA1 Message Date
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
Diego Waxemberg 20f82ff739 updated project to Moonlight and created build 0.9.1 2015-05-31 23:57:47 -07:00
Diego Waxemberg 4d55a6a7e9 missed a file in earlier commit, this actually fixes the on screen control issues 2015-05-31 23:57:04 -07:00
Cameron Gutman d7ec41d56e Fix a controller batching bug 2015-06-01 01:30:18 -05:00
Diego Waxemberg a6a1929a43 updated icons to have different resolutions and fixed layout for smaller iPhones 2015-05-31 23:22:20 -07:00
Cameron Gutman 722850ceb6 Fix mouse batching bug 2015-05-29 16:42:00 -05:00
Diego Waxemberg 5a976764c3 now use custom edge swipe detection 2015-05-29 00:46:43 -07:00
Diego Waxemberg f90becb2f6 no longer try to parse responses when a network error occurs 2015-05-29 00:15:48 -07:00
Diego Waxemberg 5296b2eb39 now stop app asset requests before attempting to start a stream 2015-05-28 23:47:30 -07:00
Diego Waxemberg 987a30e15f updated style for moonlight 2015-05-28 23:39:13 -07:00
Diego Waxemberg 0880c3639c Merge branch 'master' of github.com:limelight-stream/limelight-ios 2015-05-28 23:38:09 -07:00
Diego Waxemberg 2972d40d92 added limit to app asset request 2015-05-28 23:37:55 -07:00
Cameron Gutman c4430ef18d Use the new optimizations added to common-c 2015-05-28 15:17:37 -05:00
Cameron Gutman 6b97af13bf Update common-c and remove unused callbacks 2015-05-13 23:13:20 -05:00
Cameron Gutman cd18ca64bb Fix build of tests and a warning in the main app 2015-05-13 23:07:05 -05:00
Diego Waxemberg d3c6302681 bumping common 2015-05-12 21:54:00 -04:00
Diego Waxemberg 58bd3cc706 Merge branch 'master' of github.com:limelight-stream/limelight-ios 2015-05-12 21:49:31 -04:00
Diego Waxemberg 8d3401f962 Changed name from Limelight to Moonlight due to C&D from Limelight
Networks, Inc.
2015-05-12 21:48:30 -04:00
Cameron Gutman dfc86015bd Renaming projects to Moonlight 2015-04-21 21:43:57 -04:00
Diego Waxemberg 772ee3a680 v0.9.0 first release candidate 2015-04-05 22:02:45 -07:00
Cameron Gutman f217ca9bbe Set the bitrate slider value based on the real interval instead of 1000 2015-04-06 00:48:54 -04:00
Cameron Gutman fab8d604d2 Check UUID length is non-zero before adding a new host 2015-04-06 00:27:36 -04:00
Cameron Gutman 7767ae497b Revert "Added a hack to de-duplicate hosts and some more checks when adding a host to minimize the chances for dupes"
This reverts commit fd9ee45dac.
2015-04-06 00:22:51 -04:00
Cameron Gutman 58e41dfcf1 Revert "forgot to add project file"
This reverts commit dfa07bf94b.
2015-04-06 00:22:45 -04:00
Diego Waxemberg 796ab2bf90 should now save hosts discovered through mdns 2015-04-05 21:18:22 -07:00
Diego Waxemberg dfa07bf94b forgot to add project file 2015-04-05 20:30:44 -07:00
Diego Waxemberg f43c74d59b trim whitespace from server info responses 2015-04-05 20:30:13 -07:00
Diego Waxemberg fd9ee45dac Added a hack to de-duplicate hosts and some more checks when adding a host to minimize the chances for dupes 2015-04-05 20:08:21 -07:00
Diego Waxemberg 40a04eb08b v0.4.1 2015-04-05 19:05:08 -07:00
Diego Waxemberg e9cff8f7b7 Merge branch 'master' of github.com:limelight-stream/limelight-ios 2015-04-05 19:00:01 -07:00
Cameron Gutman acee0af9df Update common to fix #58 2015-04-05 21:59:31 -04:00
Diego Waxemberg 8d3e81ed25 L3/R3 now show up on simple on-screen controls 2015-04-05 18:59:11 -07:00
Diego Waxemberg 5f8b0672f7 v0.4.0 build 2 2015-04-05 17:36:30 -07:00
Diego Waxemberg 62bbec3c5d now hide the loading spinner on network errors 2015-04-05 17:25:05 -07:00
Diego Waxemberg 65f7e75736 now show loading frame when waiting for background tasks 2015-02-24 22:33:14 -05:00
Diego Waxemberg 3617ea98e2 created a loading frame 2015-02-24 22:13:33 -05:00
Diego Waxemberg 81c84597c8 added ability to tag logs for easier filtering 2015-02-24 00:03:21 -05:00
Diego Waxemberg ea231e16b6 changed log level for connection errors 2015-02-24 00:03:02 -05:00
Diego Waxemberg c205b99080 changed bitrate to 0.5mbps interval 2015-02-24 00:02:37 -05:00
Diego Waxemberg e3dd4e7238 Created logger with log levels 2015-02-10 21:26:55 -05:00
Diego Waxemberg 0c36754ebe Now stop retrieving assets when the user deselects the host 2015-02-10 18:40:22 -05:00
Diego Waxemberg e7dc22bb15 Host discovery is much better now 2015-02-10 17:40:49 -05:00
Cameron Gutman d4b5ec5764 Only retry 5 times to fetch box art 2015-02-10 16:13:06 -05:00
Diego Waxemberg bed8c729f9 Merge branch 'master' of github.com:limelight-stream/limelight-ios
# By Michelle Bergeron
# Via Michelle Bergeron
* 'master' of github.com:limelight-stream/limelight-ios:
  Update README.md
2015-02-10 15:49:57 -05:00
Diego Waxemberg 0a767767fb Fixed crash if the applist did not contain certain info about the app 2015-02-10 15:48:29 -05:00
Diego Waxemberg e31df3f44e Fixed unregistering controllers and emulating extra buttons 2015-02-10 15:48:01 -05:00
Michelle Bergeron 9c9795ab1f Update README.md 2015-02-08 19:40:31 -08:00
Diego Waxemberg c7c28a18c5 hooked up multiple controller support 2015-02-02 03:22:09 -05:00
Diego Waxemberg 93119f25a6 added support for multiple controllers 2015-02-02 02:42:38 -05:00
Diego Waxemberg 1313429f65 Fix static analysis warning 2015-02-01 21:09:21 -05:00
Cameron Gutman 11c27baaf8 Finish GFE 2.1.x compatibility 2015-02-01 20:31:57 -05:00
Cameron Gutman d728e63bb4 Merge branch 'master' of github.com:limelight-stream/limelight-ios 2015-02-01 20:21:59 -05:00
Cameron Gutman 7d584fb4de Update for backwards compatibility with GFE 2.1.x (WIP) 2015-02-01 20:21:54 -05:00
Diego Waxemberg 7d7adb0753 now pass stream configuration through the segue 2015-02-01 19:46:28 -05:00
Diego Waxemberg 337e5e3d9d fixed host online state and simplified some code 2015-02-01 18:33:36 -05:00
Diego Waxemberg 879f304a79 Refactored http communications to be more abstract and OOP 2015-02-01 04:26:47 -05:00
Diego Waxemberg 75d3f23f0a forgot to commit the project 2015-01-31 20:22:23 -05:00
Diego Waxemberg 14f30349a3 improved app asset management and retrying to acquire 2015-01-31 20:10:14 -05:00
Diego Waxemberg 8e721a9c6a Fixed pairing bug 2015-01-31 16:13:25 -05:00
Diego Waxemberg e3e95c29f6 Created http response class and added error checking 2015-01-31 01:57:23 -05:00
Diego Waxemberg 4224d02eae created build 0.3.2 2015-01-23 18:20:53 -05:00
Cameron Gutman f300119d23 Update common for GFE 2.2.2+ 2015-01-22 16:55:49 -05:00
253 changed files with 2713 additions and 1751 deletions
+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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8 -13
View File
@@ -1,7 +1,8 @@
<?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="6254" systemVersion="14C81f" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8121.17" systemVersion="15A204h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@@ -10,24 +11,21 @@
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/> <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2014 Limelight Stream. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye"> <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">
<rect key="frame" x="22" y="439" width="437" height="21"/> <rect key="frame" x="18" y="439.5" width="444" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.070588235294117646" green="0.45490196078431372" blue="0.074509803921568626" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
<variation key="widthClass=compact"> <variation key="widthClass=compact">
<fontDescription key="fontDescription" type="system" pointSize="11"/> <fontDescription key="fontDescription" type="system" pointSize="11"/>
</variation> </variation>
</label> </label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Limelight Flat Design Banner" translatesAutoresizingMaskIntoConstraints="NO" id="lr8-1h-ydW">
<rect key="frame" x="-8" y="115" width="496" height="251"/>
</imageView>
</subviews> </subviews>
<animations/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/> <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<constraints> <constraints>
<constraint firstAttribute="centerY" secondItem="lr8-1h-ydW" secondAttribute="centerY" id="C8A-9E-cM6"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/> <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/>
<constraint firstAttribute="centerX" secondItem="lr8-1h-ydW" secondAttribute="centerX" id="WCv-Cd-TyR"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/> <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
</constraints> </constraints>
<nil key="simulatedStatusBarMetrics"/> <nil key="simulatedStatusBarMetrics"/>
@@ -35,7 +33,4 @@
<point key="canvasLocation" x="404" y="445"/> <point key="canvasLocation" x="404" y="445"/>
</view> </view>
</objects> </objects>
<resources>
<image name="Limelight Flat Design Banner" width="496" height="251"/>
</resources>
</document> </document>
-18
View File
@@ -1,18 +0,0 @@
//
// App.h
// Limelight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight 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
// Limelight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved.
//
#import "App.h"
#import "HttpManager.h"
@implementation App
@synthesize appId, appName, appImage, isRunning;
@end
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// AppDelegate.h // AppDelegate.h
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/17/14. // Created by Diego Waxemberg on 1/17/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
+5 -5
View File
@@ -1,9 +1,9 @@
// //
// AppDelegate.m // AppDelegate.m
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/17/14. // Created by Diego Waxemberg on 1/17/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "AppDelegate.h" #import "AppDelegate.h"
@@ -85,7 +85,7 @@ static NSOperationQueue* mainQueue;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately. // Replace this implementation with code to handle the error appropriately.
// 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. // 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.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]); Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort(); abort();
} }
} }
@@ -103,7 +103,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;
@@ -159,7 +159,7 @@ static NSOperationQueue* mainQueue;
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/ */
NSLog(@"Unresolved error %@, %@", error, [error userInfo]); Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort(); abort();
} }
+3 -2
View File
@@ -1,9 +1,9 @@
// //
// CryptoManager.h // CryptoManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/14/14. // Created by Diego Waxemberg on 10/14/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -16,6 +16,7 @@
+ (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*) createAESKeyFromSalt:(NSData*)saltedPIN;
- (NSData*) SHA1HashData:(NSData*)data; - (NSData*) SHA1HashData:(NSData*)data;
+18 -12
View File
@@ -1,9 +1,9 @@
// //
// CryptoManager.m // CryptoManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/14/14. // Created by Diego Waxemberg on 10/14/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "CryptoManager.h" #import "CryptoManager.h"
@@ -76,8 +76,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);
@@ -86,7 +92,7 @@ static NSData* p12 = nil;
BIO_free(bio); BIO_free(bio);
if (!x509) { if (!x509) {
NSLog(@"ERROR: unable to parse certificate in memory"); Log(LOG_E, @"Unable to parse certificate in memory");
return NULL; return NULL;
} }
@@ -105,7 +111,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);
@@ -115,7 +121,7 @@ static NSData* p12 = nil;
BIO_free(bio); BIO_free(bio);
if (!pkey) { if (!pkey) {
NSLog(@"ERROR: unable to parse private key in memory!"); Log(LOG_E, @"Unable to parse private key in memory!");
return NULL; return NULL;
} }
@@ -188,14 +194,14 @@ 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);
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (!x509) { if (!x509) {
NSLog(@"ERROR: unable to parse certificate in memory!"); Log(LOG_E, @"Unable to parse certificate in memory!");
return NULL; return NULL;
} }
return [NSData dataWithBytes:x509->signature->data length:x509->signature->length]; return [NSData dataWithBytes:x509->signature->data length:x509->signature->length];
@@ -206,7 +212,7 @@ static NSData* p12 = nil;
dispatch_once(&pred, ^{ dispatch_once(&pred, ^{
if (![CryptoManager keyPairExists]) { if (![CryptoManager keyPairExists]) {
NSLog(@"Generating Certificate... "); Log(LOG_I, @"Generating Certificate... ");
CertKeyPair certKeyPair = generateCertKeyPair(); CertKeyPair certKeyPair = generateCertKeyPair();
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
@@ -215,10 +221,10 @@ static NSData* p12 = nil;
NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"]; NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"]; NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
//NSLog(@"Writing cert and key to: \n%@\n%@", certFile, keyPairFile); //Log(LOG_D, @"Writing cert and key to: \n%@\n%@", certFile, keyPairFile);
saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair); saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair);
freeCertKeyPair(certKeyPair); freeCertKeyPair(certKeyPair);
NSLog(@"Certificate created"); Log(LOG_I, @"Certificate created");
} }
}); });
} }
@@ -233,7 +239,7 @@ static NSData* p12 = nil;
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]]; NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)]; [uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
//NSLog(@"Unique ID: %@", uniqueId); //Log(LOG_D, @"Unique ID: %@", uniqueId);
return [NSString stringWithString:uniqueId]; return [NSString stringWithString:uniqueId];
} }
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// mkcert.h // mkcert.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/16/14. // Created by Diego Waxemberg on 10/16/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#ifndef Limelight_mkcert_h #ifndef Limelight_mkcert_h
@@ -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
+26
View File
@@ -0,0 +1,26 @@
//
// 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;
NS_ASSUME_NONNULL_BEGIN
@interface App : NSManagedObject
@property BOOL isRunning;
- (NSComparisonResult)compareName:(App *)other;
@end
NS_ASSUME_NONNULL_END
#import "App+CoreDataProperties.h"
+20
View File
@@ -0,0 +1,20 @@
//
// App.m
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import "App.h"
#import "Host.h"
@implementation App
@synthesize isRunning;
- (NSComparisonResult)compareName:(App *)other {
return [self.name caseInsensitiveCompare:other.name];
}
@end
+6 -3
View File
@@ -1,15 +1,16 @@
// //
// DataManager.h // DataManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Settings.h" #import "Settings.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "Host.h" #import "Host.h"
#import "App.h"
@interface DataManager : NSObject @interface DataManager : NSObject
@@ -18,8 +19,10 @@
- (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; - (Settings*) retrieveSettings;
- (NSArray*) retrieveHosts; - (NSArray*) retrieveHosts;
- (void) saveHosts; - (void) saveData;
- (Host*) createHost; - (Host*) createHost;
- (void) removeHost:(Host*)host; - (void) removeHost:(Host*)host;
- (App*) createApp;
- (void) removeApp:(App*)app;
@end @end
+17 -8
View File
@@ -1,9 +1,9 @@
// //
// DataManager.m // DataManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "DataManager.h" #import "DataManager.h"
@@ -20,14 +20,14 @@
Settings* settingsToSave = [self retrieveSettings]; Settings* settingsToSave = [self retrieveSettings];
settingsToSave.framerate = [NSNumber numberWithInteger:framerate]; settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
// Bitrate is persisted in kbps // Bitrate is persisted in kbps
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate * 1000]; settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
settingsToSave.height = [NSNumber numberWithInteger:height]; settingsToSave.height = [NSNumber numberWithInteger:height];
settingsToSave.width = [NSNumber numberWithInteger:width]; settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls]; settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
NSError* error; NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) { if (![[self.appDelegate managedObjectContext] save:&error]) {
NSLog(@"ERROR: Unable to save settings to database"); Log(LOG_E, @"Unable to save settings to database: %@", error);
} }
[self.appDelegate saveContext]; [self.appDelegate saveContext];
} }
@@ -48,18 +48,18 @@
- (Host*) createHost { - (Host*) createHost {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]];
Host* host = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
return host;
} }
- (void) removeHost:(Host*)host { - (void) removeHost:(Host*)host {
[[self.appDelegate managedObjectContext] deleteObject:host]; [[self.appDelegate managedObjectContext] deleteObject:host];
[self saveData];
} }
- (void) saveHosts { - (void) saveData {
NSError* error; NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) { if (![[self.appDelegate managedObjectContext] save:&error]) {
NSLog(@"ERROR: Unable to save hosts to database"); Log(LOG_E, @"Unable to save hosts to database: %@", error);
} }
[self.appDelegate saveContext]; [self.appDelegate saveContext];
} }
@@ -68,6 +68,15 @@
return [self fetchRecords:@"Host"]; return [self fetchRecords:@"Host"];
} }
- (App*) createApp {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
return [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
}
- (void) removeApp:(App*)app {
[[self.appDelegate managedObjectContext] deleteObject:app];
}
- (NSArray*) fetchRecords:(NSString*)entityName { - (NSArray*) fetchRecords:(NSString*)entityName {
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:[self.appDelegate managedObjectContext]];
@@ -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
+10 -9
View File
@@ -1,24 +1,25 @@
// //
// Host.h // Host.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright © 2015 Limelight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "Utils.h" #import "Utils.h"
NS_ASSUME_NONNULL_BEGIN
@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) BOOL online;
@property (nonatomic) PairState pairState; @property (nonatomic) PairState pairState;
@property (nonatomic) NSString * activeAddress;
@end @end
NS_ASSUME_NONNULL_END
#import "Host+CoreDataProperties.h"
+4 -10
View File
@@ -1,23 +1,17 @@
// //
// Host.m // Host.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Limelight 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; @dynamic pairState;
@synthesize online; @synthesize online;
@synthesize activeAddress;
@end @end
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// Settings.h // Settings.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// Settings.m // Settings.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "Settings.h" #import "Settings.h"
+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "a_button.png" "filename" : "a_button_40x40@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "a_button-1.png" "filename" : "a_button_80x80@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "a_button-2.png" "filename" : "a_button_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -1,80 +1,80 @@
{ {
"images" : [ "images" : [
{ {
"idiom" : "iphone",
"size" : "29x29", "size" : "29x29",
"scale" : "2x", "idiom" : "iphone",
"filename" : "Icon-Small@2x.png" "filename" : "app_icon_settings_58x58_@2x-1.png",
"scale" : "2x"
}, },
{ {
"idiom" : "iphone",
"size" : "29x29", "size" : "29x29",
"scale" : "3x", "idiom" : "iphone",
"filename" : "Icon-Small@3x.png" "filename" : "app_icon_settings_87x87_@3x.png",
"scale" : "3x"
}, },
{ {
"idiom" : "iphone",
"size" : "40x40", "size" : "40x40",
"scale" : "2x", "idiom" : "iphone",
"filename" : "Icon-40@2x.png" "filename" : "app_icon_spotlight_80x80_@2x-1.png",
"scale" : "2x"
}, },
{ {
"idiom" : "iphone",
"size" : "40x40", "size" : "40x40",
"scale" : "3x", "idiom" : "iphone",
"filename" : "Icon-40@3x.png" "filename" : "app_icon_spotlight_120x120_@3x.png",
"scale" : "3x"
}, },
{ {
"idiom" : "iphone",
"size" : "60x60", "size" : "60x60",
"scale" : "2x",
"filename" : "[email protected]"
},
{
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "[email protected]",
"scale" : "2x"
},
{
"size" : "60x60", "size" : "60x60",
"scale" : "3x", "idiom" : "iphone",
"filename" : "Icon-60@3x.png" "filename" : "app_icon_180x180_@3x.png",
"scale" : "3x"
}, },
{ {
"idiom" : "ipad",
"size" : "29x29", "size" : "29x29",
"scale" : "1x", "idiom" : "ipad",
"filename" : "Icon-Small.png" "filename" : "app_icon_settings_29x29_@1x.png",
"scale" : "1x"
}, },
{ {
"idiom" : "ipad",
"size" : "29x29", "size" : "29x29",
"scale" : "2x", "idiom" : "ipad",
"filename" : "Icon-Small@2x.png" "filename" : "app_icon_settings_58x58_@2x.png",
"scale" : "2x"
}, },
{ {
"idiom" : "ipad",
"size" : "40x40", "size" : "40x40",
"scale" : "1x", "idiom" : "ipad",
"filename" : "Icon-40.png" "filename" : "app_icon_spotlight_40x40_@1x.png",
"scale" : "1x"
}, },
{ {
"idiom" : "ipad",
"size" : "40x40", "size" : "40x40",
"scale" : "2x", "idiom" : "ipad",
"filename" : "Icon-40@2x.png" "filename" : "app_icon_spotlight_80x80_@2x.png",
"scale" : "2x"
}, },
{ {
"idiom" : "ipad",
"size" : "76x76", "size" : "76x76",
"scale" : "1x", "idiom" : "ipad",
"filename" : "Icon-76.png" "filename" : "app_icon_76x76_@1x.png",
"scale" : "1x"
}, },
{ {
"idiom" : "ipad",
"size" : "76x76", "size" : "76x76",
"scale" : "2x", "idiom" : "ipad",
"filename" : "Icon-76@2x.png" "filename" : "app_icon_152x152_@2x.png",
"scale" : "2x"
} }
], ],
"info" : { "info" : {
"version" : 1, "version" : 1,
"author" : "makeappicon" "author" : "xcode"
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

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

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "down.png" "filename" : "down_31x38@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "down-1.png" "filename" : "down_61x75@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "down-2.png" "filename" : "down_93x114@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 455 B

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "L1-1.png" "filename" : "L1_40x40@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "L1.png" "filename" : "L1_80x80@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "L1-2.png" "filename" : "L1_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "L2.png" "filename" : "L2_60x60@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "L2-1.png" "filename" : "L2_120x120@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "L2-2.png" "filename" : "L2_180x180@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "L3.png" "filename" : "L3_80x80@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "L3-1.png" "filename" : "L3_160x160@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "L3-2.png" "filename" : "L3_240x240@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

@@ -1,51 +0,0 @@
{
"images" : [
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "left.png" "filename" : "left_38x31@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "left-1.png" "filename" : "left_76x61@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "left-2.png" "filename" : "left_114x92@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 525 B

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

+10 -1
View File
@@ -2,7 +2,16 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "Limelight-logo.pdf" "scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "logo_universal.png"
},
{
"idiom" : "universal",
"scale" : "3x"
} }
], ],
"info" : { "info" : {
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

@@ -7,7 +7,7 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "Limelight Flat Design Banner.png" "filename" : "play.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "R1.png" "filename" : "R1_40x40@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "R1-1.png" "filename" : "R1_80x80@1x-1.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "R1-2.png" "filename" : "R1_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "R2-1.png" "filename" : "R2_60x60@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "R2.png" "filename" : "R2_120x120@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "R2-2.png" "filename" : "R2_120x120@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+3 -3
View File
@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "R3.png" "filename" : "R3_80x80@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "R3-1.png" "filename" : "R3_160x160@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "R3-2.png" "filename" : "R3_240x240@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

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

Before

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "select_button-1.png" "filename" : "select_button_54x24@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "select_button.png" "filename" : "select_button_108x48@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "select_button-2.png" "filename" : "select_button_162x72@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 B

Before

Width:  |  Height:  |  Size: 735 B

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "settings_1x.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "settings_2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "settings_3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "start_button-1.png" "filename" : "start_button_54x24@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "start_button.png" "filename" : "start_button_108x48@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "start_button-2.png" "filename" : "start_button_162x72@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

Before

Width:  |  Height:  |  Size: 774 B

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "stick_inner-1.png" "filename" : "stick_inner_48x49@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "stick_inner.png" "filename" : "stick_inner_96x97@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "stick_inner-2.png" "filename" : "stick_inner_144x146@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -3,17 +3,17 @@
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x", "scale" : "1x",
"filename" : "stick_outer-1.png" "filename" : "stick_outer_80x80@1x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x", "scale" : "2x",
"filename" : "stick_outer.png" "filename" : "stick_outer_160x160@2x.png"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x", "scale" : "3x",
"filename" : "stick_outer-2.png" "filename" : "stick_outer_240x240@3x.png"
} }
], ],
"info" : { "info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Before

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Before

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 969 B

After

Width:  |  Height:  |  Size: 969 B

+23
View File
@@ -0,0 +1,23 @@
//
// 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
@@ -0,0 +1,15 @@
//
// 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
+12 -11
View File
@@ -1,12 +1,13 @@
// //
// ControllerSupport.h // ControllerSupport.h
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/20/14. // Created by Cameron Gutman on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Controller.h"
@class OnScreenControls; @class OnScreenControls;
@@ -16,18 +17,18 @@
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc; -(void) initAutoOnScreenControlMode:(OnScreenControls*)osc;
-(void) cleanup; -(void) cleanup;
-(void) updateLeftStick:(short)x y:(short)y; -(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y;
-(void) updateRightStick:(short)x y:(short)y; -(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y;
-(void) updateLeftTrigger:(char)left; -(void) updateLeftTrigger:(Controller*)controller left:(char)left;
-(void) updateRightTrigger:(char)right; -(void) updateRightTrigger:(Controller*)controller right:(char)right;
-(void) updateTriggers:(char)left right:(char)right; -(void) updateTriggers:(Controller*)controller left:(char)left right:(char)right;
-(void) updateButtonFlags:(int)flags; -(void) updateButtonFlags:(Controller*)controller flags:(int)flags;
-(void) setButtonFlag:(int)flags; -(void) setButtonFlag:(Controller*)controller flags:(int)flags;
-(void) clearButtonFlag:(int)flags; -(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
-(void) updateFinished; -(void) updateFinished:(Controller*)controller;
@property (nonatomic, strong) id connectObserver; @property (nonatomic, strong) id connectObserver;
@property (nonatomic, strong) id disconnectObserver; @property (nonatomic, strong) id disconnectObserver;
+214 -197
View File
@@ -1,245 +1,235 @@
// //
// ControllerSupport.m // ControllerSupport.m
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/20/14. // Created by Cameron Gutman on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
@import GameController; @import GameController;
@implementation ControllerSupport { @implementation ControllerSupport {
NSLock *_controllerValueLock;
NSLock *_controllerStreamLock; NSLock *_controllerStreamLock;
NSMutableDictionary *_controllers;
OnScreenControls *_osc; OnScreenControls *_osc;
int _lastButtonFlags; char _controllerNumbers;
char _lastLeftTrigger, _lastRightTrigger;
short _lastLeftStickX, _lastLeftStickY;
short _lastRightStickX, _lastRightStickY;
#define EMULATING_SELECT 0x1 #define EMULATING_SELECT 0x1
#define EMULATING_SPECIAL 0x2 #define EMULATING_SPECIAL 0x2
int _emulatingButtonFlags;
} }
// UPDATE_BUTTON_FLAG(flag, pressed) // UPDATE_BUTTON_FLAG(controller, flag, pressed)
#define UPDATE_BUTTON_FLAG(x, y) \ #define UPDATE_BUTTON_FLAG(controller, x, y) \
((y) ? [self setButtonFlag:x] : [self clearButtonFlag:x]) ((y) ? [self setButtonFlag:controller flags:x] : [self clearButtonFlag:controller flags:x])
-(void) updateLeftStick:(short)x y:(short)y -(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y
{ {
[_controllerValueLock lock]; @synchronized(controller) {
_lastLeftStickX = x; controller.lastLeftStickX = x;
_lastLeftStickY = y; controller.lastLeftStickY = y;
[_controllerValueLock unlock];
}
-(void) updateRightStick:(short)x y:(short)y
{
[_controllerValueLock lock];
_lastRightStickX = x;
_lastRightStickY = y;
[_controllerValueLock unlock];
}
-(void) updateLeftTrigger:(char)left
{
[_controllerValueLock lock];
_lastLeftTrigger = left;
[_controllerValueLock unlock];
}
-(void) updateRightTrigger:(char)right
{
[_controllerValueLock lock];
_lastRightTrigger = right;
[_controllerValueLock unlock];
}
-(void) updateTriggers:(char)left right:(char)right
{
[_controllerValueLock lock];
_lastLeftTrigger = left;
_lastRightTrigger = right;
[_controllerValueLock unlock];
}
-(void) handleSpecialCombosReleased:(int)releasedButtons
{
if ((_emulatingButtonFlags & EMULATING_SELECT) &&
((releasedButtons & LB_FLAG) || (releasedButtons & PLAY_FLAG))) {
_lastButtonFlags &= ~BACK_FLAG;
_emulatingButtonFlags &= ~EMULATING_SELECT;
} }
if ((_emulatingButtonFlags & EMULATING_SPECIAL) && }
-(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y
{
@synchronized(controller) {
controller.lastRightStickX = x;
controller.lastRightStickY = y;
}
}
-(void) updateLeftTrigger:(Controller*)controller left:(char)left
{
@synchronized(controller) {
controller.lastLeftTrigger = left;
}
}
-(void) updateRightTrigger:(Controller*)controller right:(char)right
{
@synchronized(controller) {
controller.lastRightTrigger = right;
}
}
-(void) updateTriggers:(Controller*) controller left:(char)left right:(char)right
{
@synchronized(controller) {
controller.lastLeftTrigger = left;
controller.lastRightTrigger = right;
}
}
-(void) handleSpecialCombosReleased:(Controller*)controller releasedButtons:(int)releasedButtons
{
if ((controller.emulatingButtonFlags & EMULATING_SELECT) &&
((releasedButtons & LB_FLAG) || (releasedButtons & PLAY_FLAG))) {
controller.lastButtonFlags &= ~BACK_FLAG;
controller.emulatingButtonFlags &= ~EMULATING_SELECT;
}
if ((controller.emulatingButtonFlags & EMULATING_SPECIAL) &&
((releasedButtons & RB_FLAG) || (releasedButtons & PLAY_FLAG) || ((releasedButtons & RB_FLAG) || (releasedButtons & PLAY_FLAG) ||
(releasedButtons & BACK_FLAG))) { (releasedButtons & BACK_FLAG))) {
_lastButtonFlags &= ~SPECIAL_FLAG; controller.lastButtonFlags &= ~SPECIAL_FLAG;
_emulatingButtonFlags &= ~EMULATING_SPECIAL; controller.emulatingButtonFlags &= ~EMULATING_SPECIAL;
} }
} }
-(void) handleSpecialCombosPressed:(int)pressedButtons -(void) handleSpecialCombosPressed:(Controller*)controller pressedButtons:(int)pressedButtons
{ {
// Special button combos for select and special // Special button combos for select and special
if (_lastButtonFlags & PLAY_FLAG) { if (controller.lastButtonFlags & PLAY_FLAG) {
// If LB and start are down, trigger select // If LB and start are down, trigger select
if (_lastButtonFlags & LB_FLAG) { if (controller.lastButtonFlags & LB_FLAG) {
_lastButtonFlags |= BACK_FLAG; controller.lastButtonFlags |= BACK_FLAG;
_lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG)); controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG));
_emulatingButtonFlags |= EMULATING_SELECT; controller.emulatingButtonFlags |= EMULATING_SELECT;
} }
// If (RB or select) and start are down, trigger special // If (RB or select) and start are down, trigger special
else if ((_lastButtonFlags & RB_FLAG) || (_lastButtonFlags & BACK_FLAG)) { else if ((controller.lastButtonFlags & RB_FLAG) || (controller.lastButtonFlags & BACK_FLAG)) {
_lastButtonFlags |= SPECIAL_FLAG; controller.lastButtonFlags |= SPECIAL_FLAG;
_lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG)); controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG));
_emulatingButtonFlags |= EMULATING_SPECIAL; controller.emulatingButtonFlags |= EMULATING_SPECIAL;
} }
} }
}
-(void) updateButtonFlags:(Controller*)controller flags:(int)flags
{
@synchronized(controller) {
int releasedButtons = (controller.lastButtonFlags ^ flags) & ~flags;
int pressedButtons = (controller.lastButtonFlags ^ flags) & flags;
controller.lastButtonFlags = flags;
// This must be called before handleSpecialCombosPressed
// because we clear the original button flags there
[self handleSpecialCombosReleased:controller releasedButtons:releasedButtons];
[self handleSpecialCombosPressed:controller pressedButtons:pressedButtons];
}
} }
-(void) updateButtonFlags:(int)flags -(void) setButtonFlag:(Controller*)controller flags:(int)flags
{ {
[_controllerValueLock lock]; @synchronized(controller) {
int releasedButtons = (_lastButtonFlags ^ flags) & ~flags; controller.lastButtonFlags |= flags;
int pressedButtons = (_lastButtonFlags ^ flags) & flags; [self handleSpecialCombosPressed:controller pressedButtons:flags];
}
_lastButtonFlags = flags;
// This must be called before handleSpecialCombosPressed
// because we clear the original button flags there
[self handleSpecialCombosReleased: releasedButtons];
[self handleSpecialCombosPressed: pressedButtons];
[_controllerValueLock unlock];
} }
-(void) setButtonFlag:(int)flags -(void) clearButtonFlag:(Controller*)controller flags:(int)flags
{ {
[_controllerValueLock lock]; @synchronized(controller) {
_lastButtonFlags |= flags; controller.lastButtonFlags &= ~flags;
[self handleSpecialCombosPressed: flags]; [self handleSpecialCombosReleased:controller releasedButtons:flags];
[_controllerValueLock unlock]; }
} }
-(void) clearButtonFlag:(int)flags -(void) updateFinished:(Controller*)controller
{
[_controllerValueLock lock];
_lastButtonFlags &= ~flags;
[self handleSpecialCombosReleased: flags];
[_controllerValueLock unlock];
}
-(void) updateFinished
{ {
[_controllerStreamLock lock]; [_controllerStreamLock lock];
[_controllerValueLock lock]; @synchronized(controller) {
LiSendMultiControllerEvent(controller.playerIndex, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY);
LiSendControllerEvent(_lastButtonFlags, _lastLeftTrigger, _lastRightTrigger, _lastLeftStickX, _lastLeftStickY, _lastRightStickX, _lastRightStickY); }
[_controllerValueLock unlock];
[_controllerStreamLock unlock]; [_controllerStreamLock unlock];
} }
-(void) unregisterControllerCallbacks -(void) unregisterControllerCallbacks:(GCController*) controller
{ {
for (int i = 0; i < [[GCController controllers] count]; i++) { if (controller != NULL) {
GCController *controller = [GCController controllers][i]; controller.controllerPausedHandler = NULL;
if (controller != NULL) { if (controller.extendedGamepad != NULL) {
controller.controllerPausedHandler = NULL; controller.extendedGamepad.valueChangedHandler = NULL;
}
if (controller.extendedGamepad != NULL) { else if (controller.gamepad != NULL) {
controller.extendedGamepad.valueChangedHandler = NULL; controller.gamepad.valueChangedHandler = NULL;
}
else if (controller.gamepad != NULL) {
controller.gamepad.valueChangedHandler = NULL;
}
} }
} }
} }
-(void) registerControllerCallbacks -(void) registerControllerCallbacks:(GCController*) controller
{ {
for (int i = 0; i < [[GCController controllers] count]; i++) { if (controller != NULL) {
GCController *controller = [GCController controllers][i]; controller.controllerPausedHandler = ^(GCController *controller) {
Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
if (controller != NULL) { [self setButtonFlag:limeController flags:PLAY_FLAG];
NSLog(@"Controller connected!"); [self updateFinished:limeController];
controller.controllerPausedHandler = ^(GCController *controller) {
[self setButtonFlag:PLAY_FLAG];
[self updateFinished];
// Pause for 100 ms
usleep(100 * 1000);
[self clearButtonFlag:PLAY_FLAG];
[self updateFinished];
};
if (controller.extendedGamepad != NULL) { // Pause for 100 ms
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) { usleep(100 * 1000);
short leftStickX, leftStickY;
short rightStickX, rightStickY; [self clearButtonFlag:limeController flags:PLAY_FLAG];
char leftTrigger, rightTrigger; [self updateFinished:limeController];
};
UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed);
UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed); if (controller.extendedGamepad != NULL) {
UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed); controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) {
UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed); Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]];
short leftStickX, leftStickY;
UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed); short rightStickX, rightStickY;
UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed); char leftTrigger, rightTrigger;
UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed);
UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed); UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed);
UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed);
UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed); UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed);
UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed); UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed);
leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE; UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed);
leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE; UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed);
UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed);
rightStickX = gamepad.rightThumbstick.xAxis.value * 0x7FFE; UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed);
rightStickY = gamepad.rightThumbstick.yAxis.value * 0x7FFE;
UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed);
leftTrigger = gamepad.leftTrigger.value * 0xFF; UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed);
rightTrigger = gamepad.rightTrigger.value * 0xFF;
leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE;
[self updateLeftStick:leftStickX y:leftStickY]; leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE;
[self updateRightStick:rightStickX y:rightStickY];
[self updateTriggers:leftTrigger right:rightTrigger]; rightStickX = gamepad.rightThumbstick.xAxis.value * 0x7FFE;
[self updateFinished]; rightStickY = gamepad.rightThumbstick.yAxis.value * 0x7FFE;
};
} leftTrigger = gamepad.leftTrigger.value * 0xFF;
else if (controller.gamepad != NULL) { rightTrigger = gamepad.rightTrigger.value * 0xFF;
controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) {
[self updateLeftStick:limeController x:leftStickX y:leftStickY];
UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed); [self updateRightStick:limeController x:rightStickX y:rightStickY];
UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed); [self updateTriggers:limeController left:leftTrigger right:rightTrigger];
UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed); [self updateFinished:limeController];
UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed); };
UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed);
UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed);
UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed);
UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed);
UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed);
UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed);
[self updateFinished];
};
}
} }
else if (controller.gamepad != NULL) {
controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) {
Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]];
UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed);
UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed);
UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed);
UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed);
UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed);
UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed);
UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed);
UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed);
UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed);
UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed);
[self updateFinished:limeController];
};
}
} else {
Log(LOG_W, @"Tried to register controller callbacks on NULL controller");
} }
} }
-(void) updateAutoOnScreenControlMode -(void) updateAutoOnScreenControlMode
@@ -278,37 +268,61 @@
[self updateAutoOnScreenControlMode]; [self updateAutoOnScreenControlMode];
} }
-(void) assignController:(GCController*)controller {
for (int i = 0; i < 4; i++) {
if (!(_controllerNumbers & (1 << i))) {
_controllerNumbers |= (1 << i);
Controller* limeController = [[Controller alloc] init];
controller.playerIndex = i;
limeController.playerIndex = i;
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
Log(LOG_I, @"Assigning controller index: %d", i);
break;
}
}
}
-(id) init -(id) init
{ {
self = [super init]; self = [super init];
_controllerStreamLock = [[NSLock alloc] init]; _controllerStreamLock = [[NSLock alloc] init];
_controllerValueLock = [[NSLock alloc] init]; _controllers = [[NSMutableDictionary alloc] init];
_controllerNumbers = 0;
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
for (GCController* controller in [GCController controllers]) {
[self assignController:controller];
[self registerControllerCallbacks:controller];
[self updateAutoOnScreenControlMode];
}
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Log(LOG_I, @"Controller connected!");
GCController* controller = note.object;
[self assignController:controller];
// Register callbacks on the new controller // Register callbacks on the new controller
[self registerControllerCallbacks]; [self registerControllerCallbacks:controller];
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; [self updateAutoOnScreenControlMode];
}]; }];
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(@"Controller disconnected!"); Log(LOG_I, @"Controller disconnected!");
// Reset all controller state to be safe GCController* controller = note.object;
[self updateButtonFlags:0]; [self unregisterControllerCallbacks:controller];
[self updateLeftStick:0 y:0]; [_controllers removeObjectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
[self updateRightStick:0 y:0]; _controllerNumbers &= ~(1 << controller.playerIndex);
[self updateTriggers:0 right:0]; Log(LOG_I, @"Unassigning controller index: %ld", (long)controller.playerIndex);
[self updateFinished];
// Re-evaluate the on-screen control mode // Re-evaluate the on-screen control mode
[self updateAutoOnScreenControlMode]; [self updateAutoOnScreenControlMode];
}]; }];
// Register for controller callbacks on any existing controllers
[self registerControllerCallbacks];
return self; return self;
} }
@@ -316,8 +330,11 @@
{ {
[[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
[[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver]; [[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
[_controllers removeAllObjects];
[self unregisterControllerCallbacks]; _controllerNumbers = 0;
for (GCController* controller in [GCController controllers]) {
[self unregisterControllerCallbacks:controller];
}
} }
@end @end
+4 -3
View File
@@ -1,12 +1,13 @@
// //
// OnScreenControls.h // OnScreenControls.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 12/28/14. // Created by Diego Waxemberg on 12/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "StreamView.h"
@class ControllerSupport; @class ControllerSupport;
@@ -23,7 +24,7 @@ typedef NS_ENUM(NSInteger, OnScreenControlsLevel) {
OnScreenControlsLevelAutoGCExtendedGamepad, OnScreenControlsLevelAutoGCExtendedGamepad,
}; };
- (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport; - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)edgeDelegate;
- (BOOL) handleTouchDownEvent:(NSSet*)touches; - (BOOL) handleTouchDownEvent:(NSSet*)touches;
- (BOOL) handleTouchUpEvent:(NSSet*)touches; - (BOOL) handleTouchUpEvent:(NSSet*)touches;
- (BOOL) handleTouchMovedEvent:(NSSet*)touches; - (BOOL) handleTouchMovedEvent:(NSSet*)touches;
+152 -112
View File
@@ -1,13 +1,14 @@
// //
// OnScreenControls.m // OnScreenControls.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 12/28/14. // Created by Diego Waxemberg on 12/28/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "Controller.h"
#include "Limelight.h" #include "Limelight.h"
#define UPDATE_BUTTON(x, y) (buttonFlags = \ #define UPDATE_BUTTON(x, y) (buttonFlags = \
@@ -34,6 +35,7 @@
CALayer* _l1Button; CALayer* _l1Button;
CALayer* _l2Button; CALayer* _l2Button;
CALayer* _l3Button; CALayer* _l3Button;
CALayer* _edge;
UITouch* _aTouch; UITouch* _aTouch;
UITouch* _bTouch; UITouch* _bTouch;
@@ -53,6 +55,7 @@
UITouch* _l1Touch; UITouch* _l1Touch;
UITouch* _l2Touch; UITouch* _l2Touch;
UITouch* _l3Touch; UITouch* _l3Touch;
UITouch* _edgeTouch;
NSDate* l3TouchStart; NSDate* l3TouchStart;
NSDate* r3TouchStart; NSDate* r3TouchStart;
@@ -64,42 +67,36 @@
OnScreenControlsLevel _level; OnScreenControlsLevel _level;
ControllerSupport *_controllerSupport; ControllerSupport *_controllerSupport;
Controller *_controller;
id<EdgeDetectionDelegate> _edgeDelegate;
} }
static const float BUTTON_SIZE = 50; static const float EDGE_WIDTH = .1;
//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_SHORT = 50;
static const float D_PAD_LONG = 65;
static const float D_PAD_DIST = 15; static const float D_PAD_DIST = 15;
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 double STICK_CLICK_RATE = 100; static const double STICK_CLICK_RATE = 100;
static const float STICK_INNER_SIZE = 80;
static const float STICK_OUTER_SIZE = 120;
static const float STICK_DEAD_ZONE = .1; static const float STICK_DEAD_ZONE = .1;
static float STICK_INNER_SIZE;
static float STICK_OUTER_SIZE;
static float LS_CENTER_X; static float LS_CENTER_X;
static float LS_CENTER_Y; static float LS_CENTER_Y;
static float RS_CENTER_X; static float RS_CENTER_X;
static float RS_CENTER_Y; static float RS_CENTER_Y;
static const float START_WIDTH = 50;
static const float START_HEIGHT = 30;
static float START_X; static float START_X;
static float START_Y; static float START_Y;
static const float SELECT_WIDTH = 50;
static const float SELECT_HEIGHT = 30;
static float SELECT_X; static float SELECT_X;
static float SELECT_Y; static float SELECT_Y;
static const float BUMPER_SIZE = 45;
static const float TRIGGER_SIZE = 60;
static const float L3R3_SIZE = 80;
static float R1_X; static float R1_X;
static float R1_Y; static float R1_Y;
static float R2_X; static float R2_X;
@@ -113,10 +110,13 @@ static float L2_Y;
static float L3_X; static float L3_X;
static float L3_Y; static float L3_Y;
- (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport { - (id) initWithView:(UIView*)view controllerSup:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
self = [self init]; self = [self init];
_view = view; _view = view;
_controllerSupport = controllerSupport; _controllerSupport = controllerSupport;
_controller = [[Controller alloc] init];
_controller.playerIndex = 0;
_edgeDelegate = swipeDelegate;
_aButton = [CALayer layer]; _aButton = [CALayer layer];
_bButton = [CALayer layer]; _bButton = [CALayer layer];
@@ -138,7 +138,10 @@ static float L3_Y;
_rightStickBackground = [CALayer layer]; _rightStickBackground = [CALayer layer];
_leftStick = [CALayer layer]; _leftStick = [CALayer layer];
_rightStick = [CALayer layer]; _rightStick = [CALayer layer];
_edge = [CALayer layer];
[self setupEdgeDetection];
return self; return self;
} }
@@ -185,10 +188,10 @@ static float L3_Y;
[self drawTriggers]; [self drawTriggers];
[self drawStartSelect]; [self drawStartSelect];
[self drawL3R3];
[self hideButtons]; [self hideButtons];
[self hideBumpers]; [self hideBumpers];
[self hideSticks]; [self hideSticks];
[self hideL3R3];
break; break;
case OnScreenControlsLevelFull: case OnScreenControlsLevelFull:
[self setupComplexControls]; [self setupComplexControls];
@@ -201,11 +204,16 @@ static float L3_Y;
[self hideL3R3]; // Full controls don't need these they have the sticks [self hideL3R3]; // Full controls don't need these they have the sticks
break; break;
default: default:
NSLog(@"Unknown on-screen controls level: %d", (int)_level); Log(LOG_W, @"Unknown on-screen controls level: %d", (int)_level);
break; break;
} }
} }
- (void) setupEdgeDetection {
_edge.frame = CGRectMake(0, 0, _view.frame.size.width * EDGE_WIDTH, _view.frame.size.height);
[_view.layer addSublayer:_edge];
}
// For GCExtendedGamepad controls we move start, select, L3, and R3 to the button // For GCExtendedGamepad controls we move start, select, L3, and R3 to the button
- (void) setupExtendedGamepadControls { - (void) setupExtendedGamepadControls {
// Start with the default complex layout // Start with the default complex layout
@@ -232,10 +240,12 @@ static float L3_Y;
START_Y = _view.frame.size.height * .9; START_Y = _view.frame.size.height * .9;
SELECT_Y = _view.frame.size.height * .9; SELECT_Y = _view.frame.size.height * .9;
L1_Y = _view.frame.size.height * .75; L1_Y = _view.frame.size.height * .7;
L2_Y = _view.frame.size.height * .9; L2_Y = _view.frame.size.height * .9;
R1_Y = _view.frame.size.height * .75; L2_X = _view.frame.size.width * .1;
R1_Y = _view.frame.size.height * .7;
R2_Y = _view.frame.size.height * .9; R2_Y = _view.frame.size.height * .9;
R2_X = _view.frame.size.width * .9;
} }
- (void) setupComplexControls - (void) setupComplexControls
@@ -250,133 +260,156 @@ static float L3_Y;
RS_CENTER_X = _view.frame.size.width * .65; RS_CENTER_X = _view.frame.size.width * .65;
RS_CENTER_Y = _view.frame.size.height * .75; RS_CENTER_Y = _view.frame.size.height * .75;
START_X = _view.frame.size.width * .55; START_X = _view.frame.size.width * .6;
START_Y = _view.frame.size.height * .1; START_Y = _view.frame.size.height * .1;
SELECT_X = _view.frame.size.width * .45; SELECT_X = _view.frame.size.width * .4;
SELECT_Y = _view.frame.size.height * .1; SELECT_Y = _view.frame.size.height * .1;
L1_X = _view.frame.size.width * .15; L1_X = _view.frame.size.width * .15;
L1_Y = _view.frame.size.height * .25; L1_Y = _view.frame.size.height * .27;
L2_X = _view.frame.size.width * .15; L2_X = _view.frame.size.width * .15;
L2_Y = _view.frame.size.height * .1; L2_Y = _view.frame.size.height * .1;
R1_X = _view.frame.size.width * .85; R1_X = _view.frame.size.width * .85;
R1_Y = _view.frame.size.height * .25; R1_Y = _view.frame.size.height * .27;
R2_X = _view.frame.size.width * .85; R2_X = _view.frame.size.width * .85;
R2_Y = _view.frame.size.height * .1; R2_Y = _view.frame.size.height * .1;
L3_X = _view.frame.size.width * .25; L3_X = _view.frame.size.width * .25;
L3_Y = _view.frame.size.height * .85; L3_Y = _view.frame.size.height * .75;
R3_X = _view.frame.size.width * .75; R3_X = _view.frame.size.width * .75;
R3_Y = _view.frame.size.height * .85; R3_Y = _view.frame.size.height * .75;
} }
- (void) drawButtons { - (void) drawButtons {
// create A button // create A button
_aButton.contents = (id) [UIImage imageNamed:@"AButton"].CGImage; UIImage* aButtonImage = [UIImage imageNamed:@"AButton"];
_aButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_SIZE / 2, BUTTON_CENTER_Y + BUTTON_DIST, BUTTON_SIZE, BUTTON_SIZE); _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);
[_view.layer addSublayer:_aButton]; [_view.layer addSublayer:_aButton];
// create B button // create B button
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - BUTTON_SIZE / 2, BUTTON_SIZE, BUTTON_SIZE); UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
_bButton.contents = (id) [UIImage imageNamed:@"BButton"].CGImage; _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;
[_view.layer addSublayer:_bButton]; [_view.layer addSublayer:_bButton];
// create X Button // create X Button
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - BUTTON_SIZE, BUTTON_CENTER_Y - BUTTON_SIZE / 2, BUTTON_SIZE, BUTTON_SIZE); UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
_xButton.contents = (id) [UIImage imageNamed:@"XButton"].CGImage; _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;
[_view.layer addSublayer:_xButton]; [_view.layer addSublayer:_xButton];
// create Y Button // create Y Button
_yButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_SIZE / 2, BUTTON_CENTER_Y - BUTTON_DIST - BUTTON_SIZE, BUTTON_SIZE, BUTTON_SIZE); UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
_yButton.contents = (id) [UIImage imageNamed:@"YButton"].CGImage; _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;
[_view.layer addSublayer:_yButton]; [_view.layer addSublayer:_yButton];
// create Down button // create Down button
_downButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_SHORT / 2, D_PAD_CENTER_Y + D_PAD_DIST, D_PAD_SHORT, D_PAD_LONG); UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
_downButton.contents = (id) [UIImage imageNamed:@"DownButton"].CGImage; _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;
[_view.layer addSublayer:_downButton]; [_view.layer addSublayer:_downButton];
// create Right button // create Right button
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - D_PAD_SHORT / 2, D_PAD_LONG, D_PAD_SHORT); UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
_rightButton.contents = (id) [UIImage imageNamed:@"RightButton"].CGImage; _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;
[_view.layer addSublayer:_rightButton]; [_view.layer addSublayer:_rightButton];
// create Up button // create Up button
_upButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_SHORT / 2, D_PAD_CENTER_Y - D_PAD_DIST - D_PAD_LONG, D_PAD_SHORT, D_PAD_LONG); UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
_upButton.contents = (id) [UIImage imageNamed:@"UpButton"].CGImage; _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;
[_view.layer addSublayer:_upButton]; [_view.layer addSublayer:_upButton];
// create Left button // create Left button
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - D_PAD_LONG, D_PAD_CENTER_Y - D_PAD_SHORT / 2, D_PAD_LONG, D_PAD_SHORT); UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
_leftButton.contents = (id) [UIImage imageNamed:@"LeftButton"].CGImage; _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.contents = (id) leftButtonImage.CGImage;
[_view.layer addSublayer:_leftButton]; [_view.layer addSublayer:_leftButton];
} }
- (void) drawStartSelect { - (void) drawStartSelect {
// create Start button // create Start button
_startButton.frame = CGRectMake(START_X - START_WIDTH / 2, START_Y - START_HEIGHT / 2, START_WIDTH, START_HEIGHT); UIImage* startButtonImage = [UIImage imageNamed:@"StartButton"];
_startButton.contents = (id) [UIImage imageNamed:@"StartButton"].CGImage; _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;
[_view.layer addSublayer:_startButton]; [_view.layer addSublayer:_startButton];
// create Select button // create Select button
_selectButton.frame = CGRectMake(SELECT_X - SELECT_WIDTH / 2, SELECT_Y - SELECT_HEIGHT / 2, SELECT_WIDTH, SELECT_HEIGHT); UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
_selectButton.contents = (id) [UIImage imageNamed:@"SelectButton"].CGImage; _selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
_selectButton.contents = (id) selectButtonImage.CGImage;
[_view.layer addSublayer:_selectButton]; [_view.layer addSublayer:_selectButton];
} }
- (void) drawBumpers { - (void) drawBumpers {
// create L1 button // create L1 button
_l1Button.frame = CGRectMake(L1_X - BUMPER_SIZE / 2, L1_Y - BUMPER_SIZE / 2, BUMPER_SIZE, BUMPER_SIZE); UIImage* l1ButtonImage = [UIImage imageNamed:@"L1"];
_l1Button.contents = (id) [UIImage imageNamed:@"L1"].CGImage; _l1Button.frame = CGRectMake(L1_X - l1ButtonImage.size.width / 2, L1_Y - l1ButtonImage.size.height / 2, l1ButtonImage.size.width, l1ButtonImage.size.height);
_l1Button.contents = (id) l1ButtonImage.CGImage;
[_view.layer addSublayer:_l1Button]; [_view.layer addSublayer:_l1Button];
// create R1 button // create R1 button
_r1Button.frame = CGRectMake(R1_X - BUMPER_SIZE / 2, R1_Y - BUMPER_SIZE / 2, BUMPER_SIZE, BUMPER_SIZE); UIImage* r1ButtonImage = [UIImage imageNamed:@"R1"];
_r1Button.contents = (id) [UIImage imageNamed:@"R1"].CGImage; _r1Button.frame = CGRectMake(R1_X - r1ButtonImage.size.width / 2, R1_Y - r1ButtonImage.size.height / 2, r1ButtonImage.size.width, r1ButtonImage.size.height);
_r1Button.contents = (id) r1ButtonImage.CGImage;
[_view.layer addSublayer:_r1Button]; [_view.layer addSublayer:_r1Button];
} }
- (void) drawTriggers { - (void) drawTriggers {
// create L2 button // create L2 button
_l2Button.frame = CGRectMake(L2_X - TRIGGER_SIZE / 2, L2_Y - TRIGGER_SIZE / 2, TRIGGER_SIZE, TRIGGER_SIZE); UIImage* l2ButtonImage = [UIImage imageNamed:@"L2"];
_l2Button.contents = (id) [UIImage imageNamed:@"L2"].CGImage; _l2Button.frame = CGRectMake(L2_X - l2ButtonImage.size.width / 2, L2_Y - l2ButtonImage.size.height / 2, l2ButtonImage.size.width, l2ButtonImage.size.height);
_l2Button.contents = (id) l2ButtonImage.CGImage;
[_view.layer addSublayer:_l2Button]; [_view.layer addSublayer:_l2Button];
// create R2 button // create R2 button
_r2Button.frame = CGRectMake(R2_X - TRIGGER_SIZE / 2, R2_Y - TRIGGER_SIZE / 2, TRIGGER_SIZE, TRIGGER_SIZE); UIImage* r2ButtonImage = [UIImage imageNamed:@"R2"];
_r2Button.contents = (id) [UIImage imageNamed:@"R2"].CGImage; _r2Button.frame = CGRectMake(R2_X - r2ButtonImage.size.width / 2, R2_Y - r2ButtonImage.size.height / 2, r2ButtonImage.size.width, r2ButtonImage.size.height);
_r2Button.contents = (id) r2ButtonImage.CGImage;
[_view.layer addSublayer:_r2Button]; [_view.layer addSublayer:_r2Button];
} }
- (void) drawSticks { - (void) drawSticks {
// create left analog stick // create left analog stick
_leftStickBackground.frame = CGRectMake(LS_CENTER_X - STICK_OUTER_SIZE / 2, LS_CENTER_Y - STICK_OUTER_SIZE / 2, STICK_OUTER_SIZE, STICK_OUTER_SIZE); UIImage* leftStickBgImage = [UIImage imageNamed:@"StickOuter"];
_leftStickBackground.contents = (id) [UIImage imageNamed:@"StickOuter"].CGImage; _leftStickBackground.frame = CGRectMake(LS_CENTER_X - leftStickBgImage.size.width / 2, LS_CENTER_Y - leftStickBgImage.size.height / 2, leftStickBgImage.size.width, leftStickBgImage.size.height);
_leftStickBackground.contents = (id) leftStickBgImage.CGImage;
[_view.layer addSublayer:_leftStickBackground]; [_view.layer addSublayer:_leftStickBackground];
_leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); UIImage* leftStickImage = [UIImage imageNamed:@"StickInner"];
_leftStick.contents = (id) [UIImage imageNamed:@"StickInner"].CGImage; _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;
[_view.layer addSublayer:_leftStick]; [_view.layer addSublayer:_leftStick];
// create right analog stick // create right analog stick
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - STICK_OUTER_SIZE / 2, RS_CENTER_Y - STICK_OUTER_SIZE / 2, STICK_OUTER_SIZE, STICK_OUTER_SIZE); UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
_rightStickBackground.contents = (id) [UIImage imageNamed:@"StickOuter"].CGImage; _rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
_rightStickBackground.contents = (id) rightStickBgImage.CGImage;
[_view.layer addSublayer:_rightStickBackground]; [_view.layer addSublayer:_rightStickBackground];
_rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); UIImage* rightStickImage = [UIImage imageNamed:@"StickInner"];
_rightStick.contents = (id) [UIImage imageNamed:@"StickInner"].CGImage; _rightStick.frame = CGRectMake(RS_CENTER_X - rightStickImage.size.width / 2, RS_CENTER_Y - rightStickImage.size.height / 2, rightStickImage.size.width, rightStickImage.size.height);
_rightStick.contents = (id) rightStickImage.CGImage;
[_view.layer addSublayer:_rightStick]; [_view.layer addSublayer:_rightStick];
STICK_INNER_SIZE = rightStickImage.size.width;
STICK_OUTER_SIZE = rightStickBgImage.size.width;
} }
- (void) drawL3R3 { - (void) drawL3R3 {
_l3Button.frame = CGRectMake(L3_X - L3R3_SIZE / 2, L3_Y - L3R3_SIZE / 2, L3R3_SIZE, L3R3_SIZE); UIImage* l3ButtonImage = [UIImage imageNamed:@"L3"];
_l3Button.contents = (id) [UIImage imageNamed:@"L3"].CGImage; _l3Button.frame = CGRectMake(L3_X - l3ButtonImage.size.width / 2, L3_Y - l3ButtonImage.size.height / 2, l3ButtonImage.size.width, l3ButtonImage.size.height);
_l3Button.cornerRadius = L3R3_SIZE / 2; _l3Button.contents = (id) l3ButtonImage.CGImage;
_l3Button.cornerRadius = l3ButtonImage.size.width / 2;
_l3Button.borderColor = [UIColor colorWithRed:15.f/255 green:160.f/255 blue:40.f/255 alpha:1.f].CGColor; _l3Button.borderColor = [UIColor colorWithRed:15.f/255 green:160.f/255 blue:40.f/255 alpha:1.f].CGColor;
[_view.layer addSublayer:_l3Button]; [_view.layer addSublayer:_l3Button];
_r3Button.frame = CGRectMake(R3_X - L3R3_SIZE / 2, R3_Y - L3R3_SIZE / 2, L3R3_SIZE, L3R3_SIZE); UIImage* r3ButtonImage = [UIImage imageNamed:@"R3"];
_r3Button.contents = (id) [UIImage imageNamed:@"R3"].CGImage; _r3Button.frame = CGRectMake(R3_X - r3ButtonImage.size.width / 2, R3_Y - r3ButtonImage.size.height / 2, r3ButtonImage.size.width, r3ButtonImage.size.height);
_r3Button.cornerRadius = L3R3_SIZE / 2; _r3Button.contents = (id) r3ButtonImage.CGImage;
_r3Button.cornerRadius = r3ButtonImage.size.width / 2;
_r3Button.borderColor = [UIColor colorWithRed:15.f/255 green:160.f/255 blue:40.f/255 alpha:1.f].CGColor; _r3Button.borderColor = [UIColor colorWithRed:15.f/255 green:160.f/255 blue:40.f/255 alpha:1.f].CGColor;
[_view.layer addSublayer:_r3Button]; [_view.layer addSublayer:_r3Button];
} }
@@ -449,7 +482,7 @@ static float L3_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: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) {
@@ -466,7 +499,7 @@ static float L3_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:0x7FFE * xStickVal y:0x7FFE * -yStickVal]; [_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true; updated = true;
} else if (touch == _aTouch) { } else if (touch == _aTouch) {
@@ -504,7 +537,7 @@ static float L3_Y;
} }
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished]; [_controllerSupport updateFinished:_controller];
} }
return updated || buttonTouch; return updated || buttonTouch;
} }
@@ -514,69 +547,69 @@ static float L3_Y;
BOOL stickTouch = false; BOOL stickTouch = false;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInView:_view]; CGPoint touchLocation = [touch locationInView:_view];
if ([_aButton.presentationLayer hitTest:touchLocation]) { if ([_aButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:A_FLAG]; [_controllerSupport setButtonFlag:_controller flags:A_FLAG];
_aTouch = touch; _aTouch = touch;
updated = true; updated = true;
} else if ([_bButton.presentationLayer hitTest:touchLocation]) { } else if ([_bButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:B_FLAG]; [_controllerSupport setButtonFlag:_controller flags:B_FLAG];
_bTouch = touch; _bTouch = touch;
updated = true; updated = true;
} else if ([_xButton.presentationLayer hitTest:touchLocation]) { } else if ([_xButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:X_FLAG]; [_controllerSupport setButtonFlag:_controller flags:X_FLAG];
_xTouch = touch; _xTouch = touch;
updated = true; updated = true;
} else if ([_yButton.presentationLayer hitTest:touchLocation]) { } else if ([_yButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:Y_FLAG]; [_controllerSupport setButtonFlag:_controller flags:Y_FLAG];
_yTouch = touch; _yTouch = touch;
updated = true; updated = true;
} else if ([_upButton.presentationLayer hitTest:touchLocation]) { } else if ([_upButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:UP_FLAG]; [_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
_upTouch = touch; _upTouch = touch;
updated = true; updated = true;
} else if ([_downButton.presentationLayer hitTest:touchLocation]) { } else if ([_downButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:DOWN_FLAG]; [_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = touch; _downTouch = touch;
updated = true; updated = true;
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) { } else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:LEFT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = touch; _leftTouch = touch;
updated = true; updated = true;
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) { } else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:RIGHT_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = touch; _rightTouch = touch;
updated = true; updated = true;
} else if ([_startButton.presentationLayer hitTest:touchLocation]) { } else if ([_startButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:PLAY_FLAG]; [_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
_startTouch = touch; _startTouch = touch;
updated = true; updated = true;
} else if ([_selectButton.presentationLayer hitTest:touchLocation]) { } else if ([_selectButton.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:BACK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:BACK_FLAG];
_selectTouch = touch; _selectTouch = touch;
updated = true; updated = true;
} else if ([_l1Button.presentationLayer hitTest:touchLocation]) { } else if ([_l1Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:LB_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LB_FLAG];
_l1Touch = touch; _l1Touch = touch;
updated = true; updated = true;
} else if ([_r1Button.presentationLayer hitTest:touchLocation]) { } else if ([_r1Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport setButtonFlag:RB_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RB_FLAG];
_r1Touch = touch; _r1Touch = touch;
updated = true; updated = true;
} else if ([_l2Button.presentationLayer hitTest:touchLocation]) { } else if ([_l2Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport updateLeftTrigger:0xFF]; [_controllerSupport updateLeftTrigger:_controller left:0xFF];
_l2Touch = touch; _l2Touch = touch;
updated = true; updated = true;
} else if ([_r2Button.presentationLayer hitTest:touchLocation]) { } else if ([_r2Button.presentationLayer hitTest:touchLocation]) {
[_controllerSupport updateRightTrigger:0xFF]; [_controllerSupport updateRightTrigger:_controller right:0xFF];
_r2Touch = touch; _r2Touch = touch;
updated = true; updated = true;
} else if ([_l3Button.presentationLayer hitTest:touchLocation]) { } else if ([_l3Button.presentationLayer hitTest:touchLocation]) {
if (l3Set) { if (l3Set) {
[_controllerSupport clearButtonFlag:LS_CLK_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG];
_l3Button.borderWidth = 0.0f; _l3Button.borderWidth = 0.0f;
} else { } else {
[_controllerSupport setButtonFlag:LS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
_l3Button.borderWidth = 2.0f; _l3Button.borderWidth = 2.0f;
} }
l3Set = !l3Set; l3Set = !l3Set;
@@ -584,10 +617,10 @@ static float L3_Y;
updated = true; updated = true;
} else if ([_r3Button.presentationLayer hitTest:touchLocation]) { } else if ([_r3Button.presentationLayer hitTest:touchLocation]) {
if (r3Set) { if (r3Set) {
[_controllerSupport clearButtonFlag:RS_CLK_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG];
_r3Button.borderWidth = 0.0f; _r3Button.borderWidth = 0.0f;
} else { } else {
[_controllerSupport setButtonFlag:RS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
_r3Button.borderWidth = 2.0f; _r3Button.borderWidth = 2.0f;
} }
r3Set = !r3Set; r3Set = !r3Set;
@@ -599,7 +632,7 @@ static float L3_Y;
// Use (-) modifier to conversion since receiver is earlier than now // Use (-) modifier to conversion since receiver is earlier than now
double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0; double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0;
if (l3TouchTime < STICK_CLICK_RATE) { if (l3TouchTime < STICK_CLICK_RATE) {
[_controllerSupport setButtonFlag:LS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
updated = true; updated = true;
} }
} }
@@ -611,16 +644,18 @@ static float L3_Y;
// Use (-) modifier to conversion since receiver is earlier than now // Use (-) modifier to conversion since receiver is earlier than now
double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0; double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0;
if (r3TouchTime < STICK_CLICK_RATE) { if (r3TouchTime < STICK_CLICK_RATE) {
[_controllerSupport setButtonFlag:RS_CLK_FLAG]; [_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
updated = true; updated = true;
} }
} }
_rsTouch = touch; _rsTouch = touch;
stickTouch = true; stickTouch = true;
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
_edgeTouch = touch;
} }
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished]; [_controllerSupport updateFinished:_controller];
} }
return updated || stickTouch; return updated || stickTouch;
} }
@@ -630,72 +665,72 @@ static float L3_Y;
BOOL touched = false; BOOL touched = false;
for (UITouch* touch in touches) { for (UITouch* touch in touches) {
if (touch == _aTouch) { if (touch == _aTouch) {
[_controllerSupport clearButtonFlag:A_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:A_FLAG];
_aTouch = nil; _aTouch = nil;
updated = true; updated = true;
} else if (touch == _bTouch) { } else if (touch == _bTouch) {
[_controllerSupport clearButtonFlag:B_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:B_FLAG];
_bTouch = nil; _bTouch = nil;
updated = true; updated = true;
} else if (touch == _xTouch) { } else if (touch == _xTouch) {
[_controllerSupport clearButtonFlag:X_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:X_FLAG];
_xTouch = nil; _xTouch = nil;
updated = true; updated = true;
} else if (touch == _yTouch) { } else if (touch == _yTouch) {
[_controllerSupport clearButtonFlag:Y_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
_yTouch = nil; _yTouch = nil;
updated = true; updated = true;
} else if (touch == _upTouch) { } else if (touch == _upTouch) {
[_controllerSupport clearButtonFlag:UP_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:UP_FLAG];
_upTouch = nil; _upTouch = nil;
updated = true; updated = true;
} else if (touch == _downTouch) { } else if (touch == _downTouch) {
[_controllerSupport clearButtonFlag:DOWN_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
_downTouch = nil; _downTouch = nil;
updated = true; updated = true;
} else if (touch == _leftTouch) { } else if (touch == _leftTouch) {
[_controllerSupport clearButtonFlag:LEFT_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
_leftTouch = nil; _leftTouch = nil;
updated = true; updated = true;
} else if (touch == _rightTouch) { } else if (touch == _rightTouch) {
[_controllerSupport clearButtonFlag:RIGHT_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
_rightTouch = nil; _rightTouch = nil;
updated = true; updated = true;
} else if (touch == _startTouch) { } else if (touch == _startTouch) {
[_controllerSupport clearButtonFlag:PLAY_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
_startTouch = nil; _startTouch = nil;
updated = true; updated = true;
} else if (touch == _selectTouch) { } else if (touch == _selectTouch) {
[_controllerSupport clearButtonFlag:BACK_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:BACK_FLAG];
_selectTouch = nil; _selectTouch = nil;
updated = true; updated = true;
} else if (touch == _l1Touch) { } else if (touch == _l1Touch) {
[_controllerSupport clearButtonFlag:LB_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:LB_FLAG];
_l1Touch = nil; _l1Touch = nil;
updated = true; updated = true;
} else if (touch == _r1Touch) { } else if (touch == _r1Touch) {
[_controllerSupport clearButtonFlag:RB_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:RB_FLAG];
_r1Touch = nil; _r1Touch = nil;
updated = true; updated = true;
} else if (touch == _l2Touch) { } else if (touch == _l2Touch) {
[_controllerSupport updateLeftTrigger:0]; [_controllerSupport updateLeftTrigger:_controller left:0];
_l2Touch = nil; _l2Touch = nil;
updated = true; updated = true;
} else if (touch == _r2Touch) { } else if (touch == _r2Touch) {
[_controllerSupport updateRightTrigger:0]; [_controllerSupport updateRightTrigger:_controller right:0];
_r2Touch = nil; _r2Touch = nil;
updated = true; updated = true;
} else if (touch == _lsTouch) { } else if (touch == _lsTouch) {
_leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
[_controllerSupport updateLeftStick:0 y:0]; [_controllerSupport updateLeftStick:_controller x:0 y:0];
[_controllerSupport clearButtonFlag:LS_CLK_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG];
l3TouchStart = [NSDate date]; l3TouchStart = [NSDate date];
_lsTouch = nil; _lsTouch = nil;
updated = true; updated = true;
} else if (touch == _rsTouch) { } else if (touch == _rsTouch) {
_rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE); _rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
[_controllerSupport updateRightStick:0 y:0]; [_controllerSupport updateRightStick:_controller x:0 y:0];
[_controllerSupport clearButtonFlag:RS_CLK_FLAG]; [_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG];
r3TouchStart = [NSDate date]; r3TouchStart = [NSDate date];
_rsTouch = nil; _rsTouch = nil;
updated = true; updated = true;
@@ -707,10 +742,15 @@ static float L3_Y;
else if (touch == _r3Touch) { else if (touch == _r3Touch) {
_r3Touch = nil; _r3Touch = nil;
touched = true; touched = true;
} else if (touch == _edgeTouch) {
_edgeTouch = nil;
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) {
[_edgeDelegate edgeSwiped];
}
} }
} }
if (updated) { if (updated) {
[_controllerSupport updateFinished]; [_controllerSupport updateFinished:_controller];
} }
return updated || touched; return updated || touched;
} }
+9 -3
View File
@@ -1,17 +1,23 @@
// //
// StreamView.h // StreamView.h
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/19/14. // Created by Cameron Gutman on 10/19/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "ControllerSupport.h" #import "ControllerSupport.h"
@protocol EdgeDetectionDelegate <NSObject>
- (void) edgeSwiped;
@end
@interface StreamView : UIView @interface StreamView : UIView
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport; - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate;
- (void) setMouseDeltaFactors:(float)x y:(float)y; - (void) setMouseDeltaFactors:(float)x y:(float)y;
@end @end
+9 -9
View File
@@ -1,9 +1,9 @@
// //
// StreamView.m // StreamView.m
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/19/14. // Created by Cameron Gutman on 10/19/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "StreamView.h" #import "StreamView.h"
@@ -29,8 +29,8 @@
screenFactor = [[UIScreen mainScreen] scale]; screenFactor = [[UIScreen mainScreen] scale];
} }
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport { - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport]; 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 retrieveSettings].onscreenControls integerValue];
@@ -38,13 +38,13 @@
[controllerSupport initAutoOnScreenControlMode:onScreenControls]; [controllerSupport initAutoOnScreenControlMode:onScreenControls];
} }
else { else {
NSLog(@"Setting manual on-screen controls level: %d", (int)level); Log(LOG_I, @"Setting manual on-screen controls level: %d", (int)level);
[onScreenControls setLevel:level]; [onScreenControls setLevel:level];
} }
} }
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Touch down"); Log(LOG_D, @"Touch down");
if (![onScreenControls handleTouchDownEvent:touches]) { if (![onScreenControls handleTouchDownEvent:touches]) {
UITouch *touch = [[event allTouches] anyObject]; UITouch *touch = [[event allTouches] anyObject];
touchLocation = [touch locationInView:self]; touchLocation = [touch locationInView:self];
@@ -88,11 +88,11 @@
} }
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"Touch up"); Log(LOG_D, @"Touch up");
if (![onScreenControls handleTouchUpEvent:touches]) { if (![onScreenControls handleTouchUpEvent:touches]) {
if (!touchMoved) { if (!touchMoved) {
if ([[event allTouches] count] == 2) { if ([[event allTouches] count] == 2) {
NSLog(@"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);
@@ -103,7 +103,7 @@
} else { } else {
NSLog(@"Sending left mouse button press"); Log(LOG_D, @"Sending left mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
+8 -3
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.limelight-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,15 +17,20 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.3.1</string> <string>0.9.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>2</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<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>
+2 -1
View File
@@ -14,4 +14,5 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#endif #import "Logger.h"
#endif
@@ -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.xcdatamodel</string>
</dict> </dict>
</plist> </plist>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8118.17" systemVersion="15A204h" 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="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="120"/>
</elements>
</model>
@@ -1,9 +1,9 @@
// //
// AppManager.h // AppManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/25/14. // Created by Diego Waxemberg on 10/25/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -17,10 +17,10 @@
@end @end
@interface AppManager : NSObject @interface AppAssetManager : NSObject
- (id) initWithCallback:(id<AppAssetCallback>)callback; - (id) initWithCallback:(id<AppAssetCallback>)callback;
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host; - (void) retrieveAssetsFromHost:(Host*)host;
- (void) stopRetrieving; - (void) stopRetrieving;
@end @end
+52
View File
@@ -0,0 +1,52 @@
//
// AppManager.m
// Moonlight
//
// Created by Diego Waxemberg on 10/25/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import "AppAssetManager.h"
#import "CryptoManager.h"
#import "Utils.h"
#import "HttpResponse.h"
#import "AppAssetRetriever.h"
@implementation AppAssetManager {
NSOperationQueue* _opQueue;
id<AppAssetCallback> _callback;
}
static const int MAX_REQUEST_COUNT = 4;
- (id) initWithCallback:(id<AppAssetCallback>)callback {
self = [super init];
_callback = callback;
_opQueue = [[NSOperationQueue alloc] init];
[_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT];
return self;
}
- (void) retrieveAssetsFromHost:(Host*)host {
for (App* app in host.appList) {
if (app.image == nil) {
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
retriever.app = app;
retriever.host = host;
retriever.callback = _callback;
[_opQueue addOperation:retriever];
}
}
}
- (void) stopRetrieving {
[_opQueue cancelAllOperations];
}
- (void) sendCallBackForApp:(App*)app {
[_callback receivedAssetForApp:app];
}
@end
+16
View File
@@ -0,0 +1,16 @@
//
// AppAssetResponse.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "HttpResponse.h"
@interface AppAssetResponse : NSObject <Response>
@end
+25
View File
@@ -0,0 +1,25 @@
//
// AppAssetResponse.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "AppAssetResponse.h"
@implementation AppAssetResponse
@synthesize data, statusCode, statusMessage;
- (void)populateWithData:(NSData *)imageData {
self.data = imageData;
self.statusMessage = @"App asset has no status message";
self.statusCode = -1;
}
- (UIImage*) getImage {
UIImage* appImage = [[UIImage alloc] initWithData:self.data];
return appImage;
}
@end
+20
View File
@@ -0,0 +1,20 @@
//
// AppAssetRetriever.h
// Moonlight
//
// Created by Diego Waxemberg on 1/31/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Host.h"
#import "App.h"
#import "AppAssetManager.h"
@interface AppAssetRetriever : NSOperation
@property (nonatomic) Host* host;
@property (nonatomic) App* app;
@property (nonatomic) id<AppAssetCallback> callback;
@end
+42
View File
@@ -0,0 +1,42 @@
//
// AppAssetRetriever.m
// Moonlight
//
// Created by Diego Waxemberg on 1/31/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "AppAssetRetriever.h"
#import "HttpManager.h"
#import "CryptoManager.h"
#import "AppAssetResponse.h"
#import "HttpRequest.h"
@implementation AppAssetRetriever
static const double RETRY_DELAY = 2; // seconds
static const int MAX_ATTEMPTS = 5;
- (void) main {
UIImage* appImage = nil;
int attempts = 0;
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
appImage = [UIImage imageWithData:appAssetResp.data];
self.app.image = UIImagePNGRepresentation(appImage);
if (![self isCancelled] && appImage == nil) {
[NSThread sleepForTimeInterval:RETRY_DELAY];
}
}
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
}
- (void) sendCallbackForApp:(App*)app {
[self.callback receivedAssetForApp:app];
}
@end
+17
View File
@@ -0,0 +1,17 @@
//
// AppListResponse.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "HttpResponse.h"
@interface AppListResponse : NSObject <Response>
- (void)populateWithData:(NSData *)data;
- (NSArray*) getAppList;
- (BOOL) isStatusOk;
@end
+120
View File
@@ -0,0 +1,120 @@
//
// AppListResponse.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "AppListResponse.h"
#import "App.h"
#import "DataManager.h"
#import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse {
NSMutableArray* _appList;
}
@synthesize data, statusCode, statusMessage;
static const char* TAG_APP = "App";
static const char* TAG_APP_TITLE = "AppTitle";
static const char* TAG_APP_ID = "ID";
static const char* TAG_APP_IS_RUNNING = "IsRunning";
- (void)populateWithData:(NSData *)xml {
self.data = xml;
_appList = [[NSMutableArray alloc] init];
[self parseData];
}
- (void) parseData {
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
if (docPtr == NULL) {
Log(LOG_W, @"An error occured trying to parse xml.");
return;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
if (node == NULL) {
Log(LOG_W, @"No root XML element.");
xmlFreeDoc(docPtr);
return;
}
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
self.statusCode = status;
}
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
self.statusMessage = statusMsg;
node = node->children;
DataManager* dataMan = [[DataManager alloc] init];
while (node != NULL) {
//Log(LOG_D, @"node: %s", node->name);
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName = @"";
NSString* appId = nil;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
if (nodeVal != NULL) {
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else {
appName = @"";
}
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_ID)) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
if (nodeVal != NULL) {
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
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;
}
if (appId != nil) {
App* app = [dataMan createApp];
app.name = appName;
app.id = appId;
app.isRunning = appIsRunning;
[_appList addObject:app];
}
}
node = node->next;
}
xmlFreeDoc(docPtr);
}
- (NSArray*) getAppList {
return _appList;
}
- (BOOL) isStatusOk {
return self.statusCode == 200;
}
@end
-79
View File
@@ -1,79 +0,0 @@
//
// AppManager.m
// Limelight
//
// Created by Diego Waxemberg on 10/25/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved.
//
#import "AppManager.h"
#import "CryptoManager.h"
#import "Utils.h"
@implementation AppManager {
NSOperationQueue* _opQueue;
id<AppAssetCallback> _callback;
Host* _host;
NSString* _uniqueId;
NSData* _cert;
NSMutableDictionary* _imageCache;
}
- (id) initWithCallback:(id<AppAssetCallback>)callback {
self = [super init];
_callback = callback;
_opQueue = [[NSOperationQueue alloc] init];
_imageCache = [[NSMutableDictionary alloc] init];
_uniqueId = [CryptoManager getUniqueID];
return self;
}
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host {
Host* oldHost = _host;
_host = host;
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid];
NSLog(@"Using cached app images: %d", useCache);
if (!useCache) {
[_imageCache removeAllObjects];
}
for (App* app in appList) {
[_opQueue addOperationWithBlock:^{
[self retrieveAssetForApp:app useCache:useCache];
}];
}
}
- (void) stopRetrieving {
[_opQueue cancelAllOperations];
}
- (void) retrieveAssetForApp:(App*)app useCache:(BOOL)useCache {
UIImage* appImage = nil;
if (useCache) {
@synchronized(_imageCache) {
UIImage* cachedImage = [_imageCache objectForKey:app.appId];
if (cachedImage != nil) {
appImage = cachedImage;
app.appImage = appImage;
}
}
}
if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* appAsset = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]];
appImage = [UIImage imageWithData:appAsset];
app.appImage = appImage;
if (appImage != nil) {
@synchronized(_imageCache) {
[_imageCache setObject:appImage forKey:app.appId];
}
}
}
[self performSelectorOnMainThread:@selector(sendCallBackForApp:) withObject:app waitUntilDone:NO];
}
- (void) sendCallBackForApp:(App*)app {
[_callback receivedAssetForApp:app];
}
@end
+3 -3
View File
@@ -1,9 +1,9 @@
// //
// DiscoveryManager.h // DiscoveryManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/1/15. // Created by Diego Waxemberg on 1/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -24,6 +24,6 @@
- (void) stopDiscoveryBlocking; - (void) stopDiscoveryBlocking;
- (BOOL) addHostToDiscovery:(Host*)host; - (BOOL) addHostToDiscovery:(Host*)host;
- (void) removeHostFromDiscovery:(Host*)host; - (void) removeHostFromDiscovery:(Host*)host;
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*))callback; - (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback;
@end @end
+25 -16
View File
@@ -1,9 +1,9 @@
// //
// DiscoveryManager.m // DiscoveryManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/1/15. // Created by Diego Waxemberg on 1/1/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "DiscoveryManager.h" #import "DiscoveryManager.h"
@@ -12,6 +12,7 @@
#import "Utils.h" #import "Utils.h"
#import "DataManager.h" #import "DataManager.h"
#import "DiscoveryWorker.h" #import "DiscoveryWorker.h"
#import "ServerInfoResponse.h"
@implementation DiscoveryManager { @implementation DiscoveryManager {
NSMutableArray* _hostQueue; NSMutableArray* _hostQueue;
@@ -37,25 +38,32 @@
return self; return self;
} }
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback { - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, 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];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
Host* host = nil; Host* host = nil;
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if ([serverInfoResponse isStatusOk]) {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
host = [dataMan createHost]; host = [dataMan createHost];
host.address = hostAddress; host.activeAddress = host.address = hostAddress;
[HttpManager populateHostFromXML:serverInfoData host:host]; host.online = YES;
[serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) { if (![self addHostToDiscovery:host]) {
[dataMan removeHost:host]; [dataMan removeHost:host];
callback(nil, @"Host already added");
} else {
callback(host, nil);
} }
} else {
callback(nil, @"Could not connect to host");
} }
callback(host);
} }
- (void) startDiscovery { - (void) startDiscovery {
NSLog(@"Starting discovery"); Log(LOG_I, @"Starting discovery");
shouldDiscover = YES; shouldDiscover = YES;
[_mdnsMan searchForHosts]; [_mdnsMan searchForHosts];
for (Host* host in _hostQueue) { for (Host* host in _hostQueue) {
@@ -64,23 +72,23 @@
} }
- (void) stopDiscovery { - (void) stopDiscovery {
NSLog(@"Stopping discovery"); Log(LOG_I, @"Stopping discovery");
shouldDiscover = NO; shouldDiscover = NO;
[_mdnsMan stopSearching]; [_mdnsMan stopSearching];
[_opQueue cancelAllOperations]; [_opQueue cancelAllOperations];
} }
- (void) stopDiscoveryBlocking { - (void) stopDiscoveryBlocking {
NSLog(@"Stopping discovery and waiting for workers to stop"); Log(LOG_I, @"Stopping discovery and waiting for workers to stop");
shouldDiscover = NO; shouldDiscover = NO;
[_mdnsMan stopSearching]; [_mdnsMan stopSearching];
[_opQueue cancelAllOperations]; [_opQueue cancelAllOperations];
[_opQueue waitUntilAllOperationsAreFinished]; [_opQueue waitUntilAllOperationsAreFinished];
NSLog(@"All discovery workers stopped"); Log(LOG_I, @"All discovery workers stopped");
} }
- (BOOL) addHostToDiscovery:(Host *)host { - (BOOL) addHostToDiscovery:(Host *)host {
if (![self isHostInDiscovery:host]) { if (host.uuid.length > 0 && ![self isHostInDiscovery:host]) {
[_hostQueue addObject:host]; [_hostQueue addObject:host];
if (shouldDiscover) { if (shouldDiscover) {
[_opQueue addOperation:[self createWorkerForHost:host]]; [_opQueue addOperation:[self createWorkerForHost:host]];
@@ -105,18 +113,19 @@
DataManager* dataMan = [[DataManager alloc] init]; 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 (Host* host in hosts) {
NSLog(@"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];
[worker discoverHost]; [worker discoverHost];
if ([self addHostToDiscovery:host]) { if ([self addHostToDiscovery:host]) {
NSLog(@"Adding host to discovery: %@", host.name); Log(LOG_I, @"Adding host to discovery: %@", host.name);
[_callback updateAllHosts:_hostQueue]; [_callback updateAllHosts:_hostQueue];
} else { } else {
NSLog(@"Not adding host to discovery: %@", host.name); Log(LOG_I, @"Not adding host to discovery: %@", host.name);
[dataMan removeHost:host]; [dataMan removeHost:host];
} }
} }
[dataMan saveData];
}); });
} }
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// DiscoveryWorker.h // DiscoveryWorker.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/2/15. // Created by Diego Waxemberg on 1/2/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+86 -29
View File
@@ -1,14 +1,16 @@
// //
// DiscoveryWorker.m // DiscoveryWorker.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/2/15. // Created by Diego Waxemberg on 1/2/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "DiscoveryWorker.h" #import "DiscoveryWorker.h"
#import "Utils.h" #import "Utils.h"
#import "HttpManager.h" #import "HttpManager.h"
#import "ServerInfoResponse.h"
#import "HttpRequest.h"
@implementation DiscoveryWorker { @implementation DiscoveryWorker {
Host* _host; Host* _host;
@@ -39,42 +41,97 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
} }
} }
- (void) discoverHost { - (NSArray*) getHostAddressList {
BOOL receivedResponse = NO; NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
if (!self.cancelled && _host.localAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; if (_host.localAddress != nil) {
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; [array addObject:_host.localAddress];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
[HttpManager populateHostFromXML:serverInfoData host:_host];
_host.address = _host.localAddress;
receivedResponse = YES;
}
} }
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { if (_host.externalAddress != nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; [array addObject:_host.externalAddress];
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; }
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { if (_host.address != nil) {
[HttpManager populateHostFromXML:serverInfoData host:_host]; [array addObject:_host.address];
_host.address = _host.externalAddress; }
receivedResponse = YES;
// 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;
}
} }
} }
if (!self.cancelled && !receivedResponse && _host.address != nil) { return array;
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; }
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) { - (void) discoverHost {
[HttpManager populateHostFromXML:serverInfoData host:_host]; BOOL receivedResponse = NO;
receivedResponse = YES; NSArray *addresses = [self getHostAddressList];
Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
for (NSString *address in addresses) {
if (self.cancelled) {
// Get out without updating the status because
// it might not have finished checking the various
// addresses
return;
}
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
receivedResponse = [self checkResponse:serverInfoResp];
if (receivedResponse) {
_host.activeAddress = address;
break;
} }
} }
_host.online = receivedResponse; _host.online = receivedResponse;
if (receivedResponse) { if (receivedResponse) {
NSLog(@"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);
} else {
// If the host is not online, we do not know the pairstate
_host.pairState = PairStateUnknown;
} }
} }
- (ServerInfoResponse*) requestInfoAtAddress:(NSString*)address {
HttpManager* hMan = [[HttpManager alloc] initWithHost:address
uniqueId:_uniqueId
deviceName:deviceName
cert:_cert];
ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
return response;
}
- (BOOL) checkResponse:(ServerInfoResponse*)response {
if ([response isStatusOk]) {
// 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])) {
[response populateHost:_host];
return YES;
} else {
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
}
}
return NO;
}
@end @end
+8 -9
View File
@@ -1,20 +1,17 @@
// //
// HttpManager.h // HttpManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/16/14. // Created by Diego Waxemberg on 10/16/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "Host.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> @interface HttpManager : NSObject <NSURLSessionDelegate>
+ (NSArray*) getAppListFromXML:(NSData*)xml;
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host;
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
+ (NSString*) getStatusStringFromXML:(NSData*)xml;
- (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;
@@ -25,11 +22,13 @@
- (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;
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request; - (void) executeRequestSynchronously:(HttpRequest*)request;
@end @end
+91 -263
View File
@@ -1,12 +1,13 @@
// //
// HttpManager.m // HttpManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/16/14. // Created by Diego Waxemberg on 10/16/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "HttpManager.h" #import "HttpManager.h"
#import "HttpRequest.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "App.h" #import "App.h"
@@ -14,7 +15,9 @@
#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;
@@ -22,210 +25,12 @@
NSMutableData* _respData; NSMutableData* _respData;
NSData* _requestResp; NSData* _requestResp;
dispatch_semaphore_t _requestLock; dispatch_semaphore_t _requestLock;
BOOL _errorOccurred;
} }
static const NSString* PORT = @"47984"; static const NSString* HTTP_PORT = @"47989";
static const NSString* HTTPS_PORT = @"47984";
+ (NSArray*) getAppListFromXML:(NSData*)xml {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return NULL;
}
// Skip the root node
node = node->children;
NSMutableArray* appList = [[NSMutableArray alloc] init];
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName;
NSString* appId;
BOOL appIsRunning = NO;
while (appInfoNode != NULL) {
//NSLog(@"appInfoNode: %s", appInfoNode->name);
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"IsRunning")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
xmlFree(nodeVal);
}
appInfoNode = appInfoNode->next;
}
App* app = [[App alloc] init];
app.appName = appName;
app.appId = appId;
app.isRunning = appIsRunning;
[appList addObject:app];
}
node = node->next;
}
xmlFreeDoc(docPtr);
return appList;
}
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return;
}
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return;
}
// Skip the root node
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)"hostname")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.name = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"ExternalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.externalAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"LocalIP")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.localAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"uniqueid")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.uuid = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"mac")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.mac = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
} else if (!xmlStrcmp(node->name, (const xmlChar*)"PairStatus")) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
host.pairState = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
xmlFree(nodeVal);
}
node = node->next;
}
xmlFreeDoc(docPtr);
}
+ (NSString*) getStatusStringFromXML:(NSData*)xml {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
NSString* string;
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
if (rootNode == NULL) {
NSLog(@"ERROR: No root XML element.");
xmlFreeDoc(docPtr);
return NULL;
}
string = [HttpManager getStatusMessage: rootNode];
xmlFreeDoc(docPtr);
return string;
}
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
if (docPtr == NULL) {
NSLog(@"ERROR: An error occured trying to parse xml.");
return NULL;
}
NSString* value;
xmlNodePtr node;
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
// Check root status_code
if (![HttpManager verifyStatus: rootNode]) {
NSLog(@"ERROR: Request returned with failure status");
xmlFreeDoc(docPtr);
return NULL;
}
// Skip the root node
node = node->children;
while (node != NULL) {
//NSLog(@"node: %s", node->name);
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
xmlFree(nodeVal);
}
node = node->next;
}
//NSLog(@"xmlValue: %@", value);
xmlFreeDoc(docPtr);
return value;
}
+ (NSString*) getStatusMessage:(xmlNodePtr)docRoot {
xmlChar* statusMsgXml = xmlGetProp(docRoot, (const xmlChar*)"status_message");
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
return statusMsg;
}
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
return status == 200;
}
return false;
}
+ (NSData*) fixXmlVersion:(NSData*) xmlData { + (NSData*) fixXmlVersion:(NSData*) xmlData {
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]; NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
@@ -240,30 +45,59 @@ 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;
} }
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request { - (void) executeRequestSynchronously:(HttpRequest*)request {
NSLog(@"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 delegate:self];
}); if (error != NULL) {
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); Log(LOG_D, @"Connection error: %@", error);
return _requestResp; _errorOccurred = true;
} }
else {
Log(LOG_D, @"Received response: %@", response);
- (void) executeRequest:(NSURLRequest*)request { if (data != NULL) {
[NSURLConnection connectionWithRequest:request delegate:self]; 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);
if (!_errorOccurred && request.response) {
[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;
} }
- (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 5 seconds
@@ -278,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];
} }
@@ -351,33 +190,6 @@ static const NSString* PORT = @"47984";
return hex; return hex;
} }
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"Received response: %@", response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(@"\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;
@@ -400,11 +212,11 @@ static const NSString* PORT = @"47984";
OSStatus securityError = SecPKCS12Import(p12Data, options, &items); OSStatus securityError = SecPKCS12Import(p12Data, options, &items);
if (securityError == errSecSuccess) { if (securityError == errSecSuccess) {
//NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items)); //Log(LOG_D, @"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
} else { } else {
NSLog(@"Error opening Certificate."); Log(LOG_E, @"Error opening Certificate.");
} }
CFRelease(options); CFRelease(options);
@@ -413,9 +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 {
NSLog(@"connection error: %@", error); // Allow untrusted server certificates
dispatch_semaphore_signal(_requestLock); if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
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
+23
View File
@@ -0,0 +1,23 @@
//
// HttpRequest.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "HttpResponse.h"
@interface HttpRequest : NSObject
@property (nonatomic) id<Response> response;
@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) requestWithUrlRequest:(NSURLRequest*)req;
@end
+37
View File
@@ -0,0 +1,37 @@
//
// HttpRequest.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "HttpRequest.h"
#import "HttpResponse.h"
#import "HttpManager.h"
@implementation HttpRequest
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
request.response = response;
return request;
}
+ (HttpRequest*) requestWithUrlRequest:(NSURLRequest*)req {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
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
+33
View File
@@ -0,0 +1,33 @@
//
// HttpResponse.h
// Moonlight
//
// Created by Diego Waxemberg on 1/30/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Host.h"
static NSString* TAG_STATUS_CODE = @"status_code";
static NSString* TAG_STATUS_MESSAGE = @"status_message";
@protocol Response <NSObject>
- (void) populateWithData:(NSData*)data;
@property (nonatomic) NSInteger statusCode;
@property (nonatomic) NSString* statusMessage;
@property (nonatomic) NSData* data;
@end
@interface HttpResponse : NSObject <Response>
- (void) populateWithData:(NSData*)data;
- (void) parseData;
- (NSString*) getStringTag:(NSString*)tag;
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value;
- (BOOL) isStatusOk;
@end
+94
View File
@@ -0,0 +1,94 @@
//
// HttpResponse.m
// Moonlight
//
// Created by Diego Waxemberg on 1/30/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "HttpResponse.h"
#import "App.h"
#import <libxml2/libxml/xmlreader.h>
@implementation HttpResponse {
NSMutableDictionary* _elements;
}
@synthesize data, statusCode, statusMessage;
- (void) populateWithData:(NSData*)xml {
self.data = xml;
[self parseData];
}
- (NSString*) getStringTag:(NSString*)tag {
return [_elements objectForKey:tag];
}
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value {
NSString* stringVal = [self getStringTag:tag];
if (stringVal != nil) {
*value = [stringVal integerValue];
return true;
} else {
return false;
}
}
- (BOOL) isStatusOk {
return self.statusCode == 200;
}
- (void) parseData {
_elements = [[NSMutableDictionary alloc] init];
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
if (docPtr == NULL) {
Log(LOG_W, @"An error occured trying to parse xml.");
return;
}
xmlNodePtr node = xmlDocGetRootElement(docPtr);
if (node == NULL) {
Log(LOG_W, @"No root XML element.");
xmlFreeDoc(docPtr);
return;
}
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
if (statusStr != NULL) {
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
xmlFree(statusStr);
self.statusCode = status;
}
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
NSString* statusMsg;
if (statusMsgXml != NULL) {
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
xmlFree(statusMsgXml);
}
else {
statusMsg = @"Server Error";
}
self.statusMessage = statusMsg;
node = node->children;
while (node != NULL) {
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
NSString* value;
if (nodeVal == NULL) {
value = @"";
} else {
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
}
NSString* key = [[NSString alloc] initWithCString:(const char*)node->name encoding:NSUTF8StringEncoding];
[_elements setObject:value forKey:key];
xmlFree(nodeVal);
node = node->next;
}
xmlFreeDoc(docPtr);
}
@end
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// MDNSManager.h // MDNSManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/14/14. // Created by Diego Waxemberg on 10/14/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+12 -13
View File
@@ -1,9 +1,9 @@
// //
// MDNSManager.m // MDNSManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/14/14. // Created by Diego Waxemberg on 10/14/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "MDNSManager.h" #import "MDNSManager.h"
@@ -34,13 +34,13 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
} }
- (void) searchForHosts { - (void) searchForHosts {
NSLog(@"Starting mDNS discovery"); Log(LOG_I, @"Starting mDNS discovery");
scanActive = TRUE; scanActive = TRUE;
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""]; [mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
} }
- (void) stopSearching { - (void) stopSearching {
NSLog(@"Stopping mDNS discovery"); Log(LOG_I, @"Stopping mDNS discovery");
scanActive = FALSE; scanActive = FALSE;
[mDNSBrowser stop]; [mDNSBrowser stop];
} }
@@ -51,7 +51,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
for (NSNetService* service in services) { for (NSNetService* service in services) {
if (service.hostName != nil) { if (service.hostName != nil) {
Host* host = [dataMan createHost]; Host* host = [dataMan createHost];
host.address = service.hostName; host.activeAddress = host.address = service.hostName;
host.name = host.address; host.name = host.address;
[hosts addObject:host]; [hosts addObject:host];
} }
@@ -60,12 +60,12 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
} }
- (void)netServiceDidResolveAddress:(NSNetService *)service { - (void)netServiceDidResolveAddress:(NSNetService *)service {
NSLog(@"Resolved address: %@ -> %@", service, service.hostName); Log(LOG_I, @"Resolved address: %@ -> %@", service, service.hostName);
[self.callback updateHosts:[self getFoundHosts]]; [self.callback updateHosts:[self getFoundHosts]];
} }
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict { - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
NSLog(@"Did not resolve address for: %@\n%@", sender, [errorDict description]); Log(LOG_W, @"Did not resolve address for: %@\n%@", sender, [errorDict description]);
// Schedule a retry in 2 seconds // Schedule a retry in 2 seconds
[NSTimer scheduledTimerWithTimeInterval:2.0 [NSTimer scheduledTimerWithTimeInterval:2.0
@@ -76,7 +76,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
} }
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing { - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
NSLog(@"Found service: %@", aNetService); Log(LOG_I, @"Found service: %@", aNetService);
[aNetService setDelegate:self]; [aNetService setDelegate:self];
[aNetService resolveWithTimeout:5]; [aNetService resolveWithTimeout:5];
@@ -85,13 +85,12 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
} }
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing { - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
NSLog(@"Removing service: %@", aNetService); Log(LOG_I, @"Removing service: %@", aNetService);
[services removeObject:aNetService]; [services removeObject:aNetService];
} }
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict { - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict {
NSLog(@"Did not perform search"); Log(LOG_W, @"Did not perform search: \n%@", [errorDict description]);
NSLog(@"%@", [errorDict description]);
// Schedule a retry in 2 seconds // Schedule a retry in 2 seconds
[NSTimer scheduledTimerWithTimeInterval:2.0 [NSTimer scheduledTimerWithTimeInterval:2.0
@@ -107,7 +106,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
return; return;
} }
NSLog(@"Retrying mDNS search"); Log(LOG_I, @"Retrying mDNS search");
[mDNSBrowser stop]; [mDNSBrowser stop];
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""]; [mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
} }
@@ -118,7 +117,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
return; return;
} }
NSLog(@"Retrying mDNS resolution"); Log(LOG_I, @"Retrying mDNS resolution");
for (NSNetService* service in services) { for (NSNetService* service in services) {
if (service.hostName == nil) { if (service.hostName == nil) {
[service setDelegate:self]; [service setDelegate:self];
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// PairManager.h // PairManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/19/14. // Created by Diego Waxemberg on 10/19/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+73 -38
View File
@@ -1,14 +1,17 @@
// //
// PairManager.m // PairManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/19/14. // Created by Diego Waxemberg on 10/19/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "PairManager.h" #import "PairManager.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "Utils.h" #import "Utils.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
#import "ServerInfoResponse.h"
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
@@ -27,37 +30,43 @@
} }
- (void) main { - (void) main {
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
if (serverInfo == NULL) { [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]
fallbackError:401 fallbackRequest:[_httpManager newHttpServerInfoRequest]]];
if (serverInfoResp == nil) {
[_callback pairFailed:@"Unable to connect to PC"]; [_callback pairFailed:@"Unable to connect to PC"];
return; return;
} }
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) { if ([serverInfoResp isStatusOk]) {
[_callback pairFailed:@"You must stop streaming before attempting to pair."]; if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) {
} [_callback pairFailed:@"You must stop streaming before attempting to pair."];
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) { } else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
[self initiatePair]; [self initiatePair];
} else { } else {
[_callback alreadyPaired]; [_callback alreadyPaired];
}
} }
} }
- (void) initiatePair { - (void) initiatePair {
NSString* PIN = [self generatePIN]; NSString* PIN = [self generatePIN];
NSData* salt = [self saltPIN:PIN]; NSData* salt = [self saltPIN:PIN];
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt); Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
[_callback showPIN:PIN]; [_callback showPIN:PIN];
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]]; HttpResponse* pairResp = [[HttpResponse alloc] init];
NSString* pairedString; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt]]];
pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"]; if (![self verifyResponseStatus:pairResp]) {
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { return;
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; }
NSInteger pairedStatus;
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing was declined by the target."]; [_callback pairFailed:@"Pairing was declined by the target."];
return; return;
} }
NSString* plainCert = [HttpManager getStringFromXML:pairResp tag:@"plaincert"]; NSString* plainCert = [pairResp getStringTag:@"plaincert"];
CryptoManager* cryptoMan = [[CryptoManager alloc] init]; CryptoManager* cryptoMan = [[CryptoManager alloc] init];
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt]; NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
@@ -65,15 +74,18 @@
NSData* randomChallenge = [Utils randomBytes:16]; NSData* randomChallenge = [Utils randomBytes:16];
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey]; NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]]; HttpResponse* challengeResp = [[HttpResponse alloc] init];
pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:challengeResp withUrlRequest:[_httpManager newChallengeRequest:encryptedChallenge]]];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { if (![self verifyResponseStatus:challengeResp]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; return;
}
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #2 failed"]; [_callback pairFailed:@"Pairing stage #2 failed"];
return; return;
} }
NSData* encServerChallengeResp = [Utils hexToBytes:[HttpManager getStringFromXML:challengeResp tag:@"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, 20)];
@@ -83,50 +95,73 @@
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]]; NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey]; NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]; HttpResponse* secretResp = [[HttpResponse alloc] init];
pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:secretResp withUrlRequest:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { if (![self verifyResponseStatus:secretResp]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; return;
}
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #3 failed"]; [_callback pairFailed:@"Pairing stage #3 failed"];
return; return;
} }
NSData* serverSecretResp = [Utils hexToBytes:[HttpManager getStringFromXML:secretResp tag:@"pairingsecret"]]; NSData* serverSecretResp = [Utils hexToBytes:[secretResp getStringTag:@"pairingsecret"]];
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)]; NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
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 executeRequestSynchronously:[_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* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
if (![serverChallengeRespHash isEqual:serverResponse]) { if (![serverChallengeRespHash isEqual:serverResponse]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Incorrect PIN"]; [_callback pairFailed:@"Incorrect PIN"];
return; return;
} }
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]]; NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]; HttpResponse* clientSecretResp = [[HttpResponse alloc] init];
pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientSecretResp withUrlRequest:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { if (![self verifyResponseStatus:clientSecretResp]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; return;
}
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #4 failed"]; [_callback pairFailed:@"Pairing stage #4 failed"];
return; return;
} }
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]]; HttpResponse* clientPairChallengeResp = [[HttpResponse alloc] init];
pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientPairChallengeResp withUrlRequest:[_httpManager newPairChallenge]]];
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) { if (![self verifyResponseStatus:clientPairChallengeResp]) {
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]]; return;
}
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #5 failed"]; [_callback pairFailed:@"Pairing stage #5 failed"];
return; return;
} }
[_callback pairSuccessful]; [_callback pairSuccessful];
} }
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
if (resp == nil) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Network error occured."];
return false;
} else if (![resp isStatusOk]) {
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:resp.statusMessage];
return false;
} else {
return true;
}
}
- (NSData*) concatData:(NSData*)data with:(NSData*)moreData { - (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data]; NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
[concatData appendData:moreData]; [concatData appendData:moreData];
+24
View File
@@ -0,0 +1,24 @@
//
// ServerInfoResponse.h
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "HttpResponse.h"
#define TAG_HOSTNAME @"hostname"
#define TAG_EXTERNAL_IP @"ExternalIP"
#define TAG_LOCAL_IP @"LocalIP"
#define TAG_UNIQUE_ID @"uniqueid"
#define TAG_MAC_ADDRESS @"mac"
#define TAG_PAIR_STATUS @"PairStatus"
@interface ServerInfoResponse : HttpResponse <Response>
- (void) populateWithData:(NSData *)data;
- (void) populateHost:(Host*)host;
@end
+35
View File
@@ -0,0 +1,35 @@
//
// ServerInfoResponse.m
// Moonlight
//
// Created by Diego Waxemberg on 2/1/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "ServerInfoResponse.h"
#import <libxml2/libxml/xmlreader.h>
@implementation ServerInfoResponse
@synthesize data, statusCode, statusMessage;
- (void) populateWithData:(NSData *)xml {
self.data = xml;
[super parseData];
}
- (void) populateHost:(Host*)host {
host.name = [[self getStringTag:TAG_HOSTNAME] trim];
host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim];
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim];
host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim];
NSInteger pairStatus;
if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) {
host.pairState = pairStatus ? PairStatePaired : PairStateUnpaired;
} else {
host.pairState = PairStateUnknown;
}
}
@end
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// WakeOnLanManager.h // WakeOnLanManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/2/15. // Created by Diego Waxemberg on 1/2/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+6 -6
View File
@@ -1,9 +1,9 @@
// //
// WakeOnLanManager.m // WakeOnLanManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 1/2/15. // Created by Diego Waxemberg on 1/2/15.
// Copyright (c) 2015 Limelight Stream. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "WakeOnLanManager.h" #import "WakeOnLanManager.h"
@@ -24,10 +24,10 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL); CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL);
if (!wolSocket) { if (!wolSocket) {
CFRelease(dataPayload); CFRelease(dataPayload);
NSLog(@"Failed to create WOL socket"); Log(LOG_E, @"Failed to create WOL socket");
return; return;
} }
NSLog(@"WOL socket created"); Log(LOG_I, @"WOL socket created");
struct sockaddr_in addr; struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
@@ -48,7 +48,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
// try all ports // try all ports
for (int j = 0; j < numPorts; j++) { for (int j = 0; j < numPorts; j++) {
addr.sin_port = htons(ports[j]); addr.sin_port = htons(ports[j]);
NSLog(@"Sending WOL packet"); Log(LOG_I, @"Sending WOL packet");
CFSocketSendData(wolSocket, dataAddress, dataPayload, 0); CFSocketSendData(wolSocket, dataAddress, dataPayload, 0);
} }
CFRelease(dataAddress); CFRelease(dataAddress);
@@ -76,7 +76,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
+ (NSData*) macStringToBytes:(NSString*)mac { + (NSData*) macStringToBytes:(NSString*)mac {
NSString* macString = [mac stringByReplacingOccurrencesOfString:@":" withString:@""]; NSString* macString = [mac stringByReplacingOccurrencesOfString:@":" withString:@""];
NSLog(@"MAC: %@", macString); Log(LOG_D, @"MAC: %@", macString);
return [Utils hexToBytes:macString]; return [Utils hexToBytes:macString];
} }
+3 -3
View File
@@ -1,9 +1,9 @@
// //
// Connection.h // Connection.h
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/19/14. // Created by Diego Waxemberg on 1/19/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -25,7 +25,7 @@
@interface Connection : NSOperation <NSStreamDelegate> @interface Connection : NSOperation <NSStreamDelegate>
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks; -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion;
-(void) terminate; -(void) terminate;
-(void) terminateInternal; -(void) terminateInternal;
-(void) main; -(void) main;
+29 -63
View File
@@ -1,9 +1,9 @@
// //
// Connection.m // Connection.m
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/19/14. // Created by Diego Waxemberg on 1/19/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "Connection.h" #import "Connection.h"
@@ -15,11 +15,12 @@
#include "opus.h" #include "opus.h"
@implementation Connection { @implementation Connection {
IP_ADDRESS _host; const char* _host;
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 OpusDecoder *opusDecoder; static OpusDecoder *opusDecoder;
@@ -44,10 +45,6 @@ static int audioBufferQueueLength;
static AudioComponentInstance audioUnit; static AudioComponentInstance audioUnit;
static VideoDecoderRenderer* renderer; static VideoDecoderRenderer* renderer;
void DrSetup(int width, int height, int fps, void* context, int drFlags)
{
}
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
{ {
int offset = 0; int offset = 0;
@@ -68,18 +65,6 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength]; return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
} }
void DrStart(void)
{
}
void DrStop(void)
{
}
void DrRelease(void)
{
}
void ArInit(void) void ArInit(void)
{ {
int err; int err;
@@ -110,7 +95,7 @@ void ArInit(void)
status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit); status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit);
if (status) { if (status) {
NSLog(@"Unable to instantiate new AudioComponent: %d", (int32_t)status); Log(LOG_E, @"Unable to instantiate new AudioComponent: %d", (int32_t)status);
} }
AudioStreamBasicDescription audioFormat = {0}; AudioStreamBasicDescription audioFormat = {0};
@@ -131,7 +116,7 @@ void ArInit(void)
&audioFormat, &audioFormat,
sizeof(audioFormat)); sizeof(audioFormat));
if (status) { if (status) {
NSLog(@"Unable to set audio unit to input: %d", (int32_t)status); Log(LOG_E, @"Unable to set audio unit to input: %d", (int32_t)status);
} }
AURenderCallbackStruct callbackStruct = {0}; AURenderCallbackStruct callbackStruct = {0};
@@ -145,25 +130,35 @@ void ArInit(void)
&callbackStruct, &callbackStruct,
sizeof(callbackStruct)); sizeof(callbackStruct));
if (status) { if (status) {
NSLog(@"Unable to set audio unit callback: %d", (int32_t)status); Log(LOG_E, @"Unable to set audio unit callback: %d", (int32_t)status);
} }
status = AudioUnitInitialize(audioUnit); status = AudioUnitInitialize(audioUnit);
if (status) { if (status) {
NSLog(@"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) { if (status) {
NSLog(@"Unable to uninitialize audioUnit: %d", (int32_t)status); Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
}
status = AudioUnitUninitialize(audioUnit);
if (status) {
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
} }
// Audio session is now inactive // Audio session is now inactive
@@ -181,22 +176,6 @@ void ArRelease(void)
} }
} }
void ArStart(void)
{
OSStatus status = AudioOutputUnitStart(audioUnit);
if (status) {
NSLog(@"Unable to start audioUnit: %d", (int32_t)status);
}
}
void ArStop(void)
{
OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
NSLog(@"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);
@@ -213,7 +192,7 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
[audioLock lock]; [audioLock lock];
if (audioBufferQueueLength > MAX_QUEUE_ENTRIES) { if (audioBufferQueueLength > MAX_QUEUE_ENTRIES) {
NSLog(@"Audio player too slow. Dropping all decoded samples!"); Log(LOG_W, @"Audio player too slow. Dropping all decoded samples!");
// Clear all values from the buffer queue // Clear all values from the buffer queue
struct AUDIO_BUFFER_QUEUE_ENTRY *entry; struct AUDIO_BUFFER_QUEUE_ENTRY *entry;
@@ -289,17 +268,18 @@ void ClDisplayTransientMessage(char* message)
-(void) terminate -(void) terminate
{ {
// We're guaranteed to not be on a limelight-common thread // We're guaranteed to not be on a moonlight-common thread
// here so it's safe to call stop directly // here so it's safe to call stop directly
LiStopConnection(); LiStopConnection();
} }
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
{ {
self = [super init]; self = [super init];
_host = config.hostAddr; _host = [config.host cStringUsingEncoding:NSUTF8StringEncoding];
renderer = myRenderer; renderer = myRenderer;
_callbacks = callbacks; _callbacks = callbacks;
_serverMajorVersion = serverMajorVersion;
_streamConfig.width = config.width; _streamConfig.width = config.width;
_streamConfig.height = config.height; _streamConfig.height = config.height;
_streamConfig.fps = config.frameRate; _streamConfig.fps = config.frameRate;
@@ -313,16 +293,11 @@ 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 = DrSetup; memset(&_drCallbacks, 0, sizeof(_drCallbacks));
_drCallbacks.start = DrStart;
_drCallbacks.stop = DrStop;
_drCallbacks.release = DrRelease;
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit; _drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
_arCallbacks.init = ArInit; _arCallbacks.init = ArInit;
_arCallbacks.start = ArStart; _arCallbacks.cleanup = ArCleanup;
_arCallbacks.stop = ArStop;
_arCallbacks.release = ArRelease;
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample; _arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
_clCallbacks.stageStarting = ClStageStarting; _clCallbacks.stageStarting = ClStageStarting;
@@ -419,21 +394,12 @@ static OSStatus playbackCallback(void *inRefCon,
-(void) main -(void) main
{ {
PLATFORM_CALLBACKS dummyPlCallbacks;
// Only used on Windows
dummyPlCallbacks.threadStart = NULL;
dummyPlCallbacks.debugPrint = NULL;
LiStartConnection(_host, LiStartConnection(_host,
&_streamConfig, &_streamConfig,
&_clCallbacks, &_clCallbacks,
&_drCallbacks, &_drCallbacks,
&_arCallbacks, &_arCallbacks,
&dummyPlCallbacks, NULL, 0, _serverMajorVersion);
NULL, 0);
} }
@end @end
+2 -3
View File
@@ -1,9 +1,9 @@
// //
// StreamConfiguration.h // StreamConfiguration.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -12,7 +12,6 @@
@property NSString* host; @property NSString* host;
@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;
+3 -3
View File
@@ -1,13 +1,13 @@
// //
// StreamConfiguration.m // StreamConfiguration.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "StreamConfiguration.h" #import "StreamConfiguration.h"
@implementation StreamConfiguration @implementation StreamConfiguration
@synthesize host, appID, hostAddr, width, height, frameRate, bitRate, riKeyId, riKey; @synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey;
@end @end
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// StreamManager.h // StreamManager.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+35 -20
View File
@@ -1,9 +1,9 @@
// //
// StreamManager.m // StreamManager.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "StreamManager.h" #import "StreamManager.h"
@@ -12,6 +12,9 @@
#import "Utils.h" #import "Utils.h"
#import "OnScreenControls.h" #import "OnScreenControls.h"
#import "StreamView.h" #import "StreamView.h"
#import "ServerInfoResponse.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
@implementation StreamManager { @implementation StreamManager {
StreamConfiguration* _config; StreamConfiguration* _config;
@@ -41,11 +44,14 @@
deviceName:@"roth" deviceName:@"roth"
cert:cert]; cert:cert];
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
NSString* pairStatus = [HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"]; fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
NSString* currentClient = [HttpManager getStringFromXML:serverInfoResp tag:@"CurrentClient"]; NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
if (currentGame == NULL || pairStatus == NULL) { NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL || appversion == NULL) {
[_callbacks launchFailed:@"Failed to connect to PC"]; [_callbacks launchFailed:@"Failed to connect to PC"];
return; return;
} }
@@ -81,40 +87,46 @@
[((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width [((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width
y:_config.height / screenSize.height]; y:_config.height / screenSize.height];
int majorVersion = [[appversion substringToIndex:1] intValue];
Log(LOG_I, @"Server is generation %d", majorVersion);
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView]; VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks]; _connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks serverMajorVersion:majorVersion];
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init]; NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:_connection]; [opQueue addOperation:_connection];
} }
// This should NEVER be called from within a thread // This should NEVER be called from within a thread
// owned by limelight-common // owned by moonlight-common
- (void) stopStream - (void) stopStream
{ {
[_connection terminate]; [_connection terminate];
} }
// This should only be called from within a thread // This should only be called from within a thread
// owned by limelight-common // owned by moonlight-common
- (void) stopStreamInternal - (void) stopStreamInternal
{ {
[_connection terminateInternal]; [_connection terminateInternal];
} }
- (BOOL) launchApp:(HttpManager*)hMan { - (BOOL) launchApp:(HttpManager*)hMan {
NSData* launchResp = [hMan executeRequestSynchronously: HttpResponse* launchResp = [[HttpResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest:
[hMan newLaunchRequest:_config.appID [hMan newLaunchRequest:_config.appID
width:_config.width width:_config.width
height:_config.height height:_config.height
refreshRate:_config.frameRate refreshRate:_config.frameRate
rikey:[Utils bytesToHex:_config.riKey] rikey:[Utils bytesToHex:_config.riKey]
rikeyid:_config.riKeyId]]; rikeyid:_config.riKeyId]]];
NSString *gameSession = [HttpManager getStringFromXML:launchResp tag:@"gamesession"]; NSString *gameSession = [launchResp getStringTag:@"gamesession"];
if (launchResp == NULL) { if (launchResp == NULL || ![launchResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to launch app"]; [_callbacks launchFailed:@"Failed to launch app"];
Log(LOG_E, @"Failed Launch Response: %@", launchResp.statusMessage);
return FALSE; return FALSE;
} else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) { } else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) {
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:launchResp]]; [_callbacks launchFailed:launchResp.statusMessage];
Log(LOG_E, @"Failed to parse game session. Code: %ld Response: %@", (long)launchResp.statusCode, launchResp.statusMessage);
return FALSE; return FALSE;
} }
@@ -122,15 +134,18 @@
} }
- (BOOL) resumeApp:(HttpManager*)hMan { - (BOOL) resumeApp:(HttpManager*)hMan {
NSData* resumeResp = [hMan executeRequestSynchronously: HttpResponse* resumeResp = [[HttpResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:resumeResp withUrlRequest:
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey] [hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
riKeyId:_config.riKeyId]]; riKeyId:_config.riKeyId]]];
NSString *resume = [HttpManager getStringFromXML:resumeResp tag:@"resume"]; NSString* resume = [resumeResp getStringTag:@"resume"];
if (resumeResp == NULL) { if (resumeResp == NULL || ![resumeResp isStatusOk]) {
[_callbacks launchFailed:@"Failed to resume app"]; [_callbacks launchFailed:@"Failed to resume app"];
Log(LOG_E, @"Failed Resume Response: %@", resumeResp.statusMessage);
return FALSE; return FALSE;
} else if (resume == NULL || [resume isEqualToString:@"0"]) { } else if (resume == NULL || [resume isEqualToString:@"0"]) {
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:resumeResp]]; [_callbacks launchFailed:resumeResp.statusMessage];
Log(LOG_E, @"Failed to parse resume response. Code: %ld Response: %@", (long)resumeResp.statusCode, resumeResp.statusMessage);
return FALSE; return FALSE;
} }
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// VideoDecoderRenderer.h // VideoDecoderRenderer.h
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/18/14. // Created by Cameron Gutman on 10/18/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
+14 -14
View File
@@ -1,9 +1,9 @@
// //
// VideoDecoderRenderer.m // VideoDecoderRenderer.m
// Limelight // Moonlight
// //
// Created by Cameron Gutman on 10/18/14. // Created by Cameron Gutman on 10/18/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "VideoDecoderRenderer.h" #import "VideoDecoderRenderer.h"
@@ -86,7 +86,7 @@
kCFAllocatorDefault, kCFAllocatorDefault,
NULL, 0, nalLength + 1, 0); NULL, 0, nalLength + 1, 0);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return; return;
} }
@@ -96,7 +96,7 @@
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer, status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
oldOffset, NAL_LENGTH_PREFIX_SIZE); oldOffset, NAL_LENGTH_PREFIX_SIZE);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return; return;
} }
} else { } else {
@@ -106,7 +106,7 @@
kCFAllocatorDefault, NULL, 0, kCFAllocatorDefault, NULL, 0,
NAL_LENGTH_PREFIX_SIZE, 0); NAL_LENGTH_PREFIX_SIZE, 0);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferAppendMemoryBlock failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferAppendMemoryBlock failed: %d", (int)status);
return; return;
} }
@@ -117,7 +117,7 @@
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer, status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
oldOffset, NAL_LENGTH_PREFIX_SIZE); oldOffset, NAL_LENGTH_PREFIX_SIZE);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return; return;
} }
@@ -127,7 +127,7 @@
kCFAllocatorNull, // Don't deallocate data on free kCFAllocatorNull, // Don't deallocate data on free
NULL, 0, dataLength, 0); NULL, 0, dataLength, 0);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
return; return;
} }
} }
@@ -141,7 +141,7 @@
// Check for previous decoder errors before doing anything // Check for previous decoder errors before doing anything
if (displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) { if (displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) {
NSLog(@"Display layer rendering failed: %@", displayLayer.error); Log(LOG_E, @"Display layer rendering failed: %@", displayLayer.error);
// Recreate the display layer // Recreate the display layer
[self reinitializeDisplayLayer]; [self reinitializeDisplayLayer];
@@ -152,14 +152,14 @@
if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) { if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) {
if (nalType == NAL_TYPE_SPS) { if (nalType == NAL_TYPE_SPS) {
NSLog(@"Got SPS"); Log(LOG_I, @"Got SPS");
spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE]; spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
waitingForSps = false; waitingForSps = false;
// We got a new SPS so wait for a new PPS to match it // We got a new SPS so wait for a new PPS to match it
waitingForPps = true; waitingForPps = true;
} else if (nalType == NAL_TYPE_PPS) { } else if (nalType == NAL_TYPE_PPS) {
NSLog(@"Got PPS"); Log(LOG_I, @"Got PPS");
ppsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE]; ppsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
waitingForPps = false; waitingForPps = false;
} }
@@ -169,7 +169,7 @@
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] }; const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] }; const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
NSLog(@"Constructing new format description"); Log(LOG_I, @"Constructing new format description");
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
2, /* count of parameter sets */ 2, /* count of parameter sets */
parameterSetPointers, parameterSetPointers,
@@ -177,7 +177,7 @@
NAL_LENGTH_PREFIX_SIZE, NAL_LENGTH_PREFIX_SIZE,
&formatDesc); &formatDesc);
if (status != noErr) { if (status != noErr) {
NSLog(@"Failed to create format description: %d", (int)status); Log(LOG_E, @"Failed to create format description: %d", (int)status);
formatDesc = NULL; formatDesc = NULL;
} }
} }
@@ -206,7 +206,7 @@
status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer); status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status); Log(LOG_E, @"CMBlockBufferCreateEmpty failed: %d", (int)status);
free(data); free(data);
return DR_NEED_IDR; return DR_NEED_IDR;
} }
@@ -241,7 +241,7 @@
NULL, 0, NULL, NULL, 0, NULL,
&sampleBuffer); &sampleBuffer);
if (status != noErr) { if (status != noErr) {
NSLog(@"CMSampleBufferCreate failed: %d", (int)status); Log(LOG_E, @"CMSampleBufferCreate failed: %d", (int)status);
CFRelease(blockBuffer); CFRelease(blockBuffer);
return DR_NEED_IDR; return DR_NEED_IDR;
} }
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// UIAppView.h // UIAppView.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/22/14. // Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
+40 -29
View File
@@ -1,9 +1,9 @@
// //
// UIAppView.m // UIAppView.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/22/14. // Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "UIAppView.h" #import "UIAppView.h"
@@ -12,9 +12,9 @@
App* _app; App* _app;
UIButton* _appButton; UIButton* _appButton;
UILabel* _appLabel; UILabel* _appLabel;
UIImageView* _appOverlay;
id<AppCallback> _callback; id<AppCallback> _callback;
} }
static int LABEL_DY = 20;
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback { - (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback {
self = [super init]; self = [super init];
@@ -24,39 +24,58 @@ static int LABEL_DY = 20;
_appButton = [UIButton buttonWithType:UIButtonTypeCustom]; _appButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage* noImage = [UIImage imageNamed:@"NoAppImage"]; UIImage* noImage = [UIImage imageNamed:@"NoAppImage"];
[_appButton setBackgroundImage:noImage forState:UIControlStateNormal]; [_appButton setBackgroundImage:noImage forState:UIControlStateNormal];
[_appButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)]; [_appButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
[_appButton sizeToFit]; [_appButton sizeToFit];
[_appButton addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventTouchUpInside]; [_appButton addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventTouchUpInside];
_appOverlay = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Play"]];
_appOverlay.layer.shadowColor = [UIColor blackColor].CGColor;
_appOverlay.layer.shadowOffset = CGSizeMake(0, 0);
_appOverlay.layer.shadowOpacity = 1;
_appOverlay.layer.shadowRadius = 2.0;
[_appOverlay setHidden: YES];
[self addSubview:_appButton]; [self addSubview:_appButton];
[self addSubview:_appOverlay];
[self sizeToFit]; [self sizeToFit];
_appButton.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height); _appButton.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
_appOverlay.frame = CGRectMake(0, 0, noImage.size.width / 2.f, noImage.size.height / 4.f);
self.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height); self.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
return self; return self;
} }
- (void) updateBounds {
float x = _appButton.frame.origin.x < _appLabel.frame.origin.x ? _appButton.frame.origin.x : _appLabel.frame.origin.x;
float y = _appButton.frame.origin.y < _appLabel.frame.origin.y ? _appButton.frame.origin.y : _appLabel.frame.origin.y;
self.bounds = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
self.frame = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
}
- (void) appClicked { - (void) appClicked {
[_callback appClicked:_app]; [_callback appClicked:_app];
} }
- (void) updateAppImage { - (void) updateAppImage {
if (_app.appImage != nil) { [_appOverlay setHidden:!_app.isRunning];
_appButton.frame = CGRectMake(0, 0, _app.appImage.size.width / 2, _app.appImage.size.height / 2);
self.frame = CGRectMake(0, 0, _app.appImage.size.width / 2, _app.appImage.size.height / 2);
[_appButton setBackgroundImage:_app.appImage forState:UIControlStateNormal];
[self setNeedsDisplay];
}
// TODO: Improve no-app image detection // TODO: Improve no-app image detection
if (_app.appImage == nil || (_app.appImage.size.width == 130.f && _app.appImage.size.height == 180.f)) { // This size of image might be blank image received from GameStream. BOOL noAppImage = false;
if (_app.image != nil) {
UIImage* appImage = [UIImage imageWithData:_app.image];
// This size of image might be blank image received from GameStream.
if (!(appImage.size.width == 130.f && appImage.size.height == 180.f)) {
_appButton.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
self.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
_appOverlay.frame = CGRectMake(0, 0, self.frame.size.width / 2.f, self.frame.size.height / 4.f);
_appOverlay.layer.shadowRadius = 4.0;
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
[_appButton setBackgroundImage:appImage forState:UIControlStateNormal];
[self setNeedsDisplay];
} else {
noAppImage = true;
}
} else {
noAppImage = true;
}
if (noAppImage) {
_appLabel = [[UILabel alloc] init]; _appLabel = [[UILabel alloc] init];
CGFloat padding = 4.f; CGFloat padding = 4.f;
[_appLabel setFrame: CGRectMake(padding, padding, _appButton.frame.size.width - 2 * padding, _appButton.frame.size.height - 2 * padding)]; [_appLabel setFrame: CGRectMake(padding, padding, _appButton.frame.size.width - 2 * padding, _appButton.frame.size.height - 2 * padding)];
@@ -66,18 +85,10 @@ static int LABEL_DY = 20;
[_appLabel setTextAlignment:NSTextAlignmentCenter]; [_appLabel setTextAlignment:NSTextAlignmentCenter];
[_appLabel setLineBreakMode:NSLineBreakByWordWrapping]; [_appLabel setLineBreakMode:NSLineBreakByWordWrapping];
[_appLabel setNumberOfLines:0]; [_appLabel setNumberOfLines:0];
[_appLabel setText:_app.appName]; [_appLabel setText:_app.name];
[_appButton addSubview:_appLabel]; [_appButton addSubview:_appLabel];
} }
} }
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end @end
+3 -3
View File
@@ -1,9 +1,9 @@
// //
// UIComputerView.h // UIComputerView.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/22/14. // Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@@ -11,7 +11,7 @@
@protocol HostCallback <NSObject> @protocol HostCallback <NSObject>
- (void) hostClicked:(Host*)host; - (void) hostClicked:(Host*)host view:(UIView*)view;
- (void) hostLongClicked:(Host*)host view:(UIView*)view; - (void) hostLongClicked:(Host*)host view:(UIView*)view;
- (void) addHostClicked; - (void) addHostClicked;
+3 -3
View File
@@ -1,9 +1,9 @@
// //
// UIComputerView.m // UIComputerView.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/22/14. // Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "UIComputerView.h" #import "UIComputerView.h"
@@ -171,7 +171,7 @@ static const int LABEL_DY = 20;
} }
- (void) hostClicked { - (void) hostClicked {
[_callback hostClicked:_host]; [_callback hostClicked:_host view:self];
} }
- (void) addClicked { - (void) addClicked {
+29
View File
@@ -0,0 +1,29 @@
//
// Logger.h
// Moonlight
//
// Created by Diego Waxemberg on 2/10/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#ifndef Limelight_Logger_h
#define Limelight_Logger_h
#import <stdarg.h>
typedef enum {
LOG_D,
LOG_I,
LOG_W,
LOG_E
} LogLevel;
#define PRFX_DEBUG @"<DEBUG>"
#define PRFX_INFO @"<INFO>"
#define PRFX_WARN @"<WARN>"
#define PRFX_ERROR @"<ERROR>"
void Log(LogLevel level, NSString* fmt, ...);
void LogTag(LogLevel level, NSString* tag, NSString* fmt, ...);
#endif
+53
View File
@@ -0,0 +1,53 @@
//
// Logger.m
// Moonlight
//
// Created by Diego Waxemberg on 2/10/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "Logger.h"
void LogTagv(LogLevel level, NSString* tag, NSString* fmt, va_list args);
void Log(LogLevel level, NSString* fmt, ...) {
va_list args;
va_start(args, fmt);
LogTagv(level, NULL, fmt, args);
va_end(args);
}
void LogTag(LogLevel level, NSString* tag, NSString* fmt, ...) {
va_list args;
va_start(args, fmt);
LogTagv(level, tag, fmt, args);
va_end(args);
}
void LogTagv(LogLevel level, NSString* tag, NSString* fmt, va_list args) {
NSString* levelPrefix = @"";
switch(level) {
case LOG_D:
levelPrefix = PRFX_DEBUG;
break;
case LOG_I:
levelPrefix = PRFX_INFO;
break;
case LOG_W:
levelPrefix = PRFX_WARN;
break;
case LOG_E:
levelPrefix = PRFX_ERROR;
break;
default:
break;
}
NSString* prefixedString;
if (tag) {
prefixedString = [NSString stringWithFormat:@"%@ (%@) %@", levelPrefix, tag, fmt];
} else {
prefixedString = [NSString stringWithFormat:@"%@ %@", levelPrefix, fmt];
}
NSLogv(prefixedString, args);
}
+8 -2
View File
@@ -1,9 +1,9 @@
// //
// Utils.h // Utils.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -24,3 +24,9 @@ FOUNDATION_EXPORT NSString *const deviceName;
+ (int) resolveHost:(NSString*)host; + (int) resolveHost:(NSString*)host;
@end @end
@interface NSString (NSStringWithTrim)
- (NSString*) trim;
@end
+13 -6
View File
@@ -1,9 +1,9 @@
// //
// Utils.m // Utils.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/20/14. // Created by Diego Waxemberg on 10/20/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "Utils.h" #import "Utils.h"
@@ -56,22 +56,29 @@ NSString *const deviceName = @"roth";
if (inet_addr([host UTF8String]) != INADDR_NONE) { if (inet_addr([host UTF8String]) != INADDR_NONE) {
// Already an IP address // Already an IP address
int addr = inet_addr([host UTF8String]); int addr = inet_addr([host UTF8String]);
NSLog(@"host address: %d", addr); Log(LOG_I, @"host address: %d", addr);
return addr; return addr;
} else { } else {
hostent = gethostbyname([host UTF8String]); hostent = gethostbyname([host UTF8String]);
if (hostent != NULL) { if (hostent != NULL) {
char* ipstr = inet_ntoa(*(struct in_addr*)hostent->h_addr_list[0]); char* ipstr = inet_ntoa(*(struct in_addr*)hostent->h_addr_list[0]);
NSLog(@"Resolved %@ -> %s", host, ipstr); Log(LOG_I, @"Resolved %@ -> %s", host, ipstr);
int addr = inet_addr(ipstr); int addr = inet_addr(ipstr);
NSLog(@"host address: %d", addr); Log(LOG_I, @"host address: %d", addr);
return addr; return addr;
} else { } else {
NSLog(@"Failed to resolve host: %d", h_errno); Log(LOG_W, @"Failed to resolve host: %d", h_errno);
return 0; return 0;
} }
} }
} }
@end
@implementation NSString (NSStringWithTrim)
- (NSString *)trim {
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
@end @end
@@ -0,0 +1,14 @@
//
// LoadingFrameViewController.h
// Moonlight
//
// Created by Diego Waxemberg on 2/24/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface LoadingFrameViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *loadingSpinner;
@end
@@ -0,0 +1,38 @@
//
// LoadingFrameViewController.m
// Moonlight
//
// Created by Diego Waxemberg on 2/24/15.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "LoadingFrameViewController.h"
@interface LoadingFrameViewController ()
@end
@implementation LoadingFrameViewController
- (void)viewDidLoad {
[super viewDidLoad];
// center the loading spinner
self.loadingSpinner.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
@@ -1,9 +1,9 @@
// //
// MainFrameViewController.h // MainFrameViewController.h
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/17/14. // Created by Diego Waxemberg on 1/17/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@@ -12,13 +12,12 @@
#import "StreamConfiguration.h" #import "StreamConfiguration.h"
#import "UIComputerView.h" #import "UIComputerView.h"
#import "UIAppView.h" #import "UIAppView.h"
#import "AppManager.h" #import "AppAssetManager.h"
#import "SWRevealViewController.h" #import "SWRevealViewController.h"
@interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate> @interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UIButton *limelightLogoButton; @property (strong, nonatomic) IBOutlet UIButton *limelightLogoButton;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *computerNameButton; @property (weak, nonatomic) IBOutlet UIBarButtonItem *computerNameButton;
+ (StreamConfiguration*) getStreamConfiguration;
@end @end
@@ -1,15 +1,14 @@
// MainFrameViewController.m // MainFrameViewController.m
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/17/14. // Created by Diego Waxemberg on 1/17/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "MainFrameViewController.h" #import "MainFrameViewController.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "HttpManager.h" #import "HttpManager.h"
#import "Connection.h" #import "Connection.h"
#import "VideoDecoderRenderer.h"
#import "StreamManager.h" #import "StreamManager.h"
#import "Utils.h" #import "Utils.h"
#import "UIComputerView.h" #import "UIComputerView.h"
@@ -19,80 +18,174 @@
#import "DataManager.h" #import "DataManager.h"
#import "Settings.h" #import "Settings.h"
#import "WakeOnLanManager.h" #import "WakeOnLanManager.h"
#import "AppListResponse.h"
#import "ServerInfoResponse.h"
#import "StreamFrameViewController.h"
#import "LoadingFrameViewController.h"
@implementation MainFrameViewController { @implementation MainFrameViewController {
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
Host* _selectedHost; Host* _selectedHost;
NSString* _uniqueId; NSString* _uniqueId;
NSData* _cert; NSData* _cert;
NSString* _currentGame;
DiscoveryManager* _discMan; DiscoveryManager* _discMan;
AppManager* _appManager; AppAssetManager* _appManager;
UIAlertView* _pairAlert; StreamConfiguration* _streamConfig;
UIAlertController* _pairAlert;
UIScrollView* hostScrollView; UIScrollView* hostScrollView;
int currentPosition; int currentPosition;
NSArray* _sortedAppList;
} }
static NSMutableSet* hostList; static NSMutableSet* hostList;
static NSArray* appList;
static StreamConfiguration* streamConfig;
+ (StreamConfiguration*) getStreamConfiguration {
return streamConfig;
}
- (void)showPIN:(NSString *)PIN { - (void)showPIN:(NSString *)PIN {
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing" message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil]; _pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing"
[_pairAlert show]; message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:_pairAlert animated:YES completion:nil];
}); });
} }
- (void)pairFailed:(NSString *)message { - (void)pairFailed:(NSString *)message {
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO]; [_pairAlert dismissViewControllerAnimated:YES completion:nil];
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Failed" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil]; _pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
[_pairAlert show]; message:message
preferredStyle:UIAlertControllerStyleAlert];
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
[self presentViewController:_pairAlert animated:YES completion:nil];
[_discMan startDiscovery]; [_discMan startDiscovery];
[self hideLoadingFrame];
}); });
} }
- (void)pairSuccessful { - (void)pairSuccessful {
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO]; [_pairAlert dismissViewControllerAnimated:YES completion:nil];
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Succesful" message:@"Successfully paired to host" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[_pairAlert show];
[_discMan startDiscovery]; [_discMan startDiscovery];
[self alreadyPaired];
}); });
} }
- (void)alreadyPaired { - (void)alreadyPaired {
BOOL usingCachedAppList = false;
// Capture the host here because it can change once we
// leave the main thread
Host* host = _selectedHost;
if ([host.appList count] > 0) {
usingCachedAppList = true;
dispatch_async(dispatch_get_main_queue(), ^{
if (host != _selectedHost) {
return;
}
_computerNameButton.title = host.name;
[self.navigationController.navigationBar setNeedsLayout];
[self updateAppsForHost:host];
[self hideLoadingFrame];
});
}
Log(LOG_I, @"Using cached app list: %d", usingCachedAppList);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{ HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
_computerNameButton.title = _selectedHost.name;
[self.navigationController.navigationBar setNeedsLayout];
});
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
appList = [HttpManager getAppListFromXML:appListResp];
dispatch_async(dispatch_get_main_queue(), ^{ AppListResponse* appListResp = [[AppListResponse alloc] init];
[self updateApps];
});
[_appManager stopRetrieving]; // Exempt this host from discovery while handling the applist query
[_appManager retrieveAssets:appList fromHost:_selectedHost]; [_discMan removeHostFromDiscovery:host];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
[_discMan addHostToDiscovery:host];
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingFrame];
if (host != _selectedHost) {
return;
}
UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"Fetching App List Failed"
message:@"The connection to the PC was interrupted."
preferredStyle:UIAlertControllerStyleAlert];
[applistAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
[self presentViewController:applistAlert animated:YES completion:nil];
host.online = NO;
[self showHostSelectionView];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[self mergeAppLists:[appListResp getAppList] forHost:host];
if (host != _selectedHost) {
return;
}
_computerNameButton.title = host.name;
[self.navigationController.navigationBar setNeedsLayout];
[self updateAppsForHost:host];
[_appManager stopRetrieving];
[_appManager retrieveAssetsFromHost:host];
[self hideLoadingFrame];
});
}
}); });
} }
- (void) mergeAppLists:(NSArray*) newList forHost:(Host*)host {
DataManager* database = [[DataManager alloc] init];
for (App* app in newList) {
BOOL appAlreadyInList = NO;
for (App* savedApp in host.appList) {
if ([app.id isEqualToString:savedApp.id]) {
savedApp.isRunning = app.isRunning;
appAlreadyInList = YES;
break;
}
}
if (!appAlreadyInList) {
app.host = host;
[host addAppListObject:app];
} else {
[database removeApp:app];
}
}
for (App* app in host.appList) {
BOOL appWasRemoved = YES;
for (App* mergedApp in newList) {
if ([mergedApp.id isEqualToString:app.id]) {
appWasRemoved = NO;
break;
}
}
if (appWasRemoved) {
[host removeAppListObject:app];
[database removeApp:app];
}
}
[database saveData];
}
- (void)showHostSelectionView { - (void)showHostSelectionView {
appList = [[NSArray alloc] init]; [_appManager stopRetrieving];
[[[DataManager alloc] init] saveData];
_selectedHost = nil;
_computerNameButton.title = @"No Host Selected"; _computerNameButton.title = @"No Host Selected";
[self.collectionView reloadData]; [self.collectionView reloadData];
[self.view addSubview:hostScrollView]; [self.view addSubview:hostScrollView];
} }
- (void) receivedAssetForApp:(App*)app { - (void) receivedAssetForApp:(App*)app {
[self.collectionView reloadData]; dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
} }
- (void)displayDnsFailedDialog { - (void)displayDnsFailedDialog {
@@ -103,36 +196,76 @@ static StreamConfiguration* streamConfig;
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
} }
- (void) hostClicked:(Host *)host { - (void) hostClicked:(Host *)host view:(UIView *)view {
NSLog(@"Clicked host: %@", host.name); // Treat clicks on offline hosts to be long clicks
// This shows the context menu with wake, delete, etc. rather
// than just hanging for a while and failing as we would in this
// code path.
if (!host.online && view != nil) {
[self hostLongClicked:host view:view];
return;
}
Log(LOG_D, @"Clicked host: %@", host.name);
_selectedHost = host; _selectedHost = host;
[self disableNavigation];
// If we are online, paired, and have a cached app list, skip straight
// to the app grid without a loading frame. This is the fast path that users
// should hit most.
if (host.online && host.pairState == PairStatePaired && host.appList.count > 0) {
[self alreadyPaired];
return;
}
[self showLoadingFrame];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
if ([[HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"] isEqualToString:@"1"]) {
NSLog(@"Already Paired"); // Exempt this host from discovery while handling the serverinfo request
[self alreadyPaired]; [_discMan removeHostFromDiscovery:host];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
[_discMan addHostToDiscovery:host];
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage);
dispatch_async(dispatch_get_main_queue(), ^{
[self hideLoadingFrame];
if (host != _selectedHost) {
return;
}
UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"Fetching Server Info Failed"
message:@"The connection to the PC was interrupted."
preferredStyle:UIAlertControllerStyleAlert];
[applistAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
[self presentViewController:applistAlert animated:YES completion:nil];
host.online = NO;
[self showHostSelectionView];
});
} else { } else {
NSLog(@"Trying to pair"); Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
// Polling the server while pairing causes the server to screw up if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
[_discMan stopDiscoveryBlocking]; Log(LOG_I, @"Already Paired");
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self]; [self alreadyPaired];
[_opQueue addOperation:pMan]; } else {
Log(LOG_I, @"Trying to pair");
// Polling the server while pairing causes the server to screw up
[_discMan stopDiscoveryBlocking];
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
[_opQueue addOperation:pMan];
}
} }
}); });
} }
- (void)hostLongClicked:(Host *)host view:(UIView *)view { - (void)hostLongClicked:(Host *)host view:(UIView *)view {
NSLog(@"Long clicked host: %@", host.name); Log(LOG_D, @"Long clicked host: %@", host.name);
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
if (host.online) { if (!host.online) {
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
[hMan executeRequestSynchronously:[hMan newUnpairRequest]];
});
}]];
} else {
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Wake" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ [longClickAlert addAction:[UIAlertAction actionWithTitle:@"Wake" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:@"Wake On Lan" message:@"" preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:@"Wake On Lan" message:@"" preferredStyle:UIAlertControllerStyleAlert];
[wolAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [wolAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
@@ -163,7 +296,7 @@ static StreamConfiguration* streamConfig;
// these two lines are required for iPad support of UIAlertSheet // these two lines are required for iPad support of UIAlertSheet
longClickAlert.popoverPresentationController.sourceView = view; longClickAlert.popoverPresentationController.sourceView = view;
longClickAlert.popoverPresentationController.sourceRect = CGRectMake(view.bounds.size.width / 2.0, view.bounds.size.height / 2.0, 1.0, 1.0); // center of the view longClickAlert.popoverPresentationController.sourceRect = CGRectMake(view.bounds.size.width / 2.0, view.bounds.size.height / 2.0, 1.0, 1.0); // center of the view
[self presentViewController:longClickAlert animated:YES completion:^{ [self presentViewController:longClickAlert animated:YES completion:^{
[self updateHosts]; [self updateHosts];
@@ -171,16 +304,17 @@ static StreamConfiguration* streamConfig;
} }
- (void) addHostClicked { - (void) addHostClicked {
NSLog(@"Clicked add host"); Log(LOG_D, @"Clicked add host");
[self showLoadingFrame];
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text; NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[_discMan discoverHost:hostAddress withCallback:^(Host* host){ [_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){
if (host != nil) { if (host != nil) {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
[dataMan saveHosts]; [dataMan saveData];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@synchronized(hostList) { @synchronized(hostList) {
[hostList addObject:host]; [hostList addObject:host];
@@ -188,7 +322,7 @@ static StreamConfiguration* streamConfig;
[self updateHosts]; [self updateHosts];
}); });
} else { } else {
UIAlertController* hostNotFoundAlert = [UIAlertController alertControllerWithTitle:@"Host Not Found" message:[NSString stringWithFormat:@"Unable to connect to host: \n%@", hostAddress] preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* hostNotFoundAlert = [UIAlertController alertControllerWithTitle:@"Add Host" message:error preferredStyle:UIAlertControllerStyleAlert];
[hostNotFoundAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]]; [hostNotFoundAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:hostNotFoundAlert animated:YES completion:nil]; [self presentViewController:hostNotFoundAlert animated:YES completion:nil];
@@ -197,59 +331,89 @@ static StreamConfiguration* streamConfig;
}];}); }];});
}]]; }]];
[alertController addTextFieldWithConfigurationHandler:nil]; [alertController addTextFieldWithConfigurationHandler:nil];
[self hideLoadingFrame];
[self presentViewController:alertController animated:YES completion:nil]; [self presentViewController:alertController animated:YES completion:nil];
} }
- (void) appClicked:(App *)app { - (void) appClicked:(App *)app {
NSLog(@"Clicked app: %@", app.appName); Log(LOG_D, @"Clicked app: %@", app.name);
streamConfig = [[StreamConfiguration alloc] init]; _streamConfig = [[StreamConfiguration alloc] init];
streamConfig.host = _selectedHost.address; _streamConfig.host = app.host.activeAddress;
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.address]; _streamConfig.appID = app.id;
streamConfig.appID = app.appId;
if (streamConfig.hostAddr == 0) {
[self displayDnsFailedDialog];
return;
}
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
Settings* streamSettings = [dataMan retrieveSettings]; Settings* streamSettings = [dataMan retrieveSettings];
streamConfig.frameRate = [streamSettings.framerate intValue]; _streamConfig.frameRate = [streamSettings.framerate intValue];
streamConfig.bitRate = [streamSettings.bitrate intValue]; _streamConfig.bitRate = [streamSettings.bitrate intValue];
streamConfig.height = [streamSettings.height intValue]; _streamConfig.height = [streamSettings.height intValue];
streamConfig.width = [streamSettings.width intValue]; _streamConfig.width = [streamSettings.width intValue];
[_appManager stopRetrieving];
if (currentPosition != FrontViewPositionLeft) { if (currentPosition != FrontViewPositionLeft) {
[[self revealViewController] revealToggle:self]; [[self revealViewController] revealToggle:self];
} }
App* currentApp = [self findRunningApp]; App* currentApp = [self findRunningApp:app.host];
if (currentApp != nil) { if (currentApp != nil) {
UIAlertController* alertController = [UIAlertController UIAlertController* alertController = [UIAlertController
alertControllerWithTitle: app.appName alertControllerWithTitle: app.name
message: [app.appId isEqualToString:currentApp.appId] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.appName]preferredStyle:UIAlertControllerStyleAlert]; message: [app.id isEqualToString:currentApp.id] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.name]preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction [alertController addAction:[UIAlertAction
actionWithTitle:[app.appId isEqualToString:currentApp.appId] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ actionWithTitle:[app.id isEqualToString:currentApp.id] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
NSLog(@"Resuming application: %@", currentApp.appName); Log(LOG_I, @"Resuming application: %@", currentApp.name);
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil]; [self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
}]]; }]];
[alertController addAction:[UIAlertAction actionWithTitle: [alertController addAction:[UIAlertAction actionWithTitle:
[app.appId isEqualToString:currentApp.appId] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){ [app.id isEqualToString:currentApp.id] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
NSLog(@"Quitting application: %@", currentApp.appName); Log(LOG_I, @"Quitting application: %@", currentApp.name);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:app.host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
[hMan executeRequestSynchronously:[hMan newQuitAppRequest]]; HttpResponse* quitResponse = [[HttpResponse alloc] init];
// TODO: handle failure to quit app HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]];
currentApp.isRunning = NO;
// Exempt this host from discovery while handling the quit operation
if (![app.appId isEqualToString:currentApp.appId]) { [_discMan removeHostFromDiscovery:app.host];
dispatch_async(dispatch_get_main_queue(), ^{ [hMan executeRequestSynchronously:quitRequest];
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil]; [_discMan addHostToDiscovery:app.host];
});
} UIAlertController* alert;
});
}]]; // If it fails, display an error and stop the current operation
if (quitResponse.statusCode != 200) {
alert = [UIAlertController alertControllerWithTitle:@"Quitting App Failed"
message:@"Failed to quit app. If this app was started by "
"another device, you'll need to quit from that device."
preferredStyle:UIAlertControllerStyleAlert];
}
// If it succeeds and we're to start streaming, segue to the stream and return
else if (![app.id isEqualToString:currentApp.id]) {
currentApp.isRunning = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self updateAppsForHost:app.host];
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
});
return;
}
// Otherwise, display a dialog to notify the user that the app was quit
else {
currentApp.isRunning = NO;
alert = [UIAlertController alertControllerWithTitle:@"Quitting App"
message:@"The app was quit successfully."
preferredStyle:UIAlertControllerStyleAlert];
}
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateAppsForHost:app.host];
[self presentViewController:alert animated:YES completion:nil];
});
});
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertController animated:YES completion:nil]; [self presentViewController:alertController animated:YES completion:nil];
} else { } else {
@@ -257,9 +421,8 @@ static StreamConfiguration* streamConfig;
} }
} }
- (App*) findRunningApp:(Host*)host {
- (App*) findRunningApp { for (App* app in host.appList) {
for (App* app in appList) {
if (app.isRunning) { if (app.isRunning) {
return app; return app;
} }
@@ -275,14 +438,31 @@ static StreamConfiguration* streamConfig;
currentPosition = position; currentPosition = position;
} }
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController isKindOfClass:[StreamFrameViewController class]]) {
StreamFrameViewController* streamFrame = segue.destinationViewController;
streamFrame.streamConfig = _streamConfig;
}
}
- (void) showLoadingFrame {
LoadingFrameViewController* loadingFrame = [self.storyboard instantiateViewControllerWithIdentifier:@"loadingFrame"];
[self.navigationController presentViewController:loadingFrame animated:YES completion:nil];
}
- (void) hideLoadingFrame {
[self dismissViewControllerAnimated:YES completion:nil];
[self enableNavigation];
}
- (void)viewDidLoad - (void)viewDidLoad
{ {
[super viewDidLoad]; [super viewDidLoad];
// Set the side bar button action. When it's tapped, it'll show up the sidebar. // Set the side bar button action. When it's tapped, it'll show the sidebar.
[_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown]; [_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
// Set the host name button action. When it's tapped, it'll show up the host selection view. // Set the host name button action. When it's tapped, it'll show the host selection view.
[_computerNameButton setTarget:self]; [_computerNameButton setTarget:self];
[_computerNameButton setAction:@selector(showHostSelectionView)]; [_computerNameButton setAction:@selector(showHostSelectionView)];
@@ -296,12 +476,12 @@ static StreamConfiguration* streamConfig;
currentPosition = FrontViewPositionLeft; currentPosition = FrontViewPositionLeft;
// Set up crypto // Set up crypto
_opQueue = [[NSOperationQueue alloc] init];
[CryptoManager generateKeyPairUsingSSl]; [CryptoManager generateKeyPairUsingSSl];
_uniqueId = [CryptoManager getUniqueID]; _uniqueId = [CryptoManager getUniqueID];
_cert = [CryptoManager readCertFromFile]; _cert = [CryptoManager readCertFromFile];
_appManager = [[AppManager alloc] initWithCallback:self]; _appManager = [[AppAssetManager alloc] initWithCallback:self];
_opQueue = [[NSOperationQueue alloc] init];
// Only initialize the host picker list once // Only initialize the host picker list once
if (hostList == nil) { if (hostList == nil) {
@@ -335,7 +515,7 @@ static StreamConfiguration* streamConfig;
// This will refresh the applist // This will refresh the applist
if (_selectedHost != nil) { if (_selectedHost != nil) {
[self hostClicked:_selectedHost]; [self hostClicked:_selectedHost view:nil];
} }
} }
@@ -344,9 +524,9 @@ static StreamConfiguration* streamConfig;
[super viewDidDisappear:animated]; [super viewDidDisappear:animated];
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished // when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
[_discMan stopDiscovery]; [_discMan stopDiscovery];
// In case the host objects were updated in the background // In case the host objects were updated in the background
[[[DataManager alloc] init] saveHosts]; [[[DataManager alloc] init] saveData];
} }
- (void) retrieveSavedHosts { - (void) retrieveSavedHosts {
@@ -354,14 +534,27 @@ static StreamConfiguration* streamConfig;
NSArray* hosts = [dataMan retrieveHosts]; NSArray* hosts = [dataMan retrieveHosts];
@synchronized(hostList) { @synchronized(hostList) {
[hostList addObjectsFromArray:hosts]; [hostList addObjectsFromArray:hosts];
// Initialize the non-persistent host state
for (Host* host in hostList) {
if (host.activeAddress == nil) {
host.activeAddress = host.localAddress;
}
if (host.activeAddress == nil) {
host.activeAddress = host.externalAddress;
}
if (host.activeAddress == nil) {
host.activeAddress = host.address;
}
}
} }
} }
- (void) updateAllHosts:(NSArray *)hosts { - (void) updateAllHosts:(NSArray *)hosts {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"New host list:"); Log(LOG_D, @"New host list:");
for (Host* host in hosts) { for (Host* host in hosts) {
NSLog(@"Host: \n{\n\t name:%@ \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, @"Host: \n{\n\t name:%@ \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);
} }
@synchronized(hostList) { @synchronized(hostList) {
[hostList removeAllObjects]; [hostList removeAllObjects];
@@ -372,7 +565,7 @@ static StreamConfiguration* streamConfig;
} }
- (void)updateHosts { - (void)updateHosts {
NSLog(@"Updating hosts..."); Log(LOG_I, @"Updating hosts...");
[[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; [[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self]; UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
UIComputerView* compView; UIComputerView* compView;
@@ -400,7 +593,15 @@ static StreamConfiguration* streamConfig;
} }
} }
- (void) updateApps { - (void) updateAppsForHost:(Host*)host {
if (host != _selectedHost) {
Log(LOG_W, @"Mismatched host during app update");
return;
}
_sortedAppList = [host.appList allObjects];
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
[hostScrollView removeFromSuperview]; [hostScrollView removeFromSuperview];
[self.collectionView reloadData]; [self.collectionView reloadData];
} }
@@ -408,7 +609,7 @@ static StreamConfiguration* streamConfig;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath]; UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
App* app = appList[indexPath.row]; App* app = _sortedAppList[indexPath.row];
UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self]; UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self];
[appView updateAppImage]; [appView updateAppImage];
@@ -429,7 +630,12 @@ static StreamConfiguration* streamConfig;
} }
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return appList.count; if (_selectedHost != nil) {
return _selectedHost.appList.count;
}
else {
return 0;
}
} }
- (void)didReceiveMemoryWarning - (void)didReceiveMemoryWarning
@@ -450,4 +656,13 @@ static StreamConfiguration* streamConfig;
- (BOOL)shouldAutorotate { - (BOOL)shouldAutorotate {
return YES; return YES;
} }
- (void) disableNavigation {
self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = NO;
}
- (void) enableNavigation {
self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = YES;
}
@end @end
@@ -554,8 +554,8 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1
UITouch *touch = [touches anyObject]; UITouch *touch = [touches anyObject];
CGPoint nowPoint = [touch locationInView:self.view]; CGPoint nowPoint = [touch locationInView:self.view];
if (abs(nowPoint.x - _beginPoint.x) > kDirectionPanThreshold) _dragging = YES; if (fabs(nowPoint.x - _beginPoint.x) > kDirectionPanThreshold) _dragging = YES;
else if (abs(nowPoint.y - _beginPoint.y) > kDirectionPanThreshold) self.state = UIGestureRecognizerStateFailed; else if (fabs(nowPoint.y - _beginPoint.y) > kDirectionPanThreshold) self.state = UIGestureRecognizerStateFailed;
} }
@end @end
@@ -742,15 +742,6 @@ const int FrontViewPositionNone = 0xff;
_userInteractionStore = _contentView.userInteractionEnabled; _userInteractionStore = _contentView.userInteractionEnabled;
} }
- (NSUInteger)supportedInterfaceOrientations
{
// we could have simply not implemented this, but we choose to call super to make explicit that we
// want the default behavior.
return [super supportedInterfaceOrientations];
}
#pragma mark - Public methods and property accessors #pragma mark - Public methods and property accessors
- (void)setFrontViewController:(UIViewController *)frontViewController - (void)setFrontViewController:(UIViewController *)frontViewController
@@ -1140,7 +1131,7 @@ const int FrontViewPositionNone = 0xff;
// forbid gesture if the initial translation is not horizontal // forbid gesture if the initial translation is not horizontal
UIView *recognizerView = _panGestureRecognizer.view; UIView *recognizerView = _panGestureRecognizer.view;
CGPoint translation = [_panGestureRecognizer translationInView:recognizerView]; CGPoint translation = [_panGestureRecognizer translationInView:recognizerView];
// NSLog( @"translation:%@", NSStringFromCGPoint(translation) ); // Log(LOG_D, @"translation:%@", NSStringFromCGPoint(translation) );
// if ( fabs(translation.y/translation.x) > 1 ) // if ( fabs(translation.y/translation.x) > 1 )
// return NO; // return NO;
@@ -1252,7 +1243,7 @@ const int FrontViewPositionNone = 0xff;
CGFloat xLocation = frontView.frame.origin.x; CGFloat xLocation = frontView.frame.origin.x;
CGFloat velocity = [recognizer velocityInView:_contentView].x; CGFloat velocity = [recognizer velocityInView:_contentView].x;
//NSLog( @"Velocity:%1.4f", velocity); //Log(LOG_D, @"Velocity:%1.4f", velocity);
// depending on position we compute a simetric replacement of widths and positions // depending on position we compute a simetric replacement of widths and positions
int symetry = xLocation<0 ? -1 : 1; int symetry = xLocation<0 ? -1 : 1;
@@ -1274,7 +1265,7 @@ const int FrontViewPositionNone = 0xff;
NSTimeInterval duration = _toggleAnimationDuration; NSTimeInterval duration = _toggleAnimationDuration;
// Velocity driven change: // Velocity driven change:
if (fabsf(velocity) > _quickFlickVelocity) if (fabs(velocity) > _quickFlickVelocity)
{ {
// we may need to set the drag position and to adjust the animation duration // we may need to set the drag position and to adjust the animation duration
CGFloat journey = xLocation; CGFloat journey = xLocation;
@@ -1292,7 +1283,7 @@ const int FrontViewPositionNone = 0xff;
} }
} }
duration = fabsf(journey/velocity); duration = fabs(journey/velocity);
} }
// Position driven change: // Position driven change:
@@ -1349,7 +1340,7 @@ const int FrontViewPositionNone = 0xff;
NSTimeInterval duration = animated?_toggleAnimationDuration:0.0; NSTimeInterval duration = animated?_toggleAnimationDuration:0.0;
NSTimeInterval firstDuration = duration; NSTimeInterval firstDuration = duration;
int initialPosDif = abs( _frontViewPosition - preReplacementPosition ); int initialPosDif = (int) labs( _frontViewPosition - preReplacementPosition );
if ( initialPosDif == 1 ) firstDuration *= 0.8; if ( initialPosDif == 1 ) firstDuration *= 0.8;
else if ( initialPosDif == 0 ) firstDuration = 0; else if ( initialPosDif == 0 ) firstDuration = 0;
@@ -1,9 +1,9 @@
// //
// SettingsViewController.h // SettingsViewController.h
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/27/14. // Created by Diego Waxemberg on 10/27/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@@ -1,21 +1,21 @@
// //
// SettingsViewController.m // SettingsViewController.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 10/27/14. // Created by Diego Waxemberg on 10/27/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import "SettingsViewController.h" #import "SettingsViewController.h"
#import "Settings.h" #import "Settings.h"
#import "DataManager.h" #import "DataManager.h"
#define BITRATE_INTERVAL 1 #define BITRATE_INTERVAL 500 // in kbps
@implementation SettingsViewController { @implementation SettingsViewController {
NSInteger _bitrate; NSInteger _bitrate;
} }
static NSString* bitrateFormat = @"Bitrate: %d Mbps"; static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
- (void)viewDidLoad { - (void)viewDidLoad {
@@ -25,7 +25,7 @@ static NSString* bitrateFormat = @"Bitrate: %d Mbps";
Settings* currentSettings = [dataMan retrieveSettings]; Settings* currentSettings = [dataMan retrieveSettings];
// Bitrate is persisted in kbps // Bitrate is persisted in kbps
_bitrate = [currentSettings.bitrate integerValue] / 1000; _bitrate = [currentSettings.bitrate integerValue];
NSInteger framerate = [currentSettings.framerate integerValue] == 30 ? 0 : 1; NSInteger framerate = [currentSettings.framerate integerValue] == 30 ? 0 : 1;
NSInteger resolution; NSInteger resolution;
if ([currentSettings.height integerValue] == 720) { if ([currentSettings.height integerValue] == 720) {
@@ -40,16 +40,20 @@ static NSString* bitrateFormat = @"Bitrate: %d Mbps";
[self.resolutionSelector setSelectedSegmentIndex:resolution]; [self.resolutionSelector setSelectedSegmentIndex:resolution];
[self.framerateSelector setSelectedSegmentIndex:framerate]; [self.framerateSelector setSelectedSegmentIndex:framerate];
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls]; [self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
[self.bitrateSlider setValue:_bitrate animated:YES]; [self.bitrateSlider setValue:(_bitrate / BITRATE_INTERVAL) animated:YES];
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged]; [self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]]; [self updateBitrateText];
} }
- (void) bitrateSliderMoved { - (void) bitrateSliderMoved {
_bitrate = BITRATE_INTERVAL * floor((self.bitrateSlider.value/BITRATE_INTERVAL)+0.5); _bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]]; [self updateBitrateText];
} }
- (void) updateBitrateText {
// Display bitrate in Mbps
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
}
- (void) saveSettings { - (void) saveSettings {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
@@ -1,17 +1,20 @@
// //
// StreamFrameViewController.h // StreamFrameViewController.h
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/18/14. // Created by Diego Waxemberg on 1/18/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "Connection.h" #import "Connection.h"
#import "StreamConfiguration.h"
#import "StreamView.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks> @interface StreamFrameViewController : UIViewController <ConnectionCallbacks, EdgeDetectionDelegate>
@property (strong, nonatomic) IBOutlet UILabel *stageLabel; @property (strong, nonatomic) IBOutlet UILabel *stageLabel;
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner; @property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
@property (nonatomic) StreamConfiguration* streamConfig;
@end @end
@@ -1,9 +1,9 @@
// //
// StreamFrameViewController.m // StreamFrameViewController.m
// Limelight-iOS // Moonlight
// //
// Created by Diego Waxemberg on 1/18/14. // Created by Diego Waxemberg on 1/18/14.
// Copyright (c) 2014 Diego Waxemberg. All rights reserved. // Copyright (c) 2015 Moonlight Stream. All rights reserved.
// //
#import "StreamFrameViewController.h" #import "StreamFrameViewController.h"
@@ -11,7 +11,6 @@
#import "VideoDecoderRenderer.h" #import "VideoDecoderRenderer.h"
#import "StreamManager.h" #import "StreamManager.h"
#import "ControllerSupport.h" #import "ControllerSupport.h"
#import "StreamView.h"
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@@ -36,7 +35,7 @@
_controllerSupport = [[ControllerSupport alloc] init]; _controllerSupport = [[ControllerSupport alloc] init];
_streamMan = [[StreamManager alloc] initWithConfig:[MainFrameViewController getStreamConfiguration] _streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig
renderView:self.view renderView:self.view
connectionCallbacks:self]; connectionCallbacks:self];
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init]; NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
@@ -49,6 +48,7 @@
} }
- (void) returnToMainFrame { - (void) returnToMainFrame {
[_controllerSupport cleanup];
[self.navigationController popToRootViewControllerAnimated:YES]; [self.navigationController popToRootViewControllerAnimated:YES];
} }
@@ -58,30 +58,23 @@
} }
- (void)edgeSwiped { - (void)edgeSwiped {
NSLog(@"User swiped to end stream"); Log(LOG_D, @"User swiped to end stream");
[_streamMan stopStream]; [_streamMan stopStream];
[self returnToMainFrame]; [self returnToMainFrame];
} }
- (void) connectionStarted { - (void) connectionStarted {
NSLog(@"Connection started"); Log(LOG_I, @"Connection started");
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.spinner stopAnimating]; [self.spinner stopAnimating];
[self.stageLabel setText:@"Waiting for first frame..."]; [self.stageLabel setText:@"Waiting for first frame..."];
[self.stageLabel sizeToFit]; [self.stageLabel sizeToFit];
[(StreamView*)self.view setupOnScreenControls: _controllerSupport]; [(StreamView*)self.view setupOnScreenControls: _controllerSupport swipeDelegate:self];
UIScreenEdgePanGestureRecognizer* swipeGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)];
swipeGesture.edges = UIRectEdgeLeft;
if (swipeGesture == nil) {
NSLog(@"An error occured trying to create UIScreenEdgePanGestureRecognizer");
} else {
[self.view addGestureRecognizer:swipeGesture];
}
}); });
} }
- (void)connectionTerminated:(long)errorCode { - (void)connectionTerminated:(long)errorCode {
NSLog(@"Connection terminated: %ld", errorCode); Log(LOG_I, @"Connection terminated: %ld", errorCode);
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection was terminated" preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection was terminated" preferredStyle:UIAlertControllerStyleAlert];
@@ -95,7 +88,7 @@
} }
- (void) stageStarting:(char*)stageName { - (void) stageStarting:(char*)stageName {
NSLog(@"Starting %s", stageName); Log(LOG_I, @"Starting %s", stageName);
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName]; NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]]; NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
@@ -109,32 +102,40 @@
} }
- (void) stageFailed:(char*)stageName withError:(long)errorCode { - (void) stageFailed:(char*)stageName withError:(long)errorCode {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed" Log(LOG_I, @"Stage %s failed: %ld", stageName, errorCode);
message:[NSString stringWithFormat:@"%s failed with error %ld",
stageName, errorCode] dispatch_async(dispatch_get_main_queue(), ^{
preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){ message:[NSString stringWithFormat:@"%s failed with error %ld",
[self returnToMainFrame]; stageName, errorCode]
}]]; preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil]; [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
[self returnToMainFrame];
}]];
[self presentViewController:alert animated:YES completion:nil];
});
} }
- (void) launchFailed:(NSString*)message { - (void) launchFailed:(NSString*)message {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed" Log(LOG_I, @"Launch failed: %@", message);
message:message
preferredStyle:UIAlertControllerStyleAlert]; dispatch_async(dispatch_get_main_queue(), ^{
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){ UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
[self returnToMainFrame]; message:message
}]]; preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil]; [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
[self returnToMainFrame];
}]];
[self presentViewController:alert animated:YES completion:nil];
});
} }
- (void) displayMessage:(char*)message { - (void) displayMessage:(char*)message {
NSLog(@"Display message: %s", message); Log(LOG_I, @"Display message: %s", message);
} }
- (void) displayTransientMessage:(char*)message { - (void) displayTransientMessage:(char*)message {
NSLog(@"Display transient message: %s", message); Log(LOG_I, @"Display transient message: %s", message);
} }
- (void)didReceiveMemoryWarning - (void)didReceiveMemoryWarning
+2 -2
View File
@@ -1,9 +1,9 @@
// //
// main.m // main.m
// Limelight // Moonlight
// //
// Created by Diego Waxemberg on 8/30/14. // Created by Diego Waxemberg on 8/30/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved. // Copyright (c) 2014 Moonlight Stream. All rights reserved.
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
-22
View File
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.limelight-stream.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
-34
View File
@@ -1,34 +0,0 @@
//
// LimelightTests.m
// LimelightTests
//
// Created by Diego Waxemberg on 8/30/14.
// Copyright (c) 2014 Limelight Stream. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface LimelightTests : XCTestCase
@end
@implementation LimelightTests
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample
{
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
}
@end
@@ -1,2 +0,0 @@
/* Localized versions of Info.plist keys */
@@ -7,7 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
98A03B4D19F352EB00861ACA /* liblimelight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98A03B4A19F3514B00861ACA /* liblimelight-common.a */; }; 987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */; };
9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; }; 9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; };
9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; }; 9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; };
9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; }; 9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; };
@@ -24,11 +24,6 @@
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0319B2C406004C83CF /* AppDelegate.m */; }; FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0319B2C406004C83CF /* AppDelegate.m */; };
FB290D0719B2C406004C83CF /* Limelight.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */; }; FB290D0719B2C406004C83CF /* Limelight.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */; };
FB290D0919B2C406004C83CF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FB290D0819B2C406004C83CF /* Images.xcassets */; }; FB290D0919B2C406004C83CF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FB290D0819B2C406004C83CF /* Images.xcassets */; };
FB290D1119B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
FB290D1219B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
FB290D1319B2C406004C83CF /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF719B2C406004C83CF /* CoreData.framework */; };
FB290D1B19B2C406004C83CF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FB290D1919B2C406004C83CF /* InfoPlist.strings */; };
FB290D1D19B2C406004C83CF /* LimelightTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D1C19B2C406004C83CF /* LimelightTests.m */; };
FB290DB719B2C870004C83CF /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB619B2C870004C83CF /* libz.dylib */; }; FB290DB719B2C870004C83CF /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB619B2C870004C83CF /* libz.dylib */; };
FB290DB919B2C877004C83CF /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB819B2C877004C83CF /* libbz2.dylib */; }; FB290DB919B2C877004C83CF /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB819B2C877004C83CF /* libbz2.dylib */; };
FB290DC419B2E98F004C83CF /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DC319B2E98F004C83CF /* libxml2.dylib */; }; FB290DC419B2E98F004C83CF /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DC319B2E98F004C83CF /* libxml2.dylib */; };
@@ -38,6 +33,7 @@
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678F91A55FFAD00377732 /* DiscoveryManager.m */; }; FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678F91A55FFAD00377732 /* DiscoveryManager.m */; };
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; }; FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; }; FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; }; FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; }; FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; }; FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
@@ -58,43 +54,44 @@
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E019F6AFB800339C8A /* libcrypto.a */; }; FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E019F6AFB800339C8A /* libcrypto.a */; };
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E119F6AFB800339C8A /* libssl.a */; }; FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E119F6AFB800339C8A /* libssl.a */; };
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; }; FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; };
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppManager.m */; }; FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD271A7C84ED00872C98 /* HttpResponse.m */; };
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */; };
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD361A7E02DB00872C98 /* HttpRequest.m */; };
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; };
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; };
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; };
FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD421A7F0C6900872C98 /* Controller.m */; };
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD1C8E11A8AD71400C6703C /* Logger.m */; };
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; };
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; }; FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; }; FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
FBD3495B1A004411002D2A60 /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495A1A004411002D2A60 /* Host.m */; };
FBD3495E1A004412002D2A60 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495D1A004412002D2A60 /* Settings.m */; }; FBD3495E1A004412002D2A60 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495D1A004412002D2A60 /* Settings.m */; };
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; }; FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; };
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; }; FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; };
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; }; FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; };
FBDE86E919F82315001C18A8 /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E819F82315001C18A8 /* App.m */; }; FBFCB3311B50B29400089F8A /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBFCB3301B50B29400089F8A /* Host.m */; };
FBFCB3351B50B29400089F8A /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = FBFCB3341B50B29400089F8A /* App.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
98A03B4919F3514B00861ACA /* PBXContainerItemProxy */ = { 987140011B04541A00AB57D5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 98A03B4519F3514B00861ACA /* limelight-common.xcodeproj */; containerPortal = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
remoteInfo = "limelight-common";
};
98A03B4B19F3517100861ACA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 98A03B4519F3514B00861ACA /* limelight-common.xcodeproj */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = FB290E2D19B37A4E004C83CF; remoteGlobalIDString = FB290E2D19B37A4E004C83CF;
remoteInfo = "limelight-common"; remoteInfo = "moonlight-common";
}; };
FB290D1419B2C406004C83CF /* PBXContainerItemProxy */ = { FB1E430F1AE8B0F200AFF679 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = FB290CE619B2C406004C83CF /* Project object */; containerPortal = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
proxyType = 1; proxyType = 2;
remoteGlobalIDString = FB290CED19B2C406004C83CF; remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
remoteInfo = Limelight; remoteInfo = "moonlight-common";
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
98A03B4519F3514B00861ACA /* limelight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "limelight-common.xcodeproj"; path = "limelight-common-c/limelight-common.xcodeproj"; sourceTree = "<group>"; }; 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "limelight-common-c/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; }; 9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; };
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; }; 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; }; 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
@@ -102,7 +99,7 @@
9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; }; 9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; }; 9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; }; 9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; };
FB290CEE19B2C406004C83CF /* Limelight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Limelight.app; sourceTree = BUILT_PRODUCTS_DIR; }; FB290CEE19B2C406004C83CF /* Moonlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Moonlight.app; sourceTree = BUILT_PRODUCTS_DIR; };
FB290CF119B2C406004C83CF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; FB290CF119B2C406004C83CF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
FB290CF519B2C406004C83CF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; FB290CF519B2C406004C83CF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
@@ -115,10 +112,6 @@
FB290D0319B2C406004C83CF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; FB290D0319B2C406004C83CF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Limelight.xcdatamodel; sourceTree = "<group>"; }; FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Limelight.xcdatamodel; sourceTree = "<group>"; };
FB290D0819B2C406004C83CF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; }; FB290D0819B2C406004C83CF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
FB290D0E19B2C406004C83CF /* LimelightTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LimelightTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
FB290D1819B2C406004C83CF /* LimelightTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LimelightTests-Info.plist"; sourceTree = "<group>"; };
FB290D1A19B2C406004C83CF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
FB290D1C19B2C406004C83CF /* LimelightTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LimelightTests.m; sourceTree = "<group>"; };
FB290DB619B2C870004C83CF /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; FB290DB619B2C870004C83CF /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
FB290DB819B2C877004C83CF /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; }; FB290DB819B2C877004C83CF /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
FB290DC319B2E98F004C83CF /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; FB290DC319B2E98F004C83CF /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
@@ -132,9 +125,12 @@
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnLanManager.h; sourceTree = "<group>"; }; FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnLanManager.h; sourceTree = "<group>"; };
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WakeOnLanManager.m; sourceTree = "<group>"; }; FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WakeOnLanManager.m; sourceTree = "<group>"; };
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingFrameViewController.h; sourceTree = "<group>"; };
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingFrameViewController.m; sourceTree = "<group>"; };
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; }; FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; }; FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; }; FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
FB6DDEF31AE739100096499A /* libmoonlight-common.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmoonlight-common.a"; path = "limelight-common-c/build/Debug-iphoneos/libmoonlight-common.a"; sourceTree = "<group>"; };
FB7E794319C8B71B00A15F68 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; }; FB7E794319C8B71B00A15F68 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = usr/lib/libiconv.dylib; sourceTree = SDKROOT; };
FB89460519F646E200339C8A /* CryptoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoManager.h; sourceTree = "<group>"; }; FB89460519F646E200339C8A /* CryptoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoManager.h; sourceTree = "<group>"; };
FB89460619F646E200339C8A /* CryptoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CryptoManager.m; sourceTree = "<group>"; }; FB89460619F646E200339C8A /* CryptoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CryptoManager.m; sourceTree = "<group>"; };
@@ -247,15 +243,30 @@
FB8946E719F6AFB800339C8A /* opus_multistream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_multistream.h; sourceTree = "<group>"; }; FB8946E719F6AFB800339C8A /* opus_multistream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_multistream.h; sourceTree = "<group>"; };
FB8946E819F6AFB800339C8A /* opus_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_types.h; sourceTree = "<group>"; }; FB8946E819F6AFB800339C8A /* opus_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_types.h; sourceTree = "<group>"; };
FB8946EA19F6AFB800339C8A /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libopus.a; sourceTree = "<group>"; }; FB8946EA19F6AFB800339C8A /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libopus.a; sourceTree = "<group>"; };
FBD3494119FC9C04002D2A60 /* AppManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppManager.h; sourceTree = "<group>"; }; FB9AFD261A7C84ED00872C98 /* HttpResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpResponse.h; sourceTree = "<group>"; };
FBD3494219FC9C04002D2A60 /* AppManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppManager.m; sourceTree = "<group>"; }; FB9AFD271A7C84ED00872C98 /* HttpResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpResponse.m; sourceTree = "<group>"; };
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetRetriever.h; sourceTree = "<group>"; };
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetRetriever.m; sourceTree = "<group>"; };
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = "<group>"; };
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = "<group>"; };
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfoResponse.h; sourceTree = "<group>"; };
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerInfoResponse.m; sourceTree = "<group>"; };
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetResponse.h; sourceTree = "<group>"; };
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.0.xcdatamodel"; sourceTree = "<group>"; };
FBD1C8E01A8AD69E00C6703C /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = "<group>"; };
FBD1C8E11A8AD71400C6703C /* Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logger.m; sourceTree = "<group>"; };
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = "<group>"; };
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; }; FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; }; FBD3494F19FF2174002D2A60 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; }; FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = "<group>"; }; FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = "<group>"; };
FBD349571A003F05002D2A60 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; FBD349571A003F05002D2A60 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
FBD349591A004411002D2A60 /* Host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Host.h; path = Database/Host.h; sourceTree = "<group>"; };
FBD3495A1A004411002D2A60 /* Host.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Host.m; path = Database/Host.m; sourceTree = "<group>"; };
FBD3495C1A004412002D2A60 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Settings.h; path = Database/Settings.h; sourceTree = "<group>"; }; FBD3495C1A004412002D2A60 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Settings.h; path = Database/Settings.h; sourceTree = "<group>"; };
FBD3495D1A004412002D2A60 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Settings.m; path = Database/Settings.m; sourceTree = "<group>"; }; FBD3495D1A004412002D2A60 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Settings.m; path = Database/Settings.m; sourceTree = "<group>"; };
FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = "<group>"; }; FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = "<group>"; };
@@ -264,8 +275,12 @@
FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = "<group>"; }; FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = "<group>"; };
FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = "<group>"; }; FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = "<group>"; };
FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = "<group>"; }; FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = "<group>"; };
FBDE86E719F82315001C18A8 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = ../App.h; sourceTree = "<group>"; }; FBFCB32E1B50B29400089F8A /* Host+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Host+CoreDataProperties.h"; path = "Database/Host+CoreDataProperties.h"; sourceTree = "<group>"; };
FBDE86E819F82315001C18A8 /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = App.m; path = ../App.m; sourceTree = "<group>"; }; FBFCB32F1B50B29400089F8A /* Host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Host.h; path = Database/Host.h; sourceTree = "<group>"; };
FBFCB3301B50B29400089F8A /* Host.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Host.m; path = Database/Host.m; sourceTree = "<group>"; };
FBFCB3321B50B29400089F8A /* App+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "App+CoreDataProperties.h"; path = "Database/App+CoreDataProperties.h"; sourceTree = "<group>"; };
FBFCB3331B50B29400089F8A /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = Database/App.h; sourceTree = "<group>"; };
FBFCB3341B50B29400089F8A /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = App.m; path = Database/App.m; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -273,7 +288,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
98A03B4D19F352EB00861ACA /* liblimelight-common.a in Frameworks */, 987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */,
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */, FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */,
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */, FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */,
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */, FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */,
@@ -289,27 +304,9 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
FB290D0B19B2C406004C83CF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FB290D1319B2C406004C83CF /* CoreData.framework in Frameworks */,
FB290D1219B2C406004C83CF /* UIKit.framework in Frameworks */,
FB290D1119B2C406004C83CF /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
98A03B4619F3514B00861ACA /* Products */ = {
isa = PBXGroup;
children = (
98A03B4A19F3514B00861ACA /* liblimelight-common.a */,
);
name = Products;
sourceTree = "<group>";
};
9E5D5FF61A5A5A3900689918 /* Font */ = { 9E5D5FF61A5A5A3900689918 /* Font */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -332,12 +329,19 @@
path = Roboto; path = Roboto;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB1E430C1AE8B0F200AFF679 /* Products */ = {
isa = PBXGroup;
children = (
FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */,
);
name = Products;
sourceTree = "<group>";
};
FB290CE519B2C406004C83CF = { FB290CE519B2C406004C83CF = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
98A03B4519F3514B00861ACA /* limelight-common.xcodeproj */, 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */,
FB290CF919B2C406004C83CF /* Limelight */, FB290CF919B2C406004C83CF /* Limelight */,
FB290D1619B2C406004C83CF /* LimelightTests */,
FB290CF019B2C406004C83CF /* Frameworks */, FB290CF019B2C406004C83CF /* Frameworks */,
FB290CEF19B2C406004C83CF /* Products */, FB290CEF19B2C406004C83CF /* Products */,
); );
@@ -346,8 +350,7 @@
FB290CEF19B2C406004C83CF /* Products */ = { FB290CEF19B2C406004C83CF /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FB290CEE19B2C406004C83CF /* Limelight.app */, FB290CEE19B2C406004C83CF /* Moonlight.app */,
FB290D0E19B2C406004C83CF /* LimelightTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -355,6 +358,7 @@
FB290CF019B2C406004C83CF /* Frameworks */ = { FB290CF019B2C406004C83CF /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FB6DDEF31AE739100096499A /* libmoonlight-common.a */,
FB4679001A57048000377732 /* CoreFoundation.framework */, FB4679001A57048000377732 /* CoreFoundation.framework */,
FBD349571A003F05002D2A60 /* libsqlite3.dylib */, FBD349571A003F05002D2A60 /* libsqlite3.dylib */,
FB89468F19F6AFB800339C8A /* libs */, FB89468F19F6AFB800339C8A /* libs */,
@@ -408,24 +412,6 @@
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB290D1619B2C406004C83CF /* LimelightTests */ = {
isa = PBXGroup;
children = (
FB290D1C19B2C406004C83CF /* LimelightTests.m */,
FB290D1719B2C406004C83CF /* Supporting Files */,
);
path = LimelightTests;
sourceTree = "<group>";
};
FB290D1719B2C406004C83CF /* Supporting Files */ = {
isa = PBXGroup;
children = (
FB290D1819B2C406004C83CF /* LimelightTests-Info.plist */,
FB290D1919B2C406004C83CF /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
FB89460419F646E200339C8A /* Crypto */ = { FB89460419F646E200339C8A /* Crypto */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -442,6 +428,8 @@
children = ( children = (
FB89460A19F646E200339C8A /* ControllerSupport.h */, FB89460A19F646E200339C8A /* ControllerSupport.h */,
FB89460B19F646E200339C8A /* ControllerSupport.m */, FB89460B19F646E200339C8A /* ControllerSupport.m */,
FB9AFD411A7F0C6900872C98 /* Controller.h */,
FB9AFD421A7F0C6900872C98 /* Controller.m */,
FB89460C19F646E200339C8A /* StreamView.h */, FB89460C19F646E200339C8A /* StreamView.h */,
FB89460D19F646E200339C8A /* StreamView.m */, FB89460D19F646E200339C8A /* StreamView.m */,
FB4678EB1A50C40900377732 /* OnScreenControls.h */, FB4678EB1A50C40900377732 /* OnScreenControls.h */,
@@ -453,20 +441,13 @@
FB89460E19F646E200339C8A /* Network */ = { FB89460E19F646E200339C8A /* Network */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FB89460F19F646E200339C8A /* HttpManager.h */, FB9AFD2F1A7C979700872C98 /* Http */,
FB89461019F646E200339C8A /* HttpManager.m */, FB9AFD341A7D877B00872C98 /* Discovery */,
FB89461119F646E200339C8A /* MDNSManager.h */, FB9AFD331A7D876F00872C98 /* AppList */,
FB89461219F646E200339C8A /* MDNSManager.m */,
FB89461319F646E200339C8A /* PairManager.h */, FB89461319F646E200339C8A /* PairManager.h */,
FB89461419F646E200339C8A /* PairManager.m */, FB89461419F646E200339C8A /* PairManager.m */,
FBD3494119FC9C04002D2A60 /* AppManager.h */,
FBD3494219FC9C04002D2A60 /* AppManager.m */,
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */, FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */, FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */,
FB4678F81A55FFAD00377732 /* DiscoveryManager.h */,
FB4678F91A55FFAD00377732 /* DiscoveryManager.m */,
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */,
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */,
); );
path = Network; path = Network;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -489,10 +470,10 @@
FB89461E19F646E200339C8A /* Utility */ = { FB89461E19F646E200339C8A /* Utility */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FBDE86E719F82315001C18A8 /* App.h */,
FBDE86E819F82315001C18A8 /* App.m */,
FB89462119F646E200339C8A /* Utils.h */, FB89462119F646E200339C8A /* Utils.h */,
FB89462219F646E200339C8A /* Utils.m */, FB89462219F646E200339C8A /* Utils.m */,
FBD1C8E01A8AD69E00C6703C /* Logger.h */,
FBD1C8E11A8AD71400C6703C /* Logger.m */,
); );
path = Utility; path = Utility;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -508,6 +489,8 @@
FB89462719F646E200339C8A /* StreamFrameViewController.m */, FB89462719F646E200339C8A /* StreamFrameViewController.m */,
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */, FBD3494E19FF2174002D2A60 /* SettingsViewController.h */,
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */, FBD3494F19FF2174002D2A60 /* SettingsViewController.m */,
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */,
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */,
); );
path = ViewControllers; path = ViewControllers;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -673,13 +656,60 @@
path = lib; path = lib;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB9AFD2F1A7C979700872C98 /* Http */ = {
isa = PBXGroup;
children = (
FB89460F19F646E200339C8A /* HttpManager.h */,
FB89461019F646E200339C8A /* HttpManager.m */,
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */,
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */,
FB9AFD261A7C84ED00872C98 /* HttpResponse.h */,
FB9AFD271A7C84ED00872C98 /* HttpResponse.m */,
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */,
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */,
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */,
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */,
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */,
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */,
);
name = Http;
sourceTree = "<group>";
};
FB9AFD331A7D876F00872C98 /* AppList */ = {
isa = PBXGroup;
children = (
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */,
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */,
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */,
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */,
);
name = AppList;
sourceTree = "<group>";
};
FB9AFD341A7D877B00872C98 /* Discovery */ = {
isa = PBXGroup;
children = (
FB4678F81A55FFAD00377732 /* DiscoveryManager.h */,
FB4678F91A55FFAD00377732 /* DiscoveryManager.m */,
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */,
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */,
FB89461119F646E200339C8A /* MDNSManager.h */,
FB89461219F646E200339C8A /* MDNSManager.m */,
);
name = Discovery;
sourceTree = "<group>";
};
FBD3495F1A004453002D2A60 /* Database */ = { FBD3495F1A004453002D2A60 /* Database */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FBFCB3321B50B29400089F8A /* App+CoreDataProperties.h */,
FBFCB3331B50B29400089F8A /* App.h */,
FBFCB3341B50B29400089F8A /* App.m */,
FBFCB32E1B50B29400089F8A /* Host+CoreDataProperties.h */,
FBFCB32F1B50B29400089F8A /* Host.h */,
FBFCB3301B50B29400089F8A /* Host.m */,
FBD3495C1A004412002D2A60 /* Settings.h */, FBD3495C1A004412002D2A60 /* Settings.h */,
FBD3495D1A004412002D2A60 /* Settings.m */, FBD3495D1A004412002D2A60 /* Settings.m */,
FBD349591A004411002D2A60 /* Host.h */,
FBD3495A1A004411002D2A60 /* Host.m */,
FBD349601A0089F6002D2A60 /* DataManager.h */, FBD349601A0089F6002D2A60 /* DataManager.h */,
FBD349611A0089F6002D2A60 /* DataManager.m */, FBD349611A0089F6002D2A60 /* DataManager.m */,
); );
@@ -689,9 +719,9 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
FB290CED19B2C406004C83CF /* Limelight */ = { FB290CED19B2C406004C83CF /* Moonlight */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Limelight" */; buildConfigurationList = FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Moonlight" */;
buildPhases = ( buildPhases = (
FB290CEA19B2C406004C83CF /* Sources */, FB290CEA19B2C406004C83CF /* Sources */,
FB290CEB19B2C406004C83CF /* Frameworks */, FB290CEB19B2C406004C83CF /* Frameworks */,
@@ -700,49 +730,28 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
98A03B4C19F3517100861ACA /* PBXTargetDependency */, 987140021B04541A00AB57D5 /* PBXTargetDependency */,
); );
name = Limelight; name = Moonlight;
productName = Limelight; productName = Limelight;
productReference = FB290CEE19B2C406004C83CF /* Limelight.app */; productReference = FB290CEE19B2C406004C83CF /* Moonlight.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
FB290D0D19B2C406004C83CF /* LimelightTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = FB290D2319B2C406004C83CF /* Build configuration list for PBXNativeTarget "LimelightTests" */;
buildPhases = (
FB290D0A19B2C406004C83CF /* Sources */,
FB290D0B19B2C406004C83CF /* Frameworks */,
FB290D0C19B2C406004C83CF /* Resources */,
);
buildRules = (
);
dependencies = (
FB290D1519B2C406004C83CF /* PBXTargetDependency */,
);
name = LimelightTests;
productName = LimelightTests;
productReference = FB290D0E19B2C406004C83CF /* LimelightTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
FB290CE619B2C406004C83CF /* Project object */ = { FB290CE619B2C406004C83CF /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0510; LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Limelight Stream"; ORGANIZATIONNAME = "Limelight Stream";
TargetAttributes = { TargetAttributes = {
FB290CED19B2C406004C83CF = { FB290CED19B2C406004C83CF = {
DevelopmentTeam = DM46QST4M7; DevelopmentTeam = DM46QST4M7;
}; };
FB290D0D19B2C406004C83CF = {
TestTargetID = FB290CED19B2C406004C83CF;
};
}; };
}; };
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Limelight" */; buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = English;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@@ -754,24 +763,23 @@
projectDirPath = ""; projectDirPath = "";
projectReferences = ( projectReferences = (
{ {
ProductGroup = 98A03B4619F3514B00861ACA /* Products */; ProductGroup = FB1E430C1AE8B0F200AFF679 /* Products */;
ProjectRef = 98A03B4519F3514B00861ACA /* limelight-common.xcodeproj */; ProjectRef = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
}, },
); );
projectRoot = ""; projectRoot = "";
targets = ( targets = (
FB290CED19B2C406004C83CF /* Limelight */, FB290CED19B2C406004C83CF /* Moonlight */,
FB290D0D19B2C406004C83CF /* LimelightTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXReferenceProxy section */ /* Begin PBXReferenceProxy section */
98A03B4A19F3514B00861ACA /* liblimelight-common.a */ = { FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
path = "liblimelight-common.a"; path = "libmoonlight-common.a";
remoteRef = 98A03B4919F3514B00861ACA /* PBXContainerItemProxy */; remoteRef = FB1E430F1AE8B0F200AFF679 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
/* End PBXReferenceProxy section */ /* End PBXReferenceProxy section */
@@ -796,14 +804,6 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
FB290D0C19B2C406004C83CF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FB290D1B19B2C406004C83CF /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -815,55 +815,51 @@
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */, FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
FBD3495E1A004412002D2A60 /* Settings.m in Sources */, FBD3495E1A004412002D2A60 /* Settings.m in Sources */,
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */, FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */,
FB89463419F646E200339C8A /* Utils.m in Sources */, FB89463419F646E200339C8A /* Utils.m in Sources */,
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */, FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */,
FB89462F19F646E200339C8A /* Connection.m in Sources */, FB89462F19F646E200339C8A /* Connection.m in Sources */,
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */, FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
FB89462919F646E200339C8A /* mkcert.c in Sources */, FB89462919F646E200339C8A /* mkcert.c in Sources */,
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */, FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
FBDE86E919F82315001C18A8 /* App.m in Sources */,
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */, FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
FBFCB3311B50B29400089F8A /* Host.m in Sources */,
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */, FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */, FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
FB89462C19F646E200339C8A /* HttpManager.m in Sources */, FB89462C19F646E200339C8A /* HttpManager.m in Sources */,
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */, FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
FB89462B19F646E200339C8A /* StreamView.m in Sources */, FB89462B19F646E200339C8A /* StreamView.m in Sources */,
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */, FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
FBD3495B1A004411002D2A60 /* Host.m in Sources */,
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */, FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */, FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
FB89462819F646E200339C8A /* CryptoManager.m in Sources */, FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
FB89462E19F646E200339C8A /* PairManager.m in Sources */, FB89462E19F646E200339C8A /* PairManager.m in Sources */,
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */, FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
FB290D0019B2C406004C83CF /* main.m in Sources */, FB290D0019B2C406004C83CF /* main.m in Sources */,
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */, FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */,
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */,
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */, FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */, FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
FBFCB3351B50B29400089F8A /* App.m in Sources */,
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
FB89463119F646E200339C8A /* StreamManager.m in Sources */, FB89463119F646E200339C8A /* StreamManager.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
FB290D0A19B2C406004C83CF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FB290D1D19B2C406004C83CF /* LimelightTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
98A03B4C19F3517100861ACA /* PBXTargetDependency */ = { 987140021B04541A00AB57D5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
name = "limelight-common"; name = "moonlight-common";
targetProxy = 98A03B4B19F3517100861ACA /* PBXContainerItemProxy */; targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */;
};
FB290D1519B2C406004C83CF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FB290CED19B2C406004C83CF /* Limelight */;
targetProxy = FB290D1419B2C406004C83CF /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
@@ -876,14 +872,6 @@
name = InfoPlist.strings; name = InfoPlist.strings;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB290D1919B2C406004C83CF /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
FB290D1A19B2C406004C83CF /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */ /* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
@@ -906,6 +894,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
@@ -968,6 +957,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
ENABLE_BITCODE = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch"; GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
@@ -983,6 +973,7 @@
"$(PROJECT_DIR)/libs/opus/lib", "$(PROJECT_DIR)/libs/opus/lib",
"$(PROJECT_DIR)/libs/openssl/lib", "$(PROJECT_DIR)/libs/openssl/lib",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
SKIP_INSTALL = NO; SKIP_INSTALL = NO;
@@ -994,8 +985,9 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
ENABLE_BITCODE = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch"; GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
@@ -1011,6 +1003,7 @@
"$(PROJECT_DIR)/libs/opus/lib", "$(PROJECT_DIR)/libs/opus/lib",
"$(PROJECT_DIR)/libs/openssl/lib", "$(PROJECT_DIR)/libs/openssl/lib",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
SKIP_INSTALL = NO; SKIP_INSTALL = NO;
@@ -1018,50 +1011,10 @@
}; };
name = Release; name = Release;
}; };
FB290D2419B2C406004C83CF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Limelight.app/Limelight";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "LimelightTests/LimelightTests-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
FB290D2519B2C406004C83CF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Limelight.app/Limelight";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
INFOPLIST_FILE = "LimelightTests/LimelightTests-Info.plist";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Limelight" */ = { FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
FB290D1E19B2C406004C83CF /* Debug */, FB290D1E19B2C406004C83CF /* Debug */,
@@ -1070,7 +1023,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Limelight" */ = { FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Moonlight" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
FB290D2119B2C406004C83CF /* Debug */, FB290D2119B2C406004C83CF /* Debug */,
@@ -1079,26 +1032,18 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
FB290D2319B2C406004C83CF /* Build configuration list for PBXNativeTarget "LimelightTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FB290D2419B2C406004C83CF /* Debug */,
FB290D2519B2C406004C83CF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCVersionGroup section */ /* Begin XCVersionGroup section */
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = { FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
isa = XCVersionGroup; isa = XCVersionGroup;
children = ( children = (
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */,
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */, FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */,
FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */, FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */,
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */, FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */,
); );
currentVersion = FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */; currentVersion = FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */;
path = Limelight.xcdatamodeld; path = Limelight.xcdatamodeld;
sourceTree = "<group>"; sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel; versionGroupType = wrapper.xcdatamodel;
@@ -2,6 +2,6 @@
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef <FileRef
location = "self:Limelight.xcodeproj"> location = "self:Moonlight.xcodeproj">
</FileRef> </FileRef>
</Workspace> </Workspace>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>AD7C6582-F39A-441A-A7FD-9EBF143920BA</string>
<key>IDESourceControlProjectName</key>
<string>Moonlight</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
<string>github.com:limelight-stream/limelight-ios.git</string>
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
<string>github.com:limelight-stream/limelight-common-c.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>Moonlight.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
<string>../..</string>
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
<string>../../limelight-common-c</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:limelight-stream/limelight-ios.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>EB99D631D5149240E91F8D168F0F298D7A5BAA89</string>
<key>IDESourceControlWCCName</key>
<string>limelight-common-c</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
<key>IDESourceControlWCCName</key>
<string>moonlight-ios</string>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>6524503E-ED62-4E8E-8A67-B6DFB5A532FD</string>
<key>IDESourceControlProjectName</key>
<string>project</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
<string>github.com:limelight-stream/limelight-ios.git</string>
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
<string>github.com:limelight-stream/limelight-common-c.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>Moonlight.xcodeproj/project.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
<string>../..</string>
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
<string>../..limelight-common-c/</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:limelight-stream/limelight-ios.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>EB99D631D5149240E91F8D168F0F298D7A5BAA89</string>
<key>IDESourceControlWCCName</key>
<string>limelight-common-c</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
<key>IDESourceControlWCCName</key>
<string>limelight-ios</string>
</dict>
</array>
</dict>
</plist>
+6 -7
View File
@@ -1,13 +1,12 @@
#Limelight iOS #Moonlight iOS
[Limelight](https://github.com/limelight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Limelight iOS will allow you to stream your full collection of Steam games from [Moonlight](https://github.com/moonlight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Moonlight iOS allows you to stream your full collection of Steam games from
your powerful desktop computer to your iOS Device. your powerful desktop computer to your iOS Device.
This is actively being developed and should be available on the AppStore soon. This is actively being developed and will be available on the App Store soon - check back here or on [our website](http://moonlight-stream.com) for updates.
We understand that Limelight users are eager for the opportunity to stream their Steam collection to their iOS devices. Limelight for iOS is in the testing stage and preliminary versions are available for beta testers. We understand that Moonlight users are eager for the opportunity to stream their Steam collection to their iOS devices. Moonlight for iOS is in the testing stage and preliminary versions are available for beta testers.
In the meantime, check out the existing versions for [Android](https://github.com/limelight-stream/limelight-android) and [PC](https://github.com/limelight-stream/limelight-pc). Also, a client for [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) is in the works and actively being developed. In the meantime, check out the existing versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [PC](https://github.com/moonlight-stream/moonlight-pc). Also, a client for [Windows and Windows Phone](https://github.com/moonlight-stream/moonlight-windows) is in the works and actively being developed.
Please be patient as we work to bring Limelight to more platforms.
Please be patient as we work to bring Moonlight to more platforms.
+48 -20
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C81f" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies> </dependencies>
<customFonts key="customFonts"> <customFonts key="customFonts">
<mutableArray key="Roboto-Regular.ttf"> <mutableArray key="Roboto-Regular.ttf">
@@ -14,7 +14,7 @@
<objects> <objects>
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController"> <viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d"> <collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d">
<rect key="frame" x="0.0" y="0.0" width="1024" height="704"/> <rect key="frame" x="0.0" y="64" width="1024" height="704"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/> <inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc"> <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
@@ -25,7 +25,7 @@
</collectionViewFlowLayout> </collectionViewFlowLayout>
<cells> <cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="fv6-NS-qsK"> <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="fv6-NS-qsK">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/> <rect key="frame" x="20" y="20" width="150" height="200"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="150" height="200"/> <rect key="frame" x="0.0" y="0.0" width="150" height="200"/>
@@ -45,8 +45,8 @@
<rect key="frame" x="101" y="236" width="109" height="46"/> <rect key="frame" x="101" y="236" width="109" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/> <fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
<state key="normal" title="Limelight" image="Logo"> <state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/> <color key="titleColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state> </state>
</button> </button>
@@ -77,18 +77,20 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lMt-4H-fkV"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lMt-4H-fkV">
<rect key="frame" x="16" y="39" width="151" height="21"/> <rect key="frame" x="16" y="39" width="151" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10" minValue="1" maxValue="50" id="JAY-nj-UNz"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="JAY-nj-UNz">
<rect key="frame" x="14" y="68" width="213" height="31"/> <rect key="frame" x="14" y="68" width="213" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</slider> </slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aiv-r8-9k2"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aiv-r8-9k2">
<rect key="frame" x="16" y="106" width="79" height="21"/> <rect key="frame" x="16" y="106" width="79" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -96,6 +98,7 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pYZ-GR-EwO"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pYZ-GR-EwO">
<rect key="frame" x="16" y="171" width="82" height="21"/> <rect key="frame" x="16" y="171" width="82" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -108,20 +111,12 @@
<segment title="1080p"/> <segment title="1080p"/>
<segment title="Native"/> <segment title="Native"/>
</segments> </segments>
<color key="tintColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="lGK-vl-pdw">
<rect key="frame" x="16" y="135" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="30 Hz"/>
<segment title="60 Hz"/>
</segments>
<color key="tintColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/>
</segmentedControl> </segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="LGV-5y-piG"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="LGV-5y-piG">
<rect key="frame" x="16" y="236" width="153" height="21"/> <rect key="frame" x="16" y="236" width="153" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -135,7 +130,16 @@
<segment title="Simple"/> <segment title="Simple"/>
<segment title="Full"/> <segment title="Full"/>
</segments> </segments>
<color key="tintColor" red="0.3803921569" green="0.92156862750000001" blue="0.25882352939999997" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="lGK-vl-pdw">
<rect key="frame" x="16" y="135" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<segments>
<segment title="30 Hz"/>
<segment title="60 Hz"/>
</segments>
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl> </segmentedControl>
</subviews> </subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/> <color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
@@ -226,9 +230,33 @@
</objects> </objects>
<point key="canvasLocation" x="1946" y="514"/> <point key="canvasLocation" x="1946" y="514"/>
</scene> </scene>
<!--Loading Frame View Controller-->
<scene sceneID="lcG-48-utf">
<objects>
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="ZNo-L5-uxh" customClass="LoadingFrameViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="le1-tU-NEp">
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" id="N0D-dj-EuF">
<rect key="frame" x="494" y="365" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<connections>
<outlet property="loadingSpinner" destination="N0D-dj-EuF" id="xEQ-nx-SOt"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lJG-tq-Jrs" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1946" y="1425"/>
</scene>
</scenes> </scenes>
<resources> <resources>
<image name="Logo" width="36" height="36"/> <image name="Logo" width="32" height="32"/>
</resources> </resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="lightContent"/> <simulatedStatusBarMetrics key="statusBar" statusBarStyle="lightContent"/>
+41 -18
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C81f" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies> </dependencies>
<customFonts key="customFonts"> <customFonts key="customFonts">
<mutableArray key="Roboto-Regular.ttf"> <mutableArray key="Roboto-Regular.ttf">
@@ -14,7 +14,7 @@
<objects> <objects>
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController"> <viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="Rtu-AT-Alw"> <collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="Rtu-AT-Alw">
<rect key="frame" x="0.0" y="0.0" width="568" height="256"/> <rect key="frame" x="0.0" y="64" width="568" height="256"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/> <inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK"> <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK">
@@ -25,7 +25,7 @@
</collectionViewFlowLayout> </collectionViewFlowLayout>
<cells> <cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="Uqv-Di-fzX"> <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="Uqv-Di-fzX">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/> <rect key="frame" x="20" y="20" width="90" height="120"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="90" height="120"/> <rect key="frame" x="0.0" y="0.0" width="90" height="120"/>
@@ -46,14 +46,14 @@
<rect key="frame" x="0.0" y="0.0" width="109" height="46"/> <rect key="frame" x="0.0" y="0.0" width="109" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/> <fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
<state key="normal" title="Limelight" image="Logo"> <state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/> <color key="titleColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state> </state>
</button> </button>
</barButtonItem> </barButtonItem>
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="L1H-n4-HB7"> <barButtonItem key="rightBarButtonItem" title="No Host Selected" id="L1H-n4-HB7">
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="tintColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/> <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -94,16 +94,16 @@
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/> <rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10" minValue="1" maxValue="50" id="3nn-MI-9Xu"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="3nn-MI-9Xu">
<rect key="frame" x="14" y="49" width="204" height="31"/> <rect key="frame" x="14" y="49" width="204" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.39215686274509803" green="0.9137254901960784" blue="0.17254901960784313" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</slider> </slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SBv-Wn-LB7"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SBv-Wn-LB7">
<rect key="frame" x="16" y="20" width="151" height="21"/> <rect key="frame" x="16" y="20" width="151" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY">
@@ -113,20 +113,20 @@
<segment title="30 Hz"/> <segment title="30 Hz"/>
<segment title="60 Hz"/> <segment title="60 Hz"/>
</segments> </segments>
<color key="tintColor" red="0.39215686274509803" green="0.9137254901960784" blue="0.17254901960784313" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl> </segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Kkv-DF-MAl"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Kkv-DF-MAl">
<rect key="frame" x="16" y="87" width="79" height="21"/> <rect key="frame" x="16" y="87" width="79" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8zy-ri-Dqc"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8zy-ri-Dqc">
<rect key="frame" x="16" y="152" width="82" height="21"/> <rect key="frame" x="16" y="152" width="82" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="PCM-t4-Sha"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="PCM-t4-Sha">
@@ -137,13 +137,13 @@
<segment title="1080p"/> <segment title="1080p"/>
<segment title="Native"/> <segment title="Native"/>
</segments> </segments>
<color key="tintColor" red="0.39215686274509803" green="0.9137254901960784" blue="0.17254901960784313" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl> </segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HZT-dd-DuQ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HZT-dd-DuQ">
<rect key="frame" x="16" y="217" width="153" height="21"/> <rect key="frame" x="16" y="217" width="153" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm"> <segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm">
@@ -155,10 +155,10 @@
<segment title="Simple"/> <segment title="Simple"/>
<segment title="Full"/> <segment title="Full"/>
</segments> </segments>
<color key="tintColor" red="0.38039215686274508" green="0.92156862745098034" blue="0.25882352941176467" alpha="1" colorSpace="calibratedRGB"/> <color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl> </segmentedControl>
</subviews> </subviews>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/> <color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="calibratedRGB"/>
</view> </view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/> <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<connections> <connections>
@@ -229,9 +229,32 @@
</objects> </objects>
<point key="canvasLocation" x="2092" y="796"/> <point key="canvasLocation" x="2092" y="796"/>
</scene> </scene>
<!--Loading Frame View Controller-->
<scene sceneID="kPF-XD-S77">
<objects>
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="9W0-2D-0Kp" customClass="LoadingFrameViewController" sceneMemberID="viewController">
<view key="view" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="center" id="nSw-dc-mi4">
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
<rect key="frame" x="266" y="141" width="37" height="37"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<connections>
<outlet property="loadingSpinner" destination="oNu-Gu-QeM" id="5IK-qn-mIZ"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="GaV-PK-JSI" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2104" y="1266"/>
</scene>
</scenes> </scenes>
<resources> <resources>
<image name="Logo" width="36" height="36"/> <image name="Logo" width="32" height="32"/>
</resources> </resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics"> <simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/> <simulatedStatusBarMetrics key="statusBar"/>
+4 -1
View File
@@ -616,7 +616,10 @@ OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, fl
* merged. Splitting valid Opus packets is always guaranteed to succeed, * merged. Splitting valid Opus packets is always guaranteed to succeed,
* whereas merging valid packets only succeeds if all frames have the same * whereas merging valid packets only succeeds if all frames have the same
* mode, bandwidth, and frame size, and when the total duration of the merged * mode, bandwidth, and frame size, and when the total duration of the merged
* packet is no more than 120 ms. * packet is no more than 120 ms. The 120 ms limit comes from the
* specification and limits decoder memory requirements at a point where
* framing overhead becomes negligible.
*
* The repacketizer currently only operates on elementary Opus * The repacketizer currently only operates on elementary Opus
* streams. It will not manipualte multistream packets successfully, except in * streams. It will not manipualte multistream packets successfully, except in
* the degenerate case where they consist of data from a single stream. * the degenerate case where they consist of data from a single stream.
+4
View File
@@ -713,6 +713,10 @@ extern "C" {
OPUS_EXPORT const char *opus_strerror(int error); OPUS_EXPORT const char *opus_strerror(int error);
/** Gets the libopus version string. /** Gets the libopus version string.
*
* Applications may look for the substring "-fixed" in the version string to
* determine whether they have a fixed-point or floating-point build at
* runtime.
* *
* @returns Version string * @returns Version string
*/ */
Binary file not shown.