Compare commits

...
25 Commits
Author SHA1 Message Date
Diego Waxemberg 61b6e25a91 Bumping app version for 1.0.3 2016-03-08 22:35:06 -08:00
Diego Waxemberg 50cff820de Added app icon for ipad pro 2016-03-08 22:34:15 -08:00
Cameron Gutman 4e586a28c8 Update common-c to fix RTSP timeout issue 2016-03-08 13:15:33 -08:00
Cameron Gutman 0702b4ed57 Fix a performance regression in handling the applist response 2016-03-07 16:12:10 -08:00
Cameron Gutman 4a2132a682 Update common-c to support GFE 2.11 2016-03-07 14:45:05 -08:00
Diego Waxemberg ba81d1d6a9 Bumping version and creating build 1.0.2 2016-02-19 13:08:01 -08:00
Cameron Gutman 402ce4b3ec Update common-c to support Gen 5 servers 2016-02-19 15:09:37 -05:00
Cameron Gutman fc713453ad Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2016-02-16 10:38:25 -05:00
Cameron Gutman b222ccffbb Fix analysis warning 2016-02-16 10:37:59 -05:00
Michelle Bergeron 56ce7329d2 Point to website, add wiki link. 2016-02-15 22:39:32 -08:00
Michelle Bergeron 99ab6db557 Added note about Apple TV in effort to stave off some emails 2016-02-07 21:53:55 -08:00
Cameron Gutman d7adf96f3a Newer GFE versions don't mind resuming another device's stream 2016-02-06 23:10:36 -05:00
Cameron Gutman 0ae58c61a9 Remove apps from the database when they are removed from the app list 2016-01-21 16:24:02 -05:00
Cameron Gutman 2ec7d1d2f1 Use the main queue for the managed object context as a hack to prevent merge conflicts 2016-01-21 16:17:05 -05:00
Cameron Gutman ad1b9059ee Ensure the host matches for app entries 2016-01-21 15:01:15 -05:00
Cameron Gutman 4439c7cce6 Fix initial app list loading after pairing 2016-01-21 14:14:29 -05:00
Cameron Gutman b8a4093c75 Preserve app art when updating the app list 2016-01-21 14:03:07 -05:00
Cameron Gutman ec3748b26e Implement hash and isEqual for TemporaryApp and TemporaryHost 2016-01-21 13:34:34 -05:00
Cameron Gutman 1c1f22e047 Update the database on each server info poll 2016-01-21 12:09:49 -05:00
Cameron Gutman 9aa9b0fc5a Copy the pair state into the temporary host 2016-01-21 11:42:19 -05:00
Cameron Gutman f8e2ca8500 We can't hold onto managed objects in our temporary objects because they can disappear from under us, so do the lookup when we propagate values 2016-01-21 11:29:17 -05:00
Cameron Gutman 3076e29335 Basic database access is working 2015-12-02 00:25:38 -08:00
Cameron Gutman fe616d86c5 Reduce usage of DataManager 2015-12-01 20:56:08 -08:00
Cameron Gutman bfa4856bbe Move non-CoreData backed fields out of CoreData objects 2015-12-01 20:36:08 -08:00
Cameron Gutman 5ea92a7b48 Stop using CoreData-backed objects in any non-DataManager code 2015-12-01 20:31:24 -08:00
46 changed files with 546 additions and 255 deletions

No files matched your search

