summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/cocoa_common.m94
-rw-r--r--video/out/vo.h3
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())