1 /*************************************************************************/
2 /* audio_driver_rtaudio.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "audio_driver_rtaudio.h"
31
32 #include "globals.h"
33 #include "os/os.h"
34
35 #ifdef RTAUDIO_ENABLED
36
get_name() const37 const char *AudioDriverRtAudio::get_name() const {
38
39 #ifdef OSX_ENABLED
40 return "RtAudio-OSX";
41 #elif defined(UNIX_ENABLED) && (defined(ALSA_ENABLED) || defined(PULSEAUDIO_ENABLED) || defined(OSS_ENABLED))
42 #if defined(OSS_ENABLED)
43 return "RtAudio-OSS";
44 #elif defined(ALSA_ENABLED)
45 return "RtAudio-ALSA";
46 #elif defined(PULSEAUDIO_ENABLED)
47 return "RtAudio-PulseAudio";
48 #endif
49 #elif defined(WINDOWS_ENABLED)
50 return "RtAudio-DirectSound";
51 #else
52 return "RtAudio-None";
53 #endif
54 }
55
callback(void * outputBuffer,void * inputBuffer,unsigned int nBufferFrames,double streamTime,RtAudioStreamStatus status,void * userData)56 int AudioDriverRtAudio::callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void *userData) {
57
58 if (status) {
59 if (status & RTAUDIO_INPUT_OVERFLOW) {
60 WARN_PRINT("RtAudio input overflow!");
61 }
62 if (status & RTAUDIO_OUTPUT_UNDERFLOW) {
63 WARN_PRINT("RtAudio output underflow!");
64 }
65 }
66 int32_t *buffer = (int32_t *)outputBuffer;
67
68 AudioDriverRtAudio *self = (AudioDriverRtAudio *)userData;
69
70 if (self->mutex->try_lock() != OK) {
71 // what should i do..
72 for (unsigned int i = 0; i < nBufferFrames; i++)
73 buffer[i] = 0;
74
75 return 0;
76 }
77
78 self->audio_server_process(nBufferFrames, buffer);
79
80 self->mutex->unlock();
81
82 return 0;
83 }
84
init()85 Error AudioDriverRtAudio::init() {
86
87 active = false;
88 mutex = NULL;
89 dac = memnew(RtAudio);
90
91 ERR_EXPLAIN("Cannot initialize RtAudio audio driver: No devices present.")
92 ERR_FAIL_COND_V(dac->getDeviceCount() < 1, ERR_UNAVAILABLE);
93
94 String channels = GLOBAL_DEF("audio/output", "stereo");
95
96 if (channels == "5.1")
97 output_format = OUTPUT_5_1;
98 else if (channels == "quad")
99 output_format = OUTPUT_QUAD;
100 else if (channels == "mono")
101 output_format = OUTPUT_MONO;
102 else
103 output_format = OUTPUT_STEREO;
104
105 RtAudio::StreamParameters parameters;
106 parameters.deviceId = dac->getDefaultOutputDevice();
107 RtAudio::StreamOptions options;
108
109 // set the desired numberOfBuffers
110 unsigned int target_number_of_buffers = 4;
111 options.numberOfBuffers = target_number_of_buffers;
112
113 // options.
114 // RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). *///
115 // unsigned int numberOfBuffers; /*!< Number of stream buffers. */
116 // std::string streamName; /*!< A stream name (currently used only in Jack). */
117 // int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */
118
119 parameters.firstChannel = 0;
120 mix_rate = GLOBAL_DEF("audio/mix_rate", 44100);
121
122 int latency = GLOBAL_DEF("audio/output_latency", 25);
123 // calculate desired buffer_size, taking the desired numberOfBuffers into account (latency depends on numberOfBuffers*buffer_size)
124 unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000 / target_number_of_buffers);
125
126 if (OS::get_singleton()->is_stdout_verbose()) {
127 print_line("audio buffer size: " + itos(buffer_size));
128 }
129
130 short int tries = 2;
131
132 while (true) {
133 while (true) {
134 switch (output_format) {
135 case OUTPUT_MONO: parameters.nChannels = 1; break;
136 case OUTPUT_STEREO: parameters.nChannels = 2; break;
137 case OUTPUT_QUAD: parameters.nChannels = 4; break;
138 case OUTPUT_5_1: parameters.nChannels = 6; break;
139 };
140
141 try {
142 dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this, &options);
143 mutex = Mutex::create(true);
144 active = true;
145
146 break;
147 } catch (RtAudioError &e) {
148 // try with less channels
149 ERR_PRINT("Unable to open audio, retrying with fewer channels..");
150
151 switch (output_format) {
152 case OUTPUT_MONO:
153 ERR_EXPLAIN("Unable to open audio.");
154 ERR_FAIL_V(ERR_UNAVAILABLE);
155 break;
156 case OUTPUT_STEREO: output_format = OUTPUT_MONO; break;
157 case OUTPUT_QUAD: output_format = OUTPUT_STEREO; break;
158 case OUTPUT_5_1: output_format = OUTPUT_QUAD; break;
159 };
160 }
161 }
162
163 // compare actual numberOfBuffers with the desired one. If not equal, close and reopen the stream with adjusted buffer size, so the desired output_latency is still correct
164 if (target_number_of_buffers != options.numberOfBuffers) {
165 if (tries <= 0) {
166 ERR_EXPLAIN("RtAudio: Unable to set correct number of buffers.");
167 ERR_FAIL_V(ERR_UNAVAILABLE);
168 break;
169 }
170
171 try {
172 dac->closeStream();
173 } catch (RtAudioError &e) {
174 ERR_PRINT(e.what());
175 ERR_FAIL_V(ERR_UNAVAILABLE);
176 break;
177 }
178 if (OS::get_singleton()->is_stdout_verbose())
179 print_line("RtAudio: Desired number of buffers (" + itos(target_number_of_buffers) + ") not available. Using " + itos(options.numberOfBuffers) + " instead. Reopening stream with adjusted buffer_size.");
180
181 // new buffer size dependent on the ratio between set and actual numberOfBuffers
182 buffer_size = buffer_size / (options.numberOfBuffers / target_number_of_buffers);
183 target_number_of_buffers = options.numberOfBuffers;
184 tries--;
185 } else {
186 break;
187 }
188 }
189
190 return OK;
191 }
192
get_mix_rate() const193 int AudioDriverRtAudio::get_mix_rate() const {
194
195 return mix_rate;
196 }
197
get_output_format() const198 AudioDriverSW::OutputFormat AudioDriverRtAudio::get_output_format() const {
199
200 return output_format;
201 }
202
start()203 void AudioDriverRtAudio::start() {
204
205 if (active)
206 dac->startStream();
207 }
208
lock()209 void AudioDriverRtAudio::lock() {
210
211 if (mutex)
212 mutex->lock();
213 }
214
unlock()215 void AudioDriverRtAudio::unlock() {
216
217 if (mutex)
218 mutex->unlock();
219 }
220
finish()221 void AudioDriverRtAudio::finish() {
222
223 if (active && dac->isStreamOpen())
224 dac->closeStream();
225 if (mutex)
226 memdelete(mutex);
227 if (dac)
228 memdelete(dac);
229 }
230
AudioDriverRtAudio()231 AudioDriverRtAudio::AudioDriverRtAudio() {
232
233 active = false;
234 mutex = NULL;
235 mix_rate = 44100;
236 output_format = OUTPUT_STEREO;
237 }
238
239 #endif
240