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(&parameters, 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