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