diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fd9a9d6..9d889088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -636,8 +636,10 @@ if(WIN32) endforeach() target_compile_definitions(lovr PRIVATE LOVR_GL) elseif(APPLE) - target_link_libraries(lovr objc) + find_library(AVFOUNDATION AVFoundation) + target_link_libraries(lovr objc ${AVFOUNDATION}) target_sources(lovr PRIVATE src/core/os_macos.c) + set_source_files_properties(src/core/os_macos.c PROPERTIES COMPILE_FLAGS -xobjective-c) target_compile_definitions(lovr PRIVATE LOVR_GL) set_target_properties(lovr PROPERTIES MACOSX_RPATH TRUE diff --git a/Tuprules.tup b/Tuprules.tup index 917be5d2..442ca9a1 100644 --- a/Tuprules.tup +++ b/Tuprules.tup @@ -17,6 +17,7 @@ CFLAGS += -Wall -Wextra CFLAGS += -Wno-unused-parameter CFLAGS_glad.c += -Wno-pedantic CFLAGS_os_android.c += -Wno-format-pedantic +CFLAGS_os_macos.c += -xobjective-c CFLAGS_headset_openvr.c += -Wno-unused-variable -Wno-typedef-redefinition -Wno-pedantic CFLAGS_headset_vrapi.c += -Wno-c11-extensions -Wno-gnu-empty-initializer -Wno-pedantic CFLAGS_miniaudio.c += -Wno-unused-function diff --git a/src/core/os_macos.c b/src/core/os_macos.c index 37c6aa1a..af4c677b 100644 --- a/src/core/os_macos.c +++ b/src/core/os_macos.c @@ -9,20 +9,25 @@ #include #include #include +#import #include "os_glfw.h" -static uint64_t frequency; +static struct { + uint64_t frequency; + fn_permission* onPermissionEvent; +} state; bool os_init() { mach_timebase_info_data_t info; mach_timebase_info(&info); - frequency = (info.denom * 1e9) / info.numer; + state.frequency = (info.denom * 1e9) / info.numer; return true; } void os_destroy() { glfwTerminate(); + memset(&state, 0, sizeof(state)); } const char* os_get_name() { @@ -41,7 +46,7 @@ void os_open_console() { } double os_get_time() { - return mach_absolute_time() / (double) frequency; + return mach_absolute_time() / (double) state.frequency; } void os_sleep(double seconds) { @@ -53,11 +58,39 @@ void os_sleep(double seconds) { } void os_request_permission(os_permission permission) { - // + if (permission == OS_PERMISSION_AUDIO_CAPTURE) { + // If on old OS without permissions check, permission is implicitly granted + if (![AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)]) { + if (state.onPermissionEvent) state.onPermissionEvent(permission, true); + return; + } + + switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]) { + case AVAuthorizationStatusAuthorized: + if (state.onPermissionEvent) state.onPermissionEvent(permission, true); + break; + case AVAuthorizationStatusNotDetermined: + [AVCaptureDevice + requestAccessForMediaType:AVMediaTypeAudio + completionHandler:^(BOOL granted) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (state.onPermissionEvent) state.onPermissionEvent(permission, granted); + }); + } + ]; + break; + case AVAuthorizationStatusDenied: + if (state.onPermissionEvent) state.onPermissionEvent(permission, false); + break; + case AVAuthorizationStatusRestricted: + if (state.onPermissionEvent) state.onPermissionEvent(permission, false); + break; + } + } } void os_on_permission(fn_permission* callback) { - // + state.onPermissionEvent = callback; } size_t os_get_home_directory(char* buffer, size_t size) {