Low latency patch + avoid cpu pegging
[openal-soft/android/lowlatency.git] / Alc / pulseaudio.c
blobe4c6f2fcb8eac88cd30e895956c6982b808d4c60
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "alMain.h"
24 #ifdef HAVE_DLFCN_H
25 #include <dlfcn.h>
26 #endif
28 #include <pulse/pulseaudio.h>
30 #if PA_API_VERSION == 11
31 #define PA_STREAM_ADJUST_LATENCY 0x2000U
32 static __inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
34 return (x == PA_STREAM_CREATING || x == PA_STREAM_READY);
36 static __inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
38 return (x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING ||
39 x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY);
41 #define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD
42 #define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD
43 #elif PA_API_VERSION != 12
44 #error Invalid PulseAudio API version
45 #endif
47 #ifndef PA_CHECK_VERSION
48 #define PA_CHECK_VERSION(major,minor,micro) \
49 ((PA_MAJOR > (major)) || \
50 (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
51 (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
52 #endif
54 static void *pa_handle;
55 #define MAKE_FUNC(x) static typeof(x) * p##x
56 MAKE_FUNC(pa_context_unref);
57 MAKE_FUNC(pa_sample_spec_valid);
58 MAKE_FUNC(pa_stream_drop);
59 MAKE_FUNC(pa_strerror);
60 MAKE_FUNC(pa_context_get_state);
61 MAKE_FUNC(pa_stream_get_state);
62 MAKE_FUNC(pa_threaded_mainloop_signal);
63 MAKE_FUNC(pa_stream_peek);
64 MAKE_FUNC(pa_threaded_mainloop_wait);
65 MAKE_FUNC(pa_threaded_mainloop_unlock);
66 MAKE_FUNC(pa_threaded_mainloop_in_thread);
67 MAKE_FUNC(pa_context_new);
68 MAKE_FUNC(pa_threaded_mainloop_stop);
69 MAKE_FUNC(pa_context_disconnect);
70 MAKE_FUNC(pa_threaded_mainloop_start);
71 MAKE_FUNC(pa_threaded_mainloop_get_api);
72 MAKE_FUNC(pa_context_set_state_callback);
73 MAKE_FUNC(pa_stream_write);
74 MAKE_FUNC(pa_xfree);
75 MAKE_FUNC(pa_stream_connect_record);
76 MAKE_FUNC(pa_stream_connect_playback);
77 MAKE_FUNC(pa_stream_readable_size);
78 MAKE_FUNC(pa_stream_cork);
79 MAKE_FUNC(pa_stream_is_suspended);
80 MAKE_FUNC(pa_stream_get_device_name);
81 MAKE_FUNC(pa_path_get_filename);
82 MAKE_FUNC(pa_get_binary_name);
83 MAKE_FUNC(pa_threaded_mainloop_free);
84 MAKE_FUNC(pa_context_errno);
85 MAKE_FUNC(pa_xmalloc);
86 MAKE_FUNC(pa_stream_unref);
87 MAKE_FUNC(pa_threaded_mainloop_accept);
88 MAKE_FUNC(pa_stream_set_write_callback);
89 MAKE_FUNC(pa_threaded_mainloop_new);
90 MAKE_FUNC(pa_context_connect);
91 MAKE_FUNC(pa_stream_set_buffer_attr);
92 MAKE_FUNC(pa_stream_get_buffer_attr);
93 MAKE_FUNC(pa_stream_get_sample_spec);
94 MAKE_FUNC(pa_stream_set_read_callback);
95 MAKE_FUNC(pa_stream_set_state_callback);
96 MAKE_FUNC(pa_stream_set_moved_callback);
97 MAKE_FUNC(pa_stream_new);
98 MAKE_FUNC(pa_stream_disconnect);
99 MAKE_FUNC(pa_threaded_mainloop_lock);
100 MAKE_FUNC(pa_channel_map_init_auto);
101 MAKE_FUNC(pa_channel_map_parse);
102 MAKE_FUNC(pa_channel_map_snprint);
103 MAKE_FUNC(pa_channel_map_equal);
104 MAKE_FUNC(pa_context_get_server_info);
105 MAKE_FUNC(pa_context_get_sink_info_by_name);
106 MAKE_FUNC(pa_context_get_sink_info_list);
107 MAKE_FUNC(pa_context_get_source_info_list);
108 MAKE_FUNC(pa_operation_get_state);
109 MAKE_FUNC(pa_operation_unref);
110 #if PA_CHECK_VERSION(0,9,15)
111 MAKE_FUNC(pa_channel_map_superset);
112 MAKE_FUNC(pa_stream_set_buffer_attr_callback);
113 #endif
114 #if PA_CHECK_VERSION(0,9,16)
115 MAKE_FUNC(pa_stream_begin_write);
116 #endif
117 #undef MAKE_FUNC
119 #ifndef PATH_MAX
120 #define PATH_MAX 4096
121 #endif
123 typedef struct {
124 char *device_name;
126 ALCuint samples;
127 ALCuint frame_size;
129 RingBuffer *ring;
131 pa_buffer_attr attr;
132 pa_sample_spec spec;
134 pa_threaded_mainloop *loop;
136 pa_stream *stream;
137 pa_context *context;
138 } pulse_data;
140 typedef struct {
141 char *name;
142 char *device_name;
143 } DevMap;
146 static const ALCchar pulse_device[] = "PulseAudio Default";
147 static DevMap *allDevNameMap;
148 static ALuint numDevNames;
149 static DevMap *allCaptureDevNameMap;
150 static ALuint numCaptureDevNames;
151 static pa_context_flags_t pulse_ctx_flags;
154 void *pulse_load(void) //{{{
156 if(!pa_handle)
158 #ifdef _WIN32
159 pa_handle = LoadLibrary("libpulse-0.dll");
160 #define LOAD_FUNC(x) do { \
161 p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
162 if(!(p##x)) { \
163 AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \
164 FreeLibrary(pa_handle); \
165 pa_handle = NULL; \
166 return NULL; \
168 } while(0)
169 #define LOAD_OPTIONAL_FUNC(x) do { \
170 p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
171 } while(0)
173 #elif defined (HAVE_DLFCN_H)
175 const char *err;
176 #if defined(__APPLE__) && defined(__MACH__)
177 pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW);
178 #else
179 pa_handle = dlopen("libpulse.so.0", RTLD_NOW);
180 #endif
181 dlerror();
183 #define LOAD_FUNC(x) do { \
184 p##x = dlsym(pa_handle, #x); \
185 if((err=dlerror()) != NULL) { \
186 AL_PRINT("Could not load %s from libpulse: %s\n", #x, err); \
187 dlclose(pa_handle); \
188 pa_handle = NULL; \
189 return NULL; \
191 } while(0)
192 #define LOAD_OPTIONAL_FUNC(x) do { \
193 p##x = dlsym(pa_handle, #x); \
194 if((err=dlerror()) != NULL) { \
195 p##x = NULL; \
197 } while(0)
199 #else
201 pa_handle = (void*)0xDEADBEEF;
202 #define LOAD_FUNC(x) p##x = (x)
203 #define LOAD_OPTIONAL_FUNC(x) p##x = (x)
205 #endif
206 if(!pa_handle)
207 return NULL;
209 LOAD_FUNC(pa_context_unref);
210 LOAD_FUNC(pa_sample_spec_valid);
211 LOAD_FUNC(pa_stream_drop);
212 LOAD_FUNC(pa_strerror);
213 LOAD_FUNC(pa_context_get_state);
214 LOAD_FUNC(pa_stream_get_state);
215 LOAD_FUNC(pa_threaded_mainloop_signal);
216 LOAD_FUNC(pa_stream_peek);
217 LOAD_FUNC(pa_threaded_mainloop_wait);
218 LOAD_FUNC(pa_threaded_mainloop_unlock);
219 LOAD_FUNC(pa_threaded_mainloop_in_thread);
220 LOAD_FUNC(pa_context_new);
221 LOAD_FUNC(pa_threaded_mainloop_stop);
222 LOAD_FUNC(pa_context_disconnect);
223 LOAD_FUNC(pa_threaded_mainloop_start);
224 LOAD_FUNC(pa_threaded_mainloop_get_api);
225 LOAD_FUNC(pa_context_set_state_callback);
226 LOAD_FUNC(pa_stream_write);
227 LOAD_FUNC(pa_xfree);
228 LOAD_FUNC(pa_stream_connect_record);
229 LOAD_FUNC(pa_stream_connect_playback);
230 LOAD_FUNC(pa_stream_readable_size);
231 LOAD_FUNC(pa_stream_cork);
232 LOAD_FUNC(pa_stream_is_suspended);
233 LOAD_FUNC(pa_stream_get_device_name);
234 LOAD_FUNC(pa_path_get_filename);
235 LOAD_FUNC(pa_get_binary_name);
236 LOAD_FUNC(pa_threaded_mainloop_free);
237 LOAD_FUNC(pa_context_errno);
238 LOAD_FUNC(pa_xmalloc);
239 LOAD_FUNC(pa_stream_unref);
240 LOAD_FUNC(pa_threaded_mainloop_accept);
241 LOAD_FUNC(pa_stream_set_write_callback);
242 LOAD_FUNC(pa_threaded_mainloop_new);
243 LOAD_FUNC(pa_context_connect);
244 LOAD_FUNC(pa_stream_set_buffer_attr);
245 LOAD_FUNC(pa_stream_get_buffer_attr);
246 LOAD_FUNC(pa_stream_get_sample_spec);
247 LOAD_FUNC(pa_stream_set_read_callback);
248 LOAD_FUNC(pa_stream_set_state_callback);
249 LOAD_FUNC(pa_stream_set_moved_callback);
250 LOAD_FUNC(pa_stream_new);
251 LOAD_FUNC(pa_stream_disconnect);
252 LOAD_FUNC(pa_threaded_mainloop_lock);
253 LOAD_FUNC(pa_channel_map_init_auto);
254 LOAD_FUNC(pa_channel_map_parse);
255 LOAD_FUNC(pa_channel_map_snprint);
256 LOAD_FUNC(pa_channel_map_equal);
257 LOAD_FUNC(pa_context_get_server_info);
258 LOAD_FUNC(pa_context_get_sink_info_by_name);
259 LOAD_FUNC(pa_context_get_sink_info_list);
260 LOAD_FUNC(pa_context_get_source_info_list);
261 LOAD_FUNC(pa_operation_get_state);
262 LOAD_FUNC(pa_operation_unref);
263 #if PA_CHECK_VERSION(0,9,15)
264 LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
265 LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
266 #endif
267 #if PA_CHECK_VERSION(0,9,16)
268 LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
269 #endif
271 #undef LOAD_OPTIONAL_FUNC
272 #undef LOAD_FUNC
274 return pa_handle;
275 } //}}}
277 // PulseAudio Event Callbacks //{{{
278 static void context_state_callback(pa_context *context, void *pdata) //{{{
280 pa_threaded_mainloop *loop = pdata;
281 pa_context_state_t state;
283 state = ppa_context_get_state(context);
284 if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
285 ppa_threaded_mainloop_signal(loop, 0);
286 }//}}}
288 static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
290 pa_threaded_mainloop *loop = pdata;
291 pa_stream_state_t state;
293 state = ppa_stream_get_state(stream);
294 if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
295 ppa_threaded_mainloop_signal(loop, 0);
296 }//}}}
298 static void stream_buffer_attr_callback(pa_stream *stream, void *pdata) //{{{
300 ALCdevice *Device = pdata;
301 pulse_data *data = Device->ExtraData;
303 SuspendContext(NULL);
305 data->attr = *(ppa_stream_get_buffer_attr(stream));
306 Device->UpdateSize = 20 * Device->Frequency / 1000;
307 Device->NumUpdates = data->attr.tlength/data->frame_size / Device->UpdateSize;
308 if(Device->NumUpdates == 0)
309 Device->NumUpdates = 1;
311 ProcessContext(NULL);
312 }//}}}
314 static void stream_device_callback(pa_stream *stream, void *pdata) //{{{
316 ALCdevice *Device = pdata;
317 pulse_data *data = Device->ExtraData;
319 free(data->device_name);
320 data->device_name = strdup(ppa_stream_get_device_name(stream));
321 }//}}}
323 static void context_state_callback2(pa_context *context, void *pdata) //{{{
325 ALCdevice *Device = pdata;
326 pulse_data *data = Device->ExtraData;
328 if(ppa_context_get_state(context) == PA_CONTEXT_FAILED)
330 AL_PRINT("Received context failure!\n");
331 aluHandleDisconnect(Device);
333 ppa_threaded_mainloop_signal(data->loop, 0);
334 }//}}}
336 static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{
338 ALCdevice *Device = pdata;
339 pulse_data *data = Device->ExtraData;
341 if(ppa_stream_get_state(stream) == PA_STREAM_FAILED)
343 AL_PRINT("Received stream failure!\n");
344 aluHandleDisconnect(Device);
346 ppa_threaded_mainloop_signal(data->loop, 0);
347 }//}}}
349 static void stream_success_callback(pa_stream *stream, int success, void *pdata) //{{{
351 ALCdevice *Device = pdata;
352 pulse_data *data = Device->ExtraData;
353 (void)stream;
354 (void)success;
356 ppa_threaded_mainloop_signal(data->loop, 0);
357 }//}}}
359 static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
361 ALCdevice *device = pdata;
362 pulse_data *data = device->ExtraData;
363 char chanmap_str[256] = "";
364 const struct {
365 const char *str;
366 ALenum format;
367 } chanmaps[] = {
368 { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
369 AL_FORMAT_71CHN32 },
370 { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
371 AL_FORMAT_61CHN32 },
372 { "front-left,front-right,front-center,lfe,rear-left,rear-right",
373 AL_FORMAT_51CHN32 },
374 { "front-left,front-right,rear-left,rear-right", AL_FORMAT_QUAD32 },
375 { "front-left,front-right", AL_FORMAT_STEREO_FLOAT32 },
376 { "mono", AL_FORMAT_MONO_FLOAT32 },
377 { NULL, 0 }
379 int i;
380 (void)context;
382 if(eol)
384 ppa_threaded_mainloop_signal(data->loop, 0);
385 return;
388 for(i = 0;chanmaps[i].str;i++)
390 pa_channel_map map;
391 if(!ppa_channel_map_parse(&map, chanmaps[i].str))
392 continue;
394 if(ppa_channel_map_equal(&info->channel_map, &map)
395 #if PA_CHECK_VERSION(0,9,15)
396 || (ppa_channel_map_superset &&
397 ppa_channel_map_superset(&info->channel_map, &map))
398 #endif
401 device->Format = chanmaps[i].format;
402 return;
406 ppa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
407 AL_PRINT("Failed to find format for channel map:\n %s\n", chanmap_str);
408 }//}}}
410 static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
412 pa_threaded_mainloop *loop = pdata;
413 void *temp;
415 (void)context;
417 if(eol)
419 ppa_threaded_mainloop_signal(loop, 0);
420 return;
423 temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
424 if(temp)
426 char str[1024];
427 snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
429 allDevNameMap = temp;
430 allDevNameMap[numDevNames].name = strdup(str);
431 allDevNameMap[numDevNames].device_name = strdup(info->name);
432 numDevNames++;
434 }//}}}
436 static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata) //{{{
438 pa_threaded_mainloop *loop = pdata;
439 void *temp;
441 (void)context;
443 if(eol)
445 ppa_threaded_mainloop_signal(loop, 0);
446 return;
449 temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
450 if(temp)
452 char str[256];
453 snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
455 allCaptureDevNameMap = temp;
456 allCaptureDevNameMap[numCaptureDevNames].name = strdup(str);
457 allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
458 numCaptureDevNames++;
460 }//}}}
461 //}}}
463 // PulseAudio I/O Callbacks //{{{
464 static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
466 ALCdevice *Device = pdata;
467 pulse_data *data = Device->ExtraData;
469 while(len > 0)
471 size_t newlen = len;
472 void *buf;
473 pa_free_cb_t free_func = NULL;
475 #if PA_CHECK_VERSION(0,9,16)
476 if(!ppa_stream_begin_write ||
477 ppa_stream_begin_write(stream, &buf, &newlen) < 0)
478 #endif
480 buf = ppa_xmalloc(newlen);
481 free_func = ppa_xfree;
484 aluMixData(Device, buf, newlen/data->frame_size);
485 ppa_stream_write(stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
486 len -= newlen;
488 } //}}}
489 //}}}
491 static pa_context *connect_context(pa_threaded_mainloop *loop)
493 const char *name = "OpenAL Soft";
494 char path_name[PATH_MAX];
495 pa_context_state_t state;
496 pa_context *context;
497 int err;
499 if(ppa_get_binary_name(path_name, sizeof(path_name)))
500 name = ppa_path_get_filename(path_name);
502 context = ppa_context_new(ppa_threaded_mainloop_get_api(loop), name);
503 if(!context)
505 AL_PRINT("pa_context_new() failed\n");
506 return NULL;
509 ppa_context_set_state_callback(context, context_state_callback, loop);
511 if((err=ppa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
513 while((state=ppa_context_get_state(context)) != PA_CONTEXT_READY)
515 if(!PA_CONTEXT_IS_GOOD(state))
517 err = ppa_context_errno(context);
518 break;
521 ppa_threaded_mainloop_wait(loop);
524 ppa_context_set_state_callback(context, NULL, NULL);
526 if(err < 0)
528 AL_PRINT("Context did not connect: %s\n", ppa_strerror(err));
529 ppa_context_unref(context);
530 return NULL;
533 return context;
536 static pa_stream *connect_playback_stream(ALCdevice *device,
537 pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
538 pa_channel_map *chanmap)
540 pulse_data *data = device->ExtraData;
541 pa_stream_state_t state;
542 pa_stream *stream;
544 stream = ppa_stream_new(data->context, "Playback Stream", spec, chanmap);
545 if(!stream)
547 AL_PRINT("pa_stream_new() failed: %s\n",
548 ppa_strerror(ppa_context_errno(data->context)));
549 return NULL;
552 ppa_stream_set_state_callback(stream, stream_state_callback, data->loop);
554 if(ppa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0)
556 AL_PRINT("Stream did not connect: %s\n",
557 ppa_strerror(ppa_context_errno(data->context)));
558 ppa_stream_unref(stream);
559 return NULL;
562 while((state=ppa_stream_get_state(stream)) != PA_STREAM_READY)
564 if(!PA_STREAM_IS_GOOD(state))
566 AL_PRINT("Stream did not get ready: %s\n",
567 ppa_strerror(ppa_context_errno(data->context)));
568 ppa_stream_unref(stream);
569 return NULL;
572 ppa_threaded_mainloop_wait(data->loop);
574 ppa_stream_set_state_callback(stream, NULL, NULL);
576 return stream;
579 static void probe_devices(ALboolean capture)
581 pa_threaded_mainloop *loop;
583 if(capture == AL_FALSE)
585 allDevNameMap = malloc(sizeof(DevMap) * 1);
586 allDevNameMap[0].name = strdup("PulseAudio Default");
587 allDevNameMap[0].device_name = NULL;
588 numDevNames = 1;
590 else
592 allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
593 allCaptureDevNameMap[0].name = strdup("PulseAudio Default");
594 allCaptureDevNameMap[0].device_name = NULL;
595 numCaptureDevNames = 1;
598 if((loop=ppa_threaded_mainloop_new()) &&
599 ppa_threaded_mainloop_start(loop) >= 0)
601 pa_context *context;
603 ppa_threaded_mainloop_lock(loop);
604 context = connect_context(loop);
605 if(context)
607 pa_operation *o;
609 if(capture == AL_FALSE)
610 o = ppa_context_get_sink_info_list(context, sink_device_callback, loop);
611 else
612 o = ppa_context_get_source_info_list(context, source_device_callback, loop);
613 while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
614 ppa_threaded_mainloop_wait(loop);
615 ppa_operation_unref(o);
617 ppa_context_disconnect(context);
618 ppa_context_unref(context);
620 ppa_threaded_mainloop_unlock(loop);
621 ppa_threaded_mainloop_stop(loop);
623 if(loop)
624 ppa_threaded_mainloop_free(loop);
628 static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
630 pulse_data *data = ppa_xmalloc(sizeof(pulse_data));
631 memset(data, 0, sizeof(*data));
633 if(!(data->loop = ppa_threaded_mainloop_new()))
635 AL_PRINT("pa_threaded_mainloop_new() failed!\n");
636 goto out;
638 if(ppa_threaded_mainloop_start(data->loop) < 0)
640 AL_PRINT("pa_threaded_mainloop_start() failed\n");
641 goto out;
644 ppa_threaded_mainloop_lock(data->loop);
645 device->ExtraData = data;
647 data->context = connect_context(data->loop);
648 if(!data->context)
650 ppa_threaded_mainloop_unlock(data->loop);
651 goto out;
653 ppa_context_set_state_callback(data->context, context_state_callback2, device);
655 device->szDeviceName = strdup(device_name);
657 ppa_threaded_mainloop_unlock(data->loop);
658 return ALC_TRUE;
660 out:
661 if(data->loop)
663 ppa_threaded_mainloop_stop(data->loop);
664 ppa_threaded_mainloop_free(data->loop);
667 device->ExtraData = NULL;
668 ppa_xfree(data);
669 return ALC_FALSE;
670 } //}}}
672 static void pulse_close(ALCdevice *device) //{{{
674 pulse_data *data = device->ExtraData;
676 ppa_threaded_mainloop_lock(data->loop);
678 if(data->stream)
680 ppa_stream_disconnect(data->stream);
681 ppa_stream_unref(data->stream);
684 ppa_context_disconnect(data->context);
685 ppa_context_unref(data->context);
687 ppa_threaded_mainloop_unlock(data->loop);
689 ppa_threaded_mainloop_stop(data->loop);
690 ppa_threaded_mainloop_free(data->loop);
692 DestroyRingBuffer(data->ring);
693 free(data->device_name);
695 device->ExtraData = NULL;
696 ppa_xfree(data);
697 } //}}}
698 //}}}
700 // OpenAL {{{
701 static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{
703 char *pulse_name = NULL;
704 pa_sample_spec spec;
705 pulse_data *data;
706 ALuint len;
708 if(!pulse_load())
709 return ALC_FALSE;
711 if(!device_name)
712 device_name = pulse_device;
713 else if(strcmp(device_name, pulse_device) != 0)
715 ALuint i;
717 if(!allDevNameMap)
718 probe_devices(AL_FALSE);
720 for(i = 0;i < numDevNames;i++)
722 if(strcmp(device_name, allDevNameMap[i].name) == 0)
724 pulse_name = allDevNameMap[i].device_name;
725 break;
728 if(i == numDevNames)
729 return ALC_FALSE;
732 if(pulse_open(device, device_name) == ALC_FALSE)
733 return ALC_FALSE;
735 data = device->ExtraData;
737 ppa_threaded_mainloop_lock(data->loop);
739 spec.format = PA_SAMPLE_S16NE;
740 spec.rate = 44100;
741 spec.channels = 2;
743 data->device_name = pulse_name;
744 pa_stream *stream = connect_playback_stream(device, 0, NULL, &spec, NULL);
745 if(!stream)
747 ppa_threaded_mainloop_unlock(data->loop);
748 goto fail;
751 if(ppa_stream_is_suspended(stream))
753 ppa_stream_disconnect(stream);
754 ppa_stream_unref(stream);
755 ppa_threaded_mainloop_unlock(data->loop);
756 goto fail;
758 data->device_name = strdup(ppa_stream_get_device_name(stream));
760 ppa_stream_disconnect(stream);
761 ppa_stream_unref(stream);
763 ppa_threaded_mainloop_unlock(data->loop);
765 len = GetConfigValueInt("pulse", "buffer-length", 2048);
766 if(len != 0)
768 device->UpdateSize = len;
769 device->NumUpdates = 1;
771 return ALC_TRUE;
773 fail:
774 pulse_close(device);
775 return ALC_FALSE;
776 } //}}}
778 static void pulse_close_playback(ALCdevice *device) //{{{
780 pulse_close(device);
781 } //}}}
783 static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
785 pulse_data *data = device->ExtraData;
786 pa_stream_flags_t flags = 0;
787 pa_channel_map chanmap;
789 ppa_threaded_mainloop_lock(data->loop);
791 if(!ConfigValueExists(NULL, "format"))
793 pa_operation *o;
794 o = ppa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
795 while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
796 ppa_threaded_mainloop_wait(data->loop);
797 ppa_operation_unref(o);
799 if(!ConfigValueExists(NULL, "frequency"))
800 flags |= PA_STREAM_FIX_RATE;
802 data->frame_size = aluFrameSizeFromFormat(device->Format);
803 data->attr.minreq = -1;
804 data->attr.prebuf = -1;
805 data->attr.fragsize = -1;
806 data->attr.tlength = device->UpdateSize * device->NumUpdates *
807 data->frame_size;
808 data->attr.maxlength = data->attr.tlength;
810 switch(aluBytesFromFormat(device->Format))
812 case 1:
813 data->spec.format = PA_SAMPLE_U8;
814 break;
815 case 2:
816 data->spec.format = PA_SAMPLE_S16NE;
817 break;
818 case 4:
819 data->spec.format = PA_SAMPLE_FLOAT32NE;
820 break;
821 default:
822 AL_PRINT("Unknown format: 0x%x\n", device->Format);
823 ppa_threaded_mainloop_unlock(data->loop);
824 return ALC_FALSE;
826 data->spec.rate = device->Frequency;
827 data->spec.channels = aluChannelsFromFormat(device->Format);
829 if(ppa_sample_spec_valid(&data->spec) == 0)
831 AL_PRINT("Invalid sample format\n");
832 ppa_threaded_mainloop_unlock(data->loop);
833 return ALC_FALSE;
836 if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
838 AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
839 ppa_threaded_mainloop_unlock(data->loop);
840 return ALC_FALSE;
842 SetDefaultWFXChannelOrder(device);
844 data->stream = connect_playback_stream(device, flags, &data->attr, &data->spec, &chanmap);
845 if(!data->stream)
847 ppa_threaded_mainloop_unlock(data->loop);
848 return ALC_FALSE;
851 ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
853 data->spec = *(ppa_stream_get_sample_spec(data->stream));
854 if(device->Frequency != data->spec.rate)
856 pa_operation *o;
858 /* Server updated our playback rate, so modify the buffer attribs
859 * accordingly. */
860 data->attr.tlength = (ALuint64)(data->attr.tlength/data->frame_size) *
861 data->spec.rate / device->Frequency * data->frame_size;
862 data->attr.maxlength = data->attr.tlength;
864 o = ppa_stream_set_buffer_attr(data->stream, &data->attr,
865 stream_success_callback, device);
866 while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
867 ppa_threaded_mainloop_wait(data->loop);
868 ppa_operation_unref(o);
870 device->Frequency = data->spec.rate;
873 stream_buffer_attr_callback(data->stream, device);
874 #if PA_CHECK_VERSION(0,9,15)
875 if(ppa_stream_set_buffer_attr_callback)
876 ppa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
877 #endif
878 ppa_stream_set_moved_callback(data->stream, stream_device_callback, device);
880 stream_write_callback(data->stream, data->attr.tlength, device);
881 ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
883 ppa_threaded_mainloop_unlock(data->loop);
884 return ALC_TRUE;
885 } //}}}
887 static void pulse_stop_playback(ALCdevice *device) //{{{
889 pulse_data *data = device->ExtraData;
891 if(!data->stream)
892 return;
894 ppa_threaded_mainloop_lock(data->loop);
896 #if PA_CHECK_VERSION(0,9,15)
897 if(ppa_stream_set_buffer_attr_callback)
898 ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
899 #endif
900 ppa_stream_set_moved_callback(data->stream, NULL, NULL);
901 ppa_stream_set_write_callback(data->stream, NULL, NULL);
902 ppa_stream_disconnect(data->stream);
903 ppa_stream_unref(data->stream);
904 data->stream = NULL;
906 ppa_threaded_mainloop_unlock(data->loop);
907 } //}}}
910 static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
912 char *pulse_name = NULL;
913 pulse_data *data;
914 pa_stream_flags_t flags = 0;
915 pa_stream_state_t state;
916 pa_channel_map chanmap;
918 if(!pulse_load())
919 return ALC_FALSE;
921 if(!allCaptureDevNameMap)
922 probe_devices(AL_TRUE);
924 if(!device_name)
925 device_name = allCaptureDevNameMap[0].name;
926 else
928 ALuint i;
930 for(i = 0;i < numCaptureDevNames;i++)
932 if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
934 pulse_name = allCaptureDevNameMap[i].device_name;
935 break;
938 if(i == numCaptureDevNames)
939 return ALC_FALSE;
942 if(pulse_open(device, device_name) == ALC_FALSE)
943 return ALC_FALSE;
945 data = device->ExtraData;
946 ppa_threaded_mainloop_lock(data->loop);
948 data->samples = device->UpdateSize * device->NumUpdates;
949 data->frame_size = aluFrameSizeFromFormat(device->Format);
951 if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
953 ppa_threaded_mainloop_unlock(data->loop);
954 goto fail;
957 data->attr.minreq = -1;
958 data->attr.prebuf = -1;
959 data->attr.maxlength = data->frame_size * data->samples;
960 data->attr.tlength = -1;
961 data->attr.fragsize = min(data->frame_size * data->samples,
962 10 * device->Frequency / 1000);
964 data->spec.rate = device->Frequency;
965 data->spec.channels = aluChannelsFromFormat(device->Format);
967 switch(aluBytesFromFormat(device->Format))
969 case 1:
970 data->spec.format = PA_SAMPLE_U8;
971 break;
972 case 2:
973 data->spec.format = PA_SAMPLE_S16NE;
974 break;
975 case 4:
976 data->spec.format = PA_SAMPLE_FLOAT32NE;
977 break;
978 default:
979 AL_PRINT("Unknown format: 0x%x\n", device->Format);
980 ppa_threaded_mainloop_unlock(data->loop);
981 goto fail;
984 if(ppa_sample_spec_valid(&data->spec) == 0)
986 AL_PRINT("Invalid sample format\n");
987 ppa_threaded_mainloop_unlock(data->loop);
988 goto fail;
991 if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
993 AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
994 ppa_threaded_mainloop_unlock(data->loop);
995 goto fail;
998 data->stream = ppa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap);
999 if(!data->stream)
1001 AL_PRINT("pa_stream_new() failed: %s\n",
1002 ppa_strerror(ppa_context_errno(data->context)));
1004 ppa_threaded_mainloop_unlock(data->loop);
1005 goto fail;
1008 ppa_stream_set_state_callback(data->stream, stream_state_callback, data->loop);
1010 flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
1011 if(ppa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0)
1013 AL_PRINT("Stream did not connect: %s\n",
1014 ppa_strerror(ppa_context_errno(data->context)));
1016 ppa_stream_unref(data->stream);
1017 data->stream = NULL;
1019 ppa_threaded_mainloop_unlock(data->loop);
1020 goto fail;
1023 while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
1025 if(!PA_STREAM_IS_GOOD(state))
1027 AL_PRINT("Stream did not get ready: %s\n",
1028 ppa_strerror(ppa_context_errno(data->context)));
1030 ppa_stream_unref(data->stream);
1031 data->stream = NULL;
1033 ppa_threaded_mainloop_unlock(data->loop);
1034 goto fail;
1037 ppa_threaded_mainloop_wait(data->loop);
1039 ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
1041 ppa_threaded_mainloop_unlock(data->loop);
1042 return ALC_TRUE;
1044 fail:
1045 pulse_close(device);
1046 return ALC_FALSE;
1047 } //}}}
1049 static void pulse_close_capture(ALCdevice *device) //{{{
1051 pulse_close(device);
1052 } //}}}
1054 static void pulse_start_capture(ALCdevice *device) //{{{
1056 pulse_data *data = device->ExtraData;
1057 pa_operation *o;
1059 ppa_threaded_mainloop_lock(data->loop);
1060 o = ppa_stream_cork(data->stream, 0, stream_success_callback, device);
1061 while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
1062 ppa_threaded_mainloop_wait(data->loop);
1063 ppa_operation_unref(o);
1064 ppa_threaded_mainloop_unlock(data->loop);
1065 } //}}}
1067 static void pulse_stop_capture(ALCdevice *device) //{{{
1069 pulse_data *data = device->ExtraData;
1070 pa_operation *o;
1072 ppa_threaded_mainloop_lock(data->loop);
1073 o = ppa_stream_cork(data->stream, 1, stream_success_callback, device);
1074 while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
1075 ppa_threaded_mainloop_wait(data->loop);
1076 ppa_operation_unref(o);
1077 ppa_threaded_mainloop_unlock(data->loop);
1078 } //}}}
1080 static ALCuint pulse_available_samples(ALCdevice *device) //{{{
1082 pulse_data *data = device->ExtraData;
1083 size_t samples;
1085 ppa_threaded_mainloop_lock(data->loop);
1086 /* Capture is done in fragment-sized chunks, so we loop until we get all
1087 * that's available */
1088 samples = (device->Connected ? ppa_stream_readable_size(data->stream) : 0);
1089 while(samples > 0)
1091 const void *buf;
1092 size_t length;
1094 if(ppa_stream_peek(data->stream, &buf, &length) < 0)
1096 AL_PRINT("pa_stream_peek() failed: %s\n",
1097 ppa_strerror(ppa_context_errno(data->context)));
1098 break;
1101 WriteRingBuffer(data->ring, buf, length/data->frame_size);
1102 samples -= length;
1104 ppa_stream_drop(data->stream);
1106 ppa_threaded_mainloop_unlock(data->loop);
1108 return RingBufferSize(data->ring);
1109 } //}}}
1111 static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
1113 pulse_data *data = device->ExtraData;
1115 if(pulse_available_samples(device) >= samples)
1116 ReadRingBuffer(data->ring, buffer, samples);
1117 else
1118 alcSetError(device, ALC_INVALID_VALUE);
1119 } //}}}
1121 BackendFuncs pulse_funcs = { //{{{
1122 pulse_open_playback,
1123 pulse_close_playback,
1124 pulse_reset_playback,
1125 pulse_stop_playback,
1126 pulse_open_capture,
1127 pulse_close_capture,
1128 pulse_start_capture,
1129 pulse_stop_capture,
1130 pulse_capture_samples,
1131 pulse_available_samples
1132 }; //}}}
1134 void alc_pulse_init(BackendFuncs *func_list) //{{{
1136 *func_list = pulse_funcs;
1138 pulse_ctx_flags = 0;
1139 if(!GetConfigValueBool("pulse", "spawn-server", 0))
1140 pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
1141 } //}}}
1143 void alc_pulse_deinit(void) //{{{
1145 ALuint i;
1147 for(i = 0;i < numDevNames;++i)
1149 free(allDevNameMap[i].name);
1150 free(allDevNameMap[i].device_name);
1152 free(allDevNameMap);
1153 allDevNameMap = NULL;
1154 numDevNames = 0;
1156 for(i = 0;i < numCaptureDevNames;++i)
1158 free(allCaptureDevNameMap[i].name);
1159 free(allCaptureDevNameMap[i].device_name);
1161 free(allCaptureDevNameMap);
1162 allCaptureDevNameMap = NULL;
1163 numCaptureDevNames = 0;
1165 if(pa_handle)
1167 #ifdef _WIN32
1168 FreeLibrary(pa_handle);
1169 #elif defined (HAVE_DLFCN_H)
1170 dlclose(pa_handle);
1171 #endif
1172 pa_handle = NULL;
1174 } //}}}
1176 void alc_pulse_probe(int type) //{{{
1178 if(!pulse_load()) return;
1180 if(type == DEVICE_PROBE)
1181 AppendDeviceList(pulse_device);
1182 else if(type == ALL_DEVICE_PROBE)
1184 ALuint i;
1186 for(i = 0;i < numDevNames;++i)
1188 free(allDevNameMap[i].name);
1189 free(allDevNameMap[i].device_name);
1191 free(allDevNameMap);
1192 allDevNameMap = NULL;
1193 numDevNames = 0;
1195 probe_devices(AL_FALSE);
1197 for(i = 0;i < numDevNames;i++)
1198 AppendAllDeviceList(allDevNameMap[i].name);
1200 else if(type == CAPTURE_DEVICE_PROBE)
1202 ALuint i;
1204 for(i = 0;i < numCaptureDevNames;++i)
1206 free(allCaptureDevNameMap[i].name);
1207 free(allCaptureDevNameMap[i].device_name);
1209 free(allCaptureDevNameMap);
1210 allCaptureDevNameMap = NULL;
1211 numCaptureDevNames = 0;
1213 probe_devices(AL_TRUE);
1215 for(i = 0;i < numCaptureDevNames;i++)
1216 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1218 } //}}}
1219 //}}}