Skip to content

Commit aff6747

Browse files
new MicrophoneServer and MicrophoneFeed classes
1 parent 8d8041b commit aff6747

File tree

15 files changed

+503
-16
lines changed

15 files changed

+503
-16
lines changed

doc/classes/@GlobalScope.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,8 @@
15981598
<member name="Marshalls" type="Marshalls" setter="" getter="">
15991599
The [Marshalls] singleton.
16001600
</member>
1601+
<member name="MicrophoneServer" type="MicrophoneServer" setter="" getter="">
1602+
</member>
16011603
<member name="NativeMenu" type="NativeMenu" setter="" getter="">
16021604
The [NativeMenu] singleton.
16031605
[b]Note:[/b] Only implemented on macOS.

doc/classes/MicrophoneFeed.xml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="MicrophoneFeed" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
3+
<brief_description>
4+
A microphone feed gives you access to a single physical microphone attached to your device.
5+
</brief_description>
6+
<description>
7+
A microphone feed gives you access to a single physical microphone attached to your device.
8+
When enabled, Godot will start acquiring stereo sample frames at the [method AudioServer.get_input_mix_rate]
9+
and writing them into an internal buffer of size [method get_buffer_length_frames].
10+
</description>
11+
<tutorials>
12+
</tutorials>
13+
<methods>
14+
<method name="get_buffer_length_frames">
15+
<return type="int" />
16+
<description>
17+
Returns the absolute size of the microphone input buffer.
18+
This is set as some multiple of the audio latency and can be used to
19+
estimate the minimum rate at which the frames are fetched.
20+
</description>
21+
</method>
22+
<method name="get_frames">
23+
<return type="PackedVector2Array" />
24+
<param index="0" name="frames" type="int" />
25+
<description>
26+
Gets the next [param frames] audio samples from the internal microphone buffer.
27+
The buffer is filled at the rate of [method AudioServer.get_input_mix_rate] frames per second when [member feed_is_active] is true.
28+
Returns a [PackedVector2Array] containing exactly [param frames] audio samples if available, or an empty [PackedVector2Array].
29+
The samples are signed floating-point PCM between [code]-1[/code] and [code]1[/code]. You will have to scale them if you want to use them as 8 or 16-bit integer samples. ([code]v = 0x7fff * samples[0].x[/code])
30+
</description>
31+
</method>
32+
<method name="get_frames_available">
33+
<return type="int" />
34+
<description>
35+
Returns the number of frames available to read using [method get_frames].
36+
</description>
37+
</method>
38+
<method name="get_name" qualifiers="const">
39+
<return type="String" />
40+
<description>
41+
Returns the microphone's name.
42+
</description>
43+
</method>
44+
<method name="set_name">
45+
<return type="void" />
46+
<param index="0" name="name" type="String" />
47+
<description>
48+
Sets the microphone's name.
49+
</description>
50+
</method>
51+
</methods>
52+
<members>
53+
<member name="feed_is_active" type="bool" setter="set_active" getter="is_active" default="false">
54+
If [code]true[/code], the microphone feed is active.
55+
</member>
56+
</members>
57+
</class>

doc/classes/MicrophoneServer.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="MicrophoneServer" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
3+
<brief_description>
4+
Server keeping track of different microphones accessible in Godot.
5+
</brief_description>
6+
<description>
7+
The [MicrophoneServer] keeps track of different microphones accessible in Godot.
8+
[b]Note:[/b] There is currently only one default microphone implemented across all the platforms.
9+
</description>
10+
<tutorials>
11+
</tutorials>
12+
<methods>
13+
<method name="get_feed">
14+
<return type="MicrophoneFeed" />
15+
<param index="0" name="index" type="int" />
16+
<description>
17+
Returns the [MicrophoneFeed] corresponding to the microphone with the given [param index].
18+
</description>
19+
</method>
20+
<method name="get_feed_count">
21+
<return type="int" />
22+
<description>
23+
Returns the number of [MicrophoneFeed]s registered.
24+
</description>
25+
</method>
26+
</methods>
27+
</class>

drivers/pulseaudio/audio_driver_pulseaudio.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,9 @@ void AudioDriverPulseAudio::finish_input_device() {
762762
}
763763

