mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-10-22 16:17:20 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40a04eb08b | ||
|
|
e9cff8f7b7 | ||
|
|
acee0af9df | ||
|
|
8d3e81ed25 | ||
|
|
5f8b0672f7 | ||
|
|
62bbec3c5d | ||
|
|
65f7e75736 | ||
|
|
3617ea98e2 | ||
|
|
81c84597c8 | ||
|
|
ea231e16b6 | ||
|
|
c205b99080 | ||
|
|
e3dd4e7238 | ||
|
|
0c36754ebe | ||
|
|
e7dc22bb15 | ||
|
|
d4b5ec5764 | ||
|
|
bed8c729f9 | ||
|
|
0a767767fb | ||
|
|
e31df3f44e | ||
|
|
9c9795ab1f | ||
|
|
c7c28a18c5 | ||
|
|
93119f25a6 | ||
|
|
1313429f65 | ||
|
|
11c27baaf8 | ||
|
|
d728e63bb4 | ||
|
|
7d584fb4de | ||
|
|
7d7adb0753 | ||
|
|
337e5e3d9d | ||
|
|
879f304a79 | ||
|
|
75d3f23f0a | ||
|
|
14f30349a3 | ||
|
|
8e721a9c6a | ||
|
|
e3e95c29f6 |
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -38,6 +38,7 @@
|
|||||||
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678F91A55FFAD00377732 /* DiscoveryManager.m */; };
|
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678F91A55FFAD00377732 /* DiscoveryManager.m */; };
|
||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
||||||
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
||||||
|
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
|
||||||
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
|
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
|
||||||
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
||||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
||||||
@@ -58,7 +59,15 @@
|
|||||||
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E019F6AFB800339C8A /* libcrypto.a */; };
|
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E019F6AFB800339C8A /* libcrypto.a */; };
|
||||||
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E119F6AFB800339C8A /* libssl.a */; };
|
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E119F6AFB800339C8A /* libssl.a */; };
|
||||||
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; };
|
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; };
|
||||||
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppManager.m */; };
|
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD271A7C84ED00872C98 /* HttpResponse.m */; };
|
||||||
|
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */; };
|
||||||
|
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD361A7E02DB00872C98 /* HttpRequest.m */; };
|
||||||
|
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */; };
|
||||||
|
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */; };
|
||||||
|
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */; };
|
||||||
|
FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = FB9AFD421A7F0C6900872C98 /* Controller.m */; };
|
||||||
|
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD1C8E11A8AD71400C6703C /* Logger.m */; };
|
||||||
|
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; };
|
||||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
|
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
|
||||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
|
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
|
||||||
FBD3495B1A004411002D2A60 /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495A1A004411002D2A60 /* Host.m */; };
|
FBD3495B1A004411002D2A60 /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495A1A004411002D2A60 /* Host.m */; };
|
||||||
@@ -132,6 +141,8 @@
|
|||||||
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnLanManager.h; sourceTree = "<group>"; };
|
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnLanManager.h; sourceTree = "<group>"; };
|
||||||
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WakeOnLanManager.m; sourceTree = "<group>"; };
|
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WakeOnLanManager.m; sourceTree = "<group>"; };
|
||||||
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||||
|
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingFrameViewController.h; sourceTree = "<group>"; };
|
||||||
|
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingFrameViewController.m; sourceTree = "<group>"; };
|
||||||
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
|
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
|
||||||
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
|
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
|
||||||
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
|
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
@@ -247,8 +258,24 @@
|
|||||||
FB8946E719F6AFB800339C8A /* opus_multistream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_multistream.h; sourceTree = "<group>"; };
|
FB8946E719F6AFB800339C8A /* opus_multistream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_multistream.h; sourceTree = "<group>"; };
|
||||||
FB8946E819F6AFB800339C8A /* opus_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_types.h; sourceTree = "<group>"; };
|
FB8946E819F6AFB800339C8A /* opus_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_types.h; sourceTree = "<group>"; };
|
||||||
FB8946EA19F6AFB800339C8A /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libopus.a; sourceTree = "<group>"; };
|
FB8946EA19F6AFB800339C8A /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libopus.a; sourceTree = "<group>"; };
|
||||||
FBD3494119FC9C04002D2A60 /* AppManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppManager.h; sourceTree = "<group>"; };
|
FB9AFD261A7C84ED00872C98 /* HttpResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpResponse.h; sourceTree = "<group>"; };
|
||||||
FBD3494219FC9C04002D2A60 /* AppManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppManager.m; sourceTree = "<group>"; };
|
FB9AFD271A7C84ED00872C98 /* HttpResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpResponse.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetRetriever.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetRetriever.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ServerInfoResponse.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ServerInfoResponse.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetResponse.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetResponse.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppListResponse.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
||||||
|
FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
||||||
|
FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
||||||
|
FBD1C8E01A8AD69E00C6703C /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = "<group>"; };
|
||||||
|
FBD1C8E11A8AD71400C6703C /* Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logger.m; sourceTree = "<group>"; };
|
||||||
|
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
|
||||||
|
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppAssetManager.m; sourceTree = "<group>"; };
|
||||||
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
||||||
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
||||||
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
|
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
|
||||||
@@ -442,6 +469,8 @@
|
|||||||
children = (
|
children = (
|
||||||
FB89460A19F646E200339C8A /* ControllerSupport.h */,
|
FB89460A19F646E200339C8A /* ControllerSupport.h */,
|
||||||
FB89460B19F646E200339C8A /* ControllerSupport.m */,
|
FB89460B19F646E200339C8A /* ControllerSupport.m */,
|
||||||
|
FB9AFD411A7F0C6900872C98 /* Controller.h */,
|
||||||
|
FB9AFD421A7F0C6900872C98 /* Controller.m */,
|
||||||
FB89460C19F646E200339C8A /* StreamView.h */,
|
FB89460C19F646E200339C8A /* StreamView.h */,
|
||||||
FB89460D19F646E200339C8A /* StreamView.m */,
|
FB89460D19F646E200339C8A /* StreamView.m */,
|
||||||
FB4678EB1A50C40900377732 /* OnScreenControls.h */,
|
FB4678EB1A50C40900377732 /* OnScreenControls.h */,
|
||||||
@@ -453,20 +482,13 @@
|
|||||||
FB89460E19F646E200339C8A /* Network */ = {
|
FB89460E19F646E200339C8A /* Network */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FB89460F19F646E200339C8A /* HttpManager.h */,
|
FB9AFD2F1A7C979700872C98 /* Http */,
|
||||||
FB89461019F646E200339C8A /* HttpManager.m */,
|
FB9AFD341A7D877B00872C98 /* Discovery */,
|
||||||
FB89461119F646E200339C8A /* MDNSManager.h */,
|
FB9AFD331A7D876F00872C98 /* AppAsset */,
|
||||||
FB89461219F646E200339C8A /* MDNSManager.m */,
|
|
||||||
FB89461319F646E200339C8A /* PairManager.h */,
|
FB89461319F646E200339C8A /* PairManager.h */,
|
||||||
FB89461419F646E200339C8A /* PairManager.m */,
|
FB89461419F646E200339C8A /* PairManager.m */,
|
||||||
FBD3494119FC9C04002D2A60 /* AppManager.h */,
|
|
||||||
FBD3494219FC9C04002D2A60 /* AppManager.m */,
|
|
||||||
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
|
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
|
||||||
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */,
|
FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */,
|
||||||
FB4678F81A55FFAD00377732 /* DiscoveryManager.h */,
|
|
||||||
FB4678F91A55FFAD00377732 /* DiscoveryManager.m */,
|
|
||||||
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */,
|
|
||||||
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */,
|
|
||||||
);
|
);
|
||||||
path = Network;
|
path = Network;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -493,6 +515,8 @@
|
|||||||
FBDE86E819F82315001C18A8 /* App.m */,
|
FBDE86E819F82315001C18A8 /* App.m */,
|
||||||
FB89462119F646E200339C8A /* Utils.h */,
|
FB89462119F646E200339C8A /* Utils.h */,
|
||||||
FB89462219F646E200339C8A /* Utils.m */,
|
FB89462219F646E200339C8A /* Utils.m */,
|
||||||
|
FBD1C8E01A8AD69E00C6703C /* Logger.h */,
|
||||||
|
FBD1C8E11A8AD71400C6703C /* Logger.m */,
|
||||||
);
|
);
|
||||||
path = Utility;
|
path = Utility;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -508,6 +532,8 @@
|
|||||||
FB89462719F646E200339C8A /* StreamFrameViewController.m */,
|
FB89462719F646E200339C8A /* StreamFrameViewController.m */,
|
||||||
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */,
|
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */,
|
||||||
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */,
|
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */,
|
||||||
|
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */,
|
||||||
|
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */,
|
||||||
);
|
);
|
||||||
path = ViewControllers;
|
path = ViewControllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -673,6 +699,49 @@
|
|||||||
path = lib;
|
path = lib;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
FB9AFD2F1A7C979700872C98 /* Http */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FB89460F19F646E200339C8A /* HttpManager.h */,
|
||||||
|
FB89461019F646E200339C8A /* HttpManager.m */,
|
||||||
|
FB9AFD351A7E02DB00872C98 /* HttpRequest.h */,
|
||||||
|
FB9AFD361A7E02DB00872C98 /* HttpRequest.m */,
|
||||||
|
FB9AFD261A7C84ED00872C98 /* HttpResponse.h */,
|
||||||
|
FB9AFD271A7C84ED00872C98 /* HttpResponse.m */,
|
||||||
|
FB9AFD381A7E05CE00872C98 /* ServerInfoResponse.h */,
|
||||||
|
FB9AFD391A7E05CE00872C98 /* ServerInfoResponse.m */,
|
||||||
|
FB9AFD3B1A7E111600872C98 /* AppAssetResponse.h */,
|
||||||
|
FB9AFD3C1A7E111600872C98 /* AppAssetResponse.m */,
|
||||||
|
FB9AFD3E1A7E127D00872C98 /* AppListResponse.h */,
|
||||||
|
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */,
|
||||||
|
);
|
||||||
|
name = Http;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FB9AFD331A7D876F00872C98 /* AppAsset */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */,
|
||||||
|
FBD3494219FC9C04002D2A60 /* AppAssetManager.m */,
|
||||||
|
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */,
|
||||||
|
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */,
|
||||||
|
);
|
||||||
|
name = AppAsset;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FB9AFD341A7D877B00872C98 /* Discovery */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FB4678F81A55FFAD00377732 /* DiscoveryManager.h */,
|
||||||
|
FB4678F91A55FFAD00377732 /* DiscoveryManager.m */,
|
||||||
|
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */,
|
||||||
|
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */,
|
||||||
|
FB89461119F646E200339C8A /* MDNSManager.h */,
|
||||||
|
FB89461219F646E200339C8A /* MDNSManager.m */,
|
||||||
|
);
|
||||||
|
name = Discovery;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
FBD3495F1A004453002D2A60 /* Database */ = {
|
FBD3495F1A004453002D2A60 /* Database */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -815,11 +884,14 @@
|
|||||||
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
|
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
|
||||||
FBD3495E1A004412002D2A60 /* Settings.m in Sources */,
|
FBD3495E1A004412002D2A60 /* Settings.m in Sources */,
|
||||||
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
|
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
|
||||||
|
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */,
|
||||||
FB89463419F646E200339C8A /* Utils.m in Sources */,
|
FB89463419F646E200339C8A /* Utils.m in Sources */,
|
||||||
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */,
|
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */,
|
||||||
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
||||||
|
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
||||||
FB89462919F646E200339C8A /* mkcert.c in Sources */,
|
FB89462919F646E200339C8A /* mkcert.c in Sources */,
|
||||||
|
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
|
||||||
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
|
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
|
||||||
FBDE86E919F82315001C18A8 /* App.m in Sources */,
|
FBDE86E919F82315001C18A8 /* App.m in Sources */,
|
||||||
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
||||||
@@ -831,15 +903,21 @@
|
|||||||
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
|
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
|
||||||
FBD3495B1A004411002D2A60 /* Host.m in Sources */,
|
FBD3495B1A004411002D2A60 /* Host.m in Sources */,
|
||||||
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
||||||
|
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
|
||||||
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
FB89463619F646E200339C8A /* StreamFrameViewController.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 */,
|
||||||
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
|
FB4678ED1A50C40900377732 /* OnScreenControls.m in Sources */,
|
||||||
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
||||||
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */,
|
FB9AFD431A7F0C6900872C98 /* Controller.m in Sources */,
|
||||||
|
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */,
|
||||||
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
|
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */,
|
||||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||||
|
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
||||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
||||||
|
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
|
||||||
|
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
|
||||||
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
// Replace this implementation with code to handle the error appropriately.
|
||||||
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||||
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
|
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
|
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
|
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ static NSData* p12 = nil;
|
|||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
|
|
||||||
if (!x509) {
|
if (!x509) {
|
||||||
NSLog(@"ERROR: unable to parse certificate in memory");
|
Log(LOG_E, @"Unable to parse certificate in memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ static NSData* p12 = nil;
|
|||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
|
|
||||||
if (!pkey) {
|
if (!pkey) {
|
||||||
NSLog(@"ERROR: unable to parse private key in memory!");
|
Log(LOG_E, @"Unable to parse private key in memory!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ static NSData* p12 = nil;
|
|||||||
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (!x509) {
|
if (!x509) {
|
||||||
NSLog(@"ERROR: unable to parse certificate in memory!");
|
Log(LOG_E, @"Unable to parse certificate in memory!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return [NSData dataWithBytes:x509->signature->data length:x509->signature->length];
|
return [NSData dataWithBytes:x509->signature->data length:x509->signature->length];
|
||||||
@@ -206,7 +206,7 @@ static NSData* p12 = nil;
|
|||||||
dispatch_once(&pred, ^{
|
dispatch_once(&pred, ^{
|
||||||
if (![CryptoManager keyPairExists]) {
|
if (![CryptoManager keyPairExists]) {
|
||||||
|
|
||||||
NSLog(@"Generating Certificate... ");
|
Log(LOG_I, @"Generating Certificate... ");
|
||||||
CertKeyPair certKeyPair = generateCertKeyPair();
|
CertKeyPair certKeyPair = generateCertKeyPair();
|
||||||
|
|
||||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||||
@@ -215,10 +215,10 @@ static NSData* p12 = nil;
|
|||||||
NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
|
NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
|
||||||
NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
|
NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
|
||||||
|
|
||||||
//NSLog(@"Writing cert and key to: \n%@\n%@", certFile, keyPairFile);
|
//Log(LOG_D, @"Writing cert and key to: \n%@\n%@", certFile, keyPairFile);
|
||||||
saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair);
|
saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair);
|
||||||
freeCertKeyPair(certKeyPair);
|
freeCertKeyPair(certKeyPair);
|
||||||
NSLog(@"Certificate created");
|
Log(LOG_I, @"Certificate created");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ static NSData* p12 = nil;
|
|||||||
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
|
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
|
||||||
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
|
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
|
||||||
|
|
||||||
//NSLog(@"Unique ID: %@", uniqueId);
|
//Log(LOG_D, @"Unique ID: %@", uniqueId);
|
||||||
return [NSString stringWithString:uniqueId];
|
return [NSString stringWithString:uniqueId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
Settings* settingsToSave = [self retrieveSettings];
|
Settings* settingsToSave = [self retrieveSettings];
|
||||||
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
||||||
// Bitrate is persisted in kbps
|
// Bitrate is persisted in kbps
|
||||||
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate * 1000];
|
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
|
||||||
settingsToSave.height = [NSNumber numberWithInteger:height];
|
settingsToSave.height = [NSNumber numberWithInteger:height];
|
||||||
settingsToSave.width = [NSNumber numberWithInteger:width];
|
settingsToSave.width = [NSNumber numberWithInteger:width];
|
||||||
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
|
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
|
||||||
|
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
||||||
NSLog(@"ERROR: Unable to save settings to database");
|
Log(LOG_E, @"Unable to save settings to database: %@", error);
|
||||||
}
|
}
|
||||||
[self.appDelegate saveContext];
|
[self.appDelegate saveContext];
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
- (void) saveHosts {
|
- (void) saveHosts {
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
||||||
NSLog(@"ERROR: Unable to save hosts to database");
|
Log(LOG_E, @"Unable to save hosts to database: %@", error);
|
||||||
}
|
}
|
||||||
[self.appDelegate saveContext];
|
[self.appDelegate saveContext];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Controller.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Controller : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic) int playerIndex;
|
||||||
|
@property (nonatomic) int lastButtonFlags;
|
||||||
|
@property (nonatomic) int emulatingButtonFlags;
|
||||||
|
@property (nonatomic) char lastLeftTrigger;
|
||||||
|
@property (nonatomic) char lastRightTrigger;
|
||||||
|
@property (nonatomic) short lastLeftStickX;
|
||||||
|
@property (nonatomic) short lastLeftStickY;
|
||||||
|
@property (nonatomic) short lastRightStickX;
|
||||||
|
@property (nonatomic) short lastRightStickY;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Controller.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "Controller.h"
|
||||||
|
|
||||||
|
@implementation Controller
|
||||||
|
@synthesize playerIndex;
|
||||||
|
@synthesize lastButtonFlags, emulatingButtonFlags, lastLeftTrigger, lastRightTrigger;
|
||||||
|
@synthesize lastLeftStickX, lastLeftStickY, lastRightStickX, lastRightStickY;
|
||||||
|
@end
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Controller.h"
|
||||||
|
|
||||||
@class OnScreenControls;
|
@class OnScreenControls;
|
||||||
|
|
||||||
@@ -16,18 +17,18 @@
|
|||||||
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc;
|
-(void) initAutoOnScreenControlMode:(OnScreenControls*)osc;
|
||||||
-(void) cleanup;
|
-(void) cleanup;
|
||||||
|
|
||||||
-(void) updateLeftStick:(short)x y:(short)y;
|
-(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y;
|
||||||
-(void) updateRightStick:(short)x y:(short)y;
|
-(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y;
|
||||||
|
|
||||||
-(void) updateLeftTrigger:(char)left;
|
-(void) updateLeftTrigger:(Controller*)controller left:(char)left;
|
||||||
-(void) updateRightTrigger:(char)right;
|
-(void) updateRightTrigger:(Controller*)controller right:(char)right;
|
||||||
-(void) updateTriggers:(char)left right:(char)right;
|
-(void) updateTriggers:(Controller*)controller left:(char)left right:(char)right;
|
||||||
|
|
||||||
-(void) updateButtonFlags:(int)flags;
|
-(void) updateButtonFlags:(Controller*)controller flags:(int)flags;
|
||||||
-(void) setButtonFlag:(int)flags;
|
-(void) setButtonFlag:(Controller*)controller flags:(int)flags;
|
||||||
-(void) clearButtonFlag:(int)flags;
|
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags;
|
||||||
|
|
||||||
-(void) updateFinished;
|
-(void) updateFinished:(Controller*)controller;
|
||||||
|
|
||||||
@property (nonatomic, strong) id connectObserver;
|
@property (nonatomic, strong) id connectObserver;
|
||||||
@property (nonatomic, strong) id disconnectObserver;
|
@property (nonatomic, strong) id disconnectObserver;
|
||||||
|
|||||||
+212
-195
@@ -8,238 +8,228 @@
|
|||||||
|
|
||||||
#import "ControllerSupport.h"
|
#import "ControllerSupport.h"
|
||||||
#import "OnScreenControls.h"
|
#import "OnScreenControls.h"
|
||||||
|
#import "Controller.h"
|
||||||
#include "Limelight.h"
|
#include "Limelight.h"
|
||||||
|
|
||||||
@import GameController;
|
@import GameController;
|
||||||
|
|
||||||
@implementation ControllerSupport {
|
@implementation ControllerSupport {
|
||||||
NSLock *_controllerValueLock;
|
|
||||||
NSLock *_controllerStreamLock;
|
NSLock *_controllerStreamLock;
|
||||||
|
NSMutableDictionary *_controllers;
|
||||||
|
|
||||||
OnScreenControls *_osc;
|
OnScreenControls *_osc;
|
||||||
|
|
||||||
int _lastButtonFlags;
|
char _controllerNumbers;
|
||||||
char _lastLeftTrigger, _lastRightTrigger;
|
|
||||||
short _lastLeftStickX, _lastLeftStickY;
|
|
||||||
short _lastRightStickX, _lastRightStickY;
|
|
||||||
|
|
||||||
#define EMULATING_SELECT 0x1
|
#define EMULATING_SELECT 0x1
|
||||||
#define EMULATING_SPECIAL 0x2
|
#define EMULATING_SPECIAL 0x2
|
||||||
int _emulatingButtonFlags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UPDATE_BUTTON_FLAG(flag, pressed)
|
// UPDATE_BUTTON_FLAG(controller, flag, pressed)
|
||||||
#define UPDATE_BUTTON_FLAG(x, y) \
|
#define UPDATE_BUTTON_FLAG(controller, x, y) \
|
||||||
((y) ? [self setButtonFlag:x] : [self clearButtonFlag:x])
|
((y) ? [self setButtonFlag:controller flags:x] : [self clearButtonFlag:controller flags:x])
|
||||||
|
|
||||||
-(void) updateLeftStick:(short)x y:(short)y
|
-(void) updateLeftStick:(Controller*)controller x:(short)x y:(short)y
|
||||||
{
|
{
|
||||||
[_controllerValueLock lock];
|
@synchronized(controller) {
|
||||||
_lastLeftStickX = x;
|
controller.lastLeftStickX = x;
|
||||||
_lastLeftStickY = y;
|
controller.lastLeftStickY = y;
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) updateRightStick:(short)x y:(short)y
|
|
||||||
{
|
|
||||||
[_controllerValueLock lock];
|
|
||||||
_lastRightStickX = x;
|
|
||||||
_lastRightStickY = y;
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) updateLeftTrigger:(char)left
|
|
||||||
{
|
|
||||||
[_controllerValueLock lock];
|
|
||||||
_lastLeftTrigger = left;
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) updateRightTrigger:(char)right
|
|
||||||
{
|
|
||||||
[_controllerValueLock lock];
|
|
||||||
_lastRightTrigger = right;
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) updateTriggers:(char)left right:(char)right
|
|
||||||
{
|
|
||||||
[_controllerValueLock lock];
|
|
||||||
_lastLeftTrigger = left;
|
|
||||||
_lastRightTrigger = right;
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) handleSpecialCombosReleased:(int)releasedButtons
|
|
||||||
{
|
|
||||||
if ((_emulatingButtonFlags & EMULATING_SELECT) &&
|
|
||||||
((releasedButtons & LB_FLAG) || (releasedButtons & PLAY_FLAG))) {
|
|
||||||
_lastButtonFlags &= ~BACK_FLAG;
|
|
||||||
_emulatingButtonFlags &= ~EMULATING_SELECT;
|
|
||||||
}
|
}
|
||||||
if ((_emulatingButtonFlags & EMULATING_SPECIAL) &&
|
}
|
||||||
|
|
||||||
|
-(void) updateRightStick:(Controller*)controller x:(short)x y:(short)y
|
||||||
|
{
|
||||||
|
@synchronized(controller) {
|
||||||
|
controller.lastRightStickX = x;
|
||||||
|
controller.lastRightStickY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) updateLeftTrigger:(Controller*)controller left:(char)left
|
||||||
|
{
|
||||||
|
@synchronized(controller) {
|
||||||
|
controller.lastLeftTrigger = left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) updateRightTrigger:(Controller*)controller right:(char)right
|
||||||
|
{
|
||||||
|
@synchronized(controller) {
|
||||||
|
controller.lastRightTrigger = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) updateTriggers:(Controller*) controller left:(char)left right:(char)right
|
||||||
|
{
|
||||||
|
@synchronized(controller) {
|
||||||
|
controller.lastLeftTrigger = left;
|
||||||
|
controller.lastRightTrigger = right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) handleSpecialCombosReleased:(Controller*)controller releasedButtons:(int)releasedButtons
|
||||||
|
{
|
||||||
|
if ((controller.emulatingButtonFlags & EMULATING_SELECT) &&
|
||||||
|
((releasedButtons & LB_FLAG) || (releasedButtons & PLAY_FLAG))) {
|
||||||
|
controller.lastButtonFlags &= ~BACK_FLAG;
|
||||||
|
controller.emulatingButtonFlags &= ~EMULATING_SELECT;
|
||||||
|
}
|
||||||
|
if ((controller.emulatingButtonFlags & EMULATING_SPECIAL) &&
|
||||||
((releasedButtons & RB_FLAG) || (releasedButtons & PLAY_FLAG) ||
|
((releasedButtons & RB_FLAG) || (releasedButtons & PLAY_FLAG) ||
|
||||||
(releasedButtons & BACK_FLAG))) {
|
(releasedButtons & BACK_FLAG))) {
|
||||||
_lastButtonFlags &= ~SPECIAL_FLAG;
|
controller.lastButtonFlags &= ~SPECIAL_FLAG;
|
||||||
_emulatingButtonFlags &= ~EMULATING_SPECIAL;
|
controller.emulatingButtonFlags &= ~EMULATING_SPECIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) handleSpecialCombosPressed:(int)pressedButtons
|
-(void) handleSpecialCombosPressed:(Controller*)controller pressedButtons:(int)pressedButtons
|
||||||
{
|
{
|
||||||
// Special button combos for select and special
|
// Special button combos for select and special
|
||||||
if (_lastButtonFlags & PLAY_FLAG) {
|
if (controller.lastButtonFlags & PLAY_FLAG) {
|
||||||
// If LB and start are down, trigger select
|
// If LB and start are down, trigger select
|
||||||
if (_lastButtonFlags & LB_FLAG) {
|
if (controller.lastButtonFlags & LB_FLAG) {
|
||||||
_lastButtonFlags |= BACK_FLAG;
|
controller.lastButtonFlags |= BACK_FLAG;
|
||||||
_lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG));
|
controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | LB_FLAG));
|
||||||
_emulatingButtonFlags |= EMULATING_SELECT;
|
controller.emulatingButtonFlags |= EMULATING_SELECT;
|
||||||
}
|
}
|
||||||
// If (RB or select) and start are down, trigger special
|
// If (RB or select) and start are down, trigger special
|
||||||
else if ((_lastButtonFlags & RB_FLAG) || (_lastButtonFlags & BACK_FLAG)) {
|
else if ((controller.lastButtonFlags & RB_FLAG) || (controller.lastButtonFlags & BACK_FLAG)) {
|
||||||
_lastButtonFlags |= SPECIAL_FLAG;
|
controller.lastButtonFlags |= SPECIAL_FLAG;
|
||||||
_lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG));
|
controller.lastButtonFlags &= ~(pressedButtons & (PLAY_FLAG | RB_FLAG | BACK_FLAG));
|
||||||
_emulatingButtonFlags |= EMULATING_SPECIAL;
|
controller.emulatingButtonFlags |= EMULATING_SPECIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) updateButtonFlags:(Controller*)controller flags:(int)flags
|
||||||
|
{
|
||||||
|
@synchronized(controller) {
|
||||||
|
int releasedButtons = (controller.lastButtonFlags ^ flags) & ~flags;
|
||||||
|
int pressedButtons = (controller.lastButtonFlags ^ flags) & flags;
|
||||||
|
|
||||||
|
controller.lastButtonFlags = flags;
|
||||||
|
|
||||||
|
// This must be called before handleSpecialCombosPressed
|
||||||
|
// because we clear the original button flags there
|
||||||
|
[self handleSpecialCombosReleased:controller releasedButtons:releasedButtons];
|
||||||
|
|
||||||
|
[self handleSpecialCombosPressed:controller pressedButtons:pressedButtons];
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) updateButtonFlags:(int)flags
|
-(void) setButtonFlag:(Controller*)controller flags:(int)flags
|
||||||
{
|
{
|
||||||
[_controllerValueLock lock];
|
@synchronized(controller) {
|
||||||
int releasedButtons = (_lastButtonFlags ^ flags) & ~flags;
|
controller.lastButtonFlags |= flags;
|
||||||
int pressedButtons = (_lastButtonFlags ^ flags) & flags;
|
[self handleSpecialCombosPressed:controller pressedButtons:flags];
|
||||||
|
}
|
||||||
_lastButtonFlags = flags;
|
|
||||||
|
|
||||||
// This must be called before handleSpecialCombosPressed
|
|
||||||
// because we clear the original button flags there
|
|
||||||
[self handleSpecialCombosReleased: releasedButtons];
|
|
||||||
|
|
||||||
[self handleSpecialCombosPressed: pressedButtons];
|
|
||||||
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) setButtonFlag:(int)flags
|
-(void) clearButtonFlag:(Controller*)controller flags:(int)flags
|
||||||
{
|
{
|
||||||
[_controllerValueLock lock];
|
@synchronized(controller) {
|
||||||
_lastButtonFlags |= flags;
|
controller.lastButtonFlags &= ~flags;
|
||||||
[self handleSpecialCombosPressed: flags];
|
[self handleSpecialCombosReleased:controller releasedButtons:flags];
|
||||||
[_controllerValueLock unlock];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) clearButtonFlag:(int)flags
|
-(void) updateFinished:(Controller*)controller
|
||||||
{
|
|
||||||
[_controllerValueLock lock];
|
|
||||||
_lastButtonFlags &= ~flags;
|
|
||||||
[self handleSpecialCombosReleased: flags];
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) updateFinished
|
|
||||||
{
|
{
|
||||||
[_controllerStreamLock lock];
|
[_controllerStreamLock lock];
|
||||||
[_controllerValueLock lock];
|
@synchronized(controller) {
|
||||||
|
LiSendMultiControllerEvent(controller.playerIndex, controller.lastButtonFlags, controller.lastLeftTrigger, controller.lastRightTrigger, controller.lastLeftStickX, controller.lastLeftStickY, controller.lastRightStickX, controller.lastRightStickY);
|
||||||
LiSendControllerEvent(_lastButtonFlags, _lastLeftTrigger, _lastRightTrigger, _lastLeftStickX, _lastLeftStickY, _lastRightStickX, _lastRightStickY);
|
}
|
||||||
|
|
||||||
[_controllerValueLock unlock];
|
|
||||||
[_controllerStreamLock unlock];
|
[_controllerStreamLock unlock];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) unregisterControllerCallbacks
|
-(void) unregisterControllerCallbacks:(GCController*) controller
|
||||||
{
|
{
|
||||||
for (int i = 0; i < [[GCController controllers] count]; i++) {
|
if (controller != NULL) {
|
||||||
GCController *controller = [GCController controllers][i];
|
controller.controllerPausedHandler = NULL;
|
||||||
|
|
||||||
if (controller != NULL) {
|
if (controller.extendedGamepad != NULL) {
|
||||||
controller.controllerPausedHandler = NULL;
|
controller.extendedGamepad.valueChangedHandler = NULL;
|
||||||
|
}
|
||||||
if (controller.extendedGamepad != NULL) {
|
else if (controller.gamepad != NULL) {
|
||||||
controller.extendedGamepad.valueChangedHandler = NULL;
|
controller.gamepad.valueChangedHandler = NULL;
|
||||||
}
|
|
||||||
else if (controller.gamepad != NULL) {
|
|
||||||
controller.gamepad.valueChangedHandler = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) registerControllerCallbacks
|
-(void) registerControllerCallbacks:(GCController*) controller
|
||||||
{
|
{
|
||||||
for (int i = 0; i < [[GCController controllers] count]; i++) {
|
if (controller != NULL) {
|
||||||
GCController *controller = [GCController controllers][i];
|
controller.controllerPausedHandler = ^(GCController *controller) {
|
||||||
|
Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||||
if (controller != NULL) {
|
[self setButtonFlag:limeController flags:PLAY_FLAG];
|
||||||
NSLog(@"Controller connected!");
|
[self updateFinished:limeController];
|
||||||
controller.controllerPausedHandler = ^(GCController *controller) {
|
|
||||||
[self setButtonFlag:PLAY_FLAG];
|
|
||||||
[self updateFinished];
|
|
||||||
|
|
||||||
// Pause for 100 ms
|
|
||||||
usleep(100 * 1000);
|
|
||||||
|
|
||||||
[self clearButtonFlag:PLAY_FLAG];
|
|
||||||
[self updateFinished];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (controller.extendedGamepad != NULL) {
|
// Pause for 100 ms
|
||||||
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) {
|
usleep(100 * 1000);
|
||||||
short leftStickX, leftStickY;
|
|
||||||
short rightStickX, rightStickY;
|
[self clearButtonFlag:limeController flags:PLAY_FLAG];
|
||||||
char leftTrigger, rightTrigger;
|
[self updateFinished:limeController];
|
||||||
|
};
|
||||||
UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed);
|
if (controller.extendedGamepad != NULL) {
|
||||||
UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed);
|
controller.extendedGamepad.valueChangedHandler = ^(GCExtendedGamepad *gamepad, GCControllerElement *element) {
|
||||||
UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed);
|
Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]];
|
||||||
|
short leftStickX, leftStickY;
|
||||||
UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed);
|
short rightStickX, rightStickY;
|
||||||
UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed);
|
char leftTrigger, rightTrigger;
|
||||||
UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed);
|
UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed);
|
||||||
UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed);
|
UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed);
|
||||||
UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed);
|
UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed);
|
||||||
|
|
||||||
leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE;
|
UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed);
|
||||||
leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE;
|
UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed);
|
||||||
rightStickX = gamepad.rightThumbstick.xAxis.value * 0x7FFE;
|
UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed);
|
||||||
rightStickY = gamepad.rightThumbstick.yAxis.value * 0x7FFE;
|
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed);
|
||||||
leftTrigger = gamepad.leftTrigger.value * 0xFF;
|
UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed);
|
||||||
rightTrigger = gamepad.rightTrigger.value * 0xFF;
|
|
||||||
|
leftStickX = gamepad.leftThumbstick.xAxis.value * 0x7FFE;
|
||||||
[self updateLeftStick:leftStickX y:leftStickY];
|
leftStickY = gamepad.leftThumbstick.yAxis.value * 0x7FFE;
|
||||||
[self updateRightStick:rightStickX y:rightStickY];
|
|
||||||
[self updateTriggers:leftTrigger right:rightTrigger];
|
rightStickX = gamepad.rightThumbstick.xAxis.value * 0x7FFE;
|
||||||
[self updateFinished];
|
rightStickY = gamepad.rightThumbstick.yAxis.value * 0x7FFE;
|
||||||
};
|
|
||||||
}
|
leftTrigger = gamepad.leftTrigger.value * 0xFF;
|
||||||
else if (controller.gamepad != NULL) {
|
rightTrigger = gamepad.rightTrigger.value * 0xFF;
|
||||||
controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) {
|
|
||||||
|
[self updateLeftStick:limeController x:leftStickX y:leftStickY];
|
||||||
UPDATE_BUTTON_FLAG(A_FLAG, gamepad.buttonA.pressed);
|
[self updateRightStick:limeController x:rightStickX y:rightStickY];
|
||||||
UPDATE_BUTTON_FLAG(B_FLAG, gamepad.buttonB.pressed);
|
[self updateTriggers:limeController left:leftTrigger right:rightTrigger];
|
||||||
UPDATE_BUTTON_FLAG(X_FLAG, gamepad.buttonX.pressed);
|
[self updateFinished:limeController];
|
||||||
UPDATE_BUTTON_FLAG(Y_FLAG, gamepad.buttonY.pressed);
|
};
|
||||||
|
|
||||||
UPDATE_BUTTON_FLAG(UP_FLAG, gamepad.dpad.up.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(DOWN_FLAG, gamepad.dpad.down.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(LEFT_FLAG, gamepad.dpad.left.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(RIGHT_FLAG, gamepad.dpad.right.pressed);
|
|
||||||
|
|
||||||
UPDATE_BUTTON_FLAG(LB_FLAG, gamepad.leftShoulder.pressed);
|
|
||||||
UPDATE_BUTTON_FLAG(RB_FLAG, gamepad.rightShoulder.pressed);
|
|
||||||
|
|
||||||
[self updateFinished];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (controller.gamepad != NULL) {
|
||||||
|
controller.gamepad.valueChangedHandler = ^(GCGamepad *gamepad, GCControllerElement *element) {
|
||||||
|
Controller* limeController = [_controllers objectForKey:[NSNumber numberWithInteger:gamepad.controller.playerIndex]];
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, A_FLAG, gamepad.buttonA.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, B_FLAG, gamepad.buttonB.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, X_FLAG, gamepad.buttonX.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, Y_FLAG, gamepad.buttonY.pressed);
|
||||||
|
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, UP_FLAG, gamepad.dpad.up.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, DOWN_FLAG, gamepad.dpad.down.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, LEFT_FLAG, gamepad.dpad.left.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, RIGHT_FLAG, gamepad.dpad.right.pressed);
|
||||||
|
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, LB_FLAG, gamepad.leftShoulder.pressed);
|
||||||
|
UPDATE_BUTTON_FLAG(limeController, RB_FLAG, gamepad.rightShoulder.pressed);
|
||||||
|
|
||||||
|
[self updateFinished:limeController];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log(LOG_W, @"Tried to register controller callbacks on NULL controller");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) updateAutoOnScreenControlMode
|
-(void) updateAutoOnScreenControlMode
|
||||||
@@ -278,37 +268,61 @@
|
|||||||
[self updateAutoOnScreenControlMode];
|
[self updateAutoOnScreenControlMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void) assignController:(GCController*)controller {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (!(_controllerNumbers & (1 << i))) {
|
||||||
|
_controllerNumbers |= (1 << i);
|
||||||
|
Controller* limeController = [[Controller alloc] init];
|
||||||
|
controller.playerIndex = i;
|
||||||
|
limeController.playerIndex = i;
|
||||||
|
[_controllers setObject:limeController forKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||||
|
|
||||||
|
Log(LOG_I, @"Assigning controller index: %d", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
-(id) init
|
-(id) init
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
_controllerStreamLock = [[NSLock alloc] init];
|
_controllerStreamLock = [[NSLock alloc] init];
|
||||||
_controllerValueLock = [[NSLock alloc] init];
|
_controllers = [[NSMutableDictionary alloc] init];
|
||||||
|
_controllerNumbers = 0;
|
||||||
|
|
||||||
|
Log(LOG_I, @"Number of controllers connected: %ld", (long)[[GCController controllers] count]);
|
||||||
|
for (GCController* controller in [GCController controllers]) {
|
||||||
|
[self assignController:controller];
|
||||||
|
[self registerControllerCallbacks:controller];
|
||||||
|
[self updateAutoOnScreenControlMode];
|
||||||
|
}
|
||||||
|
|
||||||
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
|
Log(LOG_I, @"Controller connected!");
|
||||||
|
|
||||||
|
GCController* controller = note.object;
|
||||||
|
[self assignController:controller];
|
||||||
|
|
||||||
// Register callbacks on the new controller
|
// Register callbacks on the new controller
|
||||||
[self registerControllerCallbacks];
|
[self registerControllerCallbacks:controller];
|
||||||
|
|
||||||
// Re-evaluate the on-screen control mode
|
// Re-evaluate the on-screen control mode
|
||||||
[self updateAutoOnScreenControlMode];
|
[self updateAutoOnScreenControlMode];
|
||||||
}];
|
}];
|
||||||
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||||
NSLog(@"Controller disconnected!");
|
Log(LOG_I, @"Controller disconnected!");
|
||||||
|
|
||||||
// Reset all controller state to be safe
|
GCController* controller = note.object;
|
||||||
[self updateButtonFlags:0];
|
[self unregisterControllerCallbacks:controller];
|
||||||
[self updateLeftStick:0 y:0];
|
[_controllers removeObjectForKey:[NSNumber numberWithInteger:controller.playerIndex]];
|
||||||
[self updateRightStick:0 y:0];
|
_controllerNumbers &= ~(1 << controller.playerIndex);
|
||||||
[self updateTriggers:0 right:0];
|
Log(LOG_I, @"Unassigning controller index: %ld", (long)controller.playerIndex);
|
||||||
[self updateFinished];
|
|
||||||
|
|
||||||
// Re-evaluate the on-screen control mode
|
// Re-evaluate the on-screen control mode
|
||||||
[self updateAutoOnScreenControlMode];
|
[self updateAutoOnScreenControlMode];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Register for controller callbacks on any existing controllers
|
|
||||||
[self registerControllerCallbacks];
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,8 +330,11 @@
|
|||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
|
[[NSNotificationCenter defaultCenter] removeObserver:self.connectObserver];
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
|
[[NSNotificationCenter defaultCenter] removeObserver:self.disconnectObserver];
|
||||||
|
[_controllers removeAllObjects];
|
||||||
[self unregisterControllerCallbacks];
|
_controllerNumbers = 0;
|
||||||
|
for (GCController* controller in [GCController controllers]) {
|
||||||
|
[self unregisterControllerCallbacks:controller];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#import "OnScreenControls.h"
|
#import "OnScreenControls.h"
|
||||||
#import "ControllerSupport.h"
|
#import "ControllerSupport.h"
|
||||||
|
#import "Controller.h"
|
||||||
#include "Limelight.h"
|
#include "Limelight.h"
|
||||||
|
|
||||||
#define UPDATE_BUTTON(x, y) (buttonFlags = \
|
#define UPDATE_BUTTON(x, y) (buttonFlags = \
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
OnScreenControlsLevel _level;
|
OnScreenControlsLevel _level;
|
||||||
|
|
||||||
ControllerSupport *_controllerSupport;
|
ControllerSupport *_controllerSupport;
|
||||||
|
Controller *_controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float BUTTON_SIZE = 50;
|
static const float BUTTON_SIZE = 50;
|
||||||
@@ -117,6 +119,8 @@ static float L3_Y;
|
|||||||
self = [self init];
|
self = [self init];
|
||||||
_view = view;
|
_view = view;
|
||||||
_controllerSupport = controllerSupport;
|
_controllerSupport = controllerSupport;
|
||||||
|
_controller = [[Controller alloc] init];
|
||||||
|
_controller.playerIndex = 0;
|
||||||
|
|
||||||
_aButton = [CALayer layer];
|
_aButton = [CALayer layer];
|
||||||
_bButton = [CALayer layer];
|
_bButton = [CALayer layer];
|
||||||
@@ -185,10 +189,10 @@ static float L3_Y;
|
|||||||
|
|
||||||
[self drawTriggers];
|
[self drawTriggers];
|
||||||
[self drawStartSelect];
|
[self drawStartSelect];
|
||||||
|
[self drawL3R3];
|
||||||
[self hideButtons];
|
[self hideButtons];
|
||||||
[self hideBumpers];
|
[self hideBumpers];
|
||||||
[self hideSticks];
|
[self hideSticks];
|
||||||
[self hideL3R3];
|
|
||||||
break;
|
break;
|
||||||
case OnScreenControlsLevelFull:
|
case OnScreenControlsLevelFull:
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
@@ -201,7 +205,7 @@ static float L3_Y;
|
|||||||
[self hideL3R3]; // Full controls don't need these they have the sticks
|
[self hideL3R3]; // Full controls don't need these they have the sticks
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
NSLog(@"Unknown on-screen controls level: %d", (int)_level);
|
Log(LOG_W, @"Unknown on-screen controls level: %d", (int)_level);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,7 +453,7 @@ static float L3_Y;
|
|||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateLeftStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _rsTouch) {
|
} else if (touch == _rsTouch) {
|
||||||
@@ -466,7 +470,7 @@ static float L3_Y;
|
|||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateRightStick:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _aTouch) {
|
} else if (touch == _aTouch) {
|
||||||
@@ -504,7 +508,7 @@ static float L3_Y;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
return updated || buttonTouch;
|
return updated || buttonTouch;
|
||||||
}
|
}
|
||||||
@@ -516,67 +520,67 @@ static float L3_Y;
|
|||||||
CGPoint touchLocation = [touch locationInView:_view];
|
CGPoint touchLocation = [touch locationInView:_view];
|
||||||
|
|
||||||
if ([_aButton.presentationLayer hitTest:touchLocation]) {
|
if ([_aButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:A_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:A_FLAG];
|
||||||
_aTouch = touch;
|
_aTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_bButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_bButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:B_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:B_FLAG];
|
||||||
_bTouch = touch;
|
_bTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_xButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_xButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:X_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:X_FLAG];
|
||||||
_xTouch = touch;
|
_xTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_yButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_yButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:Y_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:Y_FLAG];
|
||||||
_yTouch = touch;
|
_yTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_upButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:UP_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:UP_FLAG];
|
||||||
_upTouch = touch;
|
_upTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_downButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:DOWN_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:DOWN_FLAG];
|
||||||
_downTouch = touch;
|
_downTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_leftButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:LEFT_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:LEFT_FLAG];
|
||||||
_leftTouch = touch;
|
_leftTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_rightButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:RIGHT_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:RIGHT_FLAG];
|
||||||
_rightTouch = touch;
|
_rightTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_startButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_startButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:PLAY_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:PLAY_FLAG];
|
||||||
_startTouch = touch;
|
_startTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_selectButton.presentationLayer hitTest:touchLocation]) {
|
} else if ([_selectButton.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:BACK_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:BACK_FLAG];
|
||||||
_selectTouch = touch;
|
_selectTouch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_l1Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_l1Button.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:LB_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:LB_FLAG];
|
||||||
_l1Touch = touch;
|
_l1Touch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_r1Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_r1Button.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport setButtonFlag:RB_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:RB_FLAG];
|
||||||
_r1Touch = touch;
|
_r1Touch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_l2Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_l2Button.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport updateLeftTrigger:0xFF];
|
[_controllerSupport updateLeftTrigger:_controller left:0xFF];
|
||||||
_l2Touch = touch;
|
_l2Touch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_r2Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_r2Button.presentationLayer hitTest:touchLocation]) {
|
||||||
[_controllerSupport updateRightTrigger:0xFF];
|
[_controllerSupport updateRightTrigger:_controller right:0xFF];
|
||||||
_r2Touch = touch;
|
_r2Touch = touch;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_l3Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_l3Button.presentationLayer hitTest:touchLocation]) {
|
||||||
if (l3Set) {
|
if (l3Set) {
|
||||||
[_controllerSupport clearButtonFlag:LS_CLK_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||||
_l3Button.borderWidth = 0.0f;
|
_l3Button.borderWidth = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
[_controllerSupport setButtonFlag:LS_CLK_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||||
_l3Button.borderWidth = 2.0f;
|
_l3Button.borderWidth = 2.0f;
|
||||||
}
|
}
|
||||||
l3Set = !l3Set;
|
l3Set = !l3Set;
|
||||||
@@ -584,10 +588,10 @@ static float L3_Y;
|
|||||||
updated = true;
|
updated = true;
|
||||||
} else if ([_r3Button.presentationLayer hitTest:touchLocation]) {
|
} else if ([_r3Button.presentationLayer hitTest:touchLocation]) {
|
||||||
if (r3Set) {
|
if (r3Set) {
|
||||||
[_controllerSupport clearButtonFlag:RS_CLK_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||||
_r3Button.borderWidth = 0.0f;
|
_r3Button.borderWidth = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
[_controllerSupport setButtonFlag:RS_CLK_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||||
_r3Button.borderWidth = 2.0f;
|
_r3Button.borderWidth = 2.0f;
|
||||||
}
|
}
|
||||||
r3Set = !r3Set;
|
r3Set = !r3Set;
|
||||||
@@ -599,7 +603,7 @@ static float L3_Y;
|
|||||||
// Use (-) modifier to conversion since receiver is earlier than now
|
// Use (-) modifier to conversion since receiver is earlier than now
|
||||||
double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0;
|
double l3TouchTime = [l3TouchStart timeIntervalSinceNow] * -1000.0;
|
||||||
if (l3TouchTime < STICK_CLICK_RATE) {
|
if (l3TouchTime < STICK_CLICK_RATE) {
|
||||||
[_controllerSupport setButtonFlag:LS_CLK_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,7 +615,7 @@ static float L3_Y;
|
|||||||
// Use (-) modifier to conversion since receiver is earlier than now
|
// Use (-) modifier to conversion since receiver is earlier than now
|
||||||
double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0;
|
double r3TouchTime = [r3TouchStart timeIntervalSinceNow] * -1000.0;
|
||||||
if (r3TouchTime < STICK_CLICK_RATE) {
|
if (r3TouchTime < STICK_CLICK_RATE) {
|
||||||
[_controllerSupport setButtonFlag:RS_CLK_FLAG];
|
[_controllerSupport setButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -620,7 +624,7 @@ static float L3_Y;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
return updated || stickTouch;
|
return updated || stickTouch;
|
||||||
}
|
}
|
||||||
@@ -630,72 +634,72 @@ static float L3_Y;
|
|||||||
BOOL touched = false;
|
BOOL touched = false;
|
||||||
for (UITouch* touch in touches) {
|
for (UITouch* touch in touches) {
|
||||||
if (touch == _aTouch) {
|
if (touch == _aTouch) {
|
||||||
[_controllerSupport clearButtonFlag:A_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:A_FLAG];
|
||||||
_aTouch = nil;
|
_aTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _bTouch) {
|
} else if (touch == _bTouch) {
|
||||||
[_controllerSupport clearButtonFlag:B_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:B_FLAG];
|
||||||
_bTouch = nil;
|
_bTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _xTouch) {
|
} else if (touch == _xTouch) {
|
||||||
[_controllerSupport clearButtonFlag:X_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:X_FLAG];
|
||||||
_xTouch = nil;
|
_xTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _yTouch) {
|
} else if (touch == _yTouch) {
|
||||||
[_controllerSupport clearButtonFlag:Y_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:Y_FLAG];
|
||||||
_yTouch = nil;
|
_yTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _upTouch) {
|
} else if (touch == _upTouch) {
|
||||||
[_controllerSupport clearButtonFlag:UP_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:UP_FLAG];
|
||||||
_upTouch = nil;
|
_upTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _downTouch) {
|
} else if (touch == _downTouch) {
|
||||||
[_controllerSupport clearButtonFlag:DOWN_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:DOWN_FLAG];
|
||||||
_downTouch = nil;
|
_downTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _leftTouch) {
|
} else if (touch == _leftTouch) {
|
||||||
[_controllerSupport clearButtonFlag:LEFT_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:LEFT_FLAG];
|
||||||
_leftTouch = nil;
|
_leftTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _rightTouch) {
|
} else if (touch == _rightTouch) {
|
||||||
[_controllerSupport clearButtonFlag:RIGHT_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:RIGHT_FLAG];
|
||||||
_rightTouch = nil;
|
_rightTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _startTouch) {
|
} else if (touch == _startTouch) {
|
||||||
[_controllerSupport clearButtonFlag:PLAY_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:PLAY_FLAG];
|
||||||
_startTouch = nil;
|
_startTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _selectTouch) {
|
} else if (touch == _selectTouch) {
|
||||||
[_controllerSupport clearButtonFlag:BACK_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:BACK_FLAG];
|
||||||
_selectTouch = nil;
|
_selectTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _l1Touch) {
|
} else if (touch == _l1Touch) {
|
||||||
[_controllerSupport clearButtonFlag:LB_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:LB_FLAG];
|
||||||
_l1Touch = nil;
|
_l1Touch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _r1Touch) {
|
} else if (touch == _r1Touch) {
|
||||||
[_controllerSupport clearButtonFlag:RB_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:RB_FLAG];
|
||||||
_r1Touch = nil;
|
_r1Touch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _l2Touch) {
|
} else if (touch == _l2Touch) {
|
||||||
[_controllerSupport updateLeftTrigger:0];
|
[_controllerSupport updateLeftTrigger:_controller left:0];
|
||||||
_l2Touch = nil;
|
_l2Touch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _r2Touch) {
|
} else if (touch == _r2Touch) {
|
||||||
[_controllerSupport updateRightTrigger:0];
|
[_controllerSupport updateRightTrigger:_controller right:0];
|
||||||
_r2Touch = nil;
|
_r2Touch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _lsTouch) {
|
} else if (touch == _lsTouch) {
|
||||||
_leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_leftStick.frame = CGRectMake(LS_CENTER_X - STICK_INNER_SIZE / 2, LS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
||||||
[_controllerSupport updateLeftStick:0 y:0];
|
[_controllerSupport updateLeftStick:_controller x:0 y:0];
|
||||||
[_controllerSupport clearButtonFlag:LS_CLK_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:LS_CLK_FLAG];
|
||||||
l3TouchStart = [NSDate date];
|
l3TouchStart = [NSDate date];
|
||||||
_lsTouch = nil;
|
_lsTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _rsTouch) {
|
} else if (touch == _rsTouch) {
|
||||||
_rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_rightStick.frame = CGRectMake(RS_CENTER_X - STICK_INNER_SIZE / 2, RS_CENTER_Y - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
||||||
[_controllerSupport updateRightStick:0 y:0];
|
[_controllerSupport updateRightStick:_controller x:0 y:0];
|
||||||
[_controllerSupport clearButtonFlag:RS_CLK_FLAG];
|
[_controllerSupport clearButtonFlag:_controller flags:RS_CLK_FLAG];
|
||||||
r3TouchStart = [NSDate date];
|
r3TouchStart = [NSDate date];
|
||||||
_rsTouch = nil;
|
_rsTouch = nil;
|
||||||
updated = true;
|
updated = true;
|
||||||
@@ -710,7 +714,7 @@ static float L3_Y;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
return updated || touched;
|
return updated || touched;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,13 @@
|
|||||||
[controllerSupport initAutoOnScreenControlMode:onScreenControls];
|
[controllerSupport initAutoOnScreenControlMode:onScreenControls];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NSLog(@"Setting manual on-screen controls level: %d", (int)level);
|
Log(LOG_I, @"Setting manual on-screen controls level: %d", (int)level);
|
||||||
[onScreenControls setLevel:level];
|
[onScreenControls setLevel:level];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||||
NSLog(@"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];
|
touchLocation = [touch locationInView:self];
|
||||||
@@ -88,11 +88,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||||
NSLog(@"Touch up");
|
Log(LOG_D, @"Touch up");
|
||||||
if (![onScreenControls handleTouchUpEvent:touches]) {
|
if (![onScreenControls handleTouchUpEvent:touches]) {
|
||||||
if (!touchMoved) {
|
if (!touchMoved) {
|
||||||
if ([[event allTouches] count] == 2) {
|
if ([[event allTouches] count] == 2) {
|
||||||
NSLog(@"Sending right mouse button press");
|
Log(LOG_D, @"Sending right mouse button press");
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Sending left mouse button press");
|
Log(LOG_D, @"Sending left mouse button press");
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.3.2</string>
|
<string>0.4.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -14,4 +14,5 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <CoreData/CoreData.h>
|
#import <CoreData/CoreData.h>
|
||||||
#endif
|
#import "Logger.h"
|
||||||
|
#endif
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppManager : NSObject
|
@interface AppAssetManager : NSObject
|
||||||
|
|
||||||
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
||||||
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host;
|
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// AppManager.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 10/25/14.
|
||||||
|
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppAssetManager.h"
|
||||||
|
#import "CryptoManager.h"
|
||||||
|
#import "Utils.h"
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "AppAssetRetriever.h"
|
||||||
|
|
||||||
|
@implementation AppAssetManager {
|
||||||
|
NSOperationQueue* _opQueue;
|
||||||
|
id<AppAssetCallback> _callback;
|
||||||
|
Host* _host;
|
||||||
|
NSMutableDictionary* _imageCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithCallback:(id<AppAssetCallback>)callback {
|
||||||
|
self = [super init];
|
||||||
|
_callback = callback;
|
||||||
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
|
_imageCache = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host {
|
||||||
|
Host* oldHost = _host;
|
||||||
|
_host = host;
|
||||||
|
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid];
|
||||||
|
Log(LOG_I, @"Using cached app images: %d", useCache);
|
||||||
|
if (!useCache) {
|
||||||
|
[_imageCache removeAllObjects];
|
||||||
|
}
|
||||||
|
for (App* app in appList) {
|
||||||
|
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
||||||
|
retriever.app = app;
|
||||||
|
retriever.host = _host;
|
||||||
|
retriever.callback = _callback;
|
||||||
|
retriever.cache = _imageCache;
|
||||||
|
retriever.useCache = useCache;
|
||||||
|
[_opQueue addOperation:retriever];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) stopRetrieving {
|
||||||
|
[_opQueue cancelAllOperations];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) sendCallBackForApp:(App*)app {
|
||||||
|
[_callback receivedAssetForApp:app];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// AppAssetResponse.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
|
||||||
|
@interface AppAssetResponse : NSObject <Response>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// AppAssetResponse.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppAssetResponse.h"
|
||||||
|
|
||||||
|
@implementation AppAssetResponse
|
||||||
|
@synthesize data, statusCode, statusMessage;
|
||||||
|
|
||||||
|
- (void)populateWithData:(NSData *)imageData {
|
||||||
|
self.data = imageData;
|
||||||
|
self.statusMessage = @"App asset has no status message";
|
||||||
|
self.statusCode = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIImage*) getImage {
|
||||||
|
UIImage* appImage = [[UIImage alloc] initWithData:self.data];
|
||||||
|
return appImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// AppAssetRetriever.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 1/31/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Host.h"
|
||||||
|
#import "App.h"
|
||||||
|
#import "AppAssetManager.h"
|
||||||
|
|
||||||
|
@interface AppAssetRetriever : NSOperation
|
||||||
|
|
||||||
|
@property (nonatomic) Host* host;
|
||||||
|
@property (nonatomic) App* app;
|
||||||
|
@property (nonatomic) NSMutableDictionary* cache;
|
||||||
|
@property (nonatomic) id<AppAssetCallback> callback;
|
||||||
|
@property (nonatomic) BOOL useCache;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// AppAssetRetriever.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 1/31/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppAssetRetriever.h"
|
||||||
|
#import "HttpManager.h"
|
||||||
|
#import "CryptoManager.h"
|
||||||
|
#import "AppAssetResponse.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
|
@implementation AppAssetRetriever
|
||||||
|
static const double RETRY_DELAY = 2; // seconds
|
||||||
|
static const int MAX_ATTEMPTS = 5;
|
||||||
|
|
||||||
|
|
||||||
|
- (void) main {
|
||||||
|
UIImage* appImage = nil;
|
||||||
|
int attempts = 0;
|
||||||
|
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
|
||||||
|
if (self.useCache) {
|
||||||
|
@synchronized(self.cache) {
|
||||||
|
UIImage* cachedImage = [self.cache objectForKey:self.app.appId];
|
||||||
|
if (cachedImage != nil) {
|
||||||
|
appImage = cachedImage;
|
||||||
|
self.app.appImage = appImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (appImage == nil) {
|
||||||
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
|
||||||
|
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]];
|
||||||
|
|
||||||
|
appImage = [UIImage imageWithData:appAssetResp.data];
|
||||||
|
self.app.appImage = appImage;
|
||||||
|
if (appImage != nil) {
|
||||||
|
@synchronized(self.cache) {
|
||||||
|
[self.cache setObject:appImage forKey:self.app.appId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NSThread sleepForTimeInterval:RETRY_DELAY];
|
||||||
|
}
|
||||||
|
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) sendCallbackForApp:(App*)app {
|
||||||
|
[self.callback receivedAssetForApp:app];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// AppListResponse.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
|
||||||
|
@interface AppListResponse : NSObject <Response>
|
||||||
|
|
||||||
|
- (void)populateWithData:(NSData *)data;
|
||||||
|
- (NSArray*) getAppList;
|
||||||
|
- (BOOL) isStatusOk;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
//
|
||||||
|
// AppListResponse.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppListResponse.h"
|
||||||
|
#import "App.h"
|
||||||
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
|
@implementation AppListResponse {
|
||||||
|
NSMutableArray* _appList;
|
||||||
|
}
|
||||||
|
@synthesize data, statusCode, statusMessage;
|
||||||
|
|
||||||
|
static const char* TAG_APP = "App";
|
||||||
|
static const char* TAG_APP_TITLE = "AppTitle";
|
||||||
|
static const char* TAG_APP_ID = "ID";
|
||||||
|
static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
||||||
|
|
||||||
|
- (void)populateWithData:(NSData *)xml {
|
||||||
|
self.data = xml;
|
||||||
|
_appList = [[NSMutableArray alloc] init];
|
||||||
|
[self parseData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) parseData {
|
||||||
|
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
|
||||||
|
if (docPtr == NULL) {
|
||||||
|
Log(LOG_W, @"An error occured trying to parse xml.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlNodePtr node = xmlDocGetRootElement(docPtr);
|
||||||
|
if (node == NULL) {
|
||||||
|
Log(LOG_W, @"No root XML element.");
|
||||||
|
xmlFreeDoc(docPtr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
|
||||||
|
if (statusStr != NULL) {
|
||||||
|
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
|
||||||
|
xmlFree(statusStr);
|
||||||
|
self.statusCode = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
|
||||||
|
NSString* statusMsg;
|
||||||
|
if (statusMsgXml != NULL) {
|
||||||
|
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
|
||||||
|
xmlFree(statusMsgXml);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statusMsg = @"Server Error";
|
||||||
|
}
|
||||||
|
self.statusMessage = statusMsg;
|
||||||
|
|
||||||
|
node = node->children;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
//Log(LOG_D, @"node: %s", node->name);
|
||||||
|
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
|
||||||
|
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
||||||
|
NSString* appName;
|
||||||
|
NSString* appId;
|
||||||
|
BOOL appIsRunning = NO;
|
||||||
|
while (appInfoNode != NULL) {
|
||||||
|
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
||||||
|
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||||
|
if (nodeVal != NULL) {
|
||||||
|
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||||
|
xmlFree(nodeVal);
|
||||||
|
} else {
|
||||||
|
appName = @"";
|
||||||
|
}
|
||||||
|
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_ID)) {
|
||||||
|
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||||
|
if (nodeVal != NULL) {
|
||||||
|
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||||
|
xmlFree(nodeVal);
|
||||||
|
}
|
||||||
|
} else if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_IS_RUNNING)) {
|
||||||
|
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||||
|
if (nodeVal != NULL) {
|
||||||
|
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
|
||||||
|
xmlFree(nodeVal);
|
||||||
|
} else {
|
||||||
|
appIsRunning = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appInfoNode = appInfoNode->next;
|
||||||
|
}
|
||||||
|
App* app = [[App alloc] init];
|
||||||
|
app.appName = appName;
|
||||||
|
app.appId = appId;
|
||||||
|
app.isRunning = appIsRunning;
|
||||||
|
if (app.appId != nil) {
|
||||||
|
[_appList addObject:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeDoc(docPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray*) getAppList {
|
||||||
|
return _appList;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isStatusOk {
|
||||||
|
return self.statusCode == 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
//
|
|
||||||
// AppManager.m
|
|
||||||
// Limelight
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 10/25/14.
|
|
||||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "AppManager.h"
|
|
||||||
#import "CryptoManager.h"
|
|
||||||
#import "Utils.h"
|
|
||||||
|
|
||||||
@implementation AppManager {
|
|
||||||
NSOperationQueue* _opQueue;
|
|
||||||
id<AppAssetCallback> _callback;
|
|
||||||
Host* _host;
|
|
||||||
NSString* _uniqueId;
|
|
||||||
NSData* _cert;
|
|
||||||
NSMutableDictionary* _imageCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) initWithCallback:(id<AppAssetCallback>)callback {
|
|
||||||
self = [super init];
|
|
||||||
_callback = callback;
|
|
||||||
_opQueue = [[NSOperationQueue alloc] init];
|
|
||||||
_imageCache = [[NSMutableDictionary alloc] init];
|
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host {
|
|
||||||
Host* oldHost = _host;
|
|
||||||
_host = host;
|
|
||||||
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid];
|
|
||||||
NSLog(@"Using cached app images: %d", useCache);
|
|
||||||
if (!useCache) {
|
|
||||||
[_imageCache removeAllObjects];
|
|
||||||
}
|
|
||||||
for (App* app in appList) {
|
|
||||||
[_opQueue addOperationWithBlock:^{
|
|
||||||
[self retrieveAssetForApp:app useCache:useCache];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) stopRetrieving {
|
|
||||||
[_opQueue cancelAllOperations];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) retrieveAssetForApp:(App*)app useCache:(BOOL)useCache {
|
|
||||||
UIImage* appImage = nil;
|
|
||||||
if (useCache) {
|
|
||||||
@synchronized(_imageCache) {
|
|
||||||
UIImage* cachedImage = [_imageCache objectForKey:app.appId];
|
|
||||||
if (cachedImage != nil) {
|
|
||||||
appImage = cachedImage;
|
|
||||||
app.appImage = appImage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (appImage == nil) {
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
|
||||||
NSData* appAsset = [hMan executeRequestSynchronously:[hMan newAppAssetRequestWithAppId:app.appId]];
|
|
||||||
appImage = [UIImage imageWithData:appAsset];
|
|
||||||
app.appImage = appImage;
|
|
||||||
if (appImage != nil) {
|
|
||||||
@synchronized(_imageCache) {
|
|
||||||
[_imageCache setObject:appImage forKey:app.appId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[self performSelectorOnMainThread:@selector(sendCallBackForApp:) withObject:app waitUntilDone:NO];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) sendCallBackForApp:(App*)app {
|
|
||||||
[_callback receivedAssetForApp:app];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
- (void) stopDiscoveryBlocking;
|
- (void) stopDiscoveryBlocking;
|
||||||
- (BOOL) addHostToDiscovery:(Host*)host;
|
- (BOOL) addHostToDiscovery:(Host*)host;
|
||||||
- (void) removeHostFromDiscovery:(Host*)host;
|
- (void) removeHostFromDiscovery:(Host*)host;
|
||||||
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*))callback;
|
- (void) discoverHost:(NSString*)hostAddress withCallback:(void (^)(Host*, NSString*))callback;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import "DiscoveryWorker.h"
|
#import "DiscoveryWorker.h"
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
|
||||||
@implementation DiscoveryManager {
|
@implementation DiscoveryManager {
|
||||||
NSMutableArray* _hostQueue;
|
NSMutableArray* _hostQueue;
|
||||||
@@ -37,25 +38,32 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *))callback {
|
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, 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];
|
||||||
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]];
|
||||||
|
|
||||||
Host* host = nil;
|
Host* host = nil;
|
||||||
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
|
if ([serverInfoResponse isStatusOk]) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
host = [dataMan createHost];
|
host = [dataMan createHost];
|
||||||
host.address = hostAddress;
|
host.address = hostAddress;
|
||||||
[HttpManager populateHostFromXML:serverInfoData host:host];
|
host.online = YES;
|
||||||
|
[serverInfoResponse populateHost:host];
|
||||||
if (![self addHostToDiscovery:host]) {
|
if (![self addHostToDiscovery:host]) {
|
||||||
[dataMan removeHost:host];
|
[dataMan removeHost:host];
|
||||||
|
callback(nil, @"Host already added");
|
||||||
|
} else {
|
||||||
|
callback(host, nil);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
callback(nil, @"Could not connect to host");
|
||||||
}
|
}
|
||||||
callback(host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) startDiscovery {
|
- (void) startDiscovery {
|
||||||
NSLog(@"Starting discovery");
|
Log(LOG_I, @"Starting discovery");
|
||||||
shouldDiscover = YES;
|
shouldDiscover = YES;
|
||||||
[_mdnsMan searchForHosts];
|
[_mdnsMan searchForHosts];
|
||||||
for (Host* host in _hostQueue) {
|
for (Host* host in _hostQueue) {
|
||||||
@@ -64,19 +72,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) stopDiscovery {
|
- (void) stopDiscovery {
|
||||||
NSLog(@"Stopping discovery");
|
Log(LOG_I, @"Stopping discovery");
|
||||||
shouldDiscover = NO;
|
shouldDiscover = NO;
|
||||||
[_mdnsMan stopSearching];
|
[_mdnsMan stopSearching];
|
||||||
[_opQueue cancelAllOperations];
|
[_opQueue cancelAllOperations];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stopDiscoveryBlocking {
|
- (void) stopDiscoveryBlocking {
|
||||||
NSLog(@"Stopping discovery and waiting for workers to stop");
|
Log(LOG_I, @"Stopping discovery and waiting for workers to stop");
|
||||||
shouldDiscover = NO;
|
shouldDiscover = NO;
|
||||||
[_mdnsMan stopSearching];
|
[_mdnsMan stopSearching];
|
||||||
[_opQueue cancelAllOperations];
|
[_opQueue cancelAllOperations];
|
||||||
[_opQueue waitUntilAllOperationsAreFinished];
|
[_opQueue waitUntilAllOperationsAreFinished];
|
||||||
NSLog(@"All discovery workers stopped");
|
Log(LOG_I, @"All discovery workers stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) addHostToDiscovery:(Host *)host {
|
- (BOOL) addHostToDiscovery:(Host *)host {
|
||||||
@@ -105,15 +113,15 @@
|
|||||||
DataManager* dataMan = [[DataManager alloc] init];
|
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 (Host* host in hosts) {
|
||||||
NSLog(@"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];
|
||||||
[worker discoverHost];
|
[worker discoverHost];
|
||||||
if ([self addHostToDiscovery:host]) {
|
if ([self addHostToDiscovery:host]) {
|
||||||
NSLog(@"Adding host to discovery: %@", host.name);
|
Log(LOG_I, @"Adding host to discovery: %@", host.name);
|
||||||
[_callback updateAllHosts:_hostQueue];
|
[_callback updateAllHosts:_hostQueue];
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Not adding host to discovery: %@", host.name);
|
Log(LOG_I, @"Not adding host to discovery: %@", host.name);
|
||||||
[dataMan removeHost:host];
|
[dataMan removeHost:host];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#import "DiscoveryWorker.h"
|
#import "DiscoveryWorker.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
@implementation DiscoveryWorker {
|
@implementation DiscoveryWorker {
|
||||||
Host* _host;
|
Host* _host;
|
||||||
@@ -42,39 +44,45 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
- (void) discoverHost {
|
- (void) discoverHost {
|
||||||
BOOL receivedResponse = NO;
|
BOOL receivedResponse = NO;
|
||||||
if (!self.cancelled && _host.localAddress != nil) {
|
if (!self.cancelled && _host.localAddress != nil) {
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.localAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.localAddress];
|
||||||
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
receivedResponse = [self checkResponse:serverInfoResp];
|
||||||
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
|
|
||||||
[HttpManager populateHostFromXML:serverInfoData host:_host];
|
|
||||||
_host.address = _host.localAddress;
|
|
||||||
receivedResponse = YES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
|
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.externalAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.externalAddress];
|
||||||
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
receivedResponse = [self checkResponse:serverInfoResp];
|
||||||
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
|
|
||||||
[HttpManager populateHostFromXML:serverInfoData host:_host];
|
|
||||||
_host.address = _host.externalAddress;
|
|
||||||
receivedResponse = YES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.cancelled && !receivedResponse && _host.address != nil) {
|
if (!self.cancelled && !receivedResponse && _host.address != nil) {
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.address];
|
||||||
NSData* serverInfoData = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
receivedResponse = [self checkResponse:serverInfoResp];
|
||||||
if ([[HttpManager getStatusStringFromXML:serverInfoData] isEqualToString:@"OK"]) {
|
|
||||||
[HttpManager populateHostFromXML:serverInfoData host:_host];
|
|
||||||
receivedResponse = YES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_host.online = receivedResponse;
|
_host.online = receivedResponse;
|
||||||
if (receivedResponse) {
|
if (receivedResponse) {
|
||||||
NSLog(@"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online);
|
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online);
|
||||||
} else {
|
|
||||||
// If the host is not online, we do not know the pairstate
|
|
||||||
_host.pairState = PairStateUnknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (ServerInfoResponse*) requestInfoAtAddress:(NSString*)address {
|
||||||
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:address
|
||||||
|
uniqueId:_uniqueId
|
||||||
|
deviceName:deviceName
|
||||||
|
cert:_cert];
|
||||||
|
ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
|
||||||
|
withUrlRequest:[hMan newServerInfoRequest]]];
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) checkResponse:(ServerInfoResponse*)response {
|
||||||
|
if ([response isStatusOk]) {
|
||||||
|
// 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])) {
|
||||||
|
[response populateHost:_host];
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
Log(LOG_I, @"Received response from incorrect host: %@ expected: %@", [response getStringTag:TAG_UNIQUE_ID], _host.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -8,14 +8,11 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "Host.h"
|
#import "Host.h"
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
||||||
|
|
||||||
+ (NSArray*) getAppListFromXML:(NSData*)xml;
|
|
||||||
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host;
|
|
||||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
|
|
||||||
+ (NSString*) getStatusStringFromXML:(NSData*)xml;
|
|
||||||
|
|
||||||
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
||||||
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
||||||
- (NSURLRequest*) newUnpairRequest;
|
- (NSURLRequest*) newUnpairRequest;
|
||||||
@@ -29,7 +26,9 @@
|
|||||||
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
|
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
|
||||||
- (NSURLRequest*) newQuitAppRequest;
|
- (NSURLRequest*) newQuitAppRequest;
|
||||||
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
|
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
|
||||||
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request;
|
- (void) executeRequestSynchronously:(HttpRequest*)request;
|
||||||
|
- (void) executeRequest:(HttpRequest*)request;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
+14
-212
@@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "App.h"
|
#import "App.h"
|
||||||
|
|
||||||
@@ -26,207 +27,6 @@
|
|||||||
|
|
||||||
static const NSString* PORT = @"47984";
|
static const NSString* PORT = @"47984";
|
||||||
|
|
||||||
+ (NSArray*) getAppListFromXML:(NSData*)xml {
|
|
||||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
|
||||||
|
|
||||||
if (docPtr == NULL) {
|
|
||||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr node;
|
|
||||||
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
|
|
||||||
|
|
||||||
// Check root status_code
|
|
||||||
if (![HttpManager verifyStatus: rootNode]) {
|
|
||||||
NSLog(@"ERROR: Request returned with failure status");
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the root node
|
|
||||||
node = node->children;
|
|
||||||
|
|
||||||
NSMutableArray* appList = [[NSMutableArray alloc] init];
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
//NSLog(@"node: %s", node->name);
|
|
||||||
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
|
|
||||||
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
|
||||||
NSString* appName;
|
|
||||||
NSString* appId;
|
|
||||||
BOOL appIsRunning = NO;
|
|
||||||
while (appInfoNode != NULL) {
|
|
||||||
//NSLog(@"appInfoNode: %s", appInfoNode->name);
|
|
||||||
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
|
||||||
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
|
||||||
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"IsRunning")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
|
||||||
appIsRunning = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
}
|
|
||||||
appInfoNode = appInfoNode->next;
|
|
||||||
}
|
|
||||||
App* app = [[App alloc] init];
|
|
||||||
app.appName = appName;
|
|
||||||
app.appId = appId;
|
|
||||||
app.isRunning = appIsRunning;
|
|
||||||
[appList addObject:app];
|
|
||||||
}
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
|
|
||||||
return appList;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) populateHostFromXML:(NSData*)xml host:(Host*)host {
|
|
||||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
|
||||||
|
|
||||||
if (docPtr == NULL) {
|
|
||||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlNodePtr node;
|
|
||||||
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
|
|
||||||
|
|
||||||
// Check root status_code
|
|
||||||
if (![HttpManager verifyStatus: rootNode]) {
|
|
||||||
NSLog(@"ERROR: Request returned with failure status");
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the root node
|
|
||||||
node = node->children;
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
//NSLog(@"node: %s", node->name);
|
|
||||||
if (!xmlStrcmp(node->name, (const xmlChar*)"hostname")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.name = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(node->name, (const xmlChar*)"ExternalIP")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.externalAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(node->name, (const xmlChar*)"LocalIP")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.localAddress = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(node->name, (const xmlChar*)"uniqueid")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.uuid = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(node->name, (const xmlChar*)"mac")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.mac = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
} else if (!xmlStrcmp(node->name, (const xmlChar*)"PairStatus")) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
host.pairState = [[[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding] isEqualToString:@"1"] ? PairStatePaired : PairStateUnpaired;
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString*) getStatusStringFromXML:(NSData*)xml {
|
|
||||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
|
||||||
|
|
||||||
if (docPtr == NULL) {
|
|
||||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString* string;
|
|
||||||
xmlNodePtr rootNode = xmlDocGetRootElement(docPtr);
|
|
||||||
if (rootNode == NULL) {
|
|
||||||
NSLog(@"ERROR: No root XML element.");
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
string = [HttpManager getStatusMessage: rootNode];
|
|
||||||
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
|
|
||||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
|
||||||
|
|
||||||
if (docPtr == NULL) {
|
|
||||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
NSString* value;
|
|
||||||
xmlNodePtr node;
|
|
||||||
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
|
|
||||||
|
|
||||||
// Check root status_code
|
|
||||||
if (![HttpManager verifyStatus: rootNode]) {
|
|
||||||
NSLog(@"ERROR: Request returned with failure status");
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the root node
|
|
||||||
node = node->children;
|
|
||||||
|
|
||||||
while (node != NULL) {
|
|
||||||
//NSLog(@"node: %s", node->name);
|
|
||||||
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
|
|
||||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
|
||||||
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
|
||||||
xmlFree(nodeVal);
|
|
||||||
}
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
//NSLog(@"xmlValue: %@", value);
|
|
||||||
|
|
||||||
xmlFreeDoc(docPtr);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString*) getStatusMessage:(xmlNodePtr)docRoot {
|
|
||||||
xmlChar* statusMsgXml = xmlGetProp(docRoot, (const xmlChar*)"status_message");
|
|
||||||
NSString* statusMsg;
|
|
||||||
if (statusMsgXml != NULL) {
|
|
||||||
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
|
|
||||||
xmlFree(statusMsgXml);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
statusMsg = @"Server Error";
|
|
||||||
}
|
|
||||||
|
|
||||||
return statusMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
|
|
||||||
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
|
|
||||||
if (statusStr != NULL) {
|
|
||||||
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
|
|
||||||
xmlFree(statusStr);
|
|
||||||
return status == 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
|
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
|
||||||
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
|
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
|
||||||
NSString* xmlString = [dataString stringByReplacingOccurrencesOfString:@"UTF-16" withString:@"UTF-8" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [dataString length])];
|
NSString* xmlString = [dataString stringByReplacingOccurrencesOfString:@"UTF-16" withString:@"UTF-8" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [dataString length])];
|
||||||
@@ -247,18 +47,20 @@ static const NSString* PORT = @"47984";
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request {
|
- (void) executeRequestSynchronously:(HttpRequest*)request {
|
||||||
NSLog(@"Making Request: %@", request);
|
Log(LOG_D, @"Making Request: %@", request);
|
||||||
[_respData setLength:0];
|
[_respData setLength:0];
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
[NSURLConnection connectionWithRequest:request delegate:self];
|
[NSURLConnection connectionWithRequest:request.request delegate:self];
|
||||||
});
|
});
|
||||||
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
|
||||||
return _requestResp;
|
if (request.response) {
|
||||||
|
[request.response populateWithData:_requestResp];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) executeRequest:(NSURLRequest*)request {
|
- (void) executeRequest:(HttpRequest*)request {
|
||||||
[NSURLConnection connectionWithRequest:request delegate:self];
|
[NSURLConnection connectionWithRequest:request.request delegate:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
|
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
|
||||||
@@ -352,11 +154,11 @@ static const NSString* PORT = @"47984";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||||
NSLog(@"Received response: %@", response);
|
Log(LOG_D, @"Received response: %@", response);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||||
NSLog(@"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
||||||
[_respData appendData:data];
|
[_respData appendData:data];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,11 +202,11 @@ static const NSString* PORT = @"47984";
|
|||||||
OSStatus securityError = SecPKCS12Import(p12Data, options, &items);
|
OSStatus securityError = SecPKCS12Import(p12Data, options, &items);
|
||||||
|
|
||||||
if (securityError == errSecSuccess) {
|
if (securityError == errSecSuccess) {
|
||||||
//NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
|
//Log(LOG_D, @"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
|
||||||
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
|
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
|
||||||
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
|
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Error opening Certificate.");
|
Log(LOG_E, @"Error opening Certificate.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CFRelease(options);
|
CFRelease(options);
|
||||||
@@ -414,7 +216,7 @@ static const NSString* PORT = @"47984";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||||
NSLog(@"connection error: %@", error);
|
Log(LOG_D, @"connection error: %@", error);
|
||||||
dispatch_semaphore_signal(_requestLock);
|
dispatch_semaphore_signal(_requestLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// HttpRequest.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
|
||||||
|
@interface HttpRequest : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic) id<Response> response;
|
||||||
|
@property (nonatomic) NSURLRequest* request;
|
||||||
|
|
||||||
|
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
|
||||||
|
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// HttpRequest.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "HttpManager.h"
|
||||||
|
|
||||||
|
@implementation HttpRequest
|
||||||
|
|
||||||
|
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req {
|
||||||
|
HttpRequest* request = [[HttpRequest alloc] init];
|
||||||
|
request.request = req;
|
||||||
|
request.response = response;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (HttpRequest*) requestWithUrlRequest:(NSURLRequest*)req {
|
||||||
|
HttpRequest* request = [[HttpRequest alloc] init];
|
||||||
|
request.request = req;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// HttpResponse.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 1/30/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Host.h"
|
||||||
|
|
||||||
|
static NSString* TAG_STATUS_CODE = @"status_code";
|
||||||
|
static NSString* TAG_STATUS_MESSAGE = @"status_message";
|
||||||
|
|
||||||
|
@protocol Response <NSObject>
|
||||||
|
|
||||||
|
- (void) populateWithData:(NSData*)data;
|
||||||
|
|
||||||
|
@property (nonatomic) NSInteger statusCode;
|
||||||
|
@property (nonatomic) NSString* statusMessage;
|
||||||
|
@property (nonatomic) NSData* data;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface HttpResponse : NSObject <Response>
|
||||||
|
|
||||||
|
- (void) populateWithData:(NSData*)data;
|
||||||
|
- (void) parseData;
|
||||||
|
- (NSString*) getStringTag:(NSString*)tag;
|
||||||
|
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value;
|
||||||
|
- (BOOL) isStatusOk;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
//
|
||||||
|
// HttpResponse.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 1/30/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "App.h"
|
||||||
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
|
@implementation HttpResponse {
|
||||||
|
NSMutableDictionary* _elements;
|
||||||
|
}
|
||||||
|
@synthesize data, statusCode, statusMessage;
|
||||||
|
|
||||||
|
- (void) populateWithData:(NSData*)xml {
|
||||||
|
self.data = xml;
|
||||||
|
[self parseData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*) getStringTag:(NSString*)tag {
|
||||||
|
return [_elements objectForKey:tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) getIntTag:(NSString *)tag value:(NSInteger*)value {
|
||||||
|
NSString* stringVal = [self getStringTag:tag];
|
||||||
|
if (stringVal != nil) {
|
||||||
|
*value = [stringVal integerValue];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) isStatusOk {
|
||||||
|
return self.statusCode == 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) parseData {
|
||||||
|
_elements = [[NSMutableDictionary alloc] init];
|
||||||
|
xmlDocPtr docPtr = xmlParseMemory([self.data bytes], (int)[self.data length]);
|
||||||
|
if (docPtr == NULL) {
|
||||||
|
Log(LOG_W, @"An error occured trying to parse xml.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlNodePtr node = xmlDocGetRootElement(docPtr);
|
||||||
|
if (node == NULL) {
|
||||||
|
Log(LOG_W, @"No root XML element.");
|
||||||
|
xmlFreeDoc(docPtr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlChar* statusStr = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_CODE UTF8String]);
|
||||||
|
if (statusStr != NULL) {
|
||||||
|
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
|
||||||
|
xmlFree(statusStr);
|
||||||
|
self.statusCode = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlChar* statusMsgXml = xmlGetProp(node, (const xmlChar*)[TAG_STATUS_MESSAGE UTF8String]);
|
||||||
|
NSString* statusMsg;
|
||||||
|
if (statusMsgXml != NULL) {
|
||||||
|
statusMsg = [NSString stringWithUTF8String:(const char*)statusMsgXml];
|
||||||
|
xmlFree(statusMsgXml);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statusMsg = @"Server Error";
|
||||||
|
}
|
||||||
|
self.statusMessage = statusMsg;
|
||||||
|
|
||||||
|
node = node->children;
|
||||||
|
|
||||||
|
while (node != NULL) {
|
||||||
|
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
||||||
|
|
||||||
|
NSString* value;
|
||||||
|
if (nodeVal == NULL) {
|
||||||
|
value = @"";
|
||||||
|
} else {
|
||||||
|
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
NSString* key = [[NSString alloc] initWithCString:(const char*)node->name encoding:NSUTF8StringEncoding];
|
||||||
|
[_elements setObject:value forKey:key];
|
||||||
|
xmlFree(nodeVal);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeDoc(docPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -34,13 +34,13 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) searchForHosts {
|
- (void) searchForHosts {
|
||||||
NSLog(@"Starting mDNS discovery");
|
Log(LOG_I, @"Starting mDNS discovery");
|
||||||
scanActive = TRUE;
|
scanActive = TRUE;
|
||||||
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) stopSearching {
|
- (void) stopSearching {
|
||||||
NSLog(@"Stopping mDNS discovery");
|
Log(LOG_I, @"Stopping mDNS discovery");
|
||||||
scanActive = FALSE;
|
scanActive = FALSE;
|
||||||
[mDNSBrowser stop];
|
[mDNSBrowser stop];
|
||||||
}
|
}
|
||||||
@@ -60,12 +60,12 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceDidResolveAddress:(NSNetService *)service {
|
- (void)netServiceDidResolveAddress:(NSNetService *)service {
|
||||||
NSLog(@"Resolved address: %@ -> %@", service, service.hostName);
|
Log(LOG_I, @"Resolved address: %@ -> %@", service, service.hostName);
|
||||||
[self.callback updateHosts:[self getFoundHosts]];
|
[self.callback updateHosts:[self getFoundHosts]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
|
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict {
|
||||||
NSLog(@"Did not resolve address for: %@\n%@", sender, [errorDict description]);
|
Log(LOG_W, @"Did not resolve address for: %@\n%@", sender, [errorDict description]);
|
||||||
|
|
||||||
// Schedule a retry in 2 seconds
|
// Schedule a retry in 2 seconds
|
||||||
[NSTimer scheduledTimerWithTimeInterval:2.0
|
[NSTimer scheduledTimerWithTimeInterval:2.0
|
||||||
@@ -76,7 +76,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
||||||
NSLog(@"Found service: %@", aNetService);
|
Log(LOG_I, @"Found service: %@", aNetService);
|
||||||
[aNetService setDelegate:self];
|
[aNetService setDelegate:self];
|
||||||
[aNetService resolveWithTimeout:5];
|
[aNetService resolveWithTimeout:5];
|
||||||
|
|
||||||
@@ -85,13 +85,12 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
|
||||||
NSLog(@"Removing service: %@", aNetService);
|
Log(LOG_I, @"Removing service: %@", aNetService);
|
||||||
[services removeObject:aNetService];
|
[services removeObject:aNetService];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict {
|
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict {
|
||||||
NSLog(@"Did not perform search");
|
Log(LOG_W, @"Did not perform search: \n%@", [errorDict description]);
|
||||||
NSLog(@"%@", [errorDict description]);
|
|
||||||
|
|
||||||
// Schedule a retry in 2 seconds
|
// Schedule a retry in 2 seconds
|
||||||
[NSTimer scheduledTimerWithTimeInterval:2.0
|
[NSTimer scheduledTimerWithTimeInterval:2.0
|
||||||
@@ -107,7 +106,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"Retrying mDNS search");
|
Log(LOG_I, @"Retrying mDNS search");
|
||||||
[mDNSBrowser stop];
|
[mDNSBrowser stop];
|
||||||
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
[mDNSBrowser searchForServicesOfType:NV_SERVICE_TYPE inDomain:@""];
|
||||||
}
|
}
|
||||||
@@ -118,7 +117,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"Retrying mDNS resolution");
|
Log(LOG_I, @"Retrying mDNS resolution");
|
||||||
for (NSNetService* service in services) {
|
for (NSNetService* service in services) {
|
||||||
if (service.hostName == nil) {
|
if (service.hostName == nil) {
|
||||||
[service setDelegate:self];
|
[service setDelegate:self];
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#import "PairManager.h"
|
#import "PairManager.h"
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
|
||||||
#include <dispatch/dispatch.h>
|
#include <dispatch/dispatch.h>
|
||||||
|
|
||||||
@@ -27,37 +30,42 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) main {
|
- (void) main {
|
||||||
NSData* serverInfo = [_httpManager executeRequestSynchronously:[_httpManager newServerInfoRequest]];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
if (serverInfo == NULL) {
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]];
|
||||||
|
if (serverInfoResp == nil) {
|
||||||
[_callback pairFailed:@"Unable to connect to PC"];
|
[_callback pairFailed:@"Unable to connect to PC"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) {
|
if ([serverInfoResp isStatusOk]) {
|
||||||
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) {
|
||||||
}
|
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||||
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
|
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
||||||
[self initiatePair];
|
[self initiatePair];
|
||||||
} else {
|
} else {
|
||||||
[_callback alreadyPaired];
|
[_callback alreadyPaired];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) initiatePair {
|
- (void) initiatePair {
|
||||||
NSString* PIN = [self generatePIN];
|
NSString* PIN = [self generatePIN];
|
||||||
NSData* salt = [self saltPIN:PIN];
|
NSData* salt = [self saltPIN:PIN];
|
||||||
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt);
|
Log(LOG_I, @"PIN: %@, saltedPIN: %@", PIN, salt);
|
||||||
[_callback showPIN:PIN];
|
[_callback showPIN:PIN];
|
||||||
|
|
||||||
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
|
HttpResponse* pairResp = [[HttpResponse alloc] init];
|
||||||
NSString* pairedString;
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:pairResp withUrlRequest:[_httpManager newPairRequest:salt]]];
|
||||||
pairedString = [HttpManager getStringFromXML:pairResp tag:@"paired"];
|
if (![self verifyResponseStatus:pairResp]) {
|
||||||
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
return;
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
}
|
||||||
|
NSInteger pairedStatus;
|
||||||
|
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing was declined by the target."];
|
[_callback pairFailed:@"Pairing was declined by the target."];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* plainCert = [HttpManager getStringFromXML:pairResp tag:@"plaincert"];
|
NSString* plainCert = [pairResp getStringTag:@"plaincert"];
|
||||||
|
|
||||||
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
|
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
|
||||||
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
|
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
|
||||||
@@ -65,15 +73,18 @@
|
|||||||
NSData* randomChallenge = [Utils randomBytes:16];
|
NSData* randomChallenge = [Utils randomBytes:16];
|
||||||
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
||||||
|
|
||||||
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
|
HttpResponse* challengeResp = [[HttpResponse alloc] init];
|
||||||
pairedString = [HttpManager getStringFromXML:challengeResp tag:@"paired"];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:challengeResp withUrlRequest:[_httpManager newChallengeRequest:encryptedChallenge]]];
|
||||||
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
if (![self verifyResponseStatus:challengeResp]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
return;
|
||||||
|
}
|
||||||
|
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #2 failed"];
|
[_callback pairFailed:@"Pairing stage #2 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* encServerChallengeResp = [Utils hexToBytes:[HttpManager getStringFromXML:challengeResp tag:@"challengeresponse"]];
|
NSData* encServerChallengeResp = [Utils hexToBytes:[challengeResp getStringTag:@"challengeresponse"]];
|
||||||
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
|
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
|
||||||
|
|
||||||
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
|
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
|
||||||
@@ -83,50 +94,73 @@
|
|||||||
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
|
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
|
||||||
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
||||||
|
|
||||||
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
|
HttpResponse* secretResp = [[HttpResponse alloc] init];
|
||||||
pairedString = [HttpManager getStringFromXML:secretResp tag:@"paired"];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:secretResp withUrlRequest:[_httpManager newChallengeRespRequest:challengeRespEncrypted]]];
|
||||||
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
if (![self verifyResponseStatus:secretResp]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
return;
|
||||||
|
}
|
||||||
|
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #3 failed"];
|
[_callback pairFailed:@"Pairing stage #3 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* serverSecretResp = [Utils hexToBytes:[HttpManager getStringFromXML:secretResp tag:@"pairingsecret"]];
|
NSData* serverSecretResp = [Utils hexToBytes:[secretResp getStringTag:@"pairingsecret"]];
|
||||||
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
|
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
|
||||||
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
|
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
|
||||||
|
|
||||||
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Server certificate invalid"];
|
[_callback pairFailed:@"Server certificate invalid"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
||||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Incorrect PIN"];
|
[_callback pairFailed:@"Incorrect PIN"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
|
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
|
||||||
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]];
|
HttpResponse* clientSecretResp = [[HttpResponse alloc] init];
|
||||||
pairedString = [HttpManager getStringFromXML:clientSecretResp tag:@"paired"];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientSecretResp withUrlRequest:[_httpManager newClientSecretRespRequest:[Utils bytesToHex:clientPairingSecret]]]];
|
||||||
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
if (![self verifyResponseStatus:clientSecretResp]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
return;
|
||||||
|
}
|
||||||
|
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #4 failed"];
|
[_callback pairFailed:@"Pairing stage #4 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
|
HttpResponse* clientPairChallengeResp = [[HttpResponse alloc] init];
|
||||||
pairedString = [HttpManager getStringFromXML:clientPairChallenge tag:@"paired"];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:clientPairChallengeResp withUrlRequest:[_httpManager newPairChallenge]]];
|
||||||
if (pairedString == NULL || ![pairedString isEqualToString:@"1"]) {
|
if (![self verifyResponseStatus:clientPairChallengeResp]) {
|
||||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
return;
|
||||||
|
}
|
||||||
|
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #5 failed"];
|
[_callback pairFailed:@"Pairing stage #5 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[_callback pairSuccessful];
|
[_callback pairSuccessful];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
|
||||||
|
if (resp == nil) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
|
[_callback pairFailed:@"Network error occured."];
|
||||||
|
return false;
|
||||||
|
} else if (![resp isStatusOk]) {
|
||||||
|
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
|
[_callback pairFailed:resp.statusMessage];
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
|
- (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
|
||||||
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
|
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
|
||||||
[concatData appendData:moreData];
|
[concatData appendData:moreData];
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// ServerInfoResponse.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
|
||||||
|
#define TAG_HOSTNAME @"hostname"
|
||||||
|
#define TAG_EXTERNAL_IP @"ExternalIP"
|
||||||
|
#define TAG_LOCAL_IP @"LocalIP"
|
||||||
|
#define TAG_UNIQUE_ID @"uniqueid"
|
||||||
|
#define TAG_MAC_ADDRESS @"mac"
|
||||||
|
#define TAG_PAIR_STATUS @"PairStatus"
|
||||||
|
|
||||||
|
@interface ServerInfoResponse : HttpResponse <Response>
|
||||||
|
|
||||||
|
- (void) populateWithData:(NSData *)data;
|
||||||
|
- (void) populateHost:(Host*)host;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// ServerInfoResponse.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/1/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
|
@implementation ServerInfoResponse
|
||||||
|
@synthesize data, statusCode, statusMessage;
|
||||||
|
|
||||||
|
- (void) populateWithData:(NSData *)xml {
|
||||||
|
self.data = xml;
|
||||||
|
[super parseData];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) populateHost:(Host*)host {
|
||||||
|
host.name = [self getStringTag:TAG_HOSTNAME];
|
||||||
|
host.externalAddress = [self getStringTag:TAG_EXTERNAL_IP];
|
||||||
|
host.localAddress = [self getStringTag:TAG_LOCAL_IP];
|
||||||
|
host.uuid = [self getStringTag:TAG_UNIQUE_ID];
|
||||||
|
host.mac = [self getStringTag:TAG_MAC_ADDRESS];
|
||||||
|
|
||||||
|
NSInteger pairStatus;
|
||||||
|
if ([self getIntTag:TAG_PAIR_STATUS value:&pairStatus]) {
|
||||||
|
host.pairState = pairStatus ? PairStatePaired : PairStateUnpaired;
|
||||||
|
} else {
|
||||||
|
host.pairState = PairStateUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -24,10 +24,10 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
|||||||
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);
|
||||||
if (!wolSocket) {
|
if (!wolSocket) {
|
||||||
CFRelease(dataPayload);
|
CFRelease(dataPayload);
|
||||||
NSLog(@"Failed to create WOL socket");
|
Log(LOG_E, @"Failed to create WOL socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSLog(@"WOL socket created");
|
Log(LOG_I, @"WOL socket created");
|
||||||
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -48,7 +48,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
|||||||
// try all ports
|
// try all ports
|
||||||
for (int j = 0; j < numPorts; j++) {
|
for (int j = 0; j < numPorts; j++) {
|
||||||
addr.sin_port = htons(ports[j]);
|
addr.sin_port = htons(ports[j]);
|
||||||
NSLog(@"Sending WOL packet");
|
Log(LOG_I, @"Sending WOL packet");
|
||||||
CFSocketSendData(wolSocket, dataAddress, dataPayload, 0);
|
CFSocketSendData(wolSocket, dataAddress, dataPayload, 0);
|
||||||
}
|
}
|
||||||
CFRelease(dataAddress);
|
CFRelease(dataAddress);
|
||||||
@@ -76,7 +76,7 @@ static const int ports[numPorts] = {7, 9, 47998, 47999, 48000};
|
|||||||
|
|
||||||
+ (NSData*) macStringToBytes:(NSString*)mac {
|
+ (NSData*) macStringToBytes:(NSString*)mac {
|
||||||
NSString* macString = [mac stringByReplacingOccurrencesOfString:@":" withString:@""];
|
NSString* macString = [mac stringByReplacingOccurrencesOfString:@":" withString:@""];
|
||||||
NSLog(@"MAC: %@", macString);
|
Log(LOG_D, @"MAC: %@", macString);
|
||||||
return [Utils hexToBytes:macString];
|
return [Utils hexToBytes:macString];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
@interface Connection : NSOperation <NSStreamDelegate>
|
@interface Connection : NSOperation <NSStreamDelegate>
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks;
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion;
|
||||||
-(void) terminate;
|
-(void) terminate;
|
||||||
-(void) terminateInternal;
|
-(void) terminateInternal;
|
||||||
-(void) main;
|
-(void) main;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
||||||
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
||||||
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
AUDIO_RENDERER_CALLBACKS _arCallbacks;
|
||||||
|
int _serverMajorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpusDecoder *opusDecoder;
|
static OpusDecoder *opusDecoder;
|
||||||
@@ -110,7 +111,7 @@ void ArInit(void)
|
|||||||
status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit);
|
status = AudioComponentInstanceNew(AudioComponentFindNext(NULL, &audioDesc), &audioUnit);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to instantiate new AudioComponent: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to instantiate new AudioComponent: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamBasicDescription audioFormat = {0};
|
AudioStreamBasicDescription audioFormat = {0};
|
||||||
@@ -131,7 +132,7 @@ void ArInit(void)
|
|||||||
&audioFormat,
|
&audioFormat,
|
||||||
sizeof(audioFormat));
|
sizeof(audioFormat));
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"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);
|
||||||
}
|
}
|
||||||
|
|
||||||
AURenderCallbackStruct callbackStruct = {0};
|
AURenderCallbackStruct callbackStruct = {0};
|
||||||
@@ -145,12 +146,12 @@ void ArInit(void)
|
|||||||
&callbackStruct,
|
&callbackStruct,
|
||||||
sizeof(callbackStruct));
|
sizeof(callbackStruct));
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to set audio unit callback: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to set audio unit callback: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = AudioUnitInitialize(audioUnit);
|
status = AudioUnitInitialize(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to initialize audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +164,7 @@ void ArRelease(void)
|
|||||||
|
|
||||||
OSStatus status = AudioUnitUninitialize(audioUnit);
|
OSStatus status = AudioUnitUninitialize(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to uninitialize audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio session is now inactive
|
// Audio session is now inactive
|
||||||
@@ -185,7 +186,7 @@ void ArStart(void)
|
|||||||
{
|
{
|
||||||
OSStatus status = AudioOutputUnitStart(audioUnit);
|
OSStatus status = AudioOutputUnitStart(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to start audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +194,7 @@ void ArStop(void)
|
|||||||
{
|
{
|
||||||
OSStatus status = AudioOutputUnitStop(audioUnit);
|
OSStatus status = AudioOutputUnitStop(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
NSLog(@"Unable to stop audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +214,7 @@ void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||||||
|
|
||||||
[audioLock lock];
|
[audioLock lock];
|
||||||
if (audioBufferQueueLength > MAX_QUEUE_ENTRIES) {
|
if (audioBufferQueueLength > MAX_QUEUE_ENTRIES) {
|
||||||
NSLog(@"Audio player too slow. Dropping all decoded samples!");
|
Log(LOG_W, @"Audio player too slow. Dropping all decoded samples!");
|
||||||
|
|
||||||
// Clear all values from the buffer queue
|
// Clear all values from the buffer queue
|
||||||
struct AUDIO_BUFFER_QUEUE_ENTRY *entry;
|
struct AUDIO_BUFFER_QUEUE_ENTRY *entry;
|
||||||
@@ -294,12 +295,13 @@ void ClDisplayTransientMessage(char* message)
|
|||||||
LiStopConnection();
|
LiStopConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_host = config.hostAddr;
|
_host = config.hostAddr;
|
||||||
renderer = myRenderer;
|
renderer = myRenderer;
|
||||||
_callbacks = callbacks;
|
_callbacks = callbacks;
|
||||||
|
_serverMajorVersion = serverMajorVersion;
|
||||||
_streamConfig.width = config.width;
|
_streamConfig.width = config.width;
|
||||||
_streamConfig.height = config.height;
|
_streamConfig.height = config.height;
|
||||||
_streamConfig.fps = config.frameRate;
|
_streamConfig.fps = config.frameRate;
|
||||||
@@ -431,7 +433,7 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||||||
&_drCallbacks,
|
&_drCallbacks,
|
||||||
&_arCallbacks,
|
&_arCallbacks,
|
||||||
&dummyPlCallbacks,
|
&dummyPlCallbacks,
|
||||||
NULL, 0);
|
NULL, 0, _serverMajorVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "OnScreenControls.h"
|
#import "OnScreenControls.h"
|
||||||
#import "StreamView.h"
|
#import "StreamView.h"
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
#import "HttpResponse.h"
|
||||||
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
@implementation StreamManager {
|
@implementation StreamManager {
|
||||||
StreamConfiguration* _config;
|
StreamConfiguration* _config;
|
||||||
@@ -41,11 +44,13 @@
|
|||||||
deviceName:@"roth"
|
deviceName:@"roth"
|
||||||
cert:cert];
|
cert:cert];
|
||||||
|
|
||||||
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
|
||||||
NSString* pairStatus = [HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"];
|
NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
|
||||||
NSString* currentClient = [HttpManager getStringFromXML:serverInfoResp tag:@"CurrentClient"];
|
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
|
||||||
if (currentGame == NULL || pairStatus == NULL) {
|
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
|
||||||
|
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
||||||
|
if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL || appversion == NULL) {
|
||||||
[_callbacks launchFailed:@"Failed to connect to PC"];
|
[_callbacks launchFailed:@"Failed to connect to PC"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,8 +86,11 @@
|
|||||||
[((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width
|
[((StreamView*)_renderView) setMouseDeltaFactors:_config.width / screenSize.width
|
||||||
y:_config.height / screenSize.height];
|
y:_config.height / screenSize.height];
|
||||||
|
|
||||||
|
int majorVersion = [[appversion substringToIndex:1] intValue];
|
||||||
|
Log(LOG_I, @"Server is generation %d", majorVersion);
|
||||||
|
|
||||||
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
VideoDecoderRenderer* renderer = [[VideoDecoderRenderer alloc]initWithView:_renderView];
|
||||||
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks];
|
_connection = [[Connection alloc] initWithConfig:_config renderer:renderer connectionCallbacks:_callbacks serverMajorVersion:majorVersion];
|
||||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||||
[opQueue addOperation:_connection];
|
[opQueue addOperation:_connection];
|
||||||
}
|
}
|
||||||
@@ -102,19 +110,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) launchApp:(HttpManager*)hMan {
|
- (BOOL) launchApp:(HttpManager*)hMan {
|
||||||
NSData* launchResp = [hMan executeRequestSynchronously:
|
HttpResponse* launchResp = [[HttpResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest:
|
||||||
[hMan newLaunchRequest:_config.appID
|
[hMan newLaunchRequest:_config.appID
|
||||||
width:_config.width
|
width:_config.width
|
||||||
height:_config.height
|
height:_config.height
|
||||||
refreshRate:_config.frameRate
|
refreshRate:_config.frameRate
|
||||||
rikey:[Utils bytesToHex:_config.riKey]
|
rikey:[Utils bytesToHex:_config.riKey]
|
||||||
rikeyid:_config.riKeyId]];
|
rikeyid:_config.riKeyId]]];
|
||||||
NSString *gameSession = [HttpManager getStringFromXML:launchResp tag:@"gamesession"];
|
NSString *gameSession = [launchResp getStringTag:@"gamesession"];
|
||||||
if (launchResp == NULL) {
|
if (launchResp == NULL || ![launchResp isStatusOk]) {
|
||||||
[_callbacks launchFailed:@"Failed to launch app"];
|
[_callbacks launchFailed:@"Failed to launch app"];
|
||||||
|
Log(LOG_E, @"Failed Launch Response: %@", launchResp.statusMessage);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) {
|
} else if (gameSession == NULL || [gameSession isEqualToString:@"0"]) {
|
||||||
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:launchResp]];
|
[_callbacks launchFailed:launchResp.statusMessage];
|
||||||
|
Log(LOG_E, @"Failed to parse game session. Code: %ld Response: %@", (long)launchResp.statusCode, launchResp.statusMessage);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,15 +133,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) resumeApp:(HttpManager*)hMan {
|
- (BOOL) resumeApp:(HttpManager*)hMan {
|
||||||
NSData* resumeResp = [hMan executeRequestSynchronously:
|
HttpResponse* resumeResp = [[HttpResponse alloc] init];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:resumeResp withUrlRequest:
|
||||||
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
|
[hMan newResumeRequestWithRiKey:[Utils bytesToHex:_config.riKey]
|
||||||
riKeyId:_config.riKeyId]];
|
riKeyId:_config.riKeyId]]];
|
||||||
NSString *resume = [HttpManager getStringFromXML:resumeResp tag:@"resume"];
|
NSString* resume = [resumeResp getStringTag:@"resume"];
|
||||||
if (resumeResp == NULL) {
|
if (resumeResp == NULL || ![resumeResp isStatusOk]) {
|
||||||
[_callbacks launchFailed:@"Failed to resume app"];
|
[_callbacks launchFailed:@"Failed to resume app"];
|
||||||
|
Log(LOG_E, @"Failed Resume Response: %@", resumeResp.statusMessage);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else if (resume == NULL || [resume isEqualToString:@"0"]) {
|
} else if (resume == NULL || [resume isEqualToString:@"0"]) {
|
||||||
[_callbacks launchFailed:[HttpManager getStatusStringFromXML:resumeResp]];
|
[_callbacks launchFailed:resumeResp.statusMessage];
|
||||||
|
Log(LOG_E, @"Failed to parse resume response. Code: %ld Response: %@", (long)resumeResp.statusCode, resumeResp.statusMessage);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
kCFAllocatorDefault,
|
kCFAllocatorDefault,
|
||||||
NULL, 0, nalLength + 1, 0);
|
NULL, 0, nalLength + 1, 0);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
|
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
|
||||||
oldOffset, NAL_LENGTH_PREFIX_SIZE);
|
oldOffset, NAL_LENGTH_PREFIX_SIZE);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
kCFAllocatorDefault, NULL, 0,
|
kCFAllocatorDefault, NULL, 0,
|
||||||
NAL_LENGTH_PREFIX_SIZE, 0);
|
NAL_LENGTH_PREFIX_SIZE, 0);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferAppendMemoryBlock failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferAppendMemoryBlock failed: %d", (int)status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
|
status = CMBlockBufferReplaceDataBytes(lengthBytes, existingBuffer,
|
||||||
oldOffset, NAL_LENGTH_PREFIX_SIZE);
|
oldOffset, NAL_LENGTH_PREFIX_SIZE);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
kCFAllocatorNull, // Don't deallocate data on free
|
kCFAllocatorNull, // Don't deallocate data on free
|
||||||
NULL, 0, dataLength, 0);
|
NULL, 0, dataLength, 0);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferReplaceDataBytes failed: %d", (int)status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
|
|
||||||
// Check for previous decoder errors before doing anything
|
// Check for previous decoder errors before doing anything
|
||||||
if (displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) {
|
if (displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) {
|
||||||
NSLog(@"Display layer rendering failed: %@", displayLayer.error);
|
Log(LOG_E, @"Display layer rendering failed: %@", displayLayer.error);
|
||||||
|
|
||||||
// Recreate the display layer
|
// Recreate the display layer
|
||||||
[self reinitializeDisplayLayer];
|
[self reinitializeDisplayLayer];
|
||||||
@@ -152,14 +152,14 @@
|
|||||||
|
|
||||||
if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) {
|
if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) {
|
||||||
if (nalType == NAL_TYPE_SPS) {
|
if (nalType == NAL_TYPE_SPS) {
|
||||||
NSLog(@"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 (nalType == NAL_TYPE_PPS) {
|
||||||
NSLog(@"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;
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
|
const uint8_t* const parameterSetPointers[] = { [spsData bytes], [ppsData bytes] };
|
||||||
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
|
const size_t parameterSetSizes[] = { [spsData length], [ppsData length] };
|
||||||
|
|
||||||
NSLog(@"Constructing new format description");
|
Log(LOG_I, @"Constructing new format description");
|
||||||
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
|
||||||
2, /* count of parameter sets */
|
2, /* count of parameter sets */
|
||||||
parameterSetPointers,
|
parameterSetPointers,
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
NAL_LENGTH_PREFIX_SIZE,
|
NAL_LENGTH_PREFIX_SIZE,
|
||||||
&formatDesc);
|
&formatDesc);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"Failed to create format description: %d", (int)status);
|
Log(LOG_E, @"Failed to create format description: %d", (int)status);
|
||||||
formatDesc = NULL;
|
formatDesc = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
|
|
||||||
status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer);
|
status = CMBlockBufferCreateEmpty(NULL, 0, 0, &blockBuffer);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status);
|
Log(LOG_E, @"CMBlockBufferCreateEmpty failed: %d", (int)status);
|
||||||
free(data);
|
free(data);
|
||||||
return DR_NEED_IDR;
|
return DR_NEED_IDR;
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
NULL, 0, NULL,
|
NULL, 0, NULL,
|
||||||
&sampleBuffer);
|
&sampleBuffer);
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
NSLog(@"CMSampleBufferCreate failed: %d", (int)status);
|
Log(LOG_E, @"CMSampleBufferCreate failed: %d", (int)status);
|
||||||
CFRelease(blockBuffer);
|
CFRelease(blockBuffer);
|
||||||
return DR_NEED_IDR;
|
return DR_NEED_IDR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// Logger.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/10/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef Limelight_Logger_h
|
||||||
|
#define Limelight_Logger_h
|
||||||
|
|
||||||
|
#import <stdarg.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LOG_D,
|
||||||
|
LOG_I,
|
||||||
|
LOG_W,
|
||||||
|
LOG_E
|
||||||
|
} LogLevel;
|
||||||
|
|
||||||
|
#define PRFX_DEBUG @"<DEBUG>"
|
||||||
|
#define PRFX_INFO @"<INFO>"
|
||||||
|
#define PRFX_WARN @"<WARN>"
|
||||||
|
#define PRFX_ERROR @"<ERROR>"
|
||||||
|
|
||||||
|
void Log(LogLevel level, NSString* fmt, ...);
|
||||||
|
void LogTag(LogLevel level, NSString* tag, NSString* fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Logger.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/10/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "Logger.h"
|
||||||
|
|
||||||
|
void LogTagv(LogLevel level, NSString* tag, NSString* fmt, va_list args);
|
||||||
|
|
||||||
|
void Log(LogLevel level, NSString* fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
LogTagv(level, NULL, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogTag(LogLevel level, NSString* tag, NSString* fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
LogTagv(level, tag, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogTagv(LogLevel level, NSString* tag, NSString* fmt, va_list args) {
|
||||||
|
NSString* levelPrefix = @"";
|
||||||
|
|
||||||
|
switch(level) {
|
||||||
|
case LOG_D:
|
||||||
|
levelPrefix = PRFX_DEBUG;
|
||||||
|
break;
|
||||||
|
case LOG_I:
|
||||||
|
levelPrefix = PRFX_INFO;
|
||||||
|
break;
|
||||||
|
case LOG_W:
|
||||||
|
levelPrefix = PRFX_WARN;
|
||||||
|
break;
|
||||||
|
case LOG_E:
|
||||||
|
levelPrefix = PRFX_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NSString* prefixedString;
|
||||||
|
if (tag) {
|
||||||
|
prefixedString = [NSString stringWithFormat:@"%@ (%@) %@", levelPrefix, tag, fmt];
|
||||||
|
} else {
|
||||||
|
prefixedString = [NSString stringWithFormat:@"%@ %@", levelPrefix, fmt];
|
||||||
|
}
|
||||||
|
NSLogv(prefixedString, args);
|
||||||
|
}
|
||||||
@@ -56,18 +56,18 @@ NSString *const deviceName = @"roth";
|
|||||||
if (inet_addr([host UTF8String]) != INADDR_NONE) {
|
if (inet_addr([host UTF8String]) != INADDR_NONE) {
|
||||||
// Already an IP address
|
// Already an IP address
|
||||||
int addr = inet_addr([host UTF8String]);
|
int addr = inet_addr([host UTF8String]);
|
||||||
NSLog(@"host address: %d", addr);
|
Log(LOG_I, @"host address: %d", addr);
|
||||||
return addr;
|
return addr;
|
||||||
} else {
|
} else {
|
||||||
hostent = gethostbyname([host UTF8String]);
|
hostent = gethostbyname([host UTF8String]);
|
||||||
if (hostent != NULL) {
|
if (hostent != NULL) {
|
||||||
char* ipstr = inet_ntoa(*(struct in_addr*)hostent->h_addr_list[0]);
|
char* ipstr = inet_ntoa(*(struct in_addr*)hostent->h_addr_list[0]);
|
||||||
NSLog(@"Resolved %@ -> %s", host, ipstr);
|
Log(LOG_I, @"Resolved %@ -> %s", host, ipstr);
|
||||||
int addr = inet_addr(ipstr);
|
int addr = inet_addr(ipstr);
|
||||||
NSLog(@"host address: %d", addr);
|
Log(LOG_I, @"host address: %d", addr);
|
||||||
return addr;
|
return addr;
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Failed to resolve host: %d", h_errno);
|
Log(LOG_W, @"Failed to resolve host: %d", h_errno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// LoadingFrameViewController.h
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/24/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface LoadingFrameViewController : UIViewController
|
||||||
|
|
||||||
|
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *loadingSpinner;
|
||||||
|
@end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// LoadingFrameViewController.m
|
||||||
|
// Limelight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 2/24/15.
|
||||||
|
// Copyright (c) 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "LoadingFrameViewController.h"
|
||||||
|
|
||||||
|
@interface LoadingFrameViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation LoadingFrameViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
// center the loading spinner
|
||||||
|
self.loadingSpinner.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didReceiveMemoryWarning {
|
||||||
|
[super didReceiveMemoryWarning];
|
||||||
|
// Dispose of any resources that can be recreated.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma mark - Navigation
|
||||||
|
|
||||||
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
// Get the new view controller using [segue destinationViewController].
|
||||||
|
// Pass the selected object to the new view controller.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -12,13 +12,12 @@
|
|||||||
#import "StreamConfiguration.h"
|
#import "StreamConfiguration.h"
|
||||||
#import "UIComputerView.h"
|
#import "UIComputerView.h"
|
||||||
#import "UIAppView.h"
|
#import "UIAppView.h"
|
||||||
#import "AppManager.h"
|
#import "AppAssetManager.h"
|
||||||
#import "SWRevealViewController.h"
|
#import "SWRevealViewController.h"
|
||||||
|
|
||||||
@interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate>
|
@interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate>
|
||||||
|
|
||||||
@property (strong, nonatomic) IBOutlet UIButton *limelightLogoButton;
|
@property (strong, nonatomic) IBOutlet UIButton *limelightLogoButton;
|
||||||
@property (weak, nonatomic) IBOutlet UIBarButtonItem *computerNameButton;
|
@property (weak, nonatomic) IBOutlet UIBarButtonItem *computerNameButton;
|
||||||
|
|
||||||
+ (StreamConfiguration*) getStreamConfiguration;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
#import "Connection.h"
|
#import "Connection.h"
|
||||||
#import "VideoDecoderRenderer.h"
|
|
||||||
#import "StreamManager.h"
|
#import "StreamManager.h"
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
#import "UIComputerView.h"
|
#import "UIComputerView.h"
|
||||||
@@ -19,6 +18,10 @@
|
|||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import "Settings.h"
|
#import "Settings.h"
|
||||||
#import "WakeOnLanManager.h"
|
#import "WakeOnLanManager.h"
|
||||||
|
#import "AppListResponse.h"
|
||||||
|
#import "ServerInfoResponse.h"
|
||||||
|
#import "StreamFrameViewController.h"
|
||||||
|
#import "LoadingFrameViewController.h"
|
||||||
|
|
||||||
@implementation MainFrameViewController {
|
@implementation MainFrameViewController {
|
||||||
NSOperationQueue* _opQueue;
|
NSOperationQueue* _opQueue;
|
||||||
@@ -27,18 +30,14 @@
|
|||||||
NSData* _cert;
|
NSData* _cert;
|
||||||
NSString* _currentGame;
|
NSString* _currentGame;
|
||||||
DiscoveryManager* _discMan;
|
DiscoveryManager* _discMan;
|
||||||
AppManager* _appManager;
|
AppAssetManager* _appManager;
|
||||||
|
StreamConfiguration* _streamConfig;
|
||||||
UIAlertView* _pairAlert;
|
UIAlertView* _pairAlert;
|
||||||
UIScrollView* hostScrollView;
|
UIScrollView* hostScrollView;
|
||||||
int currentPosition;
|
int currentPosition;
|
||||||
}
|
}
|
||||||
static NSMutableSet* hostList;
|
static NSMutableSet* hostList;
|
||||||
static NSArray* appList;
|
static NSArray* appList;
|
||||||
static StreamConfiguration* streamConfig;
|
|
||||||
|
|
||||||
+ (StreamConfiguration*) getStreamConfiguration {
|
|
||||||
return streamConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showPIN:(NSString *)PIN {
|
- (void)showPIN:(NSString *)PIN {
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||||
@@ -53,6 +52,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Failed" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Failed" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
||||||
[_pairAlert show];
|
[_pairAlert show];
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
|
[self hideLoadingFrame];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +62,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Succesful" message:@"Successfully paired to host" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Succesful" message:@"Successfully paired to host" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
||||||
[_pairAlert show];
|
[_pairAlert show];
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
|
[self hideLoadingFrame];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,23 +70,34 @@ static StreamConfiguration* streamConfig;
|
|||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
_computerNameButton.title = _selectedHost.name;
|
_computerNameButton.title = _selectedHost.name;
|
||||||
[self.navigationController.navigationBar setNeedsLayout];
|
[self.navigationController.navigationBar setNeedsLayout];
|
||||||
});
|
});
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
NSData* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
|
|
||||||
appList = [HttpManager getAppListFromXML:appListResp];
|
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
AppListResponse* appListResp = [[AppListResponse alloc] init];
|
||||||
[self updateApps];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
|
||||||
});
|
if (appListResp == nil || ![appListResp isStatusOk]) {
|
||||||
|
Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
|
||||||
[_appManager stopRetrieving];
|
} else {
|
||||||
[_appManager retrieveAssets:appList fromHost:_selectedHost];
|
appList = [appListResp getAppList];
|
||||||
|
if (appList == nil) {
|
||||||
|
Log(LOG_W, @"Failed to parse applist");
|
||||||
|
} else {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self updateApps];
|
||||||
|
});
|
||||||
|
|
||||||
|
[_appManager stopRetrieving];
|
||||||
|
[_appManager retrieveAssets:appList fromHost:_selectedHost];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self hideLoadingFrame];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showHostSelectionView {
|
- (void)showHostSelectionView {
|
||||||
appList = [[NSArray alloc] init];
|
appList = [[NSArray alloc] init];
|
||||||
|
[_appManager stopRetrieving];
|
||||||
_computerNameButton.title = @"No Host Selected";
|
_computerNameButton.title = @"No Host Selected";
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
[self.view addSubview:hostScrollView];
|
[self.view addSubview:hostScrollView];
|
||||||
@@ -104,32 +116,40 @@ static StreamConfiguration* streamConfig;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) hostClicked:(Host *)host {
|
- (void) hostClicked:(Host *)host {
|
||||||
NSLog(@"Clicked host: %@", host.name);
|
Log(LOG_D, @"Clicked host: %@", host.name);
|
||||||
|
[self showLoadingFrame];
|
||||||
_selectedHost = host;
|
_selectedHost = host;
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
if ([[HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"] isEqualToString:@"1"]) {
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
|
||||||
NSLog(@"Already Paired");
|
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
|
||||||
[self alreadyPaired];
|
Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage);
|
||||||
|
[self hideLoadingFrame];
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"Trying to pair");
|
Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
|
||||||
// Polling the server while pairing causes the server to screw up
|
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
|
||||||
[_discMan stopDiscoveryBlocking];
|
Log(LOG_I, @"Already Paired");
|
||||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
|
[self alreadyPaired];
|
||||||
[_opQueue addOperation:pMan];
|
} else {
|
||||||
|
Log(LOG_I, @"Trying to pair");
|
||||||
|
// Polling the server while pairing causes the server to screw up
|
||||||
|
[_discMan stopDiscoveryBlocking];
|
||||||
|
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
|
||||||
|
[_opQueue addOperation:pMan];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)hostLongClicked:(Host *)host view:(UIView *)view {
|
- (void)hostLongClicked:(Host *)host view:(UIView *)view {
|
||||||
NSLog(@"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) {
|
||||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
[hMan executeRequestSynchronously:[hMan newUnpairRequest]];
|
[hMan executeRequest:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]];
|
||||||
});
|
});
|
||||||
}]];
|
}]];
|
||||||
} else {
|
} else {
|
||||||
@@ -163,7 +183,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
|
|
||||||
// these two lines are required for iPad support of UIAlertSheet
|
// these two lines are required for iPad support of UIAlertSheet
|
||||||
longClickAlert.popoverPresentationController.sourceView = view;
|
longClickAlert.popoverPresentationController.sourceView = view;
|
||||||
|
|
||||||
longClickAlert.popoverPresentationController.sourceRect = CGRectMake(view.bounds.size.width / 2.0, view.bounds.size.height / 2.0, 1.0, 1.0); // center of the view
|
longClickAlert.popoverPresentationController.sourceRect = CGRectMake(view.bounds.size.width / 2.0, view.bounds.size.height / 2.0, 1.0, 1.0); // center of the view
|
||||||
[self presentViewController:longClickAlert animated:YES completion:^{
|
[self presentViewController:longClickAlert animated:YES completion:^{
|
||||||
[self updateHosts];
|
[self updateHosts];
|
||||||
@@ -171,13 +191,14 @@ static StreamConfiguration* streamConfig;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) addHostClicked {
|
- (void) addHostClicked {
|
||||||
NSLog(@"Clicked add host");
|
Log(LOG_D, @"Clicked add host");
|
||||||
|
[self showLoadingFrame];
|
||||||
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
[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){
|
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){
|
||||||
if (host != nil) {
|
if (host != nil) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
[dataMan saveHosts];
|
[dataMan saveHosts];
|
||||||
@@ -188,7 +209,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
[self updateHosts];
|
[self updateHosts];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
UIAlertController* hostNotFoundAlert = [UIAlertController alertControllerWithTitle:@"Host Not Found" message:[NSString stringWithFormat:@"Unable to connect to host: \n%@", hostAddress] preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* hostNotFoundAlert = [UIAlertController alertControllerWithTitle:@"Add Host" message:error preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[hostNotFoundAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
[hostNotFoundAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self presentViewController:hostNotFoundAlert animated:YES completion:nil];
|
[self presentViewController:hostNotFoundAlert animated:YES completion:nil];
|
||||||
@@ -197,16 +218,17 @@ static StreamConfiguration* streamConfig;
|
|||||||
}];});
|
}];});
|
||||||
}]];
|
}]];
|
||||||
[alertController addTextFieldWithConfigurationHandler:nil];
|
[alertController addTextFieldWithConfigurationHandler:nil];
|
||||||
|
[self hideLoadingFrame];
|
||||||
[self presentViewController:alertController animated:YES completion:nil];
|
[self presentViewController:alertController animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) appClicked:(App *)app {
|
- (void) appClicked:(App *)app {
|
||||||
NSLog(@"Clicked app: %@", app.appName);
|
Log(LOG_D, @"Clicked app: %@", app.appName);
|
||||||
streamConfig = [[StreamConfiguration alloc] init];
|
_streamConfig = [[StreamConfiguration alloc] init];
|
||||||
streamConfig.host = _selectedHost.address;
|
_streamConfig.host = _selectedHost.address;
|
||||||
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.address];
|
_streamConfig.hostAddr = [Utils resolveHost:_selectedHost.address];
|
||||||
streamConfig.appID = app.appId;
|
_streamConfig.appID = app.appId;
|
||||||
if (streamConfig.hostAddr == 0) {
|
if (_streamConfig.hostAddr == 0) {
|
||||||
[self displayDnsFailedDialog];
|
[self displayDnsFailedDialog];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -214,10 +236,10 @@ static StreamConfiguration* streamConfig;
|
|||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
Settings* streamSettings = [dataMan retrieveSettings];
|
Settings* streamSettings = [dataMan retrieveSettings];
|
||||||
|
|
||||||
streamConfig.frameRate = [streamSettings.framerate intValue];
|
_streamConfig.frameRate = [streamSettings.framerate intValue];
|
||||||
streamConfig.bitRate = [streamSettings.bitrate intValue];
|
_streamConfig.bitRate = [streamSettings.bitrate intValue];
|
||||||
streamConfig.height = [streamSettings.height intValue];
|
_streamConfig.height = [streamSettings.height intValue];
|
||||||
streamConfig.width = [streamSettings.width intValue];
|
_streamConfig.width = [streamSettings.width intValue];
|
||||||
|
|
||||||
|
|
||||||
if (currentPosition != FrontViewPositionLeft) {
|
if (currentPosition != FrontViewPositionLeft) {
|
||||||
@@ -227,29 +249,29 @@ static StreamConfiguration* streamConfig;
|
|||||||
App* currentApp = [self findRunningApp];
|
App* currentApp = [self findRunningApp];
|
||||||
if (currentApp != nil) {
|
if (currentApp != nil) {
|
||||||
UIAlertController* alertController = [UIAlertController
|
UIAlertController* alertController = [UIAlertController
|
||||||
alertControllerWithTitle: app.appName
|
alertControllerWithTitle: app.appName
|
||||||
message: [app.appId isEqualToString:currentApp.appId] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.appName]preferredStyle:UIAlertControllerStyleAlert];
|
message: [app.appId isEqualToString:currentApp.appId] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.appName]preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addAction:[UIAlertAction
|
[alertController addAction:[UIAlertAction
|
||||||
actionWithTitle:[app.appId isEqualToString:currentApp.appId] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
actionWithTitle:[app.appId isEqualToString:currentApp.appId] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||||
NSLog(@"Resuming application: %@", currentApp.appName);
|
Log(LOG_I, @"Resuming application: %@", currentApp.appName);
|
||||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||||
}]];
|
}]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:
|
[alertController addAction:[UIAlertAction actionWithTitle:
|
||||||
[app.appId isEqualToString:currentApp.appId] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
[app.appId isEqualToString:currentApp.appId] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
NSLog(@"Quitting application: %@", currentApp.appName);
|
Log(LOG_I, @"Quitting application: %@", currentApp.appName);
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
[hMan executeRequestSynchronously:[hMan newQuitAppRequest]];
|
[hMan executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[hMan newQuitAppRequest]]];
|
||||||
// TODO: handle failure to quit app
|
// TODO: handle failure to quit app
|
||||||
currentApp.isRunning = NO;
|
currentApp.isRunning = NO;
|
||||||
|
|
||||||
if (![app.appId isEqualToString:currentApp.appId]) {
|
if (![app.appId isEqualToString:currentApp.appId]) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]];
|
}]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
[self presentViewController:alertController animated:YES completion:nil];
|
[self presentViewController:alertController animated:YES completion:nil];
|
||||||
} else {
|
} else {
|
||||||
@@ -257,7 +279,6 @@ static StreamConfiguration* streamConfig;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (App*) findRunningApp {
|
- (App*) findRunningApp {
|
||||||
for (App* app in appList) {
|
for (App* app in appList) {
|
||||||
if (app.isRunning) {
|
if (app.isRunning) {
|
||||||
@@ -275,14 +296,30 @@ static StreamConfiguration* streamConfig;
|
|||||||
currentPosition = position;
|
currentPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
if ([segue.destinationViewController isKindOfClass:[StreamFrameViewController class]]) {
|
||||||
|
StreamFrameViewController* streamFrame = segue.destinationViewController;
|
||||||
|
streamFrame.streamConfig = _streamConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) showLoadingFrame {
|
||||||
|
LoadingFrameViewController* loadingFrame = [self.storyboard instantiateViewControllerWithIdentifier:@"loadingFrame"];
|
||||||
|
[self.navigationController presentViewController:loadingFrame animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) hideLoadingFrame {
|
||||||
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
{
|
{
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
|
// Set the side bar button action. When it's tapped, it'll show the sidebar.
|
||||||
[_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
|
[_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
|
||||||
|
|
||||||
// Set the host name button action. When it's tapped, it'll show up the host selection view.
|
// Set the host name button action. When it's tapped, it'll show the host selection view.
|
||||||
[_computerNameButton setTarget:self];
|
[_computerNameButton setTarget:self];
|
||||||
[_computerNameButton setAction:@selector(showHostSelectionView)];
|
[_computerNameButton setAction:@selector(showHostSelectionView)];
|
||||||
|
|
||||||
@@ -296,12 +333,12 @@ static StreamConfiguration* streamConfig;
|
|||||||
currentPosition = FrontViewPositionLeft;
|
currentPosition = FrontViewPositionLeft;
|
||||||
|
|
||||||
// Set up crypto
|
// Set up crypto
|
||||||
_opQueue = [[NSOperationQueue alloc] init];
|
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
_uniqueId = [CryptoManager getUniqueID];
|
||||||
_cert = [CryptoManager readCertFromFile];
|
_cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
_appManager = [[AppManager alloc] initWithCallback:self];
|
_appManager = [[AppAssetManager alloc] initWithCallback:self];
|
||||||
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
|
|
||||||
// Only initialize the host picker list once
|
// Only initialize the host picker list once
|
||||||
if (hostList == nil) {
|
if (hostList == nil) {
|
||||||
@@ -344,7 +381,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
[super viewDidDisappear:animated];
|
[super viewDidDisappear:animated];
|
||||||
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
||||||
[_discMan stopDiscovery];
|
[_discMan stopDiscovery];
|
||||||
|
|
||||||
// In case the host objects were updated in the background
|
// In case the host objects were updated in the background
|
||||||
[[[DataManager alloc] init] saveHosts];
|
[[[DataManager alloc] init] saveHosts];
|
||||||
}
|
}
|
||||||
@@ -359,9 +396,9 @@ static StreamConfiguration* streamConfig;
|
|||||||
|
|
||||||
- (void) updateAllHosts:(NSArray *)hosts {
|
- (void) updateAllHosts:(NSArray *)hosts {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
NSLog(@"New host list:");
|
Log(LOG_D, @"New host list:");
|
||||||
for (Host* host in hosts) {
|
for (Host* host in hosts) {
|
||||||
NSLog(@"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}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online);
|
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}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online);
|
||||||
}
|
}
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList removeAllObjects];
|
[hostList removeAllObjects];
|
||||||
@@ -372,7 +409,7 @@ static StreamConfiguration* streamConfig;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateHosts {
|
- (void)updateHosts {
|
||||||
NSLog(@"Updating hosts...");
|
Log(LOG_I, @"Updating hosts...");
|
||||||
[[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
[[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
|
UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
|
||||||
UIComputerView* compView;
|
UIComputerView* compView;
|
||||||
@@ -450,4 +487,5 @@ static StreamConfiguration* streamConfig;
|
|||||||
- (BOOL)shouldAutorotate {
|
- (BOOL)shouldAutorotate {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -1140,7 +1140,7 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
// forbid gesture if the initial translation is not horizontal
|
// forbid gesture if the initial translation is not horizontal
|
||||||
UIView *recognizerView = _panGestureRecognizer.view;
|
UIView *recognizerView = _panGestureRecognizer.view;
|
||||||
CGPoint translation = [_panGestureRecognizer translationInView:recognizerView];
|
CGPoint translation = [_panGestureRecognizer translationInView:recognizerView];
|
||||||
// NSLog( @"translation:%@", NSStringFromCGPoint(translation) );
|
// Log(LOG_D, @"translation:%@", NSStringFromCGPoint(translation) );
|
||||||
// if ( fabs(translation.y/translation.x) > 1 )
|
// if ( fabs(translation.y/translation.x) > 1 )
|
||||||
// return NO;
|
// return NO;
|
||||||
|
|
||||||
@@ -1252,7 +1252,7 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
|
|
||||||
CGFloat xLocation = frontView.frame.origin.x;
|
CGFloat xLocation = frontView.frame.origin.x;
|
||||||
CGFloat velocity = [recognizer velocityInView:_contentView].x;
|
CGFloat velocity = [recognizer velocityInView:_contentView].x;
|
||||||
//NSLog( @"Velocity:%1.4f", velocity);
|
//Log(LOG_D, @"Velocity:%1.4f", velocity);
|
||||||
|
|
||||||
// depending on position we compute a simetric replacement of widths and positions
|
// depending on position we compute a simetric replacement of widths and positions
|
||||||
int symetry = xLocation<0 ? -1 : 1;
|
int symetry = xLocation<0 ? -1 : 1;
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
#import "Settings.h"
|
#import "Settings.h"
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
|
|
||||||
#define BITRATE_INTERVAL 1
|
#define BITRATE_INTERVAL 500 // in kbps
|
||||||
|
|
||||||
@implementation SettingsViewController {
|
@implementation SettingsViewController {
|
||||||
NSInteger _bitrate;
|
NSInteger _bitrate;
|
||||||
}
|
}
|
||||||
static NSString* bitrateFormat = @"Bitrate: %d Mbps";
|
static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
||||||
|
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
@@ -25,7 +25,7 @@ static NSString* bitrateFormat = @"Bitrate: %d Mbps";
|
|||||||
Settings* currentSettings = [dataMan retrieveSettings];
|
Settings* currentSettings = [dataMan retrieveSettings];
|
||||||
|
|
||||||
// Bitrate is persisted in kbps
|
// Bitrate is persisted in kbps
|
||||||
_bitrate = [currentSettings.bitrate integerValue] / 1000;
|
_bitrate = [currentSettings.bitrate integerValue];
|
||||||
NSInteger framerate = [currentSettings.framerate integerValue] == 30 ? 0 : 1;
|
NSInteger framerate = [currentSettings.framerate integerValue] == 30 ? 0 : 1;
|
||||||
NSInteger resolution;
|
NSInteger resolution;
|
||||||
if ([currentSettings.height integerValue] == 720) {
|
if ([currentSettings.height integerValue] == 720) {
|
||||||
@@ -40,16 +40,20 @@ static NSString* bitrateFormat = @"Bitrate: %d Mbps";
|
|||||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||||
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
||||||
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
||||||
[self.bitrateSlider setValue:_bitrate animated:YES];
|
[self.bitrateSlider setValue:(_bitrate / 1000) animated:YES];
|
||||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]];
|
[self updateBitrateText];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) bitrateSliderMoved {
|
- (void) bitrateSliderMoved {
|
||||||
_bitrate = BITRATE_INTERVAL * floor((self.bitrateSlider.value/BITRATE_INTERVAL)+0.5);
|
_bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
|
||||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]];
|
[self updateBitrateText];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) updateBitrateText {
|
||||||
|
// Display bitrate in Mbps
|
||||||
|
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) saveSettings {
|
- (void) saveSettings {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "Connection.h"
|
#import "Connection.h"
|
||||||
|
#import "StreamConfiguration.h"
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks>
|
@interface StreamFrameViewController : UIViewController <ConnectionCallbacks>
|
||||||
@property (strong, nonatomic) IBOutlet UILabel *stageLabel;
|
@property (strong, nonatomic) IBOutlet UILabel *stageLabel;
|
||||||
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
|
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
|
||||||
|
@property (nonatomic) StreamConfiguration* streamConfig;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
_controllerSupport = [[ControllerSupport alloc] init];
|
_controllerSupport = [[ControllerSupport alloc] init];
|
||||||
|
|
||||||
_streamMan = [[StreamManager alloc] initWithConfig:[MainFrameViewController getStreamConfiguration]
|
_streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig
|
||||||
renderView:self.view
|
renderView:self.view
|
||||||
connectionCallbacks:self];
|
connectionCallbacks:self];
|
||||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) returnToMainFrame {
|
- (void) returnToMainFrame {
|
||||||
|
[_controllerSupport cleanup];
|
||||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +59,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)edgeSwiped {
|
- (void)edgeSwiped {
|
||||||
NSLog(@"User swiped to end stream");
|
Log(LOG_D, @"User swiped to end stream");
|
||||||
[_streamMan stopStream];
|
[_streamMan stopStream];
|
||||||
[self returnToMainFrame];
|
[self returnToMainFrame];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) connectionStarted {
|
- (void) connectionStarted {
|
||||||
NSLog(@"Connection started");
|
Log(LOG_I, @"Connection started");
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self.spinner stopAnimating];
|
[self.spinner stopAnimating];
|
||||||
[self.stageLabel setText:@"Waiting for first frame..."];
|
[self.stageLabel setText:@"Waiting for first frame..."];
|
||||||
@@ -73,7 +74,7 @@
|
|||||||
UIScreenEdgePanGestureRecognizer* swipeGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)];
|
UIScreenEdgePanGestureRecognizer* swipeGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)];
|
||||||
swipeGesture.edges = UIRectEdgeLeft;
|
swipeGesture.edges = UIRectEdgeLeft;
|
||||||
if (swipeGesture == nil) {
|
if (swipeGesture == nil) {
|
||||||
NSLog(@"An error occured trying to create UIScreenEdgePanGestureRecognizer");
|
Log(LOG_E, @"An error occured trying to create UIScreenEdgePanGestureRecognizer");
|
||||||
} else {
|
} else {
|
||||||
[self.view addGestureRecognizer:swipeGesture];
|
[self.view addGestureRecognizer:swipeGesture];
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)connectionTerminated:(long)errorCode {
|
- (void)connectionTerminated:(long)errorCode {
|
||||||
NSLog(@"Connection terminated: %ld", errorCode);
|
Log(LOG_I, @"Connection terminated: %ld", errorCode);
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection was terminated" preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection was terminated" preferredStyle:UIAlertControllerStyleAlert];
|
||||||
@@ -95,7 +96,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) stageStarting:(char*)stageName {
|
- (void) stageStarting:(char*)stageName {
|
||||||
NSLog(@"Starting %s", stageName);
|
Log(LOG_I, @"Starting %s", stageName);
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
||||||
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
|
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
|
||||||
@@ -130,11 +131,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) displayMessage:(char*)message {
|
- (void) displayMessage:(char*)message {
|
||||||
NSLog(@"Display message: %s", message);
|
Log(LOG_I, @"Display message: %s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) displayTransientMessage:(char*)message {
|
- (void) displayTransientMessage:(char*)message {
|
||||||
NSLog(@"Display transient message: %s", message);
|
Log(LOG_I, @"Display transient message: %s", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning
|
- (void)didReceiveMemoryWarning
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
#Limelight iOS
|
#Limelight iOS
|
||||||
|
|
||||||
[Limelight](https://github.com/limelight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Limelight iOS will allow you to stream your full collection of Steam games from
|
[Limelight](https://github.com/limelight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Limelight iOS 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.
|
||||||
|
|
||||||
This is actively being developed and should be available on the AppStore soon.
|
This is actively being developed and will be available on the App Store soon - check back here or on [our website](http://limelight-stream.com) for updates.
|
||||||
|
|
||||||
We understand that Limelight users are eager for the opportunity to stream their Steam collection to their iOS devices. Limelight for iOS is in the testing stage and preliminary versions are available for beta testers.
|
We understand that Limelight users are eager for the opportunity to stream their Steam collection to their iOS devices. Limelight for iOS is in the testing stage and preliminary versions are available for beta testers.
|
||||||
|
|
||||||
In the meantime, check out the existing versions for [Android](https://github.com/limelight-stream/limelight-android) and [PC](https://github.com/limelight-stream/limelight-pc). Also, a client for [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) is in the works and actively being developed.
|
In the meantime, check out the existing versions for [Android](https://github.com/limelight-stream/limelight-android) and [PC](https://github.com/limelight-stream/limelight-pc). Also, a client for [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) is in the works and actively being developed.
|
||||||
|
|
||||||
Please be patient as we work to bring Limelight to more platforms.
|
Please be patient as we work to bring Limelight to more platforms.
|
||||||
|
|
||||||
+26
-2
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C81f" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10" minValue="1" maxValue="50" id="JAY-nj-UNz">
|
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="JAY-nj-UNz">
|
||||||
<rect key="frame" x="14" y="68" width="213" height="31"/>
|
<rect key="frame" x="14" y="68" width="213" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<color key="tintColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.3921568627" green="0.91372549020000005" blue="0.17254901959999999" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
@@ -226,6 +226,30 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="1946" y="514"/>
|
<point key="canvasLocation" x="1946" y="514"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--Loading Frame View Controller-->
|
||||||
|
<scene sceneID="lcG-48-utf">
|
||||||
|
<objects>
|
||||||
|
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="ZNo-L5-uxh" customClass="LoadingFrameViewController" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="le1-tU-NEp">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" id="N0D-dj-EuF">
|
||||||
|
<rect key="frame" x="494" y="365" width="37" height="37"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
</activityIndicatorView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="loadingSpinner" destination="N0D-dj-EuF" id="xEQ-nx-SOt"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="lJG-tq-Jrs" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="1946" y="1425"/>
|
||||||
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="Logo" width="36" height="36"/>
|
<image name="Logo" width="36" height="36"/>
|
||||||
|
|||||||
+25
-2
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C81f" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10" minValue="1" maxValue="50" id="3nn-MI-9Xu">
|
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="3nn-MI-9Xu">
|
||||||
<rect key="frame" x="14" y="49" width="204" height="31"/>
|
<rect key="frame" x="14" y="49" width="204" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<color key="tintColor" red="0.39215686274509803" green="0.9137254901960784" blue="0.17254901960784313" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.39215686274509803" green="0.9137254901960784" blue="0.17254901960784313" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
@@ -229,6 +229,29 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="2092" y="796"/>
|
<point key="canvasLocation" x="2092" y="796"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--Loading Frame View Controller-->
|
||||||
|
<scene sceneID="kPF-XD-S77">
|
||||||
|
<objects>
|
||||||
|
<viewController storyboardIdentifier="loadingFrame" modalTransitionStyle="crossDissolve" modalPresentationStyle="overCurrentContext" id="9W0-2D-0Kp" customClass="LoadingFrameViewController" sceneMemberID="viewController">
|
||||||
|
<view key="view" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="center" id="nSw-dc-mi4">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
|
||||||
|
<rect key="frame" x="266" y="141" width="37" height="37"/>
|
||||||
|
</activityIndicatorView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="loadingSpinner" destination="oNu-Gu-QeM" id="5IK-qn-mIZ"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="GaV-PK-JSI" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="2104" y="1266"/>
|
||||||
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="Logo" width="36" height="36"/>
|
<image name="Logo" width="36" height="36"/>
|
||||||
|
|||||||
+1
-1
Submodule limelight-common-c updated: 7883ce67cd...dc270ce988.
Reference in new issue
Block a user