/
SDL_alsa_audio.c
561 lines (490 loc) · 17.9 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2009 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
20
slouken@libsdl.org
21
*/
22
#include "SDL_config.h"
23
24
25
26
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
27
#include <signal.h> /* For kill() */
28
29
#include "SDL_timer.h"
30
31
32
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
33
34
#include "SDL_alsa_audio.h"
35
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
36
37
38
39
40
41
42
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
43
44
45
/* The tag name used by ALSA audio */
#define DRIVER_NAME "alsa"
46
47
48
49
/* Whether we should set the buffer size or the period size */
/*#define SET_PERIOD_SIZE*/
/*#define DEBUG_PERIOD_SIZE*/
50
/* Audio driver functions */
51
52
53
54
55
56
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void ALSA_WaitAudio(_THIS);
static void ALSA_PlayAudio(_THIS);
static Uint8 *ALSA_GetAudioBuf(_THIS);
static void ALSA_CloseAudio(_THIS);
57
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
58
59
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
60
61
62
63
64
65
66
67
68
69
70
static void *alsa_handle = NULL;
static int alsa_loaded = 0;
static int (*SDL_NAME(snd_pcm_open))(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
static int (*SDL_NAME(snd_pcm_close))(snd_pcm_t *pcm);
static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_writei))(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
static int (*SDL_NAME(snd_pcm_resume))(snd_pcm_t *pcm);
static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm);
static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm);
static const char *(*SDL_NAME(snd_strerror))(int errnum);
static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
71
static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
72
73
74
75
static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
76
static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val);
77
78
static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
79
static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir);
80
static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
81
static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
82
static int (*SDL_NAME(snd_pcm_hw_params_set_buffer_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
83
static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
84
static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
85
86
87
88
89
/*
*/
static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
90
static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
91
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
92
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
93
94
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
95
96
97
98
static struct {
const char *name;
void **func;
} alsa_functions[] = {
99
100
101
102
103
104
105
106
{ "snd_pcm_open", (void**)(char*)&SDL_NAME(snd_pcm_open) },
{ "snd_pcm_close", (void**)(char*)&SDL_NAME(snd_pcm_close) },
{ "snd_pcm_writei", (void**)(char*)&SDL_NAME(snd_pcm_writei) },
{ "snd_pcm_resume", (void**)(char*)&SDL_NAME(snd_pcm_resume) },
{ "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) },
{ "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) },
{ "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) },
{ "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) },
107
{ "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
108
109
110
111
112
113
114
{ "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) },
{ "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) },
{ "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) },
{ "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) },
{ "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) },
{ "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
{ "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
115
{ "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
116
{ "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
117
{ "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
118
{ "snd_pcm_hw_params_set_buffer_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_buffer_size_near) },
119
{ "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
120
{ "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
121
122
123
{ "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
{ "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
{ "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
124
{ "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
125
126
127
128
};
static void UnloadALSALibrary(void) {
if (alsa_loaded) {
129
SDL_UnloadObject(alsa_handle);
130
131
132
133
134
135
136
137
alsa_handle = NULL;
alsa_loaded = 0;
}
}
static int LoadALSALibrary(void) {
int i, retval = -1;
138
alsa_handle = SDL_LoadObject(alsa_library);
139
140
141
if (alsa_handle) {
alsa_loaded = 1;
retval = 0;
142
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
143
*alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
if (!*alsa_functions[i].func) {
retval = -1;
UnloadALSALibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadALSALibrary(void) {
return;
}
static int LoadALSALibrary(void) {
return 0;
}
164
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
165
166
static const char *get_audio_device(int channels)
167
{
168
169
const char *device;
170
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
171
if ( device == NULL ) {
172
173
174
175
176
177
178
179
180
181
182
switch (channels) {
case 6:
device = "plug:surround51";
break;
case 4:
device = "plug:surround40";
break;
default:
device = "default";
break;
}
183
184
}
return device;
185
186
187
188
189
190
191
}
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int available;
192
int status;
193
194
195
snd_pcm_t *handle;
available = 0;
196
197
198
if (LoadALSALibrary() < 0) {
return available;
}
199
status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
200
201
if ( status >= 0 ) {
available = 1;
202
SDL_NAME(snd_pcm_close)(handle);
203
}
204
UnloadALSALibrary();
205
206
207
208
209
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
210
211
SDL_free(device->hidden);
SDL_free(device);
212
UnloadALSALibrary();
213
214
215
216
217
218
219
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
220
LoadALSALibrary();
221
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
222
if ( this ) {
223
SDL_memset(this, 0, (sizeof *this));
224
this->hidden = (struct SDL_PrivateAudioData *)
225
SDL_malloc((sizeof *this->hidden));
226
227
228
229
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
230
SDL_free(this);
231
232
233
}
return(0);
}
234
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
235
236
/* Set the function pointers */
237
238
239
240
241
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
242
243
244
245
246
247
248
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ALSA_bootstrap = {
249
DRIVER_NAME, "ALSA 0.9 PCM audio",
250
251
252
253
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
254
static void ALSA_WaitAudio(_THIS)
255
256
257
258
259
260
261
262
263
264
265
266
267
268
{
/* Check to see if the thread-parent process is still alive */
{ static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
if ( kill(parent, 0) < 0 ) {
this->enabled = 0;
}
}
}
}
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T) \
T *ptr = (T *) mixbuf; \
const Uint32 count = (this->spec.samples / 6); \
Uint32 i; \
for (i = 0; i < count; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
static __inline__ void swizzle_alsa_channels_6_64bit(_THIS) { SWIZ6(Uint64); }
static __inline__ void swizzle_alsa_channels_6_32bit(_THIS) { SWIZ6(Uint32); }
static __inline__ void swizzle_alsa_channels_6_16bit(_THIS) { SWIZ6(Uint16); }
static __inline__ void swizzle_alsa_channels_6_8bit(_THIS) { SWIZ6(Uint8); }
#undef SWIZ6
/*
* Called right before feeding this->mixbuf to the hardware. Swizzle channels
* from Windows/Mac order to the format alsalib will want.
*/
static __inline__ void swizzle_alsa_channels(_THIS)
{
if (this->spec.channels == 6) {
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
if (fmtsize == 16)
swizzle_alsa_channels_6_16bit(this);
else if (fmtsize == 8)
swizzle_alsa_channels_6_8bit(this);
else if (fmtsize == 32)
swizzle_alsa_channels_6_32bit(this);
else if (fmtsize == 64)
swizzle_alsa_channels_6_64bit(this);
}
/* !!! FIXME: update this for 7.1 if needed, later. */
}
315
static void ALSA_PlayAudio(_THIS)
316
{
317
int status;
318
snd_pcm_uframes_t frames_left;
319
const Uint8 *sample_buf = (const Uint8 *) mixbuf;
320
const int sample_size = ((int) (this->spec.format & 0xFF)) / 8;
321
322
323
swizzle_alsa_channels(this);
324
frames_left = ((snd_pcm_uframes_t) this->spec.samples);
325
326
327
while ( frames_left > 0 ) {
status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, frames_left);
328
329
if ( status < 0 ) {
if ( status == -EAGAIN ) {
330
SDL_Delay(1);
331
332
333
334
continue;
}
if ( status == -ESTRPIPE ) {
do {
335
SDL_Delay(1);
336
status = SDL_NAME(snd_pcm_resume)(pcm_handle);
337
338
339
} while ( status == -EAGAIN );
}
if ( status < 0 ) {
340
status = SDL_NAME(snd_pcm_prepare)(pcm_handle);
341
342
343
344
345
}
if ( status < 0 ) {
/* Hmm, not much we can do - abort */
this->enabled = 0;
return;
346
}
347
continue;
348
}
349
sample_buf += status * sample_size;
350
frames_left -= status;
351
352
353
}
}
354
static Uint8 *ALSA_GetAudioBuf(_THIS)
355
{
356
return(mixbuf);
357
358
}
359
static void ALSA_CloseAudio(_THIS)
360
{
361
362
363
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
364
}
365
if ( pcm_handle ) {
366
367
SDL_NAME(snd_pcm_drain)(pcm_handle);
SDL_NAME(snd_pcm_close)(pcm_handle);
368
pcm_handle = NULL;
369
370
371
}
}
372
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
373
{
374
int status;
375
376
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
377
378
snd_pcm_format_t format;
snd_pcm_uframes_t frames;
379
unsigned int rate;
380
#ifdef SET_PERIOD_SIZE
381
unsigned int periods;
382
383
#endif
unsigned int channels;
384
Uint16 test_format;
385
386
/* Open the audio device */
387
388
389
/* Name of device should depend on # channels in spec */
status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
390
if ( status < 0 ) {
391
SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
392
393
394
return(-1);
}
395
/* Figure out what the hardware is capable of */
396
397
snd_pcm_hw_params_alloca(&hwparams);
status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
398
if ( status < 0 ) {
399
SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
400
401
402
ALSA_CloseAudio(this);
return(-1);
}
403
404
/* SDL only uses interleaved sample output */
405
status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
406
if ( status < 0 ) {
407
SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
408
409
410
ALSA_CloseAudio(this);
return(-1);
}
411
412
/* Try for a closest match on audio format */
413
status = -1;
414
for ( test_format = SDL_FirstAudioFormat(spec->format);
415
416
test_format && (status < 0); ) {
switch ( test_format ) {
417
case AUDIO_U8:
418
format = SND_PCM_FORMAT_U8;
419
420
break;
case AUDIO_S8:
421
format = SND_PCM_FORMAT_S8;
422
423
break;
case AUDIO_S16LSB:
424
format = SND_PCM_FORMAT_S16_LE;
425
426
break;
case AUDIO_S16MSB:
427
format = SND_PCM_FORMAT_S16_BE;
428
429
break;
case AUDIO_U16LSB:
430
format = SND_PCM_FORMAT_U16_LE;
431
432
break;
case AUDIO_U16MSB:
433
format = SND_PCM_FORMAT_U16_BE;
434
435
break;
default:
436
format = 0;
437
438
break;
}
439
if ( format != 0 ) {
440
status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
441
442
}
if ( status < 0 ) {
443
444
445
test_format = SDL_NextAudioFormat();
}
}
446
if ( status < 0 ) {
447
SDL_SetError("Couldn't find any hardware audio formats");
448
ALSA_CloseAudio(this);
449
450
451
452
return(-1);
}
spec->format = test_format;
453
/* Set the number of channels */
454
status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
455
channels = spec->channels;
456
if ( status < 0 ) {
457
458
status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams, &channels);
if ( status < 0 ) {
459
460
461
462
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return(-1);
}
463
spec->channels = channels;
464
}
465
466
/* Set the audio rate */
467
468
469
rate = spec->freq;
status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, &rate, NULL);
470
if ( status < 0 ) {
471
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
472
473
474
ALSA_CloseAudio(this);
return(-1);
}
475
spec->freq = rate;
476
477
/* Set the buffer size, in samples */
478
#ifdef SET_PERIOD_SIZE
479
frames = spec->samples;
480
481
status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
if ( status < 0 ) {
482
SDL_SetError("Couldn't set period size: %s", SDL_NAME(snd_strerror)(status));
483
484
485
486
ALSA_CloseAudio(this);
return(-1);
}
487
spec->samples = frames;
488
489
periods = 2;
490
491
492
493
494
495
496
497
498
499
status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
if ( status < 0 ) {
SDL_SetError("Couldn't set period count: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
#else
frames = spec->samples * 2;
status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
#endif
500
501
/* "set" the hardware with the desired parameters */
502
503
504
505
506
507
508
status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
if ( status < 0 ) {
SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
509
/* This is useful for debugging... */
510
#ifdef DEBUG_PERIOD_SIZE
511
512
513
514
{ snd_pcm_uframes_t bufsize; snd_pcm_sframes_t persize; unsigned int periods; int dir;
SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir);
SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir);
516
fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
518
#endif
519
520
521
522
523
524
525
526
527
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams);
if ( status < 0 ) {
SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
528
status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 1);
529
530
531
532
533
534
if ( status < 0 ) {
SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
535
if ( status < 0 ) {
536
SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
537
ALSA_CloseAudio(this);
538
539
540
return(-1);
}
541
542
543
544
545
546
547
548
549
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
mixlen = spec->size;
mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
if ( mixbuf == NULL ) {
ALSA_CloseAudio(this);
return(-1);
550
}
551
SDL_memset(mixbuf, spec->silence, spec->size);
552
553
554
555
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
556
/* Switch to blocking mode for playback */
557
SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0);
558
559
560
561
/* We're ready to rock and roll. :-) */
return(0);
}