Remove LiveTV menu.
[vuplus_xbmc] / xbmc / osx / DarwinUtils.mm
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #define BOOL XBMC_BOOL 
22 #include "system.h"
23 #include "Application.h"
24 #include "DllPaths.h"
25 #include "GUIUserMessages.h"
26 #include "utils/log.h"
27
28 #undef BOOL
29
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>
36 #else
37   #import <Cocoa/Cocoa.h>
38   #import <CoreFoundation/CoreFoundation.h>
39   #import <IOKit/ps/IOPowerSources.h>
40   #import <IOKit/ps/IOPSKeys.h>
41 #endif
42
43 #import "AutoPool.h"
44 #import "DarwinUtils.h"
45
46 #ifndef NSAppKitVersionNumber10_5
47 #define NSAppKitVersionNumber10_5 949
48 #endif
49
50 #ifndef NSAppKitVersionNumber10_6
51 #define NSAppKitVersionNumber10_6 1038
52 #endif
53
54 enum iosPlatform
55 {
56   iDeviceUnknown = -1,
57   iPhone2G,
58   iPhone3G,
59   iPhone3GS,
60   iPodTouch1G,
61   iPodTouch2G,
62   iPodTouch3G,
63   iPad,
64   iPad3G,
65   iPad2WIFI,
66   iPad2CDMA,
67   iPad2,
68   iPadMini,
69   iPadMiniGSMCDMA,
70   iPadMiniWIFI,
71   AppleTV2,
72   iPhone4,            //from here on list devices with retina support (e.x. mainscreen scale == 2.0)
73   iPhone4CDMA,
74   iPhone4S,
75   iPhone5,
76   iPhone5GSMCDMA, 
77   iPhone5CGSM,
78   iPhone5CGlobal,
79   iPhone5SGSM,
80   iPhone5SGlobal,
81   iPodTouch4G,
82   iPodTouch5G,  
83   iPad3WIFI,
84   iPad3GSMCDMA,
85   iPad3,
86   iPad4WIFI,
87   iPad4,
88   iPad4GSMCDMA,
89   iPadAirWifi,
90   iPadAirCellular,
91   iPadMini2Wifi,
92   iPadMini2Cellular,
93 };
94
95 // platform strings are based on http://theiphonewiki.com/wiki/Models
96 enum iosPlatform getIosPlatform()
97 {
98 #if defined(TARGET_DARWIN_IOS)
99   // Gets a string with the device model
100   size_t size;  
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];  
105   delete [] machine; 
106   
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;
120   
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;
126   
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;
146   
147   if ([platform isEqualToString:@"AppleTV2,1"])   return AppleTV2;
148 #endif
149   return iDeviceUnknown;
150 }
151
152 bool DarwinIsAppleTV2(void)
153 {
154   static enum iosPlatform platform = iDeviceUnknown;
155 #if defined(TARGET_DARWIN_IOS)
156   if( platform == iDeviceUnknown )
157   {
158     platform = getIosPlatform();
159   }
160 #endif
161   return (platform == AppleTV2);
162 }
163
164 bool DarwinIsMavericks(void)
165 {
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)
173   {
174     CLog::Log(LOGDEBUG, "Detected Mavericks...");
175     isMavericks = [NSProcessInfo instancesRespondToSelector:@selector(beginActivityWithOptions:reason:)] == TRUE ? 1 : 0;
176   }
177 #endif
178   return isMavericks == 1;
179 }
180
181 bool DarwinIsSnowLeopard(void)
182 {
183   static int isSnowLeopard = -1;
184 #if defined(TARGET_DARWIN_OSX)
185   if (isSnowLeopard == -1)
186   {
187     double appKitVersion = floor(NSAppKitVersionNumber);
188     isSnowLeopard = (appKitVersion <= NSAppKitVersionNumber10_6 && appKitVersion > NSAppKitVersionNumber10_5) ? 1 : 0;
189   }
190 #endif
191   return isSnowLeopard == 1;
192 }
193
194 bool DarwinHasRetina(void)
195 {
196   static enum iosPlatform platform = iDeviceUnknown;
197
198 #if defined(TARGET_DARWIN_IOS)
199   if( platform == iDeviceUnknown )
200   {
201     platform = getIosPlatform();
202   }
203 #endif
204   return (platform >= iPhone4);
205 }
206
207 const char *GetDarwinOSReleaseString(void)
208 {
209   static std::string osreleaseStr;
210   if (osreleaseStr.empty())
211   {
212     size_t size;
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;
217     delete [] osrelease;
218   }
219   return osreleaseStr.c_str();
220 }
221
222 const char *GetDarwinVersionString(void)
223 {
224   CCocoaAutoPool pool;
225   return [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String];
226 }
227
228 float GetIOSVersion(void)
229 {
230   CCocoaAutoPool pool;
231   float version;
232 #if defined(TARGET_DARWIN_IOS)
233   version = [[[UIDevice currentDevice] systemVersion] floatValue];
234 #else
235   version = 0.0f;
236 #endif
237
238   return(version);
239 }
240
241 int  GetDarwinFrameworkPath(bool forPython, char* path, uint32_t *pathsize)
242 {
243   CCocoaAutoPool pool;
244   // see if we can figure out who we are
245   NSString *pathname;
246
247   path[0] = 0;
248   *pathsize = 0;
249
250   // a) XBMC frappliance running under ATV2
251   Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
252   if (XBMCfrapp != NULL)
253   {
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);
258     return 0;
259   }
260
261   // b) XBMC application running under IOS
262   pathname = [[NSBundle mainBundle] executablePath];
263   if (pathname && strstr([pathname UTF8String], "XBMC.app/XBMC"))
264   {
265     strcpy(path, [pathname UTF8String]);
266     // Move backwards to last "/"
267     for (int n=strlen(path)-1; path[n] != '/'; n--)
268       path[n] = '\0';
269     strcat(path, "Frameworks");
270     *pathsize = strlen(path);
271     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(c) -> %s", path);
272     return 0;
273   }
274
275   // d) XBMC application running under OSX
276   pathname = [[NSBundle mainBundle] executablePath];
277   if (pathname && strstr([pathname UTF8String], "Contents"))
278   {
279     strcpy(path, [pathname UTF8String]);
280     // ExectuablePath is <product>.app/Contents/MacOS/<executable>
281     char *lastSlash = strrchr(path, '/');
282     if (lastSlash)
283     {
284       *lastSlash = '\0';//remove /<executable>  
285       lastSlash = strrchr(path, '/');
286       if (lastSlash)
287         *lastSlash = '\0';//remove /MacOS
288     }
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);
293     return 0;
294   }
295
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.
299   if (!forPython)
300   {
301     strcpy(path, PREFIX_USR_PATH);
302     strcat(path, "/lib");
303     *pathsize = strlen(path);
304     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(e) -> %s", path);
305     return 0;
306   }
307
308   return -1;
309 }
310
311 int  GetDarwinExecutablePath(char* path, uint32_t *pathsize)
312 {
313   CCocoaAutoPool pool;
314   // see if we can figure out who we are
315   NSString *pathname;
316
317   // a) XBMC frappliance running under ATV2
318   Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
319   if (XBMCfrapp != NULL)
320   {
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);
325     return 0;
326   }
327
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);
334
335   return 0;
336 }
337
338 const char* DarwinGetXbmcRootFolder(void)
339 {
340   static std::string rootFolder = "";
341   if ( rootFolder.length() == 0)
342   {
343     if (DarwinIsIosSandboxed())
344     {
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";
349     }
350     else
351     {
352       rootFolder = "Library/Preferences";
353     }
354   }
355   return rootFolder.c_str();
356 }
357
358 bool DarwinIsIosSandboxed(void)
359 {
360   static int ret = -1;
361   if (ret == -1)
362   {
363     uint32_t path_size = 2*MAXPATHLEN;
364     char     given_path[2*MAXPATHLEN];
365     int      result = -1; 
366     ret = 0;
367     memset(given_path, 0x0, path_size);
368     /* Get Application directory */  
369     result = GetDarwinExecutablePath(given_path, &path_size);
370     if (result == 0)
371     {
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)
375       {
376         ret = 1;
377       }
378     }
379   }
380   return ret == 1;
381 }
382
383 bool DarwinHasVideoToolboxDecoder(void)
384 {
385   static int DecoderAvailable = -1;
386
387   if (DecoderAvailable == -1)
388   {
389     Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
390     if (XBMCfrapp != NULL)
391     {
392       // atv2 has seatbelt profile key removed so nothing to do here
393       DecoderAvailable = 1;
394     }
395     else
396     {
397       /* When XBMC is started from a sandbox directory we have to check the sysctl values */      
398       if (DarwinIsIosSandboxed())
399       {
400         uint64_t proc_enforce = 0;
401         uint64_t vnode_enforce = 0; 
402         size_t size = sizeof(vnode_enforce);
403
404         sysctlbyname("security.mac.proc_enforce",  &proc_enforce,  &size, NULL, 0);  
405         sysctlbyname("security.mac.vnode_enforce", &vnode_enforce, &size, NULL, 0);
406
407         if (vnode_enforce && proc_enforce)
408         {
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");
411         }
412         else
413         {
414           DecoderAvailable = 1;
415           CLog::Log(LOGINFO, "VideoToolBox decoder available\n");
416         }  
417       }
418       else
419       {
420         DecoderAvailable = 1;
421       }
422     }
423   }
424
425   return (DecoderAvailable == 1);
426 }
427
428 int DarwinBatteryLevel(void)
429 {
430   float batteryLevel = 0;
431 #if defined(TARGET_DARWIN_IOS)
432   if(!DarwinIsAppleTV2())
433     batteryLevel = [[UIDevice currentDevice] batteryLevel];
434 #else
435   CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo();
436   CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo);
437
438   CFDictionaryRef powerSource = NULL;
439   const void *powerSourceVal;
440
441   for (int i = 0 ; i < CFArrayGetCount(powerSources) ; i++)
442   {
443     powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, i));
444     if (!powerSource) break;
445
446     powerSourceVal = (CFStringRef)CFDictionaryGetValue(powerSource, CFSTR(kIOPSNameKey));
447
448     int curLevel = 0;
449     int maxLevel = 0;
450
451     powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSCurrentCapacityKey));
452     CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &curLevel);
453
454     powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSMaxCapacityKey));
455     CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &maxLevel);
456
457     batteryLevel = (double)curLevel/(double)maxLevel;
458   }
459 #endif
460   return batteryLevel * 100;  
461 }
462
463 void DarwinSetScheduling(int message)
464 {
465   int policy;
466   struct sched_param param;
467   pthread_t this_pthread_self = pthread_self();
468
469   int32_t result = pthread_getschedparam(this_pthread_self, &policy, &param );
470
471   policy = SCHED_OTHER;
472   thread_extended_policy_data_t theFixedPolicy={true};
473
474   if (message == GUI_MSG_PLAYBACK_STARTED && g_application.m_pPlayer->IsPlayingVideo())
475   {
476     policy = SCHED_RR;
477     theFixedPolicy.timeshare = false;
478   }
479
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);
484
485   result = pthread_setschedparam(this_pthread_self, policy, &param );
486 }
487
488 bool DarwinCFStringRefToStringWithEncoding(CFStringRef source, std::string &destination, CFStringEncoding encoding)
489 {
490   const char *cstr = CFStringGetCStringPtr(source, encoding);
491   if (!cstr)
492   {
493     CFIndex strLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(source) + 1,
494                                                        encoding);
495     char *allocStr = (char*)malloc(strLen);
496
497     if(!allocStr)
498       return false;
499
500     if(!CFStringGetCString(source, allocStr, strLen, encoding))
501     {
502       free((void*)allocStr);
503       return false;
504     }
505
506     destination = allocStr;
507     free((void*)allocStr);
508
509     return true;
510   }
511
512   destination = cstr;
513   return true;
514 }
515
516 bool DarwinCFStringRefToString(CFStringRef source, std::string &destination)
517 {
518   return DarwinCFStringRefToStringWithEncoding(source, destination, CFStringGetSystemEncoding());
519 }
520
521 bool DarwinCFStringRefToUTF8String(CFStringRef source, std::string &destination)
522 {
523   return DarwinCFStringRefToStringWithEncoding(source, destination, kCFStringEncodingUTF8);
524 }
525
526 #endif