28 #include "../../SDL_internal.h" 31 #if SDL_AUDIO_DRIVER_PULSEAUDIO 39 #include <sys/types.h> 41 #include <pulse/pulseaudio.h> 45 #include "../SDL_audio_c.h" 48 #include "../../thread/SDL_systhread.h" 50 #if (PA_API_VERSION < 12) 52 static SDL_INLINE int PA_CONTEXT_IS_GOOD(pa_context_state_t
x) {
54 x == PA_CONTEXT_CONNECTING ||
55 x == PA_CONTEXT_AUTHORIZING ||
56 x == PA_CONTEXT_SETTING_NAME ||
57 x == PA_CONTEXT_READY;
60 static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t
x) {
62 x == PA_STREAM_CREATING ||
68 static const char *(*PULSEAUDIO_pa_get_library_version) (
void);
69 static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) (
70 pa_channel_map *, unsigned, pa_channel_map_def_t);
71 static const char * (*PULSEAUDIO_pa_strerror) (int);
72 static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (
void);
73 static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *);
74 static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int,
int *);
75 static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *,
int *);
76 static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int);
77 static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
79 static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
81 static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
82 static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
84 static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
86 static int (*PULSEAUDIO_pa_context_connect) (pa_context *,
const char *,
87 pa_context_flags_t,
const pa_spawn_api *);
88 static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t,
void *);
89 static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t,
void *);
90 static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *,
uint32_t, pa_sink_info_cb_t,
void *);
91 static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *,
uint32_t, pa_source_info_cb_t,
void *);
92 static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
93 static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t,
void *);
94 static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t,
void *);
95 static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
96 static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
98 static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *,
const char *,
99 const pa_sample_spec *,
const pa_channel_map *);
100 static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *,
const char *,
101 const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
102 static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *,
const char *,
103 const pa_buffer_attr *, pa_stream_flags_t);
104 static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
105 static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
106 static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
107 static int (*PULSEAUDIO_pa_stream_write) (pa_stream *,
const void *,
size_t,
108 pa_free_cb_t,
int64_t, pa_seek_mode_t);
109 static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
110 pa_stream_success_cb_t,
void *);
111 static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *,
const void **,
size_t *);
112 static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *);
113 static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
114 pa_stream_success_cb_t,
void *);
115 static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
116 static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
118 static int load_pulseaudio_syms(
void);
121 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC 123 static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
124 static void *pulseaudio_handle =
NULL;
127 load_pulseaudio_sym(
const char *fn,
void **
addr)
139 #define SDL_PULSEAUDIO_SYM(x) \ 140 if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1 143 UnloadPulseAudioLibrary(
void)
145 if (pulseaudio_handle !=
NULL) {
147 pulseaudio_handle =
NULL;
152 LoadPulseAudioLibrary(
void)
155 if (pulseaudio_handle ==
NULL) {
157 if (pulseaudio_handle ==
NULL) {
161 retval = load_pulseaudio_syms();
163 UnloadPulseAudioLibrary();
172 #define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x 175 UnloadPulseAudioLibrary(
void)
180 LoadPulseAudioLibrary(
void)
182 load_pulseaudio_syms();
190 load_pulseaudio_syms(
void)
192 SDL_PULSEAUDIO_SYM(pa_get_library_version);
193 SDL_PULSEAUDIO_SYM(pa_mainloop_new);
194 SDL_PULSEAUDIO_SYM(pa_mainloop_get_api);
195 SDL_PULSEAUDIO_SYM(pa_mainloop_iterate);
196 SDL_PULSEAUDIO_SYM(pa_mainloop_run);
197 SDL_PULSEAUDIO_SYM(pa_mainloop_quit);
198 SDL_PULSEAUDIO_SYM(pa_mainloop_free);
199 SDL_PULSEAUDIO_SYM(pa_operation_get_state);
200 SDL_PULSEAUDIO_SYM(pa_operation_cancel);
201 SDL_PULSEAUDIO_SYM(pa_operation_unref);
202 SDL_PULSEAUDIO_SYM(pa_context_new);
203 SDL_PULSEAUDIO_SYM(pa_context_connect);
204 SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
205 SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
206 SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index);
207 SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index);
208 SDL_PULSEAUDIO_SYM(pa_context_get_state);
209 SDL_PULSEAUDIO_SYM(pa_context_subscribe);
210 SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback);
211 SDL_PULSEAUDIO_SYM(pa_context_disconnect);
212 SDL_PULSEAUDIO_SYM(pa_context_unref);
213 SDL_PULSEAUDIO_SYM(pa_stream_new);
214 SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
215 SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
216 SDL_PULSEAUDIO_SYM(pa_stream_get_state);
217 SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
218 SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
219 SDL_PULSEAUDIO_SYM(pa_stream_write);
220 SDL_PULSEAUDIO_SYM(pa_stream_drain);
221 SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
222 SDL_PULSEAUDIO_SYM(pa_stream_peek);
223 SDL_PULSEAUDIO_SYM(pa_stream_drop);
224 SDL_PULSEAUDIO_SYM(pa_stream_flush);
225 SDL_PULSEAUDIO_SYM(pa_stream_unref);
226 SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
227 SDL_PULSEAUDIO_SYM(pa_strerror);
232 squashVersion(
const int major,
const int minor,
const int patch)
234 return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
241 const char *verstr = PULSEAUDIO_pa_get_library_version();
242 if (verstr !=
NULL) {
244 if (
SDL_sscanf(verstr,
"%d.%d.%d", &maj, &min, &patch) == 3) {
245 if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
250 return "SDL Application";
254 stream_operation_complete_no_op(pa_stream *
s,
int success,
void *userdata)
260 WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
265 while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) {
266 okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1,
NULL) >= 0);
268 PULSEAUDIO_pa_operation_unref(o);
273 DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *context)
276 PULSEAUDIO_pa_context_disconnect(context);
277 PULSEAUDIO_pa_context_unref(context);
279 if (mainloop !=
NULL) {
280 PULSEAUDIO_pa_mainloop_free(mainloop);
285 ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
287 pa_mainloop *mainloop =
NULL;
288 pa_context *context =
NULL;
289 pa_mainloop_api *mainloop_api =
NULL;
296 if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) {
300 *_mainloop = mainloop;
302 mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop);
305 context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
312 if (PULSEAUDIO_pa_context_connect(context,
NULL, 0,
NULL) < 0) {
313 return SDL_SetError(
"Could not setup connection to PulseAudio");
317 if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1,
NULL) < 0) {
320 state = PULSEAUDIO_pa_context_get_state(context);
321 if (!PA_CONTEXT_IS_GOOD(state)) {
324 }
while (state != PA_CONTEXT_READY);
330 ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
332 const int retval = ConnectToPulseServer_Internal(_mainloop, _context);
334 DisconnectFromPulseServer(*_mainloop, *_context);
342 PULSEAUDIO_WaitDevice(
_THIS)
347 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
348 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
349 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
353 if (PULSEAUDIO_pa_stream_writable_size(h->
stream) >= h->
mixlen) {
360 PULSEAUDIO_PlayDevice(
_THIS)
372 PULSEAUDIO_GetDeviceBuf(
_THIS)
374 return (this->hidden->mixbuf);
379 PULSEAUDIO_CaptureFromDevice(
_THIS,
void *
buffer,
int buflen)
394 PULSEAUDIO_pa_stream_drop(h->
stream);
399 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
400 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
401 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
406 if (PULSEAUDIO_pa_stream_readable_size(h->
stream) == 0) {
411 PULSEAUDIO_pa_stream_peek(h->
stream, &data, &nbytes);
414 PULSEAUDIO_pa_stream_drop(h->
stream);
427 PULSEAUDIO_FlushCapture(
_THIS)
432 PULSEAUDIO_pa_stream_drop(h->
stream);
437 WaitForPulseOperation(h->
mainloop, PULSEAUDIO_pa_stream_flush(h->
stream, stream_operation_complete_no_op,
NULL));
441 PULSEAUDIO_CloseDevice(
_THIS)
443 if (this->hidden->stream) {
444 if (this->hidden->capturebuf !=
NULL) {
445 PULSEAUDIO_pa_stream_drop(this->hidden->stream);
447 PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
448 PULSEAUDIO_pa_stream_unref(this->hidden->stream);
451 DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
453 SDL_free(this->hidden->device_name);
458 SinkDeviceNameCallback(pa_context *
c,
const pa_sink_info *
i,
int is_last,
void *data)
461 char **devname = (
char **) data;
467 SourceDeviceNameCallback(pa_context *c,
const pa_source_info *i,
int is_last,
void *data)
470 char **devname = (
char **) data;
480 if (handle ==
NULL) {
486 PULSEAUDIO_pa_context_get_source_info_by_index(h->
context, idx,
490 PULSEAUDIO_pa_context_get_sink_info_by_index(h->
context, idx,
498 PULSEAUDIO_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
502 pa_sample_spec paspec;
503 pa_buffer_attr paattr;
504 pa_channel_map pacmap;
505 pa_stream_flags_t
flags = 0;
512 if (this->hidden ==
NULL) {
517 paspec.format = PA_SAMPLE_INVALID;
521 (paspec.format == PA_SAMPLE_INVALID) && test_format;) {
523 fprintf(stderr,
"Trying format 0x%4.4x\n", test_format);
525 switch (test_format) {
527 paspec.format = PA_SAMPLE_U8;
530 paspec.format = PA_SAMPLE_S16LE;
533 paspec.format = PA_SAMPLE_S16BE;
536 paspec.format = PA_SAMPLE_S32LE;
539 paspec.format = PA_SAMPLE_S32BE;
542 paspec.format = PA_SAMPLE_FLOAT32LE;
545 paspec.format = PA_SAMPLE_FLOAT32BE;
548 paspec.format = PA_SAMPLE_INVALID;
551 if (paspec.format == PA_SAMPLE_INVALID) {
555 if (paspec.format == PA_SAMPLE_INVALID) {
556 return SDL_SetError(
"Couldn't find any hardware audio formats");
561 #ifdef PA_STREAM_ADJUST_LATENCY 580 #ifdef PA_STREAM_ADJUST_LATENCY 582 paattr.tlength = h->
mixlen * 4;
584 paattr.maxlength = -1;
586 paattr.minreq = h->
mixlen;
587 flags = PA_STREAM_ADJUST_LATENCY;
589 paattr.tlength = h->
mixlen*2;
590 paattr.prebuf = h->
mixlen*2;
591 paattr.maxlength = h->
mixlen*2;
592 paattr.minreq = h->
mixlen;
596 return SDL_SetError(
"Could not connect to PulseAudio server");
599 if (!FindDeviceName(h, iscapture, handle)) {
600 return SDL_SetError(
"Requested PulseAudio sink/source missing?");
605 PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->
spec.
channels,
606 PA_CHANNEL_MAP_WAVEEX);
608 h->
stream = PULSEAUDIO_pa_stream_new(
610 "Simple DirectMedia Layer",
616 return SDL_SetError(
"Could not set up PulseAudio stream");
622 flags |= PA_STREAM_DONT_MOVE;
626 rc = PULSEAUDIO_pa_stream_connect_record(h->
stream, h->
device_name, &paattr, flags);
632 return SDL_SetError(
"Could not connect PulseAudio stream");
636 if (PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
639 state = PULSEAUDIO_pa_stream_get_state(h->
stream);
640 if (!PA_STREAM_IS_GOOD(state)) {
641 return SDL_SetError(
"Could not connect PulseAudio stream");
643 }
while (state != PA_STREAM_READY);
649 static pa_mainloop *hotplug_mainloop =
NULL;
650 static pa_context *hotplug_context =
NULL;
657 SinkInfoCallback(pa_context *c,
const pa_sink_info *i,
int is_last,
void *data)
666 SourceInfoCallback(pa_context *c,
const pa_source_info *i,
int is_last,
void *data)
670 if (i->monitor_of_sink == PA_INVALID_INDEX) {
678 HotplugCallback(pa_context *c, pa_subscription_event_type_t
t,
uint32_t idx,
void *data)
680 const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW);
681 const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE);
683 if (added || removed) {
684 const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK);
685 const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
689 PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback,
NULL);
690 }
else if (added && source) {
691 PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback,
NULL);
692 }
else if (removed && (sink || source)) {
701 HotplugThread(
void *data)
705 PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback,
NULL);
706 o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
NULL,
NULL);
707 PULSEAUDIO_pa_operation_unref(o);
708 PULSEAUDIO_pa_mainloop_run(hotplug_mainloop,
NULL);
713 PULSEAUDIO_DetectDevices()
715 WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback,
NULL));
716 WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback,
NULL));
723 PULSEAUDIO_Deinitialize(
void)
725 if (hotplug_thread) {
726 PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0);
728 hotplug_thread =
NULL;
731 DisconnectFromPulseServer(hotplug_mainloop, hotplug_context);
732 hotplug_mainloop =
NULL;
733 hotplug_context =
NULL;
735 UnloadPulseAudioLibrary();
741 if (LoadPulseAudioLibrary() < 0) {
745 if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
746 UnloadPulseAudioLibrary();
767 "pulseaudio",
"PulseAudio", PULSEAUDIO_Init, 0
GLsizei GLenum GLboolean sink
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
AudioBootStrap PULSEAUDIO_bootstrap
void(* DetectDevices)(void)
GLint GLint GLint GLint GLint x
LPDIRECTSOUNDCAPTUREBUFFER capturebuf
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
void(* PlayDevice)(_THIS)
void(* WaitDevice)(_THIS)
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
SDL_AudioFormat SDL_NextAudioFormat(void)
SDL_Thread * SDL_CreateThreadInternal(int(*fn)(void *), const char *name, const size_t stacksize, void *data)
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
uint8_t Uint8
An unsigned 8-bit integer type.
void(* Deinitialize)(void)
GLsizei GLsizei GLchar * source
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
GLenum GLenum GLsizei const GLuint GLboolean enabled
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define SDL_assert(condition)
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
#define SDL_OutOfMemory()
int(* CaptureFromDevice)(_THIS, void *buffer, int buflen)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
void(* CloseDevice)(_THIS)
void(* FlushCapture)(_THIS)
Uint8 *(* GetDeviceBuf)(_THIS)
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 idx
uint16_t Uint16
An unsigned 16-bit integer type.
void * SDL_LoadFunction(void *handle, const char *name)
#define SDL_SetThreadPriority
GLfloat GLfloat GLfloat GLfloat h
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)