Skip to content

MacOS Microphone Permissions #1253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/Platform.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ elseif (GEODE_TARGET_PLATFORM STREQUAL "MacOS")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)

target_link_libraries(${PROJECT_NAME} INTERFACE
"-framework AVFoundation"
"-framework Cocoa"
"-framework OpenGL"
"-framework SystemConfiguration"
Expand Down
4 changes: 4 additions & 0 deletions loader/src/load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,5 +216,9 @@ int geodeEntry(void* platformData) {
// also log after entry so that users are more likely to notice
tryLogForwardCompat();

#ifdef GEODE_IS_MACOS
checkPermissionPlist();
#endif

return 0;
}
9 changes: 8 additions & 1 deletion loader/src/load.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#pragma once

#include <Geode/platform/cplatform.h>

bool safeModeCheck();
int geodeEntry(void* platformData);
int geodeEntry(void* platformData);

#ifdef GEODE_IS_MACOS
void checkPermissionPlist();
#endif
14 changes: 14 additions & 0 deletions loader/src/load.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,18 @@ bool safeModeCheck() {
return false;
}

void checkPermissionPlist() {
std::thread([] {
// Load the plist and check for microphone key
std::string plistPath = (dirs::getGameDir() / "Info.plist").string();
NSString* nsPlistPath = [NSString stringWithUTF8String:plistPath.c_str()];

NSMutableDictionary* plist = [NSMutableDictionary dictionaryWithContentsOfFile:nsPlistPath];
if (![plist objectForKey:@"NSMicrophoneUsageDescription"]) {
// If the microphone key doesn't exist, create it
[plist setObject:@"A mod you installed is requesting microphone access" forKey:@"NSMicrophoneUsageDescription"];
[plist writeToFile:nsPlistPath atomically:YES];
}
}).detach();
}
#endif
50 changes: 48 additions & 2 deletions loader/src/platform/mac/util.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <Geode/loader/Dirs.hpp>
#import <AppKit/AppKit.h>
#import <AVFoundation/AVFoundation.h>
#include <Geode/Utils.hpp>
#include <Geode/binding/GameManager.hpp>
#include <objc/runtime.h>
Expand Down Expand Up @@ -320,11 +321,56 @@ void shutdown() {
}

bool geode::utils::permission::getPermissionStatus(Permission permission) {
return true; // unimplemented
switch (permission) {
case Permission::RecordAudio: {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status) {
case AVAuthorizationStatusRestricted: return false;
case AVAuthorizationStatusNotDetermined: return false;
case AVAuthorizationStatusDenied: return false;
case AVAuthorizationStatusAuthorized: return true;
}
} break;
}

return false;
}

static std::function<void(bool)> g_permissionCallback;

void geode::utils::permission::requestPermission(Permission permission, std::function<void(bool)> callback) {
callback(true); // unimplemented
g_permissionCallback = std::move(callback);

switch (permission) {
case Permission::RecordAudio: {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status) {
case AVAuthorizationStatusNotDetermined: {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
g_permissionCallback(granted);
g_permissionCallback = {};
}];
} break;
case AVAuthorizationStatusRestricted: {
g_permissionCallback(false);
g_permissionCallback = {};
} break;
case AVAuthorizationStatusDenied: {
g_permissionCallback(false);
g_permissionCallback = {};
} break;
case AVAuthorizationStatusAuthorized: {
g_permissionCallback(true);
g_permissionCallback = {};
} break;
}
} break;

default: {
g_permissionCallback(false);
g_permissionCallback = {};
} break;
};
}

#include "../../utils/thread.hpp"
Expand Down