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