comparison src/audio/pulse/SDL_pulseaudio.c @ 4211:3ce5bfddbaf6 SDL-1.2

Fixed bug #572 Please merge this patch for the PA driver in SDL. http://0pointer.de/public/sdl-pulse-rework.patch This patch: - fixes buffering (i.e. reduces number of "fragments" to 2, doesn't defer filling up of the buffer until the entire buffer ran completely empty.) - drops $PASERVER and $PADEVICE env var support, since this is a duplication of $PULSE_SERVER and $PULSE_SINK which the PA libs honor anyway. This fixes the sound issues in all games I tested.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 21 Sep 2009 08:03:00 +0000
parents a1b03ba2fcd0
children 5b99971a27b4
comparison
equal deleted inserted replaced
4210:8f501bbc3bf1 4211:3ce5bfddbaf6
1 /* -*- Mode: C; c-basic-offset: 8; indent-tabs-mode: t -*- */
1 /* 2 /*
2 SDL - Simple DirectMedia Layer 3 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga 4 Copyright (C) 1997-2009 Sam Lantinga
4 5
5 This library is free software; you can redistribute it and/or 6 This library is free software; you can redistribute it and/or
16 License along with this library; if not, write to the Free Software 17 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 19
19 Stéphan Kochen 20 Stéphan Kochen
20 stephan@kochen.nl 21 stephan@kochen.nl
21 22
22 Based on parts of the ALSA and ESounD output drivers. 23 Based on parts of the ALSA and ESounD output drivers.
23 */ 24 */
24 #include "SDL_config.h" 25 #include "SDL_config.h"
25 26
26 /* Allow access to an PulseAudio network stream mixing buffer */ 27 /* Allow access to an PulseAudio network stream mixing buffer */
76 static int (*SDL_NAME(pa_simple_drain))(pa_simple *s, int *error); 77 static int (*SDL_NAME(pa_simple_drain))(pa_simple *s, int *error);
77 static int (*SDL_NAME(pa_simple_write))( 78 static int (*SDL_NAME(pa_simple_write))(
78 pa_simple *s, 79 pa_simple *s,
79 const void *data, 80 const void *data,
80 size_t length, 81 size_t length,
81 int *error 82 int *error
82 ); 83 );
83 static pa_channel_map* (*SDL_NAME(pa_channel_map_init_auto))( 84 static pa_channel_map* (*SDL_NAME(pa_channel_map_init_auto))(
84 pa_channel_map *m, 85 pa_channel_map *m,
85 unsigned channels, 86 unsigned channels,
86 pa_channel_map_def_t def 87 pa_channel_map_def_t def
87 ); 88 );
88 89
89 90
90 static struct { 91 static struct {
91 const char *name; 92 const char *name;
92 void **func; 93 void **func;
93 } pulse_functions[] = { 94 } pulse_functions[] = {
156 157
157 available = 0; 158 available = 0;
158 if ( LoadPulseLibrary() < 0 ) { 159 if ( LoadPulseLibrary() < 0 ) {
159 return available; 160 return available;
160 } 161 }
161 162
162 /* Connect with a dummy format. */ 163 /* Connect with a dummy format. */
163 paspec.format = PA_SAMPLE_U8; 164 paspec.format = PA_SAMPLE_U8;
164 paspec.rate = 11025; 165 paspec.rate = 11025;
165 paspec.channels = 1; 166 paspec.channels = 1;
166 connection = SDL_NAME(pa_simple_new)( 167 connection = SDL_NAME(pa_simple_new)(
167 SDL_getenv("PASERVER"), /* server */ 168 NULL, /* server */
168 "Test stream", /* application name */ 169 "Test stream", /* application name */
169 PA_STREAM_PLAYBACK, /* playback mode */ 170 PA_STREAM_PLAYBACK, /* playback mode */
170 SDL_getenv("PADEVICE"), /* device on the server */ 171 NULL, /* device on the server */
171 "Simple DirectMedia Layer", /* stream description */ 172 "Simple DirectMedia Layer", /* stream description */
172 &paspec, /* sample format spec */ 173 &paspec, /* sample format spec */
173 NULL, /* channel map */ 174 NULL, /* channel map */
174 NULL, /* buffering attributes */ 175 NULL, /* buffering attributes */
175 NULL /* error code */ 176 NULL /* error code */
176 ); 177 );
177 if ( connection != NULL ) { 178 if ( connection != NULL ) {
178 available = 1; 179 available = 1;
179 SDL_NAME(pa_simple_free)(connection); 180 SDL_NAME(pa_simple_free)(connection);
180 } 181 }
181 182
182 UnloadPulseLibrary(); 183 UnloadPulseLibrary();
183 return(available); 184 return(available);
184 } 185 }
185 186
186 static void Audio_DeleteDevice(SDL_AudioDevice *device) 187 static void Audio_DeleteDevice(SDL_AudioDevice *device)
231 /* This function waits until it is possible to write a full sound buffer */ 232 /* This function waits until it is possible to write a full sound buffer */
232 static void PULSE_WaitAudio(_THIS) 233 static void PULSE_WaitAudio(_THIS)
233 { 234 {
234 /* Check to see if the thread-parent process is still alive */ 235 /* Check to see if the thread-parent process is still alive */
235 { static int cnt = 0; 236 { static int cnt = 0;
236 /* Note that this only works with thread implementations 237 /* Note that this only works with thread implementations
237 that use a different process id for each thread. 238 that use a different process id for each thread.
238 */ 239 */
239 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */ 240 if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
240 if ( kill(parent, 0) < 0 ) { 241 if ( kill(parent, 0) < 0 ) {
241 this->enabled = 0; 242 this->enabled = 0;
300 { 301 {
301 Uint16 test_format; 302 Uint16 test_format;
302 pa_sample_spec paspec; 303 pa_sample_spec paspec;
303 pa_buffer_attr paattr; 304 pa_buffer_attr paattr;
304 pa_channel_map pacmap; 305 pa_channel_map pacmap;
305 306
306 paspec.format = PA_SAMPLE_INVALID; 307 paspec.format = PA_SAMPLE_INVALID;
307 for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) { 308 for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) {
308 switch ( test_format ) { 309 switch ( test_format ) {
309 case AUDIO_U8: 310 case AUDIO_U8:
310 paspec.format = PA_SAMPLE_U8; 311 paspec.format = PA_SAMPLE_U8;
322 if (paspec.format == PA_SAMPLE_INVALID ) { 323 if (paspec.format == PA_SAMPLE_INVALID ) {
323 SDL_SetError("Couldn't find any suitable audio formats"); 324 SDL_SetError("Couldn't find any suitable audio formats");
324 return(-1); 325 return(-1);
325 } 326 }
326 spec->format = test_format; 327 spec->format = test_format;
327 328
328 paspec.channels = spec->channels; 329 paspec.channels = spec->channels;
329 paspec.rate = spec->freq; 330 paspec.rate = spec->freq;
330 331
331 /* Calculate the final parameters for this audio specification */ 332 /* Calculate the final parameters for this audio specification */
332 SDL_CalculateAudioSpec(spec); 333 SDL_CalculateAudioSpec(spec);
336 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); 337 mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
337 if ( mixbuf == NULL ) { 338 if ( mixbuf == NULL ) {
338 return(-1); 339 return(-1);
339 } 340 }
340 SDL_memset(mixbuf, spec->silence, spec->size); 341 SDL_memset(mixbuf, spec->silence, spec->size);
341 342
342 /* Reduced prebuffering compared to the defaults. */ 343 /* Reduced prebuffering compared to the defaults. */
343 paattr.tlength = mixlen; 344 paattr.tlength = mixlen*2;
344 paattr.minreq = mixlen; 345 paattr.minreq = mixlen;
345 paattr.fragsize = mixlen; 346 paattr.prebuf = mixlen*2;
346 paattr.prebuf = mixlen; 347 paattr.maxlength = mixlen*2;
347 paattr.maxlength = mixlen * 4; 348
348
349 /* The SDL ALSA output hints us that we use Windows' channel mapping */ 349 /* The SDL ALSA output hints us that we use Windows' channel mapping */
350 /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */ 350 /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
351 SDL_NAME(pa_channel_map_init_auto)( 351 SDL_NAME(pa_channel_map_init_auto)(
352 &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX); 352 &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX);
353 353
354 /* Connect to the PulseAudio server */ 354 /* Connect to the PulseAudio server */
355 stream = SDL_NAME(pa_simple_new)( 355 stream = SDL_NAME(pa_simple_new)(
356 SDL_getenv("PASERVER"), /* server */ 356 NULL, /* server */
357 get_progname(), /* application name */ 357 get_progname(), /* application name */
358 PA_STREAM_PLAYBACK, /* playback mode */ 358 PA_STREAM_PLAYBACK, /* playback mode */
359 SDL_getenv("PADEVICE"), /* device on the server */ 359 NULL, /* device on the server */
360 "Simple DirectMedia Layer", /* stream description */ 360 "Simple DirectMedia Layer", /* stream description */
361 &paspec, /* sample format spec */ 361 &paspec, /* sample format spec */
362 &pacmap, /* channel map */ 362 &pacmap, /* channel map */
363 &paattr, /* buffering attributes */ 363 &paattr, /* buffering attributes */
364 NULL /* error code */ 364 NULL /* error code */
369 return(-1); 369 return(-1);
370 } 370 }
371 371
372 /* Get the parent process id (we're the parent of the audio thread) */ 372 /* Get the parent process id (we're the parent of the audio thread) */
373 parent = getpid(); 373 parent = getpid();
374 374
375 return(0); 375 return(0);
376 } 376 }
377