| |
| |
| |
|
|
| #include <future> |
| #include <objc/message.h> |
| #include "common/apple_authorization.h" |
| #include "common/logging/log.h" |
|
|
| namespace AppleAuthorization { |
|
|
| |
|
|
| using NSString = void; |
| using AVMediaType = NSString*; |
| enum AVAuthorizationStatus : int { |
| AVAuthorizationStatusNotDetermined = 0, |
| AVAuthorizationStatusRestricted, |
| AVAuthorizationStatusDenied, |
| AVAuthorizationStatusAuthorized, |
| }; |
|
|
| typedef NSString* (*send_stringWithUTF8String)(Class, SEL, const char*); |
| typedef AVAuthorizationStatus (*send_authorizationStatusForMediaType)(Class, SEL, AVMediaType); |
| typedef void (*send_requestAccessForMediaType_completionHandler)(Class, SEL, AVMediaType, |
| void (^callback)(bool)); |
|
|
| NSString* StringToNSString(const std::string_view string) { |
| return reinterpret_cast<send_stringWithUTF8String>(objc_msgSend)( |
| objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), string.data()); |
| } |
|
|
| AVAuthorizationStatus GetAuthorizationStatus(AVMediaType media_type) { |
| return reinterpret_cast<send_authorizationStatusForMediaType>(objc_msgSend)( |
| objc_getClass("AVCaptureDevice"), sel_registerName("authorizationStatusForMediaType:"), |
| media_type); |
| } |
|
|
| void RequestAccess(AVMediaType media_type, void (^callback)(bool)) { |
| reinterpret_cast<send_requestAccessForMediaType_completionHandler>(objc_msgSend)( |
| objc_getClass("AVCaptureDevice"), |
| sel_registerName("requestAccessForMediaType:completionHandler:"), media_type, callback); |
| } |
|
|
| static AVMediaType AVMediaTypeAudio = StringToNSString("soun"); |
| static AVMediaType AVMediaTypeVideo = StringToNSString("vide"); |
|
|
| |
|
|
| bool CheckAuthorization(AVMediaType type, const std::string_view& type_name) { |
| switch (GetAuthorizationStatus(type)) { |
| case AVAuthorizationStatusNotDetermined: { |
| LOG_INFO(Frontend, "Requesting {} permission.", type_name); |
| __block std::promise<bool> authorization_promise; |
| std::future<bool> authorization_future = authorization_promise.get_future(); |
| RequestAccess(type, ^(bool granted) { |
| LOG_INFO(Frontend, "{} permission request result: {}", type_name, granted); |
| authorization_promise.set_value(granted); |
| }); |
| return authorization_future.get(); |
| } |
| case AVAuthorizationStatusAuthorized: |
| return true; |
| case AVAuthorizationStatusDenied: |
| LOG_WARNING(Frontend, |
| "{} permission has been denied and must be enabled via System Settings.", |
| type_name); |
| return false; |
| case AVAuthorizationStatusRestricted: |
| LOG_WARNING(Frontend, "{} permission is restricted by the system.", type_name); |
| return false; |
| } |
| } |
|
|
| bool CheckAuthorizationForCamera() { |
| return CheckAuthorization(AVMediaTypeVideo, "Camera"); |
| } |
|
|
| bool CheckAuthorizationForMicrophone() { |
| return CheckAuthorization(AVMediaTypeAudio, "Microphone"); |
| } |
|
|
| } |
|
|