+4 -5
View File
@@ -13,15 +13,14 @@
+ (NSString*) getUniqueId { + (NSString*) getUniqueId {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
Settings* prefs = [dataMan retrieveSettings];
NSString* uniqueId = [dataMan getUniqueId];
NSString* uniqueId = prefs.uniqueId;
if (uniqueId == nil) { if (uniqueId == nil) {
uniqueId = [IdManager generateUniqueId]; uniqueId = [IdManager generateUniqueId];
prefs.uniqueId = uniqueId; [dataMan updateUniqueId:uniqueId];
[dataMan saveData];
Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId); Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId);
} }
return uniqueId; return uniqueId;
} }
-8
View File
@@ -11,16 +11,8 @@
@class Host; @class Host;
NS_ASSUME_NONNULL_BEGIN
@interface App : NSManagedObject @interface App : NSManagedObject
@property BOOL isRunning;
- (NSComparisonResult)compareName:(App *)other;
@end @end
NS_ASSUME_NONNULL_END
#import "App+CoreDataProperties.h" #import "App+CoreDataProperties.h"
-7
View File
@@ -7,14 +7,7 @@
// //
#import "App.h" #import "App.h"
#import "Host.h"
@implementation App @implementation App
@synthesize isRunning;
- (NSComparisonResult)compareName:(App *)other {
return [self.name caseInsensitiveCompare:other.name];
}
@end @end
+14 -12
View File
@@ -7,23 +7,25 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Settings.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "Host.h" #import "TemporaryHost.h"
#import "App.h"
#import "TemporaryApp.h" #import "TemporaryApp.h"
#import "TemporarySettings.h"
@interface DataManager : NSObject @interface DataManager : NSObject
@property (strong, nonatomic) AppDelegate* appDelegate;
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls; - (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
- (Settings*) retrieveSettings;
- (NSArray*) retrieveHosts; - (NSArray*) getHosts;
- (void) saveData; - (void) updateHost:(TemporaryHost*)host;
- (Host*) createHost; - (void) updateAppsForExistingHost:(TemporaryHost *)host;
- (void) removeHost:(Host*)host; - (void) updateIconForExistingApp:(TemporaryApp*)app;
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp; - (void) removeHost:(TemporaryHost*)host;
- (void) removeAppFromHost:(App*)app; - (void) removeApp:(TemporaryApp*)app;
- (TemporarySettings*) getSettings;
- (void) updateUniqueId:(NSString*)uniqueId;
- (NSString*) getUniqueId;
@end @end
+168 -74
View File
@@ -8,45 +8,131 @@
#import "DataManager.h" #import "DataManager.h"
#import "TemporaryApp.h" #import "TemporaryApp.h"
#import "TemporarySettings.h"
#import "Settings.h"
@implementation DataManager @implementation DataManager {
NSManagedObjectContext *_managedObjectContext;
+ (NSObject *)databaseLock { AppDelegate *_appDelegate;
static NSObject *lock = nil;
if (lock == nil) {
lock = [[NSObject alloc] init];
}
return lock;
} }
- (id) init { - (id) init {
self = [super init]; self = [super init];
self.appDelegate = [[UIApplication sharedApplication] delegate];
_appDelegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
return self; return self;
} }
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls { - (void) updateUniqueId:(NSString*)uniqueId {
Settings* settingsToSave = [self retrieveSettings]; [_managedObjectContext performBlockAndWait:^{
settingsToSave.framerate = [NSNumber numberWithInteger:framerate]; [self retrieveSettings].uniqueId = uniqueId;
// Bitrate is persisted in kbps [self saveData];
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate]; }];
settingsToSave.height = [NSNumber numberWithInteger:height]; }
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
NSError* error; - (NSString*) getUniqueId {
if (![[self.appDelegate managedObjectContext] save:&error]) { __block NSString *uid;
Log(LOG_E, @"Unable to save settings to database: %@", error);
} [_managedObjectContext performBlockAndWait:^{
[self.appDelegate saveContext]; uid = [self retrieveSettings].uniqueId;
}];
return uid;
}
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
[_managedObjectContext performBlockAndWait:^{
Settings* settingsToSave = [self retrieveSettings];
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
// Bitrate is persisted in kbps
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
settingsToSave.height = [NSNumber numberWithInteger:height];
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
[self saveData];
}];
}
- (void) updateHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
// Add a new persistent managed object if one doesn't exist
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:_managedObjectContext];
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
// Push changes from the temp host to the persistent one
[host propagateChangesToParent:parent];
[self saveData];
}];
}
- (void) updateAppsForExistingHost:(TemporaryHost *)host {
[_managedObjectContext performBlockAndWait:^{
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
// The host must exist to be updated
return;
}
NSMutableSet *applist = [[NSMutableSet alloc] init];
NSArray *appRecords = [self fetchRecords:@"App"];
for (TemporaryApp* app in host.appList) {
// Add a new persistent managed object if one doesn't exist
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:appRecords];
if (parentApp == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:_managedObjectContext];
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
[app propagateChangesToParent:parentApp withHost:parent];
[applist addObject:parentApp];
}
parent.appList = applist;
[self saveData];
}];
}
- (void) updateIconForExistingApp:(TemporaryApp*)app {
[_managedObjectContext performBlockAndWait:^{
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (parentApp == nil) {
// The app must exist to be updated
return;
}
parentApp.image = app.image;
[self saveData];
}];
}
- (TemporarySettings*) getSettings {
__block TemporarySettings *tempSettings;
[_managedObjectContext performBlockAndWait:^{
tempSettings = [[TemporarySettings alloc] initFromSettings:[self retrieveSettings]];
}];
return tempSettings;
} }
- (Settings*) retrieveSettings { - (Settings*) retrieveSettings {
NSArray* fetchedRecords = [self fetchRecords:@"Settings"]; NSArray* fetchedRecords = [self fetchRecords:@"Settings"];
if (fetchedRecords.count == 0) { if (fetchedRecords.count == 0) {
// create a new settings object with the default values // create a new settings object with the default values
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]]; NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:_managedObjectContext];
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
return settings; return settings;
} else { } else {
@@ -55,74 +141,82 @@
} }
} }
- (Host*) createHost { - (void) removeApp:(TemporaryApp*)app {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]]; [_managedObjectContext performBlockAndWait:^{
return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]]; App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (managedApp != nil) {
[_managedObjectContext deleteObject:managedApp];
[self saveData];
}
}];
} }
- (void) removeHost:(Host*)host { - (void) removeHost:(TemporaryHost*)host {
[[self.appDelegate managedObjectContext] deleteObject:host]; [_managedObjectContext performBlockAndWait:^{
[self saveData]; Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (managedHost != nil) {
[_managedObjectContext deleteObject:managedHost];
[self saveData];
}
}];
} }
- (void) saveData { - (void) saveData {
@synchronized([DataManager databaseLock]) { NSError* error;
NSError* error; if (![_managedObjectContext save:&error]) {
if (![[self.appDelegate managedObjectContext] save:&error]) { Log(LOG_E, @"Unable to save hosts to database: %@", error);
Log(LOG_E, @"Unable to save hosts to database: %@", error); }
[_appDelegate saveContext];
}
- (NSArray*) getHosts {
__block NSMutableArray *tempHosts = [[NSMutableArray alloc] init];
[_managedObjectContext performBlockAndWait:^{
NSArray *hosts = [self fetchRecords:@"Host"];
for (Host* host in hosts) {
[tempHosts addObject:[[TemporaryHost alloc] initFromHost:host]];
} }
[self.appDelegate saveContext]; }];
}
return tempHosts;
} }
- (NSArray*) retrieveHosts { // Only call from within performBlockAndWait!!!
return [self fetchRecords:@"Host"]; - (Host*) getHostForTemporaryHost:(TemporaryHost*)tempHost withHostRecords:(NSArray*)hosts {
} for (Host* host in hosts) {
if ([tempHost.uuid isEqualToString:host.uuid]) {
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp { return host;
}
App* managedApp;
@synchronized([DataManager databaseLock]) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
managedApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
assert(tempApp.host != nil);
managedApp.id = tempApp.id;
managedApp.image = tempApp.image;
managedApp.name = tempApp.name;
managedApp.isRunning = tempApp.isRunning;
managedApp.host = tempApp.host;
[managedApp.host addAppListObject:managedApp];
} }
return managedApp; return nil;
} }
- (void) removeAppFromHost:(App*)app { // Only call from within performBlockAndWait!!!
@synchronized([DataManager databaseLock]) { - (App*) getAppForTemporaryApp:(TemporaryApp*)tempApp withAppRecords:(NSArray*)apps {
assert(app.host != nil); for (App* app in apps) {
if ([app.id isEqualToString:tempApp.id] &&
[app.host removeAppListObject:app]; [app.host.uuid isEqualToString:app.host.uuid]) {
[[self.appDelegate managedObjectContext] deleteObject:app]; return app;
}
} }
return nil;
} }
- (NSArray*) fetchRecords:(NSString*)entityName { - (NSArray*) fetchRecords:(NSString*)entityName {
NSArray* fetchedRecords; NSArray* fetchedRecords;
@synchronized([DataManager databaseLock]) { NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:_managedObjectContext];
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]]; [fetchRequest setEntity:entity];
[fetchRequest setEntity:entity];
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]]; NSError* error;
fetchedRecords = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSError* error; //TODO: handle errors
fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
//TODO: handle errors
}
return fetchedRecords; return fetchedRecords;
} }
-10
View File
@@ -10,18 +10,8 @@
#import <CoreData/CoreData.h> #import <CoreData/CoreData.h>
#import "Utils.h" #import "Utils.h"
NS_ASSUME_NONNULL_BEGIN
@interface Host : NSManagedObject @interface Host : NSManagedObject
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic) NSString * activeAddress;
- (NSComparisonResult)compareName:(Host *)other;
@end @end
NS_ASSUME_NONNULL_END
#import "Host+CoreDataProperties.h" #import "Host+CoreDataProperties.h"
-8
View File
@@ -10,12 +10,4 @@
@implementation Host @implementation Host
@dynamic pairState;
@synthesize online;
@synthesize activeAddress;
- (NSComparisonResult)compareName:(Host *)other {
return [self.name caseInsensitiveCompare:other.name];
}
@end @end
+13 -2
View File
@@ -7,7 +7,8 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
#import "App.h"
@interface TemporaryApp : NSObject @interface TemporaryApp : NSObject
@@ -15,6 +16,16 @@
@property (nullable, nonatomic, retain) NSData *image; @property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name; @property (nullable, nonatomic, retain) NSString *name;
@property (nonatomic) BOOL isRunning; @property (nonatomic) BOOL isRunning;
@property (nullable, nonatomic, retain) Host *host; @property (nullable, nonatomic, retain) TemporaryHost *host;
NS_ASSUME_NONNULL_BEGIN
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost;
- (NSComparisonResult)compareName:(TemporaryApp *)other;
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host;
NS_ASSUME_NONNULL_END
@end @end
+39
View File
@@ -7,7 +7,46 @@
// //
#import "TemporaryApp.h" #import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryApp @implementation TemporaryApp
- (id) initFromApp:(App*)app withTempHost:(TemporaryHost*)tempHost {
self = [self init];
self.id = app.id;
self.image = app.image;
self.name = app.name;
self.host = tempHost;
return self;
}
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host {
parent.id = self.id;
parent.name = self.name;
parent.host = host;
}
- (NSComparisonResult)compareName:(TemporaryApp *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.host.uuid hash] * 31 + [self.id intValue];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[App class]]) {
return NO;
}
return [self.host.uuid isEqualToString:((App*)object).host.uuid] &&
[self.id isEqualToString:((App*)object).id];
}
@end @end
+37
View File
@@ -0,0 +1,37 @@
//
// TemporaryHost.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Utils.h"
#import "Host.h"
@interface TemporaryHost : NSObject
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic, nullable) NSString * activeAddress;
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, retain) NSString *address;
@property (nonatomic, retain) NSString *externalAddress;
@property (nonatomic, retain) NSString *localAddress;
@property (nonatomic, retain) NSString *mac;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *uuid;
@property (nonatomic, retain) NSMutableSet *appList;
- (id) initFromHost:(Host*)host;
- (NSComparisonResult)compareName:(TemporaryHost *)other;
- (void) propagateChangesToParent:(Host*)host;
NS_ASSUME_NONNULL_END
@end
+77
View File
@@ -0,0 +1,77 @@
//
// TemporaryHost.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "DataManager.h"
#import "TemporaryHost.h"
#import "Host.h"
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryHost
- (id) init {
self = [super init];
self.appList = [[NSMutableSet alloc] init];
return self;
}
- (id) initFromHost:(Host*)host {
self = [self init];
self.address = host.address;
self.externalAddress = host.externalAddress;
self.localAddress = host.localAddress;
self.mac = host.mac;
self.name = host.name;
self.uuid = host.uuid;
self.pairState = [host.pairState intValue];
NSMutableSet *appList = [[NSMutableSet alloc] init];
for (App* app in host.appList) {
TemporaryApp *tempApp = [[TemporaryApp alloc] initFromApp:app withTempHost:self];
[appList addObject:tempApp];
}
self.appList = appList;
return self;
}
- (void) propagateChangesToParent:(Host*)parentHost {
parentHost.address = self.address;
parentHost.externalAddress = self.externalAddress;
parentHost.localAddress = self.localAddress;
parentHost.mac = self.mac;
parentHost.name = self.name;
parentHost.uuid = self.uuid;
parentHost.pairState = [NSNumber numberWithInt:self.pairState];
}
- (NSComparisonResult)compareName:(TemporaryHost *)other {
return [self.name caseInsensitiveCompare:other.name];
}
- (NSUInteger)hash {
return [self.uuid hash];
}
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![object isKindOfClass:[Host class]]) {
return NO;
}
return [self.uuid isEqualToString:((Host*)object).uuid];
}
@end
+25
View File
@@ -0,0 +1,25 @@
//
// TemporarySettings.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Settings.h"
@interface TemporarySettings : NSObject
@property (nonatomic, retain) Settings * parent;
@property (nonatomic, retain) NSNumber * bitrate;
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
- (id) initFromSettings:(Settings*)settings;
@end
+28
View File
@@ -0,0 +1,28 @@
//
// TemporarySettings.m
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporarySettings.h"
@implementation TemporarySettings
- (id) initFromSettings:(Settings*)settings {
self = [self init];
self.parent = settings;
self.bitrate = settings.bitrate;
self.framerate = settings.framerate;
self.height = settings.height;
self.width = settings.width;
self.onscreenControls = settings.onscreenControls;
self.uniqueId = settings.uniqueId;
return self;
}
@end
@@ -71,6 +71,12 @@
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "app_icon_152x152_@2x.png", "filename" : "app_icon_152x152_@2x.png",
"scale" : "2x" "scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "app_icon_167x167_@2x.png",
"scale" : "2x"
} }
], ],
"info" : { "info" : {
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+1 -1
View File
@@ -32,7 +32,7 @@
- (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate { - (void) setupOnScreenControls:(ControllerSupport*)controllerSupport swipeDelegate:(id<EdgeDetectionDelegate>)swipeDelegate {
onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate]; onScreenControls = [[OnScreenControls alloc] initWithView:self controllerSup:controllerSupport swipeDelegate:swipeDelegate];
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan retrieveSettings].onscreenControls integerValue]; OnScreenControlsLevel level = (OnScreenControlsLevel)[[dataMan getSettings].onscreenControls integerValue];
if (level == OnScreenControlsLevelAuto) { if (level == OnScreenControlsLevelAuto) {
[controllerSupport initAutoOnScreenControlMode:onScreenControls]; [controllerSupport initAutoOnScreenControlMode:onScreenControls];
+2 -2
View File
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0.1</string> <string>1.0.3</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>4</string> <string>1</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
+4 -4
View File
@@ -7,20 +7,20 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "App.h" #import "TemporaryApp.h"
#import "HttpManager.h" #import "HttpManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol AppAssetCallback <NSObject> @protocol AppAssetCallback <NSObject>
- (void) receivedAssetForApp:(App*)app; - (void) receivedAssetForApp:(TemporaryApp*)app;
@end @end
@interface AppAssetManager : NSObject @interface AppAssetManager : NSObject
- (id) initWithCallback:(id<AppAssetCallback>)callback; - (id) initWithCallback:(id<AppAssetCallback>)callback;
- (void) retrieveAssetsFromHost:(Host*)host; - (void) retrieveAssetsFromHost:(TemporaryHost*)host;
- (void) stopRetrieving; - (void) stopRetrieving;
@end @end
+3 -3
View File
@@ -28,8 +28,8 @@ static const int MAX_REQUEST_COUNT = 4;
return self; return self;
} }
- (void) retrieveAssetsFromHost:(Host*)host { - (void) retrieveAssetsFromHost:(TemporaryHost*)host {
for (App* app in host.appList) { for (TemporaryApp* app in host.appList) {
if (app.image == nil) { if (app.image == nil) {
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init]; AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
retriever.app = app; retriever.app = app;
@@ -45,7 +45,7 @@ static const int MAX_REQUEST_COUNT = 4;
[_opQueue cancelAllOperations]; [_opQueue cancelAllOperations];
} }
- (void) sendCallBackForApp:(App*)app { - (void) sendCallBackForApp:(TemporaryApp*)app {
[_callback receivedAssetForApp:app]; [_callback receivedAssetForApp:app];
} }
+4 -4
View File
@@ -7,14 +7,14 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
#import "App.h" #import "TemporaryApp.h"
#import "AppAssetManager.h" #import "AppAssetManager.h"
@interface AppAssetRetriever : NSOperation @interface AppAssetRetriever : NSOperation
@property (nonatomic) Host* host; @property (nonatomic) TemporaryHost* host;
@property (nonatomic) App* app; @property (nonatomic) TemporaryApp* app;
@property (nonatomic) id<AppAssetCallback> callback; @property (nonatomic) id<AppAssetCallback> callback;
@end @end
+1 -1
View File
@@ -36,7 +36,7 @@ static const int MAX_ATTEMPTS = 5;
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
} }
- (void) sendCallbackForApp:(App*)app { - (void) sendCallbackForApp:(TemporaryApp*)app {
[self.callback receivedAssetForApp:app]; [self.callback receivedAssetForApp:app];
} }
+1 -1
View File
@@ -11,7 +11,7 @@
@interface AppListResponse : NSObject <Response> @interface AppListResponse : NSObject <Response>
- (void)populateWithData:(NSData *)data; - (void)populateWithData:(NSData *)data;
- (NSArray*) getAppList; - (NSSet*) getAppList;
- (BOOL) isStatusOk; - (BOOL) isStatusOk;
@end @end
+3 -3
View File
@@ -12,7 +12,7 @@
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation AppListResponse { @implementation AppListResponse {
NSMutableArray* _appList; NSMutableSet* _appList;
} }
@synthesize data, statusCode, statusMessage; @synthesize data, statusCode, statusMessage;
@@ -23,7 +23,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
- (void)populateWithData:(NSData *)xml { - (void)populateWithData:(NSData *)xml {
self.data = xml; self.data = xml;
_appList = [[NSMutableArray alloc] init]; _appList = [[NSMutableSet alloc] init];
[self parseData]; [self parseData];
} }
@@ -108,7 +108,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
xmlFreeDoc(docPtr); xmlFreeDoc(docPtr);
} }
- (NSArray*) getAppList { - (NSSet*) getAppList {
return _appList; return _appList;
} }
+4 -4
View File
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "MDNSManager.h" #import "MDNSManager.h"
#import "Host.h" #import "TemporaryHost.h"
@protocol DiscoveryCallback <NSObject> @protocol DiscoveryCallback <NSObject>
@@ -22,8 +22,8 @@
- (void) startDiscovery; - (void) startDiscovery;
- (void) stopDiscovery; - (void) stopDiscovery;
- (void) stopDiscoveryBlocking; - (void) stopDiscoveryBlocking;
- (BOOL) addHostToDiscovery:(Host*)host; - (BOOL) addHostToDiscovery:(TemporaryHost*)host;
- (void) removeHostFromDiscovery:(Host*)host; - (void) removeHostFromDiscovery:(TemporaryHost*)host;
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback; - (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(TemporaryHost*, NSString*))callback;
@end @end
+12 -24
View File
@@ -17,7 +17,6 @@
@implementation DiscoveryManager { @implementation DiscoveryManager {
NSMutableArray* _hostQueue; NSMutableArray* _hostQueue;
NSMutableArray* _discoveredHosts;
id<DiscoveryCallback> _callback; id<DiscoveryCallback> _callback;
MDNSManager* _mdnsMan; MDNSManager* _mdnsMan;
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
@@ -34,16 +33,10 @@
_callback = callback; _callback = callback;
shouldDiscover = NO; shouldDiscover = NO;
_hostQueue = [NSMutableArray array]; _hostQueue = [NSMutableArray array];
DataManager* dataMan = [[DataManager alloc] init]; for (TemporaryHost* host in hosts)
for (Host* host in hosts)
{ {
if (![self addHostToDiscovery:host]) [self addHostToDiscovery:host];
{
// Remove the duplicate host from the database
[dataMan removeHost:host];
}
} }
[dataMan saveData];
[_callback updateAllHosts:_hostQueue]; [_callback updateAllHosts:_hostQueue];
_opQueue = [[NSOperationQueue alloc] init]; _opQueue = [[NSOperationQueue alloc] init];
@@ -54,20 +47,18 @@
return self; return self;
} }
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback { - (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(TemporaryHost *, NSString*))callback {
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert]; HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init]; ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
Host* host = nil; TemporaryHost* host = nil;
if ([serverInfoResponse isStatusOk]) { if ([serverInfoResponse isStatusOk]) {
DataManager* dataMan = [[DataManager alloc] init]; host = [[TemporaryHost alloc] init];
host = [dataMan createHost];
host.activeAddress = host.address = hostAddress; host.activeAddress = host.address = hostAddress;
host.online = YES; host.online = YES;
[serverInfoResponse populateHost:host]; [serverInfoResponse populateHost:host];
if (![self addHostToDiscovery:host]) { if (![self addHostToDiscovery:host]) {
[dataMan removeHost:host];
callback(nil, @"Host already added"); callback(nil, @"Host already added");
} else { } else {
callback(host, nil); callback(host, nil);
@@ -82,7 +73,7 @@
Log(LOG_I, @"Starting discovery"); Log(LOG_I, @"Starting discovery");
shouldDiscover = YES; shouldDiscover = YES;
[_mdnsMan searchForHosts]; [_mdnsMan searchForHosts];
for (Host* host in _hostQueue) { for (TemporaryHost* host in _hostQueue) {
[_opQueue addOperation:[self createWorkerForHost:host]]; [_opQueue addOperation:[self createWorkerForHost:host]];
} }
} }
@@ -103,7 +94,7 @@
Log(LOG_I, @"All discovery workers stopped"); Log(LOG_I, @"All discovery workers stopped");
} }
- (BOOL) addHostToDiscovery:(Host *)host { - (BOOL) addHostToDiscovery:(TemporaryHost *)host {
if (host.uuid.length > 0 && ![self isHostInDiscovery:host]) { if (host.uuid.length > 0 && ![self isHostInDiscovery:host]) {
[_hostQueue addObject:host]; [_hostQueue addObject:host];
if (shouldDiscover) { if (shouldDiscover) {
@@ -114,7 +105,7 @@
return NO; return NO;
} }
- (void) removeHostFromDiscovery:(Host *)host { - (void) removeHostFromDiscovery:(TemporaryHost *)host {
for (DiscoveryWorker* worker in [_opQueue operations]) { for (DiscoveryWorker* worker in [_opQueue operations]) {
if ([worker getHost] == host) { if ([worker getHost] == host) {
[worker cancel]; [worker cancel];
@@ -126,9 +117,8 @@
// Override from MDNSCallback // Override from MDNSCallback
- (void)updateHosts:(NSArray *)hosts { - (void)updateHosts:(NSArray *)hosts {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DataManager* dataMan = [[DataManager alloc] init];
// Discover the hosts before adding to eliminate duplicates // Discover the hosts before adding to eliminate duplicates
for (Host* host in hosts) { for (TemporaryHost* host in hosts) {
Log(LOG_I, @"Found host through MDNS: %@:", host.name); Log(LOG_I, @"Found host through MDNS: %@:", host.name);
// Since this is on a background thread, we do not need to use the opQueue // Since this is on a background thread, we do not need to use the opQueue
DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host]; DiscoveryWorker* worker = (DiscoveryWorker*)[self createWorkerForHost:host];
@@ -138,16 +128,14 @@
[_callback updateAllHosts:_hostQueue]; [_callback updateAllHosts:_hostQueue];
} else { } else {
Log(LOG_I, @"Not adding host to discovery: %@", host.name); Log(LOG_I, @"Not adding host to discovery: %@", host.name);
[dataMan removeHost:host];
} }
} }
[dataMan saveData];
}); });
} }
- (BOOL) isHostInDiscovery:(Host*)host { - (BOOL) isHostInDiscovery:(TemporaryHost*)host {
for (int i = 0; i < _hostQueue.count; i++) { for (int i = 0; i < _hostQueue.count; i++) {
Host* discoveredHost = [_hostQueue objectAtIndex:i]; TemporaryHost* discoveredHost = [_hostQueue objectAtIndex:i];
if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:host.uuid]) { if (discoveredHost.uuid.length > 0 && [discoveredHost.uuid isEqualToString:host.uuid]) {
return YES; return YES;
} }
@@ -155,7 +143,7 @@
return NO; return NO;
} }
- (NSOperation*) createWorkerForHost:(Host*)host { - (NSOperation*) createWorkerForHost:(TemporaryHost*)host {
DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert]; DiscoveryWorker* worker = [[DiscoveryWorker alloc] initWithHost:host uniqueId:_uniqueId cert:_cert];
return worker; return worker;
} }
+3 -3
View File
@@ -7,12 +7,12 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
@interface DiscoveryWorker : NSOperation @interface DiscoveryWorker : NSOperation
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert; - (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert;
- (void) discoverHost; - (void) discoverHost;
- (Host*) getHost; - (TemporaryHost*) getHost;
@end @end
+9 -4
View File
@@ -11,16 +11,17 @@
#import "HttpManager.h" #import "HttpManager.h"
#import "ServerInfoResponse.h" #import "ServerInfoResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "DataManager.h"
@implementation DiscoveryWorker { @implementation DiscoveryWorker {
Host* _host; TemporaryHost* _host;
NSString* _uniqueId; NSString* _uniqueId;
NSData* _cert; NSData* _cert;
} }
static const float POLL_RATE = 2.0f; // Poll every 2 seconds static const float POLL_RATE = 2.0f; // Poll every 2 seconds
- (id) initWithHost:(Host*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert { - (id) initWithHost:(TemporaryHost*)host uniqueId:(NSString*)uniqueId cert:(NSData*)cert {
self = [super init]; self = [super init];
_host = host; _host = host;
_uniqueId = uniqueId; _uniqueId = uniqueId;
@@ -28,7 +29,7 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
return self; return self;
} }
- (Host*) getHost { - (TemporaryHost*) getHost {
return _host; return _host;
} }
@@ -100,7 +101,12 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address]; ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
receivedResponse = [self checkResponse:serverInfoResp]; receivedResponse = [self checkResponse:serverInfoResp];
if (receivedResponse) { if (receivedResponse) {
[serverInfoResp populateHost:_host];
_host.activeAddress = address; _host.activeAddress = address;
// Update the database using the response
DataManager *dataManager = [[DataManager alloc] init];
[dataManager updateHost:_host];
break; break;
} }
} }
@@ -137,7 +143,6 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
if ([response isStatusOk]) { if ([response isStatusOk]) {
// If the response is from a different host then do not update this host // If the response is from a different host then do not update this host
if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) { if ((_host.uuid == nil || [[response getStringTag:TAG_UNIQUE_ID] isEqualToString:_host.uuid])) {
[response populateHost:_host];
return YES; return YES;
} else { } else {
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid); Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
-1
View File
@@ -7,7 +7,6 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h"
#import "HttpResponse.h" #import "HttpResponse.h"
#import "HttpRequest.h" #import "HttpRequest.h"
+1 -1
View File
@@ -9,7 +9,7 @@
#import "HttpManager.h" #import "HttpManager.h"
#import "HttpRequest.h" #import "HttpRequest.h"
#import "CryptoManager.h" #import "CryptoManager.h"
#import "App.h" #import "TemporaryApp.h"
#include <libxml2/libxml/xmlreader.h> #include <libxml2/libxml/xmlreader.h>
#include <string.h> #include <string.h>
-1
View File
@@ -7,7 +7,6 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h"
static NSString* TAG_STATUS_CODE = @"status_code"; static NSString* TAG_STATUS_CODE = @"status_code";
static NSString* TAG_STATUS_MESSAGE = @"status_message"; static NSString* TAG_STATUS_MESSAGE = @"status_message";
+1 -1
View File
@@ -7,7 +7,7 @@
// //
#import "HttpResponse.h" #import "HttpResponse.h"
#import "App.h" #import "TemporaryApp.h"
#import <libxml2/libxml/xmlreader.h> #import <libxml2/libxml/xmlreader.h>
@implementation HttpResponse { @implementation HttpResponse {
+2 -4
View File
@@ -7,8 +7,7 @@
// //
#import "MDNSManager.h" #import "MDNSManager.h"
#import "Host.h" #import "TemporaryHost.h"
#import "DataManager.h"
@implementation MDNSManager { @implementation MDNSManager {
NSNetServiceBrowser* mDNSBrowser; NSNetServiceBrowser* mDNSBrowser;
@@ -47,10 +46,9 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
- (NSArray*) getFoundHosts { - (NSArray*) getFoundHosts {
NSMutableArray* hosts = [[NSMutableArray alloc] init]; NSMutableArray* hosts = [[NSMutableArray alloc] init];
DataManager* dataMan = [[DataManager alloc] init];
for (NSNetService* service in services) { for (NSNetService* service in services) {
if (service.hostName != nil) { if (service.hostName != nil) {
Host* host = [dataMan createHost]; TemporaryHost* host = [[TemporaryHost alloc] init];
host.activeAddress = host.address = service.hostName; host.activeAddress = host.address = service.hostName;
host.name = host.address; host.name = host.address;
[hosts addObject:host]; [hosts addObject:host];
+2 -1
View File
@@ -7,6 +7,7 @@
// //
#import "HttpResponse.h" #import "HttpResponse.h"
#import "TemporaryHost.h"
#define TAG_HOSTNAME @"hostname" #define TAG_HOSTNAME @"hostname"
#define TAG_EXTERNAL_IP @"ExternalIP" #define TAG_EXTERNAL_IP @"ExternalIP"
@@ -18,7 +19,7 @@
@interface ServerInfoResponse : HttpResponse <Response> @interface ServerInfoResponse : HttpResponse <Response>
- (void) populateWithData:(NSData *)data; - (void) populateWithData:(NSData *)data;
- (void) populateHost:(Host*)host; - (void) populateHost:(TemporaryHost*)host;
@end @end
+1 -1
View File
@@ -17,7 +17,7 @@
[super parseData]; [super parseData];
} }
- (void) populateHost:(Host*)host { - (void) populateHost:(TemporaryHost*)host {
host.name = [[self getStringTag:TAG_HOSTNAME] trim]; host.name = [[self getStringTag:TAG_HOSTNAME] trim];
host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim]; host.externalAddress = [[self getStringTag:TAG_EXTERNAL_IP] trim];
host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim]; host.localAddress = [[self getStringTag:TAG_LOCAL_IP] trim];
+2 -2
View File
@@ -7,10 +7,10 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Host.h" #import "TemporaryHost.h"
@interface WakeOnLanManager : NSObject @interface WakeOnLanManager : NSObject
+ (void) wakeHost:(Host*)host; + (void) wakeHost:(TemporaryHost*)host;
@end @end
+2 -2
View File
@@ -18,7 +18,7 @@
static const int numPorts = 5; static const int numPorts = 5;
static const int ports[numPorts] = {7, 9, 47998, 47999, 48000}; static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
+ (void) wakeHost:(Host*)host { + (void) wakeHost:(TemporaryHost*)host {
NSData* wolPayload = [WakeOnLanManager createPayload:host]; NSData* wolPayload = [WakeOnLanManager createPayload:host];
CFDataRef dataPayload = CFDataCreate(kCFAllocatorDefault, [wolPayload bytes], [wolPayload length]); CFDataRef dataPayload = CFDataCreate(kCFAllocatorDefault, [wolPayload bytes], [wolPayload length]);
CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL); CFSocketRef wolSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, NULL, NULL);
@@ -56,7 +56,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
CFRelease(dataPayload); CFRelease(dataPayload);
} }
+ (NSData*) createPayload:(Host*)host { + (NSData*) createPayload:(TemporaryHost*)host {
NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102]; NSMutableData* payload = [[NSMutableData alloc] initWithCapacity:102];
// 6 bytes of FF // 6 bytes of FF
-6
View File
@@ -49,7 +49,6 @@
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest] [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"]; NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
NSString* appversion = [serverInfoResp getStringTag:@"appversion"]; NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
NSString* serverState = [serverInfoResp getStringTag:@"state"]; NSString* serverState = [serverInfoResp getStringTag:@"state"];
if (![serverInfoResp isStatusOk] || pairStatus == NULL || appversion == NULL || serverState == NULL) { if (![serverInfoResp isStatusOk] || pairStatus == NULL || appversion == NULL || serverState == NULL) {
@@ -65,11 +64,6 @@
// resumeApp and launchApp handle calling launchFailed // resumeApp and launchApp handle calling launchFailed
if ([serverState hasSuffix:@"_SERVER_BUSY"]) { if ([serverState hasSuffix:@"_SERVER_BUSY"]) {
if (![currentClient isEqualToString:@"1"]) {
// The server is streaming to someone else
[_callbacks launchFailed:@"There is another stream in progress"];
return;
}
// App already running, resume it // App already running, resume it
if (![self resumeApp:hMan]) { if (![self resumeApp:hMan]) {
return; return;
+3 -3
View File
@@ -7,17 +7,17 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "App.h" #import "TemporaryApp.h"
@protocol AppCallback <NSObject> @protocol AppCallback <NSObject>
- (void) appClicked:(App*) app; - (void) appClicked:(TemporaryApp*) app;
@end @end
@interface UIAppView : UIView @interface UIAppView : UIView
- (id) initWithApp:(App*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback; - (id) initWithApp:(TemporaryApp*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback;
- (void) updateAppImage; - (void) updateAppImage;
@end @end
+2 -2
View File
@@ -9,7 +9,7 @@
#import "UIAppView.h" #import "UIAppView.h"
@implementation UIAppView { @implementation UIAppView {
App* _app; TemporaryApp* _app;
UIButton* _appButton; UIButton* _appButton;
UILabel* _appLabel; UILabel* _appLabel;
UIImageView* _appOverlay; UIImageView* _appOverlay;
@@ -19,7 +19,7 @@
static UIImage* noImage; static UIImage* noImage;
- (id) initWithApp:(App*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback { - (id) initWithApp:(TemporaryApp*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback {
self = [super init]; self = [super init];
_app = app; _app = app;
_callback = callback; _callback = callback;
+4 -4
View File
@@ -7,19 +7,19 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "Host.h" #import "TemporaryHost.h"
@protocol HostCallback <NSObject> @protocol HostCallback <NSObject>
- (void) hostClicked:(Host*)host view:(UIView*)view; - (void) hostClicked:(TemporaryHost*)host view:(UIView*)view;
- (void) hostLongClicked:(Host*)host view:(UIView*)view; - (void) hostLongClicked:(TemporaryHost*)host view:(UIView*)view;
- (void) addHostClicked; - (void) addHostClicked;
@end @end
@interface UIComputerView : UIView @interface UIComputerView : UIView
- (id) initWithComputer:(Host*)host andCallback:(id<HostCallback>)callback; - (id) initWithComputer:(TemporaryHost*)host andCallback:(id<HostCallback>)callback;
- (id) initForAddWithCallback:(id<HostCallback>)callback; - (id) initForAddWithCallback:(id<HostCallback>)callback;
@end @end
+3 -3
View File
@@ -9,7 +9,7 @@
#import "UIComputerView.h" #import "UIComputerView.h"
@implementation UIComputerView { @implementation UIComputerView {
Host* _host; TemporaryHost* _host;
UIButton* _hostButton; UIButton* _hostButton;
UILabel* _hostLabel; UILabel* _hostLabel;
UILabel* _hostStatus; UILabel* _hostStatus;
@@ -72,7 +72,7 @@ static const int LABEL_DY = 20;
return self; return self;
} }
- (id) initWithComputer:(Host*)host andCallback:(id<HostCallback>)callback { - (id) initWithComputer:(TemporaryHost*)host andCallback:(id<HostCallback>)callback {
self = [self init]; self = [self init];
_host = host; _host = host;
_callback = callback; _callback = callback;
@@ -123,7 +123,7 @@ static const int LABEL_DY = 20;
self.frame = CGRectMake(x, y, width, height); self.frame = CGRectMake(x, y, width, height);
} }
- (void) updateContentsForHost:(Host*)host { - (void) updateContentsForHost:(TemporaryHost*)host {
_hostLabel.text = _host.name; _hostLabel.text = _host.name;
_hostLabel.textColor = [UIColor whiteColor]; _hostLabel.textColor = [UIColor whiteColor];
[_hostLabel sizeToFit]; [_hostLabel sizeToFit];
@@ -15,10 +15,9 @@
#import "Utils.h" #import "Utils.h"
#import "UIComputerView.h" #import "UIComputerView.h"
#import "UIAppView.h" #import "UIAppView.h"
#import "App.h"
#import "SettingsViewController.h" #import "SettingsViewController.h"
#import "DataManager.h" #import "DataManager.h"
#import "Settings.h" #import "TemporarySettings.h"
#import "WakeOnLanManager.h" #import "WakeOnLanManager.h"
#import "AppListResponse.h" #import "AppListResponse.h"
#import "ServerInfoResponse.h" #import "ServerInfoResponse.h"
@@ -30,7 +29,7 @@
@implementation MainFrameViewController { @implementation MainFrameViewController {
NSOperationQueue* _opQueue; NSOperationQueue* _opQueue;
Host* _selectedHost; TemporaryHost* _selectedHost;
NSString* _uniqueId; NSString* _uniqueId;
NSData* _cert; NSData* _cert;
DiscoveryManager* _discMan; DiscoveryManager* _discMan;
@@ -80,7 +79,7 @@ static NSMutableSet* hostList;
// Capture the host here because it can change once we // Capture the host here because it can change once we
// leave the main thread // leave the main thread
Host* host = _selectedHost; TemporaryHost* host = _selectedHost;
if ([host.appList count] > 0) { if ([host.appList count] > 0) {
usingCachedAppList = true; usingCachedAppList = true;
@@ -141,7 +140,7 @@ static NSMutableSet* hostList;
}); });
} else { } else {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self mergeAppLists:[appListResp getAppList] forHost:host]; [self updateApplist:[appListResp getAppList] forHost:host];
if (host != _selectedHost) { if (host != _selectedHost) {
return; return;
@@ -159,11 +158,12 @@ static NSMutableSet* hostList;
}); });
} }
- (void) mergeAppLists:(NSArray*) newList forHost:(Host*)host { - (void) updateApplist:(NSSet*) newList forHost:(TemporaryHost*)host {
DataManager* database = [[DataManager alloc] init]; DataManager* database = [[DataManager alloc] init];
for (TemporaryApp* app in newList) { for (TemporaryApp* app in newList) {
BOOL appAlreadyInList = NO; BOOL appAlreadyInList = NO;
for (App* savedApp in host.appList) { for (TemporaryApp* savedApp in host.appList) {
if ([app.id isEqualToString:savedApp.id]) { if ([app.id isEqualToString:savedApp.id]) {
savedApp.name = app.name; savedApp.name = app.name;
savedApp.isRunning = app.isRunning; savedApp.isRunning = app.isRunning;
@@ -173,7 +173,7 @@ static NSMutableSet* hostList;
} }
if (!appAlreadyInList) { if (!appAlreadyInList) {
app.host = host; app.host = host;
[database addAppFromTemporaryApp:app]; [host.appList addObject:app];
} }
} }
@@ -181,9 +181,9 @@ static NSMutableSet* hostList;
do { do {
appWasRemoved = NO; appWasRemoved = NO;
for (App* app in host.appList) { for (TemporaryApp* app in host.appList) {
appWasRemoved = YES; appWasRemoved = YES;
for (App* mergedApp in newList) { for (TemporaryApp* mergedApp in newList) {
if ([mergedApp.id isEqualToString:app.id]) { if ([mergedApp.id isEqualToString:app.id]) {
appWasRemoved = NO; appWasRemoved = NO;
break; break;
@@ -192,7 +192,14 @@ static NSMutableSet* hostList;
if (appWasRemoved) { if (appWasRemoved) {
// Removing the app mutates the list we're iterating (which isn't legal). // Removing the app mutates the list we're iterating (which isn't legal).
// We need to jump out of this loop and restart enumeration. // We need to jump out of this loop and restart enumeration.
[database removeAppFromHost:app];
[host.appList removeObject:app];
// It's important to remove the app record from the database
// since we'll have a constraint violation now that appList
// doesn't have this app in it.
[database removeApp:app];
break; break;
} }
} }
@@ -200,23 +207,25 @@ static NSMutableSet* hostList;
// Keep looping until the list is no longer being mutated // Keep looping until the list is no longer being mutated
} while (appWasRemoved); } while (appWasRemoved);
[database saveData]; [database updateAppsForExistingHost:host];
} }
- (void)showHostSelectionView { - (void)showHostSelectionView {
[_appManager stopRetrieving]; [_appManager stopRetrieving];
[[[DataManager alloc] init] saveData];
_selectedHost = nil; _selectedHost = nil;
_computerNameButton.title = @"No Host Selected"; _computerNameButton.title = @"No Host Selected";
[self.collectionView reloadData]; [self.collectionView reloadData];
[self.view addSubview:hostScrollView]; [self.view addSubview:hostScrollView];
} }
- (void) receivedAssetForApp:(App*)app { - (void) receivedAssetForApp:(TemporaryApp*)app {
// Update the box art cache now so we don't have to do it // Update the box art cache now so we don't have to do it
// on the main thread // on the main thread
[self updateBoxArtCacheForApp:app]; [self updateBoxArtCacheForApp:app];
DataManager* dataManager = [[DataManager alloc] init];
[dataManager updateIconForExistingApp: app];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData]; [self.collectionView reloadData];
}); });
@@ -230,7 +239,7 @@ static NSMutableSet* hostList;
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
} }
- (void) hostClicked:(Host *)host view:(UIView *)view { - (void) hostClicked:(TemporaryHost *)host view:(UIView *)view {
// Treat clicks on offline hosts to be long clicks // Treat clicks on offline hosts to be long clicks
// This shows the context menu with wake, delete, etc. rather // This shows the context menu with wake, delete, etc. rather
// than just hanging for a while and failing as we would in this // than just hanging for a while and failing as we would in this
@@ -296,7 +305,7 @@ static NSMutableSet* hostList;
}); });
} }
- (void)hostLongClicked:(Host *)host view:(UIView *)view { - (void)hostLongClicked:(TemporaryHost *)host view:(UIView *)view {
Log(LOG_D, @"Long clicked host: %@", host.name); Log(LOG_D, @"Long clicked host: %@", host.name);
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
if (!host.online) { if (!host.online) {
@@ -322,8 +331,8 @@ static NSMutableSet* hostList;
[dataMan removeHost:host]; [dataMan removeHost:host];
@synchronized(hostList) { @synchronized(hostList) {
[hostList removeObject:host]; [hostList removeObject:host];
[self updateAllHosts:[hostList allObjects]];
} }
[self updateAllHosts:[hostList allObjects]];
}]]; }]];
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; [longClickAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
@@ -345,10 +354,8 @@ static NSMutableSet* hostList;
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text; NSString* hostAddress = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){ [_discMan discoverHost:hostAddress withCallback:^(TemporaryHost* host, NSString* error){
if (host != nil) { if (host != nil) {
DataManager* dataMan = [[DataManager alloc] init];
[dataMan saveData];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@synchronized(hostList) { @synchronized(hostList) {
[hostList addObject:host]; [hostList addObject:host];
@@ -369,14 +376,14 @@ static NSMutableSet* hostList;
[self presentViewController:alertController animated:YES completion:nil]; [self presentViewController:alertController animated:YES completion:nil];
} }
- (void) appClicked:(App *)app { - (void) appClicked:(TemporaryApp *)app {
Log(LOG_D, @"Clicked app: %@", app.name); Log(LOG_D, @"Clicked app: %@", app.name);
_streamConfig = [[StreamConfiguration alloc] init]; _streamConfig = [[StreamConfiguration alloc] init];
_streamConfig.host = app.host.activeAddress; _streamConfig.host = app.host.activeAddress;
_streamConfig.appID = app.id; _streamConfig.appID = app.id;
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
Settings* streamSettings = [dataMan retrieveSettings]; TemporarySettings* streamSettings = [dataMan getSettings];
_streamConfig.frameRate = [streamSettings.framerate intValue]; _streamConfig.frameRate = [streamSettings.framerate intValue];
_streamConfig.bitRate = [streamSettings.bitrate intValue]; _streamConfig.bitRate = [streamSettings.bitrate intValue];
@@ -389,7 +396,7 @@ static NSMutableSet* hostList;
[[self revealViewController] revealToggle:self]; [[self revealViewController] revealToggle:self];
} }
App* currentApp = [self findRunningApp:app.host]; TemporaryApp* currentApp = [self findRunningApp:app.host];
if (currentApp != nil) { if (currentApp != nil) {
UIAlertController* alertController = [UIAlertController UIAlertController* alertController = [UIAlertController
alertControllerWithTitle: app.name alertControllerWithTitle: app.name
@@ -455,8 +462,8 @@ static NSMutableSet* hostList;
} }
} }
- (App*) findRunningApp:(Host*)host { - (TemporaryApp*) findRunningApp:(TemporaryHost*)host {
for (App* app in host.appList) { for (TemporaryApp* app in host.appList) {
if (app.isRunning) { if (app.isRunning) {
return app; return app;
} }
@@ -593,19 +600,16 @@ static NSMutableSet* hostList;
// Purge the box art cache // Purge the box art cache
[_boxArtCache removeAllObjects]; [_boxArtCache removeAllObjects];
// In case the host objects were updated in the background
[[[DataManager alloc] init] saveData];
} }
- (void) retrieveSavedHosts { - (void) retrieveSavedHosts {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
NSArray* hosts = [dataMan retrieveHosts]; NSArray* hosts = [dataMan getHosts];
@synchronized(hostList) { @synchronized(hostList) {
[hostList addObjectsFromArray:hosts]; [hostList addObjectsFromArray:hosts];
// Initialize the non-persistent host state // Initialize the non-persistent host state
for (Host* host in hostList) { for (TemporaryHost* host in hostList) {
if (host.activeAddress == nil) { if (host.activeAddress == nil) {
host.activeAddress = host.localAddress; host.activeAddress = host.localAddress;
} }
@@ -622,7 +626,7 @@ static NSMutableSet* hostList;
- (void) updateAllHosts:(NSArray *)hosts { - (void) updateAllHosts:(NSArray *)hosts {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
Log(LOG_D, @"New host list:"); Log(LOG_D, @"New host list:");
for (Host* host in hosts) { for (TemporaryHost* host in hosts) {
Log(LOG_D, @"Host: \n{\n\t name:%@ \n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online, host.activeAddress); Log(LOG_D, @"Host: \n{\n\t name:%@ \n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online, host.activeAddress);
} }
@synchronized(hostList) { @synchronized(hostList) {
@@ -642,7 +646,7 @@ static NSMutableSet* hostList;
@synchronized (hostList) { @synchronized (hostList) {
// Sort the host list in alphabetical order // Sort the host list in alphabetical order
NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)]; NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)];
for (Host* comp in sortedHostList) { for (TemporaryHost* comp in sortedHostList) {
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self]; compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2); compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
prevEdge = compView.frame.origin.x + compView.frame.size.width; prevEdge = compView.frame.origin.x + compView.frame.size.width;
@@ -667,7 +671,7 @@ static NSMutableSet* hostList;
// This function forces immediate decoding of the UIImage, rather // This function forces immediate decoding of the UIImage, rather
// than the default lazy decoding that results in janky scrolling. // than the default lazy decoding that results in janky scrolling.
+ (UIImage*) loadBoxArtForCaching:(App*)app { + (UIImage*) loadBoxArtForCaching:(TemporaryApp*)app {
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)app.image, NULL); CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)app.image, NULL);
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: (id)kCFBooleanTrue}); CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: (id)kCFBooleanTrue});
@@ -680,7 +684,7 @@ static NSMutableSet* hostList;
return boxArt; return boxArt;
} }
- (void) updateBoxArtCacheForApp:(App*)app { - (void) updateBoxArtCacheForApp:(TemporaryApp*)app {
if (app.image == nil) { if (app.image == nil) {
[_boxArtCache removeObjectForKey:app]; [_boxArtCache removeObjectForKey:app];
} }
@@ -689,7 +693,7 @@ static NSMutableSet* hostList;
} }
} }
- (void) updateAppsForHost:(Host*)host { - (void) updateAppsForHost:(TemporaryHost*)host {
if (host != _selectedHost) { if (host != _selectedHost) {
Log(LOG_W, @"Mismatched host during app update"); Log(LOG_W, @"Mismatched host during app update");
return; return;
@@ -715,12 +719,12 @@ static NSMutableSet* hostList;
// Start 2 jobs // Start 2 jobs
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (App* app in firstHalf) { for (TemporaryApp* app in firstHalf) {
[self updateBoxArtCacheForApp:app]; [self updateBoxArtCacheForApp:app];
} }
}); });
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (App* app in secondHalf) { for (TemporaryApp* app in secondHalf) {
[self updateBoxArtCacheForApp:app]; [self updateBoxArtCacheForApp:app];
} }
}); });
@@ -732,7 +736,7 @@ static NSMutableSet* hostList;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath]; UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
App* app = _sortedAppList[indexPath.row]; TemporaryApp* app = _sortedAppList[indexPath.row];
UIAppView* appView = [[UIAppView alloc] initWithApp:app cache:_boxArtCache andCallback:self]; UIAppView* appView = [[UIAppView alloc] initWithApp:app cache:_boxArtCache andCallback:self];
[appView updateAppImage]; [appView updateAppImage];
@@ -7,7 +7,7 @@
// //
#import "SettingsViewController.h" #import "SettingsViewController.h"
#import "Settings.h" #import "TemporarySettings.h"
#import "DataManager.h" #import "DataManager.h"
#define BITRATE_INTERVAL 500 // in kbps #define BITRATE_INTERVAL 500 // in kbps
@@ -22,7 +22,7 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
[super viewDidLoad]; [super viewDidLoad];
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
Settings* currentSettings = [dataMan retrieveSettings]; TemporarySettings* currentSettings = [dataMan getSettings];
// Bitrate is persisted in kbps // Bitrate is persisted in kbps
_bitrate = [currentSettings.bitrate integerValue]; _bitrate = [currentSettings.bitrate integerValue];
+12
View File
@@ -9,6 +9,8 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */; }; 9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */; };
987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */; }; 987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */; };
98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */; };
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */; };
9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; }; 9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; };
9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; }; 9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; };
9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; }; 9E5D600E1A5A5A3900689918 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */; };
@@ -98,6 +100,10 @@
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryApp.h; path = Database/TemporaryApp.h; sourceTree = "<group>"; }; 9832D1341BBCD5C50036EF48 /* TemporaryApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryApp.h; path = Database/TemporaryApp.h; sourceTree = "<group>"; };
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryApp.m; path = Database/TemporaryApp.m; sourceTree = "<group>"; }; 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryApp.m; path = Database/TemporaryApp.m; sourceTree = "<group>"; };
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "limelight-common-c/moonlight-common.xcodeproj"; sourceTree = "<group>"; }; 98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "limelight-common-c/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryHost.h; path = Database/TemporaryHost.h; sourceTree = "<group>"; };
98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryHost.m; path = Database/TemporaryHost.m; sourceTree = "<group>"; };
98D5856E1C0ED0E800F6CC00 /* TemporarySettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporarySettings.h; path = Database/TemporarySettings.h; sourceTree = "<group>"; };
98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporarySettings.m; path = Database/TemporarySettings.m; sourceTree = "<group>"; };
9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; }; 9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; };
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; }; 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; }; 9E5D5FFB1A5A5A3900689918 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = "<group>"; };
@@ -733,6 +739,10 @@
FBD349611A0089F6002D2A60 /* DataManager.m */, FBD349611A0089F6002D2A60 /* DataManager.m */,
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */, 9832D1341BBCD5C50036EF48 /* TemporaryApp.h */,
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */, 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */,
98D5856B1C0EA79600F6CC00 /* TemporaryHost.h */,
98D5856C1C0EA79600F6CC00 /* TemporaryHost.m */,
98D5856E1C0ED0E800F6CC00 /* TemporarySettings.h */,
98D5856F1C0ED0E800F6CC00 /* TemporarySettings.m */,
); );
name = Database; name = Database;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -855,11 +865,13 @@
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */, FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
FB89462B19F646E200339C8A /* StreamView.m in Sources */, FB89462B19F646E200339C8A /* StreamView.m in Sources */,
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */, FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */,
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */, FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */, FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */, FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */,
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */, FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */, 9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */,
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */,
FB89462819F646E200339C8A /* CryptoManager.m in Sources */, FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
FB89462E19F646E200339C8A /* PairManager.m in Sources */, FB89462E19F646E200339C8A /* PairManager.m in Sources */,
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */, FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
+7 -1
View File
@@ -2,7 +2,13 @@
#### Now available on the [App Store](https://itunes.apple.com/us/app/moonlight-game-streaming/id1000551566?mt=8) #### Now available on the [App Store](https://itunes.apple.com/us/app/moonlight-game-streaming/id1000551566?mt=8)
[Moonlight](https://github.com/moonlight-stream) 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 [Moonlight](http://moonlight-stream.com) 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
your powerful desktop computer to your iOS Device. your powerful desktop computer to your iOS Device.
There are also versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [PC](https://github.com/moonlight-stream/moonlight-pc). There are also versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [PC](https://github.com/moonlight-stream/moonlight-pc).
##### Apple TV Note:
We current cannot write a port for Apple TV due to a limitation in the tvOS SDK that prevents Moonlight from using the APIs that would be necessary for it to work. Thank you for your interest - you can track this issue [here](https://github.com/moonlight-stream/moonlight-ios/issues/184).
##### Questions?
Check out our [wiki](https://github.com/moonlight-stream/moonlight-android/wiki).