zenilib: zenilib/jni/external/openal-soft/Alc/backends/pulseaudio.c Source File

zenilib 0.5.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
pulseaudio.c
Go to the documentation of this file.
1
22 #include "config.h"
23
24 #include <string.h>
25
26 #include "alMain.h"
27 #include "alu.h"
28
29 #include <pulse/pulseaudio.h>
30
31 #if PA_API_VERSION == 12
32
33 #ifndef PA_CHECK_VERSION
34 #define PA_CHECK_VERSION(major,minor,micro) \
35 ((PA_MAJOR > (major)) || \
36 (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
37 (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
38 #endif
39
40 #ifdef HAVE_DYNLOAD
41 static void *pa_handle;
42 #define MAKE_FUNC(x) static typeof(x) * p##x
43 MAKE_FUNC(pa_context_unref);
44 MAKE_FUNC(pa_sample_spec_valid);
45 MAKE_FUNC(pa_frame_size);
46 MAKE_FUNC(pa_stream_drop);
47 MAKE_FUNC(pa_strerror);
48 MAKE_FUNC(pa_context_get_state);
49 MAKE_FUNC(pa_stream_get_state);
50 MAKE_FUNC(pa_threaded_mainloop_signal);
51 MAKE_FUNC(pa_stream_peek);
52 MAKE_FUNC(pa_threaded_mainloop_wait);
53 MAKE_FUNC(pa_threaded_mainloop_unlock);
54 MAKE_FUNC(pa_threaded_mainloop_in_thread);
55 MAKE_FUNC(pa_context_new);
56 MAKE_FUNC(pa_threaded_mainloop_stop);
57 MAKE_FUNC(pa_context_disconnect);
58 MAKE_FUNC(pa_threaded_mainloop_start);
59 MAKE_FUNC(pa_threaded_mainloop_get_api);
60 MAKE_FUNC(pa_context_set_state_callback);
61 MAKE_FUNC(pa_stream_write);
62 MAKE_FUNC(pa_xfree);
63 MAKE_FUNC(pa_stream_connect_record);
64 MAKE_FUNC(pa_stream_connect_playback);
65 MAKE_FUNC(pa_stream_readable_size);
66 MAKE_FUNC(pa_stream_writable_size);
67 MAKE_FUNC(pa_stream_is_corked);
68 MAKE_FUNC(pa_stream_cork);
69 MAKE_FUNC(pa_stream_is_suspended);
70 MAKE_FUNC(pa_stream_get_device_name);
71 MAKE_FUNC(pa_stream_get_latency);
72 MAKE_FUNC(pa_path_get_filename);
73 MAKE_FUNC(pa_get_binary_name);
74 MAKE_FUNC(pa_threaded_mainloop_free);
75 MAKE_FUNC(pa_context_errno);
76 MAKE_FUNC(pa_xmalloc);
77 MAKE_FUNC(pa_stream_unref);
78 MAKE_FUNC(pa_threaded_mainloop_accept);
79 MAKE_FUNC(pa_stream_set_write_callback);
80 MAKE_FUNC(pa_threaded_mainloop_new);
81 MAKE_FUNC(pa_context_connect);
82 MAKE_FUNC(pa_stream_set_buffer_attr);
83 MAKE_FUNC(pa_stream_get_buffer_attr);
84 MAKE_FUNC(pa_stream_get_sample_spec);
85 MAKE_FUNC(pa_stream_get_time);
86 MAKE_FUNC(pa_stream_set_read_callback);
87 MAKE_FUNC(pa_stream_set_state_callback);
88 MAKE_FUNC(pa_stream_set_moved_callback);
89 MAKE_FUNC(pa_stream_set_underflow_callback);
90 MAKE_FUNC(pa_stream_new_with_proplist);
91 MAKE_FUNC(pa_stream_disconnect);
92 MAKE_FUNC(pa_threaded_mainloop_lock);
93 MAKE_FUNC(pa_channel_map_init_auto);
94 MAKE_FUNC(pa_channel_map_parse);
95 MAKE_FUNC(pa_channel_map_snprint);
96 MAKE_FUNC(pa_channel_map_equal);
97 MAKE_FUNC(pa_context_get_server_info);
98 MAKE_FUNC(pa_context_get_sink_info_by_name);
99 MAKE_FUNC(pa_context_get_sink_info_list);
100 MAKE_FUNC(pa_context_get_source_info_by_name);
101 MAKE_FUNC(pa_context_get_source_info_list);
102 MAKE_FUNC(pa_operation_get_state);
103 MAKE_FUNC(pa_operation_unref);
104 MAKE_FUNC(pa_proplist_new);
105 MAKE_FUNC(pa_proplist_free);
106 MAKE_FUNC(pa_proplist_set);
107 #if PA_CHECK_VERSION(0,9,15)
108 MAKE_FUNC(pa_channel_map_superset);
109 MAKE_FUNC(pa_stream_set_buffer_attr_callback);
110 #endif
111 #if PA_CHECK_VERSION(0,9,16)
112 MAKE_FUNC(pa_stream_begin_write);
113 #endif
114 #undef MAKE_FUNC
115
116 #define pa_context_unref ppa_context_unref
117 #define pa_sample_spec_valid ppa_sample_spec_valid
118 #define pa_frame_size ppa_frame_size
119 #define pa_stream_drop ppa_stream_drop
120 #define pa_strerror ppa_strerror
121 #define pa_context_get_state ppa_context_get_state
122 #define pa_stream_get_state ppa_stream_get_state
123 #define pa_threaded_mainloop_signal ppa_threaded_mainloop_signal
124 #define pa_stream_peek ppa_stream_peek
125 #define pa_threaded_mainloop_wait ppa_threaded_mainloop_wait
126 #define pa_threaded_mainloop_unlock ppa_threaded_mainloop_unlock
127 #define pa_threaded_mainloop_in_thread ppa_threaded_mainloop_in_thread
128 #define pa_context_new ppa_context_new
129 #define pa_threaded_mainloop_stop ppa_threaded_mainloop_stop
130 #define pa_context_disconnect ppa_context_disconnect
131 #define pa_threaded_mainloop_start ppa_threaded_mainloop_start
132 #define pa_threaded_mainloop_get_api ppa_threaded_mainloop_get_api
133 #define pa_context_set_state_callback ppa_context_set_state_callback
134 #define pa_stream_write ppa_stream_write
135 #define pa_xfree ppa_xfree
136 #define pa_stream_connect_record ppa_stream_connect_record
137 #define pa_stream_connect_playback ppa_stream_connect_playback
138 #define pa_stream_readable_size ppa_stream_readable_size
139 #define pa_stream_writable_size ppa_stream_writable_size
140 #define pa_stream_is_corked ppa_stream_is_corked
141 #define pa_stream_cork ppa_stream_cork
142 #define pa_stream_is_suspended ppa_stream_is_suspended
143 #define pa_stream_get_device_name ppa_stream_get_device_name
144 #define pa_stream_get_latency ppa_stream_get_latency
145 #define pa_path_get_filename ppa_path_get_filename
146 #define pa_get_binary_name ppa_get_binary_name
147 #define pa_threaded_mainloop_free ppa_threaded_mainloop_free
148 #define pa_context_errno ppa_context_errno
149 #define pa_xmalloc ppa_xmalloc
150 #define pa_stream_unref ppa_stream_unref
151 #define pa_threaded_mainloop_accept ppa_threaded_mainloop_accept
152 #define pa_stream_set_write_callback ppa_stream_set_write_callback
153 #define pa_threaded_mainloop_new ppa_threaded_mainloop_new
154 #define pa_context_connect ppa_context_connect
155 #define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr
156 #define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr
157 #define pa_stream_get_sample_spec ppa_stream_get_sample_spec
158 #define pa_stream_get_time ppa_stream_get_time
159 #define pa_stream_set_read_callback ppa_stream_set_read_callback
160 #define pa_stream_set_state_callback ppa_stream_set_state_callback
161 #define pa_stream_set_moved_callback ppa_stream_set_moved_callback
162 #define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback
163 #define pa_stream_new_with_proplist ppa_stream_new_with_proplist
164 #define pa_stream_disconnect ppa_stream_disconnect
165 #define pa_threaded_mainloop_lock ppa_threaded_mainloop_lock
166 #define pa_channel_map_init_auto ppa_channel_map_init_auto
167 #define pa_channel_map_parse ppa_channel_map_parse
168 #define pa_channel_map_snprint ppa_channel_map_snprint
169 #define pa_channel_map_equal ppa_channel_map_equal
170 #define pa_context_get_server_info ppa_context_get_server_info
171 #define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name
172 #define pa_context_get_sink_info_list ppa_context_get_sink_info_list
173 #define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name
174 #define pa_context_get_source_info_list ppa_context_get_source_info_list
175 #define pa_operation_get_state ppa_operation_get_state
176 #define pa_operation_unref ppa_operation_unref
177 #define pa_proplist_new ppa_proplist_new
178 #define pa_proplist_free ppa_proplist_free
179 #define pa_proplist_set ppa_proplist_set
180 #if PA_CHECK_VERSION(0,9,15)
181 #define pa_channel_map_superset ppa_channel_map_superset
182 #define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback
183 #endif
184 #if PA_CHECK_VERSION(0,9,16)
185 #define pa_stream_begin_write ppa_stream_begin_write
186 #endif
187
188 #endif
189
190 #ifndef PATH_MAX
191 #define PATH_MAX 4096
192 #endif
193
194 typedef struct {
195 char *device_name;
196
197 const void *cap_store;
198 size_t cap_len;
199 size_t cap_remain;
200
201 ALCuint last_readable;
202
203 pa_buffer_attr attr;
204 pa_sample_spec spec;
205
206 pa_threaded_mainloop *loop;
207
208 ALvoid *thread;
209 volatile ALboolean killNow;
210
211 pa_stream *stream;
212 pa_context *context;
213 } pulse_data;
214
215 typedef struct {
216 char *name;
217 char *device_name;
218 } DevMap;
219
220
221 static DevMap *allDevNameMap;
222 static ALuint numDevNames;
223 static DevMap *allCaptureDevNameMap;
224 static ALuint numCaptureDevNames;
225 static pa_context_flags_t pulse_ctx_flags;
226 static pa_proplist *prop_filter;
227
228
229 static ALCboolean pulse_load(void)
230 {
231 ALCboolean ret = ALC_TRUE;
232 #ifdef HAVE_DYNLOAD
233 if(!pa_handle)
234 {
235 #ifdef _WIN32
236 #define PALIB "libpulse-0.dll"
237 #elif defined(__APPLE__) && defined(__MACH__)
238 #define PALIB "libpulse.0.dylib"
239 #else
240 #define PALIB "libpulse.so.0"
241 #endif
242 pa_handle = LoadLib(PALIB);
243 if(!pa_handle)
244 return ALC_FALSE;
245
246 #define LOAD_FUNC(x) do { \
247 p##x = GetSymbol(pa_handle, #x); \
248 if(!(p##x)) { \
249 ret = ALC_FALSE; \
250 } \
251 } while(0)
252 LOAD_FUNC(pa_context_unref);
253 LOAD_FUNC(pa_sample_spec_valid);
254 LOAD_FUNC(pa_stream_drop);
255 LOAD_FUNC(pa_frame_size);
256 LOAD_FUNC(pa_strerror);
257 LOAD_FUNC(pa_context_get_state);
258 LOAD_FUNC(pa_stream_get_state);
259 LOAD_FUNC(pa_threaded_mainloop_signal);
260 LOAD_FUNC(pa_stream_peek);
261 LOAD_FUNC(pa_threaded_mainloop_wait);
262 LOAD_FUNC(pa_threaded_mainloop_unlock);
263 LOAD_FUNC(pa_threaded_mainloop_in_thread);
264 LOAD_FUNC(pa_context_new);
265 LOAD_FUNC(pa_threaded_mainloop_stop);
266 LOAD_FUNC(pa_context_disconnect);
267 LOAD_FUNC(pa_threaded_mainloop_start);
268 LOAD_FUNC(pa_threaded_mainloop_get_api);
269 LOAD_FUNC(pa_context_set_state_callback);
270 LOAD_FUNC(pa_stream_write);
271 LOAD_FUNC(pa_xfree);
272 LOAD_FUNC(pa_stream_connect_record);
273 LOAD_FUNC(pa_stream_connect_playback);
274 LOAD_FUNC(pa_stream_readable_size);
275 LOAD_FUNC(pa_stream_writable_size);
276 LOAD_FUNC(pa_stream_is_corked);
277 LOAD_FUNC(pa_stream_cork);
278 LOAD_FUNC(pa_stream_is_suspended);
279 LOAD_FUNC(pa_stream_get_device_name);
280 LOAD_FUNC(pa_stream_get_latency);
281 LOAD_FUNC(pa_path_get_filename);
282 LOAD_FUNC(pa_get_binary_name);
283 LOAD_FUNC(pa_threaded_mainloop_free);
284 LOAD_FUNC(pa_context_errno);
285 LOAD_FUNC(pa_xmalloc);
286 LOAD_FUNC(pa_stream_unref);
287 LOAD_FUNC(pa_threaded_mainloop_accept);
288 LOAD_FUNC(pa_stream_set_write_callback);
289 LOAD_FUNC(pa_threaded_mainloop_new);
290 LOAD_FUNC(pa_context_connect);
291 LOAD_FUNC(pa_stream_set_buffer_attr);
292 LOAD_FUNC(pa_stream_get_buffer_attr);
293 LOAD_FUNC(pa_stream_get_sample_spec);
294 LOAD_FUNC(pa_stream_get_time);
295 LOAD_FUNC(pa_stream_set_read_callback);
296 LOAD_FUNC(pa_stream_set_state_callback);
297 LOAD_FUNC(pa_stream_set_moved_callback);
298 LOAD_FUNC(pa_stream_set_underflow_callback);
299 LOAD_FUNC(pa_stream_new_with_proplist);
300 LOAD_FUNC(pa_stream_disconnect);
301 LOAD_FUNC(pa_threaded_mainloop_lock);
302 LOAD_FUNC(pa_channel_map_init_auto);
303 LOAD_FUNC(pa_channel_map_parse);
304 LOAD_FUNC(pa_channel_map_snprint);
305 LOAD_FUNC(pa_channel_map_equal);
306 LOAD_FUNC(pa_context_get_server_info);
307 LOAD_FUNC(pa_context_get_sink_info_by_name);
308 LOAD_FUNC(pa_context_get_sink_info_list);
309 LOAD_FUNC(pa_context_get_source_info_by_name);
310 LOAD_FUNC(pa_context_get_source_info_list);
311 LOAD_FUNC(pa_operation_get_state);
312 LOAD_FUNC(pa_operation_unref);
313 LOAD_FUNC(pa_proplist_new);
314 LOAD_FUNC(pa_proplist_free);
315 LOAD_FUNC(pa_proplist_set);
316 #undef LOAD_FUNC
317 #define LOAD_OPTIONAL_FUNC(x) do { \
318 p##x = GetSymbol(pa_handle, #x); \
319 } while(0)
320 #if PA_CHECK_VERSION(0,9,15)
321 LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
322 LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
323 #endif
324 #if PA_CHECK_VERSION(0,9,16)
325 LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
326 #endif
327 #undef LOAD_OPTIONAL_FUNC
328
329 if(ret == ALC_FALSE)
330 {
331 CloseLib(pa_handle);
332 pa_handle = NULL;
333 }
334 }
335 #endif /* HAVE_DYNLOAD */
336 return ret;
337 }
338
339 /* PulseAudio Event Callbacks */
340 static void context_state_callback(pa_context *context, void *pdata)
341 {
342 pa_threaded_mainloop *loop = pdata;
343 pa_context_state_t state;
344
345 state = pa_context_get_state(context);
346 if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
347 pa_threaded_mainloop_signal(loop, 0);
348 }
349
350 static void stream_state_callback(pa_stream *stream, void *pdata)
351 {
352 pa_threaded_mainloop *loop = pdata;
353 pa_stream_state_t state;
354
355 state = pa_stream_get_state(stream);
356 if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
357 pa_threaded_mainloop_signal(loop, 0);
358 }
359
360 static void stream_buffer_attr_callback(pa_stream *stream, void *pdata)
361 {
362 ALCdevice *device = pdata;
363 pulse_data *data = device->ExtraData;
364
365 data->attr = *pa_stream_get_buffer_attr(stream);
366 TRACE("minreq=%d, tlength=%d, prebuf=%d\n", data->attr.minreq, data->attr.tlength, data->attr.prebuf);
367 }
368
369 static void context_state_callback2(pa_context *context, void *pdata)
370 {
371 ALCdevice *Device = pdata;
372 pulse_data *data = Device->ExtraData;
373
374 if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
375 {
376 ERR("Received context failure!\n");
377 aluHandleDisconnect(Device);
378 }
379 pa_threaded_mainloop_signal(data->loop, 0);
380 }
381
382 static void stream_state_callback2(pa_stream *stream, void *pdata)
383 {
384 ALCdevice *Device = pdata;
385 pulse_data *data = Device->ExtraData;
386
387 if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
388 {
389 ERR("Received stream failure!\n");
390 aluHandleDisconnect(Device);
391 }
392 pa_threaded_mainloop_signal(data->loop, 0);
393 }
394
395 static void stream_success_callback(pa_stream *stream, int success, void *pdata)
396 {
397 ALCdevice *Device = pdata;
398 pulse_data *data = Device->ExtraData;
399 (void)stream;
400 (void)success;
401
402 pa_threaded_mainloop_signal(data->loop, 0);
403 }
404
405 static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
406 {
407 ALCdevice *device = pdata;
408 pulse_data *data = device->ExtraData;
409 char chanmap_str[256] = "";
410 const struct {
411 const char *str;
412 enum DevFmtChannels chans;
413 } chanmaps[] = {
414 { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
415 DevFmtX71 },
416 { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
417 DevFmtX61 },
418 { "front-left,front-right,front-center,lfe,rear-left,rear-right",
419 DevFmtX51 },
420 { "front-left,front-right,front-center,lfe,side-left,side-right",
421 DevFmtX51Side },
422 { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
423 { "front-left,front-right", DevFmtStereo },
424 { "mono", DevFmtMono },
425 { NULL, 0 }
426 };
427 int i;
428 (void)context;
429
430 if(eol)
431 {
432 pa_threaded_mainloop_signal(data->loop, 0);
433 return;
434 }
435
436 for(i = 0;chanmaps[i].str;i++)
437 {
438 pa_channel_map map;
439 if(!pa_channel_map_parse(&map, chanmaps[i].str))
440 continue;
441
442 if(pa_channel_map_equal(&info->channel_map, &map)
443 #if PA_CHECK_VERSION(0,9,15)
444 || (pa_channel_map_superset &&
445 pa_channel_map_superset(&info->channel_map, &map))
446 #endif
447 )
448 {
449 device->FmtChans = chanmaps[i].chans;
450 return;
451 }
452 }
453
454 pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
455 ERR("Failed to find format for channel map:\n %s\n", chanmap_str);
456 }
457
458 static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
459 {
460 pa_threaded_mainloop *loop = pdata;
461 void *temp;
462 ALuint i;
463
464 (void)context;
465
466 if(eol)
467 {
468 pa_threaded_mainloop_signal(loop, 0);
469 return;
470 }
471
472 for(i = 0;i < numDevNames;i++)
473 {
474 if(strcmp(info->name, allDevNameMap[i].device_name) == 0)
475 return;
476 }
477
478 TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
479
480 temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
481 if(temp)
482 {
483 allDevNameMap = temp;
484 allDevNameMap[numDevNames].name = strdup(info->description);
485 allDevNameMap[numDevNames].device_name = strdup(info->name);
486 numDevNames++;
487 }
488 }
489
490 static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata)
491 {
492 pa_threaded_mainloop *loop = pdata;
493 void *temp;
494 ALuint i;
495
496 (void)context;
497
498 if(eol)
499 {
500 pa_threaded_mainloop_signal(loop, 0);
501 return;
502 }
503
504 for(i = 0;i < numCaptureDevNames;i++)
505 {
506 if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0)
507 return;
508 }
509
510 TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
511
512 temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
513 if(temp)
514 {
515 allCaptureDevNameMap = temp;
516 allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description);
517 allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
518 numCaptureDevNames++;
519 }
520 }
521
522 static void sink_name_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
523 {
524 ALCdevice *device = pdata;
525 pulse_data *data = device->ExtraData;
526 (void)context;
527
528 if(eol)
529 {
530 pa_threaded_mainloop_signal(data->loop, 0);
531 return;
532 }
533
534 free(device->DeviceName);
535 device->DeviceName = strdup(info->description);
536 }
537
538 static void source_name_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata)
539 {
540 ALCdevice *device = pdata;
541 pulse_data *data = device->ExtraData;
542 (void)context;
543
544 if(eol)
545 {
546 pa_threaded_mainloop_signal(data->loop, 0);
547 return;
548 }
549
550 free(device->DeviceName);
551 device->DeviceName = strdup(info->description);
552 }
553
554
555 static void stream_moved_callback(pa_stream *stream, void *pdata)
556 {
557 ALCdevice *device = pdata;
558 pulse_data *data = device->ExtraData;
559 (void)stream;
560
561 free(data->device_name);
562 data->device_name = strdup(pa_stream_get_device_name(data->stream));
563
564 TRACE("Stream moved to %s\n", data->device_name);
565 }
566
567
568 static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
569 {
570 const char *name = "OpenAL Soft";
571 char path_name[PATH_MAX];
572 pa_context_state_t state;
573 pa_context *context;
574 int err;
575
576 if(pa_get_binary_name(path_name, sizeof(path_name)))
577 name = pa_path_get_filename(path_name);
578
579 context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
580 if(!context)
581 {
582 ERR("pa_context_new() failed\n");
583 return NULL;
584 }
585
586 pa_context_set_state_callback(context, context_state_callback, loop);
587
588 if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
589 {
590 while((state=pa_context_get_state(context)) != PA_CONTEXT_READY)
591 {
592 if(!PA_CONTEXT_IS_GOOD(state))
593 {
594 err = pa_context_errno(context);
595 if(err > 0) err = -err;
596 break;
597 }
598
599 pa_threaded_mainloop_wait(loop);
600 }
601 }
602 pa_context_set_state_callback(context, NULL, NULL);
603
604 if(err < 0)
605 {
606 if(!silent)
607 ERR("Context did not connect: %s\n", pa_strerror(err));
608 pa_context_unref(context);
609 return NULL;
610 }
611
612 return context;
613 }
614
615 static pa_stream *connect_playback_stream(const char *device_name,
616 pa_threaded_mainloop *loop, pa_context *context,
617 pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
618 pa_channel_map *chanmap)
619 {
620 pa_stream_state_t state;
621 pa_stream *stream;
622
623 stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter);
624 if(!stream)
625 {
626 ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
627 return NULL;
628 }
629
630 pa_stream_set_state_callback(stream, stream_state_callback, loop);
631
632 if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0)
633 {
634 ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
635 pa_stream_unref(stream);
636 return NULL;
637 }
638
639 while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
640 {
641 if(!PA_STREAM_IS_GOOD(state))
642 {
643 ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
644 pa_stream_unref(stream);
645 return NULL;
646 }
647
648 pa_threaded_mainloop_wait(loop);
649 }
650 pa_stream_set_state_callback(stream, NULL, NULL);
651
652 return stream;
653 }
654
655 static pa_stream *connect_record_stream(const char *device_name,
656 pa_threaded_mainloop *loop, pa_context *context,
657 pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
658 pa_channel_map *chanmap)
659 {
660 pa_stream_state_t state;
661 pa_stream *stream;
662
663 stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter);
664 if(!stream)
665 {
666 ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
667 return NULL;
668 }
669
670 pa_stream_set_state_callback(stream, stream_state_callback, loop);
671
672 if(pa_stream_connect_record(stream, device_name, attr, flags) < 0)
673 {
674 ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
675 pa_stream_unref(stream);
676 return NULL;
677 }
678
679 while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
680 {
681 if(!PA_STREAM_IS_GOOD(state))
682 {
683 ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
684 pa_stream_unref(stream);
685 return NULL;
686 }
687
688 pa_threaded_mainloop_wait(loop);
689 }
690 pa_stream_set_state_callback(stream, NULL, NULL);
691
692 return stream;
693 }
694
695
696 static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop)
697 {
698 if(op)
699 {
700 while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
701 pa_threaded_mainloop_wait(loop);
702 pa_operation_unref(op);
703 }
704 }
705
706
707 static void probe_devices(ALboolean capture)
708 {
709 pa_threaded_mainloop *loop;
710
711 if(capture == AL_FALSE)
712 allDevNameMap = malloc(sizeof(DevMap) * 1);
713 else
714 allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
715
716 if((loop=pa_threaded_mainloop_new()) &&
717 pa_threaded_mainloop_start(loop) >= 0)
718 {
719 pa_context *context;
720
721 pa_threaded_mainloop_lock(loop);
722 context = connect_context(loop, AL_FALSE);
723 if(context)
724 {
725 pa_operation *o;
726
727 if(capture == AL_FALSE)
728 {
729 pa_stream_flags_t flags;
730 pa_sample_spec spec;
731 pa_stream *stream;
732
733 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
734 PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
735
736 spec.format = PA_SAMPLE_S16NE;
737 spec.rate = 44100;
738 spec.channels = 2;
739
740 stream = connect_playback_stream(NULL, loop, context, flags,
741 NULL, &spec, NULL);
742 if(stream)
743 {
744 o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop);
745 wait_for_operation(o, loop);
746
747 pa_stream_disconnect(stream);
748 pa_stream_unref(stream);
749 stream = NULL;
750 }
751
752 o = pa_context_get_sink_info_list(context, sink_device_callback, loop);
753 }
754 else
755 {
756 pa_stream_flags_t flags;
757 pa_sample_spec spec;
758 pa_stream *stream;
759
760 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
761 PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
762
763 spec.format = PA_SAMPLE_S16NE;
764 spec.rate = 44100;
765 spec.channels = 1;
766
767 stream = connect_record_stream(NULL, loop, context, flags,
768 NULL, &spec, NULL);
769 if(stream)
770 {
771 o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop);
772 wait_for_operation(o, loop);
773
774 pa_stream_disconnect(stream);
775 pa_stream_unref(stream);
776 stream = NULL;
777 }
778
779 o = pa_context_get_source_info_list(context, source_device_callback, loop);
780 }
781 wait_for_operation(o, loop);
782
783 pa_context_disconnect(context);
784 pa_context_unref(context);
785 }
786 pa_threaded_mainloop_unlock(loop);
787 pa_threaded_mainloop_stop(loop);
788 }
789 if(loop)
790 pa_threaded_mainloop_free(loop);
791 }
792
793
794 static ALuint PulseProc(ALvoid *param)
795 {
796 ALCdevice *Device = param;
797 pulse_data *data = Device->ExtraData;
798 ALuint buffer_size;
799 ALint update_size;
800 size_t frame_size;
801 ssize_t len;
802
803 SetRTPriority();
804
805 pa_threaded_mainloop_lock(data->loop);
806 frame_size = pa_frame_size(&data->spec);
807 update_size = Device->UpdateSize * frame_size;
808
809 /* Sanitize buffer metrics, in case we actually have less than what we
810 * asked for. */
811 buffer_size = minu(update_size*Device->NumUpdates, data->attr.tlength);
812 update_size = minu(update_size, buffer_size/2);
813 do {
814 len = pa_stream_writable_size(data->stream) - data->attr.tlength +
815 buffer_size;
816 if(len < update_size)
817 {
818 if(pa_stream_is_corked(data->stream) == 1)
819 {
820 pa_operation *o;
821 o = pa_stream_cork(data->stream, 0, NULL, NULL);
822 if(o) pa_operation_unref(o);
823 }
824 pa_threaded_mainloop_unlock(data->loop);
825 Sleep(1);
826 pa_threaded_mainloop_lock(data->loop);
827 continue;
828 }
829 len -= len%update_size;
830
831 while(len > 0)
832 {
833 size_t newlen = len;
834 void *buf;
835 pa_free_cb_t free_func = NULL;
836
837 #if PA_CHECK_VERSION(0,9,16)
838 if(!pa_stream_begin_write ||
839 pa_stream_begin_write(data->stream, &buf, &newlen) < 0)
840 #endif
841 {
842 buf = pa_xmalloc(newlen);
843 free_func = pa_xfree;
844 }
845
846 aluMixData(Device, buf, newlen/frame_size);
847
848 pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
849 len -= newlen;
850 }
851 } while(!data->killNow && Device->Connected);
852 pa_threaded_mainloop_unlock(data->loop);
853
854 return 0;
855 }
856
857
858 static ALCboolean pulse_open(ALCdevice *device)
859 {
860 pulse_data *data = pa_xmalloc(sizeof(pulse_data));
861 memset(data, 0, sizeof(*data));
862
863 if(!(data->loop = pa_threaded_mainloop_new()))
864 {
865 ERR("pa_threaded_mainloop_new() failed!\n");
866 goto out;
867 }
868 if(pa_threaded_mainloop_start(data->loop) < 0)
869 {
870 ERR("pa_threaded_mainloop_start() failed\n");
871 goto out;
872 }
873
874 pa_threaded_mainloop_lock(data->loop);
875 device->ExtraData = data;
876
877 data->context = connect_context(data->loop, AL_FALSE);
878 if(!data->context)
879 {
880 pa_threaded_mainloop_unlock(data->loop);
881 goto out;
882 }
883 pa_context_set_state_callback(data->context, context_state_callback2, device);
884
885 pa_threaded_mainloop_unlock(data->loop);
886 return ALC_TRUE;
887
888 out:
889 if(data->loop)
890 {
891 pa_threaded_mainloop_stop(data->loop);
892 pa_threaded_mainloop_free(data->loop);
893 }
894
895 device->ExtraData = NULL;
896 pa_xfree(data);
897 return ALC_FALSE;
898 }
899
900 static void pulse_close(ALCdevice *device)
901 {
902 pulse_data *data = device->ExtraData;
903
904 pa_threaded_mainloop_lock(data->loop);
905
906 if(data->stream)
907 {
908 pa_stream_set_moved_callback(data->stream, NULL, NULL);
909 #if PA_CHECK_VERSION(0,9,15)
910 if(pa_stream_set_buffer_attr_callback)
911 pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
912 #endif
913 pa_stream_disconnect(data->stream);
914 pa_stream_unref(data->stream);
915 }
916
917 pa_context_disconnect(data->context);
918 pa_context_unref(data->context);
919
920 pa_threaded_mainloop_unlock(data->loop);
921
922 pa_threaded_mainloop_stop(data->loop);
923 pa_threaded_mainloop_free(data->loop);
924
925 free(data->device_name);
926
927 device->ExtraData = NULL;
928 pa_xfree(data);
929 }
930
931 /* OpenAL */
932 static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name)
933 {
934 const char *pulse_name = NULL;
935 pa_stream_flags_t flags;
936 pa_sample_spec spec;
937 pulse_data *data;
938 pa_operation *o;
939
940 if(device_name)
941 {
942 ALuint i;
943
944 if(!allDevNameMap)
945 probe_devices(AL_FALSE);
946
947 for(i = 0;i < numDevNames;i++)
948 {
949 if(strcmp(device_name, allDevNameMap[i].name) == 0)
950 {
951 pulse_name = allDevNameMap[i].device_name;
952 break;
953 }
954 }
955 if(i == numDevNames)
956 return ALC_INVALID_VALUE;
957 }
958
959 if(pulse_open(device) == ALC_FALSE)
960 return ALC_INVALID_VALUE;
961
962 data = device->ExtraData;
963 pa_threaded_mainloop_lock(data->loop);
964
965 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
966 PA_STREAM_FIX_CHANNELS;
967 if(!GetConfigValueBool("pulse", "allow-moves", 0))
968 flags |= PA_STREAM_DONT_MOVE;
969
970 spec.format = PA_SAMPLE_S16NE;
971 spec.rate = 44100;
972 spec.channels = 2;
973
974 data->stream = connect_playback_stream(pulse_name, data->loop, data->context,
975 flags, NULL, &spec, NULL);
976 if(!data->stream)
977 {
978 pa_threaded_mainloop_unlock(data->loop);
979 pulse_close(device);
980 return ALC_INVALID_VALUE;
981 }
982
983 data->device_name = strdup(pa_stream_get_device_name(data->stream));
984 o = pa_context_get_sink_info_by_name(data->context, data->device_name,
985 sink_name_callback, device);
986 wait_for_operation(o, data->loop);
987
988 pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
989
990 pa_threaded_mainloop_unlock(data->loop);
991
992 return ALC_NO_ERROR;
993 }
994
995 static void pulse_close_playback(ALCdevice *device)
996 {
997 pulse_close(device);
998 }
999
1000 static ALCboolean pulse_reset_playback(ALCdevice *device)
1001 {
1002 pulse_data *data = device->ExtraData;
1003 pa_stream_flags_t flags = 0;
1004 pa_channel_map chanmap;
1005 ALuint len;
1006
1007 pa_threaded_mainloop_lock(data->loop);
1008
1009 if(data->stream)
1010 {
1011 pa_stream_set_moved_callback(data->stream, NULL, NULL);
1012 #if PA_CHECK_VERSION(0,9,15)
1013 if(pa_stream_set_buffer_attr_callback)
1014 pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
1015 #endif
1016 pa_stream_disconnect(data->stream);
1017 pa_stream_unref(data->stream);
1018 data->stream = NULL;
1019 }
1020
1021 if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
1022 {
1023 pa_operation *o;
1024 o = pa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
1025 wait_for_operation(o, data->loop);
1026 }
1027 if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
1028 flags |= PA_STREAM_FIX_RATE;
1029
1030 flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
1031 flags |= PA_STREAM_ADJUST_LATENCY;
1032 flags |= PA_STREAM_START_CORKED;
1033 if(!GetConfigValueBool("pulse", "allow-moves", 0))
1034 flags |= PA_STREAM_DONT_MOVE;
1035
1036 switch(device->FmtType)
1037 {
1038 case DevFmtByte:
1039 device->FmtType = DevFmtUByte;
1040 /* fall-through */
1041 case DevFmtUByte:
1042 data->spec.format = PA_SAMPLE_U8;
1043 break;
1044 case DevFmtUShort:
1045 device->FmtType = DevFmtShort;
1046 /* fall-through */
1047 case DevFmtShort:
1048 data->spec.format = PA_SAMPLE_S16NE;
1049 break;
1050 case DevFmtUInt:
1051 device->FmtType = DevFmtInt;
1052 /* fall-through */
1053 case DevFmtInt:
1054 data->spec.format = PA_SAMPLE_S32NE;
1055 break;
1056 case DevFmtFloat:
1057 data->spec.format = PA_SAMPLE_FLOAT32NE;
1058 break;
1059 }
1060 data->spec.rate = device->Frequency;
1061 data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
1062
1063 if(pa_sample_spec_valid(&data->spec) == 0)
1064 {
1065 ERR("Invalid sample format\n");
1066 pa_threaded_mainloop_unlock(data->loop);
1067 return ALC_FALSE;
1068 }
1069
1070 if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
1071 {
1072 ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
1073 pa_threaded_mainloop_unlock(data->loop);
1074 return ALC_FALSE;
1075 }
1076 SetDefaultWFXChannelOrder(device);
1077
1078 data->attr.fragsize = -1;
1079 data->attr.prebuf = 0;
1080 data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec);
1081 data->attr.tlength = data->attr.minreq * maxu(device->NumUpdates, 2);
1082 data->attr.maxlength = -1;
1083
1084 data->stream = connect_playback_stream(data->device_name, data->loop,
1085 data->context, flags, &data->attr,
1086 &data->spec, &chanmap);
1087 if(!data->stream)
1088 {
1089 pa_threaded_mainloop_unlock(data->loop);
1090 return ALC_FALSE;
1091 }
1092 pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
1093
1094 data->spec = *(pa_stream_get_sample_spec(data->stream));
1095 if(device->Frequency != data->spec.rate)
1096 {
1097 pa_operation *o;
1098
1099 /* Server updated our playback rate, so modify the buffer attribs
1100 * accordingly. */
1101 device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
1102 data->spec.rate + 0.5);
1103 data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec);
1104 data->attr.tlength = data->attr.minreq * clampu(device->NumUpdates, 2, 16);
1105 data->attr.maxlength = -1;
1106 data->attr.prebuf = 0;
1107
1108 o = pa_stream_set_buffer_attr(data->stream, &data->attr,
1109 stream_success_callback, device);
1110 wait_for_operation(o, data->loop);
1111
1112 device->Frequency = data->spec.rate;
1113 }
1114
1115 pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
1116 #if PA_CHECK_VERSION(0,9,15)
1117 if(pa_stream_set_buffer_attr_callback)
1118 pa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
1119 #endif
1120 stream_buffer_attr_callback(data->stream, device);
1121
1122 len = data->attr.minreq / pa_frame_size(&data->spec);
1123 if((CPUCapFlags&CPU_CAP_SSE))
1124 len = (len+3)&~3;
1125 device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
1126 device->NumUpdates = clampu(device->NumUpdates, 2, 16);
1127 device->UpdateSize = len;
1128
1129 pa_threaded_mainloop_unlock(data->loop);
1130 return ALC_TRUE;
1131 }
1132
1133 static ALCboolean pulse_start_playback(ALCdevice *device)
1134 {
1135 pulse_data *data = device->ExtraData;
1136
1137 data->thread = StartThread(PulseProc, device);
1138 if(!data->thread)
1139 return ALC_FALSE;
1140
1141 return ALC_TRUE;
1142 }
1143
1144 static void pulse_stop_playback(ALCdevice *device)
1145 {
1146 pulse_data *data = device->ExtraData;
1147 pa_operation *o;
1148
1149 if(!data->stream)
1150 return;
1151
1152 data->killNow = AL_TRUE;
1153 if(data->thread)
1154 {
1155 StopThread(data->thread);
1156 data->thread = NULL;
1157 }
1158 data->killNow = AL_FALSE;
1159
1160 pa_threaded_mainloop_lock(data->loop);
1161
1162 o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
1163 wait_for_operation(o, data->loop);
1164
1165 pa_threaded_mainloop_unlock(data->loop);
1166 }
1167
1168
1169 static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
1170 {
1171 const char *pulse_name = NULL;
1172 pa_stream_flags_t flags = 0;
1173 pa_channel_map chanmap;
1174 pulse_data *data;
1175 pa_operation *o;
1176 ALuint samples;
1177
1178 if(device_name)
1179 {
1180 ALuint i;
1181
1182 if(!allCaptureDevNameMap)
1183 probe_devices(AL_TRUE);
1184
1185 for(i = 0;i < numCaptureDevNames;i++)
1186 {
1187 if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
1188 {
1189 pulse_name = allCaptureDevNameMap[i].device_name;
1190 break;
1191 }
1192 }
1193 if(i == numCaptureDevNames)
1194 return ALC_INVALID_VALUE;
1195 }
1196
1197 if(pulse_open(device) == ALC_FALSE)
1198 return ALC_INVALID_VALUE;
1199
1200 data = device->ExtraData;
1201 pa_threaded_mainloop_lock(data->loop);
1202
1203 data->spec.rate = device->Frequency;
1204 data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
1205
1206 switch(device->FmtType)
1207 {
1208 case DevFmtUByte:
1209 data->spec.format = PA_SAMPLE_U8;
1210 break;
1211 case DevFmtShort:
1212 data->spec.format = PA_SAMPLE_S16NE;
1213 break;
1214 case DevFmtInt:
1215 data->spec.format = PA_SAMPLE_S32NE;
1216 break;
1217 case DevFmtFloat:
1218 data->spec.format = PA_SAMPLE_FLOAT32NE;
1219 break;
1220 case DevFmtByte:
1221 case DevFmtUShort:
1222 case DevFmtUInt:
1223 ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
1224 pa_threaded_mainloop_unlock(data->loop);
1225 goto fail;
1226 }
1227
1228 if(pa_sample_spec_valid(&data->spec) == 0)
1229 {
1230 ERR("Invalid sample format\n");
1231 pa_threaded_mainloop_unlock(data->loop);
1232 goto fail;
1233 }
1234
1235 if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
1236 {
1237 ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
1238 pa_threaded_mainloop_unlock(data->loop);
1239 goto fail;
1240 }
1241
1242 samples = device->UpdateSize * device->NumUpdates;
1243 samples = maxu(samples, 100 * device->Frequency / 1000);
1244
1245 data->attr.minreq = -1;
1246 data->attr.prebuf = -1;
1247 data->attr.maxlength = samples * pa_frame_size(&data->spec);
1248 data->attr.tlength = -1;
1249 data->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
1250 pa_frame_size(&data->spec);
1251
1252 flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
1253 if(!GetConfigValueBool("pulse", "allow-moves", 0))
1254 flags |= PA_STREAM_DONT_MOVE;
1255
1256 data->stream = connect_record_stream(pulse_name, data->loop, data->context,
1257 flags, &data->attr, &data->spec,
1258 &chanmap);
1259 if(!data->stream)
1260 {
1261 pa_threaded_mainloop_unlock(data->loop);
1262 goto fail;
1263 }
1264 pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
1265
1266 data->device_name = strdup(pa_stream_get_device_name(data->stream));
1267 o = pa_context_get_source_info_by_name(data->context, data->device_name,
1268 source_name_callback, device);
1269 wait_for_operation(o, data->loop);
1270
1271 pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
1272
1273 pa_threaded_mainloop_unlock(data->loop);
1274 return ALC_NO_ERROR;
1275
1276 fail:
1277 pulse_close(device);
1278 return ALC_INVALID_VALUE;
1279 }
1280
1281 static void pulse_close_capture(ALCdevice *device)
1282 {
1283 pulse_close(device);
1284 }
1285
1286 static void pulse_start_capture(ALCdevice *device)
1287 {
1288 pulse_data *data = device->ExtraData;
1289 pa_operation *o;
1290
1291 o = pa_stream_cork(data->stream, 0, stream_success_callback, device);
1292 wait_for_operation(o, data->loop);
1293 }
1294
1295 static void pulse_stop_capture(ALCdevice *device)
1296 {
1297 pulse_data *data = device->ExtraData;
1298 pa_operation *o;
1299
1300 o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
1301 wait_for_operation(o, data->loop);
1302 }
1303
1304 static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
1305 {
1306 pulse_data *data = device->ExtraData;
1307 ALCuint todo = samples * pa_frame_size(&data->spec);
1308
1309 /* Capture is done in fragment-sized chunks, so we loop until we get all
1310 * that's available */
1311 data->last_readable -= todo;
1312 while(todo > 0)
1313 {
1314 size_t rem = todo;
1315
1316 if(data->cap_len == 0)
1317 {
1318 pa_stream_state_t state;
1319
1320 state = pa_stream_get_state(data->stream);
1321 if(!PA_STREAM_IS_GOOD(state))
1322 {
1323 aluHandleDisconnect(device);
1324 break;
1325 }
1326 if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0)
1327 {
1328 ERR("pa_stream_peek() failed: %s\n",
1329 pa_strerror(pa_context_errno(data->context)));
1330 aluHandleDisconnect(device);
1331 break;
1332 }
1333 data->cap_remain = data->cap_len;
1334 }
1335 if(rem > data->cap_remain)
1336 rem = data->cap_remain;
1337
1338 memcpy(buffer, data->cap_store, rem);
1339
1340 buffer = (ALbyte*)buffer + rem;
1341 todo -= rem;
1342
1343 data->cap_store = (ALbyte*)data->cap_store + rem;
1344 data->cap_remain -= rem;
1345 if(data->cap_remain == 0)
1346 {
1347 pa_stream_drop(data->stream);
1348 data->cap_len = 0;
1349 }
1350 }
1351 if(todo > 0)
1352 memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
1353
1354 return ALC_NO_ERROR;
1355 }
1356
1357 static ALCuint pulse_available_samples(ALCdevice *device)
1358 {
1359 pulse_data *data = device->ExtraData;
1360 size_t readable = data->cap_remain;
1361
1362 if(device->Connected)
1363 {
1364 ssize_t got = pa_stream_readable_size(data->stream);
1365 if(got < 0)
1366 {
1367 ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
1368 aluHandleDisconnect(device);
1369 }
1370 else if((size_t)got > data->cap_len)
1371 readable += got - data->cap_len;
1372 }
1373
1374 if(data->last_readable < readable)
1375 data->last_readable = readable;
1376 return data->last_readable / pa_frame_size(&data->spec);
1377 }
1378
1379
1380 static void pulse_lock(ALCdevice *device)
1381 {
1382 pulse_data *data = device->ExtraData;
1383 pa_threaded_mainloop_lock(data->loop);
1384 }
1385
1386 static void pulse_unlock(ALCdevice *device)
1387 {
1388 pulse_data *data = device->ExtraData;
1389 pa_threaded_mainloop_unlock(data->loop);
1390 }
1391
1392
1393 static ALint64 pulse_get_latency(ALCdevice *device)
1394 {
1395 pulse_data *data = device->ExtraData;
1396 pa_usec_t latency = 0;
1397 int neg;
1398
1399 if(pa_stream_get_latency(data->stream, &latency, &neg) == 0)
1400 {
1401 if(neg)
1402 latency = 0;
1403 return (ALint64)minu64(latency, MAKEU64(0x7fffffff,0xffffffff)/1000) * 1000;
1404 }
1405 ERR("Failed to get stream latency!\n");
1406 return 0;
1407 }
1408
1409
1410 static const BackendFuncs pulse_funcs = {
1411 pulse_open_playback,
1412 pulse_close_playback,
1413 pulse_reset_playback,
1414 pulse_start_playback,
1415 pulse_stop_playback,
1416 pulse_open_capture,
1417 pulse_close_capture,
1418 pulse_start_capture,
1419 pulse_stop_capture,
1420 pulse_capture_samples,
1421 pulse_available_samples,
1422 pulse_lock,
1423 pulse_unlock,
1424 pulse_get_latency
1425 };
1426
1427 ALCboolean alc_pulse_init(BackendFuncs *func_list)
1428 {
1429 ALCboolean ret = ALC_FALSE;
1430
1431 if(pulse_load())
1432 {
1433 pa_threaded_mainloop *loop;
1434
1435 pulse_ctx_flags = 0;
1436 if(!GetConfigValueBool("pulse", "spawn-server", 1))
1437 pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
1438
1439 if((loop=pa_threaded_mainloop_new()) &&
1440 pa_threaded_mainloop_start(loop) >= 0)
1441 {
1442 pa_context *context;
1443
1444 pa_threaded_mainloop_lock(loop);
1445 context = connect_context(loop, AL_TRUE);
1446 if(context)
1447 {
1448 *func_list = pulse_funcs;
1449 ret = ALC_TRUE;
1450
1451 /* Some libraries (Phonon, Qt) set some pulseaudio properties
1452 * through environment variables, which causes all streams in
1453 * the process to inherit them. This attempts to filter those
1454 * properties out by setting them to 0-length data. */
1455 prop_filter = pa_proplist_new();
1456 pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, NULL, 0);
1457 pa_proplist_set(prop_filter, "phonon.streamid", NULL, 0);
1458
1459 pa_context_disconnect(context);
1460 pa_context_unref(context);
1461 }
1462 pa_threaded_mainloop_unlock(loop);
1463 pa_threaded_mainloop_stop(loop);
1464 }
1465 if(loop)
1466 pa_threaded_mainloop_free(loop);
1467 }
1468
1469 return ret;
1470 }
1471
1472 void alc_pulse_deinit(void)
1473 {
1474 ALuint i;
1475
1476 for(i = 0;i < numDevNames;++i)
1477 {
1478 free(allDevNameMap[i].name);
1479 free(allDevNameMap[i].device_name);
1480 }
1481 free(allDevNameMap);
1482 allDevNameMap = NULL;
1483 numDevNames = 0;
1484
1485 for(i = 0;i < numCaptureDevNames;++i)
1486 {
1487 free(allCaptureDevNameMap[i].name);
1488 free(allCaptureDevNameMap[i].device_name);
1489 }
1490 free(allCaptureDevNameMap);
1491 allCaptureDevNameMap = NULL;
1492 numCaptureDevNames = 0;
1493
1494 if(prop_filter)
1495 pa_proplist_free(prop_filter);
1496 prop_filter = NULL;
1497
1498 /* PulseAudio doesn't like being CloseLib'd sometimes */
1499 }
1500
1501 void alc_pulse_probe(enum DevProbe type)
1502 {
1503 ALuint i;
1504
1505 switch(type)
1506 {
1507 case ALL_DEVICE_PROBE:
1508 for(i = 0;i < numDevNames;++i)
1509 {
1510 free(allDevNameMap[i].name);
1511 free(allDevNameMap[i].device_name);
1512 }
1513 free(allDevNameMap);
1514 allDevNameMap = NULL;
1515 numDevNames = 0;
1516
1517 probe_devices(AL_FALSE);
1518
1519 for(i = 0;i < numDevNames;i++)
1520 AppendAllDevicesList(allDevNameMap[i].name);
1521 break;
1522
1523 case CAPTURE_DEVICE_PROBE:
1524 for(i = 0;i < numCaptureDevNames;++i)
1525 {
1526 free(allCaptureDevNameMap[i].name);
1527 free(allCaptureDevNameMap[i].device_name);
1528 }
1529 free(allCaptureDevNameMap);
1530 allCaptureDevNameMap = NULL;
1531 numCaptureDevNames = 0;
1532
1533 probe_devices(AL_TRUE);
1534
1535 for(i = 0;i < numCaptureDevNames;i++)
1536 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1537 break;
1538 }
1539 }
1540
1541 #else
1542
1543 #warning "Unsupported API version, backend will be unavailable!"
1544
1545 ALCboolean alc_pulse_init(BackendFuncs *func_list)
1546 { return ALC_FALSE; (void)func_list; }
1547
1548 void alc_pulse_deinit(void)
1549 { }
1550
1551 void alc_pulse_probe(enum DevProbe type)
1552 { (void)type; }
1553
1554 #endif
ALCdevice_struct::Connected
ALCboolean Connected
Definition: alMain.h:564
alc_pulse_init
ALCboolean alc_pulse_init(BackendFuncs *func_list)
Definition: pulseaudio.c:1545
ALvoid
void ALvoid
Definition: al.h:74
param
GLenum GLint param
Definition: gl2ext.h:1491
clampu
static __inline ALuint clampu(ALuint val, ALuint min, ALuint max)
Definition: alu.h:65
DEVICE_FREQUENCY_REQUEST
#define DEVICE_FREQUENCY_REQUEST
Definition: alMain.h:651
ALC_TRUE
#define ALC_TRUE
Definition: alc.h:84
DevFmtQuad
Definition: alMain.h:510
type
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
void
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
BackendFuncs
Definition: alMain.h:388
AL_TRUE
#define AL_TRUE
Definition: al.h:86
DevFmtUShort
Definition: alMain.h:500
strdup
char * strdup(const char *inStr)
Definition: strdup.c:6
NULL
#define NULL
Definition: ftobjs.h:61
TRACE
#define TRACE(...)
Definition: alMain.h:806
alc_pulse_probe
void alc_pulse_probe(enum DevProbe type)
Definition: pulseaudio.c:1551
stream
GLuint GLuint stream
Definition: glew.h:6573
alu.h
free
SDL_EventEntry * free
Definition: SDL_events.c:80
ALCdevice_struct::Frequency
ALuint Frequency
Definition: alMain.h:569
ALCdevice_struct
Definition: alMain.h:560
ALint
int ALint
Definition: al.h:56
aluMixData
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
Definition: ALu.c:970
memset
#define memset
Definition: SDL_malloc.c:633
AL_FALSE
#define AL_FALSE
Definition: al.h:83
name
EGLImageKHR EGLint * name
Definition: eglext.h:284
ALCdevice_struct::Flags
ALuint Flags
Definition: alMain.h:605
len
GLenum GLsizei len
Definition: glew.h:7035
AppendCaptureDeviceList
void AppendCaptureDeviceList(const ALCchar *name)
ALCuint
unsigned int ALCuint
Definition: alc.h:60
aluHandleDisconnect
ALvoid aluHandleDisconnect(ALCdevice *device)
Definition: ALu.c:1176
ALCchar
char ALCchar
Definition: alc.h:42
ALbyte
signed char ALbyte
Definition: al.h:44
DevFmtByte
Definition: alMain.h:497
ret
ret
Definition: glew_str_glx.c:2
DevFmtX51
Definition: alMain.h:511
Sleep
#define Sleep(x)
Definition: allatency.c:34
probe_devices
static DevMap * probe_devices(snd_pcm_stream_t stream, ALuint *count)
Definition: alsa.c:316
ALL_DEVICE_PROBE
Definition: alMain.h:384
buffer
EGLContext EGLenum EGLClientBuffer buffer
Definition: eglext.h:87
DevFmtStereo
Definition: alMain.h:509
ALCdevice_struct::ExtraData
void * ExtraData
Definition: alMain.h:630
ALC_FALSE
#define ALC_FALSE
Definition: alc.h:81
ALdouble
double ALdouble
Definition: al.h:71
DevFmtFloat
Definition: alMain.h:503
GetConfigValueBool
int GetConfigValueBool(const char *blockName, const char *keyName, int def)
Definition: alcConfig.c:356
DevFmtInt
Definition: alMain.h:501
StopThread
ALuint StopThread(ALvoid *thread)
Definition: alcThread.c:131
SetDefaultWFXChannelOrder
void SetDefaultWFXChannelOrder(ALCdevice *device)
Definition: ALc.c:1295
alMain.h
DevFmtShort
Definition: alMain.h:499
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
DevFmtX61
Definition: alMain.h:512
samples
GLsizei samples
Definition: gl2ext.h:970
alc_pulse_deinit
void alc_pulse_deinit(void)
Definition: pulseaudio.c:1548
LOAD_FUNC
#define LOAD_FUNC(f)
realloc
#define realloc
Definition: SDL_malloc.c:637
allDevNameMap
static DevMap * allDevNameMap
Definition: alsa.c:304
ALuint
unsigned int ALuint
Definition: al.h:59
SetRTPriority
void SetRTPriority(void)
Definition: helpers.c:470
minu64
static __inline ALuint64 minu64(ALuint64 a, ALuint64 b)
Definition: alu.h:82
ALCdevice_struct::FmtChans
enum DevFmtChannels FmtChans
Definition: alMain.h:572
minu
static __inline ALuint minu(ALuint a, ALuint b)
Definition: alu.h:61
CPU_CAP_SSE
Definition: alMain.h:827
allCaptureDevNameMap
static DevMap * allCaptureDevNameMap
Definition: alsa.c:306
DEVICE_CHANNELS_REQUEST
#define DEVICE_CHANNELS_REQUEST
Definition: alMain.h:653
DevFmtX51Side
Definition: alMain.h:516
thread
static SDL_Thread * thread
Definition: SDL_sysjoystick.c:41
PATH_MAX
#define PATH_MAX
Definition: hrtf.c:34
CAPTURE_DEVICE_PROBE
Definition: alMain.h:385
ALC_NO_ERROR
#define ALC_NO_ERROR
Definition: alc.h:102
malloc
#define malloc
Definition: SDL_malloc.c:635
ALCboolean
char ALCboolean
Definition: alc.h:39
MAKEU64
#define MAKEU64(x, y)
Definition: alMain.h:48
DevFmtUInt
Definition: alMain.h:502
DevFmtMono
Definition: alMain.h:508
numDevNames
static ALuint numDevNames
Definition: alsa.c:305
ALCvoid
void ALCvoid
Definition: alc.h:75
buf
GLenum GLuint GLsizei const GLchar * buf
Definition: glew.h:2539
ERR
#define ERR(...)
Definition: alMain.h:816
flags
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
Definition: glew.h:2767
memcpy
#define memcpy
Definition: SDL_malloc.c:634
ALCdevice_struct::UpdateSize
ALuint UpdateSize
Definition: alMain.h:570
ALCdevice_struct::NumUpdates
ALuint NumUpdates
Definition: alMain.h:571
ALCdevice_struct::FmtType
enum DevFmtType FmtType
Definition: alMain.h:573
String.h
ALCdevice_struct::DeviceName
ALCchar * DeviceName
Definition: alMain.h:575
ALboolean
char ALboolean
Definition: al.h:38
ALC_INVALID_VALUE
#define ALC_INVALID_VALUE
Definition: alc.h:114
str
#define str(s)
context
TParseContext * context
Definition: glslang_tab.cpp:1907
i
int i
Definition: pngrutil.c:1377
map
const GLubyte GLuint GLuint GLuint GLuint alpha GLboolean GLboolean GLboolean GLboolean alpha GLint GLint GLsizei GLsizei GLenum type GLenum GLint GLenum GLint GLint GLsizei GLsizei GLint border GLenum GLint GLint GLint GLint GLint GLsizei GLsizei height GLsizei GLsizei GLenum GLenum const GLvoid *pixels GLenum GLint GLint GLint GLint j2 GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLint *params GLenum GLenum GLfloat *params GLenum GLint GLenum GLenum GLvoid *pixels GLenum GLint GLenum GLint *params GLenum GLenum GLint *params GLenum GLsizei const GLvoid *pointer GLenum GLenum const GLint *params GLenum GLfloat GLfloat GLint GLint const GLfloat *points GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat *points GLint GLfloat GLfloat GLint GLfloat GLfloat v2 GLenum GLenum const GLint *params GLdouble GLdouble GLdouble GLdouble GLdouble GLdouble zFar GLenum map
Definition: SDL_glfuncs.h:268
ALCenum
int ALCenum
Definition: alc.h:66
CPUCapFlags
ALuint CPUCapFlags
Definition: helpers.c:70
DevFmtTypeString
const ALCchar * DevFmtTypeString(enum DevFmtType type)
Definition: ALc.c:1136
DevFmtUByte
Definition: alMain.h:498
DevFmtX71
Definition: alMain.h:513
maxu
static __inline ALuint maxu(ALuint a, ALuint b)
Definition: alu.h:63
DevFmtChannels
DevFmtChannels
Definition: alMain.h:507
ChannelsFromDevFmt
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
Definition: ALc.c:1179
numCaptureDevNames
static ALuint numCaptureDevNames
Definition: alsa.c:307
AppendAllDevicesList
void AppendAllDevicesList(const ALCchar *name)
StartThread
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
Definition: alcThread.c:100
DevProbe
DevProbe
Definition: alMain.h:383