darwin, fixed, compiler warning. DarwinUtils.h is C linkage so you should not be...
[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 enum iosPlatform
47 {
48   iDeviceUnknown = -1,
49   iPhone2G,
50   iPhone3G,
51   iPhone3GS,
52   iPodTouch1G,
53   iPodTouch2G,
54   iPodTouch3G,
55   iPad,
56   iPad3G,
57   iPad2WIFI,
58   iPad2CDMA,
59   iPad2,
60   iPadMini,
61   iPadMiniGSMCDMA,
62   iPadMiniWIFI,
63   AppleTV2,
64   iPhone4,            //from here on list devices with retina support (e.x. mainscreen scale == 2.0)
65   iPhone4CDMA,
66   iPhone4S,
67   iPhone5,
68   iPhone5GSMCDMA, 
69   iPhone5CGSM,
70   iPhone5CGlobal,
71   iPhone5SGSM,
72   iPhone5SGlobal,
73   iPodTouch4G,
74   iPodTouch5G,  
75   iPad3WIFI,
76   iPad3GSMCDMA,
77   iPad3,
78   iPad4WIFI,
79   iPad4,
80   iPad4GSMCDMA,  
81 };
82
83 // platform strings are based on http://theiphonewiki.com/wiki/Models
84 enum iosPlatform getIosPlatform()
85 {
86 #if defined(TARGET_DARWIN_IOS)
87   // Gets a string with the device model
88   size_t size;  
89   sysctlbyname("hw.machine", NULL, &size, NULL, 0);  
90   char *machine = new char[size];  
91   sysctlbyname("hw.machine", machine, &size, NULL, 0);  
92   NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];  
93   delete [] machine; 
94   
95   if ([platform isEqualToString:@"iPhone1,1"])    return iPhone2G;
96   if ([platform isEqualToString:@"iPhone1,2"])    return iPhone3G;
97   if ([platform isEqualToString:@"iPhone2,1"])    return iPhone3GS;
98   if ([platform isEqualToString:@"iPhone3,1"])    return iPhone4;
99   if ([platform isEqualToString:@"iPhone3,2"])    return iPhone4;
100   if ([platform isEqualToString:@"iPhone3,3"])    return iPhone4CDMA;    
101   if ([platform isEqualToString:@"iPhone4,1"])    return iPhone4S;
102   if ([platform isEqualToString:@"iPhone5,1"])    return iPhone5;
103   if ([platform isEqualToString:@"iPhone5,2"])    return iPhone5GSMCDMA;
104   if ([platform isEqualToString:@"iPhone5,3"])    return iPhone5CGSM;
105   if ([platform isEqualToString:@"iPhone5,4"])    return iPhone5CGlobal;
106   if ([platform isEqualToString:@"iPhone6,1"])    return iPhone5SGSM;
107   if ([platform isEqualToString:@"iPhone6,2"])    return iPhone5SGlobal;
108   
109   if ([platform isEqualToString:@"iPod1,1"])      return iPodTouch1G;
110   if ([platform isEqualToString:@"iPod2,1"])      return iPodTouch2G;
111   if ([platform isEqualToString:@"iPod3,1"])      return iPodTouch3G;
112   if ([platform isEqualToString:@"iPod4,1"])      return iPodTouch4G;
113   if ([platform isEqualToString:@"iPod5,1"])      return iPodTouch5G;
114   
115   if ([platform isEqualToString:@"iPad1,1"])      return iPad;
116   if ([platform isEqualToString:@"iPad1,2"])      return iPad;
117   if ([platform isEqualToString:@"iPad2,1"])      return iPad2WIFI;
118   if ([platform isEqualToString:@"iPad2,2"])      return iPad2;
119   if ([platform isEqualToString:@"iPad2,3"])      return iPad2CDMA;
120   if ([platform isEqualToString:@"iPad2,4"])      return iPad2;
121   if ([platform isEqualToString:@"iPad2,5"])      return iPadMiniWIFI;
122   if ([platform isEqualToString:@"iPad2,6"])      return iPadMini;
123   if ([platform isEqualToString:@"iPad2,7"])      return iPadMiniGSMCDMA;
124   if ([platform isEqualToString:@"iPad3,1"])      return iPad3WIFI;
125   if ([platform isEqualToString:@"iPad3,2"])      return iPad3GSMCDMA;
126   if ([platform isEqualToString:@"iPad3,3"])      return iPad3;
127   if ([platform isEqualToString:@"iPad3,4"])      return iPad4WIFI;
128   if ([platform isEqualToString:@"iPad3,5"])      return iPad4;
129   if ([platform isEqualToString:@"iPad3,6"])      return iPad4GSMCDMA;
130   if ([platform isEqualToString:@"AppleTV2,1"])   return AppleTV2;
131 #endif
132   return iDeviceUnknown;
133 }
134
135 bool DarwinIsAppleTV2(void)
136 {
137   static enum iosPlatform platform = iDeviceUnknown;
138 #if defined(TARGET_DARWIN_IOS)
139   if( platform == iDeviceUnknown )
140   {
141     platform = getIosPlatform();
142   }
143 #endif
144   return (platform == AppleTV2);
145 }
146
147 bool DarwinHasRetina(void)
148 {
149   static enum iosPlatform platform = iDeviceUnknown;
150
151 #if defined(TARGET_DARWIN_IOS)
152   if( platform == iDeviceUnknown )
153   {
154     platform = getIosPlatform();
155   }
156 #endif
157   return (platform >= iPhone4);
158 }
159
160 const char *GetDarwinOSReleaseString(void)
161 {
162   static std::string osreleaseStr;
163   if (osreleaseStr.empty())
164   {
165     size_t size;
166     sysctlbyname("kern.osrelease", NULL, &size, NULL, 0);
167     char *osrelease = new char[size];
168     sysctlbyname("kern.osrelease", osrelease, &size, NULL, 0);
169     osreleaseStr = osrelease;
170     delete [] osrelease;
171   }
172   return osreleaseStr.c_str();
173 }
174
175 const char *GetDarwinVersionString(void)
176 {
177   return [[[NSProcessInfo processInfo] operatingSystemVersionString] UTF8String];
178 }
179
180 float GetIOSVersion(void)
181 {
182   CCocoaAutoPool pool;
183   float version;
184 #if defined(TARGET_DARWIN_IOS)
185   version = [[[UIDevice currentDevice] systemVersion] floatValue];
186 #else
187   version = 0.0f;
188 #endif
189
190   return(version);
191 }
192
193 int  GetDarwinFrameworkPath(bool forPython, char* path, uint32_t *pathsize)
194 {
195   CCocoaAutoPool pool;
196   // see if we can figure out who we are
197   NSString *pathname;
198
199   path[0] = 0;
200   *pathsize = 0;
201
202   // a) XBMC frappliance running under ATV2
203   Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
204   if (XBMCfrapp != NULL)
205   {
206     pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"Frameworks" ofType:@""];
207     strcpy(path, [pathname UTF8String]);
208     *pathsize = strlen(path);
209     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(a) -> %s", path);
210     return 0;
211   }
212
213   // b) XBMC application running under IOS
214   pathname = [[NSBundle mainBundle] executablePath];
215   if (pathname && strstr([pathname UTF8String], "XBMC.app/XBMC"))
216   {
217     strcpy(path, [pathname UTF8String]);
218     // Move backwards to last "/"
219     for (int n=strlen(path)-1; path[n] != '/'; n--)
220       path[n] = '\0';
221     strcat(path, "Frameworks");
222     *pathsize = strlen(path);
223     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(c) -> %s", path);
224     return 0;
225   }
226
227   // d) XBMC application running under OSX
228   pathname = [[NSBundle mainBundle] privateFrameworksPath];
229   if (pathname && strstr([pathname UTF8String], "Contents"))
230   {
231     // check for 'Contents' if we are running as real xbmc.app
232     strcpy(path, [pathname UTF8String]);
233     *pathsize = strlen(path);
234     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(d) -> %s", path);
235     return 0;
236   }
237
238   // e) XBMC OSX binary running under xcode or command-line
239   // but only if it's not for python. In this case, let python
240   // use it's internal compiled paths.
241   if (!forPython)
242   {
243     strcpy(path, PREFIX_USR_PATH);
244     strcat(path, "/lib");
245     *pathsize = strlen(path);
246     //CLog::Log(LOGDEBUG, "DarwinFrameworkPath(e) -> %s", path);
247     return 0;
248   }
249
250   return -1;
251 }
252
253 int  GetDarwinExecutablePath(char* path, uint32_t *pathsize)
254 {
255   CCocoaAutoPool pool;
256   // see if we can figure out who we are
257   NSString *pathname;
258
259   // a) XBMC frappliance running under ATV2
260   Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
261   if (XBMCfrapp != NULL)
262   {
263     pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"XBMC" ofType:@""];
264     strcpy(path, [pathname UTF8String]);
265     *pathsize = strlen(path);
266     //CLog::Log(LOGDEBUG, "DarwinExecutablePath(a) -> %s", path);
267     return 0;
268   }
269
270   // b) XBMC application running under IOS
271   // c) XBMC application running under OSX
272   pathname = [[NSBundle mainBundle] executablePath];
273   strcpy(path, [pathname UTF8String]);
274   *pathsize = strlen(path);
275   //CLog::Log(LOGDEBUG, "DarwinExecutablePath(b/c) -> %s", path);
276
277   return 0;
278 }
279
280 const char* DarwinGetXbmcRootFolder(void)
281 {
282   static std::string rootFolder = "";
283   if ( rootFolder.length() == 0)
284   {
285     if (DarwinIsIosSandboxed())
286     {
287       // when we are sandbox make documents our root
288       // so that user can access everything he needs 
289       // via itunes sharing
290       rootFolder = "Documents";
291     }
292     else
293     {
294       rootFolder = "Library/Preferences";
295     }
296   }
297   return rootFolder.c_str();
298 }
299
300 bool DarwinIsIosSandboxed(void)
301 {
302   static int ret = -1;
303   if (ret == -1)
304   {
305     uint32_t path_size = 2*MAXPATHLEN;
306     char     given_path[2*MAXPATHLEN];
307     int      result = -1; 
308     ret = 0;
309     memset(given_path, 0x0, path_size);
310     /* Get Application directory */  
311     result = GetDarwinExecutablePath(given_path, &path_size);
312     if (result == 0)
313     {
314       // we re sandboxed if we are installed in /var/mobile/Applications
315       if (strlen("/var/mobile/Applications/") < path_size &&
316         strncmp(given_path, "/var/mobile/Applications/", strlen("/var/mobile/Applications/")) == 0)
317       {
318         ret = 1;
319       }
320     }
321   }
322   return ret == 1;
323 }
324
325 bool DarwinHasVideoToolboxDecoder(void)
326 {
327   static int DecoderAvailable = -1;
328
329   if (DecoderAvailable == -1)
330   {
331     Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
332     if (XBMCfrapp != NULL)
333     {
334       // atv2 has seatbelt profile key removed so nothing to do here
335       DecoderAvailable = 1;
336     }
337     else
338     {
339       /* When XBMC is started from a sandbox directory we have to check the sysctl values */      
340       if (DarwinIsIosSandboxed())
341       {
342         uint64_t proc_enforce = 0;
343         uint64_t vnode_enforce = 0; 
344         size_t size = sizeof(vnode_enforce);
345
346         sysctlbyname("security.mac.proc_enforce",  &proc_enforce,  &size, NULL, 0);  
347         sysctlbyname("security.mac.vnode_enforce", &vnode_enforce, &size, NULL, 0);
348
349         if (vnode_enforce && proc_enforce)
350         {
351           DecoderAvailable = 1;
352           CLog::Log(LOGINFO, "VideoToolBox decoder not available. Use : sysctl -w security.mac.proc_enforce=0; sysctl -w security.mac.vnode_enforce=0\n");
353         }
354         else
355         {
356           DecoderAvailable = 1;
357           CLog::Log(LOGINFO, "VideoToolBox decoder available\n");
358         }  
359       }
360       else
361       {
362         DecoderAvailable = 1;
363       }
364     }
365   }
366
367   return (DecoderAvailable == 1);
368 }
369
370 int DarwinBatteryLevel(void)
371 {
372   float batteryLevel = 0;
373 #if defined(TARGET_DARWIN_IOS)
374   if(!DarwinIsAppleTV2())
375     batteryLevel = [[UIDevice currentDevice] batteryLevel];
376 #else
377   CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo();
378   CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo);
379
380   CFDictionaryRef powerSource = NULL;
381   const void *powerSourceVal;
382
383   for (int i = 0 ; i < CFArrayGetCount(powerSources) ; i++)
384   {
385     powerSource = IOPSGetPowerSourceDescription(powerSourceInfo, CFArrayGetValueAtIndex(powerSources, i));
386     if (!powerSource) break;
387
388     powerSourceVal = (CFStringRef)CFDictionaryGetValue(powerSource, CFSTR(kIOPSNameKey));
389
390     int curLevel = 0;
391     int maxLevel = 0;
392
393     powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSCurrentCapacityKey));
394     CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &curLevel);
395
396     powerSourceVal = CFDictionaryGetValue(powerSource, CFSTR(kIOPSMaxCapacityKey));
397     CFNumberGetValue((CFNumberRef)powerSourceVal, kCFNumberSInt32Type, &maxLevel);
398
399     batteryLevel = (double)curLevel/(double)maxLevel;
400   }
401 #endif
402   return batteryLevel * 100;  
403 }
404
405 void DarwinSetScheduling(int message)
406 {
407   int policy;
408   struct sched_param param;
409   pthread_t this_pthread_self = pthread_self();
410
411   int32_t result = pthread_getschedparam(this_pthread_self, &policy, &param );
412
413   policy = SCHED_OTHER;
414   thread_extended_policy_data_t theFixedPolicy={true};
415
416   if (message == GUI_MSG_PLAYBACK_STARTED && g_application.m_pPlayer->IsPlayingVideo())
417   {
418     policy = SCHED_RR;
419     theFixedPolicy.timeshare = false;
420   }
421
422   result = thread_policy_set(pthread_mach_thread_np(this_pthread_self),
423     THREAD_EXTENDED_POLICY, 
424     (thread_policy_t)&theFixedPolicy,
425     THREAD_EXTENDED_POLICY_COUNT);
426
427   result = pthread_setschedparam(this_pthread_self, policy, &param );
428 }
429
430 bool DarwinCFStringRefToStringWithEncoding(CFStringRef source, std::string &destination, CFStringEncoding encoding)
431 {
432   const char *cstr = CFStringGetCStringPtr(source, encoding);
433   if (!cstr)
434   {
435     CFIndex strLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(source) + 1,
436                                                        encoding);
437     char *allocStr = (char*)malloc(strLen);
438
439     if(!allocStr)
440       return false;
441
442     if(!CFStringGetCString(source, allocStr, strLen, encoding))
443     {
444       free((void*)allocStr);
445       return false;
446     }
447
448     destination = allocStr;
449     free((void*)allocStr);
450
451     return true;
452   }
453
454   destination = cstr;
455   return true;
456 }
457
458 bool DarwinCFStringRefToString(CFStringRef source, std::string &destination)
459 {
460   return DarwinCFStringRefToStringWithEncoding(source, destination, CFStringGetSystemEncoding());
461 }
462
463 bool DarwinCFStringRefToUTF8String(CFStringRef source, std::string &destination)
464 {
465   return DarwinCFStringRefToStringWithEncoding(source, destination, kCFStringEncodingUTF8);
466 }
467
468 #endif