mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-10-25 21:40:08 +00:00
Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6273f2bb29 | ||
|
|
fac48ecf42 | ||
|
|
b5bf26bb2d | ||
|
|
00fab87b4c | ||
|
|
3554b40962 | ||
|
|
aa3752a905 | ||
|
|
c0a3ae9371 | ||
|
|
47850cd658 | ||
|
|
1b98870b41 | ||
|
|
ef98976ebf | ||
|
|
ba022da665 | ||
|
|
ae9abf2911 | ||
|
|
99e7f59df4 | ||
|
|
8273173080 | ||
|
|
3357b3882b | ||
|
|
b7510717c8 | ||
|
|
5434542877 | ||
|
|
4c2f6b269a | ||
|
|
0ccf046c69 | ||
|
|
f0b6602b99 | ||
|
|
72e0da4319 | ||
|
|
d2ad8b12ce | ||
|
|
6ef492662b | ||
|
|
3c7f33a80c | ||
|
|
eeec1f1cf5 | ||
|
|
45545e8f9b | ||
|
|
85b65d7112 | ||
|
|
26f7a27117 | ||
|
|
ea24b39fbe | ||
|
|
01a2853032 | ||
|
|
bfca061694 | ||
|
|
4a9bb00e0d | ||
|
|
72271a0c74 | ||
|
|
1ca787822b |
No files matched your search
+1
-1
@@ -1 +1 @@
|
|||||||
Limelight.xcodeproj/xcuserdata/
|
**/xcuserdata/
|
||||||
Binary file not shown.
Binary file not shown.
@@ -771,8 +771,8 @@
|
|||||||
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__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
@@ -811,8 +811,8 @@
|
|||||||
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__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Distribution: Diego Waxemberg (DM46QST4M7)";
|
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Diego Waxemberg (DM46QST4M7)";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
@@ -823,7 +823,7 @@
|
|||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
PROVISIONING_PROFILE = "d8351c44-2c9d-4b3a-bc67-ea963350dcbe";
|
PROVISIONING_PROFILE = "";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
@@ -834,8 +834,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
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 = (
|
||||||
@@ -862,8 +862,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Distribution: Diego Waxemberg (DM46QST4M7)";
|
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Diego Waxemberg (DM46QST4M7)";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
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 = (
|
||||||
@@ -880,7 +880,7 @@
|
|||||||
"$(PROJECT_DIR)/libs/openssl/lib",
|
"$(PROJECT_DIR)/libs/openssl/lib",
|
||||||
);
|
);
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "d8351c44-2c9d-4b3a-bc67-ea963350dcbe";
|
PROVISIONING_PROFILE = "";
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
WRAPPER_EXTENSION = app;
|
WRAPPER_EXTENSION = app;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:Limelight.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
|
||||||
|
<false/>
|
||||||
|
<key>IDESourceControlProjectIdentifier</key>
|
||||||
|
<string>054A62F3-1197-45FB-A607-EA7922396E24</string>
|
||||||
|
<key>IDESourceControlProjectName</key>
|
||||||
|
<string>Limelight</string>
|
||||||
|
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||||
|
<dict>
|
||||||
|
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
|
||||||
|
<string>github.com:limelight-stream/limelight-ios.git</string>
|
||||||
|
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
|
||||||
|
<string>github.com:limelight-stream/limelight-common-c.git</string>
|
||||||
|
</dict>
|
||||||
|
<key>IDESourceControlProjectPath</key>
|
||||||
|
<string>Limelight.xcodeproj</string>
|
||||||
|
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||||
|
<dict>
|
||||||
|
<key>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</key>
|
||||||
|
<string>../..</string>
|
||||||
|
<key>EB99D631D5149240E91F8D168F0F298D7A5BAA89</key>
|
||||||
|
<string>../../limelight-common-c</string>
|
||||||
|
</dict>
|
||||||
|
<key>IDESourceControlProjectURL</key>
|
||||||
|
<string>github.com:limelight-stream/limelight-ios.git</string>
|
||||||
|
<key>IDESourceControlProjectVersion</key>
|
||||||
|
<integer>111</integer>
|
||||||
|
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||||
|
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
|
||||||
|
<key>IDESourceControlProjectWCConfigurations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||||
|
<string>public.vcs.git</string>
|
||||||
|
<key>IDESourceControlWCCIdentifierKey</key>
|
||||||
|
<string>EB99D631D5149240E91F8D168F0F298D7A5BAA89</string>
|
||||||
|
<key>IDESourceControlWCCName</key>
|
||||||
|
<string>limelight-common-c</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||||
|
<string>public.vcs.git</string>
|
||||||
|
<key>IDESourceControlWCCIdentifierKey</key>
|
||||||
|
<string>A4B0849259F9566B0CBA84A6D3D4A0F895C03123</string>
|
||||||
|
<key>IDESourceControlWCCName</key>
|
||||||
|
<string>limelight-ios</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -88,8 +88,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
if (_managedObjectModel != nil) {
|
if (_managedObjectModel != nil) {
|
||||||
return _managedObjectModel;
|
return _managedObjectModel;
|
||||||
}
|
}
|
||||||
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Limelight_iOS" withExtension:@"momd"];
|
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
|
||||||
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
||||||
return _managedObjectModel;
|
return _managedObjectModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>7</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>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
||||||
|
|
||||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
|
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
|
||||||
|
+ (NSString*) getStatusStringFromXML:(NSData*)xml;
|
||||||
|
|
||||||
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
||||||
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
||||||
|
|||||||
@@ -25,6 +25,24 @@
|
|||||||
|
|
||||||
static const NSString* PORT = @"47984";
|
static const NSString* PORT = @"47984";
|
||||||
|
|
||||||
|
+ (NSString*) getStatusStringFromXML:(NSData*)xml {
|
||||||
|
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
||||||
|
|
||||||
|
if (docPtr == NULL) {
|
||||||
|
NSLog(@"ERROR: An error occured trying to parse xml.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* string;
|
||||||
|
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
|
||||||
|
|
||||||
|
string = [HttpManager getStatusMessage: rootNode];
|
||||||
|
xmlFree(rootNode);
|
||||||
|
xmlFree(docPtr);
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
|
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
|
||||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
||||||
|
|
||||||
@@ -38,7 +56,8 @@ static const NSString* PORT = @"47984";
|
|||||||
|
|
||||||
// Check root status_code
|
// Check root status_code
|
||||||
if (![HttpManager verifyStatus: rootNode]) {
|
if (![HttpManager verifyStatus: rootNode]) {
|
||||||
//TODO: handle error
|
NSLog(@"ERROR: Request returned with failure status");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the root node
|
// Skip the root node
|
||||||
@@ -59,6 +78,13 @@ static const NSString* PORT = @"47984";
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSString*) getStatusMessage:(xmlNodePtr)docRoot {
|
||||||
|
xmlChar* statusMsgXml = xmlGetProp(docRoot, (const xmlChar*)"status_message");
|
||||||
|
NSString* statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
|
||||||
|
xmlFree(statusMsgXml);
|
||||||
|
return statusMsg;
|
||||||
|
}
|
||||||
|
|
||||||
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
|
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
|
||||||
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
|
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
|
||||||
@@ -101,63 +127,75 @@ static const NSString* PORT = @"47984";
|
|||||||
[NSURLConnection connectionWithRequest:request delegate:self];
|
[NSURLConnection connectionWithRequest:request delegate:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) createRequestFromString:(NSString*) urlString {
|
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
|
||||||
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||||
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
|
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
|
||||||
return [NSURLRequest requestWithURL:url];
|
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
||||||
|
if (normalTimeout) {
|
||||||
|
// Timeout the request after 5 seconds
|
||||||
|
[request setTimeoutInterval:5];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Timeout the request after 60 seconds
|
||||||
|
[request setTimeoutInterval:60];
|
||||||
|
}
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newPairRequest:(NSData*)salt {
|
- (NSURLRequest*) newPairRequest:(NSData*)salt {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
|
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
|
||||||
return [self createRequestFromString:urlString];
|
// This call blocks while waiting for the user to input the PIN on the PC
|
||||||
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newUnpairRequest {
|
- (NSURLRequest*) newUnpairRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
|
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
|
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
|
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
|
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
|
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret];
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newPairChallenge {
|
- (NSURLRequest*) newPairChallenge {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName];
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest *)newAppListRequest {
|
- (NSURLRequest *)newAppListRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest *)newServerInfoRequest {
|
- (NSURLRequest *)newServerInfoRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
|
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
|
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
|
||||||
return [self createRequestFromString:urlString];
|
// This blocks while the app is launching
|
||||||
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
|
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId];
|
||||||
return [self createRequestFromString:urlString];
|
// This blocks while the app is resuming
|
||||||
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*) bytesToHex:(NSData*)data {
|
- (NSString*) bytesToHex:(NSData*)data {
|
||||||
@@ -229,6 +267,7 @@ static const NSString* PORT = @"47984";
|
|||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||||
NSLog(@"connection error: %@", error);
|
NSLog(@"connection error: %@", error);
|
||||||
|
dispatch_semaphore_signal(_requestLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -9,10 +9,12 @@
|
|||||||
#import "MDNSManager.h"
|
#import "MDNSManager.h"
|
||||||
#import "Computer.h"
|
#import "Computer.h"
|
||||||
|
|
||||||
@implementation MDNSManager : NSObject
|
@implementation MDNSManager {
|
||||||
NSNetServiceBrowser* mDNSBrowser;
|
NSNetServiceBrowser* mDNSBrowser;
|
||||||
NSMutableArray* domains;
|
NSMutableArray* domains;
|
||||||
NSMutableArray* services;
|
NSMutableArray* services;
|
||||||
|
BOOL scanActive;
|
||||||
|
}
|
||||||
|
|
||||||
static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
||||||
|
|
||||||
@@ -32,11 +34,13 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
|
|
||||||
- (void) searchForHosts {
|
- (void) searchForHosts {
|
||||||
NSLog(@"Starting mDNS discovery");
|
NSLog(@"Starting mDNS discovery");
|
||||||
|
scanActive = TRUE;
|
||||||
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stopSearching {
|
- (void) stopSearching {
|
||||||
NSLog(@"Stopping mDNS discovery");
|
NSLog(@"Stopping mDNS discovery");
|
||||||
|
scanActive = FALSE;
|
||||||
[mDNSBrowser stop];
|
[mDNSBrowser stop];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +51,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
[hosts addObject:[[Computer alloc] initWithHost:service]];
|
[hosts addObject:[[Computer alloc] initWithHost:service]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [[NSArray alloc] initWithArray:hosts];
|
return hosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceDidResolveAddress:(NSNetService *)service {
|
- (void)netServiceDidResolveAddress:(NSNetService *)service {
|
||||||
@@ -57,12 +61,21 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
|
|
||||||
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
|
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
|
||||||
NSLog(@"Did not resolve address for: %@\n%@", sender, [errorDict description]);
|
NSLog(@"Did not resolve address for: %@\n%@", sender, [errorDict description]);
|
||||||
|
|
||||||
|
// Schedule a retry in 2 seconds
|
||||||
|
[NSTimer scheduledTimerWithTimeInterval:2.0
|
||||||
|
target:self
|
||||||
|
selector:@selector(retryResolveTimerCallback:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
||||||
NSLog(@"Found service: %@", aNetService);
|
NSLog(@"Found service: %@", aNetService);
|
||||||
[aNetService setDelegate:self];
|
[aNetService setDelegate:self];
|
||||||
[aNetService resolveWithTimeout:5];
|
[aNetService resolveWithTimeout:5];
|
||||||
|
|
||||||
|
[services removeObject:aNetService];
|
||||||
[services addObject:aNetService];
|
[services addObject:aNetService];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +87,39 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict {
|
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict {
|
||||||
NSLog(@"Did not perform search");
|
NSLog(@"Did not perform search");
|
||||||
NSLog(@"%@", [errorDict description]);
|
NSLog(@"%@", [errorDict description]);
|
||||||
|
|
||||||
|
// Schedule a retry in 2 seconds
|
||||||
|
[NSTimer scheduledTimerWithTimeInterval:2.0
|
||||||
|
target:self
|
||||||
|
selector:@selector(retrySearchTimerCallback:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)retrySearchTimerCallback:(NSTimer *)timer {
|
||||||
|
// Check if we've been stopped since this was queued
|
||||||
|
if (!scanActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"Retrying mDNS search");
|
||||||
|
[mDNSBrowser stop];
|
||||||
|
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)retryResolveTimerCallback:(NSTimer *)timer {
|
||||||
|
// Check if we've been stopped since this was queued
|
||||||
|
if (!scanActive) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"Retrying mDNS resolution");
|
||||||
|
for (NSNetService* service in services) {
|
||||||
|
if (service.hostName == nil) {
|
||||||
|
[service setDelegate:self];
|
||||||
|
[service resolveWithTimeout:5];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -28,12 +28,19 @@
|
|||||||
|
|
||||||
- (void) main {
|
- (void) main {
|
||||||
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
|
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
|
||||||
if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
|
if (serverInfo == NULL) {
|
||||||
|
[_callback pairFailed:@"Unable to connect to PC"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) {
|
||||||
|
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||||
|
}
|
||||||
|
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
|
||||||
[self initiatePair];
|
[self initiatePair];
|
||||||
} else {
|
} else {
|
||||||
[_callback pairFailed:@"Already Paired"];
|
[_callback pairFailed:@"This device is already paired."];
|
||||||
}
|
}
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newAppListRequest]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) initiatePair {
|
- (void) initiatePair {
|
||||||
@@ -43,10 +50,11 @@
|
|||||||
[_callback showPIN:PIN];
|
[_callback showPIN:PIN];
|
||||||
|
|
||||||
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
|
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
|
||||||
if ([[HttpManager getStringFromXML:pairResp tag:@"paired"] intValue] != 1) {
|
NSString* pairedString;
|
||||||
|
pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"];
|
||||||
|
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Pairing was declined by the target."];
|
||||||
[_callback pairFailed:@"pairResp failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,10 +67,10 @@
|
|||||||
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
||||||
|
|
||||||
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
|
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
|
||||||
if ([[HttpManager getStringFromXML:challengeResp tag:@"paired"] intValue] != 1) {
|
pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"];
|
||||||
|
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Pairing stage #2 failed"];
|
||||||
[_callback pairFailed:@"challengeResp failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +85,10 @@
|
|||||||
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
||||||
|
|
||||||
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
|
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
|
||||||
if ([[HttpManager getStringFromXML:secretResp tag:@"paired"] intValue] != 1) {
|
pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"];
|
||||||
|
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Pairing stage #3 failed"];
|
||||||
[_callback pairFailed:@"secretResp failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,33 +98,31 @@
|
|||||||
|
|
||||||
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Server certificate invalid"];
|
||||||
[_callback pairFailed:@"verifySignature failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
||||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Incorrect PIN"];
|
||||||
[_callback pairFailed:@"serverChallengeResp failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
|
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
|
||||||
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
|
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
|
||||||
if (![[HttpManager getStringFromXML:clientSecretResp tag:@"paired"] isEqual:@"1"]) {
|
pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"];
|
||||||
|
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Pairing stage #4 failed"];
|
||||||
[_callback pairFailed:@"clientSecretResp failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
|
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
|
||||||
if (![[HttpManager getStringFromXML:clientPairChallenge tag:@"paired"] isEqual:@"1"]) {
|
pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"];
|
||||||
|
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||||
//TODO: better message
|
[_callback pairFailed:@"Pairing stage #5 failed"];
|
||||||
[_callback pairFailed:@"clientPairChallenge failed"];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[_callback pairSuccessful];
|
[_callback pairSuccessful];
|
||||||
|
|||||||
@@ -10,15 +10,22 @@
|
|||||||
#import "VideoDecoderRenderer.h"
|
#import "VideoDecoderRenderer.h"
|
||||||
#import "StreamConfiguration.h"
|
#import "StreamConfiguration.h"
|
||||||
|
|
||||||
@protocol ConTermCallback <NSObject>
|
@protocol ConnectionCallbacks <NSObject>
|
||||||
|
|
||||||
- (void) connectionTerminated;
|
- (void) connectionStarted;
|
||||||
|
- (void) connectionTerminated:(long)errorCode;
|
||||||
|
- (void) stageStarting:(char*)stageName;
|
||||||
|
- (void) stageComplete:(char*)stageName;
|
||||||
|
- (void) stageFailed:(char*)stageName withError:(long)errorCode;
|
||||||
|
- (void) launchFailed:(NSString*)message;
|
||||||
|
- (void) displayMessage:(char*)message;
|
||||||
|
- (void) displayTransientMessage:(char*)message;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface Connection : NSOperation <NSStreamDelegate>
|
@interface Connection : NSOperation <NSStreamDelegate>
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionTerminatedCallback:(id<ConTermCallback>)callback;
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks;
|
||||||
-(void) terminate;
|
-(void) terminate;
|
||||||
-(void) main;
|
-(void) main;
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,10 @@
|
|||||||
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
||||||
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
||||||
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpusDecoder *opusDecoder;
|
static OpusDecoder *opusDecoder;
|
||||||
static id<ConTermCallback> _callback;
|
static id<ConnectionCallbacks> _callbacks;
|
||||||
|
|
||||||
#define PCM_BUFFER_SIZE 1024
|
#define PCM_BUFFER_SIZE 1024
|
||||||
#define OUTPUT_BUS 0
|
#define OUTPUT_BUS 0
|
||||||
@@ -243,37 +242,37 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||||||
|
|
||||||
void ClStageStarting(int stage)
|
void ClStageStarting(int stage)
|
||||||
{
|
{
|
||||||
|
[_callbacks stageStarting:(char*)LiGetStageName(stage)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClStageComplete(int stage)
|
void ClStageComplete(int stage)
|
||||||
{
|
{
|
||||||
|
[_callbacks stageComplete:(char*)LiGetStageName(stage)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClStageFailed(int stage, long errorCode)
|
void ClStageFailed(int stage, long errorCode)
|
||||||
{
|
{
|
||||||
printf("Stage %d failed: %ld\n", stage, errorCode);
|
[_callbacks stageFailed:(char*)LiGetStageName(stage) withError:errorCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClConnectionStarted(void)
|
void ClConnectionStarted(void)
|
||||||
{
|
{
|
||||||
printf("Connection started\n");
|
[_callbacks connectionStarted];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClConnectionTerminated(long errorCode)
|
void ClConnectionTerminated(long errorCode)
|
||||||
{
|
{
|
||||||
printf("ConnectionTerminated: %ld\n", errorCode);
|
[_callbacks connectionTerminated: errorCode];
|
||||||
|
|
||||||
[_callback connectionTerminated];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClDisplayMessage(char* message)
|
void ClDisplayMessage(char* message)
|
||||||
{
|
{
|
||||||
printf("DisplayMessage: %s\n", message);
|
[_callbacks displayMessage: message];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClDisplayTransientMessage(char* message)
|
void ClDisplayTransientMessage(char* message)
|
||||||
{
|
{
|
||||||
printf("DisplayTransientMessage: %s\n", message);
|
[_callbacks displayTransientMessage: message];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) terminate
|
-(void) terminate
|
||||||
@@ -286,12 +285,12 @@ void ClDisplayTransientMessage(char* message)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionTerminatedCallback:(id<ConTermCallback>)callback
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_host = config.hostAddr;
|
_host = config.hostAddr;
|
||||||
renderer = myRenderer;
|
renderer = myRenderer;
|
||||||
_callback = callback;
|
_callbacks = callbacks;
|
||||||
_streamConfig.width = config.width;
|
_streamConfig.width = config.width;
|
||||||
_streamConfig.height = config.height;
|
_streamConfig.height = config.height;
|
||||||
_streamConfig.fps = config.frameRate;
|
_streamConfig.fps = config.frameRate;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
@interface StreamManager : NSOperation
|
@interface StreamManager : NSOperation
|
||||||
|
|
||||||
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionTerminatedCallback:(id<ConTermCallback>)callback;
|
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id<ConnectionCallbacks>)callback;
|
||||||
- (void) stopStream;
|
- (void) stopStream;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -14,18 +14,17 @@
|
|||||||
@implementation StreamManager {
|
@implementation StreamManager {
|
||||||
StreamConfiguration* _config;
|
StreamConfiguration* _config;
|
||||||
UIView* _renderView;
|
UIView* _renderView;
|
||||||
id<ConTermCallback> _callback;
|
id<ConnectionCallbacks> _callbacks;
|
||||||
Connection* _connection;
|
Connection* _connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionTerminatedCallback:(id<ConTermCallback>)callback {
|
- (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id<ConnectionCallbacks>)callbacks {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_config = config;
|
_config = config;
|
||||||
_renderView = view;
|
_renderView = view;
|
||||||
_callback = callback;
|
_callbacks = callbacks;
|
||||||
_config.riKey = [Utils randomBytes:16];
|
_config.riKey = [Utils randomBytes:16];
|
||||||
_config.riKeyId = arc4random();
|
_config.riKeyId = arc4random();
|
||||||
_config.bitRate = 10000;
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,16 +40,34 @@
|
|||||||
cert:cert];
|
cert:cert];
|
||||||
|
|
||||||
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
||||||
if (![[HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"] isEqualToString:@"0"]) {
|
NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"];
|
||||||
|
NSString* pairStatus = [HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"];
|
||||||
|
if (currentGame == NULL || pairStatus == NULL) {
|
||||||
|
[_callbacks launchFailed:@"Failed to connect to PC"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![pairStatus isEqualToString:@"1"]) {
|
||||||
|
// Not paired
|
||||||
|
[_callbacks launchFailed:@"Device not paired to PC"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resumeApp and launchApp handle calling launchFailed
|
||||||
|
if (![currentGame isEqualToString:@"0"]) {
|
||||||
// App already running, resume it
|
// App already running, resume it
|
||||||
[self resumeApp:hMan];
|
if (![self resumeApp:hMan]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Start app
|
// Start app
|
||||||
[self launchApp:hMan];
|
if (![self launchApp:hMan]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
||||||
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionTerminatedCallback:_callback];
|
_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];
|
||||||
}
|
}
|
||||||
@@ -60,7 +77,7 @@
|
|||||||
[_connection terminate];
|
[_connection terminate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) launchApp:(HttpManager*)hMan {
|
- (BOOL) launchApp:(HttpManager*)hMan {
|
||||||
NSData* launchResp = [hMan executeRequestSynchronously:
|
NSData* launchResp = [hMan executeRequestSynchronously:
|
||||||
[hMan newLaunchRequest:@"67339056"
|
[hMan newLaunchRequest:@"67339056"
|
||||||
width:_config.width
|
width:_config.width
|
||||||
@@ -68,14 +85,32 @@
|
|||||||
refreshRate:_config.frameRate
|
refreshRate:_config.frameRate
|
||||||
rikey:[Utils bytesToHex:_config.riKey]
|
rikey:[Utils bytesToHex:_config.riKey]
|
||||||
rikeyid:_config.riKeyId]];
|
rikeyid:_config.riKeyId]];
|
||||||
[HttpManager getStringFromXML:launchResp tag:@"gamesession"];
|
NSString *gameSession = [HttpManager getStringFromXML:launchResp tag:@"gamesession"];
|
||||||
|
if (launchResp == NULL) {
|
||||||
|
[_callbacks launchFailed:@"Failed to launch app"];
|
||||||
|
return FALSE;
|
||||||
|
} else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) {
|
||||||
|
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:launchResp]];
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) resumeApp:(HttpManager*)hMan {
|
- (BOOL) resumeApp:(HttpManager*)hMan {
|
||||||
NSData* resumeResp = [hMan executeRequestSynchronously:
|
NSData* resumeResp = [hMan executeRequestSynchronously:
|
||||||
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
|
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
|
||||||
riKeyId:_config.riKeyId]];
|
riKeyId:_config.riKeyId]];
|
||||||
[HttpManager getStringFromXML:resumeResp tag:@"gamesession"];
|
NSString *resume = [HttpManager getStringFromXML:resumeResp tag:@"resume"];
|
||||||
|
if (resumeResp == NULL) {
|
||||||
|
[_callbacks launchFailed:@"Failed to resume app"];
|
||||||
|
return FALSE;
|
||||||
|
} else if (resume == NULL || [resume isEqualToString:@"0"]) {
|
||||||
|
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:resumeResp]];
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -10,10 +10,9 @@
|
|||||||
|
|
||||||
@implementation VideoDecoderRenderer {
|
@implementation VideoDecoderRenderer {
|
||||||
AVSampleBufferDisplayLayer* displayLayer;
|
AVSampleBufferDisplayLayer* displayLayer;
|
||||||
Boolean waitingForSps, waitingForPpsA, waitingForPpsB;
|
Boolean waitingForSps, waitingForPps;
|
||||||
|
|
||||||
NSData *spsData, *ppsDataA, *ppsDataB;
|
NSData *spsData, *ppsData;
|
||||||
unsigned char ppsDataAFirstByte;
|
|
||||||
CMVideoFormatDescriptionRef formatDesc;
|
CMVideoFormatDescriptionRef formatDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,8 +29,7 @@
|
|||||||
|
|
||||||
// We need some parameter sets before we can properly start decoding frames
|
// We need some parameter sets before we can properly start decoding frames
|
||||||
waitingForSps = true;
|
waitingForSps = true;
|
||||||
waitingForPpsA = true;
|
waitingForPps = true;
|
||||||
waitingForPpsB = true;
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -114,34 +112,27 @@
|
|||||||
unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F;
|
unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F;
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
|
|
||||||
if (formatDesc == NULL && (nalType == 0x7 || nalType == 0x8)) {
|
if (nalType == 0x7 || nalType == 0x8) {
|
||||||
if (waitingForSps && nalType == 0x7) {
|
if (nalType == 0x7) {
|
||||||
printf("Got SPS\n");
|
printf("Got SPS\n");
|
||||||
spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
||||||
waitingForSps = false;
|
waitingForSps = false;
|
||||||
|
|
||||||
|
// We got a new SPS so wait for a new PPS to match it
|
||||||
|
waitingForPps = true;
|
||||||
}
|
}
|
||||||
// Nvidia's stream has 2 PPS NALUs so we'll wait for both of them
|
else if (nalType == 0x8) {
|
||||||
else if ((waitingForPpsA || waitingForPpsB) && nalType == 0x8) {
|
printf("Got PPS\n");
|
||||||
// Read the NALU's PPS index to figure out which PPS this is
|
ppsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
||||||
if (waitingForPpsA) {
|
waitingForPps = false;
|
||||||
printf("Got PPS 1\n");
|
|
||||||
ppsDataA = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
|
||||||
waitingForPpsA = false;
|
|
||||||
ppsDataAFirstByte = data[FRAME_START_PREFIX_SIZE + 1];
|
|
||||||
}
|
|
||||||
else if (data[FRAME_START_PREFIX_SIZE + 1] != ppsDataAFirstByte) {
|
|
||||||
printf("Got PPS 2\n");
|
|
||||||
ppsDataA = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
|
||||||
waitingForPpsB = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we've got all the parameter sets we need
|
// See if we've got all the parameter sets we need
|
||||||
if (!waitingForSps && !waitingForPpsA && !waitingForPpsB) {
|
if (!waitingForSps && !waitingForPps) {
|
||||||
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsDataA bytes], [ppsDataB bytes] };
|
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
|
||||||
const size_t parameterSetSizes[] = { [spsData length], [ppsDataA length], [ppsDataB length] };
|
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
|
||||||
|
|
||||||
printf("Constructing format description\n");
|
printf("Constructing new format description\n");
|
||||||
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
||||||
2, /* count of parameter sets */
|
2, /* count of parameter sets */
|
||||||
parameterSetPointers,
|
parameterSetPointers,
|
||||||
|
|||||||
@@ -15,5 +15,6 @@
|
|||||||
|
|
||||||
- (id) initWithHost:(NSNetService*)host;
|
- (id) initWithHost:(NSNetService*)host;
|
||||||
- (id) initWithIp:(NSString*)host;
|
- (id) initWithIp:(NSString*)host;
|
||||||
|
- (id) initPlaceholder;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -28,4 +28,13 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id) initPlaceholder {
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
self.hostName = NULL;
|
||||||
|
self.displayName = @"No computers found";
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
return addr;
|
return addr;
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Failed to resolve host: %d", h_errno);
|
NSLog(@"Failed to resolve host: %d", h_errno);
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,21 @@ static StreamConfiguration* streamConfig;
|
|||||||
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
||||||
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (![self validatePcSelected]) {
|
||||||
|
NSLog(@"No valid PC selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
NSString* uniqueId = [CryptoManager getUniqueID];
|
||||||
NSData* cert = [CryptoManager readCertFromFile];
|
NSData* cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
|
if ([Utils resolveHost:_selectedHost.hostName] == 0) {
|
||||||
|
[self displayDnsFailedDialog];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.hostName uniqueId:uniqueId deviceName:@"roth" cert:cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.hostName uniqueId:uniqueId deviceName:@"roth" cert:cert];
|
||||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:cert callback:self];
|
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:cert callback:self];
|
||||||
|
|
||||||
@@ -67,6 +78,14 @@ static StreamConfiguration* streamConfig;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)displayDnsFailedDialog {
|
||||||
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Network Error"
|
||||||
|
message:@"Failed to resolve host."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)StreamButton:(UIButton *)sender
|
- (void)StreamButton:(UIButton *)sender
|
||||||
{
|
{
|
||||||
NSLog(@"Stream Button Pressed!");
|
NSLog(@"Stream Button Pressed!");
|
||||||
@@ -74,9 +93,19 @@ static StreamConfiguration* streamConfig;
|
|||||||
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
||||||
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (![self validatePcSelected]) {
|
||||||
|
NSLog(@"No valid PC selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
streamConfig = [[StreamConfiguration alloc] init];
|
streamConfig = [[StreamConfiguration alloc] init];
|
||||||
streamConfig.host = _selectedHost.hostName;
|
streamConfig.host = _selectedHost.hostName;
|
||||||
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.hostName];
|
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.hostName];
|
||||||
|
if (streamConfig.hostAddr == 0) {
|
||||||
|
[self displayDnsFailedDialog];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long selectedConf = [self.StreamConfigs selectedRowInComponent:0];
|
unsigned long selectedConf = [self.StreamConfigs selectedRowInComponent:0];
|
||||||
NSLog(@"selectedConf: %ld", selectedConf);
|
NSLog(@"selectedConf: %ld", selectedConf);
|
||||||
@@ -85,29 +114,29 @@ static StreamConfiguration* streamConfig;
|
|||||||
streamConfig.width = 1280;
|
streamConfig.width = 1280;
|
||||||
streamConfig.height = 720;
|
streamConfig.height = 720;
|
||||||
streamConfig.frameRate = 30;
|
streamConfig.frameRate = 30;
|
||||||
|
streamConfig.bitRate = 5000;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
case 1:
|
case 1:
|
||||||
streamConfig.width = 1280;
|
streamConfig.width = 1280;
|
||||||
streamConfig.height = 720;
|
streamConfig.height = 720;
|
||||||
streamConfig.frameRate = 60;
|
streamConfig.frameRate = 60;
|
||||||
|
streamConfig.bitRate = 10000;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
streamConfig.width = 1920;
|
streamConfig.width = 1920;
|
||||||
streamConfig.height = 1080;
|
streamConfig.height = 1080;
|
||||||
streamConfig.frameRate = 30;
|
streamConfig.frameRate = 30;
|
||||||
|
streamConfig.bitRate = 10000;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
streamConfig.width = 1920;
|
streamConfig.width = 1920;
|
||||||
streamConfig.height = 1080;
|
streamConfig.height = 1080;
|
||||||
streamConfig.frameRate = 60;
|
streamConfig.frameRate = 60;
|
||||||
break;
|
streamConfig.bitRate = 20000;
|
||||||
default:
|
|
||||||
streamConfig.width = 1280;
|
|
||||||
streamConfig.height = 720;
|
|
||||||
streamConfig.frameRate = 60;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
NSLog(@"StreamConfig: %@, %d, %dx%dx%d", streamConfig.host, streamConfig.hostAddr, streamConfig.width, streamConfig.height, streamConfig.frameRate);
|
NSLog(@"StreamConfig: %@, %d, %dx%dx%d at %d Mbps", streamConfig.host, streamConfig.hostAddr, streamConfig.width, streamConfig.height, streamConfig.frameRate, streamConfig.bitRate);
|
||||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:self];
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +151,19 @@ static StreamConfiguration* streamConfig;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setSelectedHost:(NSInteger)selectedIndex
|
||||||
|
{
|
||||||
|
_selectedHost = (Computer*)([self.hostPickerVals objectAtIndex:selectedIndex]);
|
||||||
|
if (_selectedHost.hostName == NULL) {
|
||||||
|
// This must be the placeholder computer
|
||||||
|
_selectedHost = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
||||||
{
|
{
|
||||||
if (pickerView == self.HostPicker) {
|
if (pickerView == self.HostPicker) {
|
||||||
_selectedHost = (Computer*)([self.hostPickerVals objectAtIndex:[self.HostPicker selectedRowInComponent:0]]);
|
[self setSelectedHost:[self.HostPicker selectedRowInComponent:0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: figure out how to save this info!!
|
//TODO: figure out how to save this info!!
|
||||||
@@ -154,27 +192,51 @@ static StreamConfiguration* streamConfig;
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
self.streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
self.streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
||||||
self.hostPickerVals = [[NSArray alloc] init];
|
|
||||||
[self.StreamConfigs selectRow:1 inComponent:0 animated:NO];
|
[self.StreamConfigs selectRow:1 inComponent:0 animated:NO];
|
||||||
|
|
||||||
_opQueue = [[NSOperationQueue alloc] init];
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
|
|
||||||
|
// Initialize the host picker list
|
||||||
|
[self updateHosts:[[NSArray alloc] init]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
{
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
||||||
[_mDNSManager searchForHosts];
|
[_mDNSManager searchForHosts];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
{
|
{
|
||||||
|
[super viewDidDisappear:animated];
|
||||||
[_mDNSManager stopSearching];
|
[_mDNSManager stopSearching];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateHosts:(NSArray *)hosts {
|
- (void)updateHosts:(NSArray *)hosts {
|
||||||
self.hostPickerVals = hosts;
|
NSMutableArray *hostPickerValues = [[NSMutableArray alloc] initWithArray:hosts];
|
||||||
|
|
||||||
|
if ([hostPickerValues count] == 0) {
|
||||||
|
[hostPickerValues addObject:[[Computer alloc] initPlaceholder]];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hostPickerVals = hostPickerValues;
|
||||||
[self.HostPicker reloadAllComponents];
|
[self.HostPicker reloadAllComponents];
|
||||||
_selectedHost = (Computer*)([self.hostPickerVals objectAtIndex:[self.HostPicker selectedRowInComponent:0]]);
|
|
||||||
|
[self setSelectedHost:[self.HostPicker selectedRowInComponent:0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)validatePcSelected {
|
||||||
|
if (_selectedHost == NULL) {
|
||||||
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"No PC Selected"
|
||||||
|
message:@"You must select a PC to continue."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning
|
- (void)didReceiveMemoryWarning
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface StreamFrameViewController : UIViewController <ConTermCallback>
|
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks>
|
||||||
|
@property (strong, nonatomic) IBOutlet UILabel *stageLabel;
|
||||||
|
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -24,12 +24,16 @@
|
|||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
{
|
{
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
|
[self.stageLabel setText:@"Starting App"];
|
||||||
|
|
||||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||||
|
|
||||||
_controllerSupport = [[ControllerSupport alloc] init];
|
_controllerSupport = [[ControllerSupport alloc] init];
|
||||||
|
|
||||||
_streamMan = [[StreamManager alloc] initWithConfig:[MainFrameViewController getStreamConfiguration] renderView:self.view connectionTerminatedCallback:self];
|
_streamMan = [[StreamManager alloc] initWithConfig:[MainFrameViewController getStreamConfiguration]
|
||||||
|
renderView:self.view
|
||||||
|
connectionCallbacks:self];
|
||||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||||
[opQueue addOperation:_streamMan];
|
[opQueue addOperation:_streamMan];
|
||||||
|
|
||||||
@@ -44,7 +48,17 @@
|
|||||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connectionTerminated {
|
- (void) connectionStarted {
|
||||||
|
printf("Connection started\n");
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self.spinner stopAnimating];
|
||||||
|
[self.stageLabel setText:@"Waiting for first frame..."];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)connectionTerminated:(long)errorCode {
|
||||||
|
printf("Connection terminated: %ld\n", errorCode);
|
||||||
|
|
||||||
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection terminated unexpectedly" preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection terminated unexpectedly" preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[conTermAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
[conTermAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||||
@@ -54,6 +68,47 @@
|
|||||||
[_streamMan stopStream];
|
[_streamMan stopStream];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) stageStarting:(char*)stageName {
|
||||||
|
printf("Starting %s\n", stageName);
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
||||||
|
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
|
||||||
|
[self.stageLabel setText:titleCase];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) stageComplete:(char*)stageName {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) stageFailed:(char*)stageName withError:(long)errorCode {
|
||||||
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
||||||
|
message:[NSString stringWithFormat:@"%s failed with error %ld",
|
||||||
|
stageName, errorCode]
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
|
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||||
|
}]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) launchFailed:(NSString*)message {
|
||||||
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
||||||
|
message:message
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
|
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||||
|
}]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) displayMessage:(char*)message {
|
||||||
|
printf("Display message: %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) displayTransientMessage:(char*)message {
|
||||||
|
printf("Display transient message: %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning
|
- (void)didReceiveMemoryWarning
|
||||||
{
|
{
|
||||||
[super didReceiveMemoryWarning];
|
[super didReceiveMemoryWarning];
|
||||||
|
|||||||
@@ -109,7 +109,24 @@
|
|||||||
<view key="view" contentMode="scaleToFill" id="VPm-Ae-rc4" userLabel="RenderView" customClass="StreamView">
|
<view key="view" contentMode="scaleToFill" id="VPm-Ae-rc4" userLabel="RenderView" customClass="StreamView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
<subviews>
|
||||||
|
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="iOs-1X-mSU">
|
||||||
|
<rect key="frame" x="502" y="374" width="20" height="20"/>
|
||||||
|
</activityIndicatorView>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dDs-kT-po6">
|
||||||
|
<rect key="frame" x="491" y="402" width="42" height="21"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="dDs-kT-po6" firstAttribute="top" secondItem="iOs-1X-mSU" secondAttribute="bottom" constant="8" id="VZj-wk-dHp"/>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="iOs-1X-mSU" secondAttribute="centerY" id="YAN-0k-Rds"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="dDs-kT-po6" secondAttribute="centerX" id="bLr-5Z-OH3"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="iOs-1X-mSU" secondAttribute="centerX" id="ruD-8B-gj3"/>
|
||||||
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<nil key="simulatedTopBarMetrics"/>
|
<nil key="simulatedTopBarMetrics"/>
|
||||||
@@ -117,6 +134,8 @@
|
|||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
<simulatedScreenMetrics key="simulatedDestinationMetrics"/>
|
<simulatedScreenMetrics key="simulatedDestinationMetrics"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="spinner" destination="iOs-1X-mSU" id="LSl-lr-7fF"/>
|
||||||
|
<outlet property="stageLabel" destination="dDs-kT-po6" id="ziI-M8-UVf"/>
|
||||||
<segue destination="wb7-af-jn8" kind="modal" identifier="returnToMainFrame" id="Ryr-0y-o43"/>
|
<segue destination="wb7-af-jn8" kind="modal" identifier="returnToMainFrame" id="Ryr-0y-o43"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
|
|||||||
@@ -103,12 +103,31 @@
|
|||||||
<view key="view" contentMode="scaleToFill" id="eir-e9-IPE" customClass="StreamView">
|
<view key="view" contentMode="scaleToFill" id="eir-e9-IPE" customClass="StreamView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
<subviews>
|
||||||
|
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="0vm-Iv-K4b">
|
||||||
|
<rect key="frame" x="150" y="274" width="20" height="20"/>
|
||||||
|
</activityIndicatorView>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2HK-Z5-4Ch">
|
||||||
|
<rect key="frame" x="138" y="302" width="45" height="21"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="2HK-Z5-4Ch" secondAttribute="centerX" constant="-0.5" id="Blw-Hy-66z"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="0vm-Iv-K4b" secondAttribute="centerX" id="mCQ-CP-Yik"/>
|
||||||
|
<constraint firstAttribute="centerY" secondItem="0vm-Iv-K4b" secondAttribute="centerY" id="t8e-qp-g1j"/>
|
||||||
|
<constraint firstItem="2HK-Z5-4Ch" firstAttribute="top" secondItem="0vm-Iv-K4b" secondAttribute="bottom" constant="8" id="tta-Uo-bBO"/>
|
||||||
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
<nil key="simulatedTopBarMetrics"/>
|
<nil key="simulatedTopBarMetrics"/>
|
||||||
<nil key="simulatedBottomBarMetrics"/>
|
<nil key="simulatedBottomBarMetrics"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="spinner" destination="0vm-Iv-K4b" id="Lif-zG-6Jh"/>
|
||||||
|
<outlet property="stageLabel" destination="2HK-Z5-4Ch" id="1bI-Ig-OpD"/>
|
||||||
<segue destination="dgh-JZ-Q7z" kind="modal" identifier="returnToMainFrame" id="djB-MF-L5D"/>
|
<segue destination="dgh-JZ-Q7z" kind="modal" identifier="returnToMainFrame" id="djB-MF-L5D"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
|
|||||||
@@ -3,12 +3,10 @@
|
|||||||
[Limelight](https://github.com/limelight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Limelight iOS will allow you to stream your full collection of Steam games from
|
[Limelight](https://github.com/limelight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Limelight iOS will allow you to stream your full collection of Steam games from
|
||||||
your powerful desktop computer to your iOS Device.
|
your powerful desktop computer to your iOS Device.
|
||||||
|
|
||||||
#####Limelight iOS is not stable or buildable - it is in the very early stages of development. Please refrain from opening issues regarding Limelight iOS - we know it doesn't work yet.
|
This is in development and is not considered stable.
|
||||||
|
|
||||||
This is in development and is not considered stable (or buildable). Do not use it. It is not ready.
|
We understand that Limelight users are eager for the opportunity to stream their Steam collection to their iOS devices. Limelight for iOS is in the testing stage and a preliminary version will soon be available for download.
|
||||||
|
|
||||||
We understand that Limelight users are eager for the opportunity to stream their Steam collection to their iOS devices. Currently there is no ETA on an alpha version, but we'll post an update whenever we reach that stage.
|
In the meantime, check out the existing versions for [Android](https://github.com/limelight-stream/limelight-android) and [PC](https://github.com/limelight-stream/limelight-pc). Also, a client for [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) is in the works and actively being developed.
|
||||||
|
|
||||||
In the meantime, check out the existing versions for [Android](https://github.com/limelight-stream/limelight-android) and [PC](https://github.com/limelight-stream/limelight-pc). Also, a client for [Windows Phone 8.1](https://github.com/limelight-stream/limelight-wp) is in the works and actively being developed.
|
|
||||||
|
|
||||||
Please be patient as we work to bring Limelight to more platforms.
|
Please be patient as we work to bring Limelight to more platforms.
|
||||||
+1
-1
Submodule limelight-common-c updated: 039c2e3f10...91f0351671.
Reference in new issue
Block a user