/
SDL_alsa_audio.c
546 lines (475 loc) · 17.7 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
/* The default ALSA audio driver */
47
#define DEFAULT_DEVICE "default"
48
49
/* Audio driver functions */
50
51
52
53
54
55
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);
56
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
57
58
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
59
60
61
62
63
64
65
66
67
68
69
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);
70
static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
71
72
73
74
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);
75
static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val);
76
77
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);
78
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);
79
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);
80
81
static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
82
static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
83
84
85
86
87
88
/*
*/
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_set_avail_min))(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);
89
static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
90
#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
91
#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
92
93
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
94
95
96
97
static struct {
const char *name;
void **func;
} alsa_functions[] = {
98
99
100
101
102
103
104
105
{ "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) },
106
{ "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
107
108
109
110
111
112
113
{ "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) },
114
{ "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
115
{ "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
116
{ "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
117
{ "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
118
{ "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
119
120
121
122
{ "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_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) },
{ "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
123
{ "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
124
125
126
127
};
static void UnloadALSALibrary(void) {
if (alsa_loaded) {
128
SDL_UnloadObject(alsa_handle);
129
130
131
132
133
134
135
136
alsa_handle = NULL;
alsa_loaded = 0;
}
}
static int LoadALSALibrary(void) {
int i, retval = -1;
137
alsa_handle = SDL_LoadObject(alsa_library);
138
139
140
if (alsa_handle) {
alsa_loaded = 1;
retval = 0;
141
for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
142
*alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
if (!*alsa_functions[i].func) {
retval = -1;
UnloadALSALibrary();
break;
}
}
}
return retval;
}
#else
static void UnloadALSALibrary(void) {
return;
}
static int LoadALSALibrary(void) {
return 0;
}
163
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
164
165
static const char *get_audio_device(int channels)
166
{
167
168
const char *device;
169
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
170
if ( device == NULL ) {
171
172
173
if (channels == 6) device = "surround51";
else if (channels == 4) device = "surround40";
else device = DEFAULT_DEVICE;
174
175
}
return device;
176
177
178
179
180
181
182
}
/* Audio driver bootstrap functions */
static int Audio_Available(void)
{
int available;
183
int status;
184
185
186
snd_pcm_t *handle;
available = 0;
187
188
189
if (LoadALSALibrary() < 0) {
return available;
}
190
status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
191
192
if ( status >= 0 ) {
available = 1;
193
SDL_NAME(snd_pcm_close)(handle);
194
}
195
UnloadALSALibrary();
196
197
198
199
200
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
201
202
SDL_free(device->hidden);
SDL_free(device);
203
UnloadALSALibrary();
204
205
206
207
208
209
210
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
211
LoadALSALibrary();
212
this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
213
if ( this ) {
214
SDL_memset(this, 0, (sizeof *this));
215
this->hidden = (struct SDL_PrivateAudioData *)
216
SDL_malloc((sizeof *this->hidden));
217
218
219
220
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
221
SDL_free(this);
222
223
224
}
return(0);
}
225
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
226
227
/* Set the function pointers */
228
229
230
231
232
this->OpenAudio = ALSA_OpenAudio;
this->WaitAudio = ALSA_WaitAudio;
this->PlayAudio = ALSA_PlayAudio;
this->GetAudioBuf = ALSA_GetAudioBuf;
this->CloseAudio = ALSA_CloseAudio;
233
234
235
236
237
238
239
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap ALSA_bootstrap = {
240
DRIVER_NAME, "ALSA 0.9 PCM audio",
241
242
243
244
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
245
static void ALSA_WaitAudio(_THIS)
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
/* 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;
}
}
}
}
260
261
262
263
264
265
266
267
268
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
/*
* 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. */
}
306
static void ALSA_PlayAudio(_THIS)
307
{
308
int status;
309
snd_pcm_uframes_t samps_left;
310
const Uint8 *sample_buf = (const Uint8 *) mixbuf;
311
const int sample_size = ((int) (this->spec.format & 0xFF)) / 8;
312
313
314
swizzle_alsa_channels(this);
315
samps_left = ((snd_pcm_uframes_t) this->spec.samples);
316
317
318
while ( samps_left > 0 ) {
status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, samps_left);
319
320
if ( status < 0 ) {
if ( status == -EAGAIN ) {
321
SDL_Delay(1);
322
323
324
325
continue;
}
if ( status == -ESTRPIPE ) {
do {
326
SDL_Delay(1);
327
status = SDL_NAME(snd_pcm_resume)(pcm_handle);
328
329
330
} while ( status == -EAGAIN );
}
if ( status < 0 ) {
331
status = SDL_NAME(snd_pcm_prepare)(pcm_handle);
332
333
334
335
336
}
if ( status < 0 ) {
/* Hmm, not much we can do - abort */
this->enabled = 0;
return;
337
}
338
continue;
339
}
340
341
sample_buf += status * sample_size;
samps_left -= status;
342
343
344
}
}
345
static Uint8 *ALSA_GetAudioBuf(_THIS)
346
{
347
return(mixbuf);
348
349
}
350
static void ALSA_CloseAudio(_THIS)
351
{
352
353
354
if ( mixbuf != NULL ) {
SDL_FreeAudioMem(mixbuf);
mixbuf = NULL;
355
}
356
if ( pcm_handle ) {
357
358
SDL_NAME(snd_pcm_drain)(pcm_handle);
SDL_NAME(snd_pcm_close)(pcm_handle);
359
pcm_handle = NULL;
360
361
362
}
}
363
static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
364
{
365
int status;
366
367
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
368
369
snd_pcm_format_t format;
snd_pcm_uframes_t frames;
370
371
372
unsigned int rate;
unsigned int periods;
unsigned int channels;
373
Uint16 test_format;
374
375
/* Open the audio device */
376
377
378
/* 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);
379
if ( status < 0 ) {
380
SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
381
382
383
return(-1);
}
384
/* Figure out what the hardware is capable of */
385
386
snd_pcm_hw_params_alloca(&hwparams);
status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
387
if ( status < 0 ) {
388
SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
389
390
391
ALSA_CloseAudio(this);
return(-1);
}
392
393
/* SDL only uses interleaved sample output */
394
status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
395
if ( status < 0 ) {
396
SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
397
398
399
ALSA_CloseAudio(this);
return(-1);
}
400
401
/* Try for a closest match on audio format */
402
status = -1;
403
for ( test_format = SDL_FirstAudioFormat(spec->format);
404
405
test_format && (status < 0); ) {
switch ( test_format ) {
406
case AUDIO_U8:
407
format = SND_PCM_FORMAT_U8;
408
409
break;
case AUDIO_S8:
410
format = SND_PCM_FORMAT_S8;
411
412
break;
case AUDIO_S16LSB:
413
format = SND_PCM_FORMAT_S16_LE;
414
415
break;
case AUDIO_S16MSB:
416
format = SND_PCM_FORMAT_S16_BE;
417
418
break;
case AUDIO_U16LSB:
419
format = SND_PCM_FORMAT_U16_LE;
420
421
break;
case AUDIO_U16MSB:
422
format = SND_PCM_FORMAT_U16_BE;
423
424
break;
default:
425
format = 0;
426
427
break;
}
428
if ( format != 0 ) {
429
status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
430
431
}
if ( status < 0 ) {
432
433
434
test_format = SDL_NextAudioFormat();
}
}
435
if ( status < 0 ) {
436
SDL_SetError("Couldn't find any hardware audio formats");
437
ALSA_CloseAudio(this);
438
439
440
441
return(-1);
}
spec->format = test_format;
442
/* Set the number of channels */
443
status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
444
channels = spec->channels;
445
if ( status < 0 ) {
446
447
status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams, &channels);
if ( status < 0 ) {
448
449
450
451
SDL_SetError("Couldn't set audio channels");
ALSA_CloseAudio(this);
return(-1);
}
452
spec->channels = channels;
453
}
454
455
/* Set the audio rate */
456
457
458
rate = spec->freq;
status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, &rate, NULL);
459
if ( status < 0 ) {
460
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
461
462
463
ALSA_CloseAudio(this);
return(-1);
}
464
spec->freq = rate;
465
466
467
/* Set the buffer size, in samples */
frames = spec->samples;
468
469
470
471
472
473
474
status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
if ( status < 0 ) {
SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
475
spec->samples = frames;
476
477
478
periods = 2;
SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
479
480
/* "set" the hardware with the desired parameters */
481
482
483
484
485
486
487
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);
}
488
/* This is useful for debugging... */
489
490
491
492
493
#if 0
{ 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);
495
fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
497
#endif
498
499
500
501
502
503
504
505
506
/* 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);
}
507
status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 1);
508
509
510
511
512
513
514
515
516
517
518
519
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_set_avail_min)(pcm_handle, swparams, frames);
if ( status < 0 ) {
SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status));
ALSA_CloseAudio(this);
return(-1);
}
status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
520
if ( status < 0 ) {
521
SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
522
ALSA_CloseAudio(this);
523
524
525
return(-1);
}
526
527
528
529
530
531
532
533
534
/* 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);
535
}
536
SDL_memset(mixbuf, spec->silence, spec->size);
537
538
539
540
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
541
/* Switch to blocking mode for playback */
542
SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0);
543
544
545
546
/* We're ready to rock and roll. :-) */
return(0);
}