29 #include <pulse/pulseaudio.h>
31 #if PA_API_VERSION == 12
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)))
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);
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);
111 #if PA_CHECK_VERSION(0,9,16)
112 MAKE_FUNC(pa_stream_begin_write);
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
184 #if PA_CHECK_VERSION(0,9,16)
185 #define pa_stream_begin_write ppa_stream_begin_write
191 #define PATH_MAX 4096
197 const void *cap_store;
206 pa_threaded_mainloop *loop;
225 static pa_context_flags_t pulse_ctx_flags;
226 static pa_proplist *prop_filter;
236 #define PALIB "libpulse-0.dll"
237 #elif defined(__APPLE__) && defined(__MACH__)
238 #define PALIB "libpulse.0.dylib"
240 #define PALIB "libpulse.so.0"
242 pa_handle = LoadLib(PALIB);
246 #define LOAD_FUNC(x) do { \
247 p##x = GetSymbol(pa_handle, #x); \
263 LOAD_FUNC(pa_threaded_mainloop_in_thread);
269 LOAD_FUNC(pa_context_set_state_callback);
298 LOAD_FUNC(pa_stream_set_underflow_callback);
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);
317 #define LOAD_OPTIONAL_FUNC(x) do { \
318 p##x = GetSymbol(pa_handle, #x); \
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);
324 #if PA_CHECK_VERSION(0,9,16)
325 LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
327 #undef LOAD_OPTIONAL_FUNC
340 static void context_state_callback(pa_context *
context,
void *pdata)
342 pa_threaded_mainloop *loop = pdata;
343 pa_context_state_t state;
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);
350 static void stream_state_callback(pa_stream *
stream,
void *pdata)
352 pa_threaded_mainloop *loop = pdata;
353 pa_stream_state_t state;
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);
360 static void stream_buffer_attr_callback(pa_stream *stream,
void *pdata)
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);
369 static void context_state_callback2(pa_context *context,
void *pdata)
374 if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
376 ERR(
"Received context failure!\n");
379 pa_threaded_mainloop_signal(data->loop, 0);
382 static void stream_state_callback2(pa_stream *stream,
void *pdata)
387 if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
389 ERR(
"Received stream failure!\n");
392 pa_threaded_mainloop_signal(data->loop, 0);
395 static void stream_success_callback(pa_stream *stream,
int success,
void *pdata)
402 pa_threaded_mainloop_signal(data->loop, 0);
405 static void sink_info_callback(pa_context *context,
const pa_sink_info *info,
int eol,
void *pdata)
409 char chanmap_str[256] =
"";
414 {
"front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
416 {
"front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
418 {
"front-left,front-right,front-center,lfe,rear-left,rear-right",
420 {
"front-left,front-right,front-center,lfe,side-left,side-right",
422 {
"front-left,front-right,rear-left,rear-right",
DevFmtQuad },
432 pa_threaded_mainloop_signal(data->loop, 0);
436 for(i = 0;chanmaps[
i].str;i++)
439 if(!pa_channel_map_parse(&map, chanmaps[i].
str))
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))
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);
458 static void sink_device_callback(pa_context *context,
const pa_sink_info *info,
int eol,
void *pdata)
460 pa_threaded_mainloop *loop = pdata;
468 pa_threaded_mainloop_signal(loop, 0);
478 TRACE(
"Got device \"%s\", \"%s\"\n", info->description, info->name);
490 static void source_device_callback(pa_context *context,
const pa_source_info *info,
int eol,
void *pdata)
492 pa_threaded_mainloop *loop = pdata;
500 pa_threaded_mainloop_signal(loop, 0);
510 TRACE(
"Got device \"%s\", \"%s\"\n", info->description, info->name);
518 numCaptureDevNames++;
522 static void sink_name_callback(pa_context *context,
const pa_sink_info *info,
int eol,
void *pdata)
530 pa_threaded_mainloop_signal(data->loop, 0);
538 static void source_name_callback(pa_context *context,
const pa_source_info *info,
int eol,
void *pdata)
546 pa_threaded_mainloop_signal(data->loop, 0);
555 static void stream_moved_callback(pa_stream *stream,
void *pdata)
561 free(data->device_name);
562 data->device_name =
strdup(pa_stream_get_device_name(data->stream));
564 TRACE(
"Stream moved to %s\n", data->device_name);
568 static pa_context *connect_context(pa_threaded_mainloop *loop,
ALboolean silent)
570 const char *
name =
"OpenAL Soft";
572 pa_context_state_t state;
576 if(pa_get_binary_name(path_name,
sizeof(path_name)))
577 name = pa_path_get_filename(path_name);
579 context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
582 ERR(
"pa_context_new() failed\n");
586 pa_context_set_state_callback(context, context_state_callback, loop);
588 if((err=pa_context_connect(context,
NULL, pulse_ctx_flags,
NULL)) >= 0)
590 while((state=pa_context_get_state(context)) != PA_CONTEXT_READY)
592 if(!PA_CONTEXT_IS_GOOD(state))
594 err = pa_context_errno(context);
595 if(err > 0) err = -err;
599 pa_threaded_mainloop_wait(loop);
602 pa_context_set_state_callback(context,
NULL,
NULL);
607 ERR(
"Context did not connect: %s\n", pa_strerror(err));
608 pa_context_unref(context);
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)
620 pa_stream_state_t state;
623 stream = pa_stream_new_with_proplist(context,
"Playback Stream", spec, chanmap, prop_filter);
626 ERR(
"pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
630 pa_stream_set_state_callback(stream, stream_state_callback, loop);
632 if(pa_stream_connect_playback(stream, device_name, attr, flags,
NULL,
NULL) < 0)
634 ERR(
"Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
635 pa_stream_unref(stream);
639 while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
641 if(!PA_STREAM_IS_GOOD(state))
643 ERR(
"Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
644 pa_stream_unref(stream);
648 pa_threaded_mainloop_wait(loop);
650 pa_stream_set_state_callback(stream,
NULL,
NULL);
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)
660 pa_stream_state_t state;
663 stream = pa_stream_new_with_proplist(context,
"Capture Stream", spec, chanmap, prop_filter);
666 ERR(
"pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context)));
670 pa_stream_set_state_callback(stream, stream_state_callback, loop);
672 if(pa_stream_connect_record(stream, device_name, attr, flags) < 0)
674 ERR(
"Stream did not connect: %s\n", pa_strerror(pa_context_errno(context)));
675 pa_stream_unref(stream);
679 while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
681 if(!PA_STREAM_IS_GOOD(state))
683 ERR(
"Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context)));
684 pa_stream_unref(stream);
688 pa_threaded_mainloop_wait(loop);
690 pa_stream_set_state_callback(stream,
NULL,
NULL);
696 static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop)
700 while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
701 pa_threaded_mainloop_wait(loop);
702 pa_operation_unref(op);
709 pa_threaded_mainloop *loop;
716 if((loop=pa_threaded_mainloop_new()) &&
717 pa_threaded_mainloop_start(loop) >= 0)
721 pa_threaded_mainloop_lock(loop);
722 context = connect_context(loop,
AL_FALSE);
729 pa_stream_flags_t
flags;
733 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
734 PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
736 spec.format = PA_SAMPLE_S16NE;
740 stream = connect_playback_stream(
NULL, loop, context, flags,
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);
747 pa_stream_disconnect(stream);
748 pa_stream_unref(stream);
752 o = pa_context_get_sink_info_list(context, sink_device_callback, loop);
756 pa_stream_flags_t
flags;
760 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
761 PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;
763 spec.format = PA_SAMPLE_S16NE;
767 stream = connect_record_stream(
NULL, loop, context, flags,
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);
774 pa_stream_disconnect(stream);
775 pa_stream_unref(stream);
779 o = pa_context_get_source_info_list(context, source_device_callback, loop);
781 wait_for_operation(o, loop);
783 pa_context_disconnect(context);
784 pa_context_unref(context);
786 pa_threaded_mainloop_unlock(loop);
787 pa_threaded_mainloop_stop(loop);
790 pa_threaded_mainloop_free(loop);
805 pa_threaded_mainloop_lock(data->loop);
806 frame_size = pa_frame_size(&data->spec);
807 update_size = Device->
UpdateSize * frame_size;
811 buffer_size =
minu(update_size*Device->
NumUpdates, data->attr.tlength);
812 update_size =
minu(update_size, buffer_size/2);
814 len = pa_stream_writable_size(data->stream) - data->attr.tlength +
816 if(len < update_size)
818 if(pa_stream_is_corked(data->stream) == 1)
821 o = pa_stream_cork(data->stream, 0,
NULL,
NULL);
822 if(o) pa_operation_unref(o);
824 pa_threaded_mainloop_unlock(data->loop);
826 pa_threaded_mainloop_lock(data->loop);
829 len -= len%update_size;
835 pa_free_cb_t free_func =
NULL;
837 #if PA_CHECK_VERSION(0,9,16)
838 if(!pa_stream_begin_write ||
839 pa_stream_begin_write(data->stream, &buf, &newlen) < 0)
842 buf = pa_xmalloc(newlen);
843 free_func = pa_xfree;
848 pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
851 }
while(!data->killNow && Device->
Connected);
852 pa_threaded_mainloop_unlock(data->loop);
860 pulse_data *data = pa_xmalloc(
sizeof(pulse_data));
861 memset(data, 0,
sizeof(*data));
863 if(!(data->loop = pa_threaded_mainloop_new()))
865 ERR(
"pa_threaded_mainloop_new() failed!\n");
868 if(pa_threaded_mainloop_start(data->loop) < 0)
870 ERR(
"pa_threaded_mainloop_start() failed\n");
874 pa_threaded_mainloop_lock(data->loop);
877 data->context = connect_context(data->loop,
AL_FALSE);
880 pa_threaded_mainloop_unlock(data->loop);
883 pa_context_set_state_callback(data->context, context_state_callback2, device);
885 pa_threaded_mainloop_unlock(data->loop);
891 pa_threaded_mainloop_stop(data->loop);
892 pa_threaded_mainloop_free(data->loop);
900 static void pulse_close(
ALCdevice *device)
904 pa_threaded_mainloop_lock(data->loop);
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);
913 pa_stream_disconnect(data->stream);
914 pa_stream_unref(data->stream);
917 pa_context_disconnect(data->context);
918 pa_context_unref(data->context);
920 pa_threaded_mainloop_unlock(data->loop);
922 pa_threaded_mainloop_stop(data->loop);
923 pa_threaded_mainloop_free(data->loop);
925 free(data->device_name);
934 const char *pulse_name =
NULL;
935 pa_stream_flags_t
flags;
963 pa_threaded_mainloop_lock(data->loop);
965 flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
966 PA_STREAM_FIX_CHANNELS;
968 flags |= PA_STREAM_DONT_MOVE;
970 spec.format = PA_SAMPLE_S16NE;
974 data->stream = connect_playback_stream(pulse_name, data->loop, data->context,
978 pa_threaded_mainloop_unlock(data->loop);
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);
988 pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
990 pa_threaded_mainloop_unlock(data->loop);
995 static void pulse_close_playback(
ALCdevice *device)
1003 pa_stream_flags_t flags = 0;
1004 pa_channel_map chanmap;
1007 pa_threaded_mainloop_lock(data->loop);
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);
1016 pa_stream_disconnect(data->stream);
1017 pa_stream_unref(data->stream);
1018 data->stream =
NULL;
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);
1028 flags |= PA_STREAM_FIX_RATE;
1030 flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
1031 flags |= PA_STREAM_ADJUST_LATENCY;
1032 flags |= PA_STREAM_START_CORKED;
1034 flags |= PA_STREAM_DONT_MOVE;
1042 data->spec.format = PA_SAMPLE_U8;
1048 data->spec.format = PA_SAMPLE_S16NE;
1054 data->spec.format = PA_SAMPLE_S32NE;
1057 data->spec.format = PA_SAMPLE_FLOAT32NE;
1063 if(pa_sample_spec_valid(&data->spec) == 0)
1065 ERR(
"Invalid sample format\n");
1066 pa_threaded_mainloop_unlock(data->loop);
1070 if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
1072 ERR(
"Couldn't build map for channel count (%d)!\n", data->spec.channels);
1073 pa_threaded_mainloop_unlock(data->loop);
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;
1084 data->stream = connect_playback_stream(data->device_name, data->loop,
1085 data->context, flags, &data->attr,
1086 &data->spec, &chanmap);
1089 pa_threaded_mainloop_unlock(data->loop);
1092 pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
1094 data->spec = *(pa_stream_get_sample_spec(data->stream));
1095 if(device->
Frequency != data->spec.rate)
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;
1108 o = pa_stream_set_buffer_attr(data->stream, &data->attr,
1109 stream_success_callback, device);
1110 wait_for_operation(o, data->loop);
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);
1120 stream_buffer_attr_callback(data->stream, device);
1122 len = data->attr.minreq / pa_frame_size(&data->spec);
1129 pa_threaded_mainloop_unlock(data->loop);
1144 static void pulse_stop_playback(
ALCdevice *device)
1156 data->thread =
NULL;
1160 pa_threaded_mainloop_lock(data->loop);
1162 o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
1163 wait_for_operation(o, data->loop);
1165 pa_threaded_mainloop_unlock(data->loop);
1171 const char *pulse_name =
NULL;
1172 pa_stream_flags_t flags = 0;
1173 pa_channel_map chanmap;
1193 if(i == numCaptureDevNames)
1201 pa_threaded_mainloop_lock(data->loop);
1209 data->spec.format = PA_SAMPLE_U8;
1212 data->spec.format = PA_SAMPLE_S16NE;
1215 data->spec.format = PA_SAMPLE_S32NE;
1218 data->spec.format = PA_SAMPLE_FLOAT32NE;
1224 pa_threaded_mainloop_unlock(data->loop);
1228 if(pa_sample_spec_valid(&data->spec) == 0)
1230 ERR(
"Invalid sample format\n");
1231 pa_threaded_mainloop_unlock(data->loop);
1235 if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
1237 ERR(
"Couldn't build map for channel count (%d)!\n", data->spec.channels);
1238 pa_threaded_mainloop_unlock(data->loop);
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);
1252 flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
1254 flags |= PA_STREAM_DONT_MOVE;
1256 data->stream = connect_record_stream(pulse_name, data->loop, data->context,
1257 flags, &data->attr, &data->spec,
1261 pa_threaded_mainloop_unlock(data->loop);
1264 pa_stream_set_state_callback(data->stream, stream_state_callback2, device);
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);
1271 pa_stream_set_moved_callback(data->stream, stream_moved_callback, device);
1273 pa_threaded_mainloop_unlock(data->loop);
1277 pulse_close(device);
1281 static void pulse_close_capture(
ALCdevice *device)
1283 pulse_close(device);
1286 static void pulse_start_capture(
ALCdevice *device)
1291 o = pa_stream_cork(data->stream, 0, stream_success_callback, device);
1292 wait_for_operation(o, data->loop);
1295 static void pulse_stop_capture(
ALCdevice *device)
1300 o = pa_stream_cork(data->stream, 1, stream_success_callback, device);
1301 wait_for_operation(o, data->loop);
1307 ALCuint todo = samples * pa_frame_size(&data->spec);
1311 data->last_readable -= todo;
1316 if(data->cap_len == 0)
1318 pa_stream_state_t state;
1320 state = pa_stream_get_state(data->stream);
1321 if(!PA_STREAM_IS_GOOD(state))
1326 if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0)
1328 ERR(
"pa_stream_peek() failed: %s\n",
1329 pa_strerror(pa_context_errno(data->context)));
1333 data->cap_remain = data->cap_len;
1335 if(rem > data->cap_remain)
1336 rem = data->cap_remain;
1338 memcpy(buffer, data->cap_store, rem);
1340 buffer = (
ALbyte*)buffer + rem;
1343 data->cap_store = (
ALbyte*)data->cap_store + rem;
1344 data->cap_remain -= rem;
1345 if(data->cap_remain == 0)
1347 pa_stream_drop(data->stream);
1360 size_t readable = data->cap_remain;
1364 ssize_t got = pa_stream_readable_size(data->stream);
1367 ERR(
"pa_stream_readable_size() failed: %s\n", pa_strerror(got));
1370 else if((
size_t)got > data->cap_len)
1371 readable += got - data->cap_len;
1374 if(data->last_readable < readable)
1375 data->last_readable = readable;
1376 return data->last_readable / pa_frame_size(&data->spec);
1380 static void pulse_lock(
ALCdevice *device)
1383 pa_threaded_mainloop_lock(data->loop);
1386 static void pulse_unlock(
ALCdevice *device)
1389 pa_threaded_mainloop_unlock(data->loop);
1393 static ALint64 pulse_get_latency(
ALCdevice *device)
1396 pa_usec_t latency = 0;
1399 if(pa_stream_get_latency(data->stream, &latency, &neg) == 0)
1403 return (ALint64)
minu64(latency,
MAKEU64(0x7fffffff,0xffffffff)/1000) * 1000;
1405 ERR(
"Failed to get stream latency!\n");
1411 pulse_open_playback,
1412 pulse_close_playback,
1413 pulse_reset_playback,
1414 pulse_start_playback,
1415 pulse_stop_playback,
1417 pulse_close_capture,
1418 pulse_start_capture,
1420 pulse_capture_samples,
1421 pulse_available_samples,
1433 pa_threaded_mainloop *loop;
1435 pulse_ctx_flags = 0;
1437 pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
1439 if((loop=pa_threaded_mainloop_new()) &&
1440 pa_threaded_mainloop_start(loop) >= 0)
1444 pa_threaded_mainloop_lock(loop);
1445 context = connect_context(loop,
AL_TRUE);
1448 *func_list = pulse_funcs;
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);
1459 pa_context_disconnect(context);
1460 pa_context_unref(context);
1462 pa_threaded_mainloop_unlock(loop);
1463 pa_threaded_mainloop_stop(loop);
1466 pa_threaded_mainloop_free(loop);
1492 numCaptureDevNames = 0;
1495 pa_proplist_free(prop_filter);
1531 numCaptureDevNames = 0;
1543 #warning "Unsupported API version, backend will be unavailable!"
ALCboolean alc_pulse_init(BackendFuncs *func_list)
static __inline ALuint clampu(ALuint val, ALuint min, ALuint max)
#define DEVICE_FREQUENCY_REQUEST
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
char * strdup(const char *inStr)
void alc_pulse_probe(enum DevProbe type)
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
EGLImageKHR EGLint * name
void AppendCaptureDeviceList(const ALCchar *name)
ALvoid aluHandleDisconnect(ALCdevice *device)
static DevMap * probe_devices(snd_pcm_stream_t stream, ALuint *count)
EGLContext EGLenum EGLClientBuffer buffer
int GetConfigValueBool(const char *blockName, const char *keyName, int def)
ALuint StopThread(ALvoid *thread)
void SetDefaultWFXChannelOrder(ALCdevice *device)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
void alc_pulse_deinit(void)
static DevMap * allDevNameMap
static __inline ALuint64 minu64(ALuint64 a, ALuint64 b)
enum DevFmtChannels FmtChans
static __inline ALuint minu(ALuint a, ALuint b)
static DevMap * allCaptureDevNameMap
#define DEVICE_CHANNELS_REQUEST
static SDL_Thread * thread
static ALuint numDevNames
GLenum GLuint GLsizei const GLchar * buf
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
#define ALC_INVALID_VALUE
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
const ALCchar * DevFmtTypeString(enum DevFmtType type)
static __inline ALuint maxu(ALuint a, ALuint b)
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
static ALuint numCaptureDevNames
void AppendAllDevicesList(const ALCchar *name)
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)