diff options
Diffstat (limited to 'video')
-rw-r--r-- | video/out/cocoa_common.m | 94 | ||||
-rw-r--r-- | video/out/vo.h | 3 |
2 files changed, 97 insertions, 0 deletions
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m index 4e3c461eaa..027fd313e5 100644 --- a/video/out/cocoa_common.m +++ b/video/out/cocoa_common.m @@ -20,6 +20,8 @@ #import <Cocoa/Cocoa.h> #import <CoreServices/CoreServices.h> // for CGDisplayHideCursor #import <IOKit/pwr_mgt/IOPMLib.h> +#import <IOKit/IOKitLib.h> +#include <mach/mach.h> #import "cocoa_common.h" #import "video/out/cocoa/window.h" @@ -73,6 +75,10 @@ struct vo_cocoa_state { bool embedded; // wether we are embedding in another GUI IOPMAssertionID power_mgmt_assertion; + io_connect_t light_sensor; + uint64_t last_lmuvalue; + int last_lux; + IONotificationPortRef light_sensor_io_port; pthread_mutex_t mutex; struct mp_log *log; @@ -146,6 +152,87 @@ static void set_application_icon(NSApplication *app) [pool release]; } +static int lmuvalue_to_lux(uint64_t v) +{ + // the polinomial approximation for apple lmu value -> lux was empirically + // derived by firefox developers (Apple provides no documentation). + // https://bugzilla.mozilla.org/show_bug.cgi?id=793728 + double power_c4 = 1/pow((double)10,27); + double power_c3 = 1/pow((double)10,19); + double power_c2 = 1/pow((double)10,12); + double power_c1 = 1/pow((double)10,5); + + double term4 = -3.0 * power_c4 * pow(v,4); + double term3 = 2.6 * power_c3 * pow(v,3); + double term2 = -3.4 * power_c2 * pow(v,2); + double term1 = 3.9 * power_c1 * v; + + int lux = ceil(term4 + term3 + term2 + term1 - 0.19); + return lux > 0 ? lux : 0; +} + +static void light_sensor_cb(void *ctx, io_service_t srv, natural_t mtype, void *msg) +{ + struct vo *vo = ctx; + struct vo_cocoa_state *s = vo->cocoa; + uint32_t outputs = 2; + uint64_t values[outputs]; + + kern_return_t kr = IOConnectCallMethod( + s->light_sensor, 0, NULL, 0, NULL, 0, values, &outputs, nil, 0); + + if (kr == KERN_SUCCESS) { + uint64_t mean = (values[0] + values[1]) / 2; + if (s->last_lmuvalue != mean) { + s->last_lmuvalue = mean; + s->last_lux = lmuvalue_to_lux(s->last_lmuvalue); + s->pending_events |= VO_EVENT_AMBIENT_LIGHTING_CHANGED; + vo_wakeup(vo); + return; + } + } +} + +static void cocoa_init_light_sensor(struct vo *vo) +{ + with_cocoa_lock_on_main_thread(vo, ^{ + struct vo_cocoa_state *s = vo->cocoa; + io_service_t srv = IOServiceGetMatchingService( + kIOMasterPortDefault, IOServiceMatching("AppleLMUController")); + if (srv == IO_OBJECT_NULL) { + MP_VERBOSE(vo, "can't find an ambient light sensor\n"); + return; + } + + // subscribe to notifications from the light sensor driver + s->light_sensor_io_port = IONotificationPortCreate(kIOMasterPortDefault); + IONotificationPortSetDispatchQueue( + s->light_sensor_io_port, dispatch_get_main_queue()); + + io_object_t n; + IOServiceAddInterestNotification( + s->light_sensor_io_port, srv, kIOGeneralInterest, light_sensor_cb, + vo, &n); + + kern_return_t kr = IOServiceOpen(srv, mach_task_self(), 0, + &s->light_sensor); + IOObjectRelease(srv); + if (kr != KERN_SUCCESS) { + MP_WARN(vo, "can't start ambient light sensor connection\n"); + return; + } + + light_sensor_cb(vo, 0, 0, NULL); + }); +} + +static void cocoa_uninit_light_sensor(struct vo *vo) +{ + struct vo_cocoa_state *s = vo->cocoa; + IONotificationPortDestroy(s->light_sensor_io_port); + IOObjectRelease(s->light_sensor); +} + int vo_cocoa_init(struct vo *vo) { struct vo_cocoa_state *s = talloc_zero(vo, struct vo_cocoa_state); @@ -156,6 +243,7 @@ int vo_cocoa_init(struct vo *vo) .embedded = vo->opts->WinID >= 0, }; mpthread_mutex_init_recursive(&s->mutex); + cocoa_init_light_sensor(vo); vo->cocoa = s; return 1; } @@ -199,6 +287,7 @@ void vo_cocoa_uninit(struct vo *vo) with_cocoa_lock_on_main_thread(vo, ^{ enable_power_management(vo); + cocoa_uninit_light_sensor(vo); cocoa_rm_fs_screen_profile_observer(vo); [s->gl_ctx release]; @@ -676,6 +765,11 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg) *(double *)arg = vo->cocoa->screen_fps; return VO_TRUE; } + case VOCTRL_GET_AMBIENT_LUX: + if (vo->cocoa->light_sensor != IO_OBJECT_NULL) { + *(int *)arg = vo->cocoa->last_lux; + return VO_TRUE; + } } return VO_NOTIMPL; } diff --git a/video/out/vo.h b/video/out/vo.h index a531744c49..f1adbc0908 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -38,6 +38,8 @@ #define VO_EVENT_ICC_PROFILE_CHANGED 4 // Some other window state changed #define VO_EVENT_WIN_STATE 8 +// The ambient light conditions changed and need to be reloaded +#define VO_EVENT_AMBIENT_LIGHTING_CHANGED 16 // Set of events the player core may be interested in. #define VO_EVENTS_USER (VO_EVENT_RESIZE | VO_EVENT_WIN_STATE) @@ -103,6 +105,7 @@ enum mp_voctrl { VOCTRL_SET_COMMAND_LINE, // char** VOCTRL_GET_ICC_PROFILE, // bstr* + VOCTRL_GET_AMBIENT_LUX, // int* VOCTRL_GET_DISPLAY_FPS, // double* VOCTRL_GET_RECENT_FLIP_TIME, // int64_t* (using mp_time_us()) |