Mercurial > sdl-ios-xcode
comparison src/audio/alsa/SDL_alsa_audio.c @ 3627:631173ffd68f
Merged r4991:5154 from branches/SDL-1.2/src/audio/alsa: many 1.2.14 ALSA fixes.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sun, 10 Jan 2010 07:40:12 +0000 |
parents | 4e83cdb58134 |
children | f7b03b6838cb |
comparison
equal
deleted
inserted
replaced
3626:596468a8459e | 3627:631173ffd68f |
---|---|
39 #endif | 39 #endif |
40 | 40 |
41 /* The tag name used by ALSA audio */ | 41 /* The tag name used by ALSA audio */ |
42 #define DRIVER_NAME "alsa" | 42 #define DRIVER_NAME "alsa" |
43 | 43 |
44 /* The default ALSA audio driver */ | |
45 #define DEFAULT_DEVICE "default" | |
46 | |
47 static int (*ALSA_snd_pcm_open) | 44 static int (*ALSA_snd_pcm_open) |
48 (snd_pcm_t **, const char *, snd_pcm_stream_t, int); | 45 (snd_pcm_t **, const char *, snd_pcm_stream_t, int); |
49 static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm); | 46 static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm); |
50 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) | 47 static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) |
51 (snd_pcm_t *, const void *, snd_pcm_uframes_t); | 48 (snd_pcm_t *, const void *, snd_pcm_uframes_t); |
52 static int (*ALSA_snd_pcm_resume) (snd_pcm_t *); | 49 static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int); |
53 static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *); | 50 static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *); |
54 static int (*ALSA_snd_pcm_drain) (snd_pcm_t *); | 51 static int (*ALSA_snd_pcm_drain) (snd_pcm_t *); |
55 static const char *(*ALSA_snd_strerror) (int); | 52 static const char *(*ALSA_snd_strerror) (int); |
56 static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void); | 53 static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void); |
57 static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void); | 54 static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void); |
55 static void (*ALSA_snd_pcm_hw_params_copy) | |
56 (snd_pcm_hw_params_t *, const snd_pcm_hw_params_t *); | |
58 static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *); | 57 static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *); |
59 static int (*ALSA_snd_pcm_hw_params_set_access) | 58 static int (*ALSA_snd_pcm_hw_params_set_access) |
60 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t); | 59 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t); |
61 static int (*ALSA_snd_pcm_hw_params_set_format) | 60 static int (*ALSA_snd_pcm_hw_params_set_format) |
62 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t); | 61 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t); |
63 static int (*ALSA_snd_pcm_hw_params_set_channels) | 62 static int (*ALSA_snd_pcm_hw_params_set_channels) |
64 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int); | 63 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int); |
64 static int (*ALSA_snd_pcm_hw_params_get_channels) | |
65 (const snd_pcm_hw_params_t *, unsigned int *); | |
65 static int (*ALSA_snd_pcm_hw_params_set_rate_near) | 66 static int (*ALSA_snd_pcm_hw_params_set_rate_near) |
66 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); | 67 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); |
67 static int (*ALSA_snd_pcm_hw_params_set_period_size_near) | 68 static int (*ALSA_snd_pcm_hw_params_set_period_size_near) |
68 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *); | 69 (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *); |
69 static int (*ALSA_snd_pcm_hw_params_get_channels) | 70 static int (*ALSA_snd_pcm_hw_params_get_period_size) |
70 (const snd_pcm_hw_params_t *, unsigned int *); | 71 (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *); |
71 static snd_pcm_sframes_t(*ALSA_snd_pcm_hw_params_get_period_size) | |
72 (const snd_pcm_hw_params_t *); | |
73 static int (*ALSA_snd_pcm_hw_params_set_periods_near) | 72 static int (*ALSA_snd_pcm_hw_params_set_periods_near) |
74 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); | 73 (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); |
75 static int (*ALSA_snd_pcm_hw_params_get_periods) (snd_pcm_hw_params_t *); | 74 static int (*ALSA_snd_pcm_hw_params_get_periods) |
75 (const snd_pcm_hw_params_t *, unsigned int *, int *); | |
76 static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near) | |
77 (snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *); | |
78 static int (*ALSA_snd_pcm_hw_params_get_buffer_size) | |
79 (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *); | |
76 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *); | 80 static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *); |
77 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *, | 81 static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *, |
78 snd_pcm_sw_params_t *); | 82 snd_pcm_sw_params_t *); |
79 static int (*ALSA_snd_pcm_sw_params_set_start_threshold) | 83 static int (*ALSA_snd_pcm_sw_params_set_start_threshold) |
80 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); | 84 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); |
81 static int (*ALSA_snd_pcm_sw_params_set_avail_min) | |
82 (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); | |
83 static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *); | 85 static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *); |
84 static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int); | 86 static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int); |
87 static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int); | |
85 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof | 88 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof |
86 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof | 89 #define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof |
87 | 90 |
88 | 91 |
89 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC | 92 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC |
114 load_alsa_syms(void) | 117 load_alsa_syms(void) |
115 { | 118 { |
116 SDL_ALSA_SYM(snd_pcm_open); | 119 SDL_ALSA_SYM(snd_pcm_open); |
117 SDL_ALSA_SYM(snd_pcm_close); | 120 SDL_ALSA_SYM(snd_pcm_close); |
118 SDL_ALSA_SYM(snd_pcm_writei); | 121 SDL_ALSA_SYM(snd_pcm_writei); |
119 SDL_ALSA_SYM(snd_pcm_resume); | 122 SDL_ALSA_SYM(snd_pcm_recover); |
120 SDL_ALSA_SYM(snd_pcm_prepare); | 123 SDL_ALSA_SYM(snd_pcm_prepare); |
121 SDL_ALSA_SYM(snd_pcm_drain); | 124 SDL_ALSA_SYM(snd_pcm_drain); |
122 SDL_ALSA_SYM(snd_strerror); | 125 SDL_ALSA_SYM(snd_strerror); |
123 SDL_ALSA_SYM(snd_pcm_hw_params_sizeof); | 126 SDL_ALSA_SYM(snd_pcm_hw_params_sizeof); |
124 SDL_ALSA_SYM(snd_pcm_sw_params_sizeof); | 127 SDL_ALSA_SYM(snd_pcm_sw_params_sizeof); |
128 SDL_ALSA_SYM(snd_pcm_hw_params_copy); | |
125 SDL_ALSA_SYM(snd_pcm_hw_params_any); | 129 SDL_ALSA_SYM(snd_pcm_hw_params_any); |
126 SDL_ALSA_SYM(snd_pcm_hw_params_set_access); | 130 SDL_ALSA_SYM(snd_pcm_hw_params_set_access); |
127 SDL_ALSA_SYM(snd_pcm_hw_params_set_format); | 131 SDL_ALSA_SYM(snd_pcm_hw_params_set_format); |
128 SDL_ALSA_SYM(snd_pcm_hw_params_set_channels); | 132 SDL_ALSA_SYM(snd_pcm_hw_params_set_channels); |
129 SDL_ALSA_SYM(snd_pcm_hw_params_get_channels); | 133 SDL_ALSA_SYM(snd_pcm_hw_params_get_channels); |
130 SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near); | 134 SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near); |
131 SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near); | 135 SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near); |
132 SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size); | 136 SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size); |
133 SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near); | 137 SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near); |
134 SDL_ALSA_SYM(snd_pcm_hw_params_get_periods); | 138 SDL_ALSA_SYM(snd_pcm_hw_params_get_periods); |
139 SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near); | |
140 SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size); | |
135 SDL_ALSA_SYM(snd_pcm_hw_params); | 141 SDL_ALSA_SYM(snd_pcm_hw_params); |
136 SDL_ALSA_SYM(snd_pcm_sw_params_current); | 142 SDL_ALSA_SYM(snd_pcm_sw_params_current); |
137 SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold); | 143 SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold); |
138 SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min); | |
139 SDL_ALSA_SYM(snd_pcm_sw_params); | 144 SDL_ALSA_SYM(snd_pcm_sw_params); |
140 SDL_ALSA_SYM(snd_pcm_nonblock); | 145 SDL_ALSA_SYM(snd_pcm_nonblock); |
146 SDL_ALSA_SYM(snd_pcm_wait); | |
141 return 0; | 147 return 0; |
142 } | 148 } |
143 | 149 |
144 #undef SDL_ALSA_SYM | 150 #undef SDL_ALSA_SYM |
145 | 151 |
194 { | 200 { |
195 const char *device; | 201 const char *device; |
196 | 202 |
197 device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */ | 203 device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */ |
198 if (device == NULL) { | 204 if (device == NULL) { |
199 if (channels == 6) | 205 switch (channels) { |
200 device = "surround51"; | 206 case 6: |
201 else if (channels == 4) | 207 device = "plug:surround51"; |
202 device = "surround40"; | 208 break; |
203 else | 209 case 4: |
204 device = DEFAULT_DEVICE; | 210 device = "plug:surround40"; |
211 break; | |
212 default: | |
213 device = "default"; | |
214 break; | |
215 } | |
205 } | 216 } |
206 return device; | 217 return device; |
207 } | 218 } |
208 | 219 |
209 | 220 |
210 /* This function waits until it is possible to write a full sound buffer */ | 221 /* This function waits until it is possible to write a full sound buffer */ |
211 static void | 222 static void |
212 ALSA_WaitDevice(_THIS) | 223 ALSA_WaitDevice(_THIS) |
213 { | 224 { |
214 /* Check to see if the thread-parent process is still alive */ | 225 /* We're in blocking mode, so there's nothing to do here */ |
215 { | |
216 static int cnt = 0; | |
217 /* Note that this only works with thread implementations | |
218 that use a different process id for each thread. | |
219 */ | |
220 /* Check every 10 loops */ | |
221 if (this->hidden->parent && (((++cnt) % 10) == 0)) { | |
222 if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { | |
223 this->enabled = 0; | |
224 } | |
225 } | |
226 } | |
227 } | 226 } |
228 | 227 |
229 | 228 |
230 /* !!! FIXME: is there a channel swizzler in alsalib instead? */ | 229 /* !!! FIXME: is there a channel swizzler in alsalib instead? */ |
231 /* | 230 /* |
295 | 294 |
296 static void | 295 static void |
297 ALSA_PlayDevice(_THIS) | 296 ALSA_PlayDevice(_THIS) |
298 { | 297 { |
299 int status; | 298 int status; |
300 int sample_len; | 299 const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf; |
301 signed short *sample_buf; | 300 const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) * |
301 this->spec.channels; | |
302 snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples); | |
302 | 303 |
303 swizzle_alsa_channels(this); | 304 swizzle_alsa_channels(this); |
304 | 305 |
305 sample_len = this->spec.samples; | 306 while ( frames_left > 0 && this->enabled ) { |
306 sample_buf = (signed short *) this->hidden->mixbuf; | 307 /* !!! FIXME: This works, but needs more testing before going live */ |
307 | 308 /*ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1);*/ |
308 while (sample_len > 0) { | |
309 status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, | 309 status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, |
310 sample_buf, sample_len); | 310 sample_buf, frames_left); |
311 | 311 |
312 if (status < 0) { | 312 if (status < 0) { |
313 if (status == -EAGAIN) { | 313 if (status == -EAGAIN) { |
314 /* Apparently snd_pcm_recover() doesn't handle this case - | |
315 does it assume snd_pcm_wait() above? */ | |
314 SDL_Delay(1); | 316 SDL_Delay(1); |
315 continue; | 317 continue; |
316 } | 318 } |
317 if (status == -ESTRPIPE) { | 319 status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); |
318 do { | |
319 SDL_Delay(1); | |
320 status = ALSA_snd_pcm_resume(this->hidden->pcm_handle); | |
321 } while (status == -EAGAIN); | |
322 } | |
323 if (status < 0) { | |
324 status = ALSA_snd_pcm_prepare(this->hidden->pcm_handle); | |
325 } | |
326 if (status < 0) { | 320 if (status < 0) { |
327 /* Hmm, not much we can do - abort */ | 321 /* Hmm, not much we can do - abort */ |
322 fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", | |
323 ALSA_snd_strerror(status)); | |
328 this->enabled = 0; | 324 this->enabled = 0; |
329 return; | 325 return; |
330 } | 326 } |
331 continue; | 327 continue; |
332 } | 328 } |
333 sample_buf += status * this->spec.channels; | 329 sample_buf += status * frame_size; |
334 sample_len -= status; | 330 frames_left -= status; |
335 } | 331 } |
336 } | 332 } |
337 | 333 |
338 static Uint8 * | 334 static Uint8 * |
339 ALSA_GetDeviceBuf(_THIS) | 335 ALSA_GetDeviceBuf(_THIS) |
355 this->hidden->pcm_handle = NULL; | 351 this->hidden->pcm_handle = NULL; |
356 } | 352 } |
357 SDL_free(this->hidden); | 353 SDL_free(this->hidden); |
358 this->hidden = NULL; | 354 this->hidden = NULL; |
359 } | 355 } |
356 } | |
357 | |
358 static int | |
359 ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override) | |
360 { | |
361 int status; | |
362 snd_pcm_uframes_t bufsize; | |
363 | |
364 /* "set" the hardware with the desired parameters */ | |
365 status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams); | |
366 if ( status < 0 ) { | |
367 return(-1); | |
368 } | |
369 | |
370 /* Get samples for the actual buffer size */ | |
371 status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize); | |
372 if ( status < 0 ) { | |
373 return(-1); | |
374 } | |
375 if ( !override && bufsize != this->spec.samples * 2 ) { | |
376 return(-1); | |
377 } | |
378 | |
379 /* !!! FIXME: Is this safe to do? */ | |
380 this->spec.samples = bufsize / 2; | |
381 | |
382 /* This is useful for debugging */ | |
383 if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) { | |
384 snd_pcm_uframes_t persize = 0; | |
385 unsigned int periods = 0; | |
386 | |
387 ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize, NULL); | |
388 ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL); | |
389 | |
390 fprintf(stderr, | |
391 "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", | |
392 persize, periods, bufsize); | |
393 } | |
394 | |
395 return(0); | |
396 } | |
397 | |
398 static int | |
399 ALSA_set_period_size(_THIS, snd_pcm_hw_params_t *params, int override) | |
400 { | |
401 const char *env; | |
402 int status; | |
403 snd_pcm_hw_params_t *hwparams; | |
404 snd_pcm_uframes_t frames; | |
405 unsigned int periods; | |
406 | |
407 /* Copy the hardware parameters for this setup */ | |
408 snd_pcm_hw_params_alloca(&hwparams); | |
409 ALSA_snd_pcm_hw_params_copy(hwparams, params); | |
410 | |
411 if ( !override ) { | |
412 env = SDL_getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE"); | |
413 if ( env ) { | |
414 override = SDL_atoi(env); | |
415 if ( override == 0 ) { | |
416 return(-1); | |
417 } | |
418 } | |
419 } | |
420 | |
421 frames = this->spec.samples; | |
422 status = ALSA_snd_pcm_hw_params_set_period_size_near( | |
423 this->hidden->pcm_handle, hwparams, &frames, NULL); | |
424 if ( status < 0 ) { | |
425 return(-1); | |
426 } | |
427 | |
428 periods = 2; | |
429 status = ALSA_snd_pcm_hw_params_set_periods_near( | |
430 this->hidden->pcm_handle, hwparams, &periods, NULL); | |
431 if ( status < 0 ) { | |
432 return(-1); | |
433 } | |
434 | |
435 return ALSA_finalize_hardware(this, hwparams, override); | |
436 } | |
437 | |
438 static int | |
439 ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override) | |
440 { | |
441 const char *env; | |
442 int status; | |
443 snd_pcm_hw_params_t *hwparams; | |
444 snd_pcm_uframes_t frames; | |
445 | |
446 /* Copy the hardware parameters for this setup */ | |
447 snd_pcm_hw_params_alloca(&hwparams); | |
448 ALSA_snd_pcm_hw_params_copy(hwparams, params); | |
449 | |
450 if ( !override ) { | |
451 env = SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"); | |
452 if ( env ) { | |
453 override = SDL_atoi(env); | |
454 if ( override == 0 ) { | |
455 return(-1); | |
456 } | |
457 } | |
458 } | |
459 | |
460 frames = this->spec.samples * 2; | |
461 status = ALSA_snd_pcm_hw_params_set_buffer_size_near( | |
462 this->hidden->pcm_handle, hwparams, &frames); | |
463 if ( status < 0 ) { | |
464 return(-1); | |
465 } | |
466 | |
467 return ALSA_finalize_hardware(this, hwparams, override); | |
360 } | 468 } |
361 | 469 |
362 static int | 470 static int |
363 ALSA_OpenDevice(_THIS, const char *devname, int iscapture) | 471 ALSA_OpenDevice(_THIS, const char *devname, int iscapture) |
364 { | 472 { |
365 int status = 0; | 473 int status = 0; |
366 snd_pcm_t *pcm_handle = NULL; | 474 snd_pcm_t *pcm_handle = NULL; |
367 snd_pcm_hw_params_t *hwparams = NULL; | 475 snd_pcm_hw_params_t *hwparams = NULL; |
368 snd_pcm_sw_params_t *swparams = NULL; | 476 snd_pcm_sw_params_t *swparams = NULL; |
369 snd_pcm_format_t format = 0; | 477 snd_pcm_format_t format = 0; |
370 snd_pcm_uframes_t frames = 0; | |
371 SDL_AudioFormat test_format = 0; | 478 SDL_AudioFormat test_format = 0; |
372 unsigned int rate = 0; | 479 unsigned int rate = 0; |
373 unsigned int periods = 0; | |
374 unsigned int channels = 0; | 480 unsigned int channels = 0; |
375 | 481 |
376 /* Initialize all variables that we clean on shutdown */ | 482 /* Initialize all variables that we clean on shutdown */ |
377 this->hidden = (struct SDL_PrivateAudioData *) | 483 this->hidden = (struct SDL_PrivateAudioData *) |
378 SDL_malloc((sizeof *this->hidden)); | 484 SDL_malloc((sizeof *this->hidden)); |
497 return 0; | 603 return 0; |
498 } | 604 } |
499 this->spec.freq = rate; | 605 this->spec.freq = rate; |
500 | 606 |
501 /* Set the buffer size, in samples */ | 607 /* Set the buffer size, in samples */ |
502 frames = this->spec.samples; | 608 if ( ALSA_set_period_size(this, hwparams, 0) < 0 && |
503 status = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, | 609 ALSA_set_buffer_size(this, hwparams, 0) < 0 ) { |
504 &frames, NULL); | 610 /* Failed to set desired buffer size, do the best you can... */ |
505 if ( status < 0 ) { | 611 if ( ALSA_set_period_size(this, hwparams, 1) < 0 ) { |
506 ALSA_CloseDevice(this); | 612 ALSA_CloseDevice(this); |
507 SDL_SetError("ALSA: Couldn't set audio frequency: %s", | 613 SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status)); |
508 ALSA_snd_strerror(status)); | 614 return(-1); |
509 return(-1); | 615 } |
510 } | 616 } |
511 this->spec.samples = frames; | |
512 | |
513 periods = 2; | |
514 ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, | |
515 &periods, NULL); | |
516 | |
517 /* "set" the hardware with the desired parameters */ | |
518 status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams); | |
519 if (status < 0) { | |
520 ALSA_CloseDevice(this); | |
521 SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s", | |
522 ALSA_snd_strerror(status)); | |
523 return 0; | |
524 } | |
525 #if AUDIO_DEBUG | |
526 { | |
527 snd_pcm_sframes_t bufsize; | |
528 int fragments; | |
529 bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams); | |
530 fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams); | |
531 fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize, | |
532 fragments); | |
533 } | |
534 #endif | |
535 | |
536 /* Set the software parameters */ | 617 /* Set the software parameters */ |
537 snd_pcm_sw_params_alloca(&swparams); | 618 snd_pcm_sw_params_alloca(&swparams); |
538 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); | 619 status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); |
539 if (status < 0) { | 620 if (status < 0) { |
540 ALSA_CloseDevice(this); | 621 ALSA_CloseDevice(this); |
541 SDL_SetError("ALSA: Couldn't get software config: %s", | 622 SDL_SetError("ALSA: Couldn't get software config: %s", |
542 ALSA_snd_strerror(status)); | 623 ALSA_snd_strerror(status)); |
543 return 0; | 624 return 0; |
544 } | 625 } |
545 status = | 626 status = |
546 ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 0); | 627 ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); |
547 if (status < 0) { | 628 if (status < 0) { |
548 ALSA_CloseDevice(this); | 629 ALSA_CloseDevice(this); |
549 SDL_SetError("ALSA: Couldn't set start threshold: %s", | 630 SDL_SetError("ALSA: Couldn't set start threshold: %s", |
550 ALSA_snd_strerror(status)); | 631 ALSA_snd_strerror(status)); |
551 return 0; | |
552 } | |
553 status = | |
554 ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames); | |
555 if (status < 0) { | |
556 ALSA_CloseDevice(this); | |
557 SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status)); | |
558 return 0; | 632 return 0; |
559 } | 633 } |
560 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); | 634 status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); |
561 if (status < 0) { | 635 if (status < 0) { |
562 ALSA_CloseDevice(this); | 636 ALSA_CloseDevice(this); |
575 ALSA_CloseDevice(this); | 649 ALSA_CloseDevice(this); |
576 SDL_OutOfMemory(); | 650 SDL_OutOfMemory(); |
577 return 0; | 651 return 0; |
578 } | 652 } |
579 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); | 653 SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); |
580 | |
581 /* Get the parent process id (we're the parent of the audio thread) */ | |
582 this->hidden->parent = getpid(); | |
583 | 654 |
584 /* Switch to blocking mode for playback */ | 655 /* Switch to blocking mode for playback */ |
585 ALSA_snd_pcm_nonblock(pcm_handle, 0); | 656 ALSA_snd_pcm_nonblock(pcm_handle, 0); |
586 | 657 |
587 /* We're ready to rock and roll. :-) */ | 658 /* We're ready to rock and roll. :-) */ |
613 return 1; /* !!! FIXME: return 2 once device enum is implemented. */ | 684 return 1; /* !!! FIXME: return 2 once device enum is implemented. */ |
614 } | 685 } |
615 | 686 |
616 | 687 |
617 AudioBootStrap ALSA_bootstrap = { | 688 AudioBootStrap ALSA_bootstrap = { |
618 DRIVER_NAME, "ALSA 0.9 PCM audio", ALSA_Init, 0 | 689 DRIVER_NAME, "ALSA PCM audio", ALSA_Init, 0 |
619 }; | 690 }; |
620 | 691 |
621 /* vi: set ts=4 sw=4 expandtab: */ | 692 /* vi: set ts=4 sw=4 expandtab: */ |