1 #include "iaxclient_lib.h"
5 #include <OpenAL/alc.h>
6 #elif defined(OPENALSDK)
14 struct openal_priv_data
29 static struct iaxc_audio_device device = {
31 IAXC_AD_INPUT | IAXC_AD_OUTPUT | IAXC_AD_RING | IAXC_AD_INPUT_DEFAULT | IAXC_AD_OUTPUT_DEFAULT | IAXC_AD_RING_DEFAULT,
35 static int openal_error(const char* function, int err)
37 fprintf(stderr, "OpenAl function %s failed with code %d\n", function, err);
41 int openal_input(struct iaxc_audio_driver *d, void *samples, int *nSamples)
44 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
49 alcGetIntegerv(priv->in_dev, ALC_CAPTURE_SAMPLES, sizeof(available), &available);
50 /* do not return less data than caller wanted, iaxclient does not like it */
51 request = (available < *nSamples) ? 0 : *nSamples;
54 err = alcGetError(priv->in_dev);
55 alcCaptureSamples(priv->in_dev, samples, request);
56 err = alcGetError(priv->in_dev);
59 openal_error("alcCaptureSamples", err);
63 // software mute, but keep data flowing for sync purposes
64 if (priv->input_level == 0)
66 memset(samples, 0, 2 * request);
74 static void openal_unqueue(struct openal_priv_data* priv)
80 alGetSourcei(priv->source, AL_BUFFERS_PROCESSED, &processed);
87 alGetSourcei(priv->source, AL_BUFFERS_QUEUED, &queued);
88 alGetSourcei(priv->source, AL_SOURCE_STATE, &state);
90 fprintf(stderr, "free: %d processed: %d queued: %d head: %d tail: %d state: %d\n",
91 priv->buffers_free, processed, queued, priv->buffers_head, priv->buffers_tail, state);
96 for(i = 0; i < processed; i++)
98 alSourceUnqueueBuffers(priv->source, 1, priv->buffers + priv->buffers_tail);
102 openal_error("alSourceUnqueueBuffers", err);
105 if (++priv->buffers_tail >= priv->num_buffers)
107 priv->buffers_tail = 0;
109 ++priv->buffers_free;
113 int openal_output(struct iaxc_audio_driver *d, void *samples, int nSamples)
115 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
117 openal_unqueue(priv);
118 /* If we run out of buffers, wait for an arbitrary number to become free */
119 if (priv->buffers_free == 0)
121 while(priv->buffers_free < 4)
123 iaxc_millisleep(100);
124 openal_unqueue(priv);
128 if (priv->buffers_free > 0)
130 ALuint buffer = priv->buffers[priv->buffers_head++];
131 if (priv->buffers_head >= priv->num_buffers)
133 priv->buffers_head = 0;
136 alBufferData(buffer, AL_FORMAT_MONO16, samples, nSamples * 2, priv->sample_rate);
137 alSourceQueueBuffers(priv->source, 1, &buffer);
138 --priv->buffers_free;
140 /* delay start of output until we have 2 buffers */
141 if (priv->buffers_free == priv->num_buffers - 2)
145 alGetSourcei(priv->source, AL_SOURCE_STATE, &state);
146 if (state != AL_PLAYING)
149 fprintf(stderr, "calling alSourcePlay\n");
151 alSourcePlay(priv->source);
155 fprintf(stderr, "openal_output buffer overflow\n");
162 int openal_select_devices(struct iaxc_audio_driver *d, int input, int output, int ring)
164 return (input != 0 || output !=0 || ring != 0) ? -1 : 0;
167 int openal_selected_devices(struct iaxc_audio_driver *d, int *input, int *output, int *ring)
177 Apparently iaxclient calls openal_start a gazillion times and doesn't call openal_stop.
178 So let's just make them no-ops.
180 int openal_start(struct iaxc_audio_driver *d)
183 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
184 if (priv) /* just to stop compiler noise */
189 int openal_stop(struct iaxc_audio_driver *d)
192 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
193 if (priv) /* just to stop compiler noise */
198 float openal_input_level_get(struct iaxc_audio_driver *d)
200 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
202 return (float)priv->input_level;
205 float openal_output_level_get(struct iaxc_audio_driver *d)
207 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
209 return priv->output_level;
212 int openal_input_level_set(struct iaxc_audio_driver *d, float level)
214 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
215 priv->input_level = level;
220 int openal_output_level_set(struct iaxc_audio_driver *d, float level)
222 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
223 priv->output_level = level;
224 alSourcef(priv->source, AL_GAIN, level);
229 int openal_play_sound(struct iaxc_sound *s, int ring)
234 int openal_stop_sound(int id)
239 int openal_mic_boost_get(struct iaxc_audio_driver *d)
244 int openal_mic_boost_set(struct iaxc_audio_driver *d, int enable)
249 int openal_destroy(struct iaxc_audio_driver *d)
251 struct openal_priv_data* priv = (struct openal_priv_data*)(d->priv);
253 alcCaptureStop(priv->in_dev);
254 alcCaptureCloseDevice(priv->in_dev);
255 alDeleteSources(1, &priv->source);
260 int openal_initialize(struct iaxc_audio_driver *d, int sample_rate)
262 struct openal_priv_data* priv = malloc(sizeof(struct openal_priv_data));
263 int err = alGetError();
266 // First we are looking for input device
267 priv->in_dev = alcCaptureOpenDevice(NULL, 8000, AL_FORMAT_MONO16, 800);
268 if (!priv->in_dev) return openal_error("alcCaptureOpenDevice", alGetError());
270 alcCaptureStart(priv->in_dev);
271 if ((err = alGetError())) return openal_error("alcCaptureStart", err);
273 // Then we look for output device
274 priv->out_ctx = alcGetCurrentContext();
276 if( priv->out_ctx == NULL ) { // FGCom standalone only
277 ALCdevice* out_dev = alcOpenDevice(NULL);
278 if (out_dev == 0) return openal_error("alcOpenDevice", alGetError());
280 priv->out_ctx = alcCreateContext(out_dev, 0);
281 if (priv->out_ctx == 0) return openal_error("alcCreateContext", alGetError());
284 alcMakeContextCurrent(priv->out_ctx);
285 if ((err = alGetError())) return openal_error("alcMakeContextCurrent", err);
287 priv->sample_rate = sample_rate;
288 priv->num_buffers = 20;
289 priv->input_level = 1;
290 priv->output_level = 1;
291 priv->buffers_head = 0;
292 priv->buffers_tail = 0;
293 priv->buffers_free = priv->num_buffers;
294 priv->buffers = (ALuint*)malloc(sizeof(ALuint) * priv->num_buffers);
296 alGenBuffers(priv->num_buffers, priv->buffers);
297 if ((err = alGetError())) return openal_error("alGenBuffers", err);
299 alGenSources(1, &priv->source);
300 if ((err = alGetError())) return openal_error("alGenSources", err);
302 d->initialize = openal_initialize;
303 d->destroy = openal_destroy;
304 d->select_devices = openal_select_devices;
305 d->selected_devices = openal_selected_devices;
306 d->start = openal_start;
307 d->stop = openal_stop;
308 d->output = openal_output;
309 d->input = openal_input;
310 d->input_level_get = openal_input_level_get;
311 d->input_level_set = openal_input_level_set;
312 d->output_level_get = openal_output_level_get;
313 d->output_level_set = openal_output_level_set;
314 d->mic_boost_get = openal_mic_boost_get;
315 d->mic_boost_set = openal_mic_boost_set;
316 d->play_sound = openal_play_sound;
317 d->stop_sound = openal_stop_sound;
319 d->devices = &device;