Skip to content
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
4 changes: 3 additions & 1 deletion doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@
<description>
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 iOS, VisionOS: Returns the list of granted permissions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
On iOS, VisionOS: Returns the list of granted permissions.
On iOS, visionOS: Returns the list of granted permissions.

</description>
</method>
<method name="get_keycode_string" qualifiers="const">
Expand Down Expand Up @@ -781,8 +782,9 @@
- [code]OS.request_permission("android.permission.READ_EXTERNAL_STORAGE")[/code]
- [code]OS.request_permission("android.permission.POST_NOTIFICATIONS")[/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] This method is implemented on Android and macOS.
[b]Note:[/b] This method is implemented on Android, macOS and visionOS platforms.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[b]Note:[/b] This method is implemented on Android, macOS and visionOS platforms.
[b]Note:[/b] This method is implemented on Android, macOS, and visionOS platforms.

Please use Oxford comma.

</description>
</method>
<method name="request_permissions">
Expand Down
3 changes: 3 additions & 0 deletions drivers/apple_embedded/os_apple_embedded.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ class OS_AppleEmbedded : public OS_Unix {
void on_exit_background();

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
32 changes: 32 additions & 0 deletions drivers/apple_embedded/os_apple_embedded.mm
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#import <AudioToolbox/AudioServices.h>
#import <CoreText/CoreText.h>
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFAudio.h>
#import <dlfcn.h>
#include <sys/sysctl.h>

Expand Down Expand Up @@ -714,4 +715,35 @@ Rect2 fit_keep_aspect_covered(const Vector2 &p_container, const Vector2 &p_rect)
}
}

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);
}];
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
};
}

}
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
9 changes: 4 additions & 5 deletions drivers/coreaudio/audio_driver_coreaudio.mm
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,16 @@

AudioBufferList bufferList;
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].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);

OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
ad->input_buf.resize(inNumberFrames * ad->capture_channels);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inpuf_buf is not used for anything except temporary storage here, so if mData is nullptr, and the audio unit provide its own buffer it can be completely removed.

diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index 64c77fe97f..36f5eee73b 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -59,7 +59,7 @@ class AudioDriverCoreAudio : public AudioDriver {
        unsigned int capture_buffer_frames = 0;

        Vector<int32_t> samples_in;
-       Vector<int16_t> input_buf;
+       unsigned int buffer_size = 0;

 #ifdef MACOS_ENABLED
        PackedStringArray _get_device_list(bool capture = false);
diff --git a/drivers/coreaudio/audio_driver_coreaudio.mm b/drivers/coreaudio/audio_driver_coreaudio.mm
index fb870e4740..8763a1b933 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.mm
+++ b/drivers/coreaudio/audio_driver_coreaudio.mm
@@ -243,10 +243,9 @@
        bufferList.mNumberBuffers = 1;
        bufferList.mBuffers[0].mData = nullptr;
        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);
-       ad->input_buf.resize(inNumberFrames * ad->capture_channels);
        if (result == noErr) {
                int16_t *data = (int16_t *)bufferList.mBuffers[0].mData;
                for (unsigned int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
@@ -459,8 +458,7 @@
        // 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);

-       unsigned int buffer_size = capture_buffer_frames * capture_channels;
-       input_buf.resize(buffer_size);
+       buffer_size = capture_buffer_frames * capture_channels;

        AURenderCallbackStruct callback;
        memset(&callback, 0, sizeof(AURenderCallbackStruct));

if (result == noErr) {
int16_t *data = (int16_t *)bufferList.mBuffers[0].mData;
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);

if (ad->capture_channels == 1) {
Expand Down Expand Up @@ -393,9 +395,6 @@
UInt32 flag = 1;
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
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;
#ifdef MACOS_ENABLED
Expand Down
Loading