2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #define BOOL XBMC_BOOL
23 #include "Application.h"
25 #include "GUIUserMessages.h"
26 #include "utils/log.h"
30 #if defined(TARGET_DARWIN)
31 #if defined(TARGET_DARWIN_IOS)
32 #import <Foundation/Foundation.h>
33 #import <UIKit/UIKit.h>
34 #import <mach/mach_host.h>
35 #import <sys/sysctl.h>
37 #import <Cocoa/Cocoa.h>
38 #import <CoreFoundation/CoreFoundation.h>
39 #import <IOKit/ps/IOPowerSources.h>
40 #import <IOKit/ps/IOPSKeys.h>
44 #import "DarwinUtils.h"
46 #ifndef NSAppKitVersionNumber10_5
47 #define NSAppKitVersionNumber10_5 949
50 #ifndef NSAppKitVersionNumber10_6
51 #define NSAppKitVersionNumber10_6 1038
72 iPhone4, //from here on list devices with retina support (e.x. mainscreen scale == 2.0)
95 // platform strings are based on http://theiphonewiki.com/wiki/Models
96 enum iosPlatform getIosPlatform()
98 #if defined(TARGET_DARWIN_IOS)
99 // Gets a string with the device model
101 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
102 char *machine = new char[size];
103 sysctlbyname("hw.machine", machine, &size, NULL, 0);
104 NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];
107 if ([platform isEqualToString:@"iPhone1,1"]) return iPhone2G;
108 if ([platform isEqualToString:@"iPhone1,2"]) return iPhone3G;
109 if ([platform isEqualToString:@"iPhone2,1"]) return iPhone3GS;
110 if ([platform isEqualToString:@"iPhone3,1"]) return iPhone4;
111 if ([platform isEqualToString:@"iPhone3,2"]) return iPhone4;
112 if ([platform isEqualToString:@"iPhone3,3"]) return iPhone4CDMA;
113 if ([platform isEqualToString:@"iPhone4,1"]) return iPhone4S;
114 if ([platform isEqualToString:@"iPhone5,1"]) return iPhone5;
115 if ([platform isEqualToString:@"iPhone5,2"]) return iPhone5GSMCDMA;
116 if ([platform isEqualToString:@"iPhone5,3"]) return iPhone5CGSM;
117 if ([platform isEqualToString:@"iPhone5,4"]) return iPhone5CGlobal;
118 if ([platform isEqualToString:@"iPhone6,1"]) return iPhone5SGSM;
119 if ([platform isEqualToString:@"iPhone6,2"]) return iPhone5SGlobal;
121 if ([platform isEqualToString:@"iPod1,1"]) return iPodTouch1G;
122 if ([platform isEqualToString:@"iPod2,1"]) return iPodTouch2G;
123 if ([platform isEqualToString:@"iPod3,1"]) return iPodTouch3G;
124 if ([platform isEqualToString:@"iPod4,1"]) return iPodTouch4G;
125 if ([platform isEqualToString:@"iPod5,1"]) return iPodTouch5G;
127 if ([platform isEqualToString:@"iPad1,1"]) return iPad;
128 if ([platform isEqualToString:@"iPad1,2"]) return iPad;
129 if ([platform isEqualToString:@"iPad2,1"]) return iPad2WIFI;
130 if ([platform isEqualToString:@"iPad2,2"]) return iPad2;
131 if ([platform isEqualToString:@"iPad2,3"]) return iPad2CDMA;
132 if ([platform isEqualToString:@"iPad2,4"]) return iPad2;
133 if ([platform isEqualToString:@"iPad2,5"]) return iPadMiniWIFI;
134 if ([platform isEqualToString:@"iPad2,6"]) return iPadMini;
135 if ([platform isEqualToString:@"iPad2,7"]) return iPadMiniGSMCDMA;
136 if ([platform isEqualToString:@"iPad3,1"]) return iPad3WIFI;
137 if ([platform isEqualToString:@"iPad3,2"]) return iPad3GSMCDMA;
138 if ([platform isEqualToString:@"iPad3,3"]) return iPad3;
139 if ([platform isEqualToString:@"iPad3,4"]) return iPad4WIFI;
140 if ([platform isEqualToString:@"iPad3,5"]) return iPad4;
141 if ([platform isEqualToString:@"iPad3,6"]) return iPad4GSMCDMA;
142 if ([platform isEqualToString:@"iPad4,1"]) return iPadAirWifi;
143 if ([platform isEqualToString:@"iPad4,2"]) return iPadAirCellular;
144 if ([platform isEqualToString:@"iPad4,4"]) return iPadMini2Wifi;
145 if ([platform isEqualToString:@"iPad4,5"]) return iPadMini2Cellular;
147 if ([platform isEqualToString:@"AppleTV2,1"]) return AppleTV2;
149 return iDeviceUnknown;
152 bool DarwinIsAppleTV2(void)
154 static enum iosPlatform platform = iDeviceUnknown;
155 #if defined(TARGET_DARWIN_IOS)
156 if( platform == iDeviceUnknown )
158 platform = getIosPlatform();
161 return (platform == AppleTV2);
164 bool DarwinIsMavericks(void)
166 static int isMavericks = -1;
167 #if defined(TARGET_DARWIN_OSX)
168 // there is no NSAppKitVersionNumber10_9 out there anywhere
169 // so we detect mavericks by one of these newly added app nap
170 // methods - and fix the ugly mouse rect problem which was hitting
171 // us when mavericks came out
172 if (isMavericks == -1)
174 CLog::Log(LOGDEBUG, "Detected Mavericks...");
175 isMavericks = [NSProcessInfo instancesRespondToSelector:@selector(beginActivityWithOptions:reason:)] == TRUE ? 1 : 0;
178 return isMavericks == 1;
181 bool DarwinIsSnowLeopard(void)
183 static int isSnowLeopard = -1;
184 #if defined(TARGET_DARWIN_OSX)
185 if (isSnowLeopard == -1)
187 double appKitVersion = floor(NSAppKitVersionNumber);
188 isSnowLeopard = (appKitVersion <= NSAppKitVersionNumber10_6 && appKitVersion > NSAppKitVersionNumber10_5) ? 1 : 0;
191 return isSnowLeopard == 1;
194 bool DarwinHasRetina(void)
196 static enum iosPlatform platform = iDeviceUnknown;
198 #if defined(TARGET_DARWIN_IOS)
199 if( platform == iDeviceUnknown )
201 platform = getIosPlatform();
204 return (platform >= iPhone4);
207 const char *GetDarwinOSReleaseString(void)
209 static std::string osreleaseStr;
210 if (osreleaseStr.empty())
213 sysctlbyname("kern.osrelease", NULL, &size, NULL, 0);
214 char *osrelease = new char[size];
215 sysctlbyname("kern.osrelease", osrelease, &size, NULL, 0);
216 osreleaseStr = osrelease;
219 return osreleaseStr.c_str();
222 const char *GetDarwinVersionString(void)
225 return [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String];
228 float GetIOSVersion(void)
232 #if defined(TARGET_DARWIN_IOS)
233 version = [[[UIDevice currentDevice] systemVersion] floatValue];
241 int GetDarwinFrameworkPath(bool forPython, char* path, uint32_t *pathsize)
244 // see if we can figure out who we are
250 // a) XBMC frappliance running under ATV2
251 Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
252 if (XBMCfrapp != NULL)
254 pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"Frameworks" ofType:@""];
255 strcpy(path, [pathname UTF8String]);
256 *pathsize = strlen(path);
257 //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(a) -> %s", path);
261 // b) XBMC application running under IOS
262 pathname = [[NSBundle mainBundle] executablePath];
263 if (pathname && strstr([pathname UTF8String], "XBMC.app/XBMC"))
265 strcpy(path, [pathname UTF8String]);
266 // Move backwards to last "/"
267 for (int n=strlen(path)-1; path[n] != '/'; n--)
269 strcat(path, "Frameworks");
270 *pathsize = strlen(path);
271 //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(c) -> %s", path);
275 // d) XBMC application running under OSX
276 pathname = [[NSBundle mainBundle] executablePath];
277 if (pathname && strstr([pathname UTF8String], "Contents"))
279 strcpy(path, [pathname UTF8String]);
280 // ExectuablePath is <product>.app/Contents/MacOS/<executable>
281 char *lastSlash = strrchr(path, '/');
284 *lastSlash = '\0';//remove /<executable>
285 lastSlash = strrchr(path, '/');
287 *lastSlash = '\0';//remove /MacOS
289 strcat(path, "/Libraries");//add /Libraries
290 //we should have <product>.app/Contents/Libraries now
291 *pathsize = strlen(path);
292 //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(d) -> %s", path);
296 // e) XBMC OSX binary running under xcode or command-line
297 // but only if it's not for python. In this case, let python
298 // use it's internal compiled paths.
301 strcpy(path, PREFIX_USR_PATH);
302 strcat(path, "/lib");
303 *pathsize = strlen(path);
304 //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(e) -> %s", path);
311 int GetDarwinExecutablePath(char* path, uint32_t *pathsize)
314 // see if we can figure out who we are
317 // a) XBMC frappliance running under ATV2
318 Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
319 if (XBMCfrapp != NULL)
321 pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"XBMC" ofType:@""];
322 strcpy(path, [pathname UTF8String]);
323 *pathsize = strlen(path);
324 //CLog::Log(LOGDEBUG, "DarwinExecutablePath(a) -> %s", path);
328 // b) XBMC application running under IOS
329 // c) XBMC application running under OSX
330 pathname = [[NSBundle mainBundle] executablePath];
331 strcpy(path, [pathname UTF8String]);
332 *pathsize = strlen(path);
333 //CLog::Log(LOGDEBUG, "DarwinExecutablePath(b/c) -> %s", path);
338 const char* DarwinGetXbmcRootFolder(void)
340 static std::string rootFolder = "";
341 if ( rootFolder.length() == 0)
343 if (DarwinIsIosSandboxed())
345 // when we are sandbox make documents our root
346 // so that user can access everything he needs
347 // via itunes sharing
348 rootFolder = "Documents";
352 rootFolder = "Library/Preferences";
355 return rootFolder.c_str();
358 bool DarwinIsIosSandboxed(void)
363 uint32_t path_size = 2*MAXPATHLEN;
364 char given_path[2*MAXPATHLEN];
367 memset(given_path, 0x0, path_size);
368 /* Get Application directory */
369 result = GetDarwinExecutablePath(given_path, &path_size);
372 // we re sandboxed if we are installed in /var/mobile/Applications
373 if (strlen("/var/mobile/Applications/") < path_size &&
374 strncmp(given_path, "/var/mobile/Applications/", strlen("/var/mobile/Applications/")) == 0)
383 bool DarwinHasVideoToolboxDecoder(void)
385 static int DecoderAvailable = -1;
387 if (DecoderAvailable == -1)
389 Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
390 if (XBMCfrapp != NULL)
392 // atv2 has seatbelt profile key removed so nothing to do here
393 DecoderAvailable = 1;
397 /* When XBMC is started from a sandbox directory we have to check the sysctl values */
398 if (DarwinIsIosSandboxed())
400 uint64_t proc_enforce = 0;
401 uint64_t vnode_enforce = 0;
402 size_t size = sizeof(vnode_enforce);
404 sysctlbyname("security.mac.proc_enforce", &proc_enforce, &size, NULL, 0);
405 sysctlbyname("security.mac.vnode_enforce", &vnode_enforce, &size, NULL, 0);
407 if (vnode_enforce && proc_enforce)
409 DecoderAvailable = 1;
410 CLog::Log(LOGINFO, "VideoToolBox decoder not available. Use : sysctl -w security.mac.proc_enforce=0; sysctl -w security.mac.vnode_enforce=0\n");
414 DecoderAvailable = 1;
415 CLog::Log(LOGINFO, "VideoToolBox decoder available\n");
420 DecoderAvailable = 1;
425 return (DecoderAvailable == 1);
428 int DarwinBatteryLevel(void)
430 float batteryLevel = 0;
431 #if defined(TARGET_DARWIN_IOS)
432 if(!DarwinIsAppleTV2())
433 batteryLevel = [[UIDevice currentDevice] batteryLevel];
435 CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo();
436 CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo);
438 CFDictionaryRef powerSource = NULL;
439 const void *powerSourceVal;
441 for (int i = 0 ; i < CFArrayGetCount(powerSources) ; i++)
443 powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, i));
444 if (!powerSource) break;
446 powerSourceVal = (CFStringRef)CFDictionaryGetValue(powerSource, CFSTR(kIOPSNameKey));
451 powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSCurrentCapacityKey));
452 CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &curLevel);
454 powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSMaxCapacityKey));
455 CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &maxLevel);
457 batteryLevel = (double)curLevel/(double)maxLevel;
460 return batteryLevel * 100;
463 void DarwinSetScheduling(int message)
466 struct sched_param param;
467 pthread_t this_pthread_self = pthread_self();
469 int32_t result = pthread_getschedparam(this_pthread_self, &policy, ¶m );
471 policy = SCHED_OTHER;
472 thread_extended_policy_data_t theFixedPolicy={true};
474 if (message == GUI_MSG_PLAYBACK_STARTED && g_application.m_pPlayer->IsPlayingVideo())
477 theFixedPolicy.timeshare = false;
480 result = thread_policy_set(pthread_mach_thread_np(this_pthread_self),
481 THREAD_EXTENDED_POLICY,
482 (thread_policy_t)&theFixedPolicy,
483 THREAD_EXTENDED_POLICY_COUNT);
485 result = pthread_setschedparam(this_pthread_self, policy, ¶m );
488 bool DarwinCFStringRefToStringWithEncoding(CFStringRef source, std::string &destination, CFStringEncoding encoding)
490 const char *cstr = CFStringGetCStringPtr(source, encoding);
493 CFIndex strLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(source) + 1,
495 char *allocStr = (char*)malloc(strLen);
500 if(!CFStringGetCString(source, allocStr, strLen, encoding))
502 free((void*)allocStr);
506 destination = allocStr;
507 free((void*)allocStr);
516 bool DarwinCFStringRefToString(CFStringRef source, std::string &destination)
518 return DarwinCFStringRefToStringWithEncoding(source, destination, CFStringGetSystemEncoding());
521 bool DarwinCFStringRefToUTF8String(CFStringRef source, std::string &destination)
523 return DarwinCFStringRefToStringWithEncoding(source, destination, kCFStringEncodingUTF8);