Mercurial > sdl-ios-xcode
diff src/audio/nto/SDL_nto_audio.c @ 2049:5f6550e5184f
Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Tue, 17 Oct 2006 09:15:21 +0000 |
parents | cff63f857ff3 |
children | 866052b01ee5 |
line wrap: on
line diff
--- a/src/audio/nto/SDL_nto_audio.c Sun Oct 01 16:10:41 2006 +0000 +++ b/src/audio/nto/SDL_nto_audio.c Tue Oct 17 09:15:21 2006 +0000 @@ -69,13 +69,13 @@ {"Vortex 8830", QSA_MMAP_WORKAROUND}, }; -/* Audio driver functions */ -static void NTO_ThreadInit(_THIS); -static int NTO_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void NTO_WaitAudio(_THIS); -static void NTO_PlayAudio(_THIS); -static Uint8 *NTO_GetAudioBuf(_THIS); -static void NTO_CloseAudio(_THIS); + +static inline void +NTO_SetError(const char *fn, int rval) +{ + SDL_SetError("NTO: %s failed: %s", fn, snd_strerror(rval)); +} + /* card names check to apply the workarounds */ static int @@ -84,7 +84,7 @@ char scardname[33]; int it; - if (snd_card_get_name(cardno, scardname, 32) < 0) { + if (snd_card_get_name(this->hidden->cardno, scardname, 32) < 0) { return 0; } @@ -102,11 +102,10 @@ static void NTO_ThreadInit(_THIS) { - int status; struct sched_param param; + int status = SchedGet(0, 0, ¶m); /* increasing default 10 priority to 25 to avoid jerky sound */ - status = SchedGet(0, 0, ¶m); param.sched_priority = param.sched_curpriority + 15; status = SchedSet(0, 0, SCHED_NOCHANGE, ¶m); } @@ -130,111 +129,26 @@ cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; } -static int -NTO_AudioAvailable(void) -{ - /* See if we can open a nonblocking channel. - Return value '1' means we can. - Return value '0' means we cannot. */ - - int available; - int rval; - snd_pcm_t *handle; - - available = 0; - handle = NULL; - - rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS); - - if (rval >= 0) { - available = 1; - - if ((rval = snd_pcm_close(handle)) < 0) { - SDL_SetError - ("NTO_AudioAvailable(): snd_pcm_close failed: %s\n", - snd_strerror(rval)); - available = 0; - } - } else { - SDL_SetError - ("NTO_AudioAvailable(): there are no available audio devices.\n"); - } - - return (available); -} - -static void -NTO_DeleteAudioDevice(SDL_AudioDevice * device) -{ - if ((device) && (device->hidden)) { - SDL_free(device->hidden); - } - if (device) { - SDL_free(device); - } -} - -static SDL_AudioDevice * -NTO_CreateAudioDevice(int devindex) -{ - SDL_AudioDevice *this; - - /* Initialize all variables that we clean on shutdown */ - this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); - if (this) { - SDL_memset(this, 0, sizeof(SDL_AudioDevice)); - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc(sizeof(struct SDL_PrivateAudioData)); - } - if ((this == NULL) || (this->hidden == NULL)) { - SDL_OutOfMemory(); - if (this) { - SDL_free(this); - } - return (0); - } - SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); - audio_handle = NULL; - - /* Set the function pointers */ - this->ThreadInit = NTO_ThreadInit; - this->OpenAudio = NTO_OpenAudio; - this->WaitAudio = NTO_WaitAudio; - this->PlayAudio = NTO_PlayAudio; - this->GetAudioBuf = NTO_GetAudioBuf; - this->CloseAudio = NTO_CloseAudio; - - this->free = NTO_DeleteAudioDevice; - - return this; -} - -AudioBootStrap QNXNTOAUDIO_bootstrap = { - DRIVER_NAME, "QNX6 QSA-NTO Audio", - NTO_AudioAvailable, - NTO_CreateAudioDevice -}; /* This function waits until it is possible to write a full sound buffer */ static void -NTO_WaitAudio(_THIS) +NTO_WaitDevice(_THIS) { fd_set wfds; int selectret; FD_ZERO(&wfds); - FD_SET(audio_fd, &wfds); + FD_SET(this->hidden->audio_fd, &wfds); do { - selectret = select(audio_fd + 1, NULL, &wfds, NULL, NULL); + selectret = select(this->hidden->audio_fd+1, NULL, &wfds, NULL, NULL); switch (selectret) { case -1: case 0: - SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", - strerror(errno)); + SDL_SetError("NTO: select() failed: %s\n", strerror(errno)); return; default: - if (FD_ISSET(audio_fd, &wfds)) { + if (FD_ISSET(this->hidden->audio_fd, &wfds)) { return; } break; @@ -244,22 +158,24 @@ } static void -NTO_PlayAudio(_THIS) +NTO_PlayDevice(_THIS) { + snd_pcm_channel_status_t cstatus; int written, rval; int towrite; void *pcmbuffer; - if (!this->enabled) { + if ((!this->enabled) || (!this->hidden)) { return; } towrite = this->spec.size; - pcmbuffer = pcm_buf; + pcmbuffer = this->hidden->pcm_buf; /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ do { - written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); + written = snd_pcm_plugin_write(this->hidden->audio_handle, + pcmbuffer, towrite); if (written != towrite) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* Let a little CPU time go by and try to write again */ @@ -268,33 +184,28 @@ towrite -= written; pcmbuffer += written * this->spec.channels; continue; - } else { - if ((errno == EINVAL) || (errno == EIO)) { - SDL_memset(&cstatus, 0, sizeof(cstatus)); - cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; - if ((rval = - snd_pcm_plugin_status(audio_handle, &cstatus)) < 0) { - SDL_SetError - ("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", - snd_strerror(rval)); + } else if ((errno == EINVAL) || (errno == EIO)) { + SDL_memset(&cstatus, 0, sizeof (cstatus)); + cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; + rval = snd_pcm_plugin_status(this->hidden->audio_handle, + &cstatus); + if (rval < 0) { + NTO_SetError("snd_pcm_plugin_status", rval); + return; + } + + if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) || + (cstatus.status == SND_PCM_STATUS_READY)) { + rval = snd_pcm_plugin_prepare(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); + if (rval < 0) { + NTO_SetError("snd_pcm_plugin_prepare", rval); return; } - if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) - || (cstatus.status == SND_PCM_STATUS_READY)) { - if ((rval = - snd_pcm_plugin_prepare(audio_handle, - SND_PCM_CHANNEL_PLAYBACK)) - < 0) { - SDL_SetError - ("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n", - snd_strerror(rval)); - return; - } - } - continue; - } else { - return; } + continue; + } else { + return; } } else { /* we wrote all remaining data */ @@ -308,77 +219,74 @@ if (towrite != 0) { this->enabled = 0; } - - return; } static Uint8 * -NTO_GetAudioBuf(_THIS) +NTO_GetDeviceBuf(_THIS) { - return pcm_buf; + return this->hidden->pcm_buf; } static void -NTO_CloseAudio(_THIS) +NTO_CloseDevice(_THIS) { - int rval; - - this->enabled = 0; - - if (audio_handle != NULL) { - if ((rval = - snd_pcm_plugin_flush(audio_handle, - SND_PCM_CHANNEL_PLAYBACK)) < 0) { - SDL_SetError - ("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n", - snd_strerror(rval)); - return; + if (this->hidden != NULL) { + if (this->hidden->audio_handle != NULL) { + snd_pcm_plugin_flush(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); + snd_pcm_close(this->hidden->audio_handle); + this->hidden->audio_handle = NULL; } - if ((rval = snd_pcm_close(audio_handle)) < 0) { - SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n", - snd_strerror(rval)); - return; + if (this->hidden->pcm_buf != NULL) { + SDL_FreeAudioMem(this->hidden->pcm_buf); + this->hidden->pcm_buf = NULL; } - audio_handle = NULL; + SDL_free(this->hidden); + this->hidden = NULL; } } static int -NTO_OpenAudio(_THIS, SDL_AudioSpec * spec) +NTO_OpenDevice(_THIS, const char *devname, int iscapture) { - int rval; - int format; - SDL_AudioFormat test_format; - int found; + int rval = 0; + int format = 0; + SDL_AudioFormat test_format = 0; + int found = 0; + snd_pcm_channel_setup_t csetup; + snd_pcm_channel_params_t cparams; - audio_handle = NULL; - this->enabled = 0; - - if (pcm_buf != NULL) { - SDL_FreeAudioMem(pcm_buf); - pcm_buf = NULL; + /* Initialize all variables that we clean on shutdown */ + this->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc((sizeof *this->hidden)); + if (this->hidden == NULL) { + SDL_OutOfMemory(); + return 0; } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); /* initialize channel transfer parameters to default */ NTO_InitAudioParams(&cparams); /* Open the audio device */ - rval = - snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS); + rval = snd_pcm_open_preferred(&this->hidden->audio_handle, + &this->hidden->cardno, + &this->hidden->deviceno, OPEN_FLAGS); + if (rval < 0) { - SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", - snd_strerror(rval)); - return (-1); + NTO_CloseDevice(this); + NTO_SetError("snd_pcm_open", rval); + return 0; } if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) { /* enable count status parameter */ - if ((rval = - snd_pcm_plugin_set_disable(audio_handle, - PLUGIN_DISABLE_MMAP)) < 0) { - SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", - snd_strerror(rval)); - return (-1); + rval = snd_pcm_plugin_set_disable(this->hidden->audio_handle, + PLUGIN_DISABLE_MMAP); + if (rval < 0) { + NTO_CloseDevice(this); + NTO_SetError("snd_pcm_plugin_set_disable", rval); + return 0; } } @@ -387,7 +295,7 @@ /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ found = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); !found;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) { /* if match found set format to equivalent ALSA format */ switch (test_format) { case AUDIO_U8: @@ -441,86 +349,115 @@ /* assumes test_format not 0 on success */ if (test_format == 0) { - SDL_SetError - ("NTO_OpenAudio(): Couldn't find any hardware audio formats"); - return (-1); + NTO_CloseDevice(this); + SDL_SetError("NTO: Couldn't find any hardware audio formats"); + return 0; } - spec->format = test_format; + this->spec.format = test_format; /* Set the audio format */ cparams.format.format = format; /* Set mono or stereo audio (currently only two channels supported) */ - cparams.format.voices = spec->channels; + cparams.format.voices = this->spec.channels; /* Set rate */ - cparams.format.rate = spec->freq; + cparams.format.rate = this->spec.freq; /* Setup the transfer parameters according to cparams */ - rval = snd_pcm_plugin_params(audio_handle, &cparams); + rval = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); if (rval < 0) { - SDL_SetError - ("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", - snd_strerror(rval)); - return (-1); + NTO_CloseDevice(this); + NTO_SetError("snd_pcm_channel_params", rval); + return 0; } /* Make sure channel is setup right one last time */ - SDL_memset(&csetup, 0x00, sizeof(csetup)); + SDL_memset(&csetup, '\0', sizeof (csetup)); csetup.channel = SND_PCM_CHANNEL_PLAYBACK; - if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0) { - SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n"); - return -1; + if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) { + NTO_CloseDevice(this); + SDL_SetError("NTO: Unable to setup playback channel\n"); + return 0; } - /* Calculate the final parameters for this audio specification */ - SDL_CalculateAudioSpec(spec); + SDL_CalculateAudioSpec(&this->spec); - pcm_len = spec->size; + this->hidden->pcm_len = this->spec.size; - if (pcm_len == 0) { - pcm_len = - csetup.buf.block.frag_size * spec->channels * + if (this->hidden->pcm_len == 0) { + this->hidden->pcm_len = + csetup.buf.block.frag_size * this->spec.channels * (snd_pcm_format_width(format) / 8); } - /* Allocate memory to the audio buffer and initialize with silence (Note that - buffer size must be a multiple of fragment size, so find closest multiple) + /* + * Allocate memory to the audio buffer and initialize with silence + * (Note that buffer size must be a multiple of fragment size, so find + * closest multiple) */ - pcm_buf = (Uint8 *) SDL_AllocAudioMem(pcm_len); - if (pcm_buf == NULL) { - SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n"); - return (-1); + this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len); + if (this->hidden->pcm_buf == NULL) { + NTO_CloseDevice(this); + SDL_OutOfMemory(); + return 0; } - SDL_memset(pcm_buf, spec->silence, pcm_len); + SDL_memset(this->hidden->pcm_buf,this->spec.silence,this->hidden->pcm_len); /* get the file descriptor */ - if ((audio_fd = - snd_pcm_file_descriptor(audio_handle, - SND_PCM_CHANNEL_PLAYBACK)) < 0) { - SDL_SetError - ("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", - snd_strerror(rval)); - return (-1); + this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); + if (this->hidden->audio_fd < 0) { + NTO_CloseDevice(this); + NTO_SetError("snd_pcm_file_descriptor", rval); + return 0; } /* Trigger audio playback */ - rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK); + rval = snd_pcm_plugin_prepare(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); if (rval < 0) { - SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", - snd_strerror(rval)); - return (-1); + NTO_CloseDevice(this); + NTO_SetError("snd_pcm_plugin_prepare", rval); + return 0; } - this->enabled = 1; - - /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); - /* We're really ready to rock and roll. :-) */ - return (0); + return 1; } + +static int +NTO_Init(SDL_AudioDriverImpl *impl) +{ + /* See if we can open a nonblocking channel. */ + snd_pcm_t *handle = NULL; + int rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS); + if (rval < 0) { + SDL_SetError("NTO: couldn't open preferred audio device"); + return 0; + } + if ((rval = snd_pcm_close(handle)) < 0) { + SDL_SetError("NTO: couldn't close test audio device"); + return 0; + } + + /* Set the function pointers */ + impl->OpenDevice = NTO_OpenDevice; + impl->ThreadInit = NTO_ThreadInit; + impl->WaitDevice = NTO_WaitDevice; + impl->PlayDevice = NTO_PlayDevice; + impl->GetDeviceBuf = NTO_GetDeviceBuf; + impl->CloseDevice = NTO_CloseDevice; + impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */ + + return 1; +} + +AudioBootStrap QNXNTOAUDIO_bootstrap = { + DRIVER_NAME, "QNX6 QSA-NTO Audio", NTO_Init, 0 +}; + /* vi: set ts=4 sw=4 expandtab: */