764764
Error AudioDriverPulseAudio::input_start() {
765+
if (pa_rec_str) {
766+
return ERR_ALREADY_IN_USE;
767+
}
765768
lock();
766769
Error err = init_input_device();
767770
unlock();

drivers/wasapi/audio_driver_wasapi.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,10 @@ void AudioDriverWASAPI::finish() {
10041004
}
10051005

10061006
Error AudioDriverWASAPI::input_start() {
1007+
if (audio_input.active.is_set()) {
1008+
return ERR_ALREADY_IN_USE;
1009+
}
1010+
10071011
Error err = init_input_device();
10081012
if (err != OK) {
10091013
ERR_PRINT("WASAPI: init_input_device error");
@@ -1023,11 +1027,9 @@ Error AudioDriverWASAPI::input_stop() {
10231027
if (audio_input.active.is_set()) {
10241028
audio_input.audio_client->Stop();
10251029
audio_input.active.clear();
1026-
1027-
return OK;
10281030
}
10291031

1030-
return FAILED;
1032+
return OK;
10311033
}
10321034

10331035
PackedStringArray AudioDriverWASAPI::get_input_device_list() {

main/main.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#include "servers/audio_server.h"
7171
#include "servers/camera_server.h"
7272
#include "servers/display_server.h"
73+
#include "servers/microphone_server.h"
7374
#include "servers/movie_writer/movie_writer.h"
7475
#include "servers/register_server_types.h"
7576
#include "servers/rendering/rendering_server_default.h"
@@ -171,6 +172,7 @@ static SteamTracker *steam_tracker = nullptr;
171172
// Initialized in setup2()
172173
static AudioServer *audio_server = nullptr;
173174
static CameraServer *camera_server = nullptr;
175+
static MicrophoneServer *microphone_server = nullptr;
174176
static DisplayServer *display_server = nullptr;
175177
static RenderingServer *rendering_server = nullptr;
176178
static TextServerManager *tsman = nullptr;
@@ -3709,6 +3711,8 @@ Error Main::setup2(bool p_show_boot_logo) {
37093711

37103712
camera_server = CameraServer::create();
37113713

3714+
microphone_server = MicrophoneServer::create();
3715+
37123716
MAIN_PRINT("Main: Load Physics");
37133717

37143718
initialize_physics();
@@ -5087,6 +5091,10 @@ void Main::cleanup(bool p_force) {
50875091
memdelete(camera_server);
50885092
}
50895093

5094+
if (microphone_server) {
5095+
memdelete(microphone_server);
5096+
}
5097+
50905098
OS::get_singleton()->finalize();
50915099

50925100
finalize_display();

platform/android/audio_driver_opensl.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ void AudioDriverOpenSL::_record_buffer_callback(SLAndroidSimpleBufferQueueItf qu
195195
void AudioDriverOpenSL::_record_buffer_callbacks(SLAndroidSimpleBufferQueueItf queueItf, void *pContext) {
196196
AudioDriverOpenSL *ad = static_cast<AudioDriverOpenSL *>(pContext);
197197

198+
ad->lock();
198199
ad->_record_buffer_callback(queueItf);
200+
ad->unlock();
199201
}
200202

201203
Error AudioDriverOpenSL::init_input_device() {
@@ -271,28 +273,30 @@ Error AudioDriverOpenSL::input_start() {
271273
}
272274

273275
if (OS::get_singleton()->request_permission("RECORD_AUDIO")) {
274-
return init_input_device();
276+
Error err = init_input_device();
277+
if (err != OK) {
278+
input_stop();
279+
}
280+
return err;
275281
}
276282

277283
WARN_PRINT("Unable to start audio capture - No RECORD_AUDIO permission");
278284
return ERR_UNAUTHORIZED;
279285
}
280286

281287
Error AudioDriverOpenSL::input_stop() {
282-
if (!recordItf || !recordBufferQueueItf) {
283-
return ERR_CANT_OPEN;
288+
if (recordItf) {
289+
(*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
290+
recordItf = nullptr;
284291
}
285292

286-
SLuint32 state;
287-
SLresult res = (*recordItf)->GetRecordState(recordItf, &state);
288-
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
289-
290-
if (state != SL_RECORDSTATE_STOPPED) {
291-
res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
292-
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
293-
294-
res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
295-
ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
293+
if (recordBufferQueueItf) {
294+
(*recordBufferQueueItf)->Clear(recordBufferQueueItf);
295+
recordBufferQueueItf = nullptr;
296+
}
297+
if (recorder) {
298+
(*recorder)->Destroy(recorder);
299+
recorder = nullptr;
296300
}
297301

298302
return OK;

servers/SCsub

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ env.servers_sources = []
77

88
env.add_source_files(env.servers_sources, "audio_server.cpp")
99
env.add_source_files(env.servers_sources, "camera_server.cpp")
10+
env.add_source_files(env.servers_sources, "microphone_server.cpp")
1011
env.add_source_files(env.servers_sources, "display_server.cpp")
1112
env.add_source_files(env.servers_sources, "navigation_server_2d.cpp")
1213
env.add_source_files(env.servers_sources, "navigation_server_3d.cpp")
@@ -16,6 +17,7 @@ env.add_source_files(env.servers_sources, "text_server.cpp")
1617

1718
SConscript("audio/SCsub")
1819
SConscript("camera/SCsub")
20+
SConscript("microphone/SCsub")
1921
SConscript("debugger/SCsub")
2022
SConscript("display/SCsub")
2123
SConscript("extensions/SCsub")

servers/audio_server.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ void AudioDriver::input_buffer_write(int32_t sample) {
109109
input_size++;
110110
}
111111
} else {
112+
// This protection was added at https://github.com/godotengine/godot/commit/f529649cece9f08002c527fca25c45a5e66d2a4b due to a "possible crash".
113+
// This cannot have happened unless two non-locked threads entered function simultaneously, which was possible when multiple calls to
114+
// AudioDriver::input_start() did not raise an error condition.
112115
WARN_PRINT("input_buffer_write: Invalid input_position=" + itos(input_position) + " input_buffer.size()=" + itos(input_buffer.size()));
113116
}
114117
}

servers/microphone/SCsub

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env python
2+
from misc.utility.scons_hints import *
3+
4+
Import("env")
5+
6+
env.add_source_files(env.servers_sources, "*.cpp")

0 commit comments

Comments
 (0)