31 #include "../../SDL_internal.h" 33 #if SDL_AUDIO_DRIVER_QSA 39 #include <sys/types.h> 42 #include <sys/select.h> 43 #include <sys/neutrino.h> 44 #include <sys/asoundlib.h> 48 #include "../SDL_audiomem.h" 49 #include "../SDL_audio_c.h" 53 #define DEFAULT_CPARAMS_RATE 44100 54 #define DEFAULT_CPARAMS_VOICES 1 56 #define DEFAULT_CPARAMS_FRAG_SIZE 4096 57 #define DEFAULT_CPARAMS_FRAGS_MIN 1 58 #define DEFAULT_CPARAMS_FRAGS_MAX 1 60 #define QSA_NO_WORKAROUNDS 0x00000000 61 #define QSA_MMAP_WORKAROUND 0x00000001 66 unsigned long bugtype;
69 #define QSA_WA_CARDS 3 70 #define QSA_MAX_CARD_NAME_LENGTH 33 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},
79 #define QSA_MAX_DEVICES 32 80 #define QSA_MAX_NAME_LENGTH 81+16 82 typedef struct _QSA_Device
84 char name[QSA_MAX_NAME_LENGTH];
89 QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
92 QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
96 QSA_SetError(
const char *fn,
int status)
98 return SDL_SetError(
"QSA: %s() failed: %s", fn, snd_strerror(status));
103 QSA_CheckBuggyCards(
_THIS,
unsigned long checkfor)
105 char scardname[QSA_MAX_CARD_NAME_LENGTH];
108 if (snd_card_get_name
109 (this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) {
113 for (it = 0; it < QSA_WA_CARDS; it++) {
114 if (
SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
115 if (buggycards[it].bugtype == checkfor) {
126 QSA_ThreadInit(
_THIS)
128 struct sched_param
param;
132 status = SchedGet(0, 0, &
param);
133 param.sched_priority =
param.sched_curpriority + 15;
134 status = SchedSet(0, 0, SCHED_NOCHANGE, &
param);
139 QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
141 SDL_memset(cpars, 0,
sizeof(snd_pcm_channel_params_t));
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;
158 QSA_WaitDevice(
_THIS)
165 if (!this->hidden->iscapture) {
167 FD_SET(this->hidden->audio_fd, &wfds);
170 FD_SET(this->hidden->audio_fd, &rfds);
180 this->hidden->timeout_on_wait = 0;
182 if (!this->hidden->iscapture) {
184 select(this->hidden->audio_fd + 1,
NULL, &wfds,
NULL,
188 select(this->hidden->audio_fd + 1, &rfds,
NULL,
NULL,
195 SDL_SetError(
"QSA: select() failed: %s", strerror(errno));
202 this->hidden->timeout_on_wait = 1;
208 if (!this->hidden->iscapture) {
209 if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
213 if (FD_ISSET(this->hidden->audio_fd, &rfds)) {
224 QSA_PlayDevice(
_THIS)
226 snd_pcm_channel_status_t cstatus;
232 if ((!this->
enabled) || (!this->hidden)) {
237 pcmbuffer = this->hidden->pcm_buf;
242 snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
244 if (written != towrite) {
247 if ((errno == EAGAIN) && (written == 0)) {
248 if (this->hidden->timeout_on_wait != 0) {
255 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
264 if ((errno == EINVAL) || (errno == EIO)) {
266 if (!this->hidden->iscapture) {
267 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
269 cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
273 snd_pcm_plugin_status(this->hidden->audio_handle,
276 QSA_SetError(
"snd_pcm_plugin_status", status);
280 if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
281 (cstatus.status == SND_PCM_STATUS_READY)) {
282 if (!this->hidden->iscapture) {
284 snd_pcm_plugin_prepare(this->hidden->
286 SND_PCM_CHANNEL_PLAYBACK);
289 snd_pcm_plugin_prepare(this->hidden->
291 SND_PCM_CHANNEL_CAPTURE);
294 QSA_SetError(
"snd_pcm_plugin_prepare", status);
308 }
while ((towrite > 0) && (this->
enabled));
317 QSA_GetDeviceBuf(
_THIS)
319 return this->hidden->pcm_buf;
323 QSA_CloseDevice(
_THIS)
325 if (this->hidden !=
NULL) {
326 if (this->hidden->audio_handle !=
NULL) {
327 if (!this->hidden->iscapture) {
329 snd_pcm_plugin_flush(this->hidden->audio_handle,
330 SND_PCM_CHANNEL_PLAYBACK);
333 snd_pcm_plugin_flush(this->hidden->audio_handle,
334 SND_PCM_CHANNEL_CAPTURE);
336 snd_pcm_close(this->hidden->audio_handle);
337 this->hidden->audio_handle =
NULL;
341 this->hidden->pcm_buf =
NULL;
349 QSA_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
351 const QSA_Device *device = (
const QSA_Device *) handle;
356 snd_pcm_channel_setup_t csetup;
357 snd_pcm_channel_params_t cparams;
365 if (this->hidden ==
NULL) {
371 QSA_InitAudioParams(&cparams);
376 if (device !=
NULL) {
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);
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);
393 this->hidden->audio_handle =
NULL;
394 QSA_CloseDevice(
this);
395 return QSA_SetError(
"snd_pcm_open", status);
398 if (!QSA_CheckBuggyCards(
this, QSA_MMAP_WORKAROUND)) {
401 snd_pcm_plugin_set_disable(this->hidden->audio_handle,
402 PLUGIN_DISABLE_MMAP);
404 QSA_CloseDevice(
this);
405 return QSA_SetError(
"snd_pcm_plugin_set_disable", status);
416 switch (test_format) {
419 format = SND_PCM_SFMT_U8;
425 format = SND_PCM_SFMT_S8;
431 format = SND_PCM_SFMT_S16_LE;
437 format = SND_PCM_SFMT_S16_BE;
443 format = SND_PCM_SFMT_U16_LE;
449 format = SND_PCM_SFMT_U16_BE;
455 format = SND_PCM_SFMT_S32_LE;
461 format = SND_PCM_SFMT_S32_BE;
467 format = SND_PCM_SFMT_FLOAT_LE;
473 format = SND_PCM_SFMT_FLOAT_BE;
489 if (test_format == 0) {
490 QSA_CloseDevice(
this);
491 return SDL_SetError(
"QSA: Couldn't find any hardware audio formats");
497 cparams.format.format =
format;
503 cparams.format.rate = this->
spec.
freq;
506 status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
508 QSA_CloseDevice(
this);
509 return QSA_SetError(
"snd_pcm_channel_params", status);
514 if (!this->hidden->iscapture) {
515 csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
517 csetup.channel = SND_PCM_CHANNEL_CAPTURE;
521 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
522 QSA_CloseDevice(
this);
529 this->hidden->pcm_len = this->
spec.
size;
531 if (this->hidden->pcm_len == 0) {
532 this->hidden->pcm_len =
534 (snd_pcm_format_width(format) / 8);
542 this->hidden->pcm_buf =
544 if (this->hidden->pcm_buf ==
NULL) {
545 QSA_CloseDevice(
this);
548 SDL_memset(this->hidden->pcm_buf, this->spec.silence,
549 this->hidden->pcm_len);
552 if (!this->hidden->iscapture) {
553 this->hidden->audio_fd =
554 snd_pcm_file_descriptor(this->hidden->audio_handle,
555 SND_PCM_CHANNEL_PLAYBACK);
557 this->hidden->audio_fd =
558 snd_pcm_file_descriptor(this->hidden->audio_handle,
559 SND_PCM_CHANNEL_CAPTURE);
562 if (this->hidden->audio_fd < 0) {
563 QSA_CloseDevice(
this);
564 return QSA_SetError(
"snd_pcm_file_descriptor", status);
568 if (!this->hidden->iscapture) {
571 snd_pcm_plugin_prepare(this->hidden->audio_handle,
572 SND_PCM_CHANNEL_PLAYBACK);
576 snd_pcm_plugin_prepare(this->hidden->audio_handle,
577 SND_PCM_CHANNEL_CAPTURE);
581 QSA_CloseDevice(
this);
582 return QSA_SetError(
"snd_pcm_plugin_prepare", status);
590 QSA_DetectDevices(
void)
612 for (it = 0; it < cards; it++) {
616 snd_card_get_longname(it,
618 [qsa_playback_devices].
name,
619 QSA_MAX_NAME_LENGTH);
624 sprintf(qsa_playback_device[qsa_playback_devices].
name +
626 [qsa_playback_devices].
name),
" d%d",
630 qsa_playback_device[qsa_playback_devices].cardno = it;
634 snd_pcm_open(&handle, it, devices,
635 SND_PCM_OPEN_PLAYBACK);
637 qsa_playback_device[qsa_playback_devices].deviceno =
639 status = snd_pcm_close(handle);
642 qsa_playback_devices++;
646 if (status == -ENOENT) {
655 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
662 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
670 for (it = 0; it < cards; it++) {
674 snd_card_get_longname(it,
676 [qsa_capture_devices].
name,
677 QSA_MAX_NAME_LENGTH);
682 sprintf(qsa_capture_device[qsa_capture_devices].
name +
684 [qsa_capture_devices].
name),
" d%d",
688 qsa_capture_device[qsa_capture_devices].cardno = it;
692 snd_pcm_open(&handle, it, devices,
693 SND_PCM_OPEN_CAPTURE);
695 qsa_capture_device[qsa_capture_devices].deviceno =
697 status = snd_pcm_close(handle);
700 qsa_capture_devices++;
704 if (status == -ENOENT) {
710 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
720 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
730 if (!this->hidden->iscapture) {
731 if (this->hidden->audio_handle !=
NULL) {
733 snd_pcm_plugin_flush(this->hidden->audio_handle,
734 SND_PCM_CHANNEL_PLAYBACK);
737 if (this->hidden->audio_handle !=
NULL) {
739 snd_pcm_plugin_flush(this->hidden->audio_handle,
740 SND_PCM_CHANNEL_CAPTURE);
746 QSA_Deinitialize(
void)
750 sizeof(QSA_Device) * QSA_MAX_DEVICES);
752 sizeof(QSA_Device) * QSA_MAX_DEVICES);
753 qsa_playback_devices = 0;
754 qsa_capture_devices = 0;
760 snd_pcm_t *handle =
NULL;
765 sizeof(QSA_Device) * QSA_MAX_DEVICES);
767 sizeof(QSA_Device) * QSA_MAX_DEVICES);
768 qsa_playback_devices = 0;
769 qsa_capture_devices = 0;
794 status = snd_cards();
804 "qsa",
"QNX QSA Audio", QSA_Init, 0
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
void(* DetectDevices)(void)
AudioBootStrap QSAAUDIO_bootstrap
int ProvidesOwnCallbackThread
void(* PlayDevice)(_THIS)
void(* WaitDevice)(_THIS)
void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
Uint16 SDL_AudioFormat
Audio format flags.
GLuint const GLchar * name
void(* UnlockDevice)(_THIS)
SDL_AudioFormat SDL_NextAudioFormat(void)
void * SDL_calloc(size_t nmemb, size_t size)
void(* ThreadInit)(_THIS)
int OnlyHasDefaultOutputDevice
uint8_t Uint8
An unsigned 8-bit integer type.
void(* Deinitialize)(void)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
#define SDL_AllocAudioMem
void(* LockDevice)(_THIS)
GLenum GLenum GLsizei const GLuint GLboolean enabled
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
#define SDL_OutOfMemory()
void(* CloseDevice)(_THIS)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
GLbitfield GLuint64 timeout
Uint8 *(* GetDeviceBuf)(_THIS)
int OnlyHasDefaultInputDevice
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)