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_audio_c.h" 52 #define DEFAULT_CPARAMS_RATE 44100 53 #define DEFAULT_CPARAMS_VOICES 1 55 #define DEFAULT_CPARAMS_FRAG_SIZE 4096 56 #define DEFAULT_CPARAMS_FRAGS_MIN 1 57 #define DEFAULT_CPARAMS_FRAGS_MAX 1 59 #define QSA_NO_WORKAROUNDS 0x00000000 60 #define QSA_MMAP_WORKAROUND 0x00000001 65 unsigned long bugtype;
68 #define QSA_WA_CARDS 3 69 #define QSA_MAX_CARD_NAME_LENGTH 33 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},
78 #define QSA_MAX_DEVICES 32 79 #define QSA_MAX_NAME_LENGTH 81+16 81 typedef struct _QSA_Device
83 char name[QSA_MAX_NAME_LENGTH];
88 QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
91 QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
95 QSA_SetError(
const char *fn,
int status)
97 return SDL_SetError(
"QSA: %s() failed: %s", fn, snd_strerror(status));
102 QSA_CheckBuggyCards(
_THIS,
unsigned long checkfor)
104 char scardname[QSA_MAX_CARD_NAME_LENGTH];
107 if (snd_card_get_name
108 (this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) {
112 for (it = 0; it < QSA_WA_CARDS; it++) {
113 if (
SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
114 if (buggycards[it].bugtype == checkfor) {
125 QSA_ThreadInit(
_THIS)
127 struct sched_param
param;
131 status = SchedGet(0, 0, &
param);
132 param.sched_priority =
param.sched_curpriority + 15;
133 status = SchedSet(0, 0, SCHED_NOCHANGE, &
param);
138 QSA_InitAudioParams(snd_pcm_channel_params_t * 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;
156 QSA_WaitDevice(
_THIS)
163 if (!this->hidden->iscapture) {
165 FD_SET(this->hidden->audio_fd, &wfds);
168 FD_SET(this->hidden->audio_fd, &rfds);
178 this->hidden->timeout_on_wait = 0;
180 if (!this->hidden->iscapture) {
182 select(this->hidden->audio_fd + 1,
NULL, &wfds,
NULL,
186 select(this->hidden->audio_fd + 1, &rfds,
NULL,
NULL,
193 SDL_SetError(
"QSA: select() failed: %s", strerror(errno));
200 this->hidden->timeout_on_wait = 1;
206 if (!this->hidden->iscapture) {
207 if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
211 if (FD_ISSET(this->hidden->audio_fd, &rfds)) {
222 QSA_PlayDevice(
_THIS)
224 snd_pcm_channel_status_t cstatus;
235 pcmbuffer = this->hidden->pcm_buf;
240 snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
242 if (written != towrite) {
245 if ((errno == EAGAIN) && (written == 0)) {
246 if (this->hidden->timeout_on_wait != 0) {
253 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
262 if ((errno == EINVAL) || (errno == EIO)) {
264 if (!this->hidden->iscapture) {
265 cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
267 cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
271 snd_pcm_plugin_status(this->hidden->audio_handle,
274 QSA_SetError(
"snd_pcm_plugin_status", status);
278 if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
279 (cstatus.status == SND_PCM_STATUS_READY)) {
280 if (!this->hidden->iscapture) {
282 snd_pcm_plugin_prepare(this->hidden->
284 SND_PCM_CHANNEL_PLAYBACK);
287 snd_pcm_plugin_prepare(this->hidden->
289 SND_PCM_CHANNEL_CAPTURE);
292 QSA_SetError(
"snd_pcm_plugin_prepare", status);
315 QSA_GetDeviceBuf(
_THIS)
317 return this->hidden->pcm_buf;
321 QSA_CloseDevice(
_THIS)
323 if (this->hidden->audio_handle !=
NULL) {
324 if (!this->hidden->iscapture) {
326 snd_pcm_plugin_flush(this->hidden->audio_handle,
327 SND_PCM_CHANNEL_PLAYBACK);
330 snd_pcm_plugin_flush(this->hidden->audio_handle,
331 SND_PCM_CHANNEL_CAPTURE);
333 snd_pcm_close(this->hidden->audio_handle);
341 QSA_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
343 const QSA_Device *device = (
const QSA_Device *) handle;
348 snd_pcm_channel_setup_t csetup;
349 snd_pcm_channel_params_t cparams;
357 if (this->hidden ==
NULL) {
363 QSA_InitAudioParams(&cparams);
368 if (device !=
NULL) {
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);
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);
385 this->hidden->audio_handle =
NULL;
386 return QSA_SetError(
"snd_pcm_open", status);
389 if (!QSA_CheckBuggyCards(
this, QSA_MMAP_WORKAROUND)) {
392 snd_pcm_plugin_set_disable(this->hidden->audio_handle,
393 PLUGIN_DISABLE_MMAP);
395 return QSA_SetError(
"snd_pcm_plugin_set_disable", status);
406 switch (test_format) {
409 format = SND_PCM_SFMT_U8;
415 format = SND_PCM_SFMT_S8;
421 format = SND_PCM_SFMT_S16_LE;
427 format = SND_PCM_SFMT_S16_BE;
433 format = SND_PCM_SFMT_U16_LE;
439 format = SND_PCM_SFMT_U16_BE;
445 format = SND_PCM_SFMT_S32_LE;
451 format = SND_PCM_SFMT_S32_BE;
457 format = SND_PCM_SFMT_FLOAT_LE;
463 format = SND_PCM_SFMT_FLOAT_BE;
479 if (test_format == 0) {
480 return SDL_SetError(
"QSA: Couldn't find any hardware audio formats");
486 cparams.format.format =
format;
492 cparams.format.rate = this->
spec.
freq;
495 status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
497 return QSA_SetError(
"snd_pcm_channel_params", status);
502 if (!this->hidden->iscapture) {
503 csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
505 csetup.channel = SND_PCM_CHANNEL_CAPTURE;
509 if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
516 this->hidden->pcm_len = this->
spec.
size;
518 if (this->hidden->pcm_len == 0) {
519 this->hidden->pcm_len =
521 (snd_pcm_format_width(format) / 8);
529 this->hidden->pcm_buf =
531 if (this->hidden->pcm_buf ==
NULL) {
534 SDL_memset(this->hidden->pcm_buf, this->spec.silence,
535 this->hidden->pcm_len);
538 if (!this->hidden->iscapture) {
539 this->hidden->audio_fd =
540 snd_pcm_file_descriptor(this->hidden->audio_handle,
541 SND_PCM_CHANNEL_PLAYBACK);
543 this->hidden->audio_fd =
544 snd_pcm_file_descriptor(this->hidden->audio_handle,
545 SND_PCM_CHANNEL_CAPTURE);
548 if (this->hidden->audio_fd < 0) {
549 return QSA_SetError(
"snd_pcm_file_descriptor", status);
553 if (!this->hidden->iscapture) {
556 snd_pcm_plugin_prepare(this->hidden->audio_handle,
557 SND_PCM_CHANNEL_PLAYBACK);
561 snd_pcm_plugin_prepare(this->hidden->audio_handle,
562 SND_PCM_CHANNEL_CAPTURE);
566 return QSA_SetError(
"snd_pcm_plugin_prepare", status);
574 QSA_DetectDevices(
void)
596 for (it = 0; it < cards; it++) {
600 snd_card_get_longname(it,
602 [qsa_playback_devices].
name,
603 QSA_MAX_NAME_LENGTH);
608 sprintf(qsa_playback_device[qsa_playback_devices].
name +
610 [qsa_playback_devices].
name),
" d%d",
614 qsa_playback_device[qsa_playback_devices].cardno = it;
618 snd_pcm_open(&handle, it, devices,
619 SND_PCM_OPEN_PLAYBACK);
621 qsa_playback_device[qsa_playback_devices].deviceno =
623 status = snd_pcm_close(handle);
626 qsa_playback_devices++;
630 if (status == -ENOENT) {
639 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
646 if (qsa_playback_devices >= QSA_MAX_DEVICES) {
654 for (it = 0; it < cards; it++) {
658 snd_card_get_longname(it,
660 [qsa_capture_devices].
name,
661 QSA_MAX_NAME_LENGTH);
666 sprintf(qsa_capture_device[qsa_capture_devices].
name +
668 [qsa_capture_devices].
name),
" d%d",
672 qsa_capture_device[qsa_capture_devices].cardno = it;
676 snd_pcm_open(&handle, it, devices,
677 SND_PCM_OPEN_CAPTURE);
679 qsa_capture_device[qsa_capture_devices].deviceno =
681 status = snd_pcm_close(handle);
684 qsa_capture_devices++;
688 if (status == -ENOENT) {
694 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
704 if (qsa_capture_devices >= QSA_MAX_DEVICES) {
712 QSA_Deinitialize(
void)
718 qsa_playback_devices = 0;
719 qsa_capture_devices = 0;
725 snd_pcm_t *handle =
NULL;
731 qsa_playback_devices = 0;
732 qsa_capture_devices = 0;
756 status = snd_cards();
766 "qsa",
"QNX QSA Audio", QSA_Init, 0
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
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)
int OnlyHasDefaultCaptureDevice
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)
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)
GLbitfield GLuint64 timeout
Uint8 *(* GetDeviceBuf)(_THIS)
void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)