30 #if SDL_AUDIO_DRIVER_PULSEAUDIO
40 #include <pulse/pulseaudio.h>
41 #include <pulse/simple.h>
45 #include "../SDL_audiomem.h"
46 #include "../SDL_audio_c.h"
50 #if (PA_API_VERSION < 12)
52 static __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 __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_simple *(*PULSEAUDIO_pa_simple_new) (
const char *,
const char *,
70 pa_stream_direction_t,
const char *,
const char *,
const pa_sample_spec *,
71 const pa_channel_map *,
const pa_buffer_attr *,
int *);
72 static void (*PULSEAUDIO_pa_simple_free) (pa_simple *);
73 static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) (
74 pa_channel_map *, unsigned, pa_channel_map_def_t);
75 static const char * (*PULSEAUDIO_pa_strerror) (
int);
76 static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (
void);
77 static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *);
78 static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *,
int,
int *);
79 static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
81 static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
83 static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
84 static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
86 static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
88 static int (*PULSEAUDIO_pa_context_connect) (pa_context *,
const char *,
89 pa_context_flags_t,
const pa_spawn_api *);
90 static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
91 static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
92 static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
94 static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *,
const char *,
95 const pa_sample_spec *,
const pa_channel_map *);
96 static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *,
const char *,
97 const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
98 static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
99 static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
100 static int (*PULSEAUDIO_pa_stream_write) (pa_stream *,
const void *,
size_t,
101 pa_free_cb_t,
int64_t, pa_seek_mode_t);
102 static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
103 pa_stream_success_cb_t,
void *);
104 static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
105 static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
107 static int load_pulseaudio_syms(
void);
110 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
112 static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
113 static void *pulseaudio_handle =
NULL;
116 load_pulseaudio_sym(
const char *fn,
void **
addr)
128 #define SDL_PULSEAUDIO_SYM(x) \
129 if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1
132 UnloadPulseAudioLibrary(
void)
134 if (pulseaudio_handle !=
NULL) {
136 pulseaudio_handle =
NULL;
141 LoadPulseAudioLibrary(
void)
144 if (pulseaudio_handle ==
NULL) {
146 if (pulseaudio_handle ==
NULL) {
150 retval = load_pulseaudio_syms();
152 UnloadPulseAudioLibrary();
161 #define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x
164 UnloadPulseAudioLibrary(
void)
169 LoadPulseAudioLibrary(
void)
171 load_pulseaudio_syms();
179 load_pulseaudio_syms(
void)
181 SDL_PULSEAUDIO_SYM(pa_get_library_version);
182 SDL_PULSEAUDIO_SYM(pa_simple_new);
183 SDL_PULSEAUDIO_SYM(pa_simple_free);
184 SDL_PULSEAUDIO_SYM(pa_mainloop_new);
185 SDL_PULSEAUDIO_SYM(pa_mainloop_get_api);
186 SDL_PULSEAUDIO_SYM(pa_mainloop_iterate);
187 SDL_PULSEAUDIO_SYM(pa_mainloop_free);
188 SDL_PULSEAUDIO_SYM(pa_operation_get_state);
189 SDL_PULSEAUDIO_SYM(pa_operation_cancel);
190 SDL_PULSEAUDIO_SYM(pa_operation_unref);
191 SDL_PULSEAUDIO_SYM(pa_context_new);
192 SDL_PULSEAUDIO_SYM(pa_context_connect);
193 SDL_PULSEAUDIO_SYM(pa_context_get_state);
194 SDL_PULSEAUDIO_SYM(pa_context_disconnect);
195 SDL_PULSEAUDIO_SYM(pa_context_unref);
196 SDL_PULSEAUDIO_SYM(pa_stream_new);
197 SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
198 SDL_PULSEAUDIO_SYM(pa_stream_get_state);
199 SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
200 SDL_PULSEAUDIO_SYM(pa_stream_write);
201 SDL_PULSEAUDIO_SYM(pa_stream_drain);
202 SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
203 SDL_PULSEAUDIO_SYM(pa_stream_unref);
204 SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
205 SDL_PULSEAUDIO_SYM(pa_strerror);
212 CheckPulseAudioAvailable()
217 ss.format = PA_SAMPLE_S16NE;
221 s = PULSEAUDIO_pa_simple_new(
NULL,
"SDL", PA_STREAM_PLAYBACK,
NULL,
224 PULSEAUDIO_pa_simple_free(s);
233 PULSEAUDIO_WaitDevice(
_THIS)
238 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
239 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
240 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
244 if (PULSEAUDIO_pa_stream_writable_size(h->
stream) >= h->
mixlen) {
251 PULSEAUDIO_PlayDevice(
_THIS)
256 PA_SEEK_RELATIVE) < 0) {
262 stream_drain_complete(pa_stream *s,
int success,
void *userdata)
268 PULSEAUDIO_WaitDone(
_THIS)
273 o = PULSEAUDIO_pa_stream_drain(h->
stream, stream_drain_complete,
NULL);
278 while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) {
279 if (PULSEAUDIO_pa_context_get_state(h->
context) != PA_CONTEXT_READY ||
280 PULSEAUDIO_pa_stream_get_state(h->
stream) != PA_STREAM_READY ||
281 PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
282 PULSEAUDIO_pa_operation_cancel(o);
287 PULSEAUDIO_pa_operation_unref(o);
293 PULSEAUDIO_GetDeviceBuf(
_THIS)
295 return (this->hidden->mixbuf);
300 PULSEAUDIO_CloseDevice(
_THIS)
302 if (this->hidden !=
NULL) {
304 this->hidden->mixbuf =
NULL;
305 if (this->hidden->stream) {
306 PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
307 PULSEAUDIO_pa_stream_unref(this->hidden->stream);
308 this->hidden->stream =
NULL;
310 if (this->hidden->context !=
NULL) {
311 PULSEAUDIO_pa_context_disconnect(this->hidden->context);
312 PULSEAUDIO_pa_context_unref(this->hidden->context);
313 this->hidden->context =
NULL;
315 if (this->hidden->mainloop !=
NULL) {
316 PULSEAUDIO_pa_mainloop_free(this->hidden->mainloop);
317 this->hidden->mainloop =
NULL;
326 squashVersion(
const int major,
const int minor,
const int patch)
328 return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
335 const char *verstr = PULSEAUDIO_pa_get_library_version();
336 if (verstr !=
NULL) {
338 if (
SDL_sscanf(verstr,
"%d.%d.%d", &maj, &min, &patch) == 3) {
339 if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
344 return "SDL Application";
352 pa_sample_spec paspec;
353 pa_buffer_attr paattr;
354 pa_channel_map pacmap;
355 pa_stream_flags_t
flags = 0;
361 if (this->hidden ==
NULL) {
364 SDL_memset(this->hidden, 0, (
sizeof *this->hidden));
367 paspec.format = PA_SAMPLE_INVALID;
371 (paspec.format == PA_SAMPLE_INVALID) && test_format;) {
373 fprintf(stderr,
"Trying format 0x%4.4x\n", test_format);
375 switch (test_format) {
377 paspec.format = PA_SAMPLE_U8;
380 paspec.format = PA_SAMPLE_S16LE;
383 paspec.format = PA_SAMPLE_S16BE;
386 paspec.format = PA_SAMPLE_S32LE;
389 paspec.format = PA_SAMPLE_S32BE;
392 paspec.format = PA_SAMPLE_FLOAT32LE;
395 paspec.format = PA_SAMPLE_FLOAT32BE;
398 paspec.format = PA_SAMPLE_INVALID;
401 if (paspec.format == PA_SAMPLE_INVALID) {
405 if (paspec.format == PA_SAMPLE_INVALID) {
406 PULSEAUDIO_CloseDevice(
this);
407 return SDL_SetError(
"Couldn't find any hardware audio formats");
409 this->spec.format = test_format;
412 #ifdef PA_STREAM_ADJUST_LATENCY
413 this->spec.samples /= 2;
418 h->
mixlen = this->spec.size;
421 PULSEAUDIO_CloseDevice(
this);
426 paspec.channels = this->spec.channels;
427 paspec.rate = this->spec.freq;
430 #ifdef PA_STREAM_ADJUST_LATENCY
432 paattr.tlength = h->
mixlen * 4;
434 paattr.maxlength = -1;
436 paattr.minreq = h->
mixlen;
437 flags = PA_STREAM_ADJUST_LATENCY;
439 paattr.tlength = h->
mixlen*2;
440 paattr.prebuf = h->
mixlen*2;
441 paattr.maxlength = h->
mixlen*2;
442 paattr.minreq = h->
mixlen;
447 PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
448 PA_CHANNEL_MAP_WAVEEX);
451 if (!(h->
mainloop = PULSEAUDIO_pa_mainloop_new())) {
452 PULSEAUDIO_CloseDevice(
this);
459 PULSEAUDIO_CloseDevice(
this);
465 PULSEAUDIO_CloseDevice(
this);
466 return SDL_SetError(
"Could not setup connection to PulseAudio");
470 if (PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
471 PULSEAUDIO_CloseDevice(
this);
474 state = PULSEAUDIO_pa_context_get_state(h->
context);
475 if (!PA_CONTEXT_IS_GOOD(state)) {
476 PULSEAUDIO_CloseDevice(
this);
479 }
while (state != PA_CONTEXT_READY);
481 h->
stream = PULSEAUDIO_pa_stream_new(
483 "Simple DirectMedia Layer",
489 PULSEAUDIO_CloseDevice(
this);
490 return SDL_SetError(
"Could not set up PulseAudio stream");
493 if (PULSEAUDIO_pa_stream_connect_playback(h->
stream,
NULL, &paattr, flags,
495 PULSEAUDIO_CloseDevice(
this);
496 return SDL_SetError(
"Could not connect PulseAudio stream");
500 if (PULSEAUDIO_pa_mainloop_iterate(h->
mainloop, 1,
NULL) < 0) {
501 PULSEAUDIO_CloseDevice(
this);
504 state = PULSEAUDIO_pa_stream_get_state(h->
stream);
505 if (!PA_STREAM_IS_GOOD(state)) {
506 PULSEAUDIO_CloseDevice(
this);
507 return SDL_SetError(
"Could not create to PulseAudio stream");
509 }
while (state != PA_STREAM_READY);
517 PULSEAUDIO_Deinitialize(
void)
519 UnloadPulseAudioLibrary();
525 if (LoadPulseAudioLibrary() < 0) {
529 if (!CheckPulseAudioAvailable()) {
530 UnloadPulseAudioLibrary();
540 impl->
WaitDone = PULSEAUDIO_WaitDone;
549 "pulseaudio",
"PulseAudio", PULSEAUDIO_Init, 0
void(* CloseDevice)(_THIS)
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
GLfloat GLfloat GLfloat GLfloat h
AudioBootStrap PULSEAUDIO_bootstrap
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
void(* WaitDevice)(_THIS)
GLenum GLsizei const GLuint GLboolean enabled
Uint8 *(* GetDeviceBuf)(_THIS)
DECLSPEC void SDLCALL SDL_free(void *mem)
DECLSPEC int SDLCALL SDL_sscanf(const char *text, const char *fmt,...)
int(* OpenDevice)(_THIS, const char *devname, int iscapture)
SDL_AudioFormat SDL_NextAudioFormat(void)
void(* PlayDevice)(_THIS)
int OnlyHasDefaultOutputDevice
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
pa_mainloop_api * mainloop_api
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
void(* Deinitialize)(void)
#define SDL_AllocAudioMem
#define SDL_OutOfMemory()
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
uint8_t Uint8
An unsigned 8-bit integer type.
uint16_t Uint16
An unsigned 16-bit integer type.
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)