Преглед изворни кода

Add permission request for Apple embedded platforms, fix microphone input

Co-Authored-By: Miguel de Icaza <[email protected]>

Supersedes https://github.com/godotengine/godot/pull/107233
Fixes https://github.com/godotengine/godot-proposals/issues/12563
Fixes https://github.com/godotengine/godot/issues/33885

Superseding Miguel's PR to get it in during the beta stage.
Patrick Exner пре 2 месеци
родитељ
комит
5a7b6b7159

+ 3 - 1
doc/classes/OS.xml

@@ -302,6 +302,7 @@
 			<description>
 			<description>
 				On Android devices: Returns the list of dangerous permissions that have been granted.
 				On Android devices: Returns the list of dangerous permissions that have been granted.
 				On macOS: Returns the list of granted permissions and user selected folders accessible to the application (sandboxed applications only). Use the native file dialog to request folder access permission.
 				On macOS: Returns the list of granted permissions and user selected folders accessible to the application (sandboxed applications only). Use the native file dialog to request folder access permission.
+				On iOS, visionOS: Returns the list of granted permissions.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_keycode_string" qualifiers="const">
 		<method name="get_keycode_string" qualifiers="const">
@@ -781,8 +782,9 @@
 				- [code]OS.request_permission("android.permission.READ_EXTERNAL_STORAGE")[/code]
 				- [code]OS.request_permission("android.permission.READ_EXTERNAL_STORAGE")[/code]
 				- [code]OS.request_permission("android.permission.POST_NOTIFICATIONS")[/code]
 				- [code]OS.request_permission("android.permission.POST_NOTIFICATIONS")[/code]
 				- [code]OS.request_permission("macos.permission.RECORD_SCREEN")[/code]
 				- [code]OS.request_permission("macos.permission.RECORD_SCREEN")[/code]
+				- [code]OS.request_permission("appleembedded.permission.AUDIO_RECORD")[/code]
 				[b]Note:[/b] On Android, permission must be checked during export.
 				[b]Note:[/b] On Android, permission must be checked during export.
-				[b]Note:[/b] This method is implemented on Android and macOS.
+				[b]Note:[/b] This method is implemented on Android, macOS, and visionOS platforms.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="request_permissions">
 		<method name="request_permissions">

+ 3 - 0
drivers/apple_embedded/os_apple_embedded.h

@@ -137,6 +137,9 @@ public:
 	void on_exit_background();
 	void on_exit_background();
 
 
 	virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const override;
 	virtual Rect2 calculate_boot_screen_rect(const Size2 &p_window_size, const Size2 &p_imgrect_size) const override;
+
+	virtual bool request_permission(const String &p_name) override;
+	virtual Vector<String> get_granted_permissions() const override;
 };
 };
 
 
 #endif // APPLE_EMBEDDED_ENABLED
 #endif // APPLE_EMBEDDED_ENABLED

+ 32 - 0
drivers/apple_embedded/os_apple_embedded.mm

@@ -43,6 +43,7 @@
 #import "drivers/apple/os_log_logger.h"
 #import "drivers/apple/os_log_logger.h"
 #include "main/main.h"
 #include "main/main.h"
 
 
+#import <AVFoundation/AVFAudio.h>
 #import <AudioToolbox/AudioServices.h>
 #import <AudioToolbox/AudioServices.h>
 #import <CoreText/CoreText.h>
 #import <CoreText/CoreText.h>
 #import <UIKit/UIKit.h>
 #import <UIKit/UIKit.h>
@@ -733,4 +734,35 @@ Rect2 OS_AppleEmbedded::calculate_boot_screen_rect(const Size2 &p_window_size, c
 	}
 	}
 }
 }
 
 
