Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5584083809 | ||
|
|
9f9aec70b0 | ||
|
|
a8d1770871 | ||
|
|
d0d60b8ffc | ||
|
|
86f7112789 | ||
|
|
da1115e529 | ||
|
|
593da7ef3e | ||
|
|
de5377a95d | ||
|
|
7d7500b187 | ||
|
|
45dbd46da1 | ||
|
|
89d8bc6009 | ||
|
|
b99988836a | ||
|
|
3e94613eb3 | ||
|
|
832b9189f8 | ||
|
|
3464539bd3 | ||
|
|
815592117d | ||
|
|
b51341ef54 | ||
|
|
9ffbb5f155 | ||
|
|
9716867ade | ||
|
|
7c141c1fd2 | ||
|
|
42c4e7ca58 | ||
|
|
6a6ea4a79a | ||
|
|
5d0ca8451d | ||
|
|
4641f68eb8 | ||
|
|
dd33f57b9a | ||
|
|
f6b225ca9c | ||
|
|
4ac3f11ff8 | ||
|
|
62aaf27293 |
No files matched your search
@@ -28,8 +28,8 @@
|
|||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
||||||
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
||||||
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenDisabled="NO" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
||||||
<rect key="frame" x="-23" y="-15" width="46" height="30"/>
|
<rect key="frame" x="20" y="-1" width="109" height="46"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<animations/>
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||||
|
|||||||
@@ -19,7 +19,17 @@
|
|||||||
- (id) init {
|
- (id) init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
_appDelegate = [[UIApplication sharedApplication] delegate];
|
// HACK: Avoid calling [UIApplication delegate] off the UI thread to keep
|
||||||
|
// Main Thread Checker happy.
|
||||||
|
if ([NSThread isMainThread]) {
|
||||||
|
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
|
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
|
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 32 KiB |
@@ -1,82 +1,108 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_settings_58x58_@2x-1.png",
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_settings_87x87_@3x.png",
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_spotlight_80x80_@2x-1.png",
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_spotlight_120x120_@3x.png",
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_120x120_@2x.png",
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "app_icon_180x180_@3x.png",
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"size" : "20x20",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_settings_29x29_@1x.png",
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_settings_58x58_@2x.png",
|
"filename" : "Icon-App-29x29@2x-1.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_spotlight_40x40_@1x.png",
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_spotlight_80x80_@2x.png",
|
"filename" : "Icon-App-40x40@2x-1.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_76x76_@1x.png",
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_152x152_@2x.png",
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "83.5x83.5",
|
"size" : "83.5x83.5",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "app_icon_167x167_@2x.png",
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "1024x icon.png",
|
||||||
|
"scale" : "1x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 41 KiB |
@@ -6,8 +6,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "logo.png",
|
||||||
"filename" : "logo_universal.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
|
|||||||
|
After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 36 KiB |
@@ -146,7 +146,8 @@
|
|||||||
{
|
{
|
||||||
[_controllerStreamLock lock];
|
[_controllerStreamLock lock];
|
||||||
@synchronized(controller) {
|
@synchronized(controller) {
|
||||||
LiSendMultiControllerEvent(controller.playerIndex, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY);
|
// Player 1 is always present for OSC
|
||||||
|
LiSendMultiControllerEvent(controller.playerIndex, _controllerNumbers | 1, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY);
|
||||||
}
|
}
|
||||||
[_controllerStreamLock unlock];
|
[_controllerStreamLock unlock];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#import "ControllerSupport.h"
|
#import "ControllerSupport.h"
|
||||||
|
|
||||||
@implementation StreamView {
|
@implementation StreamView {
|
||||||
CGPoint touchLocation;
|
CGPoint touchLocation, originalLocation;
|
||||||
BOOL touchMoved;
|
BOOL touchMoved;
|
||||||
OnScreenControls* onScreenControls;
|
OnScreenControls* onScreenControls;
|
||||||
|
|
||||||
@@ -46,11 +46,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (Boolean)isConfirmedMove:(CGPoint)currentPoint from:(CGPoint)originalPoint {
|
||||||
|
// Movements of greater than 20 pixels are considered confirmed
|
||||||
|
return hypotf(originalPoint.x - currentPoint.x, originalPoint.y - currentPoint.y) >= 20;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||||
Log(LOG_D, @"Touch down");
|
Log(LOG_D, @"Touch down");
|
||||||
if (![onScreenControls handleTouchDownEvent:touches]) {
|
if (![onScreenControls handleTouchDownEvent:touches]) {
|
||||||
UITouch *touch = [[event allTouches] anyObject];
|
UITouch *touch = [[event allTouches] anyObject];
|
||||||
touchLocation = [touch locationInView:self];
|
originalLocation = touchLocation = [touch locationInView:self];
|
||||||
touchMoved = false;
|
touchMoved = false;
|
||||||
if ([[event allTouches] count] == 1 && !isDragging) {
|
if ([[event allTouches] count] == 1 && !isDragging) {
|
||||||
dragTimer = [NSTimer scheduledTimerWithTimeInterval:0.650
|
dragTimer = [NSTimer scheduledTimerWithTimeInterval:0.650
|
||||||
@@ -88,8 +93,13 @@
|
|||||||
|
|
||||||
if (deltaX != 0 || deltaY != 0) {
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||||
touchMoved = true;
|
|
||||||
touchLocation = currentLocation;
|
touchLocation = currentLocation;
|
||||||
|
|
||||||
|
// If we've moved far enough to confirm this wasn't just human/machine error,
|
||||||
|
// mark it as such.
|
||||||
|
if ([self isConfirmedMove:touchLocation from:originalLocation]) {
|
||||||
|
touchMoved = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ([[event allTouches] count] == 2) {
|
} else if ([[event allTouches] count] == 2) {
|
||||||
@@ -100,7 +110,13 @@
|
|||||||
if (touchLocation.y != avgLocation.y) {
|
if (touchLocation.y != avgLocation.y) {
|
||||||
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
||||||
}
|
}
|
||||||
touchMoved = true;
|
|
||||||
|
// If we've moved far enough to confirm this wasn't just human/machine error,
|
||||||
|
// mark it as such.
|
||||||
|
if ([self isConfirmedMove:firstLocation from:originalLocation]) {
|
||||||
|
touchMoved = true;
|
||||||
|
}
|
||||||
|
|
||||||
touchLocation = avgLocation;
|
touchLocation = avgLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,6 +155,20 @@
|
|||||||
isDragging = false;
|
isDragging = false;
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We we're moving from 2+ touches to 1. Synchronize the current position
|
||||||
|
// of the active finger so we don't jump unexpectedly on the next touchesMoved
|
||||||
|
// callback when finger 1 switches on us.
|
||||||
|
if ([[event allTouches] count] - [touches count] == 1) {
|
||||||
|
NSMutableSet *activeSet = [[NSMutableSet alloc] initWithCapacity:[[event allTouches] count]];
|
||||||
|
[activeSet unionSet:[event allTouches]];
|
||||||
|
[activeSet minusSet:touches];
|
||||||
|
touchLocation = [[activeSet anyObject] locationInView:self];
|
||||||
|
|
||||||
|
// Mark this touch as moved so we don't send a left mouse click if the user
|
||||||
|
// right clicks without moving their other finger.
|
||||||
|
touchMoved = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.1.4</string>
|
<string>1.4.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>2</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
|||||||
@@ -102,10 +102,29 @@
|
|||||||
TemporaryHost *existingHost = [self getHostInDiscovery:host.uuid];
|
TemporaryHost *existingHost = [self getHostInDiscovery:host.uuid];
|
||||||
if (existingHost != nil) {
|
if (existingHost != nil) {
|
||||||
// Update address of existing host
|
// Update address of existing host
|
||||||
existingHost.address = existingHost.activeAddress = host.address;
|
if (host.address != nil) {
|
||||||
|
existingHost.address = host.address;
|
||||||
|
}
|
||||||
|
if (host.localAddress != nil) {
|
||||||
|
existingHost.localAddress = host.localAddress;
|
||||||
|
}
|
||||||
|
if (host.externalAddress != nil) {
|
||||||
|
existingHost.externalAddress = host.externalAddress;
|
||||||
|
}
|
||||||
|
existingHost.activeAddress = host.activeAddress;
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
else {
|
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];
|
[_hostQueue addObject:host];
|
||||||
if (shouldDiscover) {
|
if (shouldDiscover) {
|
||||||
[_opQueue addOperation:[self createWorkerForHost:host]];
|
[_opQueue addOperation:[self createWorkerForHost:host]];
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
for (NSNetService* service in services) {
|
for (NSNetService* service in services) {
|
||||||
if (service.hostName != nil) {
|
if (service.hostName != nil) {
|
||||||
TemporaryHost* host = [[TemporaryHost alloc] init];
|
TemporaryHost* host = [[TemporaryHost alloc] init];
|
||||||
host.activeAddress = host.address = service.hostName;
|
host.activeAddress = host.localAddress = service.hostName;
|
||||||
host.name = host.address;
|
host.name = service.hostName;
|
||||||
[hosts addObject:host];
|
[hosts addObject:host];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#import <AudioUnit/AudioUnit.h>
|
#import <AudioUnit/AudioUnit.h>
|
||||||
#import <AVFoundation/AVFoundation.h>
|
#import <AVFoundation/AVFoundation.h>
|
||||||
|
#import <VideoToolbox/VideoToolbox.h>
|
||||||
|
|
||||||
#include "Limelight.h"
|
#include "Limelight.h"
|
||||||
#include "opus.h"
|
#include "opus.h"
|
||||||
@@ -45,6 +46,12 @@ static int audioBufferQueueLength;
|
|||||||
static AudioComponentInstance audioUnit;
|
static AudioComponentInstance audioUnit;
|
||||||
static VideoDecoderRenderer* renderer;
|
static VideoDecoderRenderer* renderer;
|
||||||
|
|
||||||
|
int DrDecoderSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags)
|
||||||
|
{
|
||||||
|
[renderer setupWithVideoFormat:videoFormat];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
@@ -65,7 +72,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
|||||||
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
int ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int flags)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -101,6 +108,7 @@ void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
|||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to instantiate new AudioComponent: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to instantiate new AudioComponent: %d", (int32_t)status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamBasicDescription audioFormat = {0};
|
AudioStreamBasicDescription audioFormat = {0};
|
||||||
@@ -122,6 +130,7 @@ void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
|||||||
sizeof(audioFormat));
|
sizeof(audioFormat));
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to set audio unit to input: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to set audio unit to input: %d", (int32_t)status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
AURenderCallbackStruct callbackStruct = {0};
|
AURenderCallbackStruct callbackStruct = {0};
|
||||||
@@ -136,17 +145,22 @@ void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
|||||||
sizeof(callbackStruct));
|
sizeof(callbackStruct));
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to set audio unit callback: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to set audio unit callback: %d", (int32_t)status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = AudioUnitInitialize(audioUnit);
|
status = AudioUnitInitialize(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = AudioOutputUnitStart(audioUnit);
|
status = AudioOutputUnitStart(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArCleanup(void)
|
void ArCleanup(void)
|
||||||
@@ -261,6 +275,14 @@ void ClDisplayTransientMessage(const char* message)
|
|||||||
[_callbacks displayTransientMessage: message];
|
[_callbacks displayTransientMessage: message];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClLogMessage(const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
vfprintf(stderr, format, va);
|
||||||
|
va_end(va);
|
||||||
|
}
|
||||||
|
|
||||||
-(void) terminate
|
-(void) terminate
|
||||||
{
|
{
|
||||||
// We dispatch this async to get out because this can be invoked
|
// We dispatch this async to get out because this can be invoked
|
||||||
@@ -299,6 +321,12 @@ void ClDisplayTransientMessage(const char* message)
|
|||||||
_streamConfig.fps = config.frameRate;
|
_streamConfig.fps = config.frameRate;
|
||||||
_streamConfig.bitrate = config.bitRate;
|
_streamConfig.bitrate = config.bitRate;
|
||||||
|
|
||||||
|
// On iOS 11, we can use HEVC if the server supports encoding it
|
||||||
|
// and this device has hardware decode for it (A9 and later)
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
_streamConfig.supportsHevc = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: We should use 1024 when streaming remotely
|
// FIXME: We should use 1024 when streaming remotely
|
||||||
_streamConfig.packetSize = 1292;
|
_streamConfig.packetSize = 1292;
|
||||||
|
|
||||||
@@ -308,8 +336,12 @@ void ClDisplayTransientMessage(const char* message)
|
|||||||
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
||||||
|
|
||||||
LiInitializeVideoCallbacks(&_drCallbacks);
|
LiInitializeVideoCallbacks(&_drCallbacks);
|
||||||
|
_drCallbacks.setup = DrDecoderSetup;
|
||||||
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
||||||
|
|
||||||
|
// RFI doesn't work properly with HEVC on iOS 11 with an iPhone SE (at least)
|
||||||
|
_drCallbacks.capabilities = CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC;
|
||||||
|
|
||||||
LiInitializeAudioCallbacks(&_arCallbacks);
|
LiInitializeAudioCallbacks(&_arCallbacks);
|
||||||
_arCallbacks.init = ArInit;
|
_arCallbacks.init = ArInit;
|
||||||
_arCallbacks.cleanup = ArCleanup;
|
_arCallbacks.cleanup = ArCleanup;
|
||||||
@@ -323,6 +355,7 @@ void ClDisplayTransientMessage(const char* message)
|
|||||||
_clCallbacks.connectionTerminated = ClConnectionTerminated;
|
_clCallbacks.connectionTerminated = ClConnectionTerminated;
|
||||||
_clCallbacks.displayMessage = ClDisplayMessage;
|
_clCallbacks.displayMessage = ClDisplayMessage;
|
||||||
_clCallbacks.displayTransientMessage = ClDisplayTransientMessage;
|
_clCallbacks.displayTransientMessage = ClDisplayTransientMessage;
|
||||||
|
_clCallbacks.logMessage = ClLogMessage;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -416,6 +449,7 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||||||
&_clCallbacks,
|
&_clCallbacks,
|
||||||
&_drCallbacks,
|
&_drCallbacks,
|
||||||
&_arCallbacks,
|
&_arCallbacks,
|
||||||
|
NULL, 0,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
[initLock unlock];
|
[initLock unlock];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
- (id)initWithView:(UIView*)view;
|
- (id)initWithView:(UIView*)view;
|
||||||
|
|
||||||
|
- (void)setupWithVideoFormat:(int)videoFormat;
|
||||||
|
|
||||||
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength;
|
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength;
|
||||||
|
|
||||||
- (int)submitDecodeBuffer:(unsigned char *)data length:(int)length;
|
- (int)submitDecodeBuffer:(unsigned char *)data length:(int)length;
|
||||||
|
|||||||
@@ -14,9 +14,10 @@
|
|||||||
UIView *_view;
|
UIView *_view;
|
||||||
|
|
||||||
AVSampleBufferDisplayLayer* displayLayer;
|
AVSampleBufferDisplayLayer* displayLayer;
|
||||||
Boolean waitingForSps, waitingForPps;
|
Boolean waitingForSps, waitingForPps, waitingForVps;
|
||||||
|
int videoFormat;
|
||||||
|
|
||||||
NSData *spsData, *ppsData;
|
NSData *spsData, *ppsData, *vpsData;
|
||||||
CMVideoFormatDescriptionRef formatDesc;
|
CMVideoFormatDescriptionRef formatDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +44,8 @@
|
|||||||
spsData = nil;
|
spsData = nil;
|
||||||
waitingForPps = true;
|
waitingForPps = true;
|
||||||
ppsData = nil;
|
ppsData = nil;
|
||||||
|
waitingForVps = true;
|
||||||
|
vpsData = nil;
|
||||||
|
|
||||||
if (formatDesc != nil) {
|
if (formatDesc != nil) {
|
||||||
CFRelease(formatDesc);
|
CFRelease(formatDesc);
|
||||||
@@ -61,11 +64,65 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setupWithVideoFormat:(int)videoFormat
|
||||||
|
{
|
||||||
|
self->videoFormat = videoFormat;
|
||||||
|
}
|
||||||
|
|
||||||
#define FRAME_START_PREFIX_SIZE 4
|
#define FRAME_START_PREFIX_SIZE 4
|
||||||
#define NALU_START_PREFIX_SIZE 3
|
#define NALU_START_PREFIX_SIZE 3
|
||||||
#define NAL_LENGTH_PREFIX_SIZE 4
|
#define NAL_LENGTH_PREFIX_SIZE 4
|
||||||
#define NAL_TYPE_SPS 0x7
|
#define AVC_NAL_TYPE_SPS 0x67
|
||||||
#define NAL_TYPE_PPS 0x8
|
#define AVC_NAL_TYPE_PPS 0x68
|
||||||
|
#define HEVC_NAL_TYPE_VPS 0x40
|
||||||
|
#define HEVC_NAL_TYPE_SPS 0x42
|
||||||
|
#define HEVC_NAL_TYPE_PPS 0x44
|
||||||
|
|
||||||
|
#define IS_NAL_SPS(x) ((videoFormat == VIDEO_FORMAT_H264) ? ((x) == AVC_NAL_TYPE_SPS) : ((x) == HEVC_NAL_TYPE_SPS))
|
||||||
|
#define IS_NAL_PPS(x) ((videoFormat == VIDEO_FORMAT_H264) ? ((x) == AVC_NAL_TYPE_PPS) : ((x) == HEVC_NAL_TYPE_PPS))
|
||||||
|
#define IS_NAL_VPS(x) ((videoFormat == VIDEO_FORMAT_H265) && ((x) == HEVC_NAL_TYPE_VPS))
|
||||||
|
|
||||||
|
- (Boolean)readyForPictureData
|
||||||
|
{
|
||||||
|
if (videoFormat == VIDEO_FORMAT_H264) {
|
||||||
|
return !waitingForSps && !waitingForPps;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// H.265 requires VPS in addition to SPS and PPS
|
||||||
|
return !waitingForVps && !waitingForSps && !waitingForPps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Boolean)isNalReferencePicture:(unsigned char)nalType
|
||||||
|
{
|
||||||
|
if (videoFormat == VIDEO_FORMAT_H264) {
|
||||||
|
return nalType == 0x65;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// HEVC has several types of reference NALU types
|
||||||
|
switch (nalType) {
|
||||||
|
case 0x20:
|
||||||
|
case 0x22:
|
||||||
|
case 0x24:
|
||||||
|
case 0x26:
|
||||||
|
case 0x28:
|
||||||
|
case 0x2A:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Boolean)isNalPictureData:(unsigned char)nalType
|
||||||
|
{
|
||||||
|
if (videoFormat == VIDEO_FORMAT_H264) {
|
||||||
|
return !(nalType == AVC_NAL_TYPE_SPS || nalType == AVC_NAL_TYPE_PPS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return !(nalType == HEVC_NAL_TYPE_VPS || nalType == HEVC_NAL_TYPE_SPS || nalType == HEVC_NAL_TYPE_PPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength
|
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength
|
||||||
{
|
{
|
||||||
@@ -136,7 +193,7 @@
|
|||||||
// This function must free data
|
// This function must free data
|
||||||
- (int)submitDecodeBuffer:(unsigned char *)data length:(int)length
|
- (int)submitDecodeBuffer:(unsigned char *)data length:(int)length
|
||||||
{
|
{
|
||||||
unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F;
|
unsigned char nalType = data[FRAME_START_PREFIX_SIZE];
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
|
|
||||||
// Check for previous decoder errors before doing anything
|
// Check for previous decoder errors before doing anything
|
||||||
@@ -150,35 +207,69 @@
|
|||||||
return DR_NEED_IDR;
|
return DR_NEED_IDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) {
|
if (![self isNalPictureData:nalType]) {
|
||||||
if (nalType == NAL_TYPE_SPS) {
|
if (IS_NAL_VPS(nalType)) {
|
||||||
|
Log(LOG_I, @"Got VPS");
|
||||||
|
vpsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
||||||
|
waitingForVps = false;
|
||||||
|
|
||||||
|
// We got a new VPS so wait for a new SPS to match it
|
||||||
|
waitingForSps = true;
|
||||||
|
}
|
||||||
|
else if (IS_NAL_SPS(nalType)) {
|
||||||
Log(LOG_I, @"Got SPS");
|
Log(LOG_I, @"Got SPS");
|
||||||
spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
spsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
||||||
waitingForSps = false;
|
waitingForSps = false;
|
||||||
|
|
||||||
// We got a new SPS so wait for a new PPS to match it
|
// We got a new SPS so wait for a new PPS to match it
|
||||||
waitingForPps = true;
|
waitingForPps = true;
|
||||||
} else if (nalType == NAL_TYPE_PPS) {
|
} else if (IS_NAL_PPS(nalType)) {
|
||||||
Log(LOG_I, @"Got PPS");
|
Log(LOG_I, @"Got PPS");
|
||||||
ppsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
ppsData = [NSData dataWithBytes:&data[FRAME_START_PREFIX_SIZE] length:length - FRAME_START_PREFIX_SIZE];
|
||||||
waitingForPps = false;
|
waitingForPps = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we've got all the parameter sets we need
|
// See if we've got all the parameter sets we need for our video format
|
||||||
if (!waitingForSps && !waitingForPps) {
|
if ([self readyForPictureData]) {
|
||||||
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
|
if (videoFormat == VIDEO_FORMAT_H264) {
|
||||||
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
|
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
|
||||||
|
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
|
||||||
Log(LOG_I, @"Constructing new format description");
|
|
||||||
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
Log(LOG_I, @"Constructing new H264 format description");
|
||||||
2, /* count of parameter sets */
|
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
||||||
parameterSetPointers,
|
2, /* count of parameter sets */
|
||||||
parameterSetSizes,
|
parameterSetPointers,
|
||||||
NAL_LENGTH_PREFIX_SIZE,
|
parameterSetSizes,
|
||||||
&formatDesc);
|
NAL_LENGTH_PREFIX_SIZE,
|
||||||
if (status != noErr) {
|
&formatDesc);
|
||||||
Log(LOG_E, @"Failed to create format description: %d", (int)status);
|
if (status != noErr) {
|
||||||
formatDesc = NULL;
|
Log(LOG_E, @"Failed to create H264 format description: %d", (int)status);
|
||||||
|
formatDesc = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint8_t* const parameterSetPointers[] = { [vpsData bytes], [spsData bytes], [ppsData bytes] };
|
||||||
|
const size_t parameterSetSizes[] = { [vpsData length], [spsData length], [ppsData length] };
|
||||||
|
|
||||||
|
Log(LOG_I, @"Constructing new HEVC format description");
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(kCFAllocatorDefault,
|
||||||
|
3, /* count of parameter sets */
|
||||||
|
parameterSetPointers,
|
||||||
|
parameterSetSizes,
|
||||||
|
NAL_LENGTH_PREFIX_SIZE,
|
||||||
|
nil,
|
||||||
|
&formatDesc);
|
||||||
|
} else {
|
||||||
|
// This means Moonlight-common-c decided to give us an HEVC stream
|
||||||
|
// even though we said we couldn't support it. All we can do is abort().
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != noErr) {
|
||||||
|
Log(LOG_E, @"Failed to create HEVC format description: %d", (int)status);
|
||||||
|
formatDesc = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,12 +286,6 @@
|
|||||||
return DR_OK;
|
return DR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nalType != 0x1 && nalType != 0x5) {
|
|
||||||
// Don't submit parameter set data
|
|
||||||
free(data);
|
|
||||||
return DR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we're decoding actual frame data here
|
// Now we're decoding actual frame data here
|
||||||
CMBlockBufferRef blockBuffer;
|
CMBlockBufferRef blockBuffer;
|
||||||
|
|
||||||
@@ -252,7 +337,7 @@
|
|||||||
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
|
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
|
||||||
CFDictionarySetValue(dict, kCMSampleAttachmentKey_IsDependedOnByOthers, kCFBooleanTrue);
|
CFDictionarySetValue(dict, kCMSampleAttachmentKey_IsDependedOnByOthers, kCFBooleanTrue);
|
||||||
|
|
||||||
if (nalType == 1) {
|
if (![self isNalReferencePicture:nalType]) {
|
||||||
// P-frame
|
// P-frame
|
||||||
CFDictionarySetValue(dict, kCMSampleAttachmentKey_NotSync, kCFBooleanTrue);
|
CFDictionarySetValue(dict, kCMSampleAttachmentKey_NotSync, kCFBooleanTrue);
|
||||||
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DependsOnOthers, kCFBooleanTrue);
|
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DependsOnOthers, kCFBooleanTrue);
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ static NSMutableSet* hostList;
|
|||||||
message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
|
message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) {
|
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) {
|
||||||
|
_pairAlert = nil;
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
[self hideLoadingFrame];
|
[self hideLoadingFrame];
|
||||||
}]];
|
}]];
|
||||||
@@ -56,24 +57,36 @@ static NSMutableSet* hostList;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)displayFailureDialog:(NSString *)message {
|
||||||
|
UIAlertController* failedDialog = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
|
||||||
|
message:message
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[failedDialog addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:failedDialog animated:YES completion:nil];
|
||||||
|
|
||||||
|
[_discMan startDiscovery];
|
||||||
|
[self hideLoadingFrame];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)pairFailed:(NSString *)message {
|
- (void)pairFailed:(NSString *)message {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[_pairAlert dismissViewControllerAnimated:YES completion:^{
|
if (_pairAlert != nil) {
|
||||||
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
|
[_pairAlert dismissViewControllerAnimated:YES completion:^{
|
||||||
message:message
|
[self displayFailureDialog:message];
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
}];
|
||||||
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
_pairAlert = nil;
|
||||||
[self presentViewController:_pairAlert animated:YES completion:nil];
|
}
|
||||||
|
else {
|
||||||
[_discMan startDiscovery];
|
[self displayFailureDialog:message];
|
||||||
[self hideLoadingFrame];
|
}
|
||||||
}];
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pairSuccessful {
|
- (void)pairSuccessful {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[_pairAlert dismissViewControllerAnimated:YES completion:nil];
|
[_pairAlert dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
_pairAlert = nil;
|
||||||
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
[self alreadyPaired];
|
[self alreadyPaired];
|
||||||
});
|
});
|
||||||
@@ -259,8 +272,10 @@ static NSMutableSet* hostList;
|
|||||||
|
|
||||||
// If we are online, paired, and have a cached app list, skip straight
|
// If we are online, paired, and have a cached app list, skip straight
|
||||||
// to the app grid without a loading frame. This is the fast path that users
|
// to the app grid without a loading frame. This is the fast path that users
|
||||||
// should hit most.
|
// should hit most. Check for a valid view because we don't want to hit the fast
|
||||||
if (host.online && host.pairState == PairStatePaired && host.appList.count > 0) {
|
// 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) {
|
||||||
[self alreadyPaired];
|
[self alreadyPaired];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -595,6 +610,9 @@ static NSMutableSet* hostList;
|
|||||||
- (void)viewDidAppear:(BOOL)animated
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
{
|
{
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
|
[[self revealViewController] setPrimaryViewController:self];
|
||||||
|
|
||||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||||
|
|
||||||
// Hide 1px border line
|
// Hide 1px border line
|
||||||
|
|||||||
@@ -180,6 +180,8 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType)
|
|||||||
|
|
||||||
@interface SWRevealViewController : UIViewController
|
@interface SWRevealViewController : UIViewController
|
||||||
|
|
||||||
|
- (void)setPrimaryViewController:(UIViewController*)viewController;
|
||||||
|
|
||||||
/* Basic API */
|
/* Basic API */
|
||||||
|
|
||||||
// Object instance init and rear view setting
|
// Object instance init and rear view setting
|
||||||
|
|||||||
@@ -583,6 +583,7 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1
|
|||||||
FrontViewPosition _panInitialFrontPosition;
|
FrontViewPosition _panInitialFrontPosition;
|
||||||
NSMutableArray *_animationQueue;
|
NSMutableArray *_animationQueue;
|
||||||
BOOL _userInteractionStore;
|
BOOL _userInteractionStore;
|
||||||
|
UIViewController *_primaryViewController;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int FrontViewPositionNone = 0xff;
|
const int FrontViewPositionNone = 0xff;
|
||||||
@@ -1364,6 +1365,26 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
_enqueue( [theSelf _performTransitionOperation:operation withViewController:newViewController animated:animated] );
|
_enqueue( [theSelf _performTransitionOperation:operation withViewController:newViewController animated:animated] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setPrimaryViewController:(UIViewController*)viewController
|
||||||
|
{
|
||||||
|
_primaryViewController = viewController;
|
||||||
|
|
||||||
|
// These are derived from the primary view controller
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||||
|
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIViewController*)childViewControllerForHomeIndicatorAutoHidden
|
||||||
|
{
|
||||||
|
return _primaryViewController;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIViewController*)childViewControllerForScreenEdgesDeferringSystemGestures
|
||||||
|
{
|
||||||
|
return _primaryViewController;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Animated view controller deployment and layout
|
#pragma mark Animated view controller deployment and layout
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,30 @@
|
|||||||
|
|
||||||
@implementation SettingsViewController {
|
@implementation SettingsViewController {
|
||||||
NSInteger _bitrate;
|
NSInteger _bitrate;
|
||||||
|
Boolean _adjustedForSafeArea;
|
||||||
}
|
}
|
||||||
static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_adjustedForSafeArea = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|||||||
@@ -21,6 +21,13 @@
|
|||||||
StreamManager *_streamMan;
|
StreamManager *_streamMan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
{
|
||||||
|
[super viewDidAppear:animated];
|
||||||
|
|
||||||
|
[[self revealViewController] setPrimaryViewController:self];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
{
|
{
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
@@ -146,6 +153,11 @@
|
|||||||
// Dispose of any resources that can be recreated.
|
// Dispose of any resources that can be recreated.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Require a confirmation when streaming to activate a system gesture
|
||||||
|
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
|
||||||
|
return UIRectEdgeAll;
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)shouldAutorotate {
|
- (BOOL)shouldAutorotate {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
9857AEEA1EBE85A20084F99E /* RtpFecQueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 9857AEE91EBE85A20084F99E /* RtpFecQueue.c */; };
|
||||||
|
9857AEF01EBE85E10084F99E /* rs.c in Sources */ = {isa = PBXBuildFile; fileRef = 9857AEEE1EBE85E10084F99E /* rs.c */; };
|
||||||
98AB2E401CAD425A0089BB98 /* AudioStream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1A1CAD423B0089BB98 /* AudioStream.c */; };
|
98AB2E401CAD425A0089BB98 /* AudioStream.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1A1CAD423B0089BB98 /* AudioStream.c */; };
|
||||||
98AB2E411CAD425A0089BB98 /* ByteBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1B1CAD423B0089BB98 /* ByteBuffer.c */; };
|
98AB2E411CAD425A0089BB98 /* ByteBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1B1CAD423B0089BB98 /* ByteBuffer.c */; };
|
||||||
98AB2E421CAD425A0089BB98 /* Connection.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1D1CAD423B0089BB98 /* Connection.c */; };
|
98AB2E421CAD425A0089BB98 /* Connection.c in Sources */ = {isa = PBXBuildFile; fileRef = 98AB2E1D1CAD423B0089BB98 /* Connection.c */; };
|
||||||
@@ -35,6 +37,10 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
9857AEE91EBE85A20084F99E /* RtpFecQueue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = RtpFecQueue.c; sourceTree = "<group>"; };
|
||||||
|
9857AEEB1EBE85AB0084F99E /* RtpFecQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RtpFecQueue.h; sourceTree = "<group>"; };
|
||||||
|
9857AEEE1EBE85E10084F99E /* rs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rs.c; path = "moonlight-common-c/reedsolomon/rs.c"; sourceTree = "<group>"; };
|
||||||
|
9857AEEF1EBE85E10084F99E /* rs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rs.h; path = "moonlight-common-c/reedsolomon/rs.h"; sourceTree = "<group>"; };
|
||||||
98AB2DF01CAD422B0089BB98 /* callbacks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = callbacks.c; sourceTree = "<group>"; };
|
98AB2DF01CAD422B0089BB98 /* callbacks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = callbacks.c; sourceTree = "<group>"; };
|
||||||
98AB2DF11CAD422B0089BB98 /* ChangeLog */ = {isa = PBXFileReference; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
|
98AB2DF11CAD422B0089BB98 /* ChangeLog */ = {isa = PBXFileReference; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; };
|
||||||
98AB2DF21CAD422B0089BB98 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
|
98AB2DF21CAD422B0089BB98 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
|
||||||
@@ -113,6 +119,15 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
9857AEED1EBE85D50084F99E /* reedsolomon */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9857AEEE1EBE85E10084F99E /* rs.c */,
|
||||||
|
9857AEEF1EBE85E10084F99E /* rs.h */,
|
||||||
|
);
|
||||||
|
name = reedsolomon;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
98AB2DEF1CAD422B0089BB98 /* enet */ = {
|
98AB2DEF1CAD422B0089BB98 /* enet */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -193,6 +208,8 @@
|
|||||||
98AB2E191CAD423B0089BB98 /* src */ = {
|
98AB2E191CAD423B0089BB98 /* src */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9857AEEB1EBE85AB0084F99E /* RtpFecQueue.h */,
|
||||||
|
9857AEE91EBE85A20084F99E /* RtpFecQueue.c */,
|
||||||
98AB2E1A1CAD423B0089BB98 /* AudioStream.c */,
|
98AB2E1A1CAD423B0089BB98 /* AudioStream.c */,
|
||||||
98AB2E1B1CAD423B0089BB98 /* ByteBuffer.c */,
|
98AB2E1B1CAD423B0089BB98 /* ByteBuffer.c */,
|
||||||
98AB2E1C1CAD423B0089BB98 /* ByteBuffer.h */,
|
98AB2E1C1CAD423B0089BB98 /* ByteBuffer.h */,
|
||||||
@@ -228,6 +245,7 @@
|
|||||||
FB290E2519B37A4E004C83CF = {
|
FB290E2519B37A4E004C83CF = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9857AEED1EBE85D50084F99E /* reedsolomon */,
|
||||||
98AB2E191CAD423B0089BB98 /* src */,
|
98AB2E191CAD423B0089BB98 /* src */,
|
||||||
98AB2DEF1CAD422B0089BB98 /* enet */,
|
98AB2DEF1CAD422B0089BB98 /* enet */,
|
||||||
FB290E2F19B37A4E004C83CF /* Products */,
|
FB290E2F19B37A4E004C83CF /* Products */,
|
||||||
@@ -307,6 +325,7 @@
|
|||||||
98AB2E4C1CAD425A0089BB98 /* RtspParser.c in Sources */,
|
98AB2E4C1CAD425A0089BB98 /* RtspParser.c in Sources */,
|
||||||
98AB2E4D1CAD425A0089BB98 /* SdpGenerator.c in Sources */,
|
98AB2E4D1CAD425A0089BB98 /* SdpGenerator.c in Sources */,
|
||||||
98AB2E4E1CAD425A0089BB98 /* VideoDepacketizer.c in Sources */,
|
98AB2E4E1CAD425A0089BB98 /* VideoDepacketizer.c in Sources */,
|
||||||
|
9857AEEA1EBE85A20084F99E /* RtpFecQueue.c in Sources */,
|
||||||
98AB2E4F1CAD425A0089BB98 /* VideoStream.c in Sources */,
|
98AB2E4F1CAD425A0089BB98 /* VideoStream.c in Sources */,
|
||||||
98AB2E501CAD427A0089BB98 /* callbacks.c in Sources */,
|
98AB2E501CAD427A0089BB98 /* callbacks.c in Sources */,
|
||||||
98AB2E511CAD427A0089BB98 /* compress.c in Sources */,
|
98AB2E511CAD427A0089BB98 /* compress.c in Sources */,
|
||||||
@@ -315,6 +334,7 @@
|
|||||||
98AB2E541CAD427A0089BB98 /* packet.c in Sources */,
|
98AB2E541CAD427A0089BB98 /* packet.c in Sources */,
|
||||||
98AB2E551CAD427A0089BB98 /* peer.c in Sources */,
|
98AB2E551CAD427A0089BB98 /* peer.c in Sources */,
|
||||||
98AB2E561CAD427A0089BB98 /* protocol.c in Sources */,
|
98AB2E561CAD427A0089BB98 /* protocol.c in Sources */,
|
||||||
|
9857AEF01EBE85E10084F99E /* rs.c in Sources */,
|
||||||
98AB2E571CAD427A0089BB98 /* unix.c in Sources */,
|
98AB2E571CAD427A0089BB98 /* unix.c in Sources */,
|
||||||
98AB2E581CAD427A0089BB98 /* win32.c in Sources */,
|
98AB2E581CAD427A0089BB98 /* win32.c in Sources */,
|
||||||
);
|
);
|
||||||
|
|||||||