comparison src/audio/qsa/SDL_qsa_audio.c @ 3139:7f684f249ec9

indent
author Sam Lantinga <slouken@libsdl.org>
date Sat, 23 May 2009 22:41:08 +0000
parents 60301ed80050
children f7b03b6838cb
comparison
equal deleted inserted replaced
3125:d71d8ceda8b3 3139:7f684f249ec9
57 #define QSA_NO_WORKAROUNDS 0x00000000 57 #define QSA_NO_WORKAROUNDS 0x00000000
58 #define QSA_MMAP_WORKAROUND 0x00000001 58 #define QSA_MMAP_WORKAROUND 0x00000001
59 59
60 struct BuggyCards 60 struct BuggyCards
61 { 61 {
62 char* cardname; 62 char *cardname;
63 unsigned long bugtype; 63 unsigned long bugtype;
64 }; 64 };
65 65
66 #define QSA_WA_CARDS 3 66 #define QSA_WA_CARDS 3
67 #define QSA_MAX_CARD_NAME_LENGTH 33 67 #define QSA_MAX_CARD_NAME_LENGTH 33
68 68
69 struct BuggyCards buggycards[QSA_WA_CARDS]= 69 struct BuggyCards buggycards[QSA_WA_CARDS] = {
70 { 70 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
71 {"Sound Blaster Live!", QSA_MMAP_WORKAROUND}, 71 {"Vortex 8820", QSA_MMAP_WORKAROUND},
72 {"Vortex 8820", QSA_MMAP_WORKAROUND}, 72 {"Vortex 8830", QSA_MMAP_WORKAROUND},
73 {"Vortex 8830", QSA_MMAP_WORKAROUND},
74 }; 73 };
75 74
76 /* List of found devices */ 75 /* List of found devices */
77 #define QSA_MAX_DEVICES 32 76 #define QSA_MAX_DEVICES 32
78 #define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */ 77 #define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */
79 78
80 typedef struct _QSA_Device 79 typedef struct _QSA_Device
81 { 80 {
82 char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */ 81 char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */
83 int cardno; 82 int cardno;
84 int deviceno; 83 int deviceno;
85 } QSA_Device; 84 } QSA_Device;
86 85
87 QSA_Device qsa_playback_device[QSA_MAX_DEVICES]; 86 QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
88 uint32_t qsa_playback_devices; 87 uint32_t qsa_playback_devices;
89 88
90 QSA_Device qsa_capture_device[QSA_MAX_DEVICES]; 89 QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
91 uint32_t qsa_capture_devices; 90 uint32_t qsa_capture_devices;
92 91
93 static inline void QSA_SetError(const char* fn, int status) 92 static inline void
94 { 93 QSA_SetError(const char *fn, int status)
95 SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status)); 94 {
95 SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status));
96 } 96 }
97 97
98 /* card names check to apply the workarounds */ 98 /* card names check to apply the workarounds */
99 static int QSA_CheckBuggyCards(_THIS, unsigned long checkfor) 99 static int
100 { 100 QSA_CheckBuggyCards(_THIS, unsigned long checkfor)
101 char scardname[QSA_MAX_CARD_NAME_LENGTH]; 101 {
102 int it; 102 char scardname[QSA_MAX_CARD_NAME_LENGTH];
103 103 int it;
104 if (snd_card_get_name(this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH-1)<0) 104
105 { 105 if (snd_card_get_name
106 return 0; 106 (this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) {
107 } 107 return 0;
108 108 }
109 for (it=0; it<QSA_WA_CARDS; it++) 109
110 { 110 for (it = 0; it < QSA_WA_CARDS; it++) {
111 if (SDL_strcmp(buggycards[it].cardname, scardname)==0) 111 if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
112 { 112 if (buggycards[it].bugtype == checkfor) {
113 if (buggycards[it].bugtype==checkfor) 113 return 1;
114 { 114 }
115 return 1; 115 }
116 } 116 }
117 } 117
118 } 118 return 0;
119 119 }
120 return 0; 120
121 } 121 static void
122 122 QSA_ThreadInit(_THIS)
123 static void QSA_ThreadInit(_THIS) 123 {
124 { 124 struct sched_param param;
125 struct sched_param param; 125 int status;
126 int status; 126
127 127 /* Increase default 10 priority to 25 to avoid jerky sound */
128 /* Increase default 10 priority to 25 to avoid jerky sound */ 128 status = SchedGet(0, 0, &param);
129 status=SchedGet(0, 0, &param); 129 param.sched_priority = param.sched_curpriority + 15;
130 param.sched_priority=param.sched_curpriority + 15; 130 status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
131 status=SchedSet(0, 0, SCHED_NOCHANGE, &param);
132 } 131 }
133 132
134 /* PCM channel parameters initialize function */ 133 /* PCM channel parameters initialize function */
135 static void QSA_InitAudioParams(snd_pcm_channel_params_t* cpars) 134 static void
136 { 135 QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
137 SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); 136 {
138 137 SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
139 cpars->channel=SND_PCM_CHANNEL_PLAYBACK; 138
140 cpars->mode=SND_PCM_MODE_BLOCK; 139 cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
141 cpars->start_mode=SND_PCM_START_DATA; 140 cpars->mode = SND_PCM_MODE_BLOCK;
142 cpars->stop_mode=SND_PCM_STOP_STOP; 141 cpars->start_mode = SND_PCM_START_DATA;
143 cpars->format.format=SND_PCM_SFMT_S16_LE; 142 cpars->stop_mode = SND_PCM_STOP_STOP;
144 cpars->format.interleave=1; 143 cpars->format.format = SND_PCM_SFMT_S16_LE;
145 cpars->format.rate=DEFAULT_CPARAMS_RATE; 144 cpars->format.interleave = 1;
146 cpars->format.voices=DEFAULT_CPARAMS_VOICES; 145 cpars->format.rate = DEFAULT_CPARAMS_RATE;
147 cpars->buf.block.frag_size=DEFAULT_CPARAMS_FRAG_SIZE; 146 cpars->format.voices = DEFAULT_CPARAMS_VOICES;
148 cpars->buf.block.frags_min=DEFAULT_CPARAMS_FRAGS_MIN; 147 cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
149 cpars->buf.block.frags_max=DEFAULT_CPARAMS_FRAGS_MAX; 148 cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
149 cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
150 } 150 }
151 151
152 /* This function waits until it is possible to write a full sound buffer */ 152 /* This function waits until it is possible to write a full sound buffer */
153 static void QSA_WaitDevice(_THIS) 153 static void
154 { 154 QSA_WaitDevice(_THIS)
155 fd_set wfds; 155 {
156 fd_set rfds; 156 fd_set wfds;
157 int selectret; 157 fd_set rfds;
158 struct timeval timeout; 158 int selectret;
159 159 struct timeval timeout;
160 if (!this->hidden->iscapture) 160
161 { 161 if (!this->hidden->iscapture) {
162 FD_ZERO(&wfds); 162 FD_ZERO(&wfds);
163 FD_SET(this->hidden->audio_fd, &wfds); 163 FD_SET(this->hidden->audio_fd, &wfds);
164 } 164 } else {
165 else 165 FD_ZERO(&rfds);
166 { 166 FD_SET(this->hidden->audio_fd, &rfds);
167 FD_ZERO(&rfds); 167 }
168 FD_SET(this->hidden->audio_fd, &rfds); 168
169 } 169 do {
170 170 /* Setup timeout for playing one fragment equal to 2 seconds */
171 do { 171 /* If timeout occured than something wrong with hardware or driver */
172 /* Setup timeout for playing one fragment equal to 2 seconds */ 172 /* For example, Vortex 8820 audio driver stucks on second DAC because */
173 /* If timeout occured than something wrong with hardware or driver */ 173 /* it doesn't exist ! */
174 /* For example, Vortex 8820 audio driver stucks on second DAC because */ 174 timeout.tv_sec = 2;
175 /* it doesn't exist ! */ 175 timeout.tv_usec = 0;
176 timeout.tv_sec=2; 176 this->hidden->timeout_on_wait = 0;
177 timeout.tv_usec=0; 177
178 this->hidden->timeout_on_wait=0; 178 if (!this->hidden->iscapture) {
179 179 selectret =
180 if (!this->hidden->iscapture) 180 select(this->hidden->audio_fd + 1, NULL, &wfds, NULL,
181 { 181 &timeout);
182 selectret=select(this->hidden->audio_fd+1, NULL, &wfds, NULL, &timeout); 182 } else {
183 } 183 selectret =
184 else 184 select(this->hidden->audio_fd + 1, &rfds, NULL, NULL,
185 { 185 &timeout);
186 selectret=select(this->hidden->audio_fd+1, &rfds, NULL, NULL, &timeout); 186 }
187 } 187
188 188 switch (selectret) {
189 switch(selectret) 189 case -1:
190 { 190 {
191 case -1: 191 SDL_SetError("QSA: select() failed: %s\n", strerror(errno));
192 { 192 return;
193 SDL_SetError("QSA: select() failed: %s\n", strerror(errno)); 193 }
194 return; 194 break;
195 } 195 case 0:
196 break; 196 {
197 case 0: 197 SDL_SetError("QSA: timeout on buffer waiting occured\n");
198 { 198 this->hidden->timeout_on_wait = 1;
199 SDL_SetError("QSA: timeout on buffer waiting occured\n"); 199 return;
200 this->hidden->timeout_on_wait=1; 200 }
201 return; 201 break;
202 } 202 default:
203 break; 203 {
204 default: 204 if (!this->hidden->iscapture) {
205 { 205 if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
206 if (!this->hidden->iscapture) 206 return;
207 {
208 if (FD_ISSET(this->hidden->audio_fd, &wfds))
209 {
210 return;
211 } 207 }
212 } 208 } else {
213 else 209 if (FD_ISSET(this->hidden->audio_fd, &rfds)) {
214 { 210 return;
215 if (FD_ISSET(this->hidden->audio_fd, &rfds))
216 {
217 return;
218 } 211 }
219 } 212 }
220 } 213 }
221 break; 214 break;
222 } 215 }
223 } while (1); 216 } while (1);
224 } 217 }
225 218
226 static void QSA_PlayDevice(_THIS) 219 static void
227 { 220 QSA_PlayDevice(_THIS)
228 snd_pcm_channel_status_t cstatus; 221 {
229 int written; 222 snd_pcm_channel_status_t cstatus;
230 int status; 223 int written;
231 int towrite; 224 int status;
232 void* pcmbuffer; 225 int towrite;
233 226 void *pcmbuffer;
234 if ((!this->enabled) || (!this->hidden)) 227
235 { 228 if ((!this->enabled) || (!this->hidden)) {
236 return; 229 return;
237 } 230 }
238 231
239 towrite = this->spec.size; 232 towrite = this->spec.size;
240 pcmbuffer = this->hidden->pcm_buf; 233 pcmbuffer = this->hidden->pcm_buf;
241 234
242 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ 235 /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
243 do { 236 do {
244 written=snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer, towrite); 237 written =
245 if (written!=towrite) 238 snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
246 { 239 towrite);
247 /* Check if samples playback got stuck somewhere in hardware or in */ 240 if (written != towrite) {
248 /* the audio device driver */ 241 /* Check if samples playback got stuck somewhere in hardware or in */
249 if ((errno==EAGAIN) && (written==0)) 242 /* the audio device driver */
250 { 243 if ((errno == EAGAIN) && (written == 0)) {
251 if (this->hidden->timeout_on_wait!=0) 244 if (this->hidden->timeout_on_wait != 0) {
252 { 245 SDL_SetError("QSA: buffer playback timeout\n");
253 SDL_SetError("QSA: buffer playback timeout\n"); 246 return;
254 return; 247 }
255 } 248 }
256 } 249
257 250 /* Check for errors or conditions */
258 /* Check for errors or conditions */ 251 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
259 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) 252 /* Let a little CPU time go by and try to write again */
260 { 253 SDL_Delay(1);
261 /* Let a little CPU time go by and try to write again */ 254
262 SDL_Delay(1); 255 /* if we wrote some data */
263 256 towrite -= written;
264 /* if we wrote some data */ 257 pcmbuffer += written * this->spec.channels;
265 towrite-=written; 258 continue;
266 pcmbuffer+=written*this->spec.channels; 259 } else {
267 continue; 260 if ((errno == EINVAL) || (errno == EIO)) {
268 } 261 SDL_memset(&cstatus, 0, sizeof(cstatus));
269 else 262 if (!this->hidden->iscapture) {
270 { 263 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
271 if ((errno==EINVAL)||(errno==EIO)) 264 } else {
272 { 265 cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
273 SDL_memset(&cstatus, 0, sizeof(cstatus)); 266 }
274 if (!this->hidden->iscapture) 267
275 { 268 status =
276 cstatus.channel=SND_PCM_CHANNEL_PLAYBACK; 269 snd_pcm_plugin_status(this->hidden->audio_handle,
277 } 270 &cstatus);
278 else 271 if (status < 0) {
279 { 272 QSA_SetError("snd_pcm_plugin_status", status);
280 cstatus.channel=SND_PCM_CHANNEL_CAPTURE; 273 return;
281 } 274 }
282 275
283 status=snd_pcm_plugin_status(this->hidden->audio_handle, &cstatus); 276 if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
284 if (status<0) 277 (cstatus.status == SND_PCM_STATUS_READY)) {
285 { 278 if (!this->hidden->iscapture) {
286 QSA_SetError("snd_pcm_plugin_status", status); 279 status =
287 return; 280 snd_pcm_plugin_prepare(this->hidden->
288 } 281 audio_handle,
289 282 SND_PCM_CHANNEL_PLAYBACK);
290 if ((cstatus.status==SND_PCM_STATUS_UNDERRUN) || 283 } else {
291 (cstatus.status==SND_PCM_STATUS_READY)) 284 status =
292 { 285 snd_pcm_plugin_prepare(this->hidden->
293 if (!this->hidden->iscapture) 286 audio_handle,
294 { 287 SND_PCM_CHANNEL_CAPTURE);
295 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, 288 }
296 SND_PCM_CHANNEL_PLAYBACK); 289 if (status < 0) {
297 } 290 QSA_SetError("snd_pcm_plugin_prepare", status);
298 else 291 return;
299 { 292 }
300 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, 293 }
301 SND_PCM_CHANNEL_CAPTURE); 294 continue;
302 } 295 } else {
303 if (status<0) 296 return;
304 { 297 }
305 QSA_SetError("snd_pcm_plugin_prepare", status); 298 }
306 return; 299 } else {
307 } 300 /* we wrote all remaining data */
308 } 301 towrite -= written;
309 continue; 302 pcmbuffer += written * this->spec.channels;
310 } 303 }
311 else 304 } while ((towrite > 0) && (this->enabled));
312 { 305
313 return; 306 /* If we couldn't write, assume fatal error for now */
314 } 307 if (towrite != 0) {
315 } 308 this->enabled = 0;
316 } 309 }
317 else 310 }
318 { 311
319 /* we wrote all remaining data */ 312 static Uint8 *
320 towrite -= written; 313 QSA_GetDeviceBuf(_THIS)
321 pcmbuffer += written * this->spec.channels; 314 {
322 } 315 return this->hidden->pcm_buf;
323 } while ((towrite>0) && (this->enabled)); 316 }
324 317
325 /* If we couldn't write, assume fatal error for now */ 318 static void
326 if (towrite!=0) 319 QSA_CloseDevice(_THIS)
327 { 320 {
328 this->enabled=0; 321 if (this->hidden != NULL) {
329 } 322 if (this->hidden->audio_handle != NULL) {
330 } 323 if (!this->hidden->iscapture) {
331 324 /* Finish playing available samples */
332 static Uint8* QSA_GetDeviceBuf(_THIS) 325 snd_pcm_plugin_flush(this->hidden->audio_handle,
333 { 326 SND_PCM_CHANNEL_PLAYBACK);
334 return this->hidden->pcm_buf; 327 } else {
335 } 328 /* Cancel unread samples during capture */
336 329 snd_pcm_plugin_flush(this->hidden->audio_handle,
337 static void QSA_CloseDevice(_THIS) 330 SND_PCM_CHANNEL_CAPTURE);
338 { 331 }
339 if (this->hidden!=NULL) 332 snd_pcm_close(this->hidden->audio_handle);
340 { 333 this->hidden->audio_handle = NULL;
341 if (this->hidden->audio_handle!=NULL) 334 }
342 { 335
343 if (!this->hidden->iscapture) 336 if (this->hidden->pcm_buf != NULL) {
344 { 337 SDL_FreeAudioMem(this->hidden->pcm_buf);
345 /* Finish playing available samples */ 338 this->hidden->pcm_buf = NULL;
346 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); 339 }
347 } 340
348 else 341 SDL_free(this->hidden);
349 { 342 this->hidden = NULL;
350 /* Cancel unread samples during capture */ 343 }
351 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE); 344 }
352 } 345
353 snd_pcm_close(this->hidden->audio_handle); 346 static int
354 this->hidden->audio_handle=NULL; 347 QSA_OpenDevice(_THIS, const char *devname, int iscapture)
355 } 348 {
356 349 int status = 0;
357 if (this->hidden->pcm_buf!=NULL) 350 int format = 0;
358 { 351 SDL_AudioFormat test_format = 0;
359 SDL_FreeAudioMem(this->hidden->pcm_buf); 352 int found = 0;
360 this->hidden->pcm_buf=NULL; 353 snd_pcm_channel_setup_t csetup;
361 } 354 snd_pcm_channel_params_t cparams;
362 355
363 SDL_free(this->hidden); 356 /* Initialize all variables that we clean on shutdown */
364 this->hidden=NULL; 357 this->hidden =
365 } 358 (struct SDL_PrivateAudioData *) SDL_calloc(1,
366 } 359 (sizeof
367 360 (struct
368 static int QSA_OpenDevice(_THIS, const char* devname, int iscapture) 361 SDL_PrivateAudioData)));
369 { 362 if (this->hidden == NULL) {
370 int status=0; 363 SDL_OutOfMemory();
371 int format=0; 364 return 0;
372 SDL_AudioFormat test_format=0; 365 }
373 int found=0; 366 SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
374 snd_pcm_channel_setup_t csetup; 367
375 snd_pcm_channel_params_t cparams; 368 /* Initialize channel transfer parameters to default */
376 369 QSA_InitAudioParams(&cparams);
377 /* Initialize all variables that we clean on shutdown */ 370
378 this->hidden=(struct SDL_PrivateAudioData*)SDL_calloc(1, (sizeof(struct SDL_PrivateAudioData))); 371 /* Initialize channel direction: capture or playback */
379 if (this->hidden==NULL) 372 this->hidden->iscapture = iscapture;
380 { 373
381 SDL_OutOfMemory(); 374 /* Find deviceid and cardid by device name for playback */
382 return 0; 375 if ((!this->hidden->iscapture) && (devname != NULL)) {
383 } 376 uint32_t device;
384 SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); 377 int32_t status;
385 378
386 /* Initialize channel transfer parameters to default */ 379 /* Search in the playback devices */
387 QSA_InitAudioParams(&cparams); 380 device = 0;
388 381 do {
389 /* Initialize channel direction: capture or playback */ 382 status = SDL_strcmp(qsa_playback_device[device].name, devname);
390 this->hidden->iscapture=iscapture; 383 if (status == 0) {
391 384 /* Found requested device */
392 /* Find deviceid and cardid by device name for playback */ 385 this->hidden->deviceno = qsa_playback_device[device].deviceno;
393 if ((!this->hidden->iscapture) && (devname!=NULL)) 386 this->hidden->cardno = qsa_playback_device[device].cardno;
394 { 387 break;
395 uint32_t device; 388 }
396 int32_t status; 389 device++;
397 390 if (device >= qsa_playback_devices) {
398 /* Search in the playback devices */ 391 QSA_CloseDevice(this);
399 device=0; 392 SDL_SetError("No such playback device");
400 do { 393 return 0;
401 status=SDL_strcmp(qsa_playback_device[device].name, devname); 394 }
402 if (status==0) 395 } while (1);
403 { 396 }
404 /* Found requested device */ 397
405 this->hidden->deviceno=qsa_playback_device[device].deviceno; 398 /* Find deviceid and cardid by device name for capture */
406 this->hidden->cardno=qsa_playback_device[device].cardno; 399 if ((this->hidden->iscapture) && (devname != NULL)) {
407 break; 400 /* Search in the capture devices */
408 } 401 uint32_t device;
409 device++; 402 int32_t status;
410 if (device>=qsa_playback_devices) 403
411 { 404 /* Searching in the playback devices */
405 device = 0;
406 do {
407 status = SDL_strcmp(qsa_capture_device[device].name, devname);
408 if (status == 0) {
409 /* Found requested device */
410 this->hidden->deviceno = qsa_capture_device[device].deviceno;
411 this->hidden->cardno = qsa_capture_device[device].cardno;
412 break;
413 }
414 device++;
415 if (device >= qsa_capture_devices) {
416 QSA_CloseDevice(this);
417 SDL_SetError("No such capture device");
418 return 0;
419 }
420 } while (1);
421 }
422
423 /* Check if SDL requested default audio device */
424 if (devname == NULL) {
425 /* Open system default audio device */
426 if (!this->hidden->iscapture) {
427 status = snd_pcm_open_preferred(&this->hidden->audio_handle,
428 &this->hidden->cardno,
429 &this->hidden->deviceno,
430 SND_PCM_OPEN_PLAYBACK);
431 } else {
432 status = snd_pcm_open_preferred(&this->hidden->audio_handle,
433 &this->hidden->cardno,
434 &this->hidden->deviceno,
435 SND_PCM_OPEN_CAPTURE);
436 }
437 } else {
438 /* Open requested audio device */
439 if (!this->hidden->iscapture) {
440 status =
441 snd_pcm_open(&this->hidden->audio_handle,
442 this->hidden->cardno, this->hidden->deviceno,
443 SND_PCM_OPEN_PLAYBACK);
444 } else {
445 status =
446 snd_pcm_open(&this->hidden->audio_handle,
447 this->hidden->cardno, this->hidden->deviceno,
448 SND_PCM_OPEN_CAPTURE);
449 }
450 }
451
452 /* Check if requested device is opened */
453 if (status < 0) {
454 this->hidden->audio_handle = NULL;
455 QSA_CloseDevice(this);
456 QSA_SetError("snd_pcm_open", status);
457 return 0;
458 }
459
460 if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
461 /* Disable QSA MMAP plugin for buggy audio drivers */
462 status =
463 snd_pcm_plugin_set_disable(this->hidden->audio_handle,
464 PLUGIN_DISABLE_MMAP);
465 if (status < 0) {
412 QSA_CloseDevice(this); 466 QSA_CloseDevice(this);
413 SDL_SetError("No such playback device"); 467 QSA_SetError("snd_pcm_plugin_set_disable", status);
414 return 0; 468 return 0;
415 } 469 }
416 } while(1); 470 }
417 } 471
418 472 /* Try for a closest match on audio format */
419 /* Find deviceid and cardid by device name for capture */ 473 format = 0;
420 if ((this->hidden->iscapture) && (devname!=NULL)) 474 /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */
421 { 475 found = 0;
422 /* Search in the capture devices */ 476
423 uint32_t device; 477 for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
424 int32_t status; 478 /* if match found set format to equivalent QSA format */
425 479 switch (test_format) {
426 /* Searching in the playback devices */ 480 case AUDIO_U8:
427 device=0; 481 {
428 do { 482 format = SND_PCM_SFMT_U8;
429 status=SDL_strcmp(qsa_capture_device[device].name, devname); 483 found = 1;
430 if (status==0) 484 }
431 { 485 break;
432 /* Found requested device */ 486 case AUDIO_S8:
433 this->hidden->deviceno=qsa_capture_device[device].deviceno; 487 {
434 this->hidden->cardno=qsa_capture_device[device].cardno; 488 format = SND_PCM_SFMT_S8;
435 break; 489 found = 1;
436 } 490 }
437 device++; 491 break;
438 if (device>=qsa_capture_devices) 492 case AUDIO_S16LSB:
439 { 493 {
440 QSA_CloseDevice(this); 494 format = SND_PCM_SFMT_S16_LE;
441 SDL_SetError("No such capture device"); 495 found = 1;
442 return 0; 496 }
443 } 497 break;
444 } while(1); 498 case AUDIO_S16MSB:
445 } 499 {
446 500 format = SND_PCM_SFMT_S16_BE;
447 /* Check if SDL requested default audio device */ 501 found = 1;
448 if (devname==NULL) 502 }
449 { 503 break;
450 /* Open system default audio device */ 504 case AUDIO_U16LSB:
451 if (!this->hidden->iscapture) 505 {
452 { 506 format = SND_PCM_SFMT_U16_LE;
453 status=snd_pcm_open_preferred(&this->hidden->audio_handle, 507 found = 1;
454 &this->hidden->cardno, 508 }
455 &this->hidden->deviceno, SND_PCM_OPEN_PLAYBACK); 509 break;
456 } 510 case AUDIO_U16MSB:
457 else 511 {
458 { 512 format = SND_PCM_SFMT_U16_BE;
459 status=snd_pcm_open_preferred(&this->hidden->audio_handle, 513 found = 1;
460 &this->hidden->cardno, 514 }
461 &this->hidden->deviceno, SND_PCM_OPEN_CAPTURE); 515 break;
462 } 516 case AUDIO_S32LSB:
463 } 517 {
464 else 518 format = SND_PCM_SFMT_S32_LE;
465 { 519 found = 1;
466 /* Open requested audio device */ 520 }
467 if (!this->hidden->iscapture) 521 break;
468 { 522 case AUDIO_S32MSB:
469 status=snd_pcm_open(&this->hidden->audio_handle, this->hidden->cardno, 523 {
470 this->hidden->deviceno, SND_PCM_OPEN_PLAYBACK); 524 format = SND_PCM_SFMT_S32_BE;
471 } 525 found = 1;
472 else 526 }
473 { 527 break;
474 status=snd_pcm_open(&this->hidden->audio_handle, this->hidden->cardno, 528 case AUDIO_F32LSB:
475 this->hidden->deviceno, SND_PCM_OPEN_CAPTURE); 529 {
476 } 530 format = SND_PCM_SFMT_FLOAT_LE;
477 } 531 found = 1;
478 532 }
479 /* Check if requested device is opened */ 533 break;
480 if (status<0) 534 case AUDIO_F32MSB:
481 { 535 {
482 this->hidden->audio_handle=NULL; 536 format = SND_PCM_SFMT_FLOAT_BE;
483 QSA_CloseDevice(this); 537 found = 1;
484 QSA_SetError("snd_pcm_open", status); 538 }
485 return 0; 539 break;
486 } 540 default:
487 541 {
488 if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) 542 break;
489 { 543 }
490 /* Disable QSA MMAP plugin for buggy audio drivers */ 544 }
491 status=snd_pcm_plugin_set_disable(this->hidden->audio_handle, PLUGIN_DISABLE_MMAP); 545
492 if (status<0) 546 if (!found) {
493 { 547 test_format = SDL_NextAudioFormat();
494 QSA_CloseDevice(this); 548 }
495 QSA_SetError("snd_pcm_plugin_set_disable", status); 549 }
496 return 0; 550
497 } 551 /* assumes test_format not 0 on success */
498 } 552 if (test_format == 0) {
499 553 QSA_CloseDevice(this);
500 /* Try for a closest match on audio format */ 554 SDL_SetError("QSA: Couldn't find any hardware audio formats");
501 format = 0; 555 return 0;
502 /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */ 556 }
503 found = 0; 557
504 558 this->spec.format = test_format;
505 for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) 559
506 { 560 /* Set the audio format */
507 /* if match found set format to equivalent QSA format */ 561 cparams.format.format = format;
508 switch (test_format) 562
509 { 563 /* Set mono/stereo/4ch/6ch/8ch audio */
510 case AUDIO_U8: 564 cparams.format.voices = this->spec.channels;
511 { 565
512 format=SND_PCM_SFMT_U8; 566 /* Set rate */
513 found=1; 567 cparams.format.rate = this->spec.freq;
514 } 568
515 break; 569 /* Setup the transfer parameters according to cparams */
516 case AUDIO_S8: 570 status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
517 { 571 if (status < 0) {
518 format=SND_PCM_SFMT_S8; 572 QSA_CloseDevice(this);
519 found=1; 573 QSA_SetError("snd_pcm_channel_params", status);
520 } 574 return 0;
521 break; 575 }
522 case AUDIO_S16LSB: 576
523 { 577 /* Make sure channel is setup right one last time */
524 format=SND_PCM_SFMT_S16_LE; 578 SDL_memset(&csetup, '\0', sizeof(csetup));
525 found=1; 579 if (!this->hidden->iscapture) {
526 } 580 csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
527 break; 581 } else {
528 case AUDIO_S16MSB: 582 csetup.channel = SND_PCM_CHANNEL_CAPTURE;
529 { 583 }
530 format=SND_PCM_SFMT_S16_BE; 584
531 found=1; 585 /* Setup an audio channel */
532 } 586 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
533 break; 587 QSA_CloseDevice(this);
534 case AUDIO_U16LSB: 588 SDL_SetError("QSA: Unable to setup channel\n");
535 { 589 return 0;
536 format=SND_PCM_SFMT_U16_LE; 590 }
537 found=1; 591
538 } 592 /* Calculate the final parameters for this audio specification */
539 break; 593 SDL_CalculateAudioSpec(&this->spec);
540 case AUDIO_U16MSB: 594
541 { 595 this->hidden->pcm_len = this->spec.size;
542 format=SND_PCM_SFMT_U16_BE; 596
543 found=1; 597 if (this->hidden->pcm_len == 0) {
544 } 598 this->hidden->pcm_len =
545 break; 599 csetup.buf.block.frag_size * this->spec.channels *
546 case AUDIO_S32LSB: 600 (snd_pcm_format_width(format) / 8);
547 { 601 }
548 format=SND_PCM_SFMT_S32_LE; 602
549 found=1; 603 /*
550 } 604 * Allocate memory to the audio buffer and initialize with silence
551 break; 605 * (Note that buffer size must be a multiple of fragment size, so find
552 case AUDIO_S32MSB: 606 * closest multiple)
553 { 607 */
554 format=SND_PCM_SFMT_S32_BE; 608 this->hidden->pcm_buf =
555 found=1; 609 (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
556 } 610 if (this->hidden->pcm_buf == NULL) {
557 break; 611 QSA_CloseDevice(this);
558 case AUDIO_F32LSB: 612 SDL_OutOfMemory();
559 { 613 return 0;
560 format=SND_PCM_SFMT_FLOAT_LE; 614 }
561 found=1; 615 SDL_memset(this->hidden->pcm_buf, this->spec.silence,
562 } 616 this->hidden->pcm_len);
563 break; 617
564 case AUDIO_F32MSB: 618 /* get the file descriptor */
565 { 619 if (!this->hidden->iscapture) {
566 format=SND_PCM_SFMT_FLOAT_BE; 620 this->hidden->audio_fd =
567 found=1; 621 snd_pcm_file_descriptor(this->hidden->audio_handle,
568 } 622 SND_PCM_CHANNEL_PLAYBACK);
569 break; 623 } else {
570 default: 624 this->hidden->audio_fd =
571 { 625 snd_pcm_file_descriptor(this->hidden->audio_handle,
572 break; 626 SND_PCM_CHANNEL_CAPTURE);
573 } 627 }
574 } 628
575 629 if (this->hidden->audio_fd < 0) {
576 if (!found) 630 QSA_CloseDevice(this);
577 { 631 QSA_SetError("snd_pcm_file_descriptor", status);
578 test_format = SDL_NextAudioFormat(); 632 return 0;
579 } 633 }
580 } 634
581 635 /* Prepare an audio channel */
582 /* assumes test_format not 0 on success */ 636 if (!this->hidden->iscapture) {
583 if (test_format==0) 637 /* Prepare audio playback */
584 { 638 status =
585 QSA_CloseDevice(this); 639 snd_pcm_plugin_prepare(this->hidden->audio_handle,
586 SDL_SetError("QSA: Couldn't find any hardware audio formats"); 640 SND_PCM_CHANNEL_PLAYBACK);
587 return 0; 641 } else {
588 } 642 /* Prepare audio capture */
589 643 status =
590 this->spec.format=test_format; 644 snd_pcm_plugin_prepare(this->hidden->audio_handle,
591 645 SND_PCM_CHANNEL_CAPTURE);
592 /* Set the audio format */ 646 }
593 cparams.format.format=format; 647
594 648 if (status < 0) {
595 /* Set mono/stereo/4ch/6ch/8ch audio */ 649 QSA_CloseDevice(this);
596 cparams.format.voices=this->spec.channels; 650 QSA_SetError("snd_pcm_plugin_prepare", status);
597 651 return 0;
598 /* Set rate */ 652 }
599 cparams.format.rate=this->spec.freq; 653
600 654 /* We're really ready to rock and roll. :-) */
601 /* Setup the transfer parameters according to cparams */ 655 return 1;
602 status=snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); 656 }
603 if (status<0) 657
604 { 658 int
605 QSA_CloseDevice(this); 659 QSA_DetectDevices(int iscapture)
606 QSA_SetError("snd_pcm_channel_params", status); 660 {
607 return 0; 661 uint32_t it;
608 } 662 uint32_t cards;
609 663 uint32_t devices;
610 /* Make sure channel is setup right one last time */ 664 int32_t status;
611 SDL_memset(&csetup, '\0', sizeof(csetup)); 665
612 if (!this->hidden->iscapture) 666 /* Detect amount of available devices */
613 { 667 /* this value can be changed in the runtime */
614 csetup.channel=SND_PCM_CHANNEL_PLAYBACK; 668 cards = snd_cards();
615 } 669
616 else 670 /* If io-audio manager is not running we will get 0 as number */
617 { 671 /* of available audio devices */
618 csetup.channel=SND_PCM_CHANNEL_CAPTURE; 672 if (cards == 0) {
619 } 673 /* We have no any available audio devices */
620 674 return 0;
621 /* Setup an audio channel */ 675 }
622 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) 676
623 { 677 /* Find requested devices by type */
624 QSA_CloseDevice(this); 678 if (!iscapture) {
625 SDL_SetError("QSA: Unable to setup channel\n"); 679 /* Playback devices enumeration requested */
626 return 0; 680 for (it = 0; it < cards; it++) {
627 } 681 devices = 0;
628 682 do {
629 /* Calculate the final parameters for this audio specification */ 683 status =
630 SDL_CalculateAudioSpec(&this->spec); 684 snd_card_get_longname(it,
631 685 qsa_playback_device
632 this->hidden->pcm_len = this->spec.size; 686 [qsa_playback_devices].name,
633 687 QSA_MAX_NAME_LENGTH);
634 if (this->hidden->pcm_len==0) 688 if (status == EOK) {
635 { 689 snd_pcm_t *handle;
636 this->hidden->pcm_len=csetup.buf.block.frag_size * this->spec.channels * 690
637 (snd_pcm_format_width(format) / 8); 691 /* Add device number to device name */
638 } 692 sprintf(qsa_playback_device[qsa_playback_devices].name +
639 693 SDL_strlen(qsa_playback_device
640 /* 694 [qsa_playback_devices].name), " d%d",
641 * Allocate memory to the audio buffer and initialize with silence 695 devices);
642 * (Note that buffer size must be a multiple of fragment size, so find 696
643 * closest multiple) 697 /* Store associated card number id */
644 */ 698 qsa_playback_device[qsa_playback_devices].cardno = it;
645 this->hidden->pcm_buf=(Uint8*)SDL_AllocAudioMem(this->hidden->pcm_len); 699
646 if (this->hidden->pcm_buf==NULL) 700 /* Check if this device id could play anything */
647 { 701 status =
648 QSA_CloseDevice(this); 702 snd_pcm_open(&handle, it, devices,
649 SDL_OutOfMemory(); 703 SND_PCM_OPEN_PLAYBACK);
650 return 0; 704 if (status == EOK) {
651 } 705 qsa_playback_device[qsa_playback_devices].deviceno =
652 SDL_memset(this->hidden->pcm_buf, this->spec.silence, this->hidden->pcm_len); 706 devices;
653 707 status = snd_pcm_close(handle);
654 /* get the file descriptor */ 708 if (status == EOK) {
655 if (!this->hidden->iscapture) 709 qsa_playback_devices++;
656 { 710 }
657 this->hidden->audio_fd=snd_pcm_file_descriptor(this->hidden->audio_handle, 711 } else {
658 SND_PCM_CHANNEL_PLAYBACK); 712 /* Check if we got end of devices list */
659 } 713 if (status == -ENOENT) {
660 else 714 break;
661 { 715 }
662 this->hidden->audio_fd=snd_pcm_file_descriptor(this->hidden->audio_handle, 716 }
663 SND_PCM_CHANNEL_CAPTURE); 717 } else {
664 } 718 break;
665 719 }
666 if (this->hidden->audio_fd<0) 720
667 { 721 /* Check if we reached maximum devices count */
668 QSA_CloseDevice(this); 722 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
669 QSA_SetError("snd_pcm_file_descriptor", status); 723 break;
670 return 0; 724 }
671 } 725 devices++;
672 726 } while (1);
673 /* Prepare an audio channel */
674 if (!this->hidden->iscapture)
675 {
676 /* Prepare audio playback */
677 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK);
678 }
679 else
680 {
681 /* Prepare audio capture */
682 status=snd_pcm_plugin_prepare(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE);
683 }
684
685 if (status<0)
686 {
687 QSA_CloseDevice(this);
688 QSA_SetError("snd_pcm_plugin_prepare", status);
689 return 0;
690 }
691
692 /* We're really ready to rock and roll. :-) */
693 return 1;
694 }
695
696 int QSA_DetectDevices(int iscapture)
697 {
698 uint32_t it;
699 uint32_t cards;
700 uint32_t devices;
701 int32_t status;
702
703 /* Detect amount of available devices */
704 /* this value can be changed in the runtime */
705 cards=snd_cards();
706
707 /* If io-audio manager is not running we will get 0 as number */
708 /* of available audio devices */
709 if (cards==0)
710 {
711 /* We have no any available audio devices */
712 return 0;
713 }
714
715 /* Find requested devices by type */
716 if (!iscapture)
717 {
718 /* Playback devices enumeration requested */
719 for(it=0; it<cards; it++)
720 {
721 devices=0;
722 do {
723 status=snd_card_get_longname(it, qsa_playback_device[qsa_playback_devices].name, QSA_MAX_NAME_LENGTH);
724 if (status==EOK)
725 {
726 snd_pcm_t* handle;
727
728 /* Add device number to device name */
729 sprintf(qsa_playback_device[qsa_playback_devices].name + SDL_strlen(qsa_playback_device[qsa_playback_devices].name), " d%d", devices);
730
731 /* Store associated card number id */
732 qsa_playback_device[qsa_playback_devices].cardno=it;
733
734 /* Check if this device id could play anything */
735 status=snd_pcm_open(&handle, it, devices, SND_PCM_OPEN_PLAYBACK);
736 if (status==EOK)
737 {
738 qsa_playback_device[qsa_playback_devices].deviceno=devices;
739 status=snd_pcm_close(handle);
740 if (status==EOK)
741 {
742 qsa_playback_devices++;
743 }
744 }
745 else
746 {
747 /* Check if we got end of devices list */
748 if (status==-ENOENT)
749 {
750 break;
751 }
752 }
753 }
754 else
755 {
756 break;
757 }
758 727
759 /* Check if we reached maximum devices count */ 728 /* Check if we reached maximum devices count */
760 if (qsa_playback_devices>=QSA_MAX_DEVICES) 729 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
761 { 730 break;
762 break; 731 }
763 } 732 }
764 devices++; 733 } else {
765 } while(1); 734 /* Capture devices enumeration requested */
766 735 for (it = 0; it < cards; it++) {
767 /* Check if we reached maximum devices count */ 736 devices = 0;
768 if (qsa_playback_devices>=QSA_MAX_DEVICES) 737 do {
769 { 738 status =
770 break; 739 snd_card_get_longname(it,
771 } 740 qsa_capture_device
772 } 741 [qsa_capture_devices].name,
773 } 742 QSA_MAX_NAME_LENGTH);
774 else 743 if (status == EOK) {
775 { 744 snd_pcm_t *handle;
776 /* Capture devices enumeration requested */ 745
777 for(it=0; it<cards; it++) 746 /* Add device number to device name */
778 { 747 sprintf(qsa_capture_device[qsa_capture_devices].name +
779 devices=0; 748 SDL_strlen(qsa_capture_device
780 do { 749 [qsa_capture_devices].name), " d%d",
781 status=snd_card_get_longname(it, qsa_capture_device[qsa_capture_devices].name, QSA_MAX_NAME_LENGTH); 750 devices);
782 if (status==EOK) 751
783 { 752 /* Store associated card number id */
784 snd_pcm_t* handle; 753 qsa_capture_device[qsa_capture_devices].cardno = it;
785 754
786 /* Add device number to device name */ 755 /* Check if this device id could play anything */
787 sprintf(qsa_capture_device[qsa_capture_devices].name + SDL_strlen(qsa_capture_device[qsa_capture_devices].name), " d%d", devices); 756 status =
788 757 snd_pcm_open(&handle, it, devices,
789 /* Store associated card number id */ 758 SND_PCM_OPEN_CAPTURE);
790 qsa_capture_device[qsa_capture_devices].cardno=it; 759 if (status == EOK) {
791 760 qsa_capture_device[qsa_capture_devices].deviceno =
792 /* Check if this device id could play anything */ 761 devices;
793 status=snd_pcm_open(&handle, it, devices, SND_PCM_OPEN_CAPTURE); 762 status = snd_pcm_close(handle);
794 if (status==EOK) 763 if (status == EOK) {
795 { 764 qsa_capture_devices++;
796 qsa_capture_device[qsa_capture_devices].deviceno=devices; 765 }
797 status=snd_pcm_close(handle); 766 } else {
798 if (status==EOK) 767 /* Check if we got end of devices list */
799 { 768 if (status == -ENOENT) {
800 qsa_capture_devices++; 769 break;
801 } 770 }
802 } 771 }
803 else 772
804 { 773 /* Check if we reached maximum devices count */
805 /* Check if we got end of devices list */ 774 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
806 if (status==-ENOENT) 775 break;
807 { 776 }
808 break; 777 } else {
809 } 778 break;
810 } 779 }
811 780 devices++;
812 /* Check if we reached maximum devices count */ 781 } while (1);
813 if (qsa_capture_devices>=QSA_MAX_DEVICES) 782
814 { 783 /* Check if we reached maximum devices count */
815 break; 784 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
816 } 785 break;
817 } 786 }
818 else 787 }
819 { 788 }
820 break; 789
821 } 790 /* Return amount of available playback or capture devices */
822 devices++; 791 if (!iscapture) {
823 } while(1); 792 return qsa_playback_devices;
824 793 } else {
825 /* Check if we reached maximum devices count */ 794 return qsa_capture_devices;
826 if (qsa_capture_devices>=QSA_MAX_DEVICES) 795 }
827 { 796 }
828 break; 797
829 } 798 const char *
830 } 799 QSA_GetDeviceName(int index, int iscapture)
831 } 800 {
832 801 if (!iscapture) {
833 /* Return amount of available playback or capture devices */ 802 if (index >= qsa_playback_devices) {
834 if (!iscapture) 803 return "No such playback device";
835 { 804 }
836 return qsa_playback_devices; 805
837 } 806 return qsa_playback_device[index].name;
838 else 807 } else {
839 { 808 if (index >= qsa_capture_devices) {
840 return qsa_capture_devices; 809 return "No such capture device";
841 } 810 }
842 } 811
843 812 return qsa_capture_device[index].name;
844 const char* QSA_GetDeviceName(int index, int iscapture) 813 }
845 { 814 }
846 if (!iscapture) 815
847 { 816 void
848 if (index>=qsa_playback_devices) 817 QSA_WaitDone(_THIS)
849 { 818 {
850 return "No such playback device"; 819 if (!this->hidden->iscapture) {
851 } 820 if (this->hidden->audio_handle != NULL) {
852 821 /* Wait till last fragment is played and stop channel */
853 return qsa_playback_device[index].name; 822 snd_pcm_plugin_flush(this->hidden->audio_handle,
854 } 823 SND_PCM_CHANNEL_PLAYBACK);
855 else 824 }
856 { 825 } else {
857 if (index>=qsa_capture_devices) 826 if (this->hidden->audio_handle != NULL) {
858 { 827 /* Discard all unread data and stop channel */
859 return "No such capture device"; 828 snd_pcm_plugin_flush(this->hidden->audio_handle,
860 } 829 SND_PCM_CHANNEL_CAPTURE);
861 830 }
862 return qsa_capture_device[index].name; 831 }
863 } 832 }
864 } 833
865 834 void
866 void QSA_WaitDone(_THIS) 835 QSA_Deinitialize(void)
867 { 836 {
868 if (!this->hidden->iscapture) 837 /* Clear devices array on shutdown */
869 { 838 SDL_memset(qsa_playback_device, 0x00,
870 if (this->hidden->audio_handle!=NULL) 839 sizeof(QSA_Device) * QSA_MAX_DEVICES);
871 { 840 SDL_memset(qsa_capture_device, 0x00,
872 /* Wait till last fragment is played and stop channel */ 841 sizeof(QSA_Device) * QSA_MAX_DEVICES);
873 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); 842 qsa_playback_devices = 0;
874 } 843 qsa_capture_devices = 0;
875 } 844 }
876 else 845
877 { 846 static int
878 if (this->hidden->audio_handle!=NULL) 847 QSA_Init(SDL_AudioDriverImpl * impl)
879 { 848 {
880 /* Discard all unread data and stop channel */ 849 snd_pcm_t *handle = NULL;
881 snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_CAPTURE); 850 int32_t status = 0;
882 } 851
883 } 852 /* Clear devices array */
884 } 853 SDL_memset(qsa_playback_device, 0x00,
885 854 sizeof(QSA_Device) * QSA_MAX_DEVICES);
886 void QSA_Deinitialize(void) 855 SDL_memset(qsa_capture_device, 0x00,
887 { 856 sizeof(QSA_Device) * QSA_MAX_DEVICES);
888 /* Clear devices array on shutdown */ 857 qsa_playback_devices = 0;
889 SDL_memset(qsa_playback_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); 858 qsa_capture_devices = 0;
890 SDL_memset(qsa_capture_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); 859
891 qsa_playback_devices=0; 860 /* Set function pointers */
892 qsa_capture_devices=0; 861 /* DeviceLock and DeviceUnlock functions are used default, */
893 } 862 /* provided by SDL, which uses pthread_mutex for lock/unlock */
894 863 impl->DetectDevices = QSA_DetectDevices;
895 static int QSA_Init(SDL_AudioDriverImpl* impl) 864 impl->GetDeviceName = QSA_GetDeviceName;
896 { 865 impl->OpenDevice = QSA_OpenDevice;
897 snd_pcm_t* handle=NULL; 866 impl->ThreadInit = QSA_ThreadInit;
898 int32_t status=0; 867 impl->WaitDevice = QSA_WaitDevice;
899 868 impl->PlayDevice = QSA_PlayDevice;
900 /* Clear devices array */ 869 impl->GetDeviceBuf = QSA_GetDeviceBuf;
901 SDL_memset(qsa_playback_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); 870 impl->CloseDevice = QSA_CloseDevice;
902 SDL_memset(qsa_capture_device, 0x00, sizeof(QSA_Device)*QSA_MAX_DEVICES); 871 impl->WaitDone = QSA_WaitDone;
903 qsa_playback_devices=0; 872 impl->Deinitialize = QSA_Deinitialize;
904 qsa_capture_devices=0; 873 impl->LockDevice = NULL;
905 874 impl->UnlockDevice = NULL;
906 /* Set function pointers */ 875
907 /* DeviceLock and DeviceUnlock functions are used default, */ 876 impl->OnlyHasDefaultOutputDevice = 0;
908 /* provided by SDL, which uses pthread_mutex for lock/unlock */ 877 impl->ProvidesOwnCallbackThread = 0;
909 impl->DetectDevices=QSA_DetectDevices; 878 impl->SkipMixerLock = 0;
910 impl->GetDeviceName=QSA_GetDeviceName; 879 impl->HasCaptureSupport = 1;
911 impl->OpenDevice=QSA_OpenDevice; 880 impl->OnlyHasDefaultOutputDevice = 0;
912 impl->ThreadInit=QSA_ThreadInit; 881 impl->OnlyHasDefaultInputDevice = 0;
913 impl->WaitDevice=QSA_WaitDevice; 882
914 impl->PlayDevice=QSA_PlayDevice; 883 /* Check if io-audio manager is running or not */
915 impl->GetDeviceBuf=QSA_GetDeviceBuf; 884 status = snd_cards();
916 impl->CloseDevice=QSA_CloseDevice; 885 if (status == 0) {
917 impl->WaitDone=QSA_WaitDone; 886 /* if no, return immediately */
918 impl->Deinitialize=QSA_Deinitialize; 887 return 1;
919 impl->LockDevice=NULL; 888 }
920 impl->UnlockDevice=NULL; 889
921 890 /* At this point we are definitely has an audio device */
922 impl->OnlyHasDefaultOutputDevice=0; 891 return 2;
923 impl->ProvidesOwnCallbackThread=0; 892 }
924 impl->SkipMixerLock=0; 893
925 impl->HasCaptureSupport=1; 894 AudioBootStrap QSAAUDIO_bootstrap = {
926 impl->OnlyHasDefaultOutputDevice=0; 895 DRIVER_NAME, "QNX QSA Audio", QSA_Init, 0
927 impl->OnlyHasDefaultInputDevice=0;
928
929 /* Check if io-audio manager is running or not */
930 status=snd_cards();
931 if (status==0)
932 {
933 /* if no, return immediately */
934 return 1;
935 }
936
937 /* At this point we are definitely has an audio device */
938 return 2;
939 }
940
941 AudioBootStrap QSAAUDIO_bootstrap=
942 {
943 DRIVER_NAME, "QNX QSA Audio", QSA_Init, 0
944 }; 896 };
945 897
946 /* vi: set ts=4 sw=4 expandtab: */ 898 /* vi: set ts=4 sw=4 expandtab: */