Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eac2d985e2 | ||
|
|
61ea7f3f1c | ||
|
|
40f7faa1b1 | ||
|
|
9e18b8021b | ||
|
|
ce95f2c153 | ||
|
|
fd50b71b16 | ||
|
|
39ab472cf6 | ||
|
|
48ba7eb2dc | ||
|
|
42edaa1bad | ||
|
|
955fb59156 | ||
|
|
2fbc67ef00 | ||
|
|
23564a3028 | ||
|
|
9a07d5a33a | ||
|
|
84c037f235 | ||
|
|
c13df82f5b | ||
|
|
b15d61a5bf | ||
|
|
5aff719984 | ||
|
|
b0c2978405 | ||
|
|
91dcb505de | ||
|
|
d1f35d938b | ||
|
|
359b822951 | ||
|
|
39580e4352 | ||
|
|
7b3d099449 | ||
|
|
b17c45e9ca | ||
|
|
4c7a2cecdd | ||
|
|
175074ece8 | ||
|
|
8a5ec513bf | ||
|
|
7cfb7f73a2 | ||
|
|
c608685737 | ||
|
|
3beca2fc72 | ||
|
|
c59aafb4bb | ||
|
|
256e40acdc | ||
|
|
39b1b65e16 | ||
|
|
1783abec13 | ||
|
|
983c65d399 | ||
|
|
4caa9672c9 | ||
|
|
15be6a3f75 | ||
|
|
d38eb0a3ba | ||
|
|
e8ea942ad2 | ||
|
|
cb68b10475 | ||
|
|
11c854ce44 | ||
|
|
9636f4742b | ||
|
|
5867317526 | ||
|
|
8a8f7b6903 | ||
|
|
61b6e25a91 | ||
|
|
50cff820de | ||
|
|
4e586a28c8 | ||
|
|
0702b4ed57 | ||
|
|
4a2132a682 | ||
|
|
ba81d1d6a9 | ||
|
|
402ce4b3ec | ||
|
|
fc713453ad | ||
|
|
b222ccffbb | ||
|
|
56ce7329d2 | ||
|
|
99ab6db557 | ||
|
|
d7adf96f3a | ||
|
|
0ae58c61a9 | ||
|
|
2ec7d1d2f1 | ||
|
|
ad1b9059ee | ||
|
|
4439c7cce6 | ||
|
|
b8a4093c75 | ||
|
|
ec3748b26e | ||
|
|
1c1f22e047 | ||
|
|
9aa9b0fc5a | ||
|
|
f8e2ca8500 | ||
|
|
3076e29335 | ||
|
|
fe616d86c5 | ||
|
|
bfa4856bbe | ||
|
|
5ea92a7b48 | ||
|
|
4ba71db7b2 | ||
|
|
c1e6aeb43c | ||
|
|
e3ffb66ef0 | ||
|
|
5daa82b0ba | ||
|
|
a8bcc6afba | ||
|
|
e6aa16ad01 | ||
|
|
ad0705d126 | ||
|
|
2f31f93bf8 | ||
|
|
ea3be613c5 | ||
|
|
b495246f34 | ||
|
|
814470f4bf | ||
|
|
82293a08b6 | ||
|
|
20d66336a7 | ||
|
|
c8441ec9fa | ||
|
|
f72135c227 | ||
|
|
100e6e4ce8 | ||
|
|
ec8be20d62 | ||
|
|
55d48101ef | ||
|
|
c36f4c5f84 | ||
|
|
06289ac4d2 | ||
|
|
e6a2d5d425 | ||
|
|
ea8db9c4ea | ||
|
|
3773e841d1 | ||
|
|
ad1ddd04f3 | ||
|
|
67a8b232b9 | ||
|
|
5293c07fc0 | ||
|
|
e3a42db007 | ||
|
|
3b1462af22 | ||
|
|
74a0c5b1cd | ||
|
|
05a5e4fa64 | ||
|
|
b6445295a7 | ||
|
|
391605ef36 | ||
|
|
695499dea9 | ||
|
|
9ba7f35444 | ||
|
|
37dc00735b | ||
|
|
920cbadc91 | ||
|
|
bc53b4dc32 | ||
|
|
6015c38d17 | ||
|
|
4ea8694a7d | ||
|
|
00f01196fb | ||
|
|
543639c93e | ||
|
|
1da877fed7 | ||
|
|
396b5fc156 | ||
|
|
297dfd4159 | ||
|
|
23e9d48b0d | ||
|
|
9ec650a84f | ||
|
|
90bdbc4ae0 | ||
|
|
dd5f06723b | ||
|
|
55b2871b83 |
No files matched your search
@@ -1,2 +1,4 @@
|
|||||||
**/xcuserdata/
|
**/xcuserdata/
|
||||||
|
**/Moonlight.xcscmblueprint
|
||||||
Build
|
Build
|
||||||
|
DerivedData
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
[submodule "limelight-common-c"]
|
[submodule "moonlight-common/moonlight-common-c"]
|
||||||
path = limelight-common-c
|
path = moonlight-common/moonlight-common-c
|
||||||
url = git@github.com:limelight-stream/limelight-common-c.git
|
url = https://github.com/moonlight-stream/moonlight-common-c.git
|
||||||
@@ -1,36 +1,51 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8121.17" systemVersion="15A204h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A279b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
<navigationController id="vV9-32-ww6">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
|
||||||
<subviews>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Moonlight Stream. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<rect key="frame" x="18" y="439.5" width="444" height="20.5"/>
|
<animations/>
|
||||||
<animations/>
|
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
</navigationBar>
|
||||||
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<viewControllers>
|
||||||
<nil key="highlightedColor"/>
|
<viewController id="l6V-ue-5Om">
|
||||||
<variation key="widthClass=compact">
|
<layoutGuides>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
<viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
|
||||||
</variation>
|
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
|
||||||
</label>
|
</layoutGuides>
|
||||||
</subviews>
|
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
|
||||||
<animations/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
<animations/>
|
||||||
<constraints>
|
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/>
|
</view>
|
||||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
||||||
</constraints>
|
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
<rect key="frame" x="-23" y="-15" width="46" height="30"/>
|
||||||
<point key="canvasLocation" x="404" y="445"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
</view>
|
<animations/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
|
<state key="normal" title="Moonlight" image="Logo">
|
||||||
|
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</state>
|
||||||
|
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
|
||||||
|
</button>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
</viewController>
|
||||||
|
</viewControllers>
|
||||||
|
</navigationController>
|
||||||
</objects>
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<image name="Logo" width="32" height="32"/>
|
||||||
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// AppCollectionView.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppCollectionView : UICollectionView
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// AppCollectionView.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppCollectionView.h"
|
||||||
|
|
||||||
|
@implementation AppCollectionView
|
||||||
|
|
||||||
|
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
|
||||||
|
if ([view isKindOfClass:[UIButton class]]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return [super touchesShouldCancelInContentView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override drawRect: if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
- (void)drawRect:(CGRect)rect {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
|
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
|
||||||
if (managedObjectContext != nil) {
|
if (managedObjectContext != nil) {
|
||||||
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||||
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
|
||||||
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
|
|||||||
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
||||||
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
|
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
|
||||||
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
|
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
|
||||||
/*
|
// Log the error
|
||||||
Replace this implementation with code to handle the error appropriately.
|
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||||
|
|
||||||
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
// Drop the database
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
|
||||||
Typical reasons for an error here include:
|
|
||||||
* The persistent store is not accessible;
|
// Try again
|
||||||
* The schema for the persistent store is incompatible with current managed object model.
|
return [self persistentStoreCoordinator];
|
||||||
Check the error message to determine what the actual problem was.
|
}
|
||||||
|
|
||||||
|
|
||||||
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
|
|
||||||
|
|
||||||
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
|
|
||||||
* Simply deleting the existing store:
|
|
||||||
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
|
|
||||||
|
|
||||||
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
|
|
||||||
@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
|
|
||||||
|
|
||||||
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
|
|
||||||
|
|
||||||
*/
|
|
||||||
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _persistentStoreCoordinator;
|
return _persistentStoreCoordinator;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// ComputerScrollView.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface ComputerScrollView : UIScrollView
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// ComputerScrollView.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ComputerScrollView.h"
|
||||||
|
|
||||||
|
@implementation ComputerScrollView
|
||||||
|
|
||||||
|
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
|
||||||
|
if ([view isKindOfClass:[UIButton class]]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return [super touchesShouldCancelInContentView:view];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override drawRect: if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
- (void)drawRect:(CGRect)rect {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -11,15 +11,16 @@
|
|||||||
@interface CryptoManager : NSObject
|
@interface CryptoManager : NSObject
|
||||||
|
|
||||||
+ (void) generateKeyPairUsingSSl;
|
+ (void) generateKeyPairUsingSSl;
|
||||||
+ (NSString*) getUniqueID;
|
|
||||||
+ (NSData*) readCertFromFile;
|
+ (NSData*) readCertFromFile;
|
||||||
+ (NSData*) readKeyFromFile;
|
+ (NSData*) readKeyFromFile;
|
||||||
+ (NSData*) readP12FromFile;
|
+ (NSData*) readP12FromFile;
|
||||||
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
||||||
+ (NSData*) nullTerminateString:(NSData*)data;
|
+ (NSData*) nullTerminateString:(NSData*)data;
|
||||||
|
|
||||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN;
|
- (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN;
|
||||||
|
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN;
|
||||||
- (NSData*) SHA1HashData:(NSData*)data;
|
- (NSData*) SHA1HashData:(NSData*)data;
|
||||||
|
- (NSData*) SHA256HashData:(NSData*)data;
|
||||||
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
|
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
|
||||||
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
|
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
|
||||||
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
|
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "mkcert.h"
|
#import "mkcert.h"
|
||||||
#import <AdSupport/ASIdentifierManager.h>
|
|
||||||
|
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
@@ -17,19 +16,31 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
@implementation CryptoManager
|
@implementation CryptoManager
|
||||||
static const int SHA1_DIGEST_LENGTH = 20;
|
static const int SHA1_HASH_LENGTH = 20;
|
||||||
|
static const int SHA256_HASH_LENGTH = 32;
|
||||||
static NSData* key = nil;
|
static NSData* key = nil;
|
||||||
static NSData* cert = nil;
|
static NSData* cert = nil;
|
||||||
static NSData* p12 = nil;
|
static NSData* p12 = nil;
|
||||||
|
|
||||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN {
|
- (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN {
|
||||||
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN {
|
||||||
|
return [[self SHA256HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSData*) SHA1HashData:(NSData*)data {
|
- (NSData*) SHA1HashData:(NSData*)data {
|
||||||
unsigned char sha1[SHA1_DIGEST_LENGTH];
|
unsigned char sha1[SHA1_HASH_LENGTH];
|
||||||
SHA1([data bytes], [data length], sha1);
|
SHA1([data bytes], [data length], sha1);
|
||||||
NSData* bytes = [NSData dataWithBytes:sha1 length:20];
|
NSData* bytes = [NSData dataWithBytes:sha1 length:sizeof(sha1)];
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData*) SHA256HashData:(NSData*)data {
|
||||||
|
unsigned char sha256[SHA256_HASH_LENGTH];
|
||||||
|
SHA256([data bytes], [data length], sha256);
|
||||||
|
NSData* bytes = [NSData dataWithBytes:sha256 length:sizeof(sha256)];
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,18 +240,4 @@ static NSData* p12 = nil;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString*) getUniqueID {
|
|
||||||
// generate a UUID
|
|
||||||
NSUUID* uuid = [ASIdentifierManager sharedManager].advertisingIdentifier;
|
|
||||||
NSString* idString = [NSString stringWithString:[uuid UUIDString]];
|
|
||||||
|
|
||||||
// we need a 16byte hex-string so we take the last 17 characters
|
|
||||||
// and remove the '-' to get a 16 character string
|
|
||||||
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
|
|
||||||
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
|
|
||||||
|
|
||||||
//Log(LOG_D, @"Unique ID: %@", uniqueId);
|
|
||||||
return [NSString stringWithString:uniqueId];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// IdManager.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 10/31/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface IdManager : NSObject
|
||||||
|
|
||||||
|
+ (NSString*) getUniqueId;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// IdManager.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 10/31/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "IdManager.h"
|
||||||
|
#import "DataManager.h"
|
||||||
|
|
||||||
|
@implementation IdManager
|
||||||
|
|
||||||
|
+ (NSString*) getUniqueId {
|
||||||
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
|
|
||||||
|
NSString* uniqueId = [dataMan getUniqueId];
|
||||||
|
if (uniqueId == nil) {
|
||||||
|
uniqueId = [IdManager generateUniqueId];
|
||||||
|
[dataMan updateUniqueId:uniqueId];
|
||||||
|
Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueId;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*) generateUniqueId {
|
||||||
|
UInt64 uuidLong = ((UInt64) arc4random() << 32) | arc4random();
|
||||||
|
return [NSString stringWithFormat:@"%016llx", uuidLong];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
|||||||
|
|
||||||
if (*pkeyp == NULL) {
|
if (*pkeyp == NULL) {
|
||||||
if ((pk=EVP_PKEY_new()) == NULL) {
|
if ((pk=EVP_PKEY_new()) == NULL) {
|
||||||
abort();
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -102,7 +101,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
|||||||
|
|
||||||
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
||||||
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
||||||
abort();
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,8 @@
|
|||||||
|
|
||||||
@class Host;
|
@class Host;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@interface App : NSManagedObject
|
@interface App : NSManagedObject
|
||||||
|
|
||||||
@property BOOL isRunning;
|
|
||||||
|
|
||||||
- (NSComparisonResult)compareName:(App *)other;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
|
||||||
#import "App+CoreDataProperties.h"
|
#import "App+CoreDataProperties.h"
|
||||||
@@ -7,14 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "App.h"
|
#import "App.h"
|
||||||
#import "Host.h"
|
|
||||||
|
|
||||||
@implementation App
|
@implementation App
|
||||||
|
|
||||||
@synthesize isRunning;
|
|
||||||
|
|
||||||
- (NSComparisonResult)compareName:(App *)other {
|
|
||||||
return [self.name caseInsensitiveCompare:other.name];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -7,22 +7,25 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Settings.h"
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
|
#import "TemporarySettings.h"
|
||||||
|
|
||||||
@interface DataManager : NSObject
|
@interface DataManager : NSObject
|
||||||
|
|
||||||
@property (strong, nonatomic) AppDelegate* appDelegate;
|
|
||||||
|
|
||||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
|
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
|
||||||
- (Settings*) retrieveSettings;
|
|
||||||
- (NSArray*) retrieveHosts;
|
- (NSArray*) getHosts;
|
||||||
- (void) saveData;
|
- (void) updateHost:(TemporaryHost*)host;
|
||||||
- (Host*) createHost;
|
- (void) updateAppsForExistingHost:(TemporaryHost *)host;
|
||||||
- (void) removeHost:(Host*)host;
|
- (void) updateIconForExistingApp:(TemporaryApp*)app;
|
||||||
- (App*) createApp;
|
- (void) removeHost:(TemporaryHost*)host;
|
||||||
- (void) removeApp:(App*)app;
|
- (void) removeApp:(TemporaryApp*)app;
|
||||||
|
|
||||||
|
- (TemporarySettings*) getSettings;
|
||||||
|
|
||||||
|
- (void) updateUniqueId:(NSString*)uniqueId;
|
||||||
|
- (NSString*) getUniqueId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -7,37 +7,132 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
#import "TemporarySettings.h"
|
||||||
|
#import "Settings.h"
|
||||||
|
|
||||||
@implementation DataManager
|
@implementation DataManager {
|
||||||
|
NSManagedObjectContext *_managedObjectContext;
|
||||||
|
AppDelegate *_appDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
- (id) init {
|
- (id) init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
self.appDelegate = [[UIApplication sharedApplication] delegate];
|
|
||||||
|
_appDelegate = [[UIApplication sharedApplication] delegate];
|
||||||
|
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
|
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
|
- (void) updateUniqueId:(NSString*)uniqueId {
|
||||||
Settings* settingsToSave = [self retrieveSettings];
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
[self retrieveSettings].uniqueId = uniqueId;
|
||||||
// Bitrate is persisted in kbps
|
[self saveData];
|
||||||
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
|
}];
|
||||||
settingsToSave.height = [NSNumber numberWithInteger:height];
|
}
|
||||||
settingsToSave.width = [NSNumber numberWithInteger:width];
|
|
||||||
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
|
|
||||||
|
|
||||||
NSError* error;
|
- (NSString*) getUniqueId {
|
||||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
__block NSString *uid;
|
||||||
Log(LOG_E, @"Unable to save settings to database: %@", error);
|
|
||||||
}
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
[self.appDelegate saveContext];
|
uid = [self retrieveSettings].uniqueId;
|
||||||
|
}];
|
||||||
|
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
|
||||||
|
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
Settings* settingsToSave = [self retrieveSettings];
|
||||||
|
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
||||||
|
// Bitrate is persisted in kbps
|
||||||
|
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
|
||||||
|
settingsToSave.height = [NSNumber numberWithInteger:height];
|
||||||
|
settingsToSave.width = [NSNumber numberWithInteger:width];
|
||||||
|
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
|
||||||
|
|
||||||
|
[self saveData];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateHost:(TemporaryHost *)host {
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
// Add a new persistent managed object if one doesn't exist
|
||||||
|
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
|
||||||
|
if (parent == nil) {
|
||||||
|
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:_managedObjectContext];
|
||||||
|
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push changes from the temp host to the persistent one
|
||||||
|
[host propagateChangesToParent:parent];
|
||||||
|
|
||||||
|
[self saveData];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateAppsForExistingHost:(TemporaryHost *)host {
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
|
||||||
|
if (parent == nil) {
|
||||||
|
// The host must exist to be updated
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableSet *applist = [[NSMutableSet alloc] init];
|
||||||
|
NSArray *appRecords = [self fetchRecords:@"App"];
|
||||||
|
for (TemporaryApp* app in host.appList) {
|
||||||
|
// Add a new persistent managed object if one doesn't exist
|
||||||
|
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:appRecords];
|
||||||
|
if (parentApp == nil) {
|
||||||
|
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:_managedObjectContext];
|
||||||
|
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
|
||||||
|
}
|
||||||
|
|
||||||
|
[app propagateChangesToParent:parentApp withHost:parent];
|
||||||
|
|
||||||
|
[applist addObject:parentApp];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.appList = applist;
|
||||||
|
|
||||||
|
[self saveData];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateIconForExistingApp:(TemporaryApp*)app {
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
|
||||||
|
if (parentApp == nil) {
|
||||||
|
// The app must exist to be updated
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentApp.image = app.image;
|
||||||
|
|
||||||
|
[self saveData];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (TemporarySettings*) getSettings {
|
||||||
|
__block TemporarySettings *tempSettings;
|
||||||
|
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
tempSettings = [[TemporarySettings alloc] initFromSettings:[self retrieveSettings]];
|
||||||
|
}];
|
||||||
|
|
||||||
|
return tempSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Settings*) retrieveSettings {
|
- (Settings*) retrieveSettings {
|
||||||
NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
|
NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
|
||||||
if (fetchedRecords.count == 0) {
|
if (fetchedRecords.count == 0) {
|
||||||
// create a new settings object with the default values
|
// create a new settings object with the default values
|
||||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:_managedObjectContext];
|
||||||
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
} else {
|
} else {
|
||||||
@@ -46,49 +141,84 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Host*) createHost {
|
- (void) removeApp:(TemporaryApp*)app {
|
||||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
|
||||||
|
if (managedApp != nil) {
|
||||||
|
[_managedObjectContext deleteObject:managedApp];
|
||||||
|
[self saveData];
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeHost:(Host*)host {
|
- (void) removeHost:(TemporaryHost*)host {
|
||||||
[[self.appDelegate managedObjectContext] deleteObject:host];
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
[self saveData];
|
Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
|
||||||
|
if (managedHost != nil) {
|
||||||
|
[_managedObjectContext deleteObject:managedHost];
|
||||||
|
[self saveData];
|
||||||
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) saveData {
|
- (void) saveData {
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
if (![_managedObjectContext save:&error]) {
|
||||||
Log(LOG_E, @"Unable to save hosts to database: %@", error);
|
Log(LOG_E, @"Unable to save hosts to database: %@", error);
|
||||||
}
|
}
|
||||||
[self.appDelegate saveContext];
|
|
||||||
|
[_appDelegate saveContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*) retrieveHosts {
|
- (NSArray*) getHosts {
|
||||||
return [self fetchRecords:@"Host"];
|
__block NSMutableArray *tempHosts = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
[_managedObjectContext performBlockAndWait:^{
|
||||||
|
NSArray *hosts = [self fetchRecords:@"Host"];
|
||||||
|
|
||||||
|
for (Host* host in hosts) {
|
||||||
|
[tempHosts addObject:[[TemporaryHost alloc] initFromHost:host]];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
return tempHosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (App*) createApp {
|
// Only call from within performBlockAndWait!!!
|
||||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
- (Host*) getHostForTemporaryHost:(TemporaryHost*)tempHost withHostRecords:(NSArray*)hosts {
|
||||||
return [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
for (Host* host in hosts) {
|
||||||
|
if ([tempHost.uuid isEqualToString:host.uuid]) {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeApp:(App*)app {
|
// Only call from within performBlockAndWait!!!
|
||||||
[[self.appDelegate managedObjectContext] deleteObject:app];
|
- (App*) getAppForTemporaryApp:(TemporaryApp*)tempApp withAppRecords:(NSArray*)apps {
|
||||||
|
for (App* app in apps) {
|
||||||
|
if ([app.id isEqualToString:tempApp.id] &&
|
||||||
|
[app.host.uuid isEqualToString:app.host.uuid]) {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*) fetchRecords:(NSString*)entityName {
|
- (NSArray*) fetchRecords:(NSString*)entityName {
|
||||||
|
NSArray* fetchedRecords;
|
||||||
|
|
||||||
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
|
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
|
||||||
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:_managedObjectContext];
|
||||||
[fetchRequest setEntity:entity];
|
[fetchRequest setEntity:entity];
|
||||||
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
|
|
||||||
|
|
||||||
NSError* error;
|
NSError* error;
|
||||||
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
|
fetchedRecords = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
|
||||||
//TODO: handle errors
|
//TODO: handle errors
|
||||||
|
|
||||||
return fetchedRecords;
|
return fetchedRecords;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,16 +10,8 @@
|
|||||||
#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) BOOL online;
|
|
||||||
@property (nonatomic) PairState pairState;
|
|
||||||
@property (nonatomic) NSString * activeAddress;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
||||||
|
|
||||||
#import "Host+CoreDataProperties.h"
|
#import "Host+CoreDataProperties.h"
|
||||||
@@ -10,8 +10,4 @@
|
|||||||
|
|
||||||
@implementation Host
|
@implementation Host
|
||||||
|
|
||||||
@dynamic pairState;
|
|
||||||
@synthesize online;
|
|
||||||
@synthesize activeAddress;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -17,5 +17,6 @@
|
|||||||
@property (nonatomic, retain) NSNumber * height;
|
@property (nonatomic, retain) NSNumber * height;
|
||||||
@property (nonatomic, retain) NSNumber * width;
|
@property (nonatomic, retain) NSNumber * width;
|
||||||
@property (nonatomic, retain) NSNumber * onscreenControls;
|
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||||
|
@property (nonatomic, retain) NSString * uniqueId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
@dynamic height;
|
@dynamic height;
|
||||||
@dynamic width;
|
@dynamic width;
|
||||||
@dynamic onscreenControls;
|
@dynamic onscreenControls;
|
||||||
|
@dynamic uniqueId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// TemporaryApp.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "TemporaryHost.h"
|
||||||
|
#import "App.h"
|
||||||
|
|
||||||
|
@interface TemporaryApp : NSObject
|
||||||
|
|
||||||
|
@property (nullable, nonatomic, retain) NSString *id;
|
||||||
|
@property (nullable, nonatomic, retain) NSData *image;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *name;
|
||||||
|
@property (nullable, nonatomic, retain) TemporaryHost *host;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(TemporaryApp *)other;
|
||||||
|
|
||||||
|
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// TemporaryApp.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 9/30/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
#import "App.h"
|
||||||
|
|
||||||
|
@implementation TemporaryApp
|
||||||
|
|
||||||
|
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost {
|
||||||
|
self = [self init];
|
||||||
|
|
||||||
|
self.id = app.id;
|
||||||
|
self.image = app.image;
|
||||||
|
self.name = app.name;
|
||||||
|
self.host = tempHost;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host {
|
||||||
|
parent.id = self.id;
|
||||||
|
parent.name = self.name;
|
||||||
|
parent.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(TemporaryApp *)other {
|
||||||
|
return [self.name caseInsensitiveCompare:other.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
return [self.host.uuid hash] * 31 + [self.id intValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
if (self == object) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![object isKindOfClass:[App class]]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self.host.uuid isEqualToString:((App*)object).host.uuid] &&
|
||||||
|
[self.id isEqualToString:((App*)object).id];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// TemporaryHost.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 12/1/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Utils.h"
|
||||||
|
#import "Host.h"
|
||||||
|
|
||||||
|
@interface TemporaryHost : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic) BOOL online;
|
||||||
|
@property (nonatomic) PairState pairState;
|
||||||
|
@property (nonatomic, nullable) NSString * activeAddress;
|
||||||
|
@property (nonatomic, nullable) NSString * currentGame;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@property (nonatomic, retain) NSString *address;
|
||||||
|
@property (nonatomic, retain) NSString *externalAddress;
|
||||||
|
@property (nonatomic, retain) NSString *localAddress;
|
||||||
|
@property (nonatomic, retain) NSString *mac;
|
||||||
|
@property (nonatomic, retain) NSString *name;
|
||||||
|
@property (nonatomic, retain) NSString *uuid;
|
||||||
|
@property (nonatomic, retain) NSMutableSet *appList;
|
||||||
|
|
||||||
|
- (id) initFromHost:(Host*)host;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(TemporaryHost *)other;
|
||||||
|
|
||||||
|
- (void) propagateChangesToParent:(Host*)host;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// TemporaryHost.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 12/1/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "DataManager.h"
|
||||||
|
#import "TemporaryHost.h"
|
||||||
|
#import "Host.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
#import "App.h"
|
||||||
|
|
||||||
|
@implementation TemporaryHost
|
||||||
|
|
||||||
|
- (id) init {
|
||||||
|
self = [super init];
|
||||||
|
self.appList = [[NSMutableSet alloc] init];
|
||||||
|
self.currentGame = @"0";
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initFromHost:(Host*)host {
|
||||||
|
self = [self init];
|
||||||
|
|
||||||
|
self.address = host.address;
|
||||||
|
self.externalAddress = host.externalAddress;
|
||||||
|
self.localAddress = host.localAddress;
|
||||||
|
self.mac = host.mac;
|
||||||
|
self.name = host.name;
|
||||||
|
self.uuid = host.uuid;
|
||||||
|
self.pairState = [host.pairState intValue];
|
||||||
|
|
||||||
|
NSMutableSet *appList = [[NSMutableSet alloc] init];
|
||||||
|
|
||||||
|
for (App* app in host.appList) {
|
||||||
|
TemporaryApp *tempApp = [[TemporaryApp alloc] initFromApp:app withTempHost:self];
|
||||||
|
[appList addObject:tempApp];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.appList = appList;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) propagateChangesToParent:(Host*)parentHost {
|
||||||
|
parentHost.address = self.address;
|
||||||
|
parentHost.externalAddress = self.externalAddress;
|
||||||
|
parentHost.localAddress = self.localAddress;
|
||||||
|
parentHost.mac = self.mac;
|
||||||
|
parentHost.name = self.name;
|
||||||
|
parentHost.uuid = self.uuid;
|
||||||
|
parentHost.pairState = [NSNumber numberWithInt:self.pairState];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(TemporaryHost *)other {
|
||||||
|
return [self.name caseInsensitiveCompare:other.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)hash {
|
||||||
|
return [self.uuid hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isEqual:(id)object {
|
||||||
|
if (self == object) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![object isKindOfClass:[Host class]]) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self.uuid isEqualToString:((Host*)object).uuid];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// TemporarySettings.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 12/1/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Settings.h"
|
||||||
|
|
||||||
|
@interface TemporarySettings : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, retain) Settings * parent;
|
||||||
|
|
||||||
|
@property (nonatomic, retain) NSNumber * bitrate;
|
||||||
|
@property (nonatomic, retain) NSNumber * framerate;
|
||||||
|
@property (nonatomic, retain) NSNumber * height;
|
||||||
|
@property (nonatomic, retain) NSNumber * width;
|
||||||
|
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||||
|
@property (nonatomic, retain) NSString * uniqueId;
|
||||||
|
|
||||||
|
- (id) initFromSettings:(Settings*)settings;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// TemporarySettings.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Cameron Gutman on 12/1/15.
|
||||||
|
// Copyright © 2015 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "TemporarySettings.h"
|
||||||
|
|
||||||
|
@implementation TemporarySettings
|
||||||
|
|
||||||
|
- (id) initFromSettings:(Settings*)settings {
|
||||||
|
self = [self init];
|
||||||
|
|
||||||
|
self.parent = settings;
|
||||||
|
|
||||||
|
self.bitrate = settings.bitrate;
|
||||||
|
self.framerate = settings.framerate;
|
||||||
|
self.height = settings.height;
|
||||||
|
self.width = settings.width;
|
||||||
|
self.onscreenControls = settings.onscreenControls;
|
||||||
|
self.uniqueId = settings.uniqueId;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "a_button_80x80@2x.png",
|
||||||
"filename" : "a_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "a_button_120x120@3x.png",
|
||||||
"filename" : "a_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "a_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -71,6 +71,12 @@
|
|||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_152x152_@2x.png",
|
"filename" : "app_icon_152x152_@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "app_icon_167x167_@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
After Width: | Height: | Size: 59 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "b_button_80x80@2x.png",
|
||||||
"filename" : "b_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "b_button_120x120@3x.png",
|
||||||
"filename" : "b_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "b_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "down_61x75@2x.png",
|
||||||
"filename" : "down_31x38@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "down_93x114@3x.png",
|
||||||
"filename" : "down_61x75@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "down_93x114@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "left_76x61@2x.png",
|
||||||
"filename" : "left_38x31@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "left_114x92@3x.png",
|
||||||
"filename" : "left_76x61@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "left_114x92@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "pull-arrow-light-14x31@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "pull-arrow-light-28x61@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "pull-arrow-light-42x92@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 901 B |
|
After Width: | Height: | Size: 812 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "right_75x61@2x.png",
|
||||||
"filename" : "right_38x31@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "right_114x93@3x.png",
|
||||||
"filename" : "right_75x61@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "right_114x93@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "up_61x76@2x.png",
|
||||||
"filename" : "up_31x39@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "up_93x116@3x.png",
|
||||||
"filename" : "up_61x76@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "up_93x116@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "x_button_80x80@2x.png",
|
||||||
"filename" : "x_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "x_button_120x120@3x.png",
|
||||||
"filename" : "x_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "x_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "y_button_80x80@2x.png",
|
||||||
"filename" : "y_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "y_button_120x120@3x.png",
|
||||||
"filename" : "y_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "y_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// Controller.h
|
|
||||||
// Moonlight
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 2/1/15.
|
|
||||||
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface Controller : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic) int playerIndex;
|
|
||||||
@property (nonatomic) int lastButtonFlags;
|
|
||||||
@property (nonatomic) int emulatingButtonFlags;
|
|
||||||
@property (nonatomic) char lastLeftTrigger;
|
|
||||||
@property (nonatomic) char lastRightTrigger;
|
|
||||||
@property (nonatomic) short lastLeftStickX;
|
|
||||||
@property (nonatomic) short lastLeftStickY;
|
|
||||||
@property (nonatomic) short lastRightStickX;
|
|
||||||
@property (nonatomic) short lastRightStickY;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// Controller.m
|
|
||||||
// Moonlight
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 2/1/15.
|
|
||||||
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "Controller.h"
|
|
||||||
|
|
||||||
@implementation Controller
|
|
||||||
@synthesize playerIndex;
|
|
||||||
@synthesize lastButtonFlags, emulatingButtonFlags, lastLeftTrigger, lastRightTrigger;
|
|
||||||
@synthesize lastLeftStickX, lastLeftStickY, lastRightStickX, lastRightStickY;
|
|
||||||
@end
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Controller.swift
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by David Aghassi on 4/11/16.
|
||||||
|
// Copyright © 2016 Moonlight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc
|
||||||
|
/**
|
||||||
|
Defines a controller layout
|
||||||
|
*/
|
||||||
|
class Controller: NSObject {
|
||||||
|
// Swift requires initial properties
|
||||||
|
var playerIndex: CInt = 0 // Controller number (e.g. 1, 2 ,3 etc)
|
||||||
|
var lastButtonFlags: CInt = 0
|
||||||
|
var emulatingButtonFlags: CInt = 0
|
||||||
|
var lastLeftTrigger: CChar = 0 // Last left trigger pressed
|
||||||
|
var lastRightTrigger: CChar = 0 // Last right trigger pressed
|
||||||
|
var lastLeftStickX: CShort = 0 // Last X direction the left joystick went
|
||||||
|
var lastLeftStickY: CShort = 0 // Last Y direction the left joystick went
|
||||||
|
var lastRightStickX: CShort = 0 // Last X direction the right joystick went
|
||||||
|
var lastRightStickY: CShort = 0 // Last Y direction the right joystick went
|
||||||
|
}
|
||||||
@@ -7,7 +7,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Controller.h"
|
|
||||||
|
// Swift
|
||||||
|
#import "Moonlight-Swift.h"
|
||||||
|
@class Controller;
|
||||||
|
|
||||||
@class OnScreenControls;
|
@class OnScreenControls;
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@
|
|||||||
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
|
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
|
||||||
|
|
||||||
-(void) updateFinished:(Controller*)controller;
|
-(void) updateFinished:(Controller*)controller;
|
||||||
|
-(Controller*) getOscController;
|
||||||
|
|
||||||
@property (nonatomic, strong) id connectObserver;
|
@property (nonatomic, strong) id connectObserver;
|
||||||
@property (nonatomic, strong) id disconnectObserver;
|
@property (nonatomic, strong) id disconnectObserver;
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
#import "ControllerSupport.h"
|
#import "ControllerSupport.h"
|
||||||
#import "OnScreenControls.h"
|
#import "OnScreenControls.h"
|
||||||
#import "Controller.h"
|
|
||||||
#include "Limelight.h"
|
#include "Limelight.h"
|
||||||
|
|
||||||
|
// Swift
|
||||||
|
#import "Moonlight-Swift.h"
|
||||||
|
@class Controller;
|
||||||
|
|
||||||
@import GameController;
|
@import GameController;
|
||||||
|
|
||||||
@implementation ControllerSupport {
|
@implementation ControllerSupport {
|
||||||
@@ -19,6 +22,10 @@
|
|||||||
|
|
||||||
OnScreenControls *_osc;
|
OnScreenControls *_osc;
|
||||||
|
|
||||||
|
// This controller object is shared between on-screen controls
|
||||||
|
// and player 0
|
||||||
|
Controller *_player0osc;
|
||||||
|
|
||||||
char _controllerNumbers;
|
char _controllerNumbers;
|
||||||
|
|
||||||
#define EMULATING_SELECT 0x1
|
#define EMULATING_SELECT 0x1
|
||||||
@@ -272,9 +279,17 @@
|
|||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (!(_controllerNumbers & (1 << i))) {
|
if (!(_controllerNumbers & (1 << i))) {
|
||||||
_controllerNumbers |= (1 << i);
|
_controllerNumbers |= (1 << i);
|
||||||
Controller* limeController = [[Controller alloc] init];
|
|
||||||
controller.playerIndex = i;
|
controller.playerIndex = i;
|
||||||
limeController.playerIndex = i;
|
|
||||||
|
Controller* limeController;
|
||||||
|
if (i == 0) {
|
||||||
|
// Player 0 shares a controller object with the on-screen controls
|
||||||
|
limeController = _player0osc;
|
||||||
|
} else {
|
||||||
|
limeController = [[Controller alloc] init];
|
||||||
|
limeController.playerIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||||
|
|
||||||
Log(LOG_I, @"Assigning controller index: %d", i);
|
Log(LOG_I, @"Assigning controller index: %d", i);
|
||||||
@@ -283,6 +298,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(Controller*) getOscController {
|
||||||
|
return _player0osc;
|
||||||
|
}
|
||||||
|
|
||||||
-(id) init
|
-(id) init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
@@ -290,6 +309,8 @@
|
|||||||
_controllerStreamLock = [[NSLock alloc] init];
|
_controllerStreamLock = [[NSLock alloc] init];
|
||||||
_controllers = [[NSMutableDictionary alloc] init];
|
_controllers = [[NSMutableDictionary alloc] init];
|
||||||
_controllerNumbers = 0;
|
_controllerNumbers = 0;
|
||||||
|
_player0osc = [[Controller alloc] init];
|
||||||
|
_player0osc.playerIndex = 0;
|
||||||
|
|
||||||
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
|
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
|
||||||
for (GCController* controller in [GCController controllers]) {
|
for (GCController* controller in [GCController controllers]) {
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
//
|
||||||
|
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||||
|
//
|
||||||
|
|
||||||
@@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
#import "OnScreenControls.h"
|
#import "OnScreenControls.h"
|
||||||
#import "ControllerSupport.h"
|
#import "ControllerSupport.h"
|
||||||
#import "Controller.h"
|
//#import "Controller.h"
|
||||||
#include "Limelight.h"
|
#include "Limelight.h"
|
||||||
|
|
||||||
|
#import "Moonlight-Swift.h"
|
||||||
|
@class Controller;
|
||||||
|
|
||||||
#define UPDATE_BUTTON(x, y) (buttonFlags = \
|
#define UPDATE_BUTTON(x, y) (buttonFlags = \
|
||||||
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
|
(y) ? (buttonFlags | (x)) : (buttonFlags & ~(x)))
|
||||||
|
|
||||||
@@ -41,10 +44,7 @@
|
|||||||
UITouch* _bTouch;
|
UITouch* _bTouch;
|
||||||
UITouch* _xTouch;
|
UITouch* _xTouch;
|
||||||
UITouch* _yTouch;
|
UITouch* _yTouch;
|
||||||
UITouch* _upTouch;
|
UITouch* _dpadTouch;
|
||||||
UITouch* _downTouch;
|
|
||||||
UITouch* _leftTouch;
|
|
||||||
UITouch* _rightTouch;
|
|
||||||
UITouch* _lsTouch;
|
UITouch* _lsTouch;
|
||||||
UITouch* _rsTouch;
|
UITouch* _rsTouch;
|
||||||
UITouch* _startTouch;
|
UITouch* _startTouch;
|
||||||
@@ -63,25 +63,30 @@
|
|||||||
BOOL l3Set;
|
BOOL l3Set;
|
||||||
BOOL r3Set;
|
BOOL r3Set;
|
||||||
|
|
||||||
|
BOOL _iPad;
|
||||||
|
CGRect _controlArea;
|
||||||
UIView* _view;
|
UIView* _view;
|
||||||
OnScreenControlsLevel _level;
|
OnScreenControlsLevel _level;
|
||||||
|
|
||||||
ControllerSupport *_controllerSupport;
|
ControllerSupport *_controllerSupport;
|
||||||
Controller *_controller;
|
Controller *_controller;
|
||||||
id<EdgeDetectionDelegate> _edgeDelegate;
|
id<EdgeDetectionDelegate> _edgeDelegate;
|
||||||
|
NSMutableArray* _deadTouches;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float EDGE_WIDTH = .1;
|
static const float EDGE_WIDTH = .05;
|
||||||
|
|
||||||
//static const float BUTTON_SIZE = 50;
|
//static const float BUTTON_SIZE = 50;
|
||||||
static const float BUTTON_DIST = 20;
|
static const float BUTTON_DIST = 20;
|
||||||
static float BUTTON_CENTER_X;
|
static float BUTTON_CENTER_X;
|
||||||
static float BUTTON_CENTER_Y;
|
static float BUTTON_CENTER_Y;
|
||||||
|
|
||||||
static const float D_PAD_DIST = 15;
|
static const float D_PAD_DIST = 10;
|
||||||
static float D_PAD_CENTER_X;
|
static float D_PAD_CENTER_X;
|
||||||
static float D_PAD_CENTER_Y;
|
static float D_PAD_CENTER_Y;
|
||||||
|
|
||||||
|
static const float DEAD_ZONE_PADDING = 15;
|
||||||
|
|
||||||
static const double STICK_CLICK_RATE = 100;
|
static const double STICK_CLICK_RATE = 100;
|
||||||
static const float STICK_DEAD_ZONE = .1;
|
static const float STICK_DEAD_ZONE = .1;
|
||||||
static float STICK_INNER_SIZE;
|
static float STICK_INNER_SIZE;
|
||||||
@@ -114,9 +119,23 @@ static float L3_Y;
|
|||||||
self = [self init];
|
self = [self init];
|
||||||
_view = view;
|
_view = view;
|
||||||
_controllerSupport = controllerSupport;
|
_controllerSupport = controllerSupport;
|
||||||
_controller = [[Controller alloc] init];
|
_controller = [controllerSupport getOscController];
|
||||||
_controller.playerIndex = 0;
|
|
||||||
_edgeDelegate = swipeDelegate;
|
_edgeDelegate = swipeDelegate;
|
||||||
|
_deadTouches = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
_iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
|
||||||
|
_controlArea = CGRectMake(0, 0, _view.frame.size.width, _view.frame.size.height);
|
||||||
|
if (_iPad)
|
||||||
|
{
|
||||||
|
// Cut down the control area on an iPad so the controls are more reachable
|
||||||
|
_controlArea.size.height = _view.frame.size.height / 2.0;
|
||||||
|
_controlArea.origin.y = _view.frame.size.height - _controlArea.size.height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_controlArea.origin.x = _controlArea.size.width * EDGE_WIDTH;
|
||||||
|
_controlArea.size.width -= _controlArea.origin.x * 2;
|
||||||
|
}
|
||||||
|
|
||||||
_aButton = [CALayer layer];
|
_aButton = [CALayer layer];
|
||||||
_bButton = [CALayer layer];
|
_bButton = [CALayer layer];
|
||||||
@@ -139,7 +158,7 @@ static float L3_Y;
|
|||||||
_leftStick = [CALayer layer];
|
_leftStick = [CALayer layer];
|
||||||
_rightStick = [CALayer layer];
|
_rightStick = [CALayer layer];
|
||||||
_edge = [CALayer layer];
|
_edge = [CALayer layer];
|
||||||
|
|
||||||
[self setupEdgeDetection];
|
[self setupEdgeDetection];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -167,10 +186,10 @@ static float L3_Y;
|
|||||||
|
|
||||||
[self hideButtons];
|
[self hideButtons];
|
||||||
[self hideBumpers];
|
[self hideBumpers];
|
||||||
|
[self hideL3R3];
|
||||||
[self drawTriggers];
|
[self drawTriggers];
|
||||||
[self drawStartSelect];
|
[self drawStartSelect];
|
||||||
[self drawSticks];
|
[self drawSticks];
|
||||||
[self drawL3R3];
|
|
||||||
break;
|
break;
|
||||||
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
||||||
// GCExtendedGamepad is missing R3, L3, and select
|
// GCExtendedGamepad is missing R3, L3, and select
|
||||||
@@ -219,8 +238,8 @@ static float L3_Y;
|
|||||||
// Start with the default complex layout
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
|
|
||||||
START_Y = _view.frame.size.height * .9;
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
SELECT_Y = _view.frame.size.height * .9;
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For GCGamepad controls we move triggers, start, and select
|
// For GCGamepad controls we move triggers, start, and select
|
||||||
@@ -229,7 +248,42 @@ static float L3_Y;
|
|||||||
// Start with the default complex layout
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
|
|
||||||
// TODO
|
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
|
||||||
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
|
||||||
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
|
|
||||||
|
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
|
|
||||||
|
if (_iPad) {
|
||||||
|
START_X = _controlArea.size.width * .75 + _controlArea.origin.x;
|
||||||
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
SELECT_X = _controlArea.size.width * .25 + _controlArea.origin.x;
|
||||||
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
// The analog sticks are kept closer to the sides on iPad
|
||||||
|
LS_CENTER_X = _controlArea.size.width * .18 + _controlArea.origin.x;
|
||||||
|
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
RS_CENTER_X = _controlArea.size.width * .82 + _controlArea.origin.x;
|
||||||
|
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
} else {
|
||||||
|
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
|
||||||
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
|
||||||
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
LS_CENTER_X = _controlArea.size.width * .25 + _controlArea.origin.x;
|
||||||
|
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
RS_CENTER_X = _controlArea.size.width * .75 + _controlArea.origin.x;
|
||||||
|
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For simple controls we move the triggers and buttons to the bottom
|
// For simple controls we move the triggers and buttons to the bottom
|
||||||
@@ -237,46 +291,59 @@ static float L3_Y;
|
|||||||
// Start with the default complex layout
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
|
|
||||||
START_Y = _view.frame.size.height * .9;
|
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
|
||||||
SELECT_Y = _view.frame.size.height * .9;
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
|
||||||
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
|
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
|
|
||||||
L1_Y = _view.frame.size.height * .7;
|
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
L2_Y = _view.frame.size.height * .9;
|
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
L2_X = _view.frame.size.width * .1;
|
|
||||||
R1_Y = _view.frame.size.height * .7;
|
|
||||||
R2_Y = _view.frame.size.height * .9;
|
|
||||||
R2_X = _view.frame.size.width * .9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setupComplexControls
|
- (void) setupComplexControls
|
||||||
{
|
{
|
||||||
D_PAD_CENTER_X = _view.frame.size.width * .15;
|
D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
D_PAD_CENTER_Y = _view.frame.size.height * .55;
|
D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||||
BUTTON_CENTER_X = _view.frame.size.width * .85;
|
BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
BUTTON_CENTER_Y = _view.frame.size.height * .55;
|
BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||||
|
|
||||||
LS_CENTER_X = _view.frame.size.width * .35;
|
if (_iPad)
|
||||||
LS_CENTER_Y = _view.frame.size.height * .75;
|
{
|
||||||
RS_CENTER_X = _view.frame.size.width * .65;
|
// The analog sticks are kept closer to the sides on iPad
|
||||||
RS_CENTER_Y = _view.frame.size.height * .75;
|
LS_CENTER_X = _controlArea.size.width * .22 + _controlArea.origin.x;
|
||||||
|
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
RS_CENTER_X = _controlArea.size.width * .77 + _controlArea.origin.x;
|
||||||
|
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LS_CENTER_X = _controlArea.size.width * .35 + _controlArea.origin.x;
|
||||||
|
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
RS_CENTER_X = _controlArea.size.width * .65 + _controlArea.origin.x;
|
||||||
|
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
|
}
|
||||||
|
|
||||||
START_X = _view.frame.size.width * .6;
|
START_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
START_Y = _view.frame.size.height * .1;
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
SELECT_X = _view.frame.size.width * .4;
|
SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
SELECT_Y = _view.frame.size.height * .1;
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
L1_X = _view.frame.size.width * .15;
|
L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
L1_Y = _view.frame.size.height * .27;
|
L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||||
L2_X = _view.frame.size.width * .15;
|
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
L2_Y = _view.frame.size.height * .1;
|
L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||||
R1_X = _view.frame.size.width * .85;
|
R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
R1_Y = _view.frame.size.height * .27;
|
R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||||
R2_X = _view.frame.size.width * .85;
|
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
R2_Y = _view.frame.size.height * .1;
|
R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||||
L3_X = _view.frame.size.width * .25;
|
L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
|
||||||
L3_Y = _view.frame.size.height * .75;
|
L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
R3_X = _view.frame.size.width * .75;
|
R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
|
||||||
R3_Y = _view.frame.size.height * .75;
|
R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) drawButtons {
|
- (void) drawButtons {
|
||||||
@@ -285,43 +352,43 @@ static float L3_Y;
|
|||||||
_aButton.contents = (id) aButtonImage.CGImage;
|
_aButton.contents = (id) aButtonImage.CGImage;
|
||||||
_aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height);
|
_aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height);
|
||||||
[_view.layer addSublayer:_aButton];
|
[_view.layer addSublayer:_aButton];
|
||||||
|
|
||||||
// create B button
|
// create B button
|
||||||
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
|
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
|
||||||
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height);
|
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height);
|
||||||
_bButton.contents = (id) bButtonImage.CGImage;
|
_bButton.contents = (id) bButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_bButton];
|
[_view.layer addSublayer:_bButton];
|
||||||
|
|
||||||
// create X Button
|
// create X Button
|
||||||
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
|
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
|
||||||
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height);
|
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height);
|
||||||
_xButton.contents = (id) xButtonImage.CGImage;
|
_xButton.contents = (id) xButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_xButton];
|
[_view.layer addSublayer:_xButton];
|
||||||
|
|
||||||
// create Y Button
|
// create Y Button
|
||||||
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
|
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
|
||||||
_yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height);
|
_yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height);
|
||||||
_yButton.contents = (id) yButtonImage.CGImage;
|
_yButton.contents = (id) yButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_yButton];
|
[_view.layer addSublayer:_yButton];
|
||||||
|
|
||||||
// create Down button
|
// create Down button
|
||||||
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
|
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
|
||||||
_downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height);
|
_downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height);
|
||||||
_downButton.contents = (id) downButtonImage.CGImage;
|
_downButton.contents = (id) downButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_downButton];
|
[_view.layer addSublayer:_downButton];
|
||||||
|
|
||||||
// create Right button
|
// create Right button
|
||||||
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
|
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
|
||||||
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height);
|
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height);
|
||||||
_rightButton.contents = (id) rightButtonImage.CGImage;
|
_rightButton.contents = (id) rightButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_rightButton];
|
[_view.layer addSublayer:_rightButton];
|
||||||
|
|
||||||
// create Up button
|
// create Up button
|
||||||
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
|
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
|
||||||
_upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height);
|
_upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height);
|
||||||
_upButton.contents = (id) upButtonImage.CGImage;
|
_upButton.contents = (id) upButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_upButton];
|
[_view.layer addSublayer:_upButton];
|
||||||
|
|
||||||
// create Left button
|
// create Left button
|
||||||
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
|
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
|
||||||
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height);
|
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height);
|
||||||
@@ -335,7 +402,7 @@ static float L3_Y;
|
|||||||
_startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height);
|
_startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height);
|
||||||
_startButton.contents = (id) startButtonImage.CGImage;
|
_startButton.contents = (id) startButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_startButton];
|
[_view.layer addSublayer:_startButton];
|
||||||
|
|
||||||
// create Select button
|
// create Select button
|
||||||
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
|
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
|
||||||
_selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
|
_selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
|
||||||
@@ -382,7 +449,7 @@ static float L3_Y;
|
|||||||
_leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height);
|
_leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height);
|
||||||
_leftStick.contents = (id) leftStickImage.CGImage;
|
_leftStick.contents = (id) leftStickImage.CGImage;
|
||||||
[_view.layer addSublayer:_leftStick];
|
[_view.layer addSublayer:_leftStick];
|
||||||
|
|
||||||
// create right analog stick
|
// create right analog stick
|
||||||
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
|
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
|
||||||
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
|
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
|
||||||
@@ -463,7 +530,7 @@ static float L3_Y;
|
|||||||
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
|
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
|
||||||
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
|
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
|
||||||
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
|
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
|
||||||
|
|
||||||
for (UITouch* touch in touches) {
|
for (UITouch* touch in touches) {
|
||||||
CGPoint touchLocation = [touch locationInView:_view];
|
CGPoint touchLocation = [touch locationInView:_view];
|
||||||
float xLoc = touchLocation.x;
|
float xLoc = touchLocation.x;
|
||||||
@@ -473,35 +540,55 @@ static float L3_Y;
|
|||||||
if (xLoc < lsMinX) xLoc = lsMinX;
|
if (xLoc < lsMinX) xLoc = lsMinX;
|
||||||
if (yLoc > lsMaxY) yLoc = lsMaxY;
|
if (yLoc > lsMaxY) yLoc = lsMaxY;
|
||||||
if (yLoc < lsMinY) yLoc = lsMinY;
|
if (yLoc < lsMinY) yLoc = lsMinY;
|
||||||
|
|
||||||
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
||||||
|
|
||||||
float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
|
float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
|
||||||
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
|
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
|
||||||
|
|
||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _rsTouch) {
|
} else if (touch == _rsTouch) {
|
||||||
if (xLoc > rsMaxX) xLoc = rsMaxX;
|
if (xLoc > rsMaxX) xLoc = rsMaxX;
|
||||||
if (xLoc < rsMinX) xLoc = rsMinX;
|
if (xLoc < rsMinX) xLoc = rsMinX;
|
||||||
if (yLoc > rsMaxY) yLoc = rsMaxY;
|
if (yLoc > rsMaxY) yLoc = rsMaxY;
|
||||||
if (yLoc < rsMinY) yLoc = rsMinY;
|
if (yLoc < rsMinY) yLoc = rsMinY;
|
||||||
|
|
||||||
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
||||||
|
|
||||||
float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
|
float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
|
||||||
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
|
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
|
||||||
|
|
||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
|
} else if (touch == _dpadTouch) {
|
||||||
|
[_controllerSupport clearButtonFlag:_controller
|
||||||
|
flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
|
||||||
|
|
||||||
|
// Allow the user to slide their finger to another d-pad button
|
||||||
|
if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
||||||
|
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
||||||
|
updated = true;
|
||||||
|
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
||||||
|
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
||||||
|
updated = true;
|
||||||
|
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
||||||
|
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
||||||
|
updated = true;
|
||||||
|
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
||||||
|
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonTouch = true;
|
||||||
} else if (touch == _aTouch) {
|
} else if (touch == _aTouch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
} else if (touch == _bTouch) {
|
} else if (touch == _bTouch) {
|
||||||
@@ -510,14 +597,6 @@ static float L3_Y;
|
|||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
} else if (touch == _yTouch) {
|
} else if (touch == _yTouch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
} else if (touch == _upTouch) {
|
|
||||||
buttonTouch = true;
|
|
||||||
} else if (touch == _downTouch) {
|
|
||||||
buttonTouch = true;
|
|
||||||
} else if (touch == _leftTouch) {
|
|
||||||
buttonTouch = true;
|
|
||||||
} else if (touch == _rightTouch) {
|
|
||||||
buttonTouch = true;
|
|
||||||
} else if (touch == _startTouch) {
|
} else if (touch == _startTouch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
} else if (touch == _selectTouch) {
|
} else if (touch == _selectTouch) {
|
||||||
@@ -535,11 +614,14 @@ static float L3_Y;
|
|||||||
} else if (touch == _r3Touch) {
|
} else if (touch == _r3Touch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
}
|
}
|
||||||
|
if ([_deadTouches containsObject:touch]) {
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
return updated || buttonTouch;
|
return updated || buttonTouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)handleTouchDownEvent:touches {
|
- (BOOL)handleTouchDownEvent:touches {
|
||||||
@@ -566,19 +648,19 @@ static float L3_Y;
|
|||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
||||||
_upTouch = touch;
|
_dpadTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
||||||
_downTouch = touch;
|
_dpadTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
||||||
_leftTouch = touch;
|
_dpadTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
||||||
_rightTouch = touch;
|
_dpadTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_startButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_startButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
|
||||||
@@ -653,6 +735,10 @@ static float L3_Y;
|
|||||||
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
|
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
|
||||||
_edgeTouch = touch;
|
_edgeTouch = touch;
|
||||||
}
|
}
|
||||||
|
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
|
||||||
|
[_deadTouches addObject:touch];
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
@@ -680,21 +766,10 @@ static float L3_Y;
|
|||||||
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
|
||||||
_yTouch = nil;
|
_yTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _upTouch) {
|
} else if (touch == _dpadTouch) {
|
||||||
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG];
|
[_controllerSupport clearButtonFlag:_controller
|
||||||
_upTouch = nil;
|
flags:UP_FLAG | DOWN_FLAG | LEFT_FLAG | RIGHT_FLAG];
|
||||||
updated = true;
|
_dpadTouch = nil;
|
||||||
} else if (touch == _downTouch) {
|
|
||||||
[_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
|
|
||||||
_downTouch = nil;
|
|
||||||
updated = true;
|
|
||||||
} else if (touch == _leftTouch) {
|
|
||||||
[_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
|
|
||||||
_leftTouch = nil;
|
|
||||||
updated = true;
|
|
||||||
} else if (touch == _rightTouch) {
|
|
||||||
[_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
|
|
||||||
_rightTouch = nil;
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _startTouch) {
|
} else if (touch == _startTouch) {
|
||||||
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
|
||||||
@@ -744,15 +819,123 @@ static float L3_Y;
|
|||||||
touched = true;
|
touched = true;
|
||||||
} else if (touch == _edgeTouch) {
|
} else if (touch == _edgeTouch) {
|
||||||
_edgeTouch = nil;
|
_edgeTouch = nil;
|
||||||
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) {
|
if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
|
||||||
[_edgeDelegate edgeSwiped];
|
[_edgeDelegate edgeSwiped];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ([_deadTouches containsObject:touch]) {
|
||||||
|
[_deadTouches removeObject:touch];
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated || touched;
|
return updated || touched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) isInDeadZone:(UITouch*) touch {
|
||||||
|
switch (_level) {
|
||||||
|
case OnScreenControlsLevelFull:
|
||||||
|
return [self isDpadDeadZone:touch]
|
||||||
|
|| [self isAbxyDeadZone:touch]
|
||||||
|
|| [self isTriggerDeadZone:touch]
|
||||||
|
|| [self isBumperDeadZone:touch]
|
||||||
|
|| [self isStartSelectDeadZone:touch];
|
||||||
|
case OnScreenControlsLevelSimple:
|
||||||
|
return [self isTriggerDeadZone:touch]
|
||||||
|
|| [self isStartSelectDeadZone:touch]
|
||||||
|
|| [self isL3R3DeadZone:touch];
|
||||||
|
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
||||||
|
return [self isL3R3DeadZone:touch]
|
||||||
|
|| [self isStartSelectDeadZone:touch];
|
||||||
|
case OnScreenControlsLevelAutoGCGamepad:
|
||||||
|
return [self isTriggerDeadZone:touch]
|
||||||
|
|| [self isStartSelectDeadZone:touch];
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isDpadDeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_view.frame.origin.x
|
||||||
|
startY:_upButton.frame.origin.y
|
||||||
|
endX:_rightButton.frame.origin.x + _rightButton.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isAbxyDeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_xButton.frame.origin.x
|
||||||
|
startY:_yButton.frame.origin.y
|
||||||
|
endX:_view.frame.origin.x + _view.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isBumperDeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_view.frame.origin.x
|
||||||
|
startY:_l2Button.frame.origin.y + _l2Button.frame.size.height
|
||||||
|
endX:_l1Button.frame.origin.x + _l1Button.frame.size.width
|
||||||
|
endY:_upButton.frame.origin.y]
|
||||||
|
|| [self isDeadZone:touch
|
||||||
|
startX:_r2Button.frame.origin.x
|
||||||
|
startY:_r2Button.frame.origin.y + _r2Button.frame.size.height
|
||||||
|
endX:_view.frame.origin.x + _view.frame.size.width
|
||||||
|
endY:_yButton.frame.origin.y];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isTriggerDeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_view.frame.origin.x
|
||||||
|
startY:_l2Button.frame.origin.y
|
||||||
|
endX:_l2Button.frame.origin.x + _l2Button.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height]
|
||||||
|
|| [self isDeadZone:touch
|
||||||
|
startX:_r2Button.frame.origin.x
|
||||||
|
startY:_r2Button.frame.origin.y
|
||||||
|
endX:_view.frame.origin.x + _view.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isL3R3DeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_view.frame.origin.x
|
||||||
|
startY:_l3Button.frame.origin.y
|
||||||
|
endX:_view.frame.origin.x
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height]
|
||||||
|
|| [self isDeadZone:touch
|
||||||
|
startX:_r3Button.frame.origin.x
|
||||||
|
startY:_r3Button.frame.origin.y
|
||||||
|
endX:_view.frame.origin.x + _view.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isStartSelectDeadZone:(UITouch*) touch {
|
||||||
|
return [self isDeadZone:touch
|
||||||
|
startX:_startButton.frame.origin.x
|
||||||
|
startY:_startButton.frame.origin.y
|
||||||
|
endX:_view.frame.origin.x + _view.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height]
|
||||||
|
|| [self isDeadZone:touch
|
||||||
|
startX:_view.frame.origin.x
|
||||||
|
startY:_selectButton.frame.origin.y
|
||||||
|
endX:_selectButton.frame.origin.x + _selectButton.frame.size.width
|
||||||
|
endY:_view.frame.origin.y + _view.frame.size.height];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isDeadZone:(UITouch*) touch startX:(float)deadZoneStartX startY:(float)deadZoneStartY endX:(float)deadZoneEndX endY:(float)deadZoneEndY {
|
||||||
|
deadZoneStartX -= DEAD_ZONE_PADDING;
|
||||||
|
deadZoneStartY -= DEAD_ZONE_PADDING;
|
||||||
|
deadZoneEndX += DEAD_ZONE_PADDING;
|
||||||
|
deadZoneEndY += DEAD_ZONE_PADDING;
|
||||||
|
|
||||||
|
CGPoint touchLocation = [touch locationInView:_view];
|
||||||
|
return (touchLocation.x > deadZoneStartX && touchLocation.x < deadZoneEndX
|
||||||
|
&& touchLocation.y > deadZoneStartY && touchLocation.y < deadZoneEndY);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
BOOL touchMoved;
|
BOOL touchMoved;
|
||||||
OnScreenControls* onScreenControls;
|
OnScreenControls* onScreenControls;
|
||||||
|
|
||||||
|
BOOL isDragging;
|
||||||
|
NSTimer* dragTimer;
|
||||||
|
|
||||||
float xDeltaFactor;
|
float xDeltaFactor;
|
||||||
float yDeltaFactor;
|
float yDeltaFactor;
|
||||||
float screenFactor;
|
float screenFactor;
|
||||||
@@ -32,7 +35,7 @@
|
|||||||
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
|
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
|
||||||
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
|
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue];
|
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue];
|
||||||
|
|
||||||
if (level == OnScreenControlsLevelAuto) {
|
if (level == OnScreenControlsLevelAuto) {
|
||||||
[controllerSupport initAutoOnScreenControlMode:onScreenControls];
|
[controllerSupport initAutoOnScreenControlMode:onScreenControls];
|
||||||
@@ -49,11 +52,27 @@
|
|||||||
UITouch *touch = [[event allTouches] anyObject];
|
UITouch *touch = [[event allTouches] anyObject];
|
||||||
touchLocation = [touch locationInView:self];
|
touchLocation = [touch locationInView:self];
|
||||||
touchMoved = false;
|
touchMoved = false;
|
||||||
|
if ([[event allTouches] count] == 1 && !isDragging) {
|
||||||
|
dragTimer = [NSTimer scheduledTimerWithTimeInterval:0.650
|
||||||
|
target:self
|
||||||
|
selector:@selector(onDragStart:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)onDragStart:(NSTimer*)timer {
|
||||||
|
if (!touchMoved && !isDragging){
|
||||||
|
isDragging = true;
|
||||||
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
|
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||||
if (![onScreenControls handleTouchMovedEvent:touches]) {
|
if (![onScreenControls handleTouchMovedEvent:touches]) {
|
||||||
|
[dragTimer invalidate];
|
||||||
|
dragTimer = nil;
|
||||||
if ([[event allTouches] count] == 1) {
|
if ([[event allTouches] count] == 1) {
|
||||||
UITouch *touch = [[event allTouches] anyObject];
|
UITouch *touch = [[event allTouches] anyObject];
|
||||||
CGPoint currentLocation = [touch locationInView:self];
|
CGPoint currentLocation = [touch locationInView:self];
|
||||||
@@ -67,15 +86,16 @@
|
|||||||
deltaX *= xDeltaFactor * screenFactor;
|
deltaX *= xDeltaFactor * screenFactor;
|
||||||
deltaY *= yDeltaFactor * screenFactor;
|
deltaY *= yDeltaFactor * screenFactor;
|
||||||
|
|
||||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
|
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||||
touchMoved = true;
|
touchMoved = true;
|
||||||
touchLocation = currentLocation;
|
touchLocation = currentLocation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ([[event allTouches] count] == 2) {
|
} else if ([[event allTouches] count] == 2) {
|
||||||
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
|
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
|
||||||
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
|
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
|
||||||
|
|
||||||
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
|
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
|
||||||
if (touchLocation.y != avgLocation.y) {
|
if (touchLocation.y != avgLocation.y) {
|
||||||
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
||||||
@@ -90,29 +110,35 @@
|
|||||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||||
Log(LOG_D, @"Touch up");
|
Log(LOG_D, @"Touch up");
|
||||||
if (![onScreenControls handleTouchUpEvent:touches]) {
|
if (![onScreenControls handleTouchUpEvent:touches]) {
|
||||||
|
[dragTimer invalidate];
|
||||||
|
dragTimer = nil;
|
||||||
if (!touchMoved) {
|
if (!touchMoved) {
|
||||||
if ([[event allTouches] count] == 2) {
|
if ([[event allTouches] count] == 2) {
|
||||||
Log(LOG_D, @"Sending right mouse button press");
|
Log(LOG_D, @"Sending right mouse button press");
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
|
|
||||||
// Wait 100 ms to simulate a real button press
|
// Wait 100 ms to simulate a real button press
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log(LOG_D, @"Sending left mouse button press");
|
if (!isDragging){
|
||||||
|
Log(LOG_D, @"Sending left mouse button press");
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
|
||||||
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
// Wait 100 ms to simulate a real button press
|
|
||||||
usleep(100 * 1000);
|
// Wait 100 ms to simulate a real button press
|
||||||
|
usleep(100 * 1000);
|
||||||
|
}
|
||||||
|
isDragging = false;
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (isDragging) {
|
||||||
|
isDragging = false;
|
||||||
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.9.2</string>
|
<string>1.1.4</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2</string>
|
<string>1</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>
|
||||||
@@ -50,9 +50,9 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>armv7</string>
|
<string>armv7</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIStatusBarHidden</key>
|
<key>UIRequiresFullScreen</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIStatusBarHidden~ipad</key>
|
<key>UIStatusBarHidden</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -64,5 +64,7 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>_XCCurrentVersionName</key>
|
<key>_XCCurrentVersionName</key>
|
||||||
<string>Moonlight v1.0.xcdatamodel</string>
|
<string>Moonlight v1.0-2.xcdatamodel</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
|
||||||
|
<entity name="App" representedClassName="App" syncable="YES">
|
||||||
|
<attribute name="id" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
|
||||||
|
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="Host" representedClassName="Host" syncable="YES">
|
||||||
|
<attribute name="address" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="localAddress" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="mac" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="pairState" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||||
|
<attribute name="uuid" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<relationship name="appList" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="App" inverseName="host" inverseEntity="App" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="Settings" representedClassName="Settings" syncable="YES">
|
||||||
|
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" syncable="YES"/>
|
||||||
|
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
|
||||||
|
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
|
||||||
|
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
|
||||||
|
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<elements>
|
||||||
|
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
|
||||||
|
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
|
||||||
|
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
|
||||||
|
</elements>
|
||||||
|
</model>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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">
|
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
|
||||||
<entity name="App" representedClassName="App" syncable="YES">
|
<entity name="App" representedClassName="App" syncable="YES">
|
||||||
<attribute name="id" attributeType="String" syncable="YES"/>
|
<attribute name="id" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
|
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
|
||||||
@@ -21,11 +21,12 @@
|
|||||||
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
|
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
|
||||||
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
|
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
|
||||||
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
|
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
|
||||||
|
<attribute name="uniqueId" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
|
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
|
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
|
||||||
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
|
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
|
||||||
<element name="Settings" positionX="0" positionY="0" width="128" height="120"/>
|
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
||||||
@@ -7,20 +7,20 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
@protocol AppAssetCallback <NSObject>
|
@protocol AppAssetCallback <NSObject>
|
||||||
|
|
||||||
- (void) receivedAssetForApp:(App*)app;
|
- (void) receivedAssetForApp:(TemporaryApp*)app;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppAssetManager : NSObject
|
@interface AppAssetManager : NSObject
|
||||||
|
|
||||||
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
||||||
- (void) retrieveAssetsFromHost:(Host*)host;
|
- (void) retrieveAssetsFromHost:(TemporaryHost*)host;
|
||||||
- (void) stopRetrieving;
|
- (void) stopRetrieving;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -28,8 +28,8 @@ static const int MAX_REQUEST_COUNT = 4;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) retrieveAssetsFromHost:(Host*)host {
|
- (void) retrieveAssetsFromHost:(TemporaryHost*)host {
|
||||||
for (App* app in host.appList) {
|
for (TemporaryApp* app in host.appList) {
|
||||||
if (app.image == nil) {
|
if (app.image == nil) {
|
||||||
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
||||||
retriever.app = app;
|
retriever.app = app;
|
||||||
@@ -45,7 +45,7 @@ static const int MAX_REQUEST_COUNT = 4;
|
|||||||
[_opQueue cancelAllOperations];
|
[_opQueue cancelAllOperations];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) sendCallBackForApp:(App*)app {
|
- (void) sendCallBackForApp:(TemporaryApp*)app {
|
||||||
[_callback receivedAssetForApp:app];
|
[_callback receivedAssetForApp:app];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
#import "AppAssetManager.h"
|
#import "AppAssetManager.h"
|
||||||
|
|
||||||
@interface AppAssetRetriever : NSOperation
|
@interface AppAssetRetriever : NSOperation
|
||||||
|
|
||||||
@property (nonatomic) Host* host;
|
@property (nonatomic) TemporaryHost* host;
|
||||||
@property (nonatomic) App* app;
|
@property (nonatomic) TemporaryApp* app;
|
||||||
@property (nonatomic) id<AppAssetCallback> callback;
|
@property (nonatomic) id<AppAssetCallback> callback;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "AppAssetResponse.h"
|
#import "AppAssetResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation AppAssetRetriever
|
@implementation AppAssetRetriever
|
||||||
static const double RETRY_DELAY = 2; // seconds
|
static const double RETRY_DELAY = 2; // seconds
|
||||||
@@ -21,7 +22,7 @@ static const int MAX_ATTEMPTS = 5;
|
|||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
|
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
|
||||||
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
|
||||||
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
|
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ static const int MAX_ATTEMPTS = 5;
|
|||||||
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
|
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) sendCallbackForApp:(App*)app {
|
- (void) sendCallbackForApp:(TemporaryApp*)app {
|
||||||
[self.callback receivedAssetForApp:app];
|
[self.callback receivedAssetForApp:app];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
@interface AppListResponse : NSObject <Response>
|
@interface AppListResponse : NSObject <Response>
|
||||||
|
|
||||||
- (void)populateWithData:(NSData *)data;
|
- (void)populateWithData:(NSData *)data;
|
||||||
- (NSArray*) getAppList;
|
- (NSSet*) getAppList;
|
||||||
- (BOOL) isStatusOk;
|
- (BOOL) isStatusOk;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -7,23 +7,22 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "AppListResponse.h"
|
#import "AppListResponse.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import <libxml2/libxml/xmlreader.h>
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
@implementation AppListResponse {
|
@implementation AppListResponse {
|
||||||
NSMutableArray* _appList;
|
NSMutableSet* _appList;
|
||||||
}
|
}
|
||||||
@synthesize data, statusCode, statusMessage;
|
@synthesize data, statusCode, statusMessage;
|
||||||
|
|
||||||
static const char* TAG_APP = "App";
|
static const char* TAG_APP = "App";
|
||||||
static const char* TAG_APP_TITLE = "AppTitle";
|
static const char* TAG_APP_TITLE = "AppTitle";
|
||||||
static const char* TAG_APP_ID = "ID";
|
static const char* TAG_APP_ID = "ID";
|
||||||
static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|
||||||
|
|
||||||
- (void)populateWithData:(NSData *)xml {
|
- (void)populateWithData:(NSData *)xml {
|
||||||
self.data = xml;
|
self.data = xml;
|
||||||
_appList = [[NSMutableArray alloc] init];
|
_appList = [[NSMutableSet alloc] init];
|
||||||
[self parseData];
|
[self parseData];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +59,6 @@ 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);
|
||||||
@@ -68,7 +66,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|||||||
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
||||||
NSString* appName = @"";
|
NSString* appName = @"";
|
||||||
NSString* appId = nil;
|
NSString* appId = nil;
|
||||||
BOOL appIsRunning = NO;
|
|
||||||
while (appInfoNode != NULL) {
|
while (appInfoNode != NULL) {
|
||||||
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||||
@@ -84,22 +81,13 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|||||||
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||||
xmlFree(nodeVal);
|
xmlFree(nodeVal);
|
||||||
}
|
}
|
||||||
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
|
||||||
if (nodeVal != NULL) {
|
|
||||||
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else {
|
|
||||||
appIsRunning = NO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
appInfoNode = appInfoNode->next;
|
appInfoNode = appInfoNode->next;
|
||||||
}
|
}
|
||||||
if (appId != nil) {
|
if (appId != nil) {
|
||||||
App* app = [dataMan createApp];
|
TemporaryApp* app = [[TemporaryApp alloc] init];
|
||||||
app.name = appName;
|
app.name = appName;
|
||||||
app.id = appId;
|
app.id = appId;
|
||||||
app.isRunning = appIsRunning;
|
|
||||||
[_appList addObject:app];
|
[_appList addObject:app];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +97,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|||||||
xmlFreeDoc(docPtr);
|
xmlFreeDoc(docPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*) getAppList {
|
- (NSSet*) getAppList {
|
||||||
return _appList;
|
return _appList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "MDNSManager.h"
|
#import "MDNSManager.h"
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
@protocol DiscoveryCallback <NSObject>
|
@protocol DiscoveryCallback <NSObject>
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
- (void) startDiscovery;
|
- (void) startDiscovery;
|
||||||
- (void) stopDiscovery;
|
- (void) stopDiscovery;
|
||||||
- (void) stopDiscoveryBlocking;
|
- (void) stopDiscoveryBlocking;
|
||||||
- (BOOL) addHostToDiscovery:(Host*)host;
|
- (BOOL) addHostToDiscovery:(TemporaryHost*)host;
|
||||||
- (void) removeHostFromDiscovery:(Host*)host;
|
- (void) removeHostFromDiscovery:(TemporaryHost*)host;
|
||||||
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback;
|
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(TemporaryHost*, NSString*))callback;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -13,10 +13,10 @@
|
|||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import "DiscoveryWorker.h"
|
#import "DiscoveryWorker.h"
|
||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation DiscoveryManager {
|
@implementation DiscoveryManager {
|
||||||
NSMutableArray* _hostQueue;
|
NSMutableArray* _hostQueue;
|
||||||
NSMutableArray* _discoveredHosts;
|
|
||||||
id<DiscoveryCallback> _callback;
|
id<DiscoveryCallback> _callback;
|
||||||
MDNSManager* _mdnsMan;
|
MDNSManager* _mdnsMan;
|
||||||
NSOperationQueue* _opQueue;
|
NSOperationQueue* _opQueue;
|
||||||
@@ -27,37 +27,44 @@
|
|||||||
|
|
||||||
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
|
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_hostQueue = [NSMutableArray arrayWithArray:hosts];
|
|
||||||
|
// Using addHostToDiscovery ensures no duplicates
|
||||||
|
// will make it into the list from the database
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
|
shouldDiscover = NO;
|
||||||
|
_hostQueue = [NSMutableArray array];
|
||||||
|
for (TemporaryHost* host in hosts)
|
||||||
|
{
|
||||||
|
[self addHostToDiscovery:host];
|
||||||
|
}
|
||||||
|
[_callback updateAllHosts:_hostQueue];
|
||||||
|
|
||||||
_opQueue = [[NSOperationQueue alloc] init];
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
_mdnsMan = [[MDNSManager alloc] initWithCallback:self];
|
_mdnsMan = [[MDNSManager alloc] initWithCallback:self];
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
_uniqueId = [IdManager getUniqueId];
|
||||||
_cert = [CryptoManager readCertFromFile];
|
_cert = [CryptoManager readCertFromFile];
|
||||||
shouldDiscover = NO;
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback {
|
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(TemporaryHost *, NSString*))callback {
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
|
|
||||||
Host* host = nil;
|
TemporaryHost* host = nil;
|
||||||
if ([serverInfoResponse isStatusOk]) {
|
if ([serverInfoResponse isStatusOk]) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
host = [[TemporaryHost alloc] init];
|
||||||
host = [dataMan createHost];
|
|
||||||
host.activeAddress = host.address = hostAddress;
|
host.activeAddress = host.address = hostAddress;
|
||||||
host.online = YES;
|
host.online = YES;
|
||||||
[serverInfoResponse populateHost:host];
|
[serverInfoResponse populateHost:host];
|
||||||
if (![self addHostToDiscovery:host]) {
|
if (![self addHostToDiscovery:host]) {
|
||||||
[dataMan removeHost:host];
|
|
||||||
callback(nil, @"Host already added");
|
callback(nil, @"Host already added");
|
||||||
} else {
|
} else {
|
||||||
callback(host, nil);
|
callback(host, nil);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback(nil, @"Could not connect to host");
|
callback(nil, @"Could not connect to host. Ensure GameStream is enabled in GeForce Experience on your PC.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -66,7 +73,7 @@
|
|||||||
Log(LOG_I, @"Starting discovery");
|
Log(LOG_I, @"Starting discovery");
|
||||||
shouldDiscover = YES;
|
shouldDiscover = YES;
|
||||||
[_mdnsMan searchForHosts];
|
[_mdnsMan searchForHosts];
|
||||||
for (Host* host in _hostQueue) {
|
for (TemporaryHost* host in _hostQueue) {
|
||||||
[_opQueue addOperation:[self createWorkerForHost:host]];
|
[_opQueue addOperation:[self createWorkerForHost:host]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,18 +94,27 @@
|
|||||||
Log(LOG_I, @"All discovery workers stopped");
|
Log(LOG_I, @"All discovery workers stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) addHostToDiscovery:(Host *)host {
|
- (BOOL) addHostToDiscovery:(TemporaryHost *)host {
|
||||||
if (host.uuid.length > 0 && ![self isHostInDiscovery:host]) {
|
if (host.uuid.length == 0) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryHost *existingHost = [self getHostInDiscovery:host.uuid];
|
||||||
|
if (existingHost != nil) {
|
||||||
|
// Update address of existing host
|
||||||
|
existingHost.address = existingHost.activeAddress = host.address;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
else {
|
||||||
[_hostQueue addObject:host];
|
[_hostQueue addObject:host];
|
||||||
if (shouldDiscover) {
|
if (shouldDiscover) {
|
||||||
[_opQueue addOperation:[self createWorkerForHost:host]];
|
[_opQueue addOperation:[self createWorkerForHost:host]];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeHostFromDiscovery:(Host *)host {
|
- (void) removeHostFromDiscovery:(TemporaryHost *)host {
|
||||||
for (DiscoveryWorker* worker in [_opQueue operations]) {
|
for (DiscoveryWorker* worker in [_opQueue operations]) {
|
||||||
if ([worker getHost] == host) {
|
if ([worker getHost] == host) {
|
||||||
[worker cancel];
|
[worker cancel];
|
||||||
@@ -110,9 +126,8 @@
|
|||||||
// Override from MDNSCallback
|
// Override from MDNSCallback
|
||||||
- (void)updateHosts:(NSArray *)hosts {
|
- (void)updateHosts:(NSArray *)hosts {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
|
||||||
// Discover the hosts before adding to eliminate duplicates
|
// Discover the hosts before adding to eliminate duplicates
|
||||||
for (Host* host in hosts) {
|
for (TemporaryHost* host in hosts) {
|
||||||
Log(LOG_I, @"Found host through MDNS: %@:", host.name);
|
Log(LOG_I, @"Found host through MDNS: %@:", host.name);
|
||||||
// Since this is on a background thread, we do not need to use the opQueue
|
// Since this is on a background thread, we do not need to use the opQueue
|
||||||
DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host];
|
DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host];
|
||||||
@@ -122,24 +137,22 @@
|
|||||||
[_callback updateAllHosts:_hostQueue];
|
[_callback updateAllHosts:_hostQueue];
|
||||||
} else {
|
} else {
|
||||||
Log(LOG_I, @"Not adding host to discovery: %@", host.name);
|
Log(LOG_I, @"Not adding host to discovery: %@", host.name);
|
||||||
[dataMan removeHost:host];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[dataMan saveData];
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) isHostInDiscovery:(Host*)host {
|
- (TemporaryHost*) getHostInDiscovery:(NSString*)uuidString {
|
||||||
for (int i = 0; i < _hostQueue.count; i++) {
|
for (int i = 0; i < _hostQueue.count; i++) {
|
||||||
Host* discoveredHost = [_hostQueue objectAtIndex:i];
|
TemporaryHost* discoveredHost = [_hostQueue objectAtIndex:i];
|
||||||
if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:host.uuid]) {
|
if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:uuidString]) {
|
||||||
return YES;
|
return discoveredHost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NO;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSOperation*) createWorkerForHost:(Host*)host {
|
- (NSOperation*) createWorkerForHost:(TemporaryHost*)host {
|
||||||
DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert];
|
DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert];
|
||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
@interface DiscoveryWorker : NSOperation
|
@interface DiscoveryWorker : NSOperation
|
||||||
|
|
||||||
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert;
|
- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert;
|
||||||
- (void) discoverHost;
|
- (void) discoverHost;
|
||||||
- (Host*) getHost;
|
- (TemporaryHost*) getHost;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -11,16 +11,17 @@
|
|||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
#import "DataManager.h"
|
||||||
|
|
||||||
@implementation DiscoveryWorker {
|
@implementation DiscoveryWorker {
|
||||||
Host* _host;
|
TemporaryHost* _host;
|
||||||
NSString* _uniqueId;
|
NSString* _uniqueId;
|
||||||
NSData* _cert;
|
NSData* _cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
||||||
|
|
||||||
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert {
|
- (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_host = host;
|
_host = host;
|
||||||
_uniqueId = uniqueId;
|
_uniqueId = uniqueId;
|
||||||
@@ -28,7 +29,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Host*) getHost {
|
- (TemporaryHost*) getHost {
|
||||||
return _host;
|
return _host;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,20 +88,37 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
|
|
||||||
Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
|
Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
|
||||||
|
|
||||||
for (NSString *address in addresses) {
|
// Give the PC 3 tries to respond before declaring it offline
|
||||||
if (self.cancelled) {
|
for (int i = 0; i < 3; i++) {
|
||||||
// Get out without updating the status because
|
for (NSString *address in addresses) {
|
||||||
// it might not have finished checking the various
|
if (self.cancelled) {
|
||||||
// addresses
|
// Get out without updating the status because
|
||||||
return;
|
// it might not have finished checking the various
|
||||||
|
// addresses
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
|
||||||
|
receivedResponse = [self checkResponse:serverInfoResp];
|
||||||
|
if (receivedResponse) {
|
||||||
|
[serverInfoResp populateHost:_host];
|
||||||
|
_host.activeAddress = address;
|
||||||
|
|
||||||
|
// Update the database using the response
|
||||||
|
DataManager *dataManager = [[DataManager alloc] init];
|
||||||
|
[dataManager updateHost:_host];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
|
|
||||||
receivedResponse = [self checkResponse:serverInfoResp];
|
|
||||||
if (receivedResponse) {
|
if (receivedResponse) {
|
||||||
_host.activeAddress = address;
|
Log(LOG_I, @"Received serverinfo response on try %d", i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Wait for one second then retry
|
||||||
|
[NSThread sleepForTimeInterval:1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_host.online = receivedResponse;
|
_host.online = receivedResponse;
|
||||||
@@ -125,7 +143,6 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
if ([response isStatusOk]) {
|
if ([response isStatusOk]) {
|
||||||
// If the response is from a different host then do not update this host
|
// If the response is from a different host then do not update this host
|
||||||
if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) {
|
if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) {
|
||||||
[response populateHost:_host];
|
|
||||||
return YES;
|
return YES;
|
||||||
} else {
|
} else {
|
||||||
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
|
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
|
||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
|
|
||||||
#include <libxml2/libxml/xmlreader.h>
|
#include <libxml2/libxml/xmlreader.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -100,8 +100,8 @@ static const NSString* HTTPS_PORT = @"47984";
|
|||||||
NSURL* url = [[NSURL alloc] initWithString:urlString];
|
NSURL* url = [[NSURL alloc] initWithString:urlString];
|
||||||
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
||||||
if (normalTimeout) {
|
if (normalTimeout) {
|
||||||
// Timeout the request after 5 seconds
|
// Timeout the request after 7 seconds
|
||||||
[request setTimeoutInterval:5];
|
[request setTimeoutInterval:7];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Timeout the request after 60 seconds
|
// Timeout the request after 60 seconds
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
|
||||||
|
|
||||||
static NSString* TAG_STATUS_CODE = @"status_code";
|
static NSString* TAG_STATUS_CODE = @"status_code";
|
||||||
static NSString* TAG_STATUS_MESSAGE = @"status_message";
|
static NSString* TAG_STATUS_MESSAGE = @"status_message";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
#import <libxml2/libxml/xmlreader.h>
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
@implementation HttpResponse {
|
@implementation HttpResponse {
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "MDNSManager.h"
|
#import "MDNSManager.h"
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
#import "DataManager.h"
|
|
||||||
|
|
||||||
@implementation MDNSManager {
|
@implementation MDNSManager {
|
||||||
NSNetServiceBrowser* mDNSBrowser;
|
NSNetServiceBrowser* mDNSBrowser;
|
||||||
@@ -47,10 +46,9 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
|
|
||||||
- (NSArray*) getFoundHosts {
|
- (NSArray*) getFoundHosts {
|
||||||
NSMutableArray* hosts = [[NSMutableArray alloc] init];
|
NSMutableArray* hosts = [[NSMutableArray alloc] init];
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
|
||||||
for (NSNetService* service in services) {
|
for (NSNetService* service in services) {
|
||||||
if (service.hostName != nil) {
|
if (service.hostName != nil) {
|
||||||
Host* host = [dataMan createHost];
|
TemporaryHost* host = [[TemporaryHost alloc] init];
|
||||||
host.activeAddress = host.address = service.hostName;
|
host.activeAddress = host.address = service.hostName;
|
||||||
host.name = host.address;
|
host.name = host.address;
|
||||||
[hosts addObject:host];
|
[hosts addObject:host];
|
||||||
|
|||||||
@@ -22,6 +22,6 @@
|
|||||||
- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id<PairCallback>)callback;
|
- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert callback:(id<PairCallback>)callback;
|
||||||
- (NSString*) generatePIN;
|
- (NSString*) generatePIN;
|
||||||
- (NSData*) saltPIN:(NSString*)PIN;
|
- (NSData*) saltPIN:(NSString*)PIN;
|
||||||
- (void) initiatePair;
|
- (void) initiatePair:(int)serverMajorVersion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -38,17 +38,24 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ([serverInfoResp isStatusOk]) {
|
if ([serverInfoResp isStatusOk]) {
|
||||||
if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) {
|
if (![[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_AVAILABLE"]) {
|
||||||
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||||
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
||||||
[self initiatePair];
|
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
||||||
|
if (appversion == nil) {
|
||||||
|
[_callback pairFailed:@"Missing XML element"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[self initiatePair: [[appversion substringToIndex:1] intValue]];
|
||||||
} else {
|
} else {
|
||||||
[_callback alreadyPaired];
|
[_callback alreadyPaired];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) initiatePair {
|
- (void) initiatePair:(int)serverMajorVersion {
|
||||||
|
Log(LOG_I, @"Pairing with generation %d server", serverMajorVersion);
|
||||||
|
|
||||||
NSString* PIN = [self generatePIN];
|
NSString* PIN = [self generatePIN];
|
||||||
NSData* salt = [self saltPIN:PIN];
|
NSData* salt = [self saltPIN:PIN];
|
||||||
Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
|
Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
|
||||||
@@ -61,15 +68,29 @@
|
|||||||
}
|
}
|
||||||
NSInteger pairedStatus;
|
NSInteger pairedStatus;
|
||||||
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
|
||||||
[_callback pairFailed:@"Pairing was declined by the target."];
|
[_callback pairFailed:@"Pairing was declined by the target."];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* plainCert = [pairResp getStringTag:@"plaincert"];
|
NSString* plainCert = [pairResp getStringTag:@"plaincert"];
|
||||||
|
if ([plainCert length] == 0) {
|
||||||
|
[_callback pairFailed:@"Another pairing attempt is already in progress."];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
|
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
|
||||||
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
|
NSData* aesKey;
|
||||||
|
|
||||||
|
// Gen 7 servers use SHA256 to get the key
|
||||||
|
int hashLength;
|
||||||
|
if (serverMajorVersion >= 7) {
|
||||||
|
aesKey = [cryptoMan createAESKeyFromSaltSHA256:salt];
|
||||||
|
hashLength = 32;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
aesKey = [cryptoMan createAESKeyFromSaltSHA1:salt];
|
||||||
|
hashLength = 20;
|
||||||
|
}
|
||||||
|
|
||||||
NSData* randomChallenge = [Utils randomBytes:16];
|
NSData* randomChallenge = [Utils randomBytes:16];
|
||||||
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
||||||
@@ -88,11 +109,18 @@
|
|||||||
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]];
|
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]];
|
||||||
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
|
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
|
||||||
|
|
||||||
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
|
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, hashLength)];
|
||||||
NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(20, 16)];
|
NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(hashLength, 16)];
|
||||||
|
|
||||||
NSData* clientSecret = [Utils randomBytes:16];
|
NSData* clientSecret = [Utils randomBytes:16];
|
||||||
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
|
NSData* challengeRespHashInput = [self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret];
|
||||||
|
NSData* challengeRespHash;
|
||||||
|
if (serverMajorVersion >= 7) {
|
||||||
|
challengeRespHash = [cryptoMan SHA256HashData: challengeRespHashInput];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
challengeRespHash = [cryptoMan SHA1HashData: challengeRespHashInput];
|
||||||
|
}
|
||||||
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
||||||
|
|
||||||
HttpResponse* secretResp = [[HttpResponse alloc] init];
|
HttpResponse* secretResp = [[HttpResponse alloc] init];
|
||||||
@@ -116,7 +144,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
NSData* serverChallengeRespHashInput = [self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret];
|
||||||
|
NSData* serverChallengeRespHash;
|
||||||
|
if (serverMajorVersion >= 7) {
|
||||||
|
serverChallengeRespHash = [cryptoMan SHA256HashData: serverChallengeRespHashInput];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serverChallengeRespHash = [cryptoMan SHA1HashData: serverChallengeRespHashInput];
|
||||||
|
}
|
||||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Incorrect PIN"];
|
[_callback pairFailed:@"Incorrect PIN"];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
#define TAG_HOSTNAME @"hostname"
|
#define TAG_HOSTNAME @"hostname"
|
||||||
#define TAG_EXTERNAL_IP @"ExternalIP"
|
#define TAG_EXTERNAL_IP @"ExternalIP"
|
||||||
@@ -14,11 +15,13 @@
|
|||||||
#define TAG_UNIQUE_ID @"uniqueid"
|
#define TAG_UNIQUE_ID @"uniqueid"
|
||||||
#define TAG_MAC_ADDRESS @"mac"
|
#define TAG_MAC_ADDRESS @"mac"
|
||||||
#define TAG_PAIR_STATUS @"PairStatus"
|
#define TAG_PAIR_STATUS @"PairStatus"
|
||||||
|
#define TAG_STATE @"state"
|
||||||
|
#define TAG_CURRENT_GAME @"currentgame"
|
||||||
|
|
||||||
@interface ServerInfoResponse : HttpResponse <Response>
|
@interface ServerInfoResponse : HttpResponse <Response>
|
||||||
|
|
||||||
- (void) populateWithData:(NSData *)data;
|
- (void) populateWithData:(NSData *)data;
|
||||||
- (void) populateHost:(Host*)host;
|
- (void) populateHost:(TemporaryHost*)host;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -17,12 +17,21 @@
|
|||||||
[super parseData];
|
[super parseData];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) populateHost:(Host*)host {
|
- (void) populateHost:(TemporaryHost*)host {
|
||||||
host.name = [[self getStringTag:TAG_HOSTNAME] trim];
|
host.name = [[self getStringTag:TAG_HOSTNAME] trim];
|
||||||
host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim];
|
host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim];
|
||||||
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
|
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
|
||||||
host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim];
|
host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim];
|
||||||
host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim];
|
host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim];
|
||||||
|
host.currentGame = [[self getStringTag:TAG_CURRENT_GAME] trim];
|
||||||
|
|
||||||
|
NSString *state = [[self getStringTag:TAG_STATE] trim];
|
||||||
|
if ([state hasSuffix:@"_SERVER_AVAILABLE"]) {
|
||||||
|
// GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer
|
||||||
|
// has the semantics that its name would indicate. To contain the effects of this change as much
|
||||||
|
// as possible, we'll force the current game to zero if the server isn't in a streaming session.
|
||||||
|
host.currentGame = @"0";
|
||||||
|
}
|
||||||
|
|
||||||
NSInteger pairStatus;
|
NSInteger pairStatus;
|
||||||
if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) {
|
if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) {
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
@interface WakeOnLanManager : NSObject
|
@interface WakeOnLanManager : NSObject
|
||||||
|
|
||||||
+ (void) wakeHost:(Host*)host;
|
+ (void) wakeHost:(TemporaryHost*)host;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -12,51 +12,86 @@
|
|||||||
#import <sys/socket.h>
|
#import <sys/socket.h>
|
||||||
#import <netinet/in.h>
|
#import <netinet/in.h>
|
||||||
#import <arpa/inet.h>
|
#import <arpa/inet.h>
|
||||||
|
#import <netdb.h>
|
||||||
|
|
||||||
@implementation WakeOnLanManager
|
@implementation WakeOnLanManager
|
||||||
|
|
||||||
static const int numPorts = 5;
|
static const int numPorts = 5;
|
||||||
static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
||||||
|
|
||||||
+ (void) wakeHost:(Host*)host {
|
+ (void) populateAddress:(struct sockaddr_storage*)addr withPort:(unsigned short)port {
|
||||||
NSData* wolPayload = [WakeOnLanManager createPayload:host];
|
if (addr->ss_family == AF_INET) {
|
||||||
CFDataRef dataPayload = CFDataCreate(kCFAllocatorDefault, [wolPayload bytes], [wolPayload length]);
|
struct sockaddr_in *sin = (struct sockaddr_in*)addr;
|
||||||
CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL);
|
sin->sin_port = htons(port);
|
||||||
if (!wolSocket) {
|
|
||||||
CFRelease(dataPayload);
|
|
||||||
Log(LOG_E, @"Failed to create WOL socket");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
Log(LOG_I, @"WOL socket created");
|
else if (addr->ss_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
|
||||||
struct sockaddr_in addr;
|
sin6->sin6_port = htons(port);
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_len = sizeof(addr);
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
// try all ip addresses
|
|
||||||
if (i == 0) {
|
|
||||||
inet_aton([host.localAddress UTF8String], &addr.sin_addr);
|
|
||||||
} else {
|
|
||||||
inet_aton([host.externalAddress UTF8String], &addr.sin_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFDataRef dataAddress = CFDataCreate(kCFAllocatorDefault, (unsigned char*)&addr, sizeof(addr));
|
|
||||||
|
|
||||||
// try all ports
|
|
||||||
for (int j = 0; j < numPorts; j++) {
|
|
||||||
addr.sin_port = htons(ports[j]);
|
|
||||||
Log(LOG_I, @"Sending WOL packet");
|
|
||||||
CFSocketSendData(wolSocket, dataAddress, dataPayload, 0);
|
|
||||||
}
|
|
||||||
CFRelease(dataAddress);
|
|
||||||
}
|
}
|
||||||
CFRelease(dataPayload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSData*) createPayload:(Host*)host {
|
+ (void) wakeHost:(TemporaryHost*)host {
|
||||||
|
NSData* wolPayload = [WakeOnLanManager createPayload:host];
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
const char* address;
|
||||||
|
struct addrinfo hints, *res, *curr;
|
||||||
|
|
||||||
|
// try all ip addresses
|
||||||
|
if (i == 0 && host.localAddress != nil) {
|
||||||
|
address = [host.localAddress UTF8String];
|
||||||
|
} else if (i == 1 && host.externalAddress != nil) {
|
||||||
|
address = [host.externalAddress UTF8String];
|
||||||
|
} else if (i == 2 && host.address != nil) {
|
||||||
|
address = [host.address UTF8String];
|
||||||
|
} else {
|
||||||
|
// Requested address wasn't present
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
|
if (getaddrinfo(address, NULL, &hints, &res) != 0 || res == NULL) {
|
||||||
|
// Failed to resolve address
|
||||||
|
Log(LOG_E, @"Failed to resolve WOL address");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try all addresses that this DNS name resolves to. We have
|
||||||
|
// to create a new socket each time because the addresses
|
||||||
|
// may be different address families.
|
||||||
|
for (curr = res; curr != NULL; curr = curr->ai_next) {
|
||||||
|
int wolSocket;
|
||||||
|
|
||||||
|
wolSocket = socket(curr->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (wolSocket < 0) {
|
||||||
|
Log(LOG_E, @"Failed to create WOL socket");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
memcpy(&addr, curr->ai_addr, curr->ai_addrlen);
|
||||||
|
|
||||||
|
for (int j = 0; j < numPorts; j++) {
|
||||||
|
[WakeOnLanManager populateAddress:&addr withPort:ports[j]];
|
||||||
|
long err = sendto(wolSocket,
|
||||||
|
[wolPayload bytes],
|
||||||
|
[wolPayload length],
|
||||||
|
0,
|
||||||
|
(struct sockaddr*)&addr,
|
||||||
|
curr->ai_addrlen);
|
||||||
|
Log(LOG_I, @"Sending WOL packet returned: %ld", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(wolSocket);
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSData*) createPayload:(TemporaryHost*)host {
|
||||||
NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102];
|
NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102];
|
||||||
|
|
||||||
// 6 bytes of FF
|
// 6 bytes of FF
|
||||||
|
|||||||
@@ -14,20 +14,19 @@
|
|||||||
|
|
||||||
- (void) connectionStarted;
|
- (void) connectionStarted;
|
||||||
- (void) connectionTerminated:(long)errorCode;
|
- (void) connectionTerminated:(long)errorCode;
|
||||||
- (void) stageStarting:(char*)stageName;
|
- (void) stageStarting:(const char*)stageName;
|
||||||
- (void) stageComplete:(char*)stageName;
|
- (void) stageComplete:(const char*)stageName;
|
||||||
- (void) stageFailed:(char*)stageName withError:(long)errorCode;
|
- (void) stageFailed:(const char*)stageName withError:(long)errorCode;
|
||||||
- (void) launchFailed:(NSString*)message;
|
- (void) launchFailed:(NSString*)message;
|
||||||
- (void) displayMessage:(char*)message;
|
- (void) displayMessage:(const char*)message;
|
||||||
- (void) displayTransientMessage:(char*)message;
|
- (void) displayTransientMessage:(const char*)message;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface Connection : NSOperation <NSStreamDelegate>
|
@interface Connection : NSOperation <NSStreamDelegate>
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion;
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks;
|
||||||
-(void) terminate;
|
-(void) terminate;
|
||||||
-(void) terminateInternal;
|
|
||||||
-(void) main;
|
-(void) main;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
#include "opus.h"
|
#include "opus.h"
|
||||||
|
|
||||||
@implementation Connection {
|
@implementation Connection {
|
||||||
const char* _host;
|
SERVER_INFORMATION _serverInfo;
|
||||||
STREAM_CONFIGURATION _streamConfig;
|
STREAM_CONFIGURATION _streamConfig;
|
||||||
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
||||||
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
||||||
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
||||||
int _serverMajorVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSLock* initLock;
|
||||||
static OpusDecoder *opusDecoder;
|
static OpusDecoder *opusDecoder;
|
||||||
static id<ConnectionCallbacks> _callbacks;
|
static id<ConnectionCallbacks> _callbacks;
|
||||||
|
|
||||||
@@ -65,11 +65,16 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
|||||||
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArInit(void)
|
void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
opusDecoder = opus_decoder_create(48000, 2, &err);
|
// We only support stereo for now
|
||||||
|
assert(audioConfiguration == AUDIO_CONFIGURATION_STEREO);
|
||||||
|
|
||||||
|
opusDecoder = opus_decoder_create(opusConfig->sampleRate,
|
||||||
|
opusConfig->channelCount,
|
||||||
|
&err);
|
||||||
|
|
||||||
audioLock = [[NSLock alloc] init];
|
audioLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
@@ -77,9 +82,9 @@ void ArInit(void)
|
|||||||
NSError *audioSessionError = nil;
|
NSError *audioSessionError = nil;
|
||||||
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
||||||
|
|
||||||
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError];
|
[audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
|
||||||
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
|
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
|
||||||
[audioSession setPreferredOutputNumberOfChannels:2 error:&audioSessionError];
|
[audioSession setPreferredOutputNumberOfChannels:opusConfig->channelCount error:&audioSessionError];
|
||||||
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
|
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
|
||||||
[audioSession setActive: YES error: &audioSessionError];
|
[audioSession setActive: YES error: &audioSessionError];
|
||||||
|
|
||||||
@@ -99,11 +104,11 @@ void ArInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamBasicDescription audioFormat = {0};
|
AudioStreamBasicDescription audioFormat = {0};
|
||||||
audioFormat.mSampleRate = 48000;
|
audioFormat.mSampleRate = opusConfig->sampleRate;
|
||||||
audioFormat.mBitsPerChannel = 16;
|
audioFormat.mBitsPerChannel = 16;
|
||||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
||||||
audioFormat.mChannelsPerFrame = 2;
|
audioFormat.mChannelsPerFrame = opusConfig->channelCount;
|
||||||
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
|
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
|
||||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
|
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
|
||||||
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
|
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
|
||||||
@@ -223,17 +228,17 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||||||
|
|
||||||
void ClStageStarting(int stage)
|
void ClStageStarting(int stage)
|
||||||
{
|
{
|
||||||
[_callbacks stageStarting:(char*)LiGetStageName(stage)];
|
[_callbacks stageStarting:LiGetStageName(stage)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClStageComplete(int stage)
|
void ClStageComplete(int stage)
|
||||||
{
|
{
|
||||||
[_callbacks stageComplete:(char*)LiGetStageName(stage)];
|
[_callbacks stageComplete:LiGetStageName(stage)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClStageFailed(int stage, long errorCode)
|
void ClStageFailed(int stage, long errorCode)
|
||||||
{
|
{
|
||||||
[_callbacks stageFailed:(char*)LiGetStageName(stage) withError:errorCode];
|
[_callbacks stageFailed:LiGetStageName(stage) withError:errorCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClConnectionStarted(void)
|
void ClConnectionStarted(void)
|
||||||
@@ -246,40 +251,49 @@ void ClConnectionTerminated(long errorCode)
|
|||||||
[_callbacks connectionTerminated: errorCode];
|
[_callbacks connectionTerminated: errorCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClDisplayMessage(char* message)
|
void ClDisplayMessage(const char* message)
|
||||||
{
|
{
|
||||||
[_callbacks displayMessage: message];
|
[_callbacks displayMessage: message];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClDisplayTransientMessage(char* message)
|
void ClDisplayTransientMessage(const char* message)
|
||||||
{
|
{
|
||||||
[_callbacks displayTransientMessage: message];
|
[_callbacks displayTransientMessage: message];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) terminateInternal
|
-(void) terminate
|
||||||
{
|
{
|
||||||
// We dispatch this async to get out because this can be invoked
|
// We dispatch this async to get out because this can be invoked
|
||||||
// on a thread inside common and we don't want to deadlock
|
// on a thread inside common and we don't want to deadlock. It also avoids
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
// blocking on the caller's thread waiting to acquire initLock.
|
||||||
// This is safe to call even before LiStartConnection
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||||
|
[initLock lock];
|
||||||
LiStopConnection();
|
LiStopConnection();
|
||||||
|
[initLock unlock];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) terminate
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks
|
||||||
{
|
|
||||||
// We're guaranteed to not be on a moonlight-common thread
|
|
||||||
// here so it's safe to call stop directly
|
|
||||||
LiStopConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
|
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_host = [config.host cStringUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
|
// Use a lock to ensure that only one thread is initializing
|
||||||
|
// or deinitializing a connection at a time.
|
||||||
|
if (initLock == nil) {
|
||||||
|
initLock = [[NSLock alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
LiInitializeServerInformation(&_serverInfo);
|
||||||
|
_serverInfo.address = [config.host cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
_serverInfo.serverInfoAppVersion = [config.appVersion cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
if (config.gfeVersion != nil) {
|
||||||
|
_serverInfo.serverInfoGfeVersion = [config.gfeVersion cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
|
||||||
renderer = myRenderer;
|
renderer = myRenderer;
|
||||||
_callbacks = callbacks;
|
_callbacks = callbacks;
|
||||||
_serverMajorVersion = serverMajorVersion;
|
|
||||||
|
LiInitializeStreamConfiguration(&_streamConfig);
|
||||||
_streamConfig.width = config.width;
|
_streamConfig.width = config.width;
|
||||||
_streamConfig.height = config.height;
|
_streamConfig.height = config.height;
|
||||||
_streamConfig.fps = config.frameRate;
|
_streamConfig.fps = config.frameRate;
|
||||||
@@ -293,13 +307,15 @@ void ClDisplayTransientMessage(char* message)
|
|||||||
int riKeyId = htonl(config.riKeyId);
|
int riKeyId = htonl(config.riKeyId);
|
||||||
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
||||||
|
|
||||||
memset(&_drCallbacks, 0, sizeof(_drCallbacks));
|
LiInitializeVideoCallbacks(&_drCallbacks);
|
||||||
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
||||||
|
|
||||||
|
LiInitializeAudioCallbacks(&_arCallbacks);
|
||||||
_arCallbacks.init = ArInit;
|
_arCallbacks.init = ArInit;
|
||||||
_arCallbacks.cleanup = ArCleanup;
|
_arCallbacks.cleanup = ArCleanup;
|
||||||
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
|
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
|
||||||
|
|
||||||
|
LiInitializeConnectionCallbacks(&_clCallbacks);
|
||||||
_clCallbacks.stageStarting = ClStageStarting;
|
_clCallbacks.stageStarting = ClStageStarting;
|
||||||
_clCallbacks.stageComplete = ClStageComplete;
|
_clCallbacks.stageComplete = ClStageComplete;
|
||||||
_clCallbacks.stageFailed = ClStageFailed;
|
_clCallbacks.stageFailed = ClStageFailed;
|
||||||
@@ -394,12 +410,14 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||||||
|
|
||||||
-(void) main
|
-(void) main
|
||||||
{
|
{
|
||||||
LiStartConnection(_host,
|
[initLock lock];
|
||||||
|
LiStartConnection(&_serverInfo,
|
||||||
&_streamConfig,
|
&_streamConfig,
|
||||||
&_clCallbacks,
|
&_clCallbacks,
|
||||||
&_drCallbacks,
|
&_drCallbacks,
|
||||||
&_arCallbacks,
|
&_arCallbacks,
|
||||||
NULL, 0, _serverMajorVersion);
|
NULL, 0);
|
||||||
|
[initLock unlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
@interface StreamConfiguration : NSObject
|
@interface StreamConfiguration : NSObject
|
||||||
|
|
||||||
@property NSString* host;
|
@property NSString* host;
|
||||||
|
@property NSString* appVersion;
|
||||||
|
@property NSString* gfeVersion;
|
||||||
@property NSString* appID;
|
@property NSString* appID;
|
||||||
@property int width;
|
@property int width;
|
||||||
@property int height;
|
@property int height;
|
||||||
|
|||||||
@@ -14,6 +14,5 @@
|
|||||||
|
|
||||||
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id<ConnectionCallbacks>)callback;
|
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id<ConnectionCallbacks>)callback;
|
||||||
- (void) stopStream;
|
- (void) stopStream;
|
||||||
- (void) stopStreamInternal;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation StreamManager {
|
@implementation StreamManager {
|
||||||
StreamConfiguration* _config;
|
StreamConfiguration* _config;
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
|
|
||||||
- (void)main {
|
- (void)main {
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
NSString* uniqueId = [IdManager getUniqueId];
|
||||||
NSData* cert = [CryptoManager readCertFromFile];
|
NSData* cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host
|
||||||
@@ -47,11 +48,11 @@
|
|||||||
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]]];
|
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
|
|
||||||
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
|
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
|
||||||
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
|
|
||||||
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
||||||
if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL || appversion == NULL) {
|
NSString* gfeVersion = [serverInfoResp getStringTag:@"GfeVersion"];
|
||||||
|
NSString* serverState = [serverInfoResp getStringTag:@"state"];
|
||||||
|
if (![serverInfoResp isStatusOk] || pairStatus == NULL || appversion == NULL || serverState == NULL) {
|
||||||
[_callbacks launchFailed:@"Failed to connect to PC"];
|
[_callbacks launchFailed:@"Failed to connect to PC"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -63,12 +64,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resumeApp and launchApp handle calling launchFailed
|
// resumeApp and launchApp handle calling launchFailed
|
||||||
if (![currentGame isEqualToString:@"0"]) {
|
if ([serverState hasSuffix:@"_SERVER_BUSY"]) {
|
||||||
if (![currentClient isEqualToString:@"1"]) {
|
|
||||||
// The server is streaming to someone else
|
|
||||||
[_callbacks launchFailed:@"There is another stream in progress"];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// App already running, resume it
|
// App already running, resume it
|
||||||
if (![self resumeApp:hMan]) {
|
if (![self resumeApp:hMan]) {
|
||||||
return;
|
return;
|
||||||
@@ -87,29 +83,21 @@
|
|||||||
[((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width
|
[((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width
|
||||||
y:_config.height / screenSize.height];
|
y:_config.height / screenSize.height];
|
||||||
|
|
||||||
int majorVersion = [[appversion substringToIndex:1] intValue];
|
// Populate the config's version fields from serverinfo
|
||||||
Log(LOG_I, @"Server is generation %d", majorVersion);
|
_config.appVersion = appversion;
|
||||||
|
_config.gfeVersion = gfeVersion;
|
||||||
|
|
||||||
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
||||||
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks serverMajorVersion:majorVersion];
|
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks];
|
||||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||||
[opQueue addOperation:_connection];
|
[opQueue addOperation:_connection];
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should NEVER be called from within a thread
|
|
||||||
// owned by moonlight-common
|
|
||||||
- (void) stopStream
|
- (void) stopStream
|
||||||
{
|
{
|
||||||
[_connection terminate];
|
[_connection terminate];
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should only be called from within a thread
|
|
||||||
// owned by moonlight-common
|
|
||||||
- (void) stopStreamInternal
|
|
||||||
{
|
|
||||||
[_connection terminateInternal];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL) launchApp:(HttpManager*)hMan {
|
- (BOOL) launchApp:(HttpManager*)hMan {
|
||||||
HttpResponse* launchResp = [[HttpResponse alloc] init];
|
HttpResponse* launchResp = [[HttpResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest:
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest:
|
||||||
|
|||||||
@@ -7,17 +7,17 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
|
|
||||||
@protocol AppCallback <NSObject>
|
@protocol AppCallback <NSObject>
|
||||||
|
|
||||||
- (void) appClicked:(App*) app;
|
- (void) appClicked:(TemporaryApp*) app;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface UIAppView : UIView
|
@interface UIAppView : UIView
|
||||||
|
|
||||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback;
|
- (id) initWithApp:(TemporaryApp*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback;
|
||||||
- (void) updateAppImage;
|
- (void) updateAppImage;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -9,40 +9,43 @@
|
|||||||
#import "UIAppView.h"
|
#import "UIAppView.h"
|
||||||
|
|
||||||
@implementation UIAppView {
|
@implementation UIAppView {
|
||||||
App* _app;
|
TemporaryApp* _app;
|
||||||
UIButton* _appButton;
|
UIButton* _appButton;
|
||||||
UILabel* _appLabel;
|
UILabel* _appLabel;
|
||||||
UIImageView* _appOverlay;
|
UIImageView* _appOverlay;
|
||||||
|
NSCache* _artCache;
|
||||||
id<AppCallback> _callback;
|
id<AppCallback> _callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback {
|
static UIImage* noImage;
|
||||||
|
|
||||||
|
- (id) initWithApp:(TemporaryApp*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_app = app;
|
_app = app;
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
|
_artCache = cache;
|
||||||
|
|
||||||
|
// Cache the NoAppImage ourselves to avoid
|
||||||
|
// having to load it each time
|
||||||
|
if (noImage == nil) {
|
||||||
|
noImage = [UIImage imageNamed:@"NoAppImage"];
|
||||||
|
}
|
||||||
|
|
||||||
_appButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
_appButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
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)];
|
|
||||||
|
// Rasterizing the cell layer increases rendering performance by quite a bit
|
||||||
|
self.layer.shouldRasterize = YES;
|
||||||
|
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -52,15 +55,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateAppImage {
|
- (void) updateAppImage {
|
||||||
[_appOverlay setHidden:!_app.isRunning];
|
if (_appOverlay != nil) {
|
||||||
|
[_appOverlay removeFromSuperview];
|
||||||
|
_appOverlay = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([_app.id isEqualToString:_app.host.currentGame]) {
|
||||||
|
// Only create the app overlay if needed
|
||||||
|
_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;
|
||||||
|
|
||||||
|
[self addSubview:_appOverlay];
|
||||||
|
|
||||||
|
_appOverlay.frame = CGRectMake(0, 0, noImage.size.width / 2.f, noImage.size.height / 4.f);
|
||||||
|
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Improve no-app image detection
|
// TODO: Improve no-app image detection
|
||||||
BOOL noAppImage = false;
|
BOOL noAppImage = false;
|
||||||
|
|
||||||
if (_app.image != nil) {
|
if (_app.image != nil) {
|
||||||
UIImage* appImage = [UIImage imageWithData:_app.image];
|
// Load the decoded image from the cache
|
||||||
|
UIImage* appImage = [_artCache objectForKey:_app];
|
||||||
|
if (appImage == nil) {
|
||||||
|
// Not cached; we have to decode this now
|
||||||
|
appImage = [UIImage imageWithData:_app.image];
|
||||||
|
[_artCache setObject:appImage forKey:_app];
|
||||||
|
}
|
||||||
|
|
||||||
// This size of image might be blank image received from GameStream.
|
// This size of image might be blank image received from GameStream.
|
||||||
if (!(appImage.size.width == 130.f && appImage.size.height == 180.f)) {
|
if (!(appImage.size.width == 130.f && appImage.size.height == 180.f) && // GFE 2.0
|
||||||
|
!(appImage.size.width == 628.f && appImage.size.height == 888.f)) { // GFE 3.0
|
||||||
_appButton.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
|
_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);
|
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.frame = CGRectMake(0, 0, self.frame.size.width / 2.f, self.frame.size.height / 4.f);
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import "Host.h"
|
#import "TemporaryHost.h"
|
||||||
|
|
||||||
@protocol HostCallback <NSObject>
|
@protocol HostCallback <NSObject>
|
||||||
|
|
||||||
- (void) hostClicked:(Host*)host view:(UIView*)view;
|
- (void) hostClicked:(TemporaryHost*)host view:(UIView*)view;
|
||||||
- (void) hostLongClicked:(Host*)host view:(UIView*)view;
|
- (void) hostLongClicked:(TemporaryHost*)host view:(UIView*)view;
|
||||||
- (void) addHostClicked;
|
- (void) addHostClicked;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface UIComputerView : UIView
|
@interface UIComputerView : UIView
|
||||||
|
|
||||||
- (id) initWithComputer:(Host*)host andCallback:(id<HostCallback>)callback;
|
- (id) initWithComputer:(TemporaryHost*)host andCallback:(id<HostCallback>)callback;
|
||||||
- (id) initForAddWithCallback:(id<HostCallback>)callback;
|
- (id) initForAddWithCallback:(id<HostCallback>)callback;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
#import "UIComputerView.h"
|
#import "UIComputerView.h"
|
||||||
|
|
||||||
@implementation UIComputerView {
|
@implementation UIComputerView {
|
||||||
Host* _host;
|
TemporaryHost* _host;
|
||||||
UIButton* _hostButton;
|
UIButton* _hostButton;
|
||||||
UILabel* _hostLabel;
|
UILabel* _hostLabel;
|
||||||
UILabel* _hostStatus;
|
UILabel* _hostStatus;
|
||||||
@@ -72,7 +72,7 @@ static const int LABEL_DY = 20;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithComputer:(Host*)host andCallback:(id<HostCallback>)callback {
|
- (id) initWithComputer:(TemporaryHost*)host andCallback:(id<HostCallback>)callback {
|
||||||
self = [self init];
|
self = [self init];
|
||||||
_host = host;
|
_host = host;
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
@@ -123,7 +123,7 @@ static const int LABEL_DY = 20;
|
|||||||
self.frame = CGRectMake(x, y, width, height);
|
self.frame = CGRectMake(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateContentsForHost:(Host*)host {
|
- (void) updateContentsForHost:(TemporaryHost*)host {
|
||||||
_hostLabel.text = _host.name;
|
_hostLabel.text = _host.name;
|
||||||
_hostLabel.textColor = [UIColor whiteColor];
|
_hostLabel.textColor = [UIColor whiteColor];
|
||||||
[_hostLabel sizeToFit];
|
[_hostLabel sizeToFit];
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import ImageIO;
|
||||||
|
|
||||||
#import "MainFrameViewController.h"
|
#import "MainFrameViewController.h"
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
@@ -13,19 +15,21 @@
|
|||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "UIComputerView.h"
|
#import "UIComputerView.h"
|
||||||
#import "UIAppView.h"
|
#import "UIAppView.h"
|
||||||
#import "App.h"
|
|
||||||
#import "SettingsViewController.h"
|
#import "SettingsViewController.h"
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import "Settings.h"
|
#import "TemporarySettings.h"
|
||||||
#import "WakeOnLanManager.h"
|
#import "WakeOnLanManager.h"
|
||||||
#import "AppListResponse.h"
|
#import "AppListResponse.h"
|
||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
#import "StreamFrameViewController.h"
|
#import "StreamFrameViewController.h"
|
||||||
#import "LoadingFrameViewController.h"
|
#import "LoadingFrameViewController.h"
|
||||||
|
#import "ComputerScrollView.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation MainFrameViewController {
|
@implementation MainFrameViewController {
|
||||||
NSOperationQueue* _opQueue;
|
NSOperationQueue* _opQueue;
|
||||||
Host* _selectedHost;
|
TemporaryHost* _selectedHost;
|
||||||
NSString* _uniqueId;
|
NSString* _uniqueId;
|
||||||
NSData* _cert;
|
NSData* _cert;
|
||||||
DiscoveryManager* _discMan;
|
DiscoveryManager* _discMan;
|
||||||
@@ -35,6 +39,7 @@
|
|||||||
UIScrollView* hostScrollView;
|
UIScrollView* hostScrollView;
|
||||||
int currentPosition;
|
int currentPosition;
|
||||||
NSArray* _sortedAppList;
|
NSArray* _sortedAppList;
|
||||||
|
NSCache* _boxArtCache;
|
||||||
}
|
}
|
||||||
static NSMutableSet* hostList;
|
static NSMutableSet* hostList;
|
||||||
|
|
||||||
@@ -43,21 +48,26 @@ static NSMutableSet* hostList;
|
|||||||
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing"
|
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing"
|
||||||
message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
|
message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) {
|
||||||
|
[_discMan startDiscovery];
|
||||||
|
[self hideLoadingFrame];
|
||||||
|
}]];
|
||||||
[self presentViewController:_pairAlert animated:YES completion:nil];
|
[self presentViewController:_pairAlert animated:YES completion:nil];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pairFailed:(NSString *)message {
|
- (void)pairFailed:(NSString *)message {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[_pairAlert dismissViewControllerAnimated:YES completion:nil];
|
[_pairAlert dismissViewControllerAnimated:YES completion:^{
|
||||||
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
|
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
|
||||||
message:message
|
message:message
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
[self presentViewController:_pairAlert animated:YES completion:nil];
|
[self presentViewController:_pairAlert animated:YES completion:nil];
|
||||||
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
[self hideLoadingFrame];
|
[self hideLoadingFrame];
|
||||||
|
}];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +84,7 @@ static NSMutableSet* hostList;
|
|||||||
|
|
||||||
// Capture the host here because it can change once we
|
// Capture the host here because it can change once we
|
||||||
// leave the main thread
|
// leave the main thread
|
||||||
Host* host = _selectedHost;
|
TemporaryHost* host = _selectedHost;
|
||||||
|
|
||||||
if ([host.appList count] > 0) {
|
if ([host.appList count] > 0) {
|
||||||
usingCachedAppList = true;
|
usingCachedAppList = true;
|
||||||
@@ -94,11 +104,26 @@ static NSMutableSet* hostList;
|
|||||||
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.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
|
|
||||||
AppListResponse* appListResp = [[AppListResponse alloc] init];
|
|
||||||
|
|
||||||
// Exempt this host from discovery while handling the applist query
|
// Exempt this host from discovery while handling the applist query
|
||||||
[_discMan removeHostFromDiscovery:host];
|
[_discMan removeHostFromDiscovery:host];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
|
|
||||||
|
// Try up to 5 times to get the app list
|
||||||
|
AppListResponse* appListResp;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
appListResp = [[AppListResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
|
||||||
|
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
|
||||||
|
Log(LOG_W, @"Failed to get applist on try %d: %@", i, appListResp.statusMessage);
|
||||||
|
|
||||||
|
// Wait for one second then retry
|
||||||
|
[NSThread sleepForTimeInterval:1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log(LOG_I, @"App list successfully retreived - took %d tries", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[_discMan addHostToDiscovery:host];
|
[_discMan addHostToDiscovery:host];
|
||||||
|
|
||||||
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
|
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
|
||||||
@@ -120,7 +145,7 @@ static NSMutableSet* hostList;
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self mergeAppLists:[appListResp getAppList] forHost:host];
|
[self updateApplist:[appListResp getAppList] forHost:host];
|
||||||
|
|
||||||
if (host != _selectedHost) {
|
if (host != _selectedHost) {
|
||||||
return;
|
return;
|
||||||
@@ -138,51 +163,73 @@ static NSMutableSet* hostList;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) mergeAppLists:(NSArray*) newList forHost:(Host*)host {
|
- (void) updateApplist:(NSSet*) newList forHost:(TemporaryHost*)host {
|
||||||
DataManager* database = [[DataManager alloc] init];
|
DataManager* database = [[DataManager alloc] init];
|
||||||
for (App* app in newList) {
|
|
||||||
BOOL appAlreadyInList = NO;
|
for (TemporaryApp* app in newList) {
|
||||||
for (App* savedApp in host.appList) {
|
BOOL appAlreadyInList = NO;
|
||||||
|
for (TemporaryApp* savedApp in host.appList) {
|
||||||
if ([app.id isEqualToString:savedApp.id]) {
|
if ([app.id isEqualToString:savedApp.id]) {
|
||||||
savedApp.isRunning = app.isRunning;
|
savedApp.name = app.name;
|
||||||
appAlreadyInList = YES;
|
appAlreadyInList = YES;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!appAlreadyInList) {
|
if (!appAlreadyInList) {
|
||||||
app.host = host;
|
app.host = host;
|
||||||
[host addAppListObject:app];
|
[host.appList addObject:app];
|
||||||
} else {
|
|
||||||
[database removeApp:app];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (App* app in host.appList) {
|
BOOL appWasRemoved;
|
||||||
BOOL appWasRemoved = YES;
|
do {
|
||||||
for (App* mergedApp in newList) {
|
appWasRemoved = NO;
|
||||||
if ([mergedApp.id isEqualToString:app.id]) {
|
|
||||||
appWasRemoved = NO;
|
for (TemporaryApp* app in host.appList) {
|
||||||
|
appWasRemoved = YES;
|
||||||
|
for (TemporaryApp* mergedApp in newList) {
|
||||||
|
if ([mergedApp.id isEqualToString:app.id]) {
|
||||||
|
appWasRemoved = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (appWasRemoved) {
|
||||||
|
// Removing the app mutates the list we're iterating (which isn't legal).
|
||||||
|
// We need to jump out of this loop and restart enumeration.
|
||||||
|
|
||||||
|
[host.appList removeObject:app];
|
||||||
|
|
||||||
|
// It's important to remove the app record from the database
|
||||||
|
// since we'll have a constraint violation now that appList
|
||||||
|
// doesn't have this app in it.
|
||||||
|
[database removeApp:app];
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (appWasRemoved) {
|
|
||||||
[host removeAppListObject:app];
|
// Keep looping until the list is no longer being mutated
|
||||||
[database removeApp:app];
|
} while (appWasRemoved);
|
||||||
}
|
|
||||||
}
|
[database updateAppsForExistingHost:host];
|
||||||
[database saveData];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showHostSelectionView {
|
- (void)showHostSelectionView {
|
||||||
[_appManager stopRetrieving];
|
[_appManager stopRetrieving];
|
||||||
[[[DataManager alloc] init] saveData];
|
|
||||||
_selectedHost = nil;
|
_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:(TemporaryApp*)app {
|
||||||
|
// Update the box art cache now so we don't have to do it
|
||||||
|
// on the main thread
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
|
||||||
|
DataManager* dataManager = [[DataManager alloc] init];
|
||||||
|
[dataManager updateIconForExistingApp: app];
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
});
|
});
|
||||||
@@ -196,7 +243,7 @@ static NSMutableSet* hostList;
|
|||||||
[self presentViewController:alert animated:YES completion:nil];
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) hostClicked:(Host *)host view:(UIView *)view {
|
- (void) hostClicked:(TemporaryHost *)host view:(UIView *)view {
|
||||||
// Treat clicks on offline hosts to be long clicks
|
// Treat clicks on offline hosts to be long clicks
|
||||||
// This shows the context menu with wake, delete, etc. rather
|
// This shows the context menu with wake, delete, etc. rather
|
||||||
// than just hanging for a while and failing as we would in this
|
// than just hanging for a while and failing as we would in this
|
||||||
@@ -262,7 +309,7 @@ static NSMutableSet* hostList;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)hostLongClicked:(Host *)host view:(UIView *)view {
|
- (void)hostLongClicked:(TemporaryHost *)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) {
|
||||||
@@ -288,8 +335,8 @@ static NSMutableSet* hostList;
|
|||||||
[dataMan removeHost:host];
|
[dataMan removeHost:host];
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList removeObject:host];
|
[hostList removeObject:host];
|
||||||
|
[self updateAllHosts:[hostList allObjects]];
|
||||||
}
|
}
|
||||||
[self updateAllHosts:[hostList allObjects]];
|
|
||||||
|
|
||||||
}]];
|
}]];
|
||||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
@@ -311,10 +358,8 @@ static NSMutableSet* hostList;
|
|||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||||
NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
|
NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||||
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){
|
[_discMan discoverHost:hostAddress withCallback:^(TemporaryHost* host, NSString* error){
|
||||||
if (host != nil) {
|
if (host != nil) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
|
||||||
[dataMan saveData];
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList addObject:host];
|
[hostList addObject:host];
|
||||||
@@ -335,14 +380,14 @@ static NSMutableSet* hostList;
|
|||||||
[self presentViewController:alertController animated:YES completion:nil];
|
[self presentViewController:alertController animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) appClicked:(App *)app {
|
- (void) appClicked:(TemporaryApp *)app {
|
||||||
Log(LOG_D, @"Clicked app: %@", app.name);
|
Log(LOG_D, @"Clicked app: %@", app.name);
|
||||||
_streamConfig = [[StreamConfiguration alloc] init];
|
_streamConfig = [[StreamConfiguration alloc] init];
|
||||||
_streamConfig.host = app.host.activeAddress;
|
_streamConfig.host = app.host.activeAddress;
|
||||||
_streamConfig.appID = app.id;
|
_streamConfig.appID = app.id;
|
||||||
|
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
Settings* streamSettings = [dataMan retrieveSettings];
|
TemporarySettings* streamSettings = [dataMan getSettings];
|
||||||
|
|
||||||
_streamConfig.frameRate = [streamSettings.framerate intValue];
|
_streamConfig.frameRate = [streamSettings.framerate intValue];
|
||||||
_streamConfig.bitRate = [streamSettings.bitrate intValue];
|
_streamConfig.bitRate = [streamSettings.bitrate intValue];
|
||||||
@@ -355,7 +400,7 @@ static NSMutableSet* hostList;
|
|||||||
[[self revealViewController] revealToggle:self];
|
[[self revealViewController] revealToggle:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
App* currentApp = [self findRunningApp:app.host];
|
TemporaryApp* currentApp = [self findRunningApp:app.host];
|
||||||
if (currentApp != nil) {
|
if (currentApp != nil) {
|
||||||
UIAlertController* alertController = [UIAlertController
|
UIAlertController* alertController = [UIAlertController
|
||||||
alertControllerWithTitle: app.name
|
alertControllerWithTitle: app.name
|
||||||
@@ -376,6 +421,17 @@ static NSMutableSet* hostList;
|
|||||||
// Exempt this host from discovery while handling the quit operation
|
// Exempt this host from discovery while handling the quit operation
|
||||||
[_discMan removeHostFromDiscovery:app.host];
|
[_discMan removeHostFromDiscovery:app.host];
|
||||||
[hMan executeRequestSynchronously:quitRequest];
|
[hMan executeRequestSynchronously:quitRequest];
|
||||||
|
if (quitResponse.statusCode == 200) {
|
||||||
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
|
||||||
|
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
|
if (![serverInfoResp isStatusOk] || ![[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_AVAILABLE"]) {
|
||||||
|
// On newer GFE versions, the quit request succeeds even though the app doesn't
|
||||||
|
// really quit if another client tries to kill your app. We'll patch the response
|
||||||
|
// to look like the old error in that case, so the UI behaves.
|
||||||
|
quitResponse.statusCode = 599;
|
||||||
|
}
|
||||||
|
}
|
||||||
[_discMan addHostToDiscovery:app.host];
|
[_discMan addHostToDiscovery:app.host];
|
||||||
|
|
||||||
UIAlertController* alert;
|
UIAlertController* alert;
|
||||||
@@ -389,7 +445,7 @@ static NSMutableSet* hostList;
|
|||||||
}
|
}
|
||||||
// If it succeeds and we're to start streaming, segue to the stream and return
|
// If it succeeds and we're to start streaming, segue to the stream and return
|
||||||
else if (![app.id isEqualToString:currentApp.id]) {
|
else if (![app.id isEqualToString:currentApp.id]) {
|
||||||
currentApp.isRunning = NO;
|
app.host.currentGame = @"0";
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self updateAppsForHost:app.host];
|
[self updateAppsForHost:app.host];
|
||||||
@@ -400,7 +456,7 @@ static NSMutableSet* hostList;
|
|||||||
}
|
}
|
||||||
// Otherwise, display a dialog to notify the user that the app was quit
|
// Otherwise, display a dialog to notify the user that the app was quit
|
||||||
else {
|
else {
|
||||||
currentApp.isRunning = NO;
|
app.host.currentGame = @"0";
|
||||||
|
|
||||||
alert = [UIAlertController alertControllerWithTitle:@"Quitting App"
|
alert = [UIAlertController alertControllerWithTitle:@"Quitting App"
|
||||||
message:@"The app was quit successfully."
|
message:@"The app was quit successfully."
|
||||||
@@ -421,9 +477,9 @@ static NSMutableSet* hostList;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (App*) findRunningApp:(Host*)host {
|
- (TemporaryApp*) findRunningApp:(TemporaryHost*)host {
|
||||||
for (App* app in host.appList) {
|
for (TemporaryApp* app in host.appList) {
|
||||||
if (app.isRunning) {
|
if ([app.id isEqualToString:host.currentGame]) {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,7 +533,7 @@ static NSMutableSet* hostList;
|
|||||||
|
|
||||||
// Set up crypto
|
// Set up crypto
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
_uniqueId = [IdManager getUniqueId];
|
||||||
_cert = [CryptoManager readCertFromFile];
|
_cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
_appManager = [[AppAssetManager alloc] initWithCallback:self];
|
_appManager = [[AppAssetManager alloc] initWithCallback:self];
|
||||||
@@ -488,17 +544,52 @@ static NSMutableSet* hostList;
|
|||||||
hostList = [[NSMutableSet alloc] init];
|
hostList = [[NSMutableSet alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_boxArtCache = [[NSCache alloc] init];
|
||||||
|
|
||||||
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
||||||
|
|
||||||
hostScrollView = [[UIScrollView alloc] init];
|
hostScrollView = [[ComputerScrollView alloc] init];
|
||||||
hostScrollView.frame = CGRectMake(0, self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height / 2);
|
hostScrollView.frame = CGRectMake(0, self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height / 2);
|
||||||
[hostScrollView setShowsHorizontalScrollIndicator:NO];
|
[hostScrollView setShowsHorizontalScrollIndicator:NO];
|
||||||
|
hostScrollView.delaysContentTouches = NO;
|
||||||
|
|
||||||
|
UIButton* pullArrow = [[UIButton alloc] init];
|
||||||
|
[pullArrow addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
|
||||||
|
[pullArrow setImage:[UIImage imageNamed:@"PullArrow"] forState:UIControlStateNormal];
|
||||||
|
[pullArrow sizeToFit];
|
||||||
|
pullArrow.frame = CGRectMake(0,
|
||||||
|
self.collectionView.frame.size.height / 6 - pullArrow.frame.size.height / 2 - self.navigationController.navigationBar.frame.size.height,
|
||||||
|
pullArrow.frame.size.width,
|
||||||
|
pullArrow.frame.size.height);
|
||||||
|
|
||||||
|
self.collectionView.delaysContentTouches = NO;
|
||||||
|
self.collectionView.allowsMultipleSelection = NO;
|
||||||
|
self.collectionView.multipleTouchEnabled = NO;
|
||||||
|
|
||||||
[self retrieveSavedHosts];
|
[self retrieveSavedHosts];
|
||||||
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
|
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||||
|
selector: @selector(handleReturnToForeground)
|
||||||
|
name: UIApplicationWillEnterForegroundNotification
|
||||||
|
object: nil];
|
||||||
|
|
||||||
[self updateHosts];
|
[self updateHosts];
|
||||||
[self.view addSubview:hostScrollView];
|
[self.view addSubview:hostScrollView];
|
||||||
|
[self.view addSubview:pullArrow];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)dealloc
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)handleReturnToForeground
|
||||||
|
{
|
||||||
|
// This will refresh the applist when a paired host is selected
|
||||||
|
if (_selectedHost != nil && _selectedHost.pairState == PairStatePaired) {
|
||||||
|
[self hostClicked:_selectedHost view:nil];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
@@ -513,10 +604,7 @@ static NSMutableSet* hostList;
|
|||||||
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
|
|
||||||
// This will refresh the applist
|
[self handleReturnToForeground];
|
||||||
if (_selectedHost != nil) {
|
|
||||||
[self hostClicked:_selectedHost view:nil];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
@@ -525,18 +613,18 @@ static NSMutableSet* hostList;
|
|||||||
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
||||||
[_discMan stopDiscovery];
|
[_discMan stopDiscovery];
|
||||||
|
|
||||||
// In case the host objects were updated in the background
|
// Purge the box art cache
|
||||||
[[[DataManager alloc] init] saveData];
|
[_boxArtCache removeAllObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) retrieveSavedHosts {
|
- (void) retrieveSavedHosts {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
NSArray* hosts = [dataMan retrieveHosts];
|
NSArray* hosts = [dataMan getHosts];
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList addObjectsFromArray:hosts];
|
[hostList addObjectsFromArray:hosts];
|
||||||
|
|
||||||
// Initialize the non-persistent host state
|
// Initialize the non-persistent host state
|
||||||
for (Host* host in hostList) {
|
for (TemporaryHost* host in hostList) {
|
||||||
if (host.activeAddress == nil) {
|
if (host.activeAddress == nil) {
|
||||||
host.activeAddress = host.localAddress;
|
host.activeAddress = host.localAddress;
|
||||||
}
|
}
|
||||||
@@ -553,7 +641,7 @@ static NSMutableSet* hostList;
|
|||||||
- (void) updateAllHosts:(NSArray *)hosts {
|
- (void) updateAllHosts:(NSArray *)hosts {
|
||||||
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 (TemporaryHost* 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\t activeAddress:%@ \n}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online, host.activeAddress);
|
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) {
|
||||||
@@ -571,13 +659,16 @@ static NSMutableSet* hostList;
|
|||||||
UIComputerView* compView;
|
UIComputerView* compView;
|
||||||
float prevEdge = -1;
|
float prevEdge = -1;
|
||||||
@synchronized (hostList) {
|
@synchronized (hostList) {
|
||||||
for (Host* comp in hostList) {
|
// Sort the host list in alphabetical order
|
||||||
|
NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)];
|
||||||
|
for (TemporaryHost* comp in sortedHostList) {
|
||||||
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
||||||
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
||||||
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
||||||
[hostScrollView addSubview:compView];
|
[hostScrollView addSubview:compView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
||||||
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
||||||
|
|
||||||
@@ -593,7 +684,31 @@ static NSMutableSet* hostList;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateAppsForHost:(Host*)host {
|
// This function forces immediate decoding of the UIImage, rather
|
||||||
|
// than the default lazy decoding that results in janky scrolling.
|
||||||
|
+ (UIImage*) loadBoxArtForCaching:(TemporaryApp*)app {
|
||||||
|
|
||||||
|
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)app.image, NULL);
|
||||||
|
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: (id)kCFBooleanTrue});
|
||||||
|
|
||||||
|
UIImage *boxArt = [UIImage imageWithCGImage:cgImage];
|
||||||
|
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
CFRelease(source);
|
||||||
|
|
||||||
|
return boxArt;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateBoxArtCacheForApp:(TemporaryApp*)app {
|
||||||
|
if (app.image == nil) {
|
||||||
|
[_boxArtCache removeObjectForKey:app];
|
||||||
|
}
|
||||||
|
else if ([_boxArtCache objectForKey:app] == nil) {
|
||||||
|
[_boxArtCache setObject:[MainFrameViewController loadBoxArtForCaching:app] forKey:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateAppsForHost:(TemporaryHost*)host {
|
||||||
if (host != _selectedHost) {
|
if (host != _selectedHost) {
|
||||||
Log(LOG_W, @"Mismatched host during app update");
|
Log(LOG_W, @"Mismatched host during app update");
|
||||||
return;
|
return;
|
||||||
@@ -602,6 +717,33 @@ static NSMutableSet* hostList;
|
|||||||
_sortedAppList = [host.appList allObjects];
|
_sortedAppList = [host.appList allObjects];
|
||||||
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
|
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
|
||||||
|
|
||||||
|
// Split the sorted array in half to allow 2 jobs to process app assets at once
|
||||||
|
NSArray *firstHalf;
|
||||||
|
NSArray *secondHalf;
|
||||||
|
NSRange range;
|
||||||
|
|
||||||
|
range.location = 0;
|
||||||
|
range.length = [_sortedAppList count] / 2;
|
||||||
|
|
||||||
|
firstHalf = [_sortedAppList subarrayWithRange:range];
|
||||||
|
|
||||||
|
range.location = range.length;
|
||||||
|
range.length = [_sortedAppList count] - range.length;
|
||||||
|
|
||||||
|
secondHalf = [_sortedAppList subarrayWithRange:range];
|
||||||
|
|
||||||
|
// Start 2 jobs
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
for (TemporaryApp* app in firstHalf) {
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
for (TemporaryApp* app in secondHalf) {
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
[hostScrollView removeFromSuperview];
|
[hostScrollView removeFromSuperview];
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
}
|
}
|
||||||
@@ -609,8 +751,8 @@ static NSMutableSet* hostList;
|
|||||||
- (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 = _sortedAppList[indexPath.row];
|
TemporaryApp* app = _sortedAppList[indexPath.row];
|
||||||
UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self];
|
UIAppView* appView = [[UIAppView alloc] initWithApp:app cache:_boxArtCache andCallback:self];
|
||||||
[appView updateAppImage];
|
[appView updateAppImage];
|
||||||
|
|
||||||
if (appView.bounds.size.width > 10.0) {
|
if (appView.bounds.size.width > 10.0) {
|
||||||
@@ -621,7 +763,19 @@ static NSMutableSet* hostList;
|
|||||||
|
|
||||||
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
|
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
|
||||||
[cell addSubview:appView];
|
[cell addSubview:appView];
|
||||||
|
|
||||||
|
|
||||||
|
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds];
|
||||||
|
cell.layer.masksToBounds = NO;
|
||||||
|
cell.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
|
cell.layer.shadowOffset = CGSizeMake(1.0f, 5.0f);
|
||||||
|
cell.layer.shadowOpacity = 0.5f;
|
||||||
|
cell.layer.shadowPath = shadowPath.CGPath;
|
||||||
|
|
||||||
|
cell.layer.borderColor = [[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3f] CGColor];
|
||||||
|
cell.layer.borderWidth = 1;
|
||||||
|
cell.exclusiveTouch = YES;
|
||||||
|
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "SettingsViewController.h"
|
#import "SettingsViewController.h"
|
||||||
#import "Settings.h"
|
#import "TemporarySettings.h"
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
|
|
||||||
#define BITRATE_INTERVAL 500 // in kbps
|
#define BITRATE_INTERVAL 500 // in kbps
|
||||||
@@ -22,7 +22,7 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
Settings* currentSettings = [dataMan retrieveSettings];
|
TemporarySettings* currentSettings = [dataMan getSettings];
|
||||||
|
|
||||||
// Bitrate is persisted in kbps
|
// Bitrate is persisted in kbps
|
||||||
_bitrate = [currentSettings.bitrate integerValue];
|
_bitrate = [currentSettings.bitrate integerValue];
|
||||||
@@ -33,18 +33,44 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
|||||||
} else if ([currentSettings.height integerValue] == 1080) {
|
} else if ([currentSettings.height integerValue] == 1080) {
|
||||||
resolution = 1;
|
resolution = 1;
|
||||||
} else {
|
} else {
|
||||||
resolution = 2;
|
resolution = 0;
|
||||||
}
|
}
|
||||||
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
||||||
|
|
||||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||||
|
[self.resolutionSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||||
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
||||||
|
[self.framerateSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||||
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
||||||
[self.bitrateSlider setValue:(_bitrate / BITRATE_INTERVAL) animated:YES];
|
[self.bitrateSlider setValue:(_bitrate / BITRATE_INTERVAL) animated:YES];
|
||||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||||
[self updateBitrateText];
|
[self updateBitrateText];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) newResolutionFpsChosen {
|
||||||
|
NSInteger frameRate = [self getChosenFrameRate];
|
||||||
|
NSInteger resHeight = [self getChosenStreamHeight];
|
||||||
|
NSInteger defaultBitrate;
|
||||||
|
|
||||||
|
// 1080p60 is 20 Mbps
|
||||||
|
if (frameRate == 60 && resHeight == 1080) {
|
||||||
|
defaultBitrate = 20000;
|
||||||
|
}
|
||||||
|
// 720p60 and 1080p30 are 10 Mbps
|
||||||
|
else if (frameRate == 60 || resHeight == 1080) {
|
||||||
|
defaultBitrate = 10000;
|
||||||
|
}
|
||||||
|
// 720p30 is 5 Mbps
|
||||||
|
else {
|
||||||
|
defaultBitrate = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
_bitrate = defaultBitrate;
|
||||||
|
[self.bitrateSlider setValue:defaultBitrate / BITRATE_INTERVAL animated:YES];
|
||||||
|
|
||||||
|
[self updateBitrateText];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) bitrateSliderMoved {
|
- (void) bitrateSliderMoved {
|
||||||
_bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
|
_bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
|
||||||
[self updateBitrateText];
|
[self updateBitrateText];
|
||||||
@@ -55,25 +81,23 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
|||||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
|
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenFrameRate {
|
||||||
|
return [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenStreamHeight {
|
||||||
|
return [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenStreamWidth {
|
||||||
|
return [self getChosenStreamHeight] == 720 ? 1280 : 1920;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) saveSettings {
|
- (void) saveSettings {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
NSInteger framerate = [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
|
NSInteger framerate = [self getChosenFrameRate];
|
||||||
NSInteger height;
|
NSInteger height = [self getChosenStreamHeight];
|
||||||
NSInteger width;
|
NSInteger width = [self getChosenStreamWidth];
|
||||||
if ([self.resolutionSelector selectedSegmentIndex] == 2) {
|
|
||||||
// Get screen native resolution
|
|
||||||
height = [UIScreen mainScreen].bounds.size.height * [UIScreen mainScreen].scale;
|
|
||||||
width = [UIScreen mainScreen].bounds.size.width * [UIScreen mainScreen].scale;
|
|
||||||
|
|
||||||
UIAlertController *alertResolution = [UIAlertController alertControllerWithTitle:@"Native resolution" message:[NSString stringWithFormat:@"You must select the following resolution in the game settings: %lix%li", (long)width, (long)height] preferredStyle:UIAlertControllerStyleAlert];
|
|
||||||
[alertResolution addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:nil]];
|
|
||||||
[self presentViewController:alertResolution animated:YES completion:nil];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
height = [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
|
|
||||||
width = height == 720 ? 1280 : 1920;
|
|
||||||
}
|
|
||||||
NSInteger onscreenControls = [self.onscreenControlSelector selectedSegmentIndex];
|
NSInteger onscreenControls = [self.onscreenControlSelector selectedSegmentIndex];
|
||||||
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width onscreenControls:onscreenControls];
|
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width onscreenControls:onscreenControls];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,10 +84,10 @@
|
|||||||
[self presentViewController:conTermAlert animated:YES completion:nil];
|
[self presentViewController:conTermAlert animated:YES completion:nil];
|
||||||
});
|
});
|
||||||
|
|
||||||
[_streamMan stopStreamInternal];
|
[_streamMan stopStream];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stageStarting:(char*)stageName {
|
- (void) stageStarting:(const char*)stageName {
|
||||||
Log(LOG_I, @"Starting %s", stageName);
|
Log(LOG_I, @"Starting %s", stageName);
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
||||||
@@ -98,10 +98,10 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stageComplete:(char*)stageName {
|
- (void) stageComplete:(const char*)stageName {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stageFailed:(char*)stageName withError:(long)errorCode {
|
- (void) stageFailed:(const char*)stageName withError:(long)errorCode {
|
||||||
Log(LOG_I, @"Stage %s failed: %ld", stageName, errorCode);
|
Log(LOG_I, @"Stage %s failed: %ld", stageName, errorCode);
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
@@ -114,6 +114,8 @@
|
|||||||
}]];
|
}]];
|
||||||
[self presentViewController:alert animated:YES completion:nil];
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[_streamMan stopStream];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) launchFailed:(NSString*)message {
|
- (void) launchFailed:(NSString*)message {
|
||||||
@@ -130,11 +132,11 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) displayMessage:(char*)message {
|
- (void) displayMessage:(const char*)message {
|
||||||
Log(LOG_I, @"Display message: %s", message);
|
Log(LOG_I, @"Display message: %s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) displayTransientMessage:(char*)message {
|
- (void) displayTransientMessage:(const char*)message {
|
||||||
Log(LOG_I, @"Display transient message: %s", message);
|
Log(LOG_I, @"Display transient message: %s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,14 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 46;
|
objectVersion = 47;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */; };
|
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */; };
|
||||||
|
98CFB82F1CAD481B0048EF74 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98AB2E841CAD46840089BB98 /* libmoonlight-common.a */; };
|
||||||
|
98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */; };
|
||||||
|
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */; };
|
||||||
9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; };
|
9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; };
|
||||||
9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; };
|
9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; };
|
||||||
9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; };
|
9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; };
|
||||||
@@ -15,6 +18,10 @@
|
|||||||
9E5D60131A5A5A3900689918 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */; };
|
9E5D60131A5A5A3900689918 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */; };
|
||||||
9E5D60151A5A5A3900689918 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */; };
|
9E5D60151A5A5A3900689918 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */; };
|
||||||
9E5D60161A5A5A3900689918 /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */; };
|
9E5D60161A5A5A3900689918 /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */; };
|
||||||
|
D46A73AD1CBC7D090039F1EE /* ControllerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46A73AC1CBC7D090039F1EE /* ControllerUnitTests.swift */; };
|
||||||
|
D4746EEC1CBC740C006FB401 /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4746EEB1CBC740C006FB401 /* Controller.swift */; };
|
||||||
|
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */; };
|
||||||
|
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */; };
|
||||||
FB290CF219B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
|
FB290CF219B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
|
||||||
FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; };
|
FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; };
|
||||||
FB290CF619B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
|
FB290CF619B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
|
||||||
@@ -34,6 +41,7 @@
|
|||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
||||||
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
||||||
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
|
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
|
||||||
|
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB53E1421BE5DC4400CD6ECE /* IdManager.m */; };
|
||||||
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
|
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
|
||||||
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
||||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
||||||
@@ -60,7 +68,6 @@
|
|||||||
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; };
|
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; };
|
||||||
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; };
|
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; };
|
||||||
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; };
|
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; };
|
||||||
FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD421A7F0C6900872C98 /* Controller.m */; };
|
|
||||||
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD1C8E11A8AD71400C6703C /* Logger.m */; };
|
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD1C8E11A8AD71400C6703C /* Logger.m */; };
|
||||||
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 */; };
|
||||||
@@ -74,24 +81,37 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
987140011B04541A00AB57D5 /* PBXContainerItemProxy */ = {
|
98AB2E831CAD46840089BB98 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
|
containerPortal = 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */;
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = FB290E2D19B37A4E004C83CF;
|
|
||||||
remoteInfo = "moonlight-common";
|
|
||||||
};
|
|
||||||
FB1E430F1AE8B0F200AFF679 /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
|
|
||||||
proxyType = 2;
|
proxyType = 2;
|
||||||
remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
|
remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
|
||||||
remoteInfo = "moonlight-common";
|
remoteInfo = "moonlight-common";
|
||||||
};
|
};
|
||||||
|
98AB2E851CAD468B0089BB98 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = FB290E2D19B37A4E004C83CF;
|
||||||
|
remoteInfo = "moonlight-common";
|
||||||
|
};
|
||||||
|
D46A73A51CBC7CB60039F1EE /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = FB290CE619B2C406004C83CF /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = FB290CED19B2C406004C83CF;
|
||||||
|
remoteInfo = Moonlight;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "limelight-common-c/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
|
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryApp.h; path = Database/TemporaryApp.h; sourceTree = "<group>"; };
|
||||||
|
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryApp.m; path = Database/TemporaryApp.m; sourceTree = "<group>"; };
|
||||||
|
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "moonlight-common/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
|
||||||
|
98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryHost.h; path = Database/TemporaryHost.h; sourceTree = "<group>"; };
|
||||||
|
98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryHost.m; path = Database/TemporaryHost.m; sourceTree = "<group>"; };
|
||||||
|
98D5856E1C0ED0E800F6CC00 /* TemporarySettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporarySettings.h; path = Database/TemporarySettings.h; sourceTree = "<group>"; };
|
||||||
|
98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporarySettings.m; path = Database/TemporarySettings.m; sourceTree = "<group>"; };
|
||||||
9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; };
|
9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; };
|
||||||
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
|
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
|
||||||
9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
|
9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
|
||||||
@@ -99,6 +119,16 @@
|
|||||||
9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
|
9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
|
||||||
9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
|
9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
|
||||||
9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; };
|
9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; };
|
||||||
|
D46A73A01CBC7CB60039F1EE /* MoonlightUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MoonlightUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D46A73A41CBC7CB60039F1EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
D46A73AB1CBC7D080039F1EE /* MoonlightUnitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MoonlightUnitTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
D46A73AC1CBC7D090039F1EE /* ControllerUnitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllerUnitTests.swift; path = Input/ControllerUnitTests.swift; sourceTree = "<group>"; };
|
||||||
|
D4746EEA1CBC740C006FB401 /* Moonlight-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Moonlight-Bridging-Header.h"; path = "Input/Moonlight-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
D4746EEB1CBC740C006FB401 /* Controller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = "<group>"; };
|
||||||
|
FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComputerScrollView.h; sourceTree = "<group>"; };
|
||||||
|
FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ComputerScrollView.m; sourceTree = "<group>"; };
|
||||||
|
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppCollectionView.h; sourceTree = "<group>"; };
|
||||||
|
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppCollectionView.m; sourceTree = "<group>"; };
|
||||||
FB290CEE19B2C406004C83CF /* Moonlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Moonlight.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
FB290CEE19B2C406004C83CF /* Moonlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Moonlight.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
FB290CF119B2C406004C83CF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
FB290CF119B2C406004C83CF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
@@ -127,6 +157,9 @@
|
|||||||
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||||
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingFrameViewController.h; sourceTree = "<group>"; };
|
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingFrameViewController.h; sourceTree = "<group>"; };
|
||||||
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingFrameViewController.m; sourceTree = "<group>"; };
|
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingFrameViewController.m; sourceTree = "<group>"; };
|
||||||
|
FB53E1411BE5DC4400CD6ECE /* IdManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdManager.h; sourceTree = "<group>"; };
|
||||||
|
FB53E1421BE5DC4400CD6ECE /* IdManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdManager.m; sourceTree = "<group>"; };
|
||||||
|
FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.0-2.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
|
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
|
||||||
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
|
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
|
||||||
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
|
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
@@ -255,8 +288,6 @@
|
|||||||
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
|
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
|
||||||
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
|
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
|
||||||
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
||||||
FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
|
||||||
FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
|
||||||
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.0.xcdatamodel"; sourceTree = "<group>"; };
|
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>"; };
|
||||||
@@ -284,11 +315,18 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
D46A739D1CBC7CB60039F1EE /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
FB290CEB19B2C406004C83CF /* Frameworks */ = {
|
FB290CEB19B2C406004C83CF /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */,
|
98CFB82F1CAD481B0048EF74 /* libmoonlight-common.a in Frameworks */,
|
||||||
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */,
|
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */,
|
||||||
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */,
|
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */,
|
||||||
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */,
|
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */,
|
||||||
@@ -307,6 +345,14 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
98AB2E801CAD46830089BB98 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
98AB2E841CAD46840089BB98 /* libmoonlight-common.a */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9E5D5FF61A5A5A3900689918 /* Font */ = {
|
9E5D5FF61A5A5A3900689918 /* Font */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -329,19 +375,30 @@
|
|||||||
path = Roboto;
|
path = Roboto;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB1E430C1AE8B0F200AFF679 /* Products */ = {
|
D46A73A11CBC7CB60039F1EE /* MoonlightUnitTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */,
|
D46A73AB1CBC7D080039F1EE /* MoonlightUnitTests-Bridging-Header.h */,
|
||||||
|
D46A73AA1CBC7CEF0039F1EE /* Input */,
|
||||||
|
D46A73A41CBC7CB60039F1EE /* Info.plist */,
|
||||||
);
|
);
|
||||||
name = Products;
|
path = MoonlightUnitTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D46A73AA1CBC7CEF0039F1EE /* Input */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D46A73AC1CBC7D090039F1EE /* ControllerUnitTests.swift */,
|
||||||
|
);
|
||||||
|
name = Input;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB290CE519B2C406004C83CF = {
|
FB290CE519B2C406004C83CF = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */,
|
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */,
|
||||||
FB290CF919B2C406004C83CF /* Limelight */,
|
FB290CF919B2C406004C83CF /* Moonlight */,
|
||||||
|
D46A73A11CBC7CB60039F1EE /* MoonlightUnitTests */,
|
||||||
FB290CF019B2C406004C83CF /* Frameworks */,
|
FB290CF019B2C406004C83CF /* Frameworks */,
|
||||||
FB290CEF19B2C406004C83CF /* Products */,
|
FB290CEF19B2C406004C83CF /* Products */,
|
||||||
);
|
);
|
||||||
@@ -351,6 +408,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FB290CEE19B2C406004C83CF /* Moonlight.app */,
|
FB290CEE19B2C406004C83CF /* Moonlight.app */,
|
||||||
|
D46A73A01CBC7CB60039F1EE /* MoonlightUnitTests.xctest */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -374,9 +432,10 @@
|
|||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB290CF919B2C406004C83CF /* Limelight */ = {
|
FB290CF919B2C406004C83CF /* Moonlight */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D4746EEA1CBC740C006FB401 /* Moonlight-Bridging-Header.h */,
|
||||||
9E5D5FF61A5A5A3900689918 /* Font */,
|
9E5D5FF61A5A5A3900689918 /* Font */,
|
||||||
FB89460419F646E200339C8A /* Crypto */,
|
FB89460419F646E200339C8A /* Crypto */,
|
||||||
FB89460919F646E200339C8A /* Input */,
|
FB89460919F646E200339C8A /* Input */,
|
||||||
@@ -397,7 +456,12 @@
|
|||||||
FB89463719F6473800339C8A /* Launch Screen.xib */,
|
FB89463719F6473800339C8A /* Launch Screen.xib */,
|
||||||
FB290D0819B2C406004C83CF /* Images.xcassets */,
|
FB290D0819B2C406004C83CF /* Images.xcassets */,
|
||||||
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */,
|
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */,
|
||||||
|
FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */,
|
||||||
|
FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */,
|
||||||
|
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */,
|
||||||
|
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */,
|
||||||
);
|
);
|
||||||
|
name = Moonlight;
|
||||||
path = Limelight;
|
path = Limelight;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -419,6 +483,8 @@
|
|||||||
FB89460619F646E200339C8A /* CryptoManager.m */,
|
FB89460619F646E200339C8A /* CryptoManager.m */,
|
||||||
FB89460719F646E200339C8A /* mkcert.c */,
|
FB89460719F646E200339C8A /* mkcert.c */,
|
||||||
FB89460819F646E200339C8A /* mkcert.h */,
|
FB89460819F646E200339C8A /* mkcert.h */,
|
||||||
|
FB53E1411BE5DC4400CD6ECE /* IdManager.h */,
|
||||||
|
FB53E1421BE5DC4400CD6ECE /* IdManager.m */,
|
||||||
);
|
);
|
||||||
path = Crypto;
|
path = Crypto;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -428,8 +494,7 @@
|
|||||||
children = (
|
children = (
|
||||||
FB89460A19F646E200339C8A /* ControllerSupport.h */,
|
FB89460A19F646E200339C8A /* ControllerSupport.h */,
|
||||||
FB89460B19F646E200339C8A /* ControllerSupport.m */,
|
FB89460B19F646E200339C8A /* ControllerSupport.m */,
|
||||||
FB9AFD411A7F0C6900872C98 /* Controller.h */,
|
D4746EEB1CBC740C006FB401 /* Controller.swift */,
|
||||||
FB9AFD421A7F0C6900872C98 /* Controller.m */,
|
|
||||||
FB89460C19F646E200339C8A /* StreamView.h */,
|
FB89460C19F646E200339C8A /* StreamView.h */,
|
||||||
FB89460D19F646E200339C8A /* StreamView.m */,
|
FB89460D19F646E200339C8A /* StreamView.m */,
|
||||||
FB4678EB1A50C40900377732 /* OnScreenControls.h */,
|
FB4678EB1A50C40900377732 /* OnScreenControls.h */,
|
||||||
@@ -712,6 +777,12 @@
|
|||||||
FBD3495D1A004412002D2A60 /* Settings.m */,
|
FBD3495D1A004412002D2A60 /* Settings.m */,
|
||||||
FBD349601A0089F6002D2A60 /* DataManager.h */,
|
FBD349601A0089F6002D2A60 /* DataManager.h */,
|
||||||
FBD349611A0089F6002D2A60 /* DataManager.m */,
|
FBD349611A0089F6002D2A60 /* DataManager.m */,
|
||||||
|
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */,
|
||||||
|
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */,
|
||||||
|
98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */,
|
||||||
|
98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */,
|
||||||
|
98D5856E1C0ED0E800F6CC00 /* TemporarySettings.h */,
|
||||||
|
98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */,
|
||||||
);
|
);
|
||||||
name = Database;
|
name = Database;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -719,6 +790,24 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
D46A739F1CBC7CB60039F1EE /* MoonlightUnitTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = D46A73A91CBC7CB60039F1EE /* Build configuration list for PBXNativeTarget "MoonlightUnitTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
D46A739C1CBC7CB60039F1EE /* Sources */,
|
||||||
|
D46A739D1CBC7CB60039F1EE /* Frameworks */,
|
||||||
|
D46A739E1CBC7CB60039F1EE /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
D46A73A61CBC7CB60039F1EE /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = MoonlightUnitTests;
|
||||||
|
productName = MoonlightUnitTests;
|
||||||
|
productReference = D46A73A01CBC7CB60039F1EE /* MoonlightUnitTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
FB290CED19B2C406004C83CF /* Moonlight */ = {
|
FB290CED19B2C406004C83CF /* Moonlight */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Moonlight" */;
|
buildConfigurationList = FB290D2019B2C406004C83CF /* Build configuration list for PBXNativeTarget "Moonlight" */;
|
||||||
@@ -730,7 +819,7 @@
|
|||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
987140021B04541A00AB57D5 /* PBXTargetDependency */,
|
98AB2E861CAD468B0089BB98 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Moonlight;
|
name = Moonlight;
|
||||||
productName = Limelight;
|
productName = Limelight;
|
||||||
@@ -743,16 +832,23 @@
|
|||||||
FB290CE619B2C406004C83CF /* Project object */ = {
|
FB290CE619B2C406004C83CF /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0700;
|
LastSwiftUpdateCheck = 0730;
|
||||||
ORGANIZATIONNAME = "Limelight Stream";
|
LastUpgradeCheck = 0800;
|
||||||
|
ORGANIZATIONNAME = "Moonlight Stream";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
D46A739F1CBC7CB60039F1EE = {
|
||||||
|
CreatedOnToolsVersion = 7.3;
|
||||||
|
LastSwiftMigration = 0800;
|
||||||
|
TestTargetID = FB290CED19B2C406004C83CF;
|
||||||
|
};
|
||||||
FB290CED19B2C406004C83CF = {
|
FB290CED19B2C406004C83CF = {
|
||||||
DevelopmentTeam = DM46QST4M7;
|
DevelopmentTeam = DM46QST4M7;
|
||||||
|
LastSwiftMigration = 0800;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
|
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
|
||||||
compatibilityVersion = "Xcode 3.2";
|
compatibilityVersion = "Xcode 6.3";
|
||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
@@ -763,28 +859,36 @@
|
|||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectReferences = (
|
projectReferences = (
|
||||||
{
|
{
|
||||||
ProductGroup = FB1E430C1AE8B0F200AFF679 /* Products */;
|
ProductGroup = 98AB2E801CAD46830089BB98 /* Products */;
|
||||||
ProjectRef = 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */;
|
ProjectRef = 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
FB290CED19B2C406004C83CF /* Moonlight */,
|
FB290CED19B2C406004C83CF /* Moonlight */,
|
||||||
|
D46A739F1CBC7CB60039F1EE /* MoonlightUnitTests */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXReferenceProxy section */
|
/* Begin PBXReferenceProxy section */
|
||||||
FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */ = {
|
98AB2E841CAD46840089BB98 /* libmoonlight-common.a */ = {
|
||||||
isa = PBXReferenceProxy;
|
isa = PBXReferenceProxy;
|
||||||
fileType = archive.ar;
|
fileType = archive.ar;
|
||||||
path = "libmoonlight-common.a";
|
path = "libmoonlight-common.a";
|
||||||
remoteRef = FB1E430F1AE8B0F200AFF679 /* PBXContainerItemProxy */;
|
remoteRef = 98AB2E831CAD46840089BB98 /* PBXContainerItemProxy */;
|
||||||
sourceTree = BUILT_PRODUCTS_DIR;
|
sourceTree = BUILT_PRODUCTS_DIR;
|
||||||
};
|
};
|
||||||
/* End PBXReferenceProxy section */
|
/* End PBXReferenceProxy section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
D46A739E1CBC7CB60039F1EE /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
FB290CEC19B2C406004C83CF /* Resources */ = {
|
FB290CEC19B2C406004C83CF /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -807,6 +911,14 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
D46A739C1CBC7CB60039F1EE /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D46A73AD1CBC7D090039F1EE /* ControllerUnitTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
FB290CEA19B2C406004C83CF /* Sources */ = {
|
FB290CEA19B2C406004C83CF /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -821,31 +933,37 @@
|
|||||||
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
||||||
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
||||||
|
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
|
||||||
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 */,
|
||||||
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
||||||
FBFCB3311B50B29400089F8A /* Host.m in Sources */,
|
FBFCB3311B50B29400089F8A /* Host.m in Sources */,
|
||||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
||||||
|
FB1D59971BBCCB6400F482CA /* ComputerScrollView.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 */,
|
||||||
|
98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */,
|
||||||
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
||||||
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
|
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
|
||||||
|
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */,
|
||||||
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
||||||
|
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */,
|
||||||
|
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */,
|
||||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
||||||
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
||||||
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
|
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
|
||||||
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
|
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
|
||||||
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
||||||
FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */,
|
|
||||||
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */,
|
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */,
|
||||||
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
|
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
|
||||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||||
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
||||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
||||||
|
D4746EEC1CBC740C006FB401 /* Controller.swift in Sources */,
|
||||||
FBFCB3351B50B29400089F8A /* App.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 */,
|
||||||
@@ -856,10 +974,15 @@
|
|||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
987140021B04541A00AB57D5 /* PBXTargetDependency */ = {
|
98AB2E861CAD468B0089BB98 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
name = "moonlight-common";
|
name = "moonlight-common";
|
||||||
targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */;
|
targetProxy = 98AB2E851CAD468B0089BB98 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
D46A73A61CBC7CB60039F1EE /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = FB290CED19B2C406004C83CF /* Moonlight */;
|
||||||
|
targetProxy = D46A73A51CBC7CB60039F1EE /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
@@ -875,6 +998,54 @@
|
|||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
D46A73A71CBC7CB60039F1EE /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
INFOPLIST_FILE = MoonlightUnitTests/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.MoonlightUnitTests";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "MoonlightUnitTests/MoonlightUnitTests-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
D46A73A81CBC7CB60039F1EE /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
INFOPLIST_FILE = MoonlightUnitTests/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.MoonlightUnitTests";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "MoonlightUnitTests/MoonlightUnitTests-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
FB290D1E19B2C406004C83CF /* Debug */ = {
|
FB290D1E19B2C406004C83CF /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -888,15 +1059,20 @@
|
|||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
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_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@@ -929,14 +1105,19 @@
|
|||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
@@ -955,6 +1136,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
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;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -963,11 +1145,12 @@
|
|||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||||
"$(PROJECT_DIR)/limelight-common-c/limelight-common",
|
"$(PROJECT_DIR)/moonlight-common/moonlight-common-c/src",
|
||||||
"$(SDKROOT)/usr/include/libxml2/**",
|
"$(SDKROOT)/usr/include/libxml2/**",
|
||||||
"$(PROJECT_DIR)/libs/**",
|
"$(PROJECT_DIR)/libs/**",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "Limelight/Limelight-Info.plist";
|
INFOPLIST_FILE = "Limelight/Limelight-Info.plist";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/libs/opus/lib",
|
"$(PROJECT_DIR)/libs/opus/lib",
|
||||||
@@ -977,6 +1160,9 @@
|
|||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Limelight/Input/Moonlight-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
WRAPPER_EXTENSION = app;
|
WRAPPER_EXTENSION = app;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -985,19 +1171,21 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
ENABLE_BITCODE = NO;
|
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 = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||||
"$(PROJECT_DIR)/limelight-common-c/limelight-common",
|
"$(PROJECT_DIR)/moonlight-common/moonlight-common-c/src",
|
||||||
"$(SDKROOT)/usr/include/libxml2/**",
|
"$(SDKROOT)/usr/include/libxml2/**",
|
||||||
"$(PROJECT_DIR)/libs/**",
|
"$(PROJECT_DIR)/libs/**",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "Limelight/Limelight-Info.plist";
|
INFOPLIST_FILE = "Limelight/Limelight-Info.plist";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/libs/opus/lib",
|
"$(PROJECT_DIR)/libs/opus/lib",
|
||||||
@@ -1007,6 +1195,9 @@
|
|||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Limelight/Input/Moonlight-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
WRAPPER_EXTENSION = app;
|
WRAPPER_EXTENSION = app;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
@@ -1014,6 +1205,15 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
D46A73A91CBC7CB60039F1EE /* Build configuration list for PBXNativeTarget "MoonlightUnitTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D46A73A71CBC7CB60039F1EE /* Debug */,
|
||||||
|
D46A73A81CBC7CB60039F1EE /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */ = {
|
FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
@@ -1038,12 +1238,13 @@
|
|||||||
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
|
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
|
||||||
isa = XCVersionGroup;
|
isa = XCVersionGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */,
|
||||||
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */,
|
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 = FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */;
|
currentVersion = FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */;
|
||||||
path = Limelight.xcdatamodeld;
|
path = Limelight.xcdatamodeld;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
versionGroupType = wrapper.xcdatamodel;
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?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>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</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>
|
||||||