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