src/audio/pulseaudio/SDL_pulseaudio.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Oct 2013 21:56:15 -0700
changeset 7860 2b0bcdea3a79
parent 7719 31b5f9ff36ca
child 8093 b43765095a6f
permissions -rw-r--r--
Fixed bug 2129 - fix for bug 2121 breaks linking for mingw and throws multiple warnings

Andreas Ertelt

The problem in question is caused by changeset 7771 (http://hg.libsdl.org/SDL/rev/4434498bf4b9 / https://bugzilla.libsdl.org/show_bug.cgi?id=2121)

The redefinition of __inline__ (introduced by the addition of begin_code.h:128's "|| __STRICT_ANSI__") results in mingw's gcc throwing multiple

warning: always_inline function might not be inlinable [-Wattributes]

as well as a whole bunch of redefinitions of mingw internals which break linking of projects including the SDL2 headers.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /*
    23   The PulseAudio target for SDL 1.3 is based on the 1.3 arts target, with
    24    the appropriate parts replaced with the 1.2 PulseAudio target code. This
    25    was the cleanest way to move it to 1.3. The 1.2 target was written by
    26    St├ęphan Kochen: stephan .a.t. kochen.nl
    27 */
    28 #include "SDL_config.h"
    29 
    30 #if SDL_AUDIO_DRIVER_PULSEAUDIO
    31 
    32 /* Allow access to a raw mixing buffer */
    33 
    34 #ifdef HAVE_SIGNAL_H
    35 #include <signal.h>
    36 #endif
    37 #include <unistd.h>
    38 #include <sys/types.h>
    39 #include <errno.h>
    40 #include <pulse/pulseaudio.h>
    41 #include <pulse/simple.h>
    42 
    43 #include "SDL_timer.h"
    44 #include "SDL_audio.h"
    45 #include "../SDL_audiomem.h"
    46 #include "../SDL_audio_c.h"
    47 #include "SDL_pulseaudio.h"
    48 #include "SDL_loadso.h"
    49 
    50 #if (PA_API_VERSION < 12)
    51 /** Return non-zero if the passed state is one of the connected states */
    52 static SDL_INLINE int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
    53     return
    54         x == PA_CONTEXT_CONNECTING ||
    55         x == PA_CONTEXT_AUTHORIZING ||
    56         x == PA_CONTEXT_SETTING_NAME ||
    57         x == PA_CONTEXT_READY;
    58 }
    59 /** Return non-zero if the passed state is one of the connected states */
    60 static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
    61     return
    62         x == PA_STREAM_CREATING ||
    63         x == PA_STREAM_READY;
    64 }
    65 #endif /* pulseaudio <= 0.9.10 */
    66 
    67 
    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 *);
    80 
    81 static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
    82     pa_operation *);
    83 static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
    84 static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
    85 
    86 static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
    87     const char *);
    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 *);
    93 
    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 *);
   106 
   107 static int load_pulseaudio_syms(void);
   108 
   109 
   110 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
   111 
   112 static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
   113 static void *pulseaudio_handle = NULL;
   114 
   115 static int
   116 load_pulseaudio_sym(const char *fn, void **addr)
   117 {
   118     *addr = SDL_LoadFunction(pulseaudio_handle, fn);
   119     if (*addr == NULL) {
   120         /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
   121         return 0;
   122     }
   123 
   124     return 1;
   125 }
   126 
   127 /* cast funcs to char* first, to please GCC's strict aliasing rules. */
   128 #define SDL_PULSEAUDIO_SYM(x) \
   129     if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1
   130 
   131 static void
   132 UnloadPulseAudioLibrary(void)
   133 {
   134     if (pulseaudio_handle != NULL) {
   135         SDL_UnloadObject(pulseaudio_handle);
   136         pulseaudio_handle = NULL;
   137     }
   138 }
   139 
   140 static int
   141 LoadPulseAudioLibrary(void)
   142 {
   143     int retval = 0;
   144     if (pulseaudio_handle == NULL) {
   145         pulseaudio_handle = SDL_LoadObject(pulseaudio_library);
   146         if (pulseaudio_handle == NULL) {
   147             retval = -1;
   148             /* Don't call SDL_SetError(): SDL_LoadObject already did. */
   149         } else {
   150             retval = load_pulseaudio_syms();
   151             if (retval < 0) {
   152                 UnloadPulseAudioLibrary();
   153             }
   154         }
   155     }
   156     return retval;
   157 }
   158 
   159 #else
   160 
   161 #define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x
   162 
   163 static void
   164 UnloadPulseAudioLibrary(void)
   165 {
   166 }
   167 
   168 static int
   169 LoadPulseAudioLibrary(void)
   170 {
   171     load_pulseaudio_syms();
   172     return 0;
   173 }
   174 
   175 #endif /* SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC */
   176 
   177 
   178 static int
   179 load_pulseaudio_syms(void)
   180 {
   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);
   206     return 0;
   207 }
   208 
   209 
   210 /* Check to see if we can connect to PulseAudio */
   211 static SDL_bool
   212 CheckPulseAudioAvailable()
   213 {
   214     pa_simple *s;
   215     pa_sample_spec ss;
   216 
   217     ss.format = PA_SAMPLE_S16NE;
   218     ss.channels = 1;
   219     ss.rate = 22050;
   220 
   221     s = PULSEAUDIO_pa_simple_new(NULL, "SDL", PA_STREAM_PLAYBACK, NULL,
   222                                  "Test", &ss, NULL, NULL, NULL);
   223     if (s) {
   224         PULSEAUDIO_pa_simple_free(s);
   225         return SDL_TRUE;
   226     } else {
   227         return SDL_FALSE;
   228     }
   229 }
   230 
   231 /* This function waits until it is possible to write a full sound buffer */
   232 static void
   233 PULSEAUDIO_WaitDevice(_THIS)
   234 {
   235     struct SDL_PrivateAudioData *h = this->hidden;
   236 
   237     while(1) {
   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) {
   241             this->enabled = 0;
   242             return;
   243         }
   244         if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
   245             return;
   246         }
   247     }
   248 }
   249 
   250 static void
   251 PULSEAUDIO_PlayDevice(_THIS)
   252 {
   253     /* Write the audio data */
   254     struct SDL_PrivateAudioData *h = this->hidden;
   255     if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL,
   256                                    PA_SEEK_RELATIVE) < 0) {
   257         this->enabled = 0;
   258     }
   259 }
   260 
   261 static void
   262 stream_drain_complete(pa_stream *s, int success, void *userdata)
   263 {
   264     /* no-op for pa_stream_drain() to use for callback. */
   265 }
   266 
   267 static void
   268 PULSEAUDIO_WaitDone(_THIS)
   269 {
   270     struct SDL_PrivateAudioData *h = this->hidden;
   271     pa_operation *o;
   272 
   273     o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL);
   274     if (!o) {
   275         return;
   276     }
   277 
   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);
   283             break;
   284         }
   285     }
   286 
   287     PULSEAUDIO_pa_operation_unref(o);
   288 }
   289 
   290 
   291 
   292 static Uint8 *
   293 PULSEAUDIO_GetDeviceBuf(_THIS)
   294 {
   295     return (this->hidden->mixbuf);
   296 }
   297 
   298 
   299 static void
   300 PULSEAUDIO_CloseDevice(_THIS)
   301 {
   302     if (this->hidden != NULL) {
   303         SDL_FreeAudioMem(this->hidden->mixbuf);
   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;
   309         }
   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;
   314         }
   315         if (this->hidden->mainloop != NULL) {
   316             PULSEAUDIO_pa_mainloop_free(this->hidden->mainloop);
   317             this->hidden->mainloop = NULL;
   318         }
   319         SDL_free(this->hidden);
   320         this->hidden = NULL;
   321     }
   322 }
   323 
   324 
   325 static SDL_INLINE int
   326 squashVersion(const int major, const int minor, const int patch)
   327 {
   328     return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
   329 }
   330 
   331 /* Workaround for older pulse: pa_context_new() must have non-NULL appname */
   332 static const char *
   333 getAppName(void)
   334 {
   335     const char *verstr = PULSEAUDIO_pa_get_library_version();
   336     if (verstr != NULL) {
   337         int maj, min, patch;
   338         if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
   339             if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
   340                 return NULL;  /* 0.9.15+ handles NULL correctly. */
   341             }
   342         }
   343     }
   344     return "SDL Application";  /* oh well. */
   345 }
   346 
   347 static int
   348 PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
   349 {
   350     struct SDL_PrivateAudioData *h = NULL;
   351     Uint16 test_format = 0;
   352     pa_sample_spec paspec;
   353     pa_buffer_attr paattr;
   354     pa_channel_map pacmap;
   355     pa_stream_flags_t flags = 0;
   356     int state = 0;
   357 
   358     /* Initialize all variables that we clean on shutdown */
   359     this->hidden = (struct SDL_PrivateAudioData *)
   360         SDL_malloc((sizeof *this->hidden));
   361     if (this->hidden == NULL) {
   362         return SDL_OutOfMemory();
   363     }
   364     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   365     h = this->hidden;
   366 
   367     paspec.format = PA_SAMPLE_INVALID;
   368 
   369     /* Try for a closest match on audio format */
   370     for (test_format = SDL_FirstAudioFormat(this->spec.format);
   371          (paspec.format == PA_SAMPLE_INVALID) && test_format;) {
   372 #ifdef DEBUG_AUDIO
   373         fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
   374 #endif
   375         switch (test_format) {
   376         case AUDIO_U8:
   377             paspec.format = PA_SAMPLE_U8;
   378             break;
   379         case AUDIO_S16LSB:
   380             paspec.format = PA_SAMPLE_S16LE;
   381             break;
   382         case AUDIO_S16MSB:
   383             paspec.format = PA_SAMPLE_S16BE;
   384             break;
   385         case AUDIO_S32LSB:
   386             paspec.format = PA_SAMPLE_S32LE;
   387             break;
   388         case AUDIO_S32MSB:
   389             paspec.format = PA_SAMPLE_S32BE;
   390             break;
   391         case AUDIO_F32LSB:
   392             paspec.format = PA_SAMPLE_FLOAT32LE;
   393             break;
   394         case AUDIO_F32MSB:
   395             paspec.format = PA_SAMPLE_FLOAT32BE;
   396             break;
   397         default:
   398             paspec.format = PA_SAMPLE_INVALID;
   399             break;
   400         }
   401         if (paspec.format == PA_SAMPLE_INVALID) {
   402             test_format = SDL_NextAudioFormat();
   403         }
   404     }
   405     if (paspec.format == PA_SAMPLE_INVALID) {
   406         PULSEAUDIO_CloseDevice(this);
   407         return SDL_SetError("Couldn't find any hardware audio formats");
   408     }
   409     this->spec.format = test_format;
   410 
   411     /* Calculate the final parameters for this audio specification */
   412 #ifdef PA_STREAM_ADJUST_LATENCY
   413     this->spec.samples /= 2; /* Mix in smaller chunck to avoid underruns */
   414 #endif
   415     SDL_CalculateAudioSpec(&this->spec);
   416 
   417     /* Allocate mixing buffer */
   418     h->mixlen = this->spec.size;
   419     h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen);
   420     if (h->mixbuf == NULL) {
   421         PULSEAUDIO_CloseDevice(this);
   422         return SDL_OutOfMemory();
   423     }
   424     SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
   425 
   426     paspec.channels = this->spec.channels;
   427     paspec.rate = this->spec.freq;
   428 
   429     /* Reduced prebuffering compared to the defaults. */
   430 #ifdef PA_STREAM_ADJUST_LATENCY
   431     /* 2x original requested bufsize */
   432     paattr.tlength = h->mixlen * 4;
   433     paattr.prebuf = -1;
   434     paattr.maxlength = -1;
   435     /* -1 can lead to pa_stream_writable_size() >= mixlen never being true */
   436     paattr.minreq = h->mixlen;
   437     flags = PA_STREAM_ADJUST_LATENCY;
   438 #else
   439     paattr.tlength = h->mixlen*2;
   440     paattr.prebuf = h->mixlen*2;
   441     paattr.maxlength = h->mixlen*2;
   442     paattr.minreq = h->mixlen;
   443 #endif
   444 
   445     /* The SDL ALSA output hints us that we use Windows' channel mapping */
   446     /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
   447     PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
   448                                         PA_CHANNEL_MAP_WAVEEX);
   449 
   450     /* Set up a new main loop */
   451     if (!(h->mainloop = PULSEAUDIO_pa_mainloop_new())) {
   452         PULSEAUDIO_CloseDevice(this);
   453         return SDL_SetError("pa_mainloop_new() failed");
   454     }
   455 
   456     h->mainloop_api = PULSEAUDIO_pa_mainloop_get_api(h->mainloop);
   457     h->context = PULSEAUDIO_pa_context_new(h->mainloop_api, getAppName());
   458     if (!h->context) {
   459         PULSEAUDIO_CloseDevice(this);
   460         return SDL_SetError("pa_context_new() failed");
   461     }
   462 
   463     /* Connect to the PulseAudio server */
   464     if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) {
   465         PULSEAUDIO_CloseDevice(this);
   466         return SDL_SetError("Could not setup connection to PulseAudio");
   467     }
   468 
   469     do {
   470         if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
   471             PULSEAUDIO_CloseDevice(this);
   472             return SDL_SetError("pa_mainloop_iterate() failed");
   473         }
   474         state = PULSEAUDIO_pa_context_get_state(h->context);
   475         if (!PA_CONTEXT_IS_GOOD(state)) {
   476             PULSEAUDIO_CloseDevice(this);
   477             return SDL_SetError("Could not connect to PulseAudio");
   478         }
   479     } while (state != PA_CONTEXT_READY);
   480 
   481     h->stream = PULSEAUDIO_pa_stream_new(
   482         h->context,
   483         "Simple DirectMedia Layer", /* stream description */
   484         &paspec,    /* sample format spec */
   485         &pacmap     /* channel map */
   486         );
   487 
   488     if (h->stream == NULL) {
   489         PULSEAUDIO_CloseDevice(this);
   490         return SDL_SetError("Could not set up PulseAudio stream");
   491     }
   492 
   493     if (PULSEAUDIO_pa_stream_connect_playback(h->stream, NULL, &paattr, flags,
   494             NULL, NULL) < 0) {
   495         PULSEAUDIO_CloseDevice(this);
   496         return SDL_SetError("Could not connect PulseAudio stream");
   497     }
   498 
   499     do {
   500         if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
   501             PULSEAUDIO_CloseDevice(this);
   502             return SDL_SetError("pa_mainloop_iterate() failed");
   503         }
   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");
   508         }
   509     } while (state != PA_STREAM_READY);
   510 
   511     /* We're ready to rock and roll. :-) */
   512     return 0;
   513 }
   514 
   515 
   516 static void
   517 PULSEAUDIO_Deinitialize(void)
   518 {
   519     UnloadPulseAudioLibrary();
   520 }
   521 
   522 static int
   523 PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
   524 {
   525     if (LoadPulseAudioLibrary() < 0) {
   526         return 0;
   527     }
   528 
   529     if (!CheckPulseAudioAvailable()) {
   530         UnloadPulseAudioLibrary();
   531         return 0;
   532     }
   533 
   534     /* Set the function pointers */
   535     impl->OpenDevice = PULSEAUDIO_OpenDevice;
   536     impl->PlayDevice = PULSEAUDIO_PlayDevice;
   537     impl->WaitDevice = PULSEAUDIO_WaitDevice;
   538     impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
   539     impl->CloseDevice = PULSEAUDIO_CloseDevice;
   540     impl->WaitDone = PULSEAUDIO_WaitDone;
   541     impl->Deinitialize = PULSEAUDIO_Deinitialize;
   542     impl->OnlyHasDefaultOutputDevice = 1;
   543 
   544     return 1;   /* this audio target is available. */
   545 }
   546 
   547 
   548 AudioBootStrap PULSEAUDIO_bootstrap = {
   549     "pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0
   550 };
   551 
   552 #endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
   553 
   554 /* vi: set ts=4 sw=4 expandtab: */