+bool OS_AppleEmbedded::request_permission(const String &p_name) {
+	if (p_name == "appleembedded.permission.AUDIO_RECORD") {
+		if (@available(iOS 17.0, *)) {
+			AVAudioApplicationRecordPermission permission = [AVAudioApplication sharedInstance].recordPermission;
+			if (permission == AVAudioApplicationRecordPermissionGranted) {
+				// Permission already granted, you can start recording.
+				return true;
+			} else if (permission == AVAudioApplicationRecordPermissionDenied) {
+				// Permission denied, or not yet granted.
+				return false;
+			} else {
+				// Request the permission, but for now return false as documented.
+				[AVAudioApplication requestRecordPermissionWithCompletionHandler:^(BOOL granted) {
+					get_main_loop()->emit_signal(SNAME("on_request_permissions_result"), p_name, granted);
+				}];
+			}
+		}
+	}
+	return false;
+}
+
+Vector<String> OS_AppleEmbedded::get_granted_permissions() const {
+	Vector<String> ret;
+
+	if (@available(iOS 17.0, *)) {
+		if ([AVAudioApplication sharedInstance].recordPermission == AVAudioApplicationRecordPermissionGranted) {
+			ret.push_back("appleembedded.permission.AUDIO_RECORD");
+		}
+	}
+	return ret;
+}
 #endif // APPLE_EMBEDDED_ENABLED
 #endif // APPLE_EMBEDDED_ENABLED

+ 1 - 1
drivers/coreaudio/audio_driver_coreaudio.h

@@ -59,7 +59,7 @@ class AudioDriverCoreAudio : public AudioDriver {
 	unsigned int capture_buffer_frames = 0;
 	unsigned int capture_buffer_frames = 0;
 
 
 	Vector<int32_t> samples_in;
 	Vector<int32_t> samples_in;
-	Vector<int16_t> input_buf;
+	unsigned int buffer_size = 0;
 
 
 #ifdef MACOS_ENABLED
 #ifdef MACOS_ENABLED
 	PackedStringArray _get_device_list(bool capture = false);
 	PackedStringArray _get_device_list(bool capture = false);

+ 5 - 8
drivers/coreaudio/audio_driver_coreaudio.mm

@@ -241,14 +241,15 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
 
 
 	AudioBufferList bufferList;
 	AudioBufferList bufferList;
 	bufferList.mNumberBuffers = 1;
 	bufferList.mNumberBuffers = 1;
-	bufferList.mBuffers[0].mData = ad->input_buf.ptrw();
+	bufferList.mBuffers[0].mData = nullptr;
 	bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
 	bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
-	bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);
+	bufferList.mBuffers[0].mDataByteSize = ad->buffer_size * sizeof(int16_t);
 
 
 	OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
 	OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
 	if (result == noErr) {
 	if (result == noErr) {
+		int16_t *data = (int16_t *)bufferList.mBuffers[0].mData;
 		for (unsigned int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
 		for (unsigned int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
-			int32_t sample = ad->input_buf[i] << 16;
+			int32_t sample = data[i] << 16;
 			ad->input_buffer_write(sample);
 			ad->input_buffer_write(sample);
 
 
 			if (ad->capture_channels == 1) {
 			if (ad->capture_channels == 1) {
@@ -393,9 +394,6 @@ Error AudioDriverCoreAudio::init_input_device() {
 	UInt32 flag = 1;
 	UInt32 flag = 1;
 	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
 	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
 	ERR_FAIL_COND_V(result != noErr, FAILED);
 	ERR_FAIL_COND_V(result != noErr, FAILED);
-	flag = 0;
-	result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag));
-	ERR_FAIL_COND_V(result != noErr, FAILED);
 
 
 	UInt32 size;
 	UInt32 size;
 #ifdef MACOS_ENABLED
 #ifdef MACOS_ENABLED
@@ -460,8 +458,7 @@ Error AudioDriverCoreAudio::init_input_device() {
 	// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
 	// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
 	capture_buffer_frames = closest_power_of_2(latency * (uint32_t)capture_mix_rate / (uint32_t)1000);
 	capture_buffer_frames = closest_power_of_2(latency * (uint32_t)capture_mix_rate / (uint32_t)1000);
 
 
-	unsigned int buffer_size = capture_buffer_frames * capture_channels;
-	input_buf.resize(buffer_size);
+	buffer_size = capture_buffer_frames * capture_channels;
 
 
 	AURenderCallbackStruct callback;
 	AURenderCallbackStruct callback;
 	memset(&callback, 0, sizeof(AURenderCallbackStruct));
 	memset(&callback, 0, sizeof(AURenderCallbackStruct));