Compare commits

...
60 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
53 changed files with 818 additions and 605 deletions

No files matched your search

+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.
+6 -3
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="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8121.17" systemVersion="15A204h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/>
</dependencies> </dependencies>
<objects> <objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
@@ -11,7 +12,8 @@
<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) 2015 Moonlight 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="19" y="439" width="444" 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.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@@ -20,6 +22,7 @@
</variation> </variation>
</label> </label>
</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="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"/>
-18
View File
@@ -1,18 +0,0 @@
//
// App.h
// Moonlight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface App : NSObject
@property NSString* appId;
@property NSString* appName;
@property UIImage* appImage;
@property BOOL isRunning;
@end
-15
View File
@@ -1,15 +0,0 @@
//
// App.m
// Moonlight
//
// Created by Diego Waxemberg on 10/22/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import "App.h"
#import "HttpManager.h"
@implementation App
@synthesize appId, appName, appImage, isRunning;
@end
+1 -1
View File
@@ -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;
+1
View File
@@ -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;
+9 -3
View File
@@ -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);
@@ -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);
@@ -188,7 +194,7 @@ static NSData* p12 = nil;
} }
+ (NSData *)getSignatureFromCert:(NSData *)cert { + (NSData *)getSignatureFromCert:(NSData *)cert {
const char* buffer = [cert bytes]; const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
X509* x509; X509* x509;
BIO* bio = BIO_new(BIO_s_mem()); BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer); BIO_puts(bio, buffer);
@@ -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
+4 -1
View File
@@ -10,6 +10,7 @@
#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
+12 -3
View File
@@ -48,15 +48,15 @@
- (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]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error); Log(LOG_E, @"Unable to save hosts to database: %@", error);
@@ -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
+9 -8
View File
@@ -2,23 +2,24 @@
// Host.h // Host.h
// Moonlight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Moonlight Stream. All rights reserved. // Copyright © 2015 Limelight Stream. All rights reserved.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#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"
+3 -9
View File
@@ -2,22 +2,16 @@
// Host.m // Host.m
// Moonlight // Moonlight
// //
// Created by Diego Waxemberg on 10/28/14. // Created by Diego Waxemberg on 7/10/15.
// Copyright (c) 2014 Moonlight Stream. All rights reserved. // Copyright © 2015 Limelight Stream. All rights reserved.
// //
#import "Host.h" #import "Host.h"
@implementation Host @implementation Host
@dynamic name;
@dynamic address;
@dynamic localAddress;
@dynamic externalAddress;
@dynamic uuid;
@dynamic mac;
@dynamic pairState; @dynamic pairState;
@synthesize online; @synthesize online;
@synthesize activeAddress;
@end @end
+21
View File
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "play.png"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+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.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
@@ -17,15 +17,20 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.9.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>
@@ -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 -1
View File
@@ -20,7 +20,7 @@
@interface AppAssetManager : NSObject @interface AppAssetManager : NSObject
- (id) initWithCallback:(id<AppAssetCallback>)callback; - (id) initWithCallback:(id<AppAssetCallback>)callback;
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host; - (void) retrieveAssetsFromHost:(Host*)host;
- (void) stopRetrieving; - (void) stopRetrieving;
@end @end
+11 -20
View File
@@ -15,8 +15,6 @@
@implementation AppAssetManager { @implementation AppAssetManager {
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
id<AppAssetCallback> _callback; id<AppAssetCallback> _callback;
Host* _host;
NSMutableDictionary* _imageCache;
} }
static const int MAX_REQUEST_COUNT = 4; static const int MAX_REQUEST_COUNT = 4;
@@ -24,29 +22,22 @@ static const int MAX_REQUEST_COUNT = 4;
- (id) initWithCallback:(id<AppAssetCallback>)callback { - (id) initWithCallback:(id<AppAssetCallback>)callback {
self = [super init]; self = [super init];
_callback = callback; _callback = callback;
_imageCache = [[NSMutableDictionary alloc] init];
_opQueue = [[NSOperationQueue alloc] init]; _opQueue = [[NSOperationQueue alloc] init];
[_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT]; [_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT];
return self; return self;
} }
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host { - (void) retrieveAssetsFromHost:(Host*)host {
Host* oldHost = _host; for (App* app in host.appList) {
_host = host; if (app.image == nil) {
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid]; AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
Log(LOG_I, @"Using cached app images: %d", useCache); retriever.app = app;
if (!useCache) { retriever.host = host;
[_imageCache removeAllObjects]; retriever.callback = _callback;
}
for (App* app in appList) { [_opQueue addOperation:retriever];
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init]; }
retriever.app = app;
retriever.host = _host;
retriever.callback = _callback;
retriever.cache = _imageCache;
retriever.useCache = useCache;
[_opQueue addOperation:retriever];
} }
} }
-2
View File
@@ -15,8 +15,6 @@
@property (nonatomic) Host* host; @property (nonatomic) Host* host;
@property (nonatomic) App* app; @property (nonatomic) App* app;
@property (nonatomic) NSMutableDictionary* cache;
@property (nonatomic) id<AppAssetCallback> callback; @property (nonatomic) id<AppAssetCallback> callback;
@property (nonatomic) BOOL useCache;
@end @end
+10 -24
View File
@@ -16,35 +16,21 @@
static const double RETRY_DELAY = 2; // seconds static const double RETRY_DELAY = 2; // seconds
static const int MAX_ATTEMPTS = 5; static const int MAX_ATTEMPTS = 5;
- (void) main { - (void) main {
UIImage* appImage = nil; UIImage* appImage = nil;
int attempts = 0; int attempts = 0;
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) { while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
if (self.useCache) {
@synchronized(self.cache) { HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
UIImage* cachedImage = [self.cache objectForKey:self.app.appId]; AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
if (cachedImage != nil) { [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
appImage = cachedImage;
self.app.appImage = appImage; appImage = [UIImage imageWithData:appAssetResp.data];
} self.app.image = UIImagePNGRepresentation(appImage);
}
if (![self isCancelled] && appImage == nil) {
[NSThread sleepForTimeInterval:RETRY_DELAY];
} }
if (appImage == nil) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]];
appImage = [UIImage imageWithData:appAssetResp.data];
self.app.appImage = appImage;
if (appImage != nil) {
@synchronized(self.cache) {
[self.cache setObject:appImage forKey:self.app.appId];
}
}
}
[NSThread sleepForTimeInterval:RETRY_DELAY];
} }
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
} }
+9 -7
View File
@@ -8,6 +8,7 @@
#import "AppListResponse.h" #import "AppListResponse.h"
#import "App.h" #import "App.h"
#import "DataManager.h"
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse { @implementation AppListResponse {
@@ -59,13 +60,14 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
self.statusMessage = statusMsg; self.statusMessage = statusMsg;
node = node->children; node = node->children;
DataManager* dataMan = [[DataManager alloc] init];
while (node != NULL) { while (node != NULL) {
//Log(LOG_D, @"node: %s", node->name); //Log(LOG_D, @"node: %s", node->name);
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) { if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
xmlNodePtr appInfoNode = node->xmlChildrenNode; xmlNodePtr appInfoNode = node->xmlChildrenNode;
NSString* appName; NSString* appName = @"";
NSString* appId; NSString* appId = nil;
BOOL appIsRunning = NO; BOOL appIsRunning = NO;
while (appInfoNode != NULL) { while (appInfoNode != NULL) {
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) { if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
@@ -93,11 +95,11 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
} }
appInfoNode = appInfoNode->next; appInfoNode = appInfoNode->next;
} }
App* app = [[App alloc] init]; if (appId != nil) {
app.appName = appName; App* app = [dataMan createApp];
app.appId = appId; app.name = appName;
app.isRunning = appIsRunning; app.id = appId;
if (app.appId != nil) { app.isRunning = appIsRunning;
[_appList addObject:app]; [_appList addObject:app];
} }
} }
+3 -3
View File
@@ -41,13 +41,13 @@
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))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];
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
Host* host = nil; Host* host = nil;
if ([serverInfoResponse isStatusOk]) { 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;
host.online = YES; host.online = YES;
[serverInfoResponse populateHost:host]; [serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) { if (![self addHostToDiscovery:host]) {
@@ -125,7 +125,7 @@
[dataMan removeHost:host]; [dataMan removeHost:host];
} }
} }
[dataMan saveHosts]; [dataMan saveData];
}); });
} }
+61 -12
View File
@@ -41,23 +41,71 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
} }
} }
- (NSArray*) getHostAddressList {
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
if (_host.localAddress != nil) {
[array addObject:_host.localAddress];
}
if (_host.externalAddress != nil) {
[array addObject:_host.externalAddress];
}
if (_host.address != nil) {
[array addObject:_host.address];
}
// Remove duplicate addresses from the list.
// This is done using an array rather than a set
// to preserve insertion order of addresses.
for (int i = 0; i < [array count]; i++) {
NSString *addr1 = [array objectAtIndex:i];
for (int j = 1; j < [array count]; j++) {
if (i == j) {
continue;
}
NSString *addr2 = [array objectAtIndex:j];
if ([addr1 isEqualToString:addr2]) {
// Remove the last address
[array removeObjectAtIndex:j];
// Begin searching again from the start
i = -1;
break;
}
}
}
return array;
}
- (void) discoverHost { - (void) discoverHost {
BOOL receivedResponse = NO; BOOL receivedResponse = NO;
if (!self.cancelled && _host.localAddress != nil) { NSArray *addresses = [self getHostAddressList];
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.localAddress];
receivedResponse = [self checkResponse:serverInfoResp]; Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
}
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) { for (NSString *address in addresses) {
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.externalAddress]; if (self.cancelled) {
receivedResponse = [self checkResponse:serverInfoResp]; // Get out without updating the status because
} // it might not have finished checking the various
if (!self.cancelled && !receivedResponse && _host.address != nil) { // addresses
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.address]; return;
}
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
receivedResponse = [self checkResponse:serverInfoResp]; receivedResponse = [self checkResponse:serverInfoResp];
if (receivedResponse) {
_host.activeAddress = address;
break;
}
} }
_host.online = receivedResponse; _host.online = receivedResponse;
if (receivedResponse) { if (receivedResponse) {
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online); Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online, _host.activeAddress);
} }
} }
@@ -68,7 +116,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
cert:_cert]; cert:_cert];
ServerInfoResponse* response = [[ServerInfoResponse alloc] init]; ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response [hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
withUrlRequest:[hMan newServerInfoRequest]]]; withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
return response; return response;
} }
+2 -2
View File
@@ -11,7 +11,7 @@
#import "HttpResponse.h" #import "HttpResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> @interface HttpManager : NSObject <NSURLSessionDelegate>
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert; - (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
- (NSURLRequest*) newPairRequest:(NSData*)salt; - (NSURLRequest*) newPairRequest:(NSData*)salt;
@@ -22,12 +22,12 @@
- (NSURLRequest*) newPairChallenge; - (NSURLRequest*) newPairChallenge;
- (NSURLRequest*) newAppListRequest; - (NSURLRequest*) newAppListRequest;
- (NSURLRequest*) newServerInfoRequest; - (NSURLRequest*) newServerInfoRequest;
- (NSURLRequest*) newHttpServerInfoRequest;
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid; - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid;
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId; - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
- (NSURLRequest*) newQuitAppRequest; - (NSURLRequest*) newQuitAppRequest;
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId; - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
- (void) executeRequestSynchronously:(HttpRequest*)request; - (void) executeRequestSynchronously:(HttpRequest*)request;
- (void) executeRequest:(HttpRequest*)request;
@end @end
+77 -56
View File
@@ -15,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;
@@ -27,7 +29,8 @@
BOOL _errorOccurred; BOOL _errorOccurred;
} }
static const NSString* PORT = @"47984"; static const NSString* HTTP_PORT = @"47989";
static const NSString* HTTPS_PORT = @"47984";
+ (NSData*) fixXmlVersion:(NSData*) xmlData { + (NSData*) fixXmlVersion:(NSData*) xmlData {
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]; NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
@@ -42,34 +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;
} }
- (void) executeRequestSynchronously:(HttpRequest*)request { - (void) executeRequestSynchronously:(HttpRequest*)request {
Log(LOG_D, @"Making Request: %@", request); Log(LOG_D, @"Making Request: %@", request);
[_respData setLength:0]; [_respData setLength:0];
dispatch_sync(dispatch_get_main_queue(), ^{ [[_urlSession dataTaskWithRequest:request.request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
[NSURLConnection connectionWithRequest:request.request delegate:self];
}); if (error != NULL) {
Log(LOG_D, @"Connection error: %@", error);
_errorOccurred = true;
}
else {
Log(LOG_D, @"Received response: %@", response);
if (data != NULL) {
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[_respData appendData:data];
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
_requestResp = [HttpManager fixXmlVersion:_respData];
} else {
_requestResp = _respData;
}
}
}
dispatch_semaphore_signal(_requestLock);
}] resume];
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
if (!_errorOccurred && request.response) { if (!_errorOccurred && request.response) {
[request.response populateWithData:_requestResp]; [request.response populateWithData:_requestResp];
// If the fallback error code was detected, issue the fallback request
if (request.response.statusCode == request.fallbackError && request.fallbackRequest != NULL) {
Log(LOG_D, @"Request failed with fallback error code: %d", request.fallbackError);
request.request = request.fallbackRequest;
request.fallbackError = 0;
request.fallbackRequest = NULL;
[self executeRequestSynchronously:request];
}
} }
_errorOccurred = false; _errorOccurred = false;
} }
- (void) executeRequest:(HttpRequest*)request {
[NSURLConnection connectionWithRequest:request.request delegate:self];
}
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout { - (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL* url = [[NSURL alloc] initWithString:urlString];
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
if (normalTimeout) { if (normalTimeout) {
// Timeout the request after 5 seconds // Timeout the request after 5 seconds
@@ -84,67 +112,72 @@ static const NSString* PORT = @"47984";
- (NSURLRequest*) newPairRequest:(NSData*)salt { - (NSURLRequest*) newPairRequest:(NSData*)salt {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
// This call blocks while waiting for the user to input the PIN on the PC // This call blocks while waiting for the user to input the PIN on the PC
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newUnpairRequest { - (NSURLRequest*) newUnpairRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge { - (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp { - (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@", NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]]; _baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret { - (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret]; NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPSURL, _uniqueId, _deviceName, clientPairSecret];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newPairChallenge { - (NSURLRequest*) newPairChallenge {
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName]; NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseHTTPSURL, _uniqueId, _deviceName];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest *)newAppListRequest { - (NSURLRequest *)newAppListRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest *)newServerInfoRequest { - (NSURLRequest *)newServerInfoRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:TRUE];
}
- (NSURLRequest *)newHttpServerInfoRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo", _baseHTTPURL];
return [self createRequestFromString:urlString enableTimeout:TRUE]; return [self createRequestFromString:urlString enableTimeout:TRUE];
} }
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid { - (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid]; NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
// This blocks while the app is launching // This blocks while the app is launching
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId { - (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId]; NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, riKey, riKeyId];
// This blocks while the app is resuming // This blocks while the app is resuming
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newQuitAppRequest { - (NSURLRequest*) newQuitAppRequest {
NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseURL, _uniqueId]; NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseHTTPSURL, _uniqueId];
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId { - (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId {
NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseURL, _uniqueId, appId]; NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseHTTPSURL, _uniqueId, appId];
return [self createRequestFromString:urlString enableTimeout:FALSE]; return [self createRequestFromString:urlString enableTimeout:FALSE];
} }
@@ -157,33 +190,6 @@ static const NSString* PORT = @"47984";
return hex; return hex;
} }
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
Log(LOG_D, @"Received response: %@", response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
[_respData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
_requestResp = [HttpManager fixXmlVersion:_respData];
} else {
_requestResp = _respData;
}
dispatch_semaphore_signal(_requestLock);
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
SecIdentityRef identity = [self getClientCertificate];
NSArray *certArray = [self getCertificate:identity];
NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
}
// Returns an array containing the certificate // Returns an array containing the certificate
- (NSArray*)getCertificate:(SecIdentityRef) identity { - (NSArray*)getCertificate:(SecIdentityRef) identity {
SecCertificateRef certificate = nil; SecCertificateRef certificate = nil;
@@ -219,10 +225,25 @@ static const NSString* PORT = @"47984";
return identityApp; return identityApp;
} }
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * __nullable))completionHandler {
Log(LOG_D, @"connection error: %@", error); // Allow untrusted server certificates
_errorOccurred = true; if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
dispatch_semaphore_signal(_requestLock); {
completionHandler(NSURLSessionAuthChallengeUseCredential,
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]);
}
// Respond to client certificate challenge with our certificate
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])
{
SecIdentityRef identity = [self getClientCertificate];
NSArray* certArray = [self getCertificate:identity];
NSURLCredential* newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
}
else
{
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL);
}
} }
@end @end
+3
View File
@@ -13,7 +13,10 @@
@property (nonatomic) id<Response> response; @property (nonatomic) id<Response> response;
@property (nonatomic) NSURLRequest* request; @property (nonatomic) NSURLRequest* request;
@property (nonatomic) int fallbackError;
@property (nonatomic) NSURLRequest* fallbackRequest;
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq;
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req; + (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req; + (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
+9
View File
@@ -25,4 +25,13 @@
return request; return request;
} }
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq {
HttpRequest* request = [[HttpRequest alloc] init];
request.request = req;
request.response = response;
request.fallbackError = error;
request.fallbackRequest = fallbackReq;
return request;
}
@end @end
+1 -1
View File
@@ -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];
} }
+15 -14
View File
@@ -31,7 +31,8 @@
- (void) main { - (void) main {
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]
fallbackError:401 fallbackRequest:[_httpManager newHttpServerInfoRequest]]];
if (serverInfoResp == nil) { if (serverInfoResp == nil) {
[_callback pairFailed:@"Unable to connect to PC"]; [_callback pairFailed:@"Unable to connect to PC"];
return; return;
@@ -60,7 +61,7 @@
} }
NSInteger pairedStatus; NSInteger pairedStatus;
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing was declined by the target."]; [_callback pairFailed:@"Pairing was declined by the target."];
return; return;
} }
@@ -78,8 +79,8 @@
if (![self verifyResponseStatus:challengeResp]) { if (![self verifyResponseStatus:challengeResp]) {
return; return;
} }
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #2 failed"]; [_callback pairFailed:@"Pairing stage #2 failed"];
return; return;
} }
@@ -99,8 +100,8 @@
if (![self verifyResponseStatus:secretResp]) { if (![self verifyResponseStatus:secretResp]) {
return; return;
} }
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![secretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #3 failed"]; [_callback pairFailed:@"Pairing stage #3 failed"];
return; return;
} }
@@ -110,14 +111,14 @@
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)]; NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) { if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Server certificate invalid"]; [_callback pairFailed:@"Server certificate invalid"];
return; return;
} }
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]]; NSData* 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 executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Incorrect PIN"]; [_callback pairFailed:@"Incorrect PIN"];
return; return;
} }
@@ -128,8 +129,8 @@
if (![self verifyResponseStatus:clientSecretResp]) { if (![self verifyResponseStatus:clientSecretResp]) {
return; return;
} }
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #4 failed"]; [_callback pairFailed:@"Pairing stage #4 failed"];
return; return;
} }
@@ -139,8 +140,8 @@
if (![self verifyResponseStatus:clientPairChallengeResp]) { if (![self verifyResponseStatus:clientPairChallengeResp]) {
return; return;
} }
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) { if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Pairing stage #5 failed"]; [_callback pairFailed:@"Pairing stage #5 failed"];
return; return;
} }
@@ -149,11 +150,11 @@
- (BOOL) verifyResponseStatus:(HttpResponse*)resp { - (BOOL) verifyResponseStatus:(HttpResponse*)resp {
if (resp == nil) { if (resp == nil) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:@"Network error occured."]; [_callback pairFailed:@"Network error occured."];
return false; return false;
} else if (![resp isStatusOk]) { } else if (![resp isStatusOk]) {
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]]; [_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
[_callback pairFailed:resp.statusMessage]; [_callback pairFailed:resp.statusMessage];
return false; return false;
} else { } else {
+16 -28
View File
@@ -15,7 +15,7 @@
#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;
@@ -137,16 +137,26 @@ void ArInit(void)
if (status) { if (status) {
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status); Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
} }
status = AudioOutputUnitStart(audioUnit);
if (status) {
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
}
} }
void ArRelease(void) void ArCleanup(void)
{ {
if (opusDecoder != NULL) { if (opusDecoder != NULL) {
opus_decoder_destroy(opusDecoder); opus_decoder_destroy(opusDecoder);
opusDecoder = NULL; opusDecoder = NULL;
} }
OSStatus status = AudioUnitUninitialize(audioUnit); OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
}
status = AudioUnitUninitialize(audioUnit);
if (status) { if (status) {
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status); Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
} }
@@ -166,22 +176,6 @@ void ArRelease(void)
} }
} }
void ArStart(void)
{
OSStatus status = AudioOutputUnitStart(audioUnit);
if (status) {
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
}
}
void ArStop(void)
{
OSStatus status = AudioOutputUnitStop(audioUnit);
if (status) {
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
}
}
void ArDecodeAndPlaySample(char* sampleData, int sampleLength) void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
{ {
int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0); int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0);
@@ -282,7 +276,7 @@ void ClDisplayTransientMessage(char* message)
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks 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; _serverMajorVersion = serverMajorVersion;
@@ -299,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 = NULL; memset(&_drCallbacks, 0, sizeof(_drCallbacks));
_drCallbacks.start = NULL;
_drCallbacks.stop = NULL;
_drCallbacks.release = NULL;
_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;
@@ -410,7 +399,6 @@ static OSStatus playbackCallback(void *inRefCon,
&_clCallbacks, &_clCallbacks,
&_drCallbacks, &_drCallbacks,
&_arCallbacks, &_arCallbacks,
NULL,
NULL, 0, _serverMajorVersion); NULL, 0, _serverMajorVersion);
} }
-1
View File
@@ -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;
+1 -1
View File
@@ -9,5 +9,5 @@
#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 -1
View File
@@ -45,7 +45,8 @@
cert:cert]; cert:cert];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"]; NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"]; NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"]; NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
+38 -27
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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 {
@@ -28,83 +28,164 @@
Host* _selectedHost; Host* _selectedHost;
NSString* _uniqueId; NSString* _uniqueId;
NSData* _cert; NSData* _cert;
NSString* _currentGame;
DiscoveryManager* _discMan; DiscoveryManager* _discMan;
AppAssetManager* _appManager; AppAssetManager* _appManager;
StreamConfiguration* _streamConfig; StreamConfiguration* _streamConfig;
UIAlertView* _pairAlert; UIAlertController* _pairAlert;
UIScrollView* hostScrollView; UIScrollView* hostScrollView;
int currentPosition; int currentPosition;
NSArray* _sortedAppList;
} }
static NSMutableSet* hostList; static NSMutableSet* hostList;
static NSArray* appList;
- (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]; [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 hideLoadingFrame]; [self alreadyPaired];
}); });
} }
- (void)alreadyPaired { - (void)alreadyPaired {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 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(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
_computerNameButton.title = _selectedHost.name; if (host != _selectedHost) {
return;
}
_computerNameButton.title = host.name;
[self.navigationController.navigationBar setNeedsLayout]; [self.navigationController.navigationBar setNeedsLayout];
[self updateAppsForHost:host];
[self hideLoadingFrame];
}); });
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert]; }
Log(LOG_I, @"Using cached app list: %d", usingCachedAppList);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
AppListResponse* appListResp = [[AppListResponse alloc] init]; AppListResponse* appListResp = [[AppListResponse alloc] init];
// Exempt this host from discovery while handling the applist query
[_discMan removeHostFromDiscovery:host];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
if (appListResp == nil || ![appListResp isStatusOk]) { [_discMan addHostToDiscovery:host];
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage); Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
} else { dispatch_async(dispatch_get_main_queue(), ^{
appList = [appListResp getAppList]; [self hideLoadingFrame];
if (appList == nil) {
Log(LOG_W, @"Failed to parse applist");
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateApps];
});
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 stopRetrieving];
[_appManager retrieveAssets:appList fromHost:_selectedHost]; [_appManager retrieveAssetsFromHost:host];
} [self hideLoadingFrame];
});
} }
[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]; [_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 {
@@ -115,17 +196,56 @@ static NSArray* appList;
[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 {
// 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); Log(LOG_D, @"Clicked host: %@", host.name);
[self showLoadingFrame];
_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];
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
// Exempt this host from discovery while handling the serverinfo request
[_discMan removeHostFromDiscovery:host];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
[_discMan addHostToDiscovery:host];
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) { if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage); Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage);
[self hideLoadingFrame]; 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 {
Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]); Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) { if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
@@ -145,14 +265,7 @@ static NSArray* appList;
- (void)hostLongClicked:(Host *)host view:(UIView *)view { - (void)hostLongClicked:(Host *)host view:(UIView *)view {
Log(LOG_D, @"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 executeRequest:[HttpRequest requestWithUrlRequest:[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]];
@@ -201,7 +314,7 @@ static NSArray* appList;
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){ [_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];
@@ -223,15 +336,10 @@ static NSArray* appList;
} }
- (void) appClicked:(App *)app { - (void) appClicked:(App *)app {
Log(LOG_D, @"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];
@@ -247,30 +355,63 @@ static NSArray* appList;
[[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){
Log(LOG_I, @"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){
Log(LOG_I, @"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:[HttpRequest requestWithUrlRequest:[hMan newQuitAppRequest]]]; HttpResponse* quitResponse = [[HttpResponse alloc] init];
// TODO: handle failure to quit app HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]];
currentApp.isRunning = NO;
if (![app.appId isEqualToString:currentApp.appId]) { // Exempt this host from discovery while handling the quit operation
[_discMan removeHostFromDiscovery:app.host];
[hMan executeRequestSynchronously:quitRequest];
[_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(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self updateAppsForHost:app.host];
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil]; [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]];
@@ -280,8 +421,8 @@ static NSArray* appList;
} }
} }
- (App*) findRunningApp { - (App*) findRunningApp:(Host*)host {
for (App* app in appList) { for (App* app in host.appList) {
if (app.isRunning) { if (app.isRunning) {
return app; return app;
} }
@@ -311,6 +452,7 @@ static NSArray* appList;
- (void) hideLoadingFrame { - (void) hideLoadingFrame {
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
[self enableNavigation];
} }
- (void)viewDidLoad - (void)viewDidLoad
@@ -373,7 +515,7 @@ static NSArray* appList;
// This will refresh the applist // This will refresh the applist
if (_selectedHost != nil) { if (_selectedHost != nil) {
[self hostClicked:_selectedHost]; [self hostClicked:_selectedHost view:nil];
} }
} }
@@ -384,7 +526,7 @@ static NSArray* appList;
[_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 {
@@ -392,6 +534,19 @@ static NSArray* appList;
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;
}
}
} }
} }
@@ -399,7 +554,7 @@ static NSArray* appList;
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
Log(LOG_D, @"New host list:"); Log(LOG_D, @"New host list:");
for (Host* host in hosts) { for (Host* host in hosts) {
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}", 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];
@@ -438,7 +593,15 @@ static NSArray* appList;
} }
} }
- (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];
} }
@@ -446,7 +609,7 @@ static NSArray* appList;
- (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];
@@ -467,7 +630,12 @@ static NSArray* appList;
} }
- (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
@@ -489,4 +657,12 @@ static NSArray* appList;
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
@@ -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;
@@ -102,24 +102,32 @@
} }
- (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 {
-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 @@
//
// MoonlightTests.m
// MoonlightTests
//
// Created by Diego Waxemberg on 8/30/14.
// Copyright (c) 2014 Moonlight 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 */
+28 -163
View File
@@ -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 */; };
@@ -70,12 +65,12 @@
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.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 */
@@ -93,13 +88,6 @@
remoteGlobalIDString = FB290E2E19B37A4E004C83CF; remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
remoteInfo = "moonlight-common"; remoteInfo = "moonlight-common";
}; };
FB290D1419B2C406004C83CF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FB290CE619B2C406004C83CF /* Project object */;
proxyType = 1;
remoteGlobalIDString = FB290CED19B2C406004C83CF;
remoteInfo = Limelight;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -124,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; };
@@ -273,6 +257,7 @@
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
@@ -282,8 +267,6 @@
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>"; };
@@ -292,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 */
@@ -317,16 +304,6 @@
); );
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 */
@@ -365,7 +342,6 @@
children = ( children = (
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */, 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */,
FB290CF919B2C406004C83CF /* Limelight */, FB290CF919B2C406004C83CF /* Limelight */,
FB290D1619B2C406004C83CF /* LimelightTests */,
FB290CF019B2C406004C83CF /* Frameworks */, FB290CF019B2C406004C83CF /* Frameworks */,
FB290CEF19B2C406004C83CF /* Products */, FB290CEF19B2C406004C83CF /* Products */,
); );
@@ -375,7 +351,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FB290CEE19B2C406004C83CF /* Moonlight.app */, FB290CEE19B2C406004C83CF /* Moonlight.app */,
FB290D0E19B2C406004C83CF /* LimelightTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -437,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 = (
@@ -486,7 +443,7 @@
children = ( children = (
FB9AFD2F1A7C979700872C98 /* Http */, FB9AFD2F1A7C979700872C98 /* Http */,
FB9AFD341A7D877B00872C98 /* Discovery */, FB9AFD341A7D877B00872C98 /* Discovery */,
FB9AFD331A7D876F00872C98 /* AppAsset */, FB9AFD331A7D876F00872C98 /* AppList */,
FB89461319F646E200339C8A /* PairManager.h */, FB89461319F646E200339C8A /* PairManager.h */,
FB89461419F646E200339C8A /* PairManager.m */, FB89461419F646E200339C8A /* PairManager.m */,
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */, FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
@@ -513,8 +470,6 @@
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 */, FBD1C8E01A8AD69E00C6703C /* Logger.h */,
@@ -720,7 +675,7 @@
name = Http; name = Http;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB9AFD331A7D876F00872C98 /* AppAsset */ = { FB9AFD331A7D876F00872C98 /* AppList */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */, FBD3494119FC9C04002D2A60 /* AppAssetManager.h */,
@@ -728,7 +683,7 @@
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */, FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */,
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */, FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */,
); );
name = AppAsset; name = AppList;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FB9AFD341A7D877B00872C98 /* Discovery */ = { FB9AFD341A7D877B00872C98 /* Discovery */ = {
@@ -747,10 +702,14 @@
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 */,
); );
@@ -778,39 +737,18 @@
productReference = FB290CEE19B2C406004C83CF /* Moonlight.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 "Moonlight" */; buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
@@ -832,7 +770,6 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
FB290CED19B2C406004C83CF /* Moonlight */, FB290CED19B2C406004C83CF /* Moonlight */,
FB290D0D19B2C406004C83CF /* LimelightTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -867,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 */
@@ -895,15 +824,14 @@
FB89462919F646E200339C8A /* mkcert.c in Sources */, FB89462919F646E200339C8A /* mkcert.c in Sources */,
FB9AFD281A7C84ED00872C98 /* HttpResponse.m 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 */, FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */, FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
@@ -918,20 +846,13 @@
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.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 */, FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.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 */
@@ -940,11 +861,6 @@
name = "moonlight-common"; name = "moonlight-common";
targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */; targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */;
}; };
FB290D1519B2C406004C83CF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FB290CED19B2C406004C83CF /* Moonlight */;
targetProxy = FB290D1419B2C406004C83CF /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
@@ -956,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 */
@@ -986,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;
@@ -1048,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 = (
@@ -1063,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;
@@ -1076,6 +987,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 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 = (
@@ -1091,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;
@@ -1098,46 +1011,6 @@
}; };
name = Release; name = Release;
}; };
FB290D2419B2C406004C83CF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
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)/Moonlight.app/Moonlight";
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 */
@@ -1159,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;
+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.