Apple: request authorization for camera usage
This commit is contained in:
		@@ -244,7 +244,8 @@ endif()
 | 
			
		||||
if (APPLE)
 | 
			
		||||
    # Umbrella framework for everything GUI-related
 | 
			
		||||
    find_library(COCOA_LIBRARY Cocoa)
 | 
			
		||||
    set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
 | 
			
		||||
    find_library(AVFOUNDATION_LIBRARY AVFoundation)
 | 
			
		||||
    set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${AVFOUNDATION_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
 | 
			
		||||
elseif (WIN32)
 | 
			
		||||
    # WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
 | 
			
		||||
    add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
 | 
			
		||||
 
 | 
			
		||||
@@ -236,6 +236,10 @@ if (APPLE)
 | 
			
		||||
    target_sources(citra-qt PRIVATE ${MACOSX_ICON})
 | 
			
		||||
    set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE TRUE)
 | 
			
		||||
    set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
 | 
			
		||||
    target_sources(citra-qt PRIVATE
 | 
			
		||||
        usage_authorization.h
 | 
			
		||||
        usage_authorization.mm
 | 
			
		||||
    )
 | 
			
		||||
elseif(WIN32)
 | 
			
		||||
    # compile as a win32 gui application instead of a console application
 | 
			
		||||
    target_link_libraries(citra-qt PRIVATE Qt5::WinMain)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
#include <QThread>
 | 
			
		||||
#include "citra_qt/camera/qt_multimedia_camera.h"
 | 
			
		||||
#include "citra_qt/main.h"
 | 
			
		||||
#include "citra_qt/usage_authorization.h"
 | 
			
		||||
 | 
			
		||||
namespace Camera {
 | 
			
		||||
 | 
			
		||||
@@ -187,6 +188,13 @@ void QtMultimediaCameraHandler::StopCamera() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtMultimediaCameraHandler::StartCamera() {
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
    bool authorized = AppleAuthorization::CheckAuthorizationForCamera();
 | 
			
		||||
    if (!authorized) {
 | 
			
		||||
        LOG_ERROR(Service_CAM, "Unable to start camera due to lack of authorization");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    camera->setViewfinderSettings(settings);
 | 
			
		||||
    camera->start();
 | 
			
		||||
    started = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,10 @@
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "ui_configure_camera.h"
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
#include "citra_qt/usage_authorization.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const std::array<std::string, 3> ConfigureCamera::Implementations = {
 | 
			
		||||
    "blank", /* Blank */
 | 
			
		||||
    "image", /* Image */
 | 
			
		||||
@@ -46,9 +50,15 @@ ConfigureCamera::~ConfigureCamera() {
 | 
			
		||||
 | 
			
		||||
void ConfigureCamera::ConnectEvents() {
 | 
			
		||||
    connect(ui->image_source,
 | 
			
		||||
            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
 | 
			
		||||
            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
 | 
			
		||||
            [this](int index) {
 | 
			
		||||
                StopPreviewing();
 | 
			
		||||
                UpdateImageSourceUI();
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
                if (index == 2) {
 | 
			
		||||
                    AppleAuthorization::CheckAuthorizationForCamera();
 | 
			
		||||
                }
 | 
			
		||||
#endif
 | 
			
		||||
            });
 | 
			
		||||
    connect(ui->camera_selection,
 | 
			
		||||
            static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this] {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								src/citra_qt/usage_authorization.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/citra_qt/usage_authorization.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
// Copyright 2020 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace AppleAuthorization {
 | 
			
		||||
 | 
			
		||||
bool CheckAuthorizationForCamera();
 | 
			
		||||
bool CheckAuthorizationForAudio();
 | 
			
		||||
 | 
			
		||||
} // namespace AppleAuthorization
 | 
			
		||||
							
								
								
									
										79
									
								
								src/citra_qt/usage_authorization.mm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/citra_qt/usage_authorization.mm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
// Copyright 2020 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#import <AVFoundation/AVFoundation.h>
 | 
			
		||||
 | 
			
		||||
#include "citra_qt/usage_authorization.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
 | 
			
		||||
namespace AppleAuthorization {
 | 
			
		||||
 | 
			
		||||
static bool authorized = false;
 | 
			
		||||
 | 
			
		||||
enum class AuthMediaType {
 | 
			
		||||
    Camera,
 | 
			
		||||
    Microphone
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Based on https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_macos
 | 
			
		||||
void CheckAuthorization(AuthMediaType type) {
 | 
			
		||||
    if (@available(macOS 10.14, *)) {
 | 
			
		||||
        NSString *media_type;
 | 
			
		||||
        if(type == AuthMediaType::Camera) {
 | 
			
		||||
            media_type = AVMediaTypeVideo;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            media_type = AVMediaTypeAudio;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Request permission to access the camera and microphone.
 | 
			
		||||
        switch ([AVCaptureDevice authorizationStatusForMediaType:media_type]) {
 | 
			
		||||
            case AVAuthorizationStatusAuthorized:
 | 
			
		||||
                // The user has previously granted access to the camera.
 | 
			
		||||
                authorized = true;
 | 
			
		||||
                break;
 | 
			
		||||
            case AVAuthorizationStatusNotDetermined:
 | 
			
		||||
            {
 | 
			
		||||
                // The app hasn't yet asked the user for camera access.
 | 
			
		||||
                [AVCaptureDevice requestAccessForMediaType:media_type completionHandler:^(BOOL) {
 | 
			
		||||
                    authorized = true;
 | 
			
		||||
                }];
 | 
			
		||||
                if(type == AuthMediaType::Camera) {
 | 
			
		||||
                    LOG_INFO(Frontend, "Camera access requested.");
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case AVAuthorizationStatusDenied:
 | 
			
		||||
            {
 | 
			
		||||
                // The user has previously denied access.
 | 
			
		||||
                authorized = false;
 | 
			
		||||
                if(type == AuthMediaType::Camera) {
 | 
			
		||||
                    LOG_WARNING(Frontend, "Camera access denied. To change this you may modify the macos system settings for Citra at 'System Preferences -> Security & Privacy -> Camera'");
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            case AVAuthorizationStatusRestricted:
 | 
			
		||||
            {
 | 
			
		||||
                // The user can't grant access due to restrictions.
 | 
			
		||||
                authorized = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        authorized = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CheckAuthorizationForCamera() {
 | 
			
		||||
    CheckAuthorization(AuthMediaType::Camera);
 | 
			
		||||
    return authorized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CheckAuthorizationForMicrophone() {
 | 
			
		||||
    CheckAuthorization(AuthMediaType::Microphone);
 | 
			
		||||
    return authorized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} //AppleAuthorization
 | 
			
		||||
		Reference in New Issue
	
	Block a user