28 #include "../../SDL_internal.h" 31 #if SDL_AUDIO_DRIVER_PULSEAUDIO 39 #include <sys/types.h> 40 #include <pulse/pulseaudio.h> 44 #include "../SDL_audio_c.h" 47 #include "../../thread/SDL_systhread.h" 49 #if (PA_API_VERSION < 12) 51 static SDL_INLINE int PA_CONTEXT_IS_GOOD(pa_context_state_t
x) {
53 x == PA_CONTEXT_CONNECTING ||
54 x == PA_CONTEXT_AUTHORIZING ||
55 x == PA_CONTEXT_SETTING_NAME ||
56 x == PA_CONTEXT_READY;
59 static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t
x) {
61 x == PA_STREAM_CREATING ||
67 static const char *(*PULSEAUDIO_pa_get_library_version) (
void);
68 static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) (
69 pa_channel_map *, unsigned, pa_channel_map_def_t);
70 static const char * (*PULSEAUDIO_pa_strerror) (int);
71 static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (
void);
72 static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *);
73 static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int,
int *);
74 static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *,
int *);
75 static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int);
76 static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
78 static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
80 static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
81 static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
83 static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
85 static int (*PULSEAUDIO_pa_context_connect) (pa_context *,
const char *,
86 pa_context_flags_t,
const pa_spawn_api *);
87 static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t,
void *);
88 static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t,
void *);
89 static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *,
uint32_t, pa_sink_info_cb_t,
void *);
90 static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *,
uint32_t, pa_source_info_cb_t,
void *);
91 static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
92 static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t,
void *);
93 static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t,
void *);
94 static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
95 static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
97 static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *,
const char *,
98 const pa_sample_spec *,
const pa_channel_map *);
99 static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *,
const char *,
100 const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
101 static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *,
const char *,
102 const pa_buffer_attr *, pa_stream_flags_t);
103 static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
104 static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
105 static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
106 static int (*PULSEAUDIO_pa_stream_write) (pa_stream *,
const void *,
size_t,
107 pa_free_cb_t,
int64_t, pa_seek_mode_t);
108 static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
109 pa_stream_success_cb_t,
void *);
110 static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *,
const void **,
size_t *);
111 static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *);
112 static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
113 pa_stream_success_cb_t,
void *);
114 static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
115 static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
117 static int load_pulseaudio_syms(
void);
120 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC 122 static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
123 static void *pulseaudio_handle =
NULL;
126 load_pulseaudio_sym(
const char *fn,
void **
addr)
138 #define SDL_PULSEAUDIO_SYM(x) \ 139 if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1 142 UnloadPulseAudioLibrary(
void)
144 if (pulseaudio_handle !=
NULL) {
146 pulseaudio_handle =
NULL;
151 LoadPulseAudioLibrary(
void)
154 if (pulseaudio_handle ==
NULL) {
156 if (pulseaudio_handle ==
NULL) {
160 retval = load_pulseaudio_syms();
162 UnloadPulseAudioLibrary();
171 #define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x 174 UnloadPulseAudioLibrary(
void)
179 LoadPulseAudioLibrary(
void)
181 load_pulseaudio_syms();
189 load_pulseaudio_syms(
void)
191 SDL_PULSEAUDIO_SYM(pa_get_library_version);
192 SDL_PULSEAUDIO_SYM(pa_mainloop_new);
193 SDL_PULSEAUDIO_SYM(pa_mainloop_get_api);
194 SDL_PULSEAUDIO_SYM(pa_mainloop_iterate);
195 SDL_PULSEAUDIO_SYM(pa_mainloop_run);
196 SDL_PULSEAUDIO_SYM(pa_mainloop_quit);
197 SDL_PULSEAUDIO_SYM(pa_mainloop_free);
198 SDL_PULSEAUDIO_SYM(pa_operation_get_state);
199 SDL_PULSEAUDIO_SYM(pa_operation_cancel);
200 SDL_PULSEAUDIO_SYM(pa_operation_unref);
201 SDL_PULSEAUDIO_SYM(pa_context_new);
202 SDL_PULSEAUDIO_SYM(pa_context_connect);
203 SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
204 SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
205 SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index);
206 SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index);
207 SDL_PULSEAUDIO_SYM(pa_context_get_state);
208 SDL_PULSEAUDIO_SYM(pa_context_subscribe);
209 SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback);
210 SDL_PULSEAUDIO_SYM(pa_context_disconnect);
211 SDL_PULSEAUDIO_SYM(pa_context_unref);
212 SDL_PULSEAUDIO_SYM(pa_stream_new);
213 SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
214 SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
215 SDL_PULSEAUDIO_SYM(pa_stream_get_state);
216 SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
217 SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
218 SDL_PULSEAUDIO_SYM(pa_stream_write);
219 SDL_PULSEAUDIO_SYM(pa_stream_drain);
220 SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
221 SDL_PULSEAUDIO_SYM(pa_stream_peek);
222 SDL_PULSEAUDIO_SYM(pa_stream_drop);
223 SDL_PULSEAUDIO_SYM(pa_stream_flush);
224 SDL_PULSEAUDIO_SYM(pa_stream_unref);
225 SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
226 SDL_PULSEAUDIO_SYM(pa_strerror);
231 squashVersion(
const int major,
const int minor,
const int patch)
233 return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
240 const char *verstr = PULSEAUDIO_pa_get_library_version();
241 if (verstr !=
NULL) {
243 if (
SDL_sscanf(verstr,
"%d.%d.%d", &maj, &min, &patch) == 3) {
244 if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
249 return "SDL Application";
253 WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
258 while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) {
259 okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1,
NULL) >= 0);
261 PULSEAUDIO_pa_operation_unref(o);
266 DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *
context)
269 PULSEAUDIO_pa_context_disconnect(context);
270 PULSEAUDIO_pa_context_unref(context);
272 if (mainloop !=
NULL) {
273 PULSEAUDIO_pa_mainloop_free(mainloop);
278 ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
280 pa_mainloop *mainloop =
NULL;
281 pa_context *context =
NULL;
282 pa_mainloop_api *mainloop_api =
NULL;
289 if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) {
293 *_mainloop = mainloop;
295 mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop);
298 context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
305 if (PULSEAUDIO_pa_context_connect(context,
NULL, 0,
NULL) < 0) {
306 return SDL_SetError(
"Could not setup connection to PulseAudio");
310 if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1,
NULL) < 0) {
313 state = PULSEAUDIO_pa_context_get_state(context);
314 if (!PA_CONTEXT_IS_GOOD(state)) {
317 }
while (state != PA_CONTEXT_READY);
323 ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
325 const int retval = ConnectToPulseServer_Internal(_mainloop, _context);
327 DisconnectFromPulseServer(*_mainloop, *_context);
335 PULSEAUDIO_WaitDevice(
_THIS)
340 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
341 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
342 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
346 if (PULSEAUDIO_pa_stream_writable_size(h->
stream) >= h->
mixlen) {
353 PULSEAUDIO_PlayDevice(
_THIS)
365 PULSEAUDIO_GetDeviceBuf(
_THIS)
367 return (this->hidden->mixbuf);
372 PULSEAUDIO_CaptureFromDevice(
_THIS,
void *
buffer,
int buflen)
387 PULSEAUDIO_pa_stream_drop(h->
stream);
392 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
393 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
394 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
399 if (PULSEAUDIO_pa_stream_readable_size(h->
stream) == 0) {
404 PULSEAUDIO_pa_stream_peek(h->
stream, &data, &nbytes);
407 PULSEAUDIO_pa_stream_drop(h->
stream);
420 PULSEAUDIO_FlushCapture(
_THIS)
423 const void *data =
NULL;
427 PULSEAUDIO_pa_stream_drop(h->
stream);
433 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
434 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
435 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
440 if (PULSEAUDIO_pa_stream_readable_size(h->
stream) == 0) {
445 PULSEAUDIO_pa_stream_peek(h->
stream, &data, &nbytes);
446 PULSEAUDIO_pa_stream_drop(h->
stream);
451 PULSEAUDIO_CloseDevice(
_THIS)
453 if (this->hidden->stream) {
454 if (this->hidden->capturebuf !=
NULL) {
455 PULSEAUDIO_pa_stream_drop(this->hidden->stream);
457 PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
458 PULSEAUDIO_pa_stream_unref(this->hidden->stream);
461 DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
463 SDL_free(this->hidden->device_name);
468 SinkDeviceNameCallback(pa_context *
c,
const pa_sink_info *
i,
int is_last,
void *data)
471 char **devname = (
char **) data;
477 SourceDeviceNameCallback(pa_context *c,
const pa_source_info *i,
int is_last,
void *data)
480 char **devname = (
char **) data;
490 if (handle ==
NULL) {
496 PULSEAUDIO_pa_context_get_source_info_by_index(h->
context, idx,
500 PULSEAUDIO_pa_context_get_sink_info_by_index(h->
context, idx,
508 PULSEAUDIO_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
512 pa_sample_spec paspec;
513 pa_buffer_attr paattr;
514 pa_channel_map pacmap;
515 pa_stream_flags_t
flags = 0;
522 if (this->hidden ==
NULL) {
527 paspec.format = PA_SAMPLE_INVALID;
531 (paspec.format == PA_SAMPLE_INVALID) && test_format;) {
533 fprintf(stderr,
"Trying format 0x%4.4x\n", test_format);
535 switch (test_format) {
537 paspec.format = PA_SAMPLE_U8;
540 paspec.format = PA_SAMPLE_S16LE;
543 paspec.format = PA_SAMPLE_S16BE;
546 paspec.format = PA_SAMPLE_S32LE;
549 paspec.format = PA_SAMPLE_S32BE;
552 paspec.format = PA_SAMPLE_FLOAT32LE;
555 paspec.format = PA_SAMPLE_FLOAT32BE;
558 paspec.format = PA_SAMPLE_INVALID;
561 if (paspec.format == PA_SAMPLE_INVALID) {
565 if (paspec.format == PA_SAMPLE_INVALID) {
566 return SDL_SetError(
"Couldn't find any hardware audio formats");
571 #ifdef PA_STREAM_ADJUST_LATENCY 590 #ifdef PA_STREAM_ADJUST_LATENCY 592 paattr.tlength = h->
mixlen * 4;
594 paattr.maxlength = -1;
596 paattr.minreq = h->
mixlen;
597 flags = PA_STREAM_ADJUST_LATENCY;
599 paattr.tlength = h->
mixlen*2;
600 paattr.prebuf = h->
mixlen*2;
601 paattr.maxlength = h->
mixlen*2;
602 paattr.minreq = h->
mixlen;
606 return SDL_SetError(
"Could not connect to PulseAudio server");
609 if (!FindDeviceName(h, iscapture, handle)) {
610 return SDL_SetError(
"Requested PulseAudio sink/source missing?");
615 PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->
spec.
channels,
616 PA_CHANNEL_MAP_WAVEEX);
618 h->
stream = PULSEAUDIO_pa_stream_new(
620 "Simple DirectMedia Layer",
626 return SDL_SetError(
"Could not set up PulseAudio stream");
632 flags |= PA_STREAM_DONT_MOVE;
636 rc = PULSEAUDIO_pa_stream_connect_record(h->
stream, h->
device_name, &paattr, flags);
642 return SDL_SetError(
"Could not connect PulseAudio stream");
646 if (PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
649 state = PULSEAUDIO_pa_stream_get_state(h->
stream);
650 if (!PA_STREAM_IS_GOOD(state)) {
651 return SDL_SetError(
"Could not connect PulseAudio stream");
653 }
while (state != PA_STREAM_READY);
659 static pa_mainloop *hotplug_mainloop =
NULL;
660 static pa_context *hotplug_context =
NULL;
667 SinkInfoCallback(pa_context *c,
const pa_sink_info *i,
int is_last,
void *data)
676 SourceInfoCallback(pa_context *c,
const pa_source_info *i,
int is_last,
void *data)
680 if (i->monitor_of_sink == PA_INVALID_INDEX) {
688 HotplugCallback(pa_context *c, pa_subscription_event_type_t
t,
uint32_t idx,
void *data)
690 const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW);
691 const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE);
693 if (added || removed) {
694 const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK);
695 const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
699 PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback,
NULL);
700 }
else if (added && source) {
701 PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback,
NULL);
702 }
else if (removed && (sink || source)) {
711 HotplugThread(
void *data)
715 PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback,
NULL);
716 o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
NULL,
NULL);
717 PULSEAUDIO_pa_operation_unref(o);
718 PULSEAUDIO_pa_mainloop_run(hotplug_mainloop,
NULL);
723 PULSEAUDIO_DetectDevices()
725 WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback,
NULL));
726 WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback,
NULL));
733 PULSEAUDIO_Deinitialize(
void)
735 if (hotplug_thread) {
736 PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0);
738 hotplug_thread =
NULL;
741 DisconnectFromPulseServer(hotplug_mainloop, hotplug_context);
742 hotplug_mainloop =
NULL;
743 hotplug_context =
NULL;
745 UnloadPulseAudioLibrary();
751 if (LoadPulseAudioLibrary() < 0) {
755 if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
756 UnloadPulseAudioLibrary();
777 "pulseaudio",
"PulseAudio", PULSEAUDIO_Init, 0
GLsizei GLenum GLboolean sink
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
void(* DetectDevices)(void)
GLint GLint GLint GLint GLint x
LPDIRECTSOUNDCAPTUREBUFFER capturebuf
GLfloat GLfloat GLfloat GLfloat h
static screen_context_t context
void(* PlayDevice)(_THIS)
void(* WaitDevice)(_THIS)
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
SDL_AudioFormat SDL_NextAudioFormat(void)
SDL_Thread * SDL_CreateThreadInternal(int(*fn)(void *), const char *name, const size_t stacksize, void *data)
EGLImageKHR EGLint EGLint * handle
void SDL_RemoveAudioDevice(const int iscapture, void *handle)
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)
void(* CloseDevice)(_THIS)
void(* FlushCapture)(_THIS)
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
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
AudioBootStrap PULSEAUDIO_bootstrap
void * SDL_LoadFunction(void *handle, const char *name)
#define SDL_SetThreadPriority
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)