Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15fe5a06c2 | ||
|
|
8d4c7bd705 | ||
|
|
b0d85abfa6 | ||
|
|
4295017324 | ||
|
|
d80d70215a | ||
|
|
a46f905aa6 | ||
|
|
453c50d505 | ||
|
|
61c7d9f2b3 | ||
|
|
34707e7743 | ||
|
|
9a9b9651a1 | ||
|
|
d4576a8739 | ||
|
|
87824c2650 | ||
|
|
283e735f90 | ||
|
|
202f968b98 | ||
|
|
62df1cd5ba | ||
|
|
f24c28c848 | ||
|
|
8fb465d3ca | ||
|
|
29dff2320b | ||
|
|
a40b30016b | ||
|
|
409b262a4f | ||
|
|
73197e4378 | ||
|
|
f51dbe4295 | ||
|
|
597aaa1bab | ||
|
|
b9656da8a5 | ||
|
|
422db1898c | ||
|
|
56691791b8 | ||
|
|
de2a5d3cd7 | ||
|
|
49fc10191c | ||
|
|
bf8aaa8198 | ||
|
|
9a4cdc9c94 | ||
|
|
f6153fe818 | ||
|
|
f2fa9e18ea | ||
|
|
aa013be6e6 | ||
|
|
7e21b131ac | ||
|
|
97681f3a0d | ||
|
|
e476cc407c | ||
|
|
f2e03bbf1f | ||
|
|
a6cef32c9a | ||
|
|
6d94897c21 | ||
|
|
a065c78b5f | ||
|
|
83479719a4 | ||
|
|
fd4ede58ca | ||
|
|
7ed5a9831f | ||
|
|
42b7fd35ce | ||
|
|
42c97eafaa | ||
|
|
5b82be0546 | ||
|
|
1529058f52 | ||
|
|
3dcca3a922 | ||
|
|
9b8f230c46 | ||
|
|
7699d9e574 | ||
|
|
641e1c5066 | ||
|
|
617ef7c6a6 | ||
|
|
c2620b8321 | ||
|
|
9e91d136bf | ||
|
|
9960d2a2ff | ||
|
|
311e77e01a | ||
|
|
c08df921da | ||
|
|
ba4e55aac4 | ||
|
|
af16f03703 | ||
|
|
8189d54703 | ||
|
|
ac8514e3cb | ||
|
|
8f4b8da3ce | ||
|
|
8337b3e708 | ||
|
|
cb527baead | ||
|
|
ed10612e2c | ||
|
|
7d3eaeef83 | ||
|
|
dd5ecb37c4 | ||
|
|
636143ee97 | ||
|
|
28ff29bb96 | ||
|
|
a508c6d855 | ||
|
|
dbd6eabd24 | ||
|
|
ad0a5935f7 | ||
|
|
dcd2dc97a6 | ||
|
|
f92544c7d2 | ||
|
|
797fa0f492 | ||
|
|
ff52adf4f8 | ||
|
|
8bb49ada11 | ||
|
|
3f709b616b |
@@ -0,0 +1,25 @@
|
||||
language: objective-c
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env:
|
||||
- SCHEME="Moonlight"
|
||||
- TARGET="platform=iOS Simulator,OS=12.1,name=iPhone SE"
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env:
|
||||
- SCHEME="Moonlight"
|
||||
- TARGET="platform=iOS Simulator,OS=12.1,name=iPad Pro (9.7-inch)"
|
||||
- os: osx
|
||||
osx_image: xcode11
|
||||
env:
|
||||
- SCHEME="Moonlight TV"
|
||||
- TARGET="platform=tvOS Simulator,OS=12.1,name=Apple TV 4K"
|
||||
|
||||
script:
|
||||
- set -o pipefail && xcodebuild -project Moonlight.xcodeproj -scheme "$SCHEME" -destination "$TARGET" build | xcpretty
|
||||
@@ -1,19 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="landscape" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<navigationController id="vV9-32-ww6">
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="barTintColor" red="0.66666668653488159" green="0.66666668653488159" blue="0.66666668653488159" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</navigationBar>
|
||||
<viewControllers>
|
||||
<viewController id="l6V-ue-5Om">
|
||||
@@ -22,30 +22,14 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.3333333432674408" green="0.3333333432674408" blue="0.3333333432674408" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
||||
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
||||
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
||||
<rect key="frame" x="20" y="-1" width="109" height="46"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<state key="normal" title="Moonlight" image="Logo">
|
||||
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
|
||||
</button>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<navigationItem key="navigationItem" id="rW0-BH-s7l"/>
|
||||
</viewController>
|
||||
</viewControllers>
|
||||
<point key="canvasLocation" x="34" y="149"/>
|
||||
</navigationController>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="Logo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -107,13 +107,7 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
||||
*/
|
||||
X509_set_issuer_name(x, name);
|
||||
|
||||
/* Add various extensions: standard extensions */
|
||||
add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
|
||||
add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
|
||||
|
||||
add_ext(x, NID_subject_key_identifier, "hash");
|
||||
|
||||
if (!X509_sign(x, pk, EVP_sha1())) {
|
||||
if (!X509_sign(x, pk, EVP_sha256())) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -124,29 +118,3 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
||||
err:
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Add extension using V3 code: we can set the config file as NULL
|
||||
* because we wont reference any other sections.
|
||||
*/
|
||||
|
||||
int add_ext(X509 *cert, int nid, char *value)
|
||||
{
|
||||
X509_EXTENSION *ex;
|
||||
X509V3_CTX ctx;
|
||||
/* This sets the 'context' of the extensions. */
|
||||
/* No configuration database */
|
||||
X509V3_set_ctx_nodb(&ctx);
|
||||
/* Issuer and subject certs: both the target since it is self signed,
|
||||
* no request and no CRL
|
||||
*/
|
||||
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
|
||||
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
|
||||
if (!ex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
X509_add_ext(cert, ex, -1);
|
||||
X509_EXTENSION_free(ex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
@property (nullable, nonatomic, retain) NSString *id;
|
||||
@property (nullable, nonatomic, retain) NSString *name;
|
||||
@property (nullable, nonatomic, retain) NSString *installPath;
|
||||
@property (nonatomic) BOOL hdrSupported;
|
||||
@property (nullable, nonatomic, retain) TemporaryHost *host;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
@interface TemporaryHost : NSObject
|
||||
|
||||
@property (nonatomic) BOOL online;
|
||||
@property (nonatomic) State state;
|
||||
@property (nonatomic) PairState pairState;
|
||||
@property (nonatomic, nullable) NSString * activeAddress;
|
||||
@property (nonatomic, nullable) NSString * currentGame;
|
||||
@@ -20,6 +20,7 @@
|
||||
@property (nonatomic, nullable, retain) NSString *address;
|
||||
@property (nonatomic, nullable, retain) NSString *externalAddress;
|
||||
@property (nonatomic, nullable, retain) NSString *localAddress;
|
||||
@property (nonatomic, nullable, retain) NSString *ipv6Address;
|
||||
@property (nonatomic, nullable, retain) NSString *mac;
|
||||
@property (nonatomic) int serverCodecModeSupport;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
self = [super init];
|
||||
self.appList = [[NSMutableSet alloc] init];
|
||||
self.currentGame = @"0";
|
||||
self.state = StateUnknown;
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -26,6 +27,7 @@
|
||||
self.address = host.address;
|
||||
self.externalAddress = host.externalAddress;
|
||||
self.localAddress = host.localAddress;
|
||||
self.ipv6Address = host.ipv6Address;
|
||||
self.mac = host.mac;
|
||||
self.name = host.name;
|
||||
self.uuid = host.uuid;
|
||||
@@ -60,6 +62,9 @@
|
||||
if (self.localAddress != nil) {
|
||||
parentHost.localAddress = self.localAddress;
|
||||
}
|
||||
if (self.ipv6Address != nil) {
|
||||
parentHost.ipv6Address = self.ipv6Address;
|
||||
}
|
||||
if (self.mac != nil) {
|
||||
parentHost.mac = self.mac;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
self.width = [NSNumber numberWithInteger:1920];
|
||||
break;
|
||||
}
|
||||
self.onscreenControls = (NSInteger)OnScreenControlsLevelOff;
|
||||
self.onscreenControls = [NSNumber numberWithInteger:OnScreenControlsLevelOff];
|
||||
#else
|
||||
self.bitrate = settings.bitrate;
|
||||
self.framerate = settings.framerate;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "limelight_computer_add_icon_1x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "limelight_computer_add_icon_2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "limelight_computer_add_icon_3x.png"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -2,11 +2,11 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "add.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "logo.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
@@ -0,0 +1,69 @@
|
||||
%PDF-1.5
|
||||
%µí®û
|
||||
4 0 obj
|
||||
<< /Length 5 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
xœ]‘]!„ß{Š^ÀÊ”Àâ1<‚Ùøó êý…E␍ »ÛN‡Yp°µƒmª‰×=)´³×•÷§À×7iØ·¸Hbä"‹= ¯3_\W«FÆ!K©%ðÁ½ÛñÎX¤@;$Ú®‹ ”mÊê@Œ¬Ç¿ ‰µµ+¸“!ïd�±ùË}œ#¡TÙ;7_Û«†,ÚLÙ˜EˆMHS~»ì8Ðà—î�$ëô¾±ÍX™F—ØÙ´<òŸ\W¾Í¤MlæÜûþeÓeÇÿÎé¦Lg7
|
||||
endstream
|
||||
endobj
|
||||
5 0 obj
|
||||
212
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 0.3 /ca 0.3 >>
|
||||
/a1 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Page % 1
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 225 225 ]
|
||||
/Contents 4 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 3 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 2 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Producer (cairo 1.16.0 (https://cairographics.org))
|
||||
/CreationDate (D:20190830180928-07'00)
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000648 00000 n
|
||||
0000000430 00000 n
|
||||
0000000326 00000 n
|
||||
0000000015 00000 n
|
||||
0000000304 00000 n
|
||||
0000000713 00000 n
|
||||
0000000829 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
881
|
||||
%%EOF
|
||||
@@ -2,18 +2,16 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "limelight_computer_1x.png"
|
||||
"filename" : "Computer.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "limelight_computer_2x.png"
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "limelight_computer_3x.png"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 22 KiB |
@@ -2,17 +2,15 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pull-arrow-light-14x31@1x.png",
|
||||
"filename" : "error.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pull-arrow-light-28x61@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "pull-arrow-light-42x92@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
@@ -0,0 +1,68 @@
|
||||
%PDF-1.5
|
||||
%µí®û
|
||||
4 0 obj
|
||||
<< /Length 5 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
xœeŒÑ Ã0Dÿ5Å-Uªì(kt„Rhò¤Ýª8µ �t︓Bb�å¯B)öù̸=ó—Œõž1fã¸òä�W˜sW½P’jçjXbó†kG Ý’rî%c?õì=ÓãÍ?ÜðÒ~Óƒ~®L+·
|
||||
endstream
|
||||
endobj
|
||||
5 0 obj
|
||||
115
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Page % 1
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 75 75 ]
|
||||
/Contents 4 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 3 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 2 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Producer (cairo 1.16.0 (https://cairographics.org))
|
||||
/CreationDate (D:20190830180932-07'00)
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000517 00000 n
|
||||
0000000301 00000 n
|
||||
0000000229 00000 n
|
||||
0000000015 00000 n
|
||||
0000000207 00000 n
|
||||
0000000582 00000 n
|
||||
0000000698 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
750
|
||||
%%EOF
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "lock.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
%PDF-1.5
|
||||
%µí®û
|
||||
4 0 obj
|
||||
<< /Length 5 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
xœUQKnÅ Üû¾@]ÌÇðŽñŽP!õu‘,ÚÞ_*ø¥"‚ÐÌØcZë�×Öξ�q¯Ÿ¾$|ýBÊ␍×wb+Ć�À<¨ßiÒ£ŠvW:9œ˜�O™•¸*˜ZÎ šfwΰ çåœ;␍ΆïZ§ÙÛá¸Ñ£×¢¨›y‚xœõ)Ñσd§r³�ËzÚa™Ç2ºUãòõp�oâè(|T'–JIrpóiI+4²Æ8´6§…êªÀd€5‘ÄxÏ␍v•Η¢_:'áiÔò tíöËïºk'¶vÎèP{ŽÙûЂ®¼$X2q|h“ê†Wv¦Q«?¹¹«‚ù_ùŸý Oøp…&
|
||||
endstream
|
||||
endobj
|
||||
5 0 obj
|
||||
267
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Page % 1
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 75 75 ]
|
||||
/Contents 4 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 3 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 2 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Producer (cairo 1.16.0 (https://cairographics.org))
|
||||
/CreationDate (D:20190830180930-07'00)
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000669 00000 n
|
||||
0000000453 00000 n
|
||||
0000000381 00000 n
|
||||
0000000015 00000 n
|
||||
0000000359 00000 n
|
||||
0000000734 00000 n
|
||||
0000000850 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
902
|
||||
%%EOF
|
||||
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "settings.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
%PDF-1.5
|
||||
%µí®û
|
||||
4 0 obj
|
||||
<< /Length 5 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
xœeTIŽÜ0¼óú@‰Z,=#OÌÌA}Hò ,.== °»d®Å¢j*òûVåq�t?èÕ„ßï÷ôýgIï¨]y¤V3�ôHç2Ù¡?¿ÁøvÐKÞm¹¥Þòåö÷ƒþ|=òp,EØÏ„ö÷N4vnbjÏGª#OxRå\ÇL¯68Z+€™ß‰�p´÷ä¼*G”iÆî3ÃÕ}ÓQ¯Þã ^Ê‘ûÜÿÄ<O¬ER„úR\¸Jï-ï2�‘G
|
||||
´2×␍OA nŸ;J^CXFR¾V»!PïJ” 8 šÂ�øv8␍Ö,G³Î␍<Q°À.¾×¥VÛ�|ÄX¯Üa\2zí37)qT+fä‚䌗iGJ‚«¦ílyVîÒÏÖK�iZã¦Wû¦ˆ Ζ+¿L·±5jX�~µP‚J«šH�)»~6xïè␍^¼´@i°ŒÎE_wbަ.e‹«%V^PsÙg.ÙâêŒê´^ºrw€J0Ê„—°$Ã!@’ti^[•µiZØÅ€¬»‡PADt?áTúÃqê"zÔáô¤B�횕Ԕ Šz[±²naä·÷*ô Ë "·ÊÁ+Ã$úÇ;Hæ®*ò°2�á@qlÂóÙÁ³w‚␍WªÒωѣV9vYø2ºhžW„«Ê0™1s7pAz(—+©\ÎÞÃ�ÚU=êD±
|
||||
lèk"␍š}�Ę•-_²—m }%ßO0ë›®½Ïë»-X·Ëö¾Ùú€yÖ␍¶üÖZÛy^)&†¸nL(¯WÑÿWÓý ¿¾?1
|
||||
endstream
|
||||
endobj
|
||||
5 0 obj
|
||||
608
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Page % 1
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 75 75 ]
|
||||
/Contents 4 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 3 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 2 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Producer (cairo 1.16.0 (https://cairographics.org))
|
||||
/CreationDate (D:20190830202122-07'00)
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000001010 00000 n
|
||||
0000000794 00000 n
|
||||
0000000722 00000 n
|
||||
0000000015 00000 n
|
||||
0000000700 00000 n
|
||||
0000001075 00000 n
|
||||
0000001191 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
1243
|
||||
%%EOF
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "up_arrow.pdf",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
%PDF-1.5
|
||||
%µí®û
|
||||
4 0 obj
|
||||
<< /Length 5 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
xœUŽQ
|
||||
ƒ@Dÿsй€1ÙÍF=†G(…êÇú¡½?-e`ƒÌ$
|
||||
5Ö¼ZIqh›Ð¾Ó—4qAî¨ó ÓsTdã¹dl>üØ�H… {º‰n|–KÏâé,Ë}°?‡ê5ôª™ÿ^øÐH;U$}
|
||||
endstream
|
||||
endobj
|
||||
5 0 obj
|
||||
114
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 << /CA 1 /ca 1 >>
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /Type /Page % 1
|
||||
/Parent 1 0 R
|
||||
/MediaBox [ 0 0 75 75 ]
|
||||
/Contents 4 0 R
|
||||
/Group <<
|
||||
/Type /Group
|
||||
/S /Transparency
|
||||
/I true
|
||||
/CS /DeviceRGB
|
||||
>>
|
||||
/Resources 3 0 R
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [ 2 0 R ]
|
||||
/Count 1
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Producer (cairo 1.16.0 (https://cairographics.org))
|
||||
/CreationDate (D:20190830203401-07'00)
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 1 0 R
|
||||
>>
|
||||
endobj
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000516 00000 n
|
||||
0000000300 00000 n
|
||||
0000000228 00000 n
|
||||
0000000015 00000 n
|
||||
0000000206 00000 n
|
||||
0000000581 00000 n
|
||||
0000000697 00000 n
|
||||
trailer
|
||||
<< /Size 8
|
||||
/Root 7 0 R
|
||||
/Info 6 0 R
|
||||
>>
|
||||
startxref
|
||||
749
|
||||
%%EOF
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
-(void) rumbleController: (Controller*)controller
|
||||
{
|
||||
#if 0
|
||||
// Only vibrate if the amplitude is large enough
|
||||
if (controller.lowFreqMotor > 0x5000 || controller.highFreqMotor > 0x5000) {
|
||||
// If the gamepad is nil (on-screen controls) or it's attached to the device,
|
||||
@@ -54,6 +55,7 @@
|
||||
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
-(void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor
|
||||
@@ -192,6 +194,9 @@
|
||||
[_controllerStreamLock unlock];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
-(void) unregisterControllerCallbacks:(GCController*) controller
|
||||
{
|
||||
if (controller != NULL) {
|
||||
@@ -209,21 +214,28 @@
|
||||
-(void) registerControllerCallbacks:(GCController*) controller
|
||||
{
|
||||
if (controller != NULL) {
|
||||
controller.controllerPausedHandler = ^(GCController *controller) {
|
||||
Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||
|
||||
// Get off the main thread
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
[self setButtonFlag:limeController flags:PLAY_FLAG];
|
||||
[self updateFinished:limeController];
|
||||
// On iOS 13, we want to use the new buttonMenu property which lets users hold down Start.
|
||||
// On prior versions, we must use the controllerPausedHandler.
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
// Nothing - buttonMenu is already handled in valueChangedHandler
|
||||
}
|
||||
else {
|
||||
controller.controllerPausedHandler = ^(GCController *controller) {
|
||||
Controller* limeController = [self->_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||
|
||||
// Pause for 100 ms
|
||||
usleep(100 * 1000);
|
||||
|
||||
[self clearButtonFlag:limeController flags:PLAY_FLAG];
|
||||
[self updateFinished:limeController];
|
||||
});
|
||||
};
|
||||
// Get off the main thread
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
[self setButtonFlag:limeController flags:PLAY_FLAG];
|
||||
[self updateFinished:limeController];
|
||||
|
||||
// Pause for 100 ms
|
||||
usleep(100 * 1000);
|
||||
|
||||
[self clearButtonFlag:limeController flags:PLAY_FLAG];
|
||||
[self updateFinished:limeController];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (controller.extendedGamepad != NULL) {
|
||||
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) {
|
||||
@@ -255,6 +267,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
// Menu button is mandatory, so no need to check for nil
|
||||
UPDATE_BUTTON_FLAG(limeController, PLAY_FLAG, gamepad.buttonMenu.pressed);
|
||||
|
||||
// Options button is optional (only present on Xbox One S and PS4 gamepads)
|
||||
if (gamepad.buttonOptions != nil) {
|
||||
UPDATE_BUTTON_FLAG(limeController, BACK_FLAG, gamepad.buttonOptions.pressed);
|
||||
}
|
||||
}
|
||||
|
||||
leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE;
|
||||
leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE;
|
||||
|
||||
@@ -315,6 +337,12 @@
|
||||
if (controller.extendedGamepad.leftThumbstickButton != nil &&
|
||||
controller.extendedGamepad.rightThumbstickButton != nil) {
|
||||
level = OnScreenControlsLevelAutoGCExtendedGamepadWithStickButtons;
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
if (controller.extendedGamepad.buttonOptions != nil) {
|
||||
// Has L3/R3 and Select, so we can show nothing :)
|
||||
level = OnScreenControlsLevelOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -403,6 +431,8 @@
|
||||
return controller.extendedGamepad != nil || controller.gamepad != nil;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
+(int) getGamepadCount {
|
||||
int count = 0;
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ static float L3_Y;
|
||||
_edgeDelegate = swipeDelegate;
|
||||
_deadTouches = [[NSMutableArray alloc] init];
|
||||
|
||||
_iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
|
||||
_iPad = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
|
||||
_controlArea = CGRectMake(0, 0, _view.frame.size.width, _view.frame.size.height);
|
||||
if (_iPad)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UITextField* keyInputField;
|
||||
|
||||
- (void) setupStreamView;
|
||||
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate;
|
||||
- (void) setMouseDeltaFactors:(float)x y:(float)y;
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
float yDeltaFactor;
|
||||
float screenFactor;
|
||||
|
||||
#if TARGET_OS_TV
|
||||
UIGestureRecognizer* remotePressRecognizer;
|
||||
UIGestureRecognizer* remoteLongPressRecognizer;
|
||||
#endif
|
||||
|
||||
NSDictionary<NSString *, NSNumber *> *dictCodes;
|
||||
}
|
||||
|
||||
@@ -36,6 +41,19 @@
|
||||
screenFactor = [[UIScreen mainScreen] scale];
|
||||
}
|
||||
|
||||
- (void) setupStreamView {
|
||||
#if TARGET_OS_TV
|
||||
remotePressRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(remoteButtonPressed:)];
|
||||
remotePressRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
|
||||
|
||||
remoteLongPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(remoteButtonLongPressed:)];
|
||||
remoteLongPressRecognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
|
||||
|
||||
[self addGestureRecognizer:remotePressRecognizer];
|
||||
[self addGestureRecognizer:remoteLongPressRecognizer];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
|
||||
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
@@ -199,6 +217,37 @@
|
||||
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
- (void)remoteButtonPressed:(id)sender {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
Log(LOG_D, @"Sending left mouse button press");
|
||||
|
||||
// Mark this as touchMoved to avoid a duplicate press on touch up
|
||||
self->touchMoved = true;
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
|
||||
// Wait 100 ms to simulate a real button press
|
||||
usleep(100 * 1000);
|
||||
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||
});
|
||||
}
|
||||
- (void)remoteButtonLongPressed:(id)sender {
|
||||
Log(LOG_D, @"Holding left mouse button");
|
||||
|
||||
isDragging = true;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
|
||||
// Disable all gesture recognizers to prevent them from eating our touches.
|
||||
// This can happen on iOS 13 where the 3 finger tap gesture is taken over for
|
||||
// displaying custom edit controls.
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
// This method is called when the "Return" key is pressed.
|
||||
LiSendKeyboardEvent(0x0d, KEY_ACTION_DOWN, 0);
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.6.0</string>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>GCSupportedGameControllers</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>Moonlight v1.3.xcdatamodel</string>
|
||||
<string>Moonlight v1.4.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14490.99" systemVersion="18F132" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
||||
<entity name="App" representedClassName="App" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="hdrSupported" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="id" attributeType="String" syncable="YES"/>
|
||||
<attribute name="name" 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" codeGenerationType="class">
|
||||
<attribute name="address" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="ipv6Address" 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" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="serverCert" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||
<attribute name="serverCodecModeSupport" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" 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" codeGenerationType="class">
|
||||
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="enableHdr" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="height" attributeType="Integer 32" defaultValueString="720" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="multiController" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
|
||||
<attribute name="optimizeGames" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="playAudioOnPC" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="streamingRemotely" attributeType="Boolean" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
|
||||
<attribute name="useHevc" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" usesScalarValueType="NO" 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="210"/>
|
||||
<element name="Settings" positionX="0" positionY="0" width="128" height="225"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -20,6 +20,7 @@ static const char* TAG_APP = "App";
|
||||
static const char* TAG_APP_TITLE = "AppTitle";
|
||||
static const char* TAG_APP_ID = "ID";
|
||||
static const char* TAG_HDR_SUPPORTED = "IsHdrSupported";
|
||||
static const char* TAG_APP_INSTALL_PATH = "AppInstallPath";
|
||||
|
||||
- (void)populateWithData:(NSData *)xml {
|
||||
self.data = xml;
|
||||
@@ -68,6 +69,7 @@ static const char* TAG_HDR_SUPPORTED = "IsHdrSupported";
|
||||
NSString* appName = @"";
|
||||
NSString* appId = nil;
|
||||
NSString* hdrSupported = @"0";
|
||||
NSString* appInstallPath = nil;
|
||||
while (appInfoNode != NULL) {
|
||||
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||
@@ -87,7 +89,14 @@ static const char* TAG_HDR_SUPPORTED = "IsHdrSupported";
|
||||
hdrSupported = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||
xmlFree(nodeVal);
|
||||
}
|
||||
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_INSTALL_PATH)) {
|
||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||
if (nodeVal != NULL) {
|
||||
appInstallPath = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||
xmlFree(nodeVal);
|
||||
}
|
||||
}
|
||||
|
||||
appInfoNode = appInfoNode->next;
|
||||
}
|
||||
if (appId != nil) {
|
||||
@@ -95,6 +104,7 @@ static const char* TAG_HDR_SUPPORTED = "IsHdrSupported";
|
||||
app.name = appName;
|
||||
app.id = appId;
|
||||
app.hdrSupported = [hdrSupported intValue] != 0;
|
||||
app.installPath = appInstallPath;
|
||||
[_appList addObject:app];
|
||||
}
|
||||
}
|
||||
@@ -102,6 +112,40 @@ static const char* TAG_HDR_SUPPORTED = "IsHdrSupported";
|
||||
}
|
||||
|
||||
xmlFreeDoc(docPtr);
|
||||
|
||||
// APP STORE REVIEW COMPLIANCE
|
||||
//
|
||||
// Remove default Steam entry from the app list to comply with Apple App Store Guideline 4.2.7d:
|
||||
//
|
||||
// The UI appearing on the client does not resemble an iOS or App Store view, does not provide a store-like interface,
|
||||
// or include the ability to browse, select, or purchase software not already owned or licensed by the user.
|
||||
//
|
||||
// However, if the user manually adds Steam themselves, then we will display it.
|
||||
TemporaryApp* officialSteamApp = nil;
|
||||
TemporaryApp* manuallyAddedSteamApp = nil;
|
||||
for (TemporaryApp* app in _appList) {
|
||||
if (app.installPath != nil && [[app.installPath lowercaseString] hasSuffix:@"\\steam\\"]) {
|
||||
// The official Steam app is marked as HDR supported, while manually added ones are not.
|
||||
if ([app.name isEqualToString:@"Steam"] && app.hdrSupported) {
|
||||
officialSteamApp = app;
|
||||
}
|
||||
else {
|
||||
manuallyAddedSteamApp = app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To be safe, don't do anything if we didn't find an HDR-enabled Steam app.
|
||||
if (officialSteamApp != nil) {
|
||||
// If we didn't find a manually added Steam app, remove the official one to
|
||||
// comply with the App Store guidelines.
|
||||
if (manuallyAddedSteamApp == nil) {
|
||||
[_appList removeObject:officialSteamApp];
|
||||
}
|
||||
else {
|
||||
[_appList removeObject:manuallyAddedSteamApp];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSSet*) getAppList {
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
if ([serverInfoResponse isStatusOk]) {
|
||||
host = [[TemporaryHost alloc] init];
|
||||
host.activeAddress = host.address = hostAddress;
|
||||
host.online = YES;
|
||||
host.state = StateOnline;
|
||||
[serverInfoResponse populateHost:host];
|
||||
if (![self addHostToDiscovery:host]) {
|
||||
callback(nil, @"Host information updated");
|
||||
@@ -130,24 +130,17 @@
|
||||
if (host.localAddress != nil) {
|
||||
existingHost.localAddress = host.localAddress;
|
||||
}
|
||||
if (host.ipv6Address != nil) {
|
||||
existingHost.ipv6Address = host.ipv6Address;
|
||||
}
|
||||
if (host.externalAddress != nil) {
|
||||
existingHost.externalAddress = host.externalAddress;
|
||||
}
|
||||
existingHost.activeAddress = host.activeAddress;
|
||||
existingHost.online = host.online;
|
||||
existingHost.state = host.state;
|
||||
return NO;
|
||||
}
|
||||
else {
|
||||
// If we were added without an explicit address,
|
||||
// populate it from our other available addresses
|
||||
if (host.address == nil) {
|
||||
if (host.externalAddress != nil) {
|
||||
host.address = host.externalAddress;
|
||||
}
|
||||
else {
|
||||
host.address = host.localAddress;
|
||||
}
|
||||
}
|
||||
[_hostQueue addObject:host];
|
||||
if (shouldDiscover) {
|
||||
[_opQueue addOperation:[self createWorkerForHost:host]];
|
||||
|
||||
@@ -52,6 +52,9 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
||||
if (_host.externalAddress != nil) {
|
||||
[array addObject:_host.externalAddress];
|
||||
}
|
||||
if (_host.ipv6Address != nil) {
|
||||
[array addObject:_host.ipv6Address];
|
||||
}
|
||||
|
||||
// Remove duplicate addresses from the list.
|
||||
// This is done using an array rather than a set
|
||||
@@ -115,9 +118,9 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
||||
}
|
||||
}
|
||||
|
||||
_host.online = receivedResponse;
|
||||
_host.state = receivedResponse ? StateOnline : StateOffline;
|
||||
if (receivedResponse) {
|
||||
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online, _host.activeAddress);
|
||||
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t ipv6Address:%@ \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.ipv6Address, _host.uuid, _host.mac, _host.pairState, _host.state, _host.activeAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,26 +63,158 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
||||
[mDNSBrowser stop];
|
||||
}
|
||||
|
||||
+ (NSString*)sockAddrToString:(NSData*)addrData {
|
||||
char addrStr[INET6_ADDRSTRLEN];
|
||||
struct sockaddr* addr = (struct sockaddr*)[addrData bytes];
|
||||
if (addr->sa_family == AF_INET) {
|
||||
inet_ntop(addr->sa_family, &((struct sockaddr_in*)addr)->sin_addr, addrStr, sizeof(addrStr));
|
||||
}
|
||||
else {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
|
||||
inet_ntop(addr->sa_family, &sin6->sin6_addr, addrStr, sizeof(addrStr));
|
||||
if (sin6->sin6_scope_id != 0) {
|
||||
// Link-local addresses with scope IDs are special
|
||||
return [NSString stringWithFormat: @"%s%%%u", addrStr, sin6->sin6_scope_id];
|
||||
}
|
||||
}
|
||||
return [NSString stringWithFormat: @"%s", addrStr];
|
||||
}
|
||||
|
||||
+ (BOOL)isAddress:(uint8_t*)address inSubnet:(uint8_t*)subnet netmask:(int)bits {
|
||||
for (int i = 0; i < bits; i++) {
|
||||
uint8_t mask = 1 << (i % 8);
|
||||
if ((address[i / 8] & mask) != (subnet[i / 8] & mask)) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)isLocalIpv6Address:(NSData*)addrData {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)[addrData bytes];
|
||||
if (sin6->sin6_family != AF_INET6) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
uint8_t* addrBytes = sin6->sin6_addr.s6_addr;
|
||||
uint8_t prefix[2];
|
||||
|
||||
// fe80::/10
|
||||
prefix[0] = 0xfe;
|
||||
prefix[1] = 0x80;
|
||||
if ([MDNSManager isAddress:addrBytes inSubnet:prefix netmask:10]) {
|
||||
// Link-local
|
||||
return YES;
|
||||
}
|
||||
|
||||
// fec0::/10
|
||||
prefix[0] = 0xfe;
|
||||
prefix[1] = 0xc0;
|
||||
if ([MDNSManager isAddress:addrBytes inSubnet:prefix netmask:10]) {
|
||||
// Site local
|
||||
return YES;
|
||||
}
|
||||
|
||||
// fc00::/7
|
||||
prefix[0] = 0xfc;
|
||||
prefix[1] = 0x00;
|
||||
if ([MDNSManager isAddress:addrBytes inSubnet:prefix netmask:7]) {
|
||||
// ULA
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSString*)getBestIpv6Address:(NSArray<NSData*>*)addresses {
|
||||
for (NSData* addrData in addresses) {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)[addrData bytes];
|
||||
if (sin6->sin6_family != AF_INET6) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([MDNSManager isLocalIpv6Address:addrData]) {
|
||||
// Skip non-global addresses
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* addrBytes = sin6->sin6_addr.s6_addr;
|
||||
uint8_t prefix[2];
|
||||
|
||||
// 2002::/16
|
||||
prefix[0] = 0x20;
|
||||
prefix[1] = 0x02;
|
||||
if ([MDNSManager isAddress:addrBytes inSubnet:prefix netmask:16]) {
|
||||
Log(LOG_I, @"Ignoring 6to4 address: %@", [MDNSManager sockAddrToString:addrData]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2001::/32
|
||||
prefix[0] = 0x20;
|
||||
prefix[1] = 0x01;
|
||||
if ([MDNSManager isAddress:addrBytes inSubnet:prefix netmask:32]) {
|
||||
Log(LOG_I, @"Ignoring Teredo address: %@", [MDNSManager sockAddrToString:addrData]);
|
||||
continue;
|
||||
}
|
||||
|
||||
return [MDNSManager sockAddrToString:addrData];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)netServiceDidResolveAddress:(NSNetService *)service {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
Log(LOG_D, @"Resolved address: %@ -> %@", service, service.hostName);
|
||||
NSArray<NSData*>* addresses = [service addresses];
|
||||
|
||||
for (NSData* addrData in addresses) {
|
||||
Log(LOG_I, @"Resolved address: %@ -> %@", [service hostName], [MDNSManager sockAddrToString: addrData]);
|
||||
}
|
||||
|
||||
TemporaryHost* host = [[TemporaryHost alloc] init];
|
||||
|
||||
// Since we discovered this host over mDNS, we know we're on the same network
|
||||
// as the PC and we can use our current WAN address as a likely candidate
|
||||
// for our PC's external address.
|
||||
struct in_addr wanAddr;
|
||||
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &wanAddr.s_addr);
|
||||
if (err == 0) {
|
||||
char addrStr[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &wanAddr, addrStr, sizeof(addrStr));
|
||||
host.externalAddress = [NSString stringWithFormat: @"%s", addrStr];
|
||||
}
|
||||
else {
|
||||
Log(LOG_E, @"STUN failed to get WAN address: %d", err);
|
||||
// First, look for an IPv4 record for the local address
|
||||
for (NSData* addrData in addresses) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)[addrData bytes];
|
||||
if (sin->sin_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Since we discovered this host over IPv4 mDNS, we know we're on the same network
|
||||
// as the PC and we can use our current WAN address as a likely candidate
|
||||
// for our PC's external address.
|
||||
struct in_addr wanAddr;
|
||||
int err = LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &wanAddr.s_addr);
|
||||
if (err == 0) {
|
||||
char addrStr[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &wanAddr, addrStr, sizeof(addrStr));
|
||||
host.externalAddress = [NSString stringWithFormat: @"%s", addrStr];
|
||||
Log(LOG_I, @"External IPv4 address (STUN): %@ -> %@", [service hostName], host.externalAddress);
|
||||
}
|
||||
else {
|
||||
Log(LOG_E, @"STUN failed to get WAN address: %d", err);
|
||||
}
|
||||
|
||||
host.localAddress = [MDNSManager sockAddrToString:addrData];
|
||||
Log(LOG_I, @"Local address chosen: %@ -> %@", [service hostName], host.localAddress);
|
||||
break;
|
||||
}
|
||||
|
||||
host.activeAddress = host.localAddress = service.hostName;
|
||||
if (host.localAddress == nil) {
|
||||
// If we didn't find an IPv4 record, look for a local IPv6 record
|
||||
for (NSData* addrData in addresses) {
|
||||
if ([MDNSManager isLocalIpv6Address:addrData]) {
|
||||
host.localAddress = [MDNSManager sockAddrToString:addrData];
|
||||
Log(LOG_I, @"Local address chosen: %@ -> %@", [service hostName], host.localAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
host.ipv6Address = [MDNSManager getBestIpv6Address:addresses];
|
||||
Log(LOG_I, @"IPv6 address chosen: %@ -> %@", [service hostName], host.ipv6Address);
|
||||
|
||||
host.activeAddress = host.localAddress;
|
||||
host.name = service.hostName;
|
||||
[self.callback updateHost:host];
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
if ([serverInfoResp isStatusOk]) {
|
||||
if ([[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_BUSY"]) {
|
||||
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||
[_callback pairFailed:@"You cannot pair while a previous session is still running on the host PC. Quit any running games or reboot the host PC, then try pairing again."];
|
||||
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
||||
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
||||
if (appversion == nil) {
|
||||
@@ -53,10 +53,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
// All codepaths must call pairFailed or pairSuccessful exactly once before returning!
|
||||
- (void) finishPairing:(UIBackgroundTaskIdentifier)bgId withError:(NSString*)errorMsg {
|
||||
if (bgId != UIBackgroundTaskInvalid) {
|
||||
[[UIApplication sharedApplication] endBackgroundTask:bgId];
|
||||
}
|
||||
|
||||
[_callback pairFailed:errorMsg];
|
||||
}
|
||||
|
||||
- (void) finishPairing:(UIBackgroundTaskIdentifier)bgId withSuccess:(NSData*)derCertBytes {
|
||||
if (bgId != UIBackgroundTaskInvalid) {
|
||||
[[UIApplication sharedApplication] endBackgroundTask:bgId];
|
||||
}
|
||||
|
||||
[_callback pairSuccessful:derCertBytes];
|
||||
}
|
||||
|
||||
// All codepaths must call finishPairing exactly once before returning!
|
||||
- (void) initiatePair:(int)serverMajorVersion {
|
||||
Log(LOG_I, @"Pairing with generation %d server", serverMajorVersion);
|
||||
|
||||
// Start a background task to help prevent the app from being killed
|
||||
// while pairing is in progress.
|
||||
UIBackgroundTaskIdentifier bgId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"Pairing PC" expirationHandler:^{
|
||||
Log(LOG_W, @"Background pairing time has expired!");
|
||||
}];
|
||||
|
||||
NSString* PIN = [self generatePIN];
|
||||
NSData* salt = [self saltPIN:PIN];
|
||||
Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
|
||||
@@ -65,18 +87,18 @@
|
||||
HttpResponse* pairResp = [[HttpResponse alloc] init];
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt clientCert:_clientCert]]];
|
||||
if (![self verifyResponseStatus:pairResp]) {
|
||||
[_callback pairFailed:@"Pairing stage #1 failed"];
|
||||
[self finishPairing:bgId withError:@"Pairing stage #1 failed"];
|
||||
return;
|
||||
}
|
||||
NSInteger pairedStatus;
|
||||
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||
[_callback pairFailed:@"Pairing was declined by the target."];
|
||||
[self finishPairing:bgId withError:@"Pairing was declined by the target."];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString* plainCert = [pairResp getStringTag:@"plaincert"];
|
||||
if ([plainCert length] == 0) {
|
||||
[_callback pairFailed:@"Another pairing attempt is already in progress."];
|
||||
[self finishPairing:bgId withError:@"Another pairing attempt is already in progress."];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +129,7 @@
|
||||
![challengeResp getIntTag:@"paired" value:&pairedStatus] ||
|
||||
pairedStatus != 1) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Pairing stage #2 failed"];
|
||||
[self finishPairing:bgId withError:@"Pairing stage #2 failed"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,7 +156,7 @@
|
||||
![secretResp getIntTag:@"paired" value:&pairedStatus] ||
|
||||
pairedStatus != 1) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Pairing stage #3 failed"];
|
||||
[self finishPairing:bgId withError:@"Pairing stage #3 failed"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -144,7 +166,7 @@
|
||||
|
||||
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Server certificate invalid"];
|
||||
[self finishPairing:bgId withError:@"Server certificate invalid"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,7 +180,7 @@
|
||||
}
|
||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Incorrect PIN"];
|
||||
[self finishPairing:bgId withError:@"Incorrect PIN"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -169,7 +191,7 @@
|
||||
![clientSecretResp getIntTag:@"paired" value:&pairedStatus] ||
|
||||
pairedStatus != 1) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Pairing stage #4 failed"];
|
||||
[self finishPairing:bgId withError:@"Pairing stage #4 failed"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -179,21 +201,20 @@
|
||||
![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] ||
|
||||
pairedStatus != 1) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Pairing stage #5 failed"];
|
||||
[self finishPairing:bgId withError:@"Pairing stage #5 failed"];
|
||||
return;
|
||||
}
|
||||
|
||||
[_callback pairSuccessful: derCertBytes];
|
||||
[self finishPairing:bgId withSuccess:derCertBytes];
|
||||
}
|
||||
|
||||
// Caller calls finishPairing for us on failure
|
||||
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
|
||||
if (resp == nil) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:@"Network error occured."];
|
||||
return false;
|
||||
} else if (![resp isStatusOk]) {
|
||||
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||
[_callback pairFailed:resp.statusMessage];
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
|
||||
@@ -19,11 +19,16 @@
|
||||
|
||||
- (void) populateHost:(TemporaryHost*)host {
|
||||
host.name = [[self getStringTag:TAG_HOSTNAME] trim];
|
||||
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
|
||||
host.uuid = [[self getStringTag:TAG_UNIQUE_ID] trim];
|
||||
host.mac = [[self getStringTag:TAG_MAC_ADDRESS] trim];
|
||||
host.currentGame = [[self getStringTag:TAG_CURRENT_GAME] trim];
|
||||
|
||||
// We might get an IPv4 loopback address if we're using GS IPv6 Forwarder
|
||||
NSString *lanAddr = [[self getStringTag:TAG_LOCAL_IP] trim];
|
||||
if (![lanAddr hasPrefix:@"127."]) {
|
||||
host.localAddress = lanAddr;
|
||||
}
|
||||
|
||||
// Modern GFE versions don't actually give us a WAN address anymore
|
||||
// so we leave the one that we populated from mDNS discovery via STUN.
|
||||
NSString *wanAddr = [[self getStringTag:TAG_EXTERNAL_IP] trim];
|
||||
|
||||
@@ -33,7 +33,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
||||
+ (void) wakeHost:(TemporaryHost*)host {
|
||||
NSData* wolPayload = [WakeOnLanManager createPayload:host];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
const char* address;
|
||||
struct addrinfo hints, *res, *curr;
|
||||
|
||||
@@ -44,7 +44,9 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
||||
address = [host.externalAddress UTF8String];
|
||||
} else if (i == 2 && host.address != nil) {
|
||||
address = [host.address UTF8String];
|
||||
} else if (i == 3) {
|
||||
} else if (i == 3 && host.ipv6Address != nil) {
|
||||
address = [host.ipv6Address UTF8String];
|
||||
} else if (i == 4) {
|
||||
address = "255.255.255.255";
|
||||
} else {
|
||||
// Requested address wasn't present
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
- (void) stageFailed:(const char*)stageName withError:(long)errorCode;
|
||||
- (void) launchFailed:(NSString*)message;
|
||||
- (void) rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor;
|
||||
- (void) connectionStatusUpdate:(int)status;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,15 +32,13 @@ static id<ConnectionCallbacks> _callbacks;
|
||||
|
||||
#define OUTPUT_BUS 0
|
||||
|
||||
#define MAX_CHANNEL_COUNT 2
|
||||
#define FRAME_SIZE 240
|
||||
|
||||
#define CIRCULAR_BUFFER_SIZE 32
|
||||
#define CIRCULAR_BUFFER_SIZE 16
|
||||
|
||||
static int audioBufferWriteIndex;
|
||||
static int audioBufferReadIndex;
|
||||
static int activeChannelCount;
|
||||
static short audioCircularBuffer[CIRCULAR_BUFFER_SIZE][FRAME_SIZE * MAX_CHANNEL_COUNT];
|
||||
static int audioBufferStride;
|
||||
static int audioSamplesPerFrame;
|
||||
static short* audioCircularBuffer;
|
||||
|
||||
#define AUDIO_QUEUE_BUFFERS 4
|
||||
|
||||
@@ -50,10 +48,15 @@ static VideoDecoderRenderer* renderer;
|
||||
|
||||
int DrDecoderSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags)
|
||||
{
|
||||
[renderer setupWithVideoFormat:videoFormat];
|
||||
[renderer setupWithVideoFormat:videoFormat refreshRate:redrawRate];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DrCleanup(void)
|
||||
{
|
||||
[renderer cleanup];
|
||||
}
|
||||
|
||||
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
||||
{
|
||||
int offset = 0;
|
||||
@@ -90,15 +93,16 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
{
|
||||
int err;
|
||||
|
||||
// Clear the circular buffer
|
||||
// Initialize the circular buffer
|
||||
audioBufferWriteIndex = audioBufferReadIndex = 0;
|
||||
audioSamplesPerFrame = opusConfig->samplesPerFrame;
|
||||
audioBufferStride = opusConfig->channelCount * opusConfig->samplesPerFrame;
|
||||
audioCircularBuffer = malloc(CIRCULAR_BUFFER_SIZE * audioBufferStride * sizeof(short));
|
||||
if (audioCircularBuffer == NULL) {
|
||||
Log(LOG_E, @"Error allocating output queue\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We only support stereo for now.
|
||||
// TODO: Ensure AudioToolbox's channel mapping matches Opus's
|
||||
// and correct if neccessary.
|
||||
assert(audioConfiguration == AUDIO_CONFIGURATION_STEREO);
|
||||
|
||||
activeChannelCount = opusConfig->channelCount;
|
||||
opusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
||||
opusConfig->channelCount,
|
||||
opusConfig->streams,
|
||||
@@ -113,9 +117,11 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
|
||||
[audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
|
||||
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
|
||||
[audioSession setPreferredOutputNumberOfChannels:opusConfig->channelCount error:&audioSessionError];
|
||||
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
|
||||
[audioSession setActive: YES error: &audioSessionError];
|
||||
|
||||
// FIXME: Calling this breaks surround audio for some reason
|
||||
//[audioSession setPreferredOutputNumberOfChannels:opusConfig->channelCount error:&audioSessionError];
|
||||
#endif
|
||||
|
||||
OSStatus status;
|
||||
@@ -137,8 +143,29 @@ int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, v
|
||||
return status;
|
||||
}
|
||||
|
||||
// We need to specify a channel layout for surround sound configurations
|
||||
if (opusConfig->channelCount > 2) {
|
||||
AudioChannelLayout channelLayout = {};
|
||||
|
||||
switch (opusConfig->channelCount) {
|
||||
case 6:
|
||||
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A;
|
||||
break;
|
||||
default:
|
||||
// Unsupported channel layout
|
||||
Log(LOG_E, @"Unsupported channel layout: %d\n", opusConfig->channelCount);
|
||||
abort();
|
||||
}
|
||||
|
||||
status = AudioQueueSetProperty(audioQueue, kAudioQueueProperty_ChannelLayout, &channelLayout, sizeof(channelLayout));
|
||||
if (status != noErr) {
|
||||
Log(LOG_E, @"Error configuring surround channel layout: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < AUDIO_QUEUE_BUFFERS; i++) {
|
||||
status = AudioQueueAllocateBuffer(audioQueue, audioFormat.mBytesPerFrame * FRAME_SIZE, &audioBuffers[i]);
|
||||
status = AudioQueueAllocateBuffer(audioQueue, audioFormat.mBytesPerFrame * opusConfig->samplesPerFrame, &audioBuffers[i]);
|
||||
if (status != noErr) {
|
||||
Log(LOG_E, @"Error allocating output buffer: %d\n", status);
|
||||
return status;
|
||||
@@ -170,10 +197,15 @@ void ArCleanup(void)
|
||||
// Also frees buffers
|
||||
AudioQueueDispose(audioQueue, true);
|
||||
|
||||
// Must be freed after the queue is stopped
|
||||
if (audioCircularBuffer != NULL) {
|
||||
free(audioCircularBuffer);
|
||||
audioCircularBuffer = NULL;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
// Audio session is now inactive
|
||||
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
||||
[audioSession setActive: YES error: nil];
|
||||
[[AVAudioSession sharedInstance] setActive: NO error: nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -188,7 +220,7 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||
}
|
||||
|
||||
decodeLen = opus_multistream_decode(opusDecoder, (unsigned char *)sampleData, sampleLength,
|
||||
audioCircularBuffer[audioBufferWriteIndex], FRAME_SIZE, 0);
|
||||
(short*)&audioCircularBuffer[audioBufferWriteIndex * audioBufferStride], audioSamplesPerFrame, 0);
|
||||
if (decodeLen > 0) {
|
||||
// Use a full memory barrier to ensure the circular buffer is written before incrementing the index
|
||||
__sync_synchronize();
|
||||
@@ -238,6 +270,11 @@ void ClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsi
|
||||
[_callbacks rumble:controllerNumber lowFreqMotor:lowFreqMotor highFreqMotor:highFreqMotor];
|
||||
}
|
||||
|
||||
void ClConnectionStatusUpdate(int status)
|
||||
{
|
||||
[_callbacks connectionStatusUpdate:status];
|
||||
}
|
||||
|
||||
-(void) terminate
|
||||
{
|
||||
// Interrupt any action blocking LiStartConnection(). This is
|
||||
@@ -327,7 +364,7 @@ void ClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsi
|
||||
// Additionally, iPhone X had a bug which would cause video
|
||||
// to freeze after a few minutes with HEVC prior to iOS 11.3.
|
||||
// As a result, we will only use HEVC on iOS 11.3 or later.
|
||||
if (@available(iOS 11.3, *)) {
|
||||
if (@available(iOS 11.3, tvOS 11.3, *)) {
|
||||
_streamConfig.supportsHevc = config.allowHevc && VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
|
||||
}
|
||||
#else
|
||||
@@ -348,6 +385,7 @@ void ClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsi
|
||||
|
||||
LiInitializeVideoCallbacks(&_drCallbacks);
|
||||
_drCallbacks.setup = DrDecoderSetup;
|
||||
_drCallbacks.cleanup = DrCleanup;
|
||||
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
||||
|
||||
// RFI doesn't work properly with HEVC on iOS 11 with an iPhone SE (at least)
|
||||
@@ -369,6 +407,7 @@ void ClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsi
|
||||
_clCallbacks.connectionTerminated = ClConnectionTerminated;
|
||||
_clCallbacks.logMessage = ClLogMessage;
|
||||
_clCallbacks.rumble = ClRumble;
|
||||
_clCallbacks.connectionStatusUpdate = ClConnectionStatusUpdate;
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -376,7 +415,7 @@ void ClRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsi
|
||||
static void FillOutputBuffer(void *aqData,
|
||||
AudioQueueRef inAQ,
|
||||
AudioQueueBufferRef inBuffer) {
|
||||
inBuffer->mAudioDataByteSize = activeChannelCount * FRAME_SIZE * sizeof(short);
|
||||
inBuffer->mAudioDataByteSize = audioBufferStride * sizeof(short);
|
||||
|
||||
assert(inBuffer->mAudioDataByteSize == inBuffer->mAudioDataBytesCapacity);
|
||||
|
||||
@@ -384,7 +423,7 @@ static void FillOutputBuffer(void *aqData,
|
||||
if (audioBufferWriteIndex != audioBufferReadIndex) {
|
||||
// Copy data to the audio buffer
|
||||
memcpy(inBuffer->mAudioData,
|
||||
audioCircularBuffer[audioBufferReadIndex],
|
||||
&audioCircularBuffer[audioBufferReadIndex * audioBufferStride],
|
||||
inBuffer->mAudioDataByteSize);
|
||||
|
||||
// Use a full memory barrier to ensure the circular buffer is read before incrementing the index
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
- (id)initWithView:(OSView*)view;
|
||||
|
||||
- (void)setupWithVideoFormat:(int)videoFormat;
|
||||
- (void)setupWithVideoFormat:(int)videoFormat refreshRate:(int)refreshRate;
|
||||
|
||||
- (void)cleanup;
|
||||
|
||||
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
NSData *spsData, *ppsData, *vpsData;
|
||||
CMVideoFormatDescriptionRef formatDesc;
|
||||
|
||||
CADisplayLink* _displayLink;
|
||||
}
|
||||
|
||||
- (void)reinitializeDisplayLayer
|
||||
@@ -70,12 +72,33 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupWithVideoFormat:(int)videoFormat
|
||||
- (void)setupWithVideoFormat:(int)videoFormat refreshRate:(int)refreshRate
|
||||
{
|
||||
self->videoFormat = videoFormat;
|
||||
#if !TARGET_OS_IPHONE
|
||||
_view.codec = videoFormat;
|
||||
#endif
|
||||
|
||||
if (refreshRate > 60) {
|
||||
// HACK: We seem to just get 60 Hz screen updates even with a 120 FPS stream if
|
||||
// we don't set preferredFramesPerSecond somewhere. Since we're a UIKit view, we
|
||||
// have to use CADisplayLink for that. See https://github.com/moonlight-stream/moonlight-ios/issues/372
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkCallback:)];
|
||||
if (@available(iOS 10.0, tvOS 10.0, *)) {
|
||||
_displayLink.preferredFramesPerSecond = refreshRate;
|
||||
}
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayLinkCallback:(CADisplayLink *)sender
|
||||
{
|
||||
// No-op - rendering done in submitDecodeBuffer
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[_displayLink invalidate];
|
||||
}
|
||||
|
||||
#define FRAME_START_PREFIX_SIZE 4
|
||||
@@ -356,8 +379,10 @@
|
||||
// Enqueue the next frame
|
||||
[self->displayLayer enqueueSampleBuffer:sampleBuffer];
|
||||
|
||||
// Ensure the layer is visible now
|
||||
self->displayLayer.hidden = NO;
|
||||
if ([self isNalReferencePicture:nalType]) {
|
||||
// Ensure the layer is visible now
|
||||
self->displayLayer.hidden = NO;
|
||||
}
|
||||
|
||||
// Dereference the buffers
|
||||
CFRelease(blockBuffer);
|
||||
|
||||
@@ -66,33 +66,51 @@ static UIImage* noImage;
|
||||
[_callback appClicked:_app];
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
- (UIImageView*) renderToImageView:(UIImage*)appImage {
|
||||
//custom image to do TvOS hover popup effect
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:appImage];
|
||||
imageView.userInteractionEnabled = YES;
|
||||
imageView.adjustsImageWhenAncestorFocused = YES;
|
||||
imageView.frame = self.frame;
|
||||
UIGraphicsBeginImageContextWithOptions(self.frame.size, false, 0);
|
||||
[imageView.layer renderInContext:(UIGraphicsGetCurrentContext())];
|
||||
[_appLabel.layer renderInContext:(UIGraphicsGetCurrentContext())];
|
||||
[_appOverlay.layer renderInContext:(UIGraphicsGetCurrentContext())];
|
||||
UIImage *imageWithText = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
[imageView setImage:imageWithText];
|
||||
[_appButton addSubview:imageView];
|
||||
return imageView;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void) updateAppImage {
|
||||
if (_appOverlay != nil) {
|
||||
[_appOverlay removeFromSuperview];
|
||||
_appOverlay = nil;
|
||||
}
|
||||
|
||||
_appButton.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
||||
self.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
||||
#if TARGET_OS_TV
|
||||
_appButton.frame = CGRectMake(0, 0, 200, 265);
|
||||
#else
|
||||
_appButton.frame = CGRectMake(0, 0, 150, 200);
|
||||
#endif
|
||||
|
||||
self.frame = _appButton.frame;
|
||||
|
||||
if ([_app.id isEqualToString:_app.host.currentGame]) {
|
||||
#if TARGET_OS_TV
|
||||
_appButton.layer.masksToBounds = NO;
|
||||
|
||||
_appButton.layer.shadowColor = [UIColor greenColor].CGColor;
|
||||
_appButton.layer.shadowOffset = CGSizeMake(5,8);
|
||||
_appButton.layer.shadowOpacity = 0.7;
|
||||
#else
|
||||
// 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)];
|
||||
_appOverlay.layer.shadowRadius = 4.0;
|
||||
#if TARGET_OS_TV
|
||||
_appOverlay.contentMode = UIViewContentModeScaleAspectFit;
|
||||
_appOverlay.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height / 3.f);
|
||||
#else
|
||||
_appOverlay.frame = CGRectMake(self.frame.size.width / 4, 10, self.frame.size.width / 2, self.frame.size.height / 4.f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -112,24 +130,13 @@ static UIImage* noImage;
|
||||
// TODO: Improve no-app image detection
|
||||
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
|
||||
#if TARGET_OS_TV
|
||||
//custom image to do TvOS hover popup effect
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:appImage];
|
||||
imageView.userInteractionEnabled = YES;
|
||||
imageView.adjustsImageWhenAncestorFocused = YES;
|
||||
imageView.frame = CGRectMake(0, 0, 200, 265);
|
||||
[_appButton addSubview:imageView];
|
||||
|
||||
_appButton.frame = CGRectMake(0, 0, 200, 265);
|
||||
self.frame = CGRectMake(0, 0, 200, 265);
|
||||
#if TARGET_OS_TV
|
||||
[_appButton addSubview:[self renderToImageView:appImage]];
|
||||
#else
|
||||
_appButton.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
|
||||
self.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
|
||||
|
||||
_appOverlay.frame = CGRectMake(0, 0, self.frame.size.width / 2.f, self.frame.size.height / 4.f);
|
||||
_appOverlay.layer.shadowRadius = 4.0;
|
||||
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
|
||||
[self addSubview:_appOverlay];
|
||||
#endif
|
||||
|
||||
[_appButton setBackgroundImage:appImage forState:UIControlStateNormal];
|
||||
[self setNeedsDisplay];
|
||||
} else {
|
||||
@@ -140,35 +147,27 @@ static UIImage* noImage;
|
||||
}
|
||||
|
||||
if (noAppImage) {
|
||||
#if TARGET_OS_TV
|
||||
_appLabel = [[UILabel alloc] init];
|
||||
[_appLabel setTextColor:[UIColor whiteColor]];
|
||||
[_appLabel setText:_app.name];
|
||||
[_appLabel setFrame:self.frame];
|
||||
#else
|
||||
_appLabel = _appButton.titleLabel;
|
||||
[_appButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[_appButton setTitle:_app.name forState:UIControlStateNormal];
|
||||
[_appButton setTitleEdgeInsets:UIEdgeInsetsMake(_appOverlay != nil ? _appOverlay.frame.size.height : 5, 5, 5, 5)];
|
||||
#endif
|
||||
[_appLabel setFont:[UIFont systemFontOfSize:24]];
|
||||
[_appLabel setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
|
||||
[_appLabel setTextAlignment:NSTextAlignmentCenter];
|
||||
[_appLabel setLineBreakMode:NSLineBreakByWordWrapping];
|
||||
[_appLabel setNumberOfLines:0];
|
||||
[_appLabel setText:_app.name];
|
||||
|
||||
#if TARGET_OS_TV
|
||||
[_appLabel setFont:[UIFont systemFontOfSize:16]];
|
||||
[_appLabel setAdjustsFontSizeToFitWidth:YES];
|
||||
[_appLabel setFrame: CGRectMake(0, 0, 200, 265)];
|
||||
//custom image to do TvOS hover popup effect
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:appImage];
|
||||
imageView.userInteractionEnabled = YES;
|
||||
imageView.adjustsImageWhenAncestorFocused = YES;
|
||||
imageView.frame = CGRectMake(0, 0, 200, 265);
|
||||
UIGraphicsBeginImageContextWithOptions(_appLabel.frame.size, false, 0);
|
||||
[imageView.layer renderInContext:(UIGraphicsGetCurrentContext())];
|
||||
[_appLabel.layer renderInContext:(UIGraphicsGetCurrentContext())];
|
||||
UIImage *imageWithText = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
[imageView setImage:imageWithText];
|
||||
[_appButton addSubview:imageView];
|
||||
_appButton.frame = CGRectMake(0, 0, 200, 265);
|
||||
self.frame = CGRectMake(0, 0, 200, 265);
|
||||
[_appButton addSubview:[self renderToImageView:noImage]];
|
||||
#else
|
||||
CGFloat padding = 4.f;
|
||||
[_appLabel setFrame: CGRectMake(padding, padding, _appButton.frame.size.width - 2 * padding, _appButton.frame.size.height - 2 * padding)];
|
||||
[_appButton addSubview:_appLabel];
|
||||
[self addSubview:_appOverlay];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -182,9 +181,7 @@ static UIImage* noImage;
|
||||
// Update the app image if neccessary
|
||||
if ((_appOverlay != nil && ![_app.id isEqualToString:_app.host.currentGame]) ||
|
||||
(_appOverlay == nil && [_app.id isEqualToString:_app.host.currentGame])) {
|
||||
#if !TARGET_OS_TV
|
||||
[self updateAppImage];
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stop updating when we detach from our parent view
|
||||
|
||||
@@ -12,16 +12,18 @@
|
||||
TemporaryHost* _host;
|
||||
UIButton* _hostButton;
|
||||
UILabel* _hostLabel;
|
||||
UILabel* _hostStatus;
|
||||
UILabel* _hostPairState;
|
||||
UIImageView* _hostOverlay;
|
||||
UIActivityIndicatorView* _hostSpinner;
|
||||
id<HostCallback> _callback;
|
||||
CGSize _labelSize;
|
||||
}
|
||||
static const float REFRESH_CYCLE = 2.0f;
|
||||
|
||||
#if TARGET_OS_TV
|
||||
static const int ITEM_PADDING = 50;
|
||||
static const int LABEL_DY = 40;
|
||||
#else
|
||||
static const int ITEM_PADDING = 0;
|
||||
static const int LABEL_DY = 20;
|
||||
#endif
|
||||
|
||||
@@ -32,53 +34,70 @@ static const int LABEL_DY = 20;
|
||||
[_hostButton setBackgroundImage:[UIImage imageNamed:@"Computer"] forState:UIControlStateNormal];
|
||||
[_hostButton sizeToFit];
|
||||
|
||||
_hostButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||
#if TARGET_OS_TV
|
||||
_hostButton.frame = CGRectMake(0, 0, 400, 400);
|
||||
#else
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
_hostButton.frame = CGRectMake(0, 0, 200, 200);
|
||||
} else {
|
||||
_hostButton.frame = CGRectMake(0, 0, 100, 100);
|
||||
}
|
||||
#endif
|
||||
|
||||
_hostButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||
_hostButton.layer.shadowOffset = CGSizeMake(5,8);
|
||||
_hostButton.layer.shadowOpacity = 0.7;
|
||||
_hostButton.layer.shadowOpacity = 0.3;
|
||||
|
||||
[_hostButton addTarget:self action:@selector(hostButtonSelected:) forControlEvents:UIControlEventTouchDown];
|
||||
[_hostButton addTarget:self action:@selector(hostButtonDeselected:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchDragExit];
|
||||
|
||||
_hostLabel = [[UILabel alloc] init];
|
||||
_hostStatus = [[UILabel alloc] init];
|
||||
_hostPairState = [[UILabel alloc] init];
|
||||
_hostLabel.textColor = [UIColor whiteColor];
|
||||
|
||||
_hostOverlay = [[UIImageView alloc] initWithFrame:CGRectMake(_hostButton.frame.size.width / 3, _hostButton.frame.size.height / 4, _hostButton.frame.size.width / 3, _hostButton.frame.size.height / 3)];
|
||||
_hostSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
[_hostSpinner setFrame:_hostOverlay.frame];
|
||||
_hostSpinner.userInteractionEnabled = NO;
|
||||
_hostSpinner.hidesWhenStopped = YES;
|
||||
|
||||
[self addSubview:_hostButton];
|
||||
[self addSubview:_hostLabel];
|
||||
[self addSubview:_hostOverlay];
|
||||
[self addSubview:_hostSpinner];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) hostButtonSelected:(id)sender {
|
||||
_hostSpinner.layer.opacity = 0.5f;
|
||||
_hostOverlay.layer.opacity = 0.5f;
|
||||
}
|
||||
- (void) hostButtonDeselected:(id)sender {
|
||||
_hostSpinner.layer.opacity = 1.0f;
|
||||
_hostOverlay.layer.opacity = 1.0f;
|
||||
}
|
||||
|
||||
- (id) initForAddWithCallback:(id<HostCallback>)callback {
|
||||
self = [self init];
|
||||
_callback = callback;
|
||||
|
||||
[_hostButton setBackgroundImage:[UIImage imageNamed:@"Computer"] forState:UIControlStateNormal];
|
||||
[_hostButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
||||
if (@available(iOS 9.0, tvOS 9.0, *)) {
|
||||
[_hostButton addTarget:self action:@selector(addClicked) forControlEvents:UIControlEventPrimaryActionTriggered];
|
||||
}
|
||||
else {
|
||||
[_hostButton addTarget:self action:@selector(addClicked) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
[_hostButton sizeToFit];
|
||||
|
||||
[_hostLabel setText:@"Add Host"];
|
||||
[_hostLabel sizeToFit];
|
||||
#if !TARGET_OS_TV
|
||||
_hostLabel.textColor = [UIColor whiteColor];
|
||||
#endif
|
||||
_hostLabel.center = CGPointMake(_hostButton.frame.origin.x + (_hostButton.frame.size.width / 2), _hostButton.frame.origin.y + _hostButton.frame.size.height + LABEL_DY);
|
||||
|
||||
UIImageView* addIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AddComputerIcon"]];
|
||||
[addIcon sizeToFit];
|
||||
addIcon.center = CGPointMake(_hostButton.frame.origin.x + _hostButton.frame.size.width, _hostButton.frame.origin.y);
|
||||
float x = _hostButton.frame.origin.x + _hostButton.frame.size.width / 2;
|
||||
_hostLabel.center = CGPointMake(x, _hostButton.frame.origin.y + _hostButton.frame.size.height + LABEL_DY);
|
||||
|
||||
// This is required to ensure this button is the same size as the others
|
||||
_hostPairState.text = @"None";
|
||||
_hostStatus.text = @"None";
|
||||
[_hostPairState sizeToFit];
|
||||
[_hostStatus sizeToFit];
|
||||
[_hostOverlay setImage:[UIImage imageNamed:@"AddOverlayIcon"]];
|
||||
|
||||
[self updateBounds];
|
||||
[self addSubview:_hostButton];
|
||||
[self addSubview:_hostLabel];
|
||||
[self addSubview:addIcon];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -99,10 +118,6 @@ static const int LABEL_DY = 20;
|
||||
|
||||
[self updateContentsForHost:host];
|
||||
[self updateBounds];
|
||||
[self addSubview:_hostButton];
|
||||
[self addSubview:_hostLabel];
|
||||
[self addSubview:_hostStatus];
|
||||
[self addSubview:_hostPairState];
|
||||
[self startUpdateLoop];
|
||||
|
||||
return self;
|
||||
@@ -116,65 +131,44 @@ static const int LABEL_DY = 20;
|
||||
|
||||
x = MIN(x, _hostButton.frame.origin.x);
|
||||
x = MIN(x, _hostLabel.frame.origin.x);
|
||||
x = MIN(x, _hostStatus.frame.origin.x);
|
||||
x = MIN(x, _hostPairState.frame.origin.x);
|
||||
|
||||
y = MIN(y, _hostButton.frame.origin.y);
|
||||
y = MIN(y, _hostLabel.frame.origin.y);
|
||||
y = MIN(y, _hostStatus.frame.origin.y);
|
||||
y = MIN(y, _hostPairState.frame.origin.y);
|
||||
|
||||
width = MAX(width, _hostButton.frame.size.width);
|
||||
width = MAX(width, _hostLabel.frame.size.width);
|
||||
width = MAX(width, _hostStatus.frame.size.width);
|
||||
width = MAX(width, _hostPairState.frame.size.width);
|
||||
|
||||
height = _hostButton.frame.size.height +
|
||||
_hostLabel.frame.size.height +
|
||||
_hostStatus.frame.size.height +
|
||||
_hostPairState.frame.size.height +
|
||||
LABEL_DY / 2;
|
||||
|
||||
self.bounds = CGRectMake(x, y, width, height);
|
||||
self.frame = CGRectMake(x, y, width, height);
|
||||
self.bounds = CGRectMake(x - ITEM_PADDING, y - ITEM_PADDING, width + 2 * ITEM_PADDING, height + 2 * ITEM_PADDING);
|
||||
}
|
||||
|
||||
- (void) updateContentsForHost:(TemporaryHost*)host {
|
||||
_hostLabel.text = _host.name;
|
||||
#if !TARGET_OS_TV
|
||||
_hostLabel.textColor = [UIColor whiteColor];
|
||||
#endif
|
||||
[_hostLabel sizeToFit];
|
||||
|
||||
switch (host.pairState) {
|
||||
case PairStateUnknown:
|
||||
_hostPairState.text = @"Pair State Unknown";
|
||||
break;
|
||||
case PairStateUnpaired:
|
||||
_hostPairState.text = @"Not Paired";
|
||||
break;
|
||||
case PairStatePaired:
|
||||
_hostPairState.text = @"Paired";
|
||||
break;
|
||||
if (host.state == StateOnline) {
|
||||
[_hostSpinner stopAnimating];
|
||||
|
||||
if (host.pairState == PairStateUnpaired) {
|
||||
[_hostOverlay setImage:[UIImage imageNamed:@"LockedOverlayIcon"]];
|
||||
}
|
||||
else {
|
||||
[_hostOverlay setImage:nil];
|
||||
}
|
||||
}
|
||||
#if !TARGET_OS_TV
|
||||
_hostPairState.textColor = [UIColor whiteColor];
|
||||
#endif
|
||||
[_hostPairState sizeToFit];
|
||||
|
||||
if (host.online) {
|
||||
_hostStatus.text = @"Online";
|
||||
_hostStatus.textColor = [UIColor greenColor];
|
||||
} else {
|
||||
_hostStatus.text = @"Offline";
|
||||
_hostStatus.textColor = [UIColor grayColor];
|
||||
else if (host.state == StateOffline) {
|
||||
[_hostSpinner stopAnimating];
|
||||
[_hostOverlay setImage:[UIImage imageNamed:@"ErrorOverlayIcon"]];
|
||||
}
|
||||
else {
|
||||
[_hostSpinner startAnimating];
|
||||
}
|
||||
[_hostStatus sizeToFit];
|
||||
|
||||
float x = _hostButton.frame.origin.x + _hostButton.frame.size.width / 2;
|
||||
_hostLabel.center = CGPointMake(x, _hostButton.frame.origin.y + _hostButton.frame.size.height + LABEL_DY);
|
||||
_hostPairState.center = CGPointMake(x, _hostLabel.center.y + LABEL_DY);
|
||||
_hostStatus.center = CGPointMake(x, _hostPairState.center.y + LABEL_DY);
|
||||
}
|
||||
|
||||
- (void) startUpdateLoop {
|
||||
@@ -209,8 +203,12 @@ static const int LABEL_DY = 20;
|
||||
UIButton *previousButton = (UIButton *)context.previouslyFocusedItem;
|
||||
UIButton *nextButton = (UIButton *) context.nextFocusedItem;
|
||||
|
||||
previousButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||
nextButton.layer.shadowColor = [[UIColor greenColor] CGColor];
|
||||
if (previousButton.superview == self) {
|
||||
self.backgroundColor = nil;
|
||||
}
|
||||
if (nextButton.superview == self) {
|
||||
nextButton.superview.backgroundColor = [UIColor darkGrayColor];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ typedef NS_ENUM(int, PairState) {
|
||||
PairStatePaired
|
||||
};
|
||||
|
||||
typedef NS_ENUM(int, State) {
|
||||
StateUnknown,
|
||||
StateOffline,
|
||||
StateOnline
|
||||
};
|
||||
|
||||
FOUNDATION_EXPORT NSString *const deviceName;
|
||||
|
||||
+ (NSData*) randomBytes:(NSInteger)length;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
@interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate>
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
@property (strong, nonatomic) IBOutlet UIButton *limelightLogoButton;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *computerNameButton;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsButton;
|
||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *upButton;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,14 +44,12 @@
|
||||
UIAlertController* _pairAlert;
|
||||
LoadingFrameViewController* _loadingFrame;
|
||||
UIScrollView* hostScrollView;
|
||||
int currentPosition;
|
||||
FrontViewPosition currentPosition;
|
||||
NSArray* _sortedAppList;
|
||||
NSCache* _boxArtCache;
|
||||
bool _background;
|
||||
#if TARGET_OS_TV
|
||||
UITapGestureRecognizer* _menuRecognizer;
|
||||
#else
|
||||
UIButton* _pullArrow;
|
||||
#endif
|
||||
}
|
||||
static NSMutableSet* hostList;
|
||||
@@ -111,6 +109,18 @@ static NSMutableSet* hostList;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)disableUpButton {
|
||||
#if !TARGET_OS_TV
|
||||
[self->_upButton setTitle:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)enableUpButton {
|
||||
#if !TARGET_OS_TV
|
||||
[self->_upButton setTitle:@"Select New Host"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)alreadyPaired {
|
||||
BOOL usingCachedAppList = false;
|
||||
|
||||
@@ -126,13 +136,9 @@ static NSMutableSet* hostList;
|
||||
return;
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
self.title = host.name;
|
||||
#else
|
||||
self->_computerNameButton.title = host.name;
|
||||
#endif
|
||||
[self.navigationController.navigationBar setNeedsLayout];
|
||||
|
||||
[self enableUpButton];
|
||||
[self updateAppsForHost:host];
|
||||
[self hideLoadingFrame: nil];
|
||||
});
|
||||
@@ -162,7 +168,7 @@ static NSMutableSet* hostList;
|
||||
[self hideLoadingFrame: ^{
|
||||
[[self activeViewController] presentViewController:applistAlert animated:YES completion:nil];
|
||||
}];
|
||||
host.online = NO;
|
||||
host.state = StateOffline;
|
||||
[self showHostSelectionView];
|
||||
});
|
||||
} else {
|
||||
@@ -174,12 +180,8 @@ static NSMutableSet* hostList;
|
||||
return;
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
self.title = host.name;
|
||||
#else
|
||||
self->_computerNameButton.title = host.name;
|
||||
#endif
|
||||
[self.navigationController.navigationBar setNeedsLayout];
|
||||
[self enableUpButton];
|
||||
|
||||
[self updateAppsForHost:host];
|
||||
[self->_appManager stopRetrieving];
|
||||
@@ -251,11 +253,10 @@ static NSMutableSet* hostList;
|
||||
|
||||
[_appManager stopRetrieving];
|
||||
_selectedHost = nil;
|
||||
#if TARGET_OS_TV
|
||||
|
||||
self.title = @"Select Host";
|
||||
#else
|
||||
_computerNameButton.title = @"No Host Selected";
|
||||
#endif
|
||||
[self disableUpButton];
|
||||
|
||||
[self.collectionView reloadData];
|
||||
[self.view addSubview:hostScrollView];
|
||||
}
|
||||
@@ -284,7 +285,7 @@ static NSMutableSet* hostList;
|
||||
// This shows the context menu with wake, delete, etc. rather
|
||||
// than just hanging for a while and failing as we would in this
|
||||
// code path.
|
||||
if (!host.online && view != nil) {
|
||||
if (host.state != StateOnline && view != nil) {
|
||||
[self hostLongClicked:host view:view];
|
||||
return;
|
||||
}
|
||||
@@ -303,7 +304,7 @@ static NSMutableSet* hostList;
|
||||
// should hit most. Check for a valid view because we don't want to hit the fast
|
||||
// path after coming back from streaming, since we need to fetch serverinfo too
|
||||
// so that our active game data is correct.
|
||||
if (host.online && host.pairState == PairStatePaired && host.appList.count > 0 && view != nil) {
|
||||
if (host.state == StateOnline && host.pairState == PairStatePaired && host.appList.count > 0 && view != nil) {
|
||||
[self alreadyPaired];
|
||||
return;
|
||||
}
|
||||
@@ -341,7 +342,7 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
}];
|
||||
|
||||
host.online = NO;
|
||||
host.state = StateOffline;
|
||||
[self showHostSelectionView];
|
||||
});
|
||||
} else {
|
||||
@@ -384,8 +385,32 @@ static NSMutableSet* hostList;
|
||||
|
||||
- (void)hostLongClicked:(TemporaryHost *)host view:(UIView *)view {
|
||||
Log(LOG_D, @"Long clicked host: %@", host.name);
|
||||
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
if (!host.online) {
|
||||
NSString* message;
|
||||
|
||||
switch (host.state) {
|
||||
case StateOffline:
|
||||
message = @"Offline";
|
||||
break;
|
||||
|
||||
case StateOnline:
|
||||
if (host.pairState == PairStatePaired) {
|
||||
message = @"Online - Paired";
|
||||
}
|
||||
else {
|
||||
message = @"Online - Not Paired";
|
||||
}
|
||||
break;
|
||||
|
||||
case StateUnknown:
|
||||
message = @"Connecting";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:message preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
if (host.state != StateOnline) {
|
||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Wake" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:@"Wake On LAN" message:@"" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[wolAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
||||
@@ -479,10 +504,17 @@ static NSMutableSet* hostList;
|
||||
_streamConfig.multiController = streamSettings.multiController;
|
||||
_streamConfig.gamepadMask = [ControllerSupport getConnectedGamepadMask:_streamConfig];
|
||||
|
||||
// TODO: Detect attached surround sound system then address 5.1 TODOs
|
||||
// in Connection.m
|
||||
_streamConfig.audioChannelCount = 2;
|
||||
_streamConfig.audioChannelMask = 0x3;
|
||||
|
||||
// Probe for supported channel configurations
|
||||
Log(LOG_I, @"Audio device supports %d channels", [AVAudioSession sharedInstance].maximumOutputNumberOfChannels);
|
||||
if ([AVAudioSession sharedInstance].maximumOutputNumberOfChannels >= 6) {
|
||||
_streamConfig.audioChannelCount = 6;
|
||||
_streamConfig.audioChannelMask = 0xFC;
|
||||
}
|
||||
else {
|
||||
_streamConfig.audioChannelCount = 2;
|
||||
_streamConfig.audioChannelMask = 0x3;
|
||||
}
|
||||
|
||||
// HDR requires HDR10 game, HDR10 display, and HEVC Main10 decoder on the client.
|
||||
// It additionally requires an HEVC Main10 encoder on the server (GTX 1000+).
|
||||
@@ -552,46 +584,40 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
}
|
||||
[self->_discMan addHostToDiscovery:app.host];
|
||||
|
||||
UIAlertController* alert;
|
||||
|
||||
|
||||
// If it fails, display an error and stop the current operation
|
||||
if (quitResponse.statusCode != 200) {
|
||||
alert = [UIAlertController alertControllerWithTitle:@"Quitting App Failed"
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Quitting App Failed"
|
||||
message:@"Failed to quit app. If this app was started by "
|
||||
"another device, you'll need to quit from that device."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
}
|
||||
// If it succeeds and we're to start streaming, segue to the stream and return
|
||||
else if (![app.id isEqualToString:currentApp.id]) {
|
||||
app.host.currentGame = @"0";
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateAppsForHost:app.host];
|
||||
[self prepareToStreamApp:app];
|
||||
[self hideLoadingFrame: ^{
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
[[self activeViewController] presentViewController:alert animated:YES completion:nil];
|
||||
}];
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
// Otherwise, display a dialog to notify the user that the app was quit
|
||||
else {
|
||||
app.host.currentGame = @"0";
|
||||
|
||||
alert = [UIAlertController alertControllerWithTitle:@"Quitting App"
|
||||
message:@"The app was quit successfully."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Refresh the UI
|
||||
[self updateAppsForHost:app.host];
|
||||
|
||||
// If it succeeds and we're to start streaming, segue to the stream
|
||||
if (![app.id isEqualToString:currentApp.id]) {
|
||||
[self prepareToStreamApp:app];
|
||||
[self hideLoadingFrame: ^{
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
// Otherwise, just hide the loading icon
|
||||
[self hideLoadingFrame:nil];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateAppsForHost:app.host];
|
||||
[self hideLoadingFrame: ^{
|
||||
[[self activeViewController] presentViewController:alert animated:YES completion:nil];
|
||||
}];
|
||||
});
|
||||
});
|
||||
}];
|
||||
|
||||
@@ -620,30 +646,6 @@ static NSMutableSet* hostList;
|
||||
[(SettingsViewController*)[revealController rearViewController] saveSettings];
|
||||
}
|
||||
|
||||
// Fade out the pull arrow
|
||||
[UIView animateWithDuration:0.1
|
||||
animations:^{
|
||||
self->_pullArrow.alpha = 0.0;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
// Flip the direction of the arrow
|
||||
if (position == FrontViewPositionLeft) {
|
||||
// Change the pull arrow back to the default rotation
|
||||
self->_pullArrow.imageView.transform = CGAffineTransformMakeRotation(0);
|
||||
}
|
||||
else {
|
||||
// Flip the pull arrow when the reveal is toggled
|
||||
self->_pullArrow.imageView.transform = CGAffineTransformMakeRotation(M_PI);
|
||||
}
|
||||
|
||||
// Fade it back in
|
||||
[UIView animateWithDuration:0.2
|
||||
animations:^{
|
||||
self->_pullArrow.alpha = 1.0;
|
||||
}
|
||||
completion:nil];
|
||||
}];
|
||||
|
||||
currentPosition = position;
|
||||
}
|
||||
#endif
|
||||
@@ -670,31 +672,53 @@ static NSMutableSet* hostList;
|
||||
[_loadingFrame dismissLoadingFrame:completion];
|
||||
}
|
||||
|
||||
- (void)adjustScrollViewForSafeArea:(UIScrollView*)view {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if (self.view.safeAreaInsets.left >= 20 || self.view.safeAreaInsets.right >= 20) {
|
||||
view.contentInset = UIEdgeInsetsMake(0, 20, 0, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the subviews for the safe area on the iPhone X.
|
||||
- (void)viewSafeAreaInsetsDidChange {
|
||||
[super viewSafeAreaInsetsDidChange];
|
||||
|
||||
[self adjustScrollViewForSafeArea:self.collectionView];
|
||||
[self adjustScrollViewForSafeArea:self->hostScrollView];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.title = @"Select Host";
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
// Set the side bar button action. When it's tapped, it'll show the sidebar.
|
||||
[_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
|
||||
[_settingsButton setTarget:self.revealViewController];
|
||||
[_settingsButton setAction:@selector(revealToggle:)];
|
||||
|
||||
// Set the host name button action. When it's tapped, it'll show the host selection view.
|
||||
[_computerNameButton setTarget:self];
|
||||
[_computerNameButton setAction:@selector(showHostSelectionView)];
|
||||
[_upButton setTarget:self];
|
||||
[_upButton setAction:@selector(showHostSelectionView)];
|
||||
[self disableUpButton];
|
||||
|
||||
// Set the gesture
|
||||
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
|
||||
|
||||
// Get callbacks associated with the viewController
|
||||
[self.revealViewController setDelegate:self];
|
||||
|
||||
// Disable bounce-back on reveal VC otherwise the settings will snap closed
|
||||
// if the user drags all the way off the screen opposite the settings pane.
|
||||
self.revealViewController.bounceBackOnOverdraw = NO;
|
||||
#else
|
||||
_menuRecognizer = [[UITapGestureRecognizer alloc] init];
|
||||
[_menuRecognizer addTarget:self action: @selector(showHostSelectionView)];
|
||||
_menuRecognizer.allowedPressTypes = [[NSArray alloc] initWithObjects:[NSNumber numberWithLong:UIPressTypeMenu], nil];
|
||||
|
||||
self.navigationController.navigationBar.titleTextAttributes = [NSDictionary dictionaryWithObject:[UIColor whiteColor] forKey:NSForegroundColorAttributeName];
|
||||
|
||||
self.title = @"Select Host";
|
||||
#endif
|
||||
|
||||
_loadingFrame = [self.storyboard instantiateViewControllerWithIdentifier:@"loadingFrame"];
|
||||
@@ -716,25 +740,12 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
|
||||
_boxArtCache = [[NSCache alloc] init];
|
||||
|
||||
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
||||
|
||||
|
||||
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 setShowsHorizontalScrollIndicator:NO];
|
||||
hostScrollView.delaysContentTouches = NO;
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
_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);
|
||||
#endif
|
||||
|
||||
self.collectionView.delaysContentTouches = NO;
|
||||
self.collectionView.allowsMultipleSelection = NO;
|
||||
#if !TARGET_OS_TV
|
||||
@@ -745,9 +756,6 @@ static NSMutableSet* hostList;
|
||||
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
|
||||
|
||||
[self.view addSubview:hostScrollView];
|
||||
#if !TARGET_OS_TV
|
||||
[self.view addSubview:_pullArrow];
|
||||
#endif
|
||||
}
|
||||
|
||||
-(void)beginForegroundRefresh:(bool)refreshAppList
|
||||
@@ -861,6 +869,9 @@ static NSMutableSet* hostList;
|
||||
if (host.activeAddress == nil) {
|
||||
host.activeAddress = host.address;
|
||||
}
|
||||
if (host.activeAddress == nil) {
|
||||
host.activeAddress = host.ipv6Address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -869,7 +880,7 @@ static NSMutableSet* hostList;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
Log(LOG_D, @"New host list:");
|
||||
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 ipv6Address:%@ \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.ipv6Address, host.uuid, host.mac, host.pairState, host.state, host.activeAddress);
|
||||
}
|
||||
@synchronized(hostList) {
|
||||
[hostList removeAllObjects];
|
||||
@@ -911,10 +922,18 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
|
||||
- (float) getCompViewX:(UIComputerView*)comp addComp:(UIComputerView*)addComp prevEdge:(float)prevEdge {
|
||||
float padding;
|
||||
|
||||
#if TARGET_OS_TV
|
||||
padding = 100;
|
||||
#else
|
||||
padding = addComp.frame.size.width / 2;
|
||||
#endif
|
||||
|
||||
if (prevEdge == -1) {
|
||||
return hostScrollView.frame.origin.x + comp.frame.size.width / 2 + addComp.frame.size.width / 2;
|
||||
return hostScrollView.frame.origin.x + comp.frame.size.width / 2 + padding;
|
||||
} else {
|
||||
return prevEdge + addComp.frame.size.width / 2 + comp.frame.size.width / 2;
|
||||
return prevEdge + comp.frame.size.width / 2 + padding;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *hevcSelector;
|
||||
@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
||||
|
||||
// This is okay because it's just an enum and access uses @available checks
|
||||
@property(nonatomic) UIUserInterfaceStyle overrideUserInterfaceStyle;
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (void) saveSettings;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
#import "TemporarySettings.h"
|
||||
#import "DataManager.h"
|
||||
|
||||
#import <VideoToolbox/VideoToolbox.h>
|
||||
|
||||
@implementation SettingsViewController {
|
||||
NSInteger _bitrate;
|
||||
Boolean _adjustedForSafeArea;
|
||||
}
|
||||
|
||||
@dynamic overrideUserInterfaceStyle;
|
||||
|
||||
static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
||||
static const int bitrateTable[] = {
|
||||
500,
|
||||
@@ -65,10 +69,12 @@ static const int bitrateTable[] = {
|
||||
// highest view Y value to set our scroll view's content
|
||||
// size.
|
||||
for (UIView* view in self.scrollView.subviews) {
|
||||
// UIScrollViews have 2 default UIImageView children
|
||||
// UIScrollViews have 2 default child views
|
||||
// which represent the horizontal and vertical scrolling
|
||||
// indicators. Ignore these when computing content size.
|
||||
if ([view isKindOfClass:[UIImageView class]]) {
|
||||
// indicators. Ignore any views we don't recognize.
|
||||
if (![view isKindOfClass:[UILabel class]] &&
|
||||
![view isKindOfClass:[UISegmentedControl class]] &&
|
||||
![view isKindOfClass:[UISlider class]]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -82,26 +88,31 @@ static const int bitrateTable[] = {
|
||||
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width,
|
||||
highestViewY + 20);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the subviews for the safe area on the iPhone X.
|
||||
- (void)viewSafeAreaInsetsDidChange {
|
||||
[super viewSafeAreaInsetsDidChange];
|
||||
|
||||
// Adjust the subviews for the safe area on the iPhone X.
|
||||
if (!_adjustedForSafeArea) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
for (UIView* view in self.view.subviews) {
|
||||
// HACK: The official safe area is much too large for our purposes
|
||||
// so we'll just use the presence of any safe area to indicate we should
|
||||
// pad by 20.
|
||||
if (self.view.safeAreaInsets.left >= 20 || self.view.safeAreaInsets.right >= 20) {
|
||||
view.frame = CGRectMake(view.frame.origin.x + 20, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
|
||||
}
|
||||
if (@available(iOS 11.0, *)) {
|
||||
for (UIView* view in self.view.subviews) {
|
||||
// HACK: The official safe area is much too large for our purposes
|
||||
// so we'll just use the presence of any safe area to indicate we should
|
||||
// pad by 20.
|
||||
if (self.view.safeAreaInsets.left >= 20 || self.view.safeAreaInsets.right >= 20) {
|
||||
view.frame = CGRectMake(view.frame.origin.x + 20, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
_adjustedForSafeArea = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Always run settings in dark mode because we want the light fonts
|
||||
if (@available(iOS 13.0, tvOS 13.0, *)) {
|
||||
self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
|
||||
}
|
||||
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
TemporarySettings* currentSettings = [dataMan getSettings];
|
||||
@@ -134,11 +145,14 @@ static const int bitrateTable[] = {
|
||||
case 1080:
|
||||
resolution = 2;
|
||||
break;
|
||||
case 2160:
|
||||
resolution = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
// Only show the 120 FPS option if we have a > 60-ish Hz display
|
||||
bool enable120Fps = false;
|
||||
if (@available(iOS 10.3, *)) {
|
||||
if (@available(iOS 10.3, tvOS 10.3, *)) {
|
||||
if ([UIScreen mainScreen].maximumFramesPerSecond > 62) {
|
||||
enable120Fps = true;
|
||||
}
|
||||
@@ -147,10 +161,39 @@ static const int bitrateTable[] = {
|
||||
[self.framerateSelector removeSegmentAtIndex:2 animated:NO];
|
||||
}
|
||||
|
||||
// Only show the 4K option for "recent" devices. We'll judge that by whether
|
||||
// they support HEVC decoding (A9 or later).
|
||||
if (@available(iOS 11.0, tvOS 11.0, *)) {
|
||||
if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
||||
[self.resolutionSelector removeSegmentAtIndex:3 animated:NO];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[self.resolutionSelector removeSegmentAtIndex:3 animated:NO];
|
||||
}
|
||||
|
||||
// Disable the HEVC selector if HEVC is not supported by the hardware
|
||||
// or the version of iOS. See comment in Connection.m for reasoning behind
|
||||
// the iOS 11.3 check.
|
||||
if (@available(iOS 11.3, tvOS 11.3, *)) {
|
||||
if (VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) {
|
||||
[self.hevcSelector setSelectedSegmentIndex:currentSettings.useHevc ? 1 : 0];
|
||||
}
|
||||
else {
|
||||
[self.hevcSelector removeAllSegments];
|
||||
[self.hevcSelector insertSegmentWithTitle:@"Unsupported on this device" atIndex:0 animated:NO];
|
||||
[self.hevcSelector setEnabled:NO];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[self.hevcSelector removeAllSegments];
|
||||
[self.hevcSelector insertSegmentWithTitle:@"Requires iOS 11.3 or later" atIndex:0 animated:NO];
|
||||
[self.hevcSelector setEnabled:NO];
|
||||
}
|
||||
|
||||
[self.optimizeSettingsSelector setSelectedSegmentIndex:currentSettings.optimizeGames ? 1 : 0];
|
||||
[self.multiControllerSelector setSelectedSegmentIndex:currentSettings.multiController ? 1 : 0];
|
||||
[self.audioOnPCSelector setSelectedSegmentIndex:currentSettings.playAudioOnPC ? 1 : 0];
|
||||
[self.hevcSelector setSelectedSegmentIndex:currentSettings.useHevc ? 1 : 0];
|
||||
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||
[self.resolutionSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||
@@ -196,7 +239,7 @@ static const int bitrateTable[] = {
|
||||
}
|
||||
|
||||
// We should always be exactly on a slider position with default bitrates
|
||||
_bitrate = defaultBitrate;
|
||||
_bitrate = MIN(defaultBitrate, 100000);
|
||||
assert(bitrateTable[[self getSliderValueForBitrate:_bitrate]] == _bitrate);
|
||||
[self.bitrateSlider setValue:[self getSliderValueForBitrate:_bitrate] animated:YES];
|
||||
|
||||
@@ -228,7 +271,7 @@ static const int bitrateTable[] = {
|
||||
}
|
||||
|
||||
- (NSInteger) getChosenStreamHeight {
|
||||
const int resolutionTable[] = { 360, 720, 1080 };
|
||||
const int resolutionTable[] = { 360, 720, 1080, 2160 };
|
||||
return resolutionTable[[self.resolutionSelector selectedSegmentIndex]];
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <Limelight.h>
|
||||
|
||||
@implementation StreamFrameViewController {
|
||||
ControllerSupport *_controllerSupport;
|
||||
@@ -22,6 +23,7 @@
|
||||
NSTimer *_inactivityTimer;
|
||||
UITapGestureRecognizer *_menuGestureRecognizer;
|
||||
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
|
||||
UITextView *_overlayView;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
@@ -48,6 +50,8 @@
|
||||
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
|
||||
[(StreamView*)self.view setupStreamView];
|
||||
|
||||
[self.stageLabel setText:[NSString stringWithFormat:@"Starting %@...", self.streamConfig.appName]];
|
||||
[self.stageLabel sizeToFit];
|
||||
self.stageLabel.textAlignment = NSTextAlignmentCenter;
|
||||
@@ -118,6 +122,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateOverlayText:(NSString*)text {
|
||||
if (_overlayView == nil) {
|
||||
_overlayView = [[UITextView alloc] init];
|
||||
#ifndef TARGET_OS_TV
|
||||
[_overlayView setEditable:NO];
|
||||
#endif
|
||||
[_overlayView setUserInteractionEnabled:NO];
|
||||
[_overlayView setSelectable:NO];
|
||||
[_overlayView setScrollEnabled:NO];
|
||||
[_overlayView setTextAlignment:NSTextAlignmentCenter];
|
||||
[_overlayView setTextColor:[OSColor lightGrayColor]];
|
||||
[_overlayView setBackgroundColor:[OSColor blackColor]];
|
||||
[_overlayView setFont:[UIFont systemFontOfSize:12]];
|
||||
[_overlayView setAlpha:0.5];
|
||||
[self.view addSubview:_overlayView];
|
||||
}
|
||||
|
||||
if (text != nil) {
|
||||
[_overlayView setText:text];
|
||||
[_overlayView sizeToFit];
|
||||
[_overlayView setCenter:CGPointMake(self.view.frame.size.width / 2, _overlayView.frame.size.height / 2)];
|
||||
[_overlayView setHidden:NO];
|
||||
}
|
||||
else {
|
||||
[_overlayView setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) returnToMainFrame {
|
||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||
}
|
||||
@@ -264,6 +296,27 @@
|
||||
[_controllerSupport rumble:controllerNumber lowFreqMotor:lowFreqMotor highFreqMotor:highFreqMotor];
|
||||
}
|
||||
|
||||
- (void)connectionStatusUpdate:(int)status {
|
||||
Log(LOG_W, @"Connection status update: %d", status);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
switch (status) {
|
||||
case CONN_STATUS_OKAY:
|
||||
[self updateOverlayText:nil];
|
||||
break;
|
||||
|
||||
case CONN_STATUS_POOR:
|
||||
if (self->_streamConfig.bitRate > 5000) {
|
||||
[self updateOverlayText:@"Slow connection to PC\nReduce your bitrate"];
|
||||
}
|
||||
else {
|
||||
[self updateOverlayText:@"Poor connection to PC"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="14313.18" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="pui-7y-JNH">
|
||||
<device id="appleTV" orientation="landscape">
|
||||
<adaptation id="light"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder.AppleTV.Storyboard" version="3.0" toolsVersion="14868" targetRuntime="AppleTV" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="pui-7y-JNH">
|
||||
<device id="appleTV" appearance="dark"/>
|
||||
<dependencies>
|
||||
<deployment identifier="tvOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -15,10 +13,10 @@
|
||||
<objects>
|
||||
<navigationController id="pui-7y-JNH" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translucent="NO" id="Lgd-OS-TqA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="145"/>
|
||||
<rect key="frame" x="0.0" y="60" width="1920" height="145"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="barTintColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="barTintColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="textShadowColor" white="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -37,7 +35,7 @@
|
||||
<objects>
|
||||
<collectionViewController id="vKn-MI-uG7" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" prefetchingEnabled="YES" id="8P0-wP-bDe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="875"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="50" minimumInteritemSpacing="50" id="m6l-TM-5FZ">
|
||||
<size key="itemSize" width="300" height="400"/>
|
||||
@@ -105,7 +103,7 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="6Xc-C7-Or1"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="CAm-nS-IFz" userLabel="RenderView" customClass="StreamView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="1080"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1920" height="875"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="0eJ-kd-ugl" userLabel="Spinner">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Automatic</string>
|
||||
<string>Dark</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
|
||||
@@ -6,66 +6,6 @@
|
||||
<string>Root</string>
|
||||
<key>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Host Configuration</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
<key>Title</key>
|
||||
<string>Play Audio on Host PC</string>
|
||||
<key>Key</key>
|
||||
<string>audioOnPC</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>TrueValue</key>
|
||||
<string>Optimize Games</string>
|
||||
<key>FalseValue</key>
|
||||
<string>Off</string>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Optimize Games</string>
|
||||
<key>Key</key>
|
||||
<string>optimizeGames</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>HEVC Video</string>
|
||||
<key>Key</key>
|
||||
<string>useHevc</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Enable HDR</string>
|
||||
<key>Key</key>
|
||||
<string>enableHdr</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Enable multi-controller support</string>
|
||||
<key>Key</key>
|
||||
<string>multipleControllers</string>
|
||||
<key>DefaultValue</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
@@ -122,7 +62,7 @@
|
||||
<key>Key</key>
|
||||
<string>bitrate</string>
|
||||
<key>DefaultValue</key>
|
||||
<string>10000</string>
|
||||
<string>20000</string>
|
||||
<key>Titles</key>
|
||||
<array>
|
||||
<string>0.5 Mbps</string>
|
||||
@@ -148,6 +88,62 @@
|
||||
<string>100000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Host Configuration</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
<key>Title</key>
|
||||
<string>Play Audio on Host PC</string>
|
||||
<key>Key</key>
|
||||
<string>audioOnPC</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Optimize Game Settings</string>
|
||||
<key>Key</key>
|
||||
<string>optimizeGames</string>
|
||||
<key>DefaultValue</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Use HEVC Codec</string>
|
||||
<key>Key</key>
|
||||
<string>useHevc</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Request HDR Video</string>
|
||||
<key>Key</key>
|
||||
<string>enableHdr</string>
|
||||
<key>DefaultValue</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>Title</key>
|
||||
<string>Automatic Game Controller Detection</string>
|
||||
<key>Key</key>
|
||||
<string>multipleControllers</string>
|
||||
<key>DefaultValue</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
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 */; };
|
||||
D46A73AD1CBC7D090039F1EE /* ControllerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46A73AC1CBC7D090039F1EE /* ControllerUnitTests.swift */; };
|
||||
DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1F5A06206436B20037755F /* ConnectionHelper.m */; };
|
||||
FB1A674D2131E65900507771 /* KeyboardSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1A674C2131E65900507771 /* KeyboardSupport.m */; };
|
||||
FB1A67602132419700507771 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FB1A675E2132419700507771 /* Main.storyboard */; };
|
||||
@@ -137,13 +136,6 @@
|
||||
remoteGlobalIDString = FB290E2D19B37A4E004C83CF;
|
||||
remoteInfo = "moonlight-common";
|
||||
};
|
||||
D46A73A51CBC7CB60039F1EE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = FB290CE619B2C406004C83CF /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = FB290CED19B2C406004C83CF;
|
||||
remoteInfo = Moonlight;
|
||||
};
|
||||
FB1A68142132509400507771 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */;
|
||||
@@ -166,6 +158,7 @@
|
||||
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>"; };
|
||||
98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.3.xcdatamodel"; sourceTree = "<group>"; };
|
||||
98608BDD22DC0C2C000E5672 /* Moonlight v1.4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.4.xcdatamodel"; sourceTree = "<group>"; };
|
||||
9865DC3B2132922E0005B9B9 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS11.4.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
|
||||
986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.2.xcdatamodel"; sourceTree = "<group>"; };
|
||||
98878AE0206A226D00586E90 /* OSPortabilityDefs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OSPortabilityDefs.h; sourceTree = "<group>"; };
|
||||
@@ -177,10 +170,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
DC1F5A05206436B10037755F /* ConnectionHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnectionHelper.h; sourceTree = "<group>"; };
|
||||
DC1F5A06206436B20037755F /* ConnectionHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConnectionHelper.m; sourceTree = "<group>"; };
|
||||
@@ -369,13 +358,6 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D46A739D1CBC7CB60039F1EE /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FB1A67502132419700507771 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -419,24 +401,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D46A73A11CBC7CB60039F1EE /* MoonlightUnitTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D46A73AB1CBC7D080039F1EE /* MoonlightUnitTests-Bridging-Header.h */,
|
||||
D46A73AA1CBC7CEF0039F1EE /* Input */,
|
||||
D46A73A41CBC7CB60039F1EE /* Info.plist */,
|
||||
);
|
||||
path = MoonlightUnitTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D46A73AA1CBC7CEF0039F1EE /* Input */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D46A73AC1CBC7D090039F1EE /* ControllerUnitTests.swift */,
|
||||
);
|
||||
name = Input;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FB1A67542132419700507771 /* Moonlight TV */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -454,7 +418,6 @@
|
||||
children = (
|
||||
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */,
|
||||
FB290CF919B2C406004C83CF /* Moonlight */,
|
||||
D46A73A11CBC7CB60039F1EE /* MoonlightUnitTests */,
|
||||
FB1A67542132419700507771 /* Moonlight TV */,
|
||||
FB290CF019B2C406004C83CF /* Frameworks */,
|
||||
FB290CEF19B2C406004C83CF /* Products */,
|
||||
@@ -465,7 +428,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FB290CEE19B2C406004C83CF /* Moonlight.app */,
|
||||
D46A73A01CBC7CB60039F1EE /* MoonlightUnitTests.xctest */,
|
||||
FB1A67532132419700507771 /* Moonlight TV.app */,
|
||||
);
|
||||
name = Products;
|
||||
@@ -835,24 +797,6 @@
|
||||
/* End PBXGroup 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";
|
||||
};
|
||||
FB1A67522132419700507771 /* Moonlight TV */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = FB1A67682132419A00507771 /* Build configuration list for PBXNativeTarget "Moonlight TV" */;
|
||||
@@ -899,11 +843,6 @@
|
||||
LastUpgradeCheck = 1010;
|
||||
ORGANIZATIONNAME = "Moonlight Game Streaming Project";
|
||||
TargetAttributes = {
|
||||
D46A739F1CBC7CB60039F1EE = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
LastSwiftMigration = 0920;
|
||||
TestTargetID = FB290CED19B2C406004C83CF;
|
||||
};
|
||||
FB1A67522132419700507771 = {
|
||||
CreatedOnToolsVersion = 9.4.1;
|
||||
LastSwiftMigration = 1010;
|
||||
@@ -922,10 +861,9 @@
|
||||
};
|
||||
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
@@ -941,7 +879,6 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
FB290CED19B2C406004C83CF /* Moonlight */,
|
||||
D46A739F1CBC7CB60039F1EE /* MoonlightUnitTests */,
|
||||
FB1A67522132419700507771 /* Moonlight TV */,
|
||||
);
|
||||
};
|
||||
@@ -965,13 +902,6 @@
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
D46A739E1CBC7CB60039F1EE /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FB1A67512132419700507771 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -998,14 +928,6 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D46A739C1CBC7CB60039F1EE /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D46A73AD1CBC7D090039F1EE /* ControllerUnitTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
FB1A674F2132419700507771 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1114,11 +1036,6 @@
|
||||
name = "moonlight-common";
|
||||
targetProxy = 98AB2E851CAD468B0089BB98 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D46A73A61CBC7CB60039F1EE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = FB290CED19B2C406004C83CF /* Moonlight */;
|
||||
targetProxy = D46A73A51CBC7CB60039F1EE /* PBXContainerItemProxy */;
|
||||
};
|
||||
FB1A68172132509800507771 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "moonlight-common-tv";
|
||||
@@ -1146,56 +1063,6 @@
|
||||
/* End PBXVariantGroup 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_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.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_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
FB1A67662132419A00507771 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1205,7 +1072,6 @@
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
@@ -1248,7 +1114,6 @@
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@@ -1373,6 +1238,7 @@
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -1396,6 +1262,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
ENABLE_BITCODE = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
||||
@@ -1413,6 +1280,7 @@
|
||||
"$(PROJECT_DIR)/libs/opus/lib/iOS",
|
||||
"$(PROJECT_DIR)/libs/openssl/lib/iOS",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
@@ -1433,6 +1301,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
ENABLE_BITCODE = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
||||
@@ -1450,6 +1319,7 @@
|
||||
"$(PROJECT_DIR)/libs/opus/lib/iOS",
|
||||
"$(PROJECT_DIR)/libs/openssl/lib/iOS",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE = "";
|
||||
@@ -1466,15 +1336,6 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D46A73A91CBC7CB60039F1EE /* Build configuration list for PBXNativeTarget "MoonlightUnitTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D46A73A71CBC7CB60039F1EE /* Debug */,
|
||||
D46A73A81CBC7CB60039F1EE /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
FB1A67682132419A00507771 /* Build configuration list for PBXNativeTarget "Moonlight TV" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
@@ -1508,6 +1369,7 @@
|
||||
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
98608BDD22DC0C2C000E5672 /* Moonlight v1.4.xcdatamodel */,
|
||||
98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */,
|
||||
986CCE6C2133E45300168291 /* Moonlight v1.2.xcdatamodel */,
|
||||
98132E8C20BC9A62007A053F /* Moonlight v1.1.xcdatamodel */,
|
||||
@@ -1517,7 +1379,7 @@
|
||||
FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */,
|
||||
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */,
|
||||
);
|
||||
currentVersion = 98517B1B21CE0A9000481377 /* Moonlight v1.3.xcdatamodel */;
|
||||
currentVersion = 98608BDD22DC0C2C000E5672 /* Moonlight v1.4.xcdatamodel */;
|
||||
path = Limelight.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(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>
|
||||
@@ -1,192 +0,0 @@
|
||||
//
|
||||
// ControllerUnitTests.swift
|
||||
// Moonlight
|
||||
//
|
||||
// Created by David Aghassi on 4/11/16.
|
||||
// Copyright © 2016 Moonlight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Moonlight
|
||||
|
||||
/**
|
||||
Tests the `Controller.swift` class
|
||||
*/
|
||||
class ControllerUnitTests: XCTestCase {
|
||||
var controllerUnderTest: Controller!
|
||||
|
||||
override func setUp() {
|
||||
controllerUnderTest = Controller()
|
||||
XCTAssertNotNil(controllerUnderTest, "controllerUnderTest is nil, and should not be for this test. See line \(#line) \n")
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
resetAllValues()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Helper Methods
|
||||
/**
|
||||
Sets all the values of `controllerUnderTest` to `0`
|
||||
*/
|
||||
func resetAllValues() {
|
||||
controllerUnderTest.emulatingButtonFlags = CInt(0)
|
||||
controllerUnderTest.lastButtonFlags = CInt(0)
|
||||
|
||||
controllerUnderTest.lastLeftStickX = CShort(0)
|
||||
controllerUnderTest.lastLeftStickY = CShort(0)
|
||||
controllerUnderTest.lastRightStickX = CShort(0)
|
||||
controllerUnderTest.lastRightStickY = CShort(0)
|
||||
|
||||
controllerUnderTest.lastLeftTrigger = CChar(0)
|
||||
controllerUnderTest.lastRightTrigger = CChar(0)
|
||||
}
|
||||
|
||||
/**
|
||||
Displays "*name* failed to set CInt correctly." Shows expected and actual, as well as failure line.
|
||||
|
||||
- parameter name: The property being tested
|
||||
- parameter expected: The expected value for the property
|
||||
- parameter actual: The actual value for the property
|
||||
|
||||
- returns: A string with the failure in it. Formatted to state actual, expected, and the failure line.
|
||||
*/
|
||||
func displayCIntFailure(name: String, expected: CInt, actual: CInt) -> String {
|
||||
return "\(name) failed to set CInt correctly \n. Expected: \(expected)\n. Actual: \(actual) \n. See line \(#line) \n"
|
||||
}
|
||||
|
||||
/**
|
||||
Displays "*name* failed to set CShort correctly." Shows expected and actual, as well as failure line.
|
||||
|
||||
- parameter name: The property being tested
|
||||
- parameter expected: The expected value for the property
|
||||
- parameter actual: The actual value for the property
|
||||
|
||||
- returns: A string with the failure in it. Formatted to state actual, expected, and the failure line.
|
||||
*/
|
||||
func displayCShortFailure(name: String, expected: CShort, actual: CShort) -> String {
|
||||
return "\(name) failed to set CShort correctly \n. Expected: \(expected)\n. Actual: \(actual) \n. See line \(#line) \n"
|
||||
}
|
||||
|
||||
/**
|
||||
Displays "*name* failed to set CCHar correctly." Shows expected and actual, as well as the failure line.
|
||||
|
||||
- parameter name: The property being tested
|
||||
- parameter expected: The expected value for the property
|
||||
- parameter actual: The actual value for the property
|
||||
|
||||
- returns: A string with the failure in it. Formatted to state actual, expected, and the failure line.
|
||||
*/
|
||||
func displayCCharFailure(name: String, expected: CChar, actual: CChar) -> String {
|
||||
return "\(name) failed to set CChar correctly \n. Expected: \(expected)\n. Actual: \(actual) \n. See line \(#line) \n"
|
||||
}
|
||||
|
||||
|
||||
// MARK: Tests
|
||||
/**
|
||||
Asserts that the `emulatingButtonFlags` is of type `CInt` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_emulatingButtonFlags_Sets_To_CInt() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.emulatingButtonFlags) == CInt.self, "Expected emulatingButtonFlags to be of type CInt. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CInt(1)
|
||||
controllerUnderTest.emulatingButtonFlags = expected
|
||||
XCTAssertTrue(controllerUnderTest.emulatingButtonFlags == expected, displayCIntFailure(name: "emulatingButtonFlags", expected: expected, actual: controllerUnderTest.emulatingButtonFlags))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastButtonFlags` is of type `CInt` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastButtonFlags_Sets_To_CInt() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastButtonFlags) == CInt.self, "Expected lastButtonFlags to be of type CInt. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CInt(1)
|
||||
controllerUnderTest.lastButtonFlags = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastButtonFlags == expected, displayCIntFailure(name: "lastButtonFlags", expected: expected, actual: controllerUnderTest.lastButtonFlags))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastLeftStickX` is of type `CShort` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastLeftStickX_Sets_To_CShort() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastLeftStickX) == CShort.self, "Expected lastLeftStickX to be of type CShort. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CShort(1)
|
||||
controllerUnderTest.lastLeftStickX = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastLeftStickX == expected, displayCShortFailure(name: "lastLeftStickX", expected: expected, actual: controllerUnderTest.lastLeftStickX))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that lastLeftStickY` is of type `CShort` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastLeftStickY_Sets_To_CShort() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastLeftStickY) == CShort.self, "Expected lastLeftStickY to be of type CShort. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CShort(1)
|
||||
controllerUnderTest.lastLeftStickY = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastLeftStickY == expected, displayCShortFailure(name: "lastLeftStickY", expected: expected, actual: controllerUnderTest.lastLeftStickY))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastRightStickX` is of type `CShort` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastRightStickX_SetsTo_CShort() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastRightStickX) == CShort.self, "Expected lastRightStickX to be of type CShort. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CShort(1)
|
||||
controllerUnderTest.lastRightStickX = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastRightStickX == expected, displayCShortFailure(name: "lastRightStickX", expected: expected, actual: controllerUnderTest.lastRightStickX))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastRightStickY` is of type `CShort` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastRightStickY_Sets_To_CShort() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastRightStickY) == CShort.self, "Expected lastRightStickY to be of type CShort. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CShort(1)
|
||||
controllerUnderTest.lastRightStickY = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastRightStickY == expected, displayCShortFailure(name: "lastRightStickY", expected: expected, actual: controllerUnderTest.lastRightStickY))
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastLeftTrigger` is of type `CChar` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastLeftTrigger_Sets_To_CChar() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastLeftTrigger) == CChar.self, "Expected lastLeftTrigger to be of type CChar. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CChar(1)
|
||||
controllerUnderTest.lastLeftTrigger = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastLeftTrigger == expected, displayCCharFailure(name: "lastLeftTrigger", expected: expected, actual: controllerUnderTest.lastLeftTrigger))
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Asserts that the `lastRightTrigger` is of type `CChar` and can be set and gotten from properly
|
||||
*/
|
||||
func test_Assert_lastRightTrigger_Sets_To_CChar() {
|
||||
// Assert type hasn't changed
|
||||
XCTAssertTrue(type(of: controllerUnderTest.lastRightTrigger) == CChar.self, "Expected lastRightTrigger to be of type CChar. See line \(#line) \n")
|
||||
|
||||
// Assert value is assigned properly.
|
||||
let expected = CChar(1)
|
||||
controllerUnderTest.lastRightTrigger = expected
|
||||
XCTAssertTrue(controllerUnderTest.lastRightTrigger == expected, displayCCharFailure(name: "lastRightTrigger", expected: expected, actual: controllerUnderTest.lastRightTrigger))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Moonlight iOS
|
||||
|
||||
[](https://travis-ci.org/moonlight-stream/moonlight-ios)
|
||||
|
||||
#### Now available on the [App Store](https://itunes.apple.com/us/app/moonlight-game-streaming/id1000551566?mt=8)
|
||||
|
||||
[Moonlight](https://moonlight-stream.org) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Moonlight iOS allows you to stream your full collection of Steam games from
|
||||
|
||||
|
After Width: | Height: | Size: 4.0 MiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 239 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 240 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 208 KiB |
@@ -1,28 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" colorMatched="YES" initialViewController="EVd-wq-ego">
|
||||
<device id="ipad9_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="EVd-wq-ego">
|
||||
<device id="ipad11_0rounded" orientation="landscape" layout="fullscreen" appearance="dark"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
<array key="Roboto-Regular.ttf">
|
||||
<string>Roboto-Regular</string>
|
||||
</array>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--Main Frame View Controller-->
|
||||
<scene sceneID="Me4-Nr-liz">
|
||||
<objects>
|
||||
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d" customClass="AppCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="768" height="960"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="784"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.3333333432674408" green="0.3333333432674408" blue="0.3333333432674408" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
|
||||
<size key="itemSize" width="150" height="200"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
@@ -45,40 +37,32 @@
|
||||
</connections>
|
||||
</collectionView>
|
||||
<navigationItem key="navigationItem" id="pSu-bl-gL9">
|
||||
<barButtonItem key="leftBarButtonItem" style="done" id="mSL-ru-nRm">
|
||||
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Tiq-VS-Ua5">
|
||||
<rect key="frame" x="20" y="0.0" width="109" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
||||
<state key="normal" title="Moonlight" image="Logo">
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
</button>
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="KDy-JC-2sU">
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="leftBarButtonItem" title="Settings" id="mSL-ru-nRm"/>
|
||||
<barButtonItem key="rightBarButtonItem" id="KDy-JC-2sU"/>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="computerNameButton" destination="KDy-JC-2sU" id="Lkg-yz-GE6"/>
|
||||
<outlet property="limelightLogoButton" destination="Tiq-VS-Ua5" id="cue-NW-Hty"/>
|
||||
<outlet property="settingsButton" destination="mSL-ru-nRm" id="NRf-lv-vlh"/>
|
||||
<outlet property="upButton" destination="KDy-JC-2sU" id="tXB-Rc-IvJ"/>
|
||||
<segue destination="OIm-0n-i9v" kind="push" identifier="createStreamFrame" id="7gN-E7-Ips"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ZYl-Xu-QyD" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="779" y="295"/>
|
||||
<point key="canvasLocation" x="608.59375" y="172.8515625"/>
|
||||
</scene>
|
||||
<!--Settings View Controller-->
|
||||
<scene sceneID="tWo-uo-hHg">
|
||||
<objects>
|
||||
<viewController id="BsV-3c-455" customClass="SettingsViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="ef6-uF-5Hh"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="XvO-F3-j4u"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="WRy-3f-gEP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pYZ-GR-EwO">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pYZ-GR-EwO">
|
||||
<rect key="frame" x="16" y="20" width="82" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -86,17 +70,19 @@
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="ckc-Dm-8ex">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="ckc-Dm-8ex">
|
||||
<rect key="frame" x="16" y="49" width="209" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="360p"/>
|
||||
<segment title="720p"/>
|
||||
<segment title="1080p"/>
|
||||
<segment title="4K"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Frame Rate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aiv-r8-9k2">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Frame Rate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Aiv-r8-9k2">
|
||||
<rect key="frame" x="16" y="85" width="88" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -104,7 +90,7 @@
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="lGK-vl-pdw">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="lGK-vl-pdw">
|
||||
<rect key="frame" x="16" y="114" width="209" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
@@ -113,8 +99,9 @@
|
||||
<segment title="120 FPS"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lMt-4H-fkV">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lMt-4H-fkV">
|
||||
<rect key="frame" x="16" y="150" width="151" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -122,12 +109,12 @@
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="JAY-nj-UNz">
|
||||
<slider opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="JAY-nj-UNz">
|
||||
<rect key="frame" x="14" y="179" width="213" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="LGV-5y-piG">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LGV-5y-piG">
|
||||
<rect key="frame" x="16" y="217" width="153" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -135,7 +122,7 @@
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="qSU-wh-tqA">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="qSU-wh-tqA">
|
||||
<rect key="frame" x="16" y="246" width="209" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
@@ -145,70 +132,75 @@
|
||||
<segment title="Full"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Optimize Game Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="WSI-9V-G6c">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Optimize Game Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WSI-9V-G6c">
|
||||
<rect key="frame" x="16" y="282" width="186" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="nCO-OT-dV1" userLabel="Optimize Settings Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="nCO-OT-dV1" userLabel="Optimize Settings Selector">
|
||||
<rect key="frame" x="16" y="311" width="209" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Multi-Controller Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="bFD-Ng-abn">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Multi-Controller Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bFD-Ng-abn">
|
||||
<rect key="frame" x="16" y="347" width="169" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="KlC-fG-wEi" userLabel="MC Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="KlC-fG-wEi" userLabel="MC Selector">
|
||||
<rect key="frame" x="16" y="376" width="209" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="Single"/>
|
||||
<segment title="Auto"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Play Audio on PC" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="fXq-oD-MrL">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Play Audio on PC" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fXq-oD-MrL">
|
||||
<rect key="frame" x="16" y="412" width="131" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="WDY-9o-6Hb" userLabel="PC Audio Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="WDY-9o-6Hb" userLabel="PC Audio Selector">
|
||||
<rect key="frame" x="16" y="441" width="209" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="HEVC Video" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6w5-Md-NpV">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="HEVC Video" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6w5-Md-NpV">
|
||||
<rect key="frame" x="16" y="477" width="93" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="aFy-0w-YPe" userLabel="HEVC Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="aFy-0w-YPe" userLabel="HEVC Selector">
|
||||
<rect key="frame" x="16" y="506" width="209" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
|
||||
@@ -227,14 +219,18 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="01j-TU-OoL" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="779" y="1425"/>
|
||||
<point key="canvasLocation" x="608.59375" y="834.9609375"/>
|
||||
</scene>
|
||||
<!--Reveal View Controller-->
|
||||
<scene sceneID="rR7-ZT-bc7">
|
||||
<objects>
|
||||
<viewController id="EVd-wq-ego" customClass="SWRevealViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="CpC-Tn-whm"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="YRO-Lg-RCg"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="hGs-BR-t4b">
|
||||
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
@@ -245,14 +241,14 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="lUU-kb-wrO" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-1728" y="514"/>
|
||||
<point key="canvasLocation" x="-1350" y="301.171875"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="FxL-or-HET">
|
||||
<objects>
|
||||
<navigationController id="baW-rW-rBd" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="RUe-14-4Ya">
|
||||
<rect key="frame" x="0.0" y="20" width="768" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="barTintColor" red="0.66666668653488159" green="0.66666668653488159" blue="0.66666668653488159" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</navigationBar>
|
||||
@@ -262,28 +258,32 @@
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iLe-Yz-zIG" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-397" y="514"/>
|
||||
<point key="canvasLocation" x="-310.15625" y="301.171875"/>
|
||||
</scene>
|
||||
<!--Stream Frame View Controller-->
|
||||
<scene sceneID="RuD-qk-7nb">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="MainFrame" id="OIm-0n-i9v" customClass="StreamFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="l3k-pD-Q9i"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="vu8-3s-HlY"/>
|
||||
</layoutGuides>
|
||||
<view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="VPm-Ae-rc4" userLabel="RenderView" customClass="StreamView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" id="iOs-1X-mSU">
|
||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="iOs-1X-mSU">
|
||||
<rect key="frame" x="502" y="374" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dDs-kT-po6">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" 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"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" id="JkF-l4-Qyt">
|
||||
<textField hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="JkF-l4-Qyt">
|
||||
<rect key="frame" x="335" y="503" width="97" height="65"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -292,7 +292,7 @@
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardAppearance="alert" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tip Text" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Vij-AB-rV8" userLabel="Tip Label">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Tip Text" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vij-AB-rV8" userLabel="Tip Label">
|
||||
<rect key="frame" x="478" y="718" width="68" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||
@@ -317,17 +317,21 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="hON-k2-Efa" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1959" y="295"/>
|
||||
<point key="canvasLocation" x="1530.46875" y="172.8515625"/>
|
||||
</scene>
|
||||
<!--Loading Frame View Controller-->
|
||||
<scene sceneID="lcG-48-utf">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="ZNo-L5-uxh" customClass="LoadingFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="cVC-VG-qBz"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="YZj-An-sqS"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="le1-tU-NEp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1194" height="834"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" id="N0D-dj-EuF">
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="N0D-dj-EuF">
|
||||
<rect key="frame" x="494" y="365" width="37" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
@@ -340,10 +344,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="lJG-tq-Jrs" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1959" y="1425"/>
|
||||
<point key="canvasLocation" x="1530.46875" y="834.9609375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Logo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES" initialViewController="DL0-L5-LOv">
|
||||
<device id="retina4_7" orientation="landscape">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="DL0-L5-LOv">
|
||||
<device id="retina6_1" orientation="landscape" appearance="dark"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<customFonts key="customFonts">
|
||||
<array key="Roboto-Regular.ttf">
|
||||
<string>Roboto-Regular</string>
|
||||
</array>
|
||||
</customFonts>
|
||||
<scenes>
|
||||
<!--Main Frame View Controller-->
|
||||
<scene sceneID="emz-kO-L7q">
|
||||
<objects>
|
||||
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="Rtu-AT-Alw" customClass="AppCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="343"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="370"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.3333333432674408" green="0.3333333432674408" blue="0.3333333432674408" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK">
|
||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="15" minimumInteritemSpacing="15" id="YcZ-cR-3tK">
|
||||
<size key="itemSize" width="90" height="120"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
@@ -45,38 +37,30 @@
|
||||
</connections>
|
||||
</collectionView>
|
||||
<toolbarItems/>
|
||||
<navigationItem key="navigationItem" id="1jn-Sf-Xky">
|
||||
<barButtonItem key="leftBarButtonItem" style="done" id="zAn-CM-7Yz">
|
||||
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="pZ9-ft-T24">
|
||||
<rect key="frame" x="20" y="0.0" width="109" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
||||
<state key="normal" title="Moonlight" image="Logo">
|
||||
<color key="titleColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</state>
|
||||
</button>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="L1H-n4-HB7">
|
||||
<color key="tintColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</barButtonItem>
|
||||
<navigationItem key="navigationItem" id="pSu-bl-gL9">
|
||||
<barButtonItem key="leftBarButtonItem" title="Settings" id="mSL-ru-nRm"/>
|
||||
<barButtonItem key="rightBarButtonItem" id="KDy-JC-2sU"/>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="computerNameButton" destination="L1H-n4-HB7" id="bng-Ky-oQs"/>
|
||||
<outlet property="limelightLogoButton" destination="pZ9-ft-T24" id="yRw-rK-9lQ"/>
|
||||
<segue destination="mI3-9F-XwU" kind="push" identifier="createStreamFrame" id="Vgc-B6-lvM"/>
|
||||
<outlet property="settingsButton" destination="mSL-ru-nRm" id="NRf-lv-vlh"/>
|
||||
<outlet property="upButton" destination="KDy-JC-2sU" id="tXB-Rc-IvJ"/>
|
||||
<segue destination="mI3-9F-XwU" kind="push" identifier="createStreamFrame" id="NuQ-Ez-IEX"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="HNf-lX-GEO" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1362.5" y="795.5"/>
|
||||
<point key="canvasLocation" x="1974.6376811594205" y="532.70089285714289"/>
|
||||
</scene>
|
||||
<!--Reveal View Controller-->
|
||||
<scene sceneID="QYt-XN-Ojr">
|
||||
<objects>
|
||||
<viewController id="DL0-L5-LOv" customClass="SWRevealViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="r4Q-3y-YAU"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="iBq-4E-Dbr"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Usg-e0-g4a">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
@@ -87,41 +71,47 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RXm-iV-Zqb" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-66" y="796"/>
|
||||
<point key="canvasLocation" x="-95.652173913043484" y="533.03571428571422"/>
|
||||
</scene>
|
||||
<!--Side Bar-->
|
||||
<scene sceneID="uYM-56-Ivb">
|
||||
<objects>
|
||||
<viewController id="rYd-e6-cQU" userLabel="Side Bar" customClass="SettingsViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="TeT-8j-xwM"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="HaZ-6S-ZpN"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="iNk-qF-gIr" customClass="UIScrollView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8zy-ri-Dqc">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8zy-ri-Dqc">
|
||||
<rect key="frame" x="16" y="20" width="82" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="PCM-t4-Sha">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="PCM-t4-Sha">
|
||||
<rect key="frame" x="16" y="49" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="360p"/>
|
||||
<segment title="720p"/>
|
||||
<segment title="1080p"/>
|
||||
<segment title="4K"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Frame Rate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Kkv-DF-MAl">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Frame Rate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Kkv-DF-MAl">
|
||||
<rect key="frame" x="16" y="85" width="88" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="dLF-qJ-2nY">
|
||||
<rect key="frame" x="16" y="114" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
@@ -130,27 +120,28 @@
|
||||
<segment title="120 FPS"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SBv-Wn-LB7">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SBv-Wn-LB7">
|
||||
<rect key="frame" x="16" y="150" width="151" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<slider opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="3nn-MI-9Xu">
|
||||
<slider opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="3nn-MI-9Xu">
|
||||
<rect key="frame" x="14" y="179" width="204" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HZT-dd-DuQ">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HZT-dd-DuQ">
|
||||
<rect key="frame" x="16" y="217" width="153" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.9513210654258728" green="0.97490358352661133" blue="0.99987185001373291" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="WGf-9d-eAm">
|
||||
<rect key="frame" x="16" y="246" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
@@ -160,70 +151,75 @@
|
||||
<segment title="Full"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Optimize Game Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hxa-gT-JXC">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Optimize Game Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hxa-gT-JXC">
|
||||
<rect key="frame" x="16" y="282" width="186" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="Gob-Lu-b1y" userLabel="Optimize Settings Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="Gob-Lu-b1y" userLabel="Optimize Settings Selector">
|
||||
<rect key="frame" x="16" y="311" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Multi-Controller Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Jps-kj-bYJ">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Multi-Controller Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jps-kj-bYJ">
|
||||
<rect key="frame" x="16" y="347" width="169" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="OCT-oL-Dqb" userLabel="MC Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="OCT-oL-Dqb" userLabel="MC Selector">
|
||||
<rect key="frame" x="16" y="376" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="Single"/>
|
||||
<segment title="Auto"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Play Audio on PC" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="T6M-nz-TW0">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Play Audio on PC" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="T6M-nz-TW0">
|
||||
<rect key="frame" x="16" y="412" width="131" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="8GA-Js-kQN" userLabel="PC Audio Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="8GA-Js-kQN" userLabel="PC Audio Selector">
|
||||
<rect key="frame" x="16" y="441" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="HEVC Video" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="BEG-Id-J8y">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="HEVC Video" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BEG-Id-J8y">
|
||||
<rect key="frame" x="16" y="477" width="93" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.93902439019999995" green="0.9625305918" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="AbS-CW-fjP" userLabel="HEVC Selector">
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="AbS-CW-fjP" userLabel="HEVC Selector">
|
||||
<rect key="frame" x="16" y="506" width="200" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="No"/>
|
||||
<segment title="Yes"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.6716768742" green="0.61711704730000005" blue="0.99902987480000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="tintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="selectedSegmentTintColor" red="0.6716768741607666" green="0.61711704730987549" blue="0.99902987480163574" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -243,14 +239,14 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RWc-Km-KG5" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1362.5" y="1265.5"/>
|
||||
<point key="canvasLocation" x="1974" y="1487"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="pfX-8A-htT">
|
||||
<objects>
|
||||
<navigationController id="ftZ-kC-fxI" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="0ZA-Ec-QgD">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="32"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="barTintColor" red="0.66666668653488159" green="0.66666668653488159" blue="0.66666668653488159" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<textAttributes key="titleTextAttributes">
|
||||
@@ -263,28 +259,32 @@
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Dr2-S8-dHh" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="660" y="796"/>
|
||||
<point key="canvasLocation" x="956.52173913043487" y="533.03571428571422"/>
|
||||
</scene>
|
||||
<!--Stream Frame View Controller-->
|
||||
<scene sceneID="5Eb-q2-vjt">
|
||||
<objects>
|
||||
<viewController id="mI3-9F-XwU" customClass="StreamFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="JIX-qR-Sh3"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="ody-Fj-H4p"/>
|
||||
</layoutGuides>
|
||||
<view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="eir-e9-IPE" customClass="StreamView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2HK-Z5-4Ch">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Stage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2HK-Z5-4Ch">
|
||||
<rect key="frame" x="262" y="149" width="45" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" id="0vm-Iv-K4b">
|
||||
<rect key="frame" x="324" y="143" width="20" height="20"/>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="0vm-Iv-K4b">
|
||||
<rect key="frame" x="439" y="159" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<textField hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" id="r45-6t-nxS">
|
||||
<textField hidden="YES" opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="r45-6t-nxS">
|
||||
<rect key="frame" x="406" y="293" width="97" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -293,7 +293,7 @@
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardAppearance="alert" smartDashesType="no" smartInsertDeleteType="no" smartQuotesType="no"/>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tip Text" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QwC-QD-dae" userLabel="Tip Label">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Tip Text" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QwC-QD-dae" userLabel="Tip Label">
|
||||
<rect key="frame" x="304" y="334" width="61" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
@@ -318,18 +318,23 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="pqv-jd-33O" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2092" y="796"/>
|
||||
<point key="canvasLocation" x="3031.884057971015" y="533.03571428571422"/>
|
||||
</scene>
|
||||
<!--Loading Frame View Controller-->
|
||||
<scene sceneID="kPF-XD-S77">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="9W0-2D-0Kp" customClass="LoadingFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="VID-dc-yvh"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="hby-2y-jAk"/>
|
||||
</layoutGuides>
|
||||
<view key="view" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="center" id="nSw-dc-mi4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
|
||||
<rect key="frame" x="266" y="168" width="37" height="37"/>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
|
||||
<rect key="frame" x="266" y="187" width="37" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -340,10 +345,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="GaV-PK-JSI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2104" y="1266"/>
|
||||
<point key="canvasLocation" x="3031" y="1487"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Logo" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -365,10 +365,11 @@
|
||||
};
|
||||
buildConfigurationList = FB290E2919B37A4E004C83CF /* Build configuration list for PBXProject "moonlight-common" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = FB290E2519B37A4E004C83CF;
|
||||
productRefGroup = FB290E2F19B37A4E004C83CF /* Products */;
|
||||
@@ -543,7 +544,7 @@
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = NO;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@@ -562,7 +563,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
@@ -600,7 +601,7 @@
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = NO;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
@@ -612,7 +613,7 @@
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
|
||||