Skip to content

Latest commit

 

History

History
490 lines (415 loc) · 12.3 KB

SDL_nto_audio.c

File metadata and controls

490 lines (415 loc) · 12.3 KB
 
Apr 26, 2001
Apr 26, 2001
1
2
/*
SDL - Simple DirectMedia Layer
Mar 6, 2002
Mar 6, 2002
3
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
Apr 26, 2001
Apr 26, 2001
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
Dec 14, 2001
Dec 14, 2001
20
slouken@libsdl.org
Apr 26, 2001
Apr 26, 2001
21
22
23
24
25
26
27
28
29
30
31
32
33
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sched.h>
#include <sys/asoundlib.h>
Jun 16, 2002
Jun 16, 2002
34
#include <sys/select.h>
Apr 26, 2001
Apr 26, 2001
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_audiomem.h"
#include "SDL_audio_c.h"
#include "SDL_timer.h"
#include "SDL_nto_audio.h"
/* The tag name used by NTO audio */
#define DRIVER_NAME "nto"
/* default channel communication parameters */
#define DEFAULT_CPARAMS_RATE 22050
#define DEFAULT_CPARAMS_VOICES 1
Jun 16, 2002
Jun 16, 2002
49
#define DEFAULT_CPARAMS_FRAG_SIZE 4096
Apr 26, 2001
Apr 26, 2001
50
#define DEFAULT_CPARAMS_FRAGS_MIN 1
Feb 20, 2002
Feb 20, 2002
51
#define DEFAULT_CPARAMS_FRAGS_MAX 1
Apr 26, 2001
Apr 26, 2001
52
53
/* Open the audio device for playback, and don't block if busy */
Jun 16, 2002
Jun 16, 2002
54
#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
Apr 26, 2001
Apr 26, 2001
55
56
57
58
59
60
61
62
63
/* Audio driver functions */
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void NTO_WaitAudio(_THIS);
static void NTO_PlayAudio(_THIS);
static Uint8 *NTO_GetAudioBuf(_THIS);
static void NTO_CloseAudio(_THIS);
static snd_pcm_channel_status_t cstatus;
Jun 16, 2002
Jun 16, 2002
64
65
static snd_pcm_channel_params_t cparams;
static snd_pcm_channel_setup_t csetup;
Apr 26, 2001
Apr 26, 2001
66
67
68
69
70
71
72
73
/* PCM transfer channel parameters initialize function */
static void init_pcm_cparams(snd_pcm_channel_params_t* cparams)
{
memset(cparams,0,sizeof(snd_pcm_channel_params_t));
cparams->channel = SND_PCM_CHANNEL_PLAYBACK;
cparams->mode = SND_PCM_MODE_BLOCK;
Jun 16, 2002
Jun 16, 2002
74
cparams->start_mode = SND_PCM_START_DATA;
Apr 26, 2001
Apr 26, 2001
75
76
77
78
79
80
81
82
83
84
85
86
cparams->stop_mode = SND_PCM_STOP_STOP;
cparams->format.format = SND_PCM_SFMT_S16_LE;
cparams->format.interleave = 1;
cparams->format.rate = DEFAULT_CPARAMS_RATE;
cparams->format.voices = DEFAULT_CPARAMS_VOICES;
cparams->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
cparams->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
cparams->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
}
static int Audio_Available(void)
{
Jun 16, 2002
Jun 16, 2002
87
88
89
90
91
92
/*
See if we can open a nonblocking channel.
Return value '1' means we can.
Return value '0' means we cannot.
*/
Apr 26, 2001
Apr 26, 2001
93
94
95
96
97
98
99
int available;
int rval;
snd_pcm_t *handle;
available = 0;
handle = NULL;
Jun 16, 2002
Jun 16, 2002
100
rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
Apr 26, 2001
Apr 26, 2001
101
Jun 16, 2002
Jun 16, 2002
102
103
104
105
106
if (rval >= 0){
available = 1;
if ((rval = snd_pcm_close(handle)) < 0){
SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval));
Apr 26, 2001
Apr 26, 2001
107
available = 0;
Jun 16, 2002
Jun 16, 2002
108
}
Apr 26, 2001
Apr 26, 2001
109
}
Jun 16, 2002
Jun 16, 2002
110
111
else{
SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval));
Apr 26, 2001
Apr 26, 2001
112
113
}
Jun 16, 2002
Jun 16, 2002
114
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
115
fprintf(stderr,"AudioAvailable rtns %d\n", available);
Jun 16, 2002
Jun 16, 2002
116
117
#endif
Apr 26, 2001
Apr 26, 2001
118
119
120
121
122
return(available);
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
Jun 16, 2002
Jun 16, 2002
123
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
124
fprintf(stderr,"Audio_DeleteDevice\n");
Jun 16, 2002
Jun 16, 2002
125
#endif
Apr 26, 2001
Apr 26, 2001
126
127
128
129
130
131
132
133
free(device->hidden);
free(device);
}
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
Jun 16, 2002
Jun 16, 2002
134
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
135
fprintf(stderr,"Audio_CreateDevice\n");
Jun 16, 2002
Jun 16, 2002
136
#endif
Apr 26, 2001
Apr 26, 2001
137
138
139
140
141
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( this ) {
memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
Jun 16, 2002
Jun 16, 2002
142
malloc((sizeof *this->hidden));
Apr 26, 2001
Apr 26, 2001
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
}
if ( (this == NULL) || (this->hidden == NULL) ) {
SDL_OutOfMemory();
if ( this ) {
free(this);
}
return(0);
}
memset(this->hidden, 0, (sizeof *this->hidden));
audio_handle = NULL;
/* Set the function pointers */
this->OpenAudio = NTO_OpenAudio;
this->WaitAudio = NTO_WaitAudio;
this->PlayAudio = NTO_PlayAudio;
this->GetAudioBuf = NTO_GetAudioBuf;
this->CloseAudio = NTO_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
Aug 4, 2003
Aug 4, 2003
166
167
AudioBootStrap QNXNTOAUDIO_bootstrap = {
DRIVER_NAME, "QNX6 NTO PCM audio",
Apr 26, 2001
Apr 26, 2001
168
169
170
171
172
173
Audio_Available, Audio_CreateDevice
};
/* This function waits until it is possible to write a full sound buffer */
static void NTO_WaitAudio(_THIS)
{
Jun 16, 2002
Jun 16, 2002
174
fd_set wfds;
Apr 26, 2001
Apr 26, 2001
175
Jun 16, 2002
Jun 16, 2002
176
177
FD_SET( audio_fd, &wfds );
switch( select( audio_fd + 1, NULL, &wfds, NULL, NULL ) )
Apr 26, 2001
Apr 26, 2001
178
{
Jun 16, 2002
Jun 16, 2002
179
180
181
182
183
184
185
186
187
case -1:
case 0:
/* Error */
SDL_SetError("select() in NTO_WaitAudio failed: %s\n", strerror(errno));
break;
default:
if(FD_ISSET(audio_fd, &wfds))
return;
}
Apr 26, 2001
Apr 26, 2001
188
189
190
191
}
static void NTO_PlayAudio(_THIS)
{
Jun 16, 2002
Jun 16, 2002
192
193
int written, rval;
int towrite;
Apr 26, 2001
Apr 26, 2001
194
Jun 16, 2002
Jun 16, 2002
195
196
197
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_PlayAudio\n");
#endif
Apr 26, 2001
Apr 26, 2001
198
Jun 16, 2002
Jun 16, 2002
199
200
201
if( !this->enabled){
return;
}
Apr 26, 2001
Apr 26, 2001
202
203
204
towrite = pcm_len;
Jun 16, 2002
Jun 16, 2002
205
206
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do {
Apr 26, 2001
Apr 26, 2001
207
written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
Jun 16, 2002
Jun 16, 2002
208
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
209
fprintf(stderr, "NTO_PlayAudio: written = %d towrite = %d\n",written,towrite);
Jun 16, 2002
Jun 16, 2002
210
211
212
213
214
#endif
if (written != towrite){
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){
SDL_Delay(1); /* Let a little CPU time go by and try to write again */
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
215
fprintf(stderr, "errno == EAGAIN written %d\n", written);
Jun 16, 2002
Jun 16, 2002
216
#endif
Apr 26, 2001
Apr 26, 2001
217
218
towrite -= written; //we wrote some data
continue;
Jun 16, 2002
Jun 16, 2002
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
}
else if((errno == EINVAL) || (errno == EIO)){
if(errno == EIO){
#ifdef DEBUG_AUDIO
fprintf(stderr,"snd_pcm_plugin_write failed EIO: %s\n", snd_strerror(written));
#endif
}
if(errno == EINVAL){
#ifdef DEBUG_AUDIO
fprintf(stderr,"snd_pcm_plugin_write failed EINVAL: %s\n", snd_strerror(written));
#endif
}
memset(&cstatus, 0, sizeof(cstatus));
if( (rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0 ){
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
235
fprintf(stderr, "snd_pcm_plugin_status failed %s\n",snd_strerror(rval));
Jun 16, 2002
Jun 16, 2002
236
237
238
239
#endif
SDL_SetError("snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
return;
}
Apr 26, 2001
Apr 26, 2001
240
Jun 16, 2002
Jun 16, 2002
241
242
if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY) ){
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
243
fprintf(stderr, "buffer underrun\n");
Jun 16, 2002
Jun 16, 2002
244
245
246
#endif
if ( (rval = snd_pcm_plugin_prepare (audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0 ){
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
247
fprintf(stderr, "NTO_PlayAudio: prepare failed %s\n",snd_strerror(rval));
Jun 16, 2002
Jun 16, 2002
248
#endif
Apr 26, 2001
Apr 26, 2001
249
250
251
252
253
254
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",snd_strerror(rval) );
return;
}
}
continue;
}
Jun 16, 2002
Jun 16, 2002
255
256
257
258
else{
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_PlayAudio: snd_pcm_plugin_write failed unknown errno %d %s\n",errno, snd_strerror(rval));
#endif
Apr 26, 2001
Apr 26, 2001
259
260
261
262
263
264
265
266
return;
}
}
else
{
towrite -= written; //we wrote all remaining data
}
Jun 16, 2002
Jun 16, 2002
267
} while ( (towrite > 0) && (this->enabled) );
Apr 26, 2001
Apr 26, 2001
268
Jun 16, 2002
Jun 16, 2002
269
270
271
272
/* If we couldn't write, assume fatal error for now */
if ( towrite != 0 ) {
this->enabled = 0;
}
Apr 26, 2001
Apr 26, 2001
273
274
275
276
277
return;
}
static Uint8 *NTO_GetAudioBuf(_THIS)
{
Jun 16, 2002
Jun 16, 2002
278
279
280
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_GetAudioBuf: pcm_buf %X\n",(Uint8 *)pcm_buf);
#endif
Apr 26, 2001
Apr 26, 2001
281
282
283
284
285
286
287
return(pcm_buf);
}
static void NTO_CloseAudio(_THIS)
{
int rval;
Jun 16, 2002
Jun 16, 2002
288
289
290
291
292
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_CloseAudio\n");
#endif
this->enabled = 0;
Apr 26, 2001
Apr 26, 2001
293
294
if ( audio_handle != NULL ) {
Jun 16, 2002
Jun 16, 2002
295
296
if ((rval = snd_pcm_plugin_flush(audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0){
SDL_SetError("snd_pcm_plugin_flush failed: %s\n",snd_strerror(rval));
Apr 26, 2001
Apr 26, 2001
297
298
return;
}
Jun 16, 2002
Jun 16, 2002
299
if ((rval = snd_pcm_close(audio_handle)) < 0){
Apr 26, 2001
Apr 26, 2001
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval));
return;
}
audio_handle = NULL;
}
}
static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
int rval;
int format;
Uint16 test_format;
int twidth;
int found;
Jun 16, 2002
Jun 16, 2002
315
316
317
#ifdef DEBUG_AUDIO
fprintf(stderr, "NTO_OpenAudio\n");
#endif
Apr 26, 2001
Apr 26, 2001
318
319
audio_handle = NULL;
Jun 16, 2002
Jun 16, 2002
320
this->enabled = 0;
Apr 26, 2001
Apr 26, 2001
321
322
323
324
325
326
327
328
329
330
if ( pcm_buf != NULL ) {
free((Uint8 *)pcm_buf);
pcm_buf = NULL;
}
/* initialize channel transfer parameters to default */
init_pcm_cparams(&cparams);
/* Open the audio device */
Jun 16, 2002
Jun 16, 2002
331
rval = snd_pcm_open_preferred(&audio_handle, NULL, NULL, OPEN_FLAGS);
Apr 26, 2001
Apr 26, 2001
332
333
334
335
336
if ( rval < 0 ) {
SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval));
return(-1);
}
Jun 16, 2002
Jun 16, 2002
337
338
339
340
341
/* enable count status parameter */
if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP))<0){
SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval));
return(-1);
}
Apr 26, 2001
Apr 26, 2001
342
343
344
/* Try for a closest match on audio format */
format = 0;
Jun 16, 2002
Jun 16, 2002
345
found = 0; /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
Apr 26, 2001
Apr 26, 2001
346
347
for ( test_format = SDL_FirstAudioFormat(spec->format); !found ; )
{
Jun 16, 2002
Jun 16, 2002
348
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
349
fprintf(stderr, "Trying format 0x%4.4x spec->samples %d\n", test_format,spec->samples);
Jun 16, 2002
Jun 16, 2002
350
351
352
353
#endif
/* if match found set format to equivalent ALSA format */
switch ( test_format ) {
Apr 26, 2001
Apr 26, 2001
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
case AUDIO_U8:
format = SND_PCM_SFMT_U8;
found = 1;
break;
case AUDIO_S8:
format = SND_PCM_SFMT_S8;
found = 1;
break;
case AUDIO_S16LSB:
format = SND_PCM_SFMT_S16_LE;
found = 1;
break;
case AUDIO_S16MSB:
format = SND_PCM_SFMT_S16_BE;
found = 1;
break;
case AUDIO_U16LSB:
format = SND_PCM_SFMT_U16_LE;
found = 1;
break;
case AUDIO_U16MSB:
format = SND_PCM_SFMT_U16_BE;
found = 1;
break;
default:
break;
}
if ( ! found ) {
test_format = SDL_NextAudioFormat();
}
}
Jun 16, 2002
Jun 16, 2002
385
Apr 26, 2001
Apr 26, 2001
386
387
388
389
390
/* assumes test_format not 0 on success */
if ( test_format == 0 ) {
SDL_SetError("Couldn't find any hardware audio formats");
return(-1);
}
Jun 16, 2002
Jun 16, 2002
391
Apr 26, 2001
Apr 26, 2001
392
393
394
395
396
397
398
399
spec->format = test_format;
/* Set the audio format */
cparams.format.format = format;
/* Set mono or stereo audio (currently only two channels supported) */
cparams.format.voices = spec->channels;
Jun 16, 2002
Jun 16, 2002
400
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
401
fprintf(stderr,"intializing channels %d\n", cparams.format.voices);
Jun 16, 2002
Jun 16, 2002
402
#endif
Apr 26, 2001
Apr 26, 2001
403
404
405
406
407
408
409
410
411
412
413
/* Set rate */
cparams.format.rate = spec->freq ;
/* Setup the transfer parameters according to cparams */
rval = snd_pcm_plugin_params(audio_handle, &cparams);
if (rval < 0) {
SDL_SetError("snd_pcm_channel_params failed: %s\n", snd_strerror (rval));
return(-1);
}
Jun 16, 2002
Jun 16, 2002
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/* Make sure channel is setup right one last time */
memset( &csetup, 0, sizeof( csetup ) );
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if ( snd_pcm_plugin_setup( audio_handle, &csetup ) < 0 )
{
SDL_SetError("Unable to setup playback channel\n" );
return(-1);
}
else
{
#ifdef DEBUG_AUDIO
fprintf(stderr,"requested format: %d\n",cparams.format.format);
fprintf(stderr,"requested frag size: %d\n",cparams.buf.block.frag_size);
fprintf(stderr,"requested max frags: %d\n\n",cparams.buf.block.frags_max);
fprintf(stderr,"real format: %d\n", csetup.format.format );
fprintf(stderr,"real frag size : %d\n", csetup.buf.block.frag_size );
Apr 26, 2001
Apr 26, 2001
431
fprintf(stderr,"real max frags : %d\n", csetup.buf.block.frags_max );
Jun 16, 2002
Jun 16, 2002
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#endif
}
/*
Allocate memory to the audio buffer and initialize with silence (Note that
buffer size must be a multiple of fragment size, so find closest multiple)
*/
twidth = snd_pcm_format_width(format);
if (twidth < 0) {
printf("snd_pcm_format_width failed\n");
twidth = 0;
}
#ifdef DEBUG_AUDIO
fprintf(stderr,"format is %d bits wide\n",twidth);
#endif
pcm_len = spec->size ;
#ifdef DEBUG_AUDIO
fprintf(stderr,"pcm_len set to %d\n", pcm_len);
#endif
if (pcm_len == 0){
pcm_len = csetup.buf.block.frag_size;
}
pcm_buf = (Uint8*)malloc(pcm_len);
if (pcm_buf == NULL) {
SDL_SetError("pcm_buf malloc failed\n");
return(-1);
}
memset(pcm_buf,spec->silence,pcm_len);
#ifdef DEBUG_AUDIO
Apr 26, 2001
Apr 26, 2001
468
fprintf(stderr,"pcm_buf malloced and silenced.\n");
Jun 16, 2002
Jun 16, 2002
469
#endif
Apr 26, 2001
Apr 26, 2001
470
Jun 16, 2002
Jun 16, 2002
471
472
473
474
/* get the file descriptor */
if( (audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0){
fprintf(stderr, "snd_pcm_file_descriptor failed with error code: %d\n", audio_fd);
}
Apr 26, 2001
Apr 26, 2001
475
476
477
478
/* Trigger audio playback */
rval = snd_pcm_plugin_prepare( audio_handle, SND_PCM_CHANNEL_PLAYBACK);
if (rval < 0) {
Jun 16, 2002
Jun 16, 2002
479
480
SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror (rval));
return(-1);
Apr 26, 2001
Apr 26, 2001
481
}
Jun 16, 2002
Jun 16, 2002
482
483
484
this->enabled = 1;
Apr 26, 2001
Apr 26, 2001
485
486
487
488
489
490
/* Get the parent process id (we're the parent of the audio thread) */
parent = getpid();
/* We're ready to rock and roll. :-) */
return(0);
}