Mercurial > sdl-ios-xcode
diff src/audio/nto/SDL_nto_audio.c @ 718:cbc0f7fabd1c
Date: Sat, 13 Sep 2003 15:50:43 +0300
From: "Mike Gorchak"
Subject: QNX fixes
improved sound code for the QNX, added workarounds for known bugs, fixed photon detect code. Update .qpg file.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 21 Sep 2003 18:13:48 +0000 |
parents | 8bedd6d61642 |
children | b8d311d90021 |
line wrap: on
line diff
--- a/src/audio/nto/SDL_nto_audio.c Mon Sep 15 13:51:25 2003 +0000 +++ b/src/audio/nto/SDL_nto_audio.c Sun Sep 21 18:13:48 2003 +0000 @@ -30,8 +30,9 @@ #include <sys/types.h> #include <sys/time.h> #include <sched.h> +#include <sys/select.h> +#include <sys/neutrino.h> #include <sys/asoundlib.h> -#include <sys/select.h> #include "SDL_audio.h" #include "SDL_error.h" @@ -41,11 +42,12 @@ #include "SDL_nto_audio.h" /* The tag name used by NTO audio */ -#define DRIVER_NAME "nto" +#define DRIVER_NAME "qsa-nto" /* default channel communication parameters */ #define DEFAULT_CPARAMS_RATE 22050 #define DEFAULT_CPARAMS_VOICES 1 +/* FIXME: need to add in the near future flexible logic with frag_size and frags count */ #define DEFAULT_CPARAMS_FRAG_SIZE 4096 #define DEFAULT_CPARAMS_FRAGS_MIN 1 #define DEFAULT_CPARAMS_FRAGS_MAX 1 @@ -53,438 +55,456 @@ /* Open the audio device for playback, and don't block if busy */ #define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK +#define QSA_NO_WORKAROUNDS 0x00000000 +#define QSA_MMAP_WORKAROUND 0x00000001 + +struct BuggyCards +{ + char* cardname; + unsigned long bugtype; +}; + +#define QSA_WA_CARDS 3 + +struct BuggyCards buggycards[QSA_WA_CARDS]= +{ + {"Sound Blaster Live!", QSA_MMAP_WORKAROUND}, + {"Vortex 8820", QSA_MMAP_WORKAROUND}, + {"Vortex 8830", QSA_MMAP_WORKAROUND}, +}; + /* Audio driver functions */ -static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec); +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 Uint8* NTO_GetAudioBuf(_THIS); static void NTO_CloseAudio(_THIS); -static snd_pcm_channel_status_t cstatus; -static snd_pcm_channel_params_t cparams; -static snd_pcm_channel_setup_t csetup; +/* card names check to apply the workarounds */ +static int NTO_CheckBuggyCards(_THIS, unsigned long checkfor) +{ + char scardname[33]; + int it; + + if (snd_card_get_name(cardno, scardname, 32)<0) + { + return 0; + } + + for (it=0; it<QSA_WA_CARDS; it++) + { + if (strcmp(buggycards[it].cardname, scardname)==0) + { + if (buggycards[it].bugtype==checkfor) + { + return 1; + } + } + } + + return 0; +} + +static void NTO_ThreadInit(_THIS) +{ + int status; + struct sched_param param; + + /* 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); +} /* PCM transfer channel parameters initialize function */ -static void init_pcm_cparams(snd_pcm_channel_params_t* cparams) +static void NTO_InitAudioParams(snd_pcm_channel_params_t* cpars) { - memset(cparams,0,sizeof(snd_pcm_channel_params_t)); + memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); - cparams->channel = SND_PCM_CHANNEL_PLAYBACK; - cparams->mode = SND_PCM_MODE_BLOCK; - cparams->start_mode = SND_PCM_START_DATA; - cparams->stop_mode = SND_PCM_STOP_STOP; - cparams->format.format = SND_PCM_SFMT_S16_LE; - cparams->format.interleave = 1; - cparams->format.rate = DEFAULT_CPARAMS_RATE; - cparams->format.voices = DEFAULT_CPARAMS_VOICES; - cparams->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE; - cparams->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN; - cparams->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; + cpars->channel = SND_PCM_CHANNEL_PLAYBACK; + cpars->mode = SND_PCM_MODE_BLOCK; + cpars->start_mode = SND_PCM_START_DATA; + cpars->stop_mode = SND_PCM_STOP_STOP; + cpars->format.format = SND_PCM_SFMT_S16_LE; + cpars->format.interleave = 1; + cpars->format.rate = DEFAULT_CPARAMS_RATE; + cpars->format.voices = DEFAULT_CPARAMS_VOICES; + cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE; + cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN; + cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX; } -static int Audio_Available(void) +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. - */ + /* 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; + int available; + int rval; + snd_pcm_t* handle; - available = 0; - handle = NULL; + available = 0; + handle = NULL; - rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS); + rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS); - if (rval >= 0){ - available = 1; - - if ((rval = snd_pcm_close(handle)) < 0){ - SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval)); - available = 0; - } - } - else{ - SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval)); - } - - #ifdef DEBUG_AUDIO - fprintf(stderr,"AudioAvailable rtns %d\n", available); - #endif - - return(available); + 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 Audio_DeleteDevice(SDL_AudioDevice *device) +static void NTO_DeleteAudioDevice(SDL_AudioDevice *device) { - #ifdef DEBUG_AUDIO - fprintf(stderr,"Audio_DeleteDevice\n"); - #endif - - free(device->hidden); - free(device); + if ((device)&&(device->hidden)) + { + free(device->hidden); + } + if (device) + { + free(device); + } } -static SDL_AudioDevice *Audio_CreateDevice(int devindex) +static SDL_AudioDevice* NTO_CreateAudioDevice(int devindex) { - SDL_AudioDevice *this; - #ifdef DEBUG_AUDIO - fprintf(stderr,"Audio_CreateDevice\n"); - #endif - /* Initialize all variables that we clean on shutdown */ - this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); - if ( this ) { - memset(this, 0, (sizeof *this)); - this->hidden = (struct SDL_PrivateAudioData *) - malloc((sizeof *this->hidden)); + SDL_AudioDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); + if (this) + { + memset(this, 0, sizeof(SDL_AudioDevice)); + this->hidden = (struct SDL_PrivateAudioData *)malloc(sizeof(struct SDL_PrivateAudioData)); + } + if ((this == NULL) || (this->hidden == NULL)) + { + SDL_OutOfMemory(); + if (this) + { + free(this); } - if ( (this == NULL) || (this->hidden == NULL) ) { - SDL_OutOfMemory(); - if ( this ) { - free(this); - } - return(0); - } - memset(this->hidden, 0, (sizeof *this->hidden)); - audio_handle = NULL; + return (0); + } + memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); + audio_handle = NULL; - /* Set the function pointers */ - this->OpenAudio = NTO_OpenAudio; - this->WaitAudio = NTO_WaitAudio; - this->PlayAudio = NTO_PlayAudio; - this->GetAudioBuf = NTO_GetAudioBuf; - this->CloseAudio = NTO_CloseAudio; + /* 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 = Audio_DeleteDevice; + this->free = NTO_DeleteAudioDevice; - return this; + return this; } -AudioBootStrap QNXNTOAUDIO_bootstrap = { - DRIVER_NAME, "QNX6 NTO PCM audio", - Audio_Available, Audio_CreateDevice +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) { - fd_set wfds; + fd_set wfds; + int selectret; + + FD_ZERO(&wfds); + FD_SET(audio_fd, &wfds); - FD_SET( audio_fd, &wfds ); - switch( select( audio_fd + 1, NULL, &wfds, NULL, NULL ) ) - { - case -1: - case 0: - /* Error */ - SDL_SetError("select() in NTO_WaitAudio failed: %s\n", strerror(errno)); - break; - default: - if(FD_ISSET(audio_fd, &wfds)) - return; - } + do { + selectret=select(audio_fd + 1, NULL, &wfds, NULL, NULL); + switch (selectret) + { + case -1: + case 0: SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", strerror(errno)); + return; + default: if (FD_ISSET(audio_fd, &wfds)) + { + return; + } + break; + } + } while(1); } static void NTO_PlayAudio(_THIS) { - int written, rval; - int towrite; + int written, rval; + int towrite; + void* pcmbuffer; - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_PlayAudio\n"); - #endif - - if( !this->enabled){ - return; - } + if (!this->enabled) + { + return; + } + + towrite = this->spec.size; + pcmbuffer = pcm_buf; - towrite = pcm_len; - - /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ - do { - written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_PlayAudio: written = %d towrite = %d\n",written,towrite); - #endif - if (written != towrite){ - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){ - SDL_Delay(1); /* Let a little CPU time go by and try to write again */ - #ifdef DEBUG_AUDIO - fprintf(stderr, "errno == EAGAIN written %d\n", written); - #endif - towrite -= written; //we wrote some data - continue; - } - else if((errno == EINVAL) || (errno == EIO)){ - if(errno == EIO){ - #ifdef DEBUG_AUDIO - fprintf(stderr,"snd_pcm_plugin_write failed EIO: %s\n", snd_strerror(written)); - #endif - } - if(errno == EINVAL){ - #ifdef DEBUG_AUDIO - fprintf(stderr,"snd_pcm_plugin_write failed EINVAL: %s\n", snd_strerror(written)); - #endif - } - - memset(&cstatus, 0, sizeof(cstatus)); - if( (rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0 ){ - #ifdef DEBUG_AUDIO - fprintf(stderr, "snd_pcm_plugin_status failed %s\n",snd_strerror(rval)); - #endif - SDL_SetError("snd_pcm_plugin_status failed: %s\n", snd_strerror(rval)); - return; - } - - if ( (cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY) ){ - #ifdef DEBUG_AUDIO - fprintf(stderr, "buffer underrun\n"); - #endif - if ( (rval = snd_pcm_plugin_prepare (audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0 ){ - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_PlayAudio: prepare failed %s\n",snd_strerror(rval)); - #endif - SDL_SetError("snd_pcm_plugin_prepare failed: %s\n",snd_strerror(rval) ); - return; - } - } - continue; - } - else{ - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_PlayAudio: snd_pcm_plugin_write failed unknown errno %d %s\n",errno, snd_strerror(rval)); - #endif - return; - } - - } - else - { - towrite -= written; //we wrote all remaining data - } - } while ( (towrite > 0) && (this->enabled) ); + /* Write the audio data, checking for EAGAIN (buffer full) and underrun */ + do { + written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite); + if (written != towrite) + { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + /* Let a little CPU time go by and try to write again */ + SDL_Delay(1); + /* if we wrote some data */ + towrite -= written; + pcmbuffer += written * this->spec.channels; + continue; + } + else + { + if ((errno == EINVAL) || (errno == EIO)) + { + 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)); + 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; + } + } + } + else + { + /* we wrote all remaining data */ + towrite -= written; + pcmbuffer += written * this->spec.channels; + } + } while ((towrite > 0) && (this->enabled)); - /* If we couldn't write, assume fatal error for now */ - if ( towrite != 0 ) { - this->enabled = 0; - } - return; + /* If we couldn't write, assume fatal error for now */ + if (towrite != 0) + { + this->enabled = 0; + } + + return; } -static Uint8 *NTO_GetAudioBuf(_THIS) +static Uint8* NTO_GetAudioBuf(_THIS) { - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_GetAudioBuf: pcm_buf %X\n",(Uint8 *)pcm_buf); - #endif - return(pcm_buf); + return pcm_buf; } static void NTO_CloseAudio(_THIS) { - int rval; + int rval; - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_CloseAudio\n"); - #endif - - this->enabled = 0; + this->enabled = 0; - if ( audio_handle != NULL ) { - if ((rval = snd_pcm_plugin_flush(audio_handle,SND_PCM_CHANNEL_PLAYBACK)) < 0){ - SDL_SetError("snd_pcm_plugin_flush failed: %s\n",snd_strerror(rval)); - return; - } - if ((rval = snd_pcm_close(audio_handle)) < 0){ - SDL_SetError("snd_pcm_close failed: %s\n",snd_strerror(rval)); - return; - } - audio_handle = NULL; - } + 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 ((rval = snd_pcm_close(audio_handle)) < 0) + { + SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",snd_strerror(rval)); + return; + } + audio_handle = NULL; + } } -static int NTO_OpenAudio(_THIS, SDL_AudioSpec *spec) +static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec) { - int rval; - int format; - Uint16 test_format; - int twidth; - int found; + int rval; + int format; + Uint16 test_format; + int found; - #ifdef DEBUG_AUDIO - fprintf(stderr, "NTO_OpenAudio\n"); - #endif - - audio_handle = NULL; - this->enabled = 0; + audio_handle = NULL; + this->enabled = 0; + + if (pcm_buf != NULL) + { + SDL_FreeAudioMem(pcm_buf); + pcm_buf = NULL; + } - if ( pcm_buf != NULL ) { - free((Uint8 *)pcm_buf); - pcm_buf = NULL; - } - - /* initialize channel transfer parameters to default */ - init_pcm_cparams(&cparams); + /* initialize channel transfer parameters to default */ + NTO_InitAudioParams(&cparams); - /* Open the audio device */ - rval = snd_pcm_open_preferred(&audio_handle, NULL, NULL, OPEN_FLAGS); - if ( rval < 0 ) { - SDL_SetError("snd_pcm_open failed: %s\n", snd_strerror(rval)); - return(-1); - } + /* Open the audio device */ + rval = snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS); + if (rval < 0) + { + SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", snd_strerror(rval)); + return (-1); + } - /* 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); - } + 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); + } + } - /* Try for a closest match on audio format */ - format = 0; - found = 0; /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ - for ( test_format = SDL_FirstAudioFormat(spec->format); !found ; ) - { - #ifdef DEBUG_AUDIO - fprintf(stderr, "Trying format 0x%4.4x spec->samples %d\n", test_format,spec->samples); - #endif - - /* if match found set format to equivalent ALSA format */ - switch ( test_format ) { - case AUDIO_U8: - format = SND_PCM_SFMT_U8; - found = 1; - break; - case AUDIO_S8: - format = SND_PCM_SFMT_S8; - found = 1; - break; - case AUDIO_S16LSB: - format = SND_PCM_SFMT_S16_LE; - found = 1; - break; - case AUDIO_S16MSB: - format = SND_PCM_SFMT_S16_BE; - found = 1; - break; - case AUDIO_U16LSB: - format = SND_PCM_SFMT_U16_LE; - found = 1; - break; - case AUDIO_U16MSB: - format = SND_PCM_SFMT_U16_BE; - found = 1; - break; - default: - break; - } - if ( ! found ) { - test_format = SDL_NextAudioFormat(); - } - } + /* Try for a closest match on audio format */ + format = 0; + /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */ + found = 0; - /* assumes test_format not 0 on success */ - if ( test_format == 0 ) { - SDL_SetError("Couldn't find any hardware audio formats"); - return(-1); - } + for (test_format=SDL_FirstAudioFormat(spec->format); !found ;) + { + /* if match found set format to equivalent ALSA format */ + switch (test_format) + { + case AUDIO_U8: + format = SND_PCM_SFMT_U8; + found = 1; + break; + case AUDIO_S8: + format = SND_PCM_SFMT_S8; + found = 1; + break; + case AUDIO_S16LSB: + format = SND_PCM_SFMT_S16_LE; + found = 1; + break; + case AUDIO_S16MSB: + format = SND_PCM_SFMT_S16_BE; + found = 1; + break; + case AUDIO_U16LSB: + format = SND_PCM_SFMT_U16_LE; + found = 1; + break; + case AUDIO_U16MSB: + format = SND_PCM_SFMT_U16_BE; + found = 1; + break; + default: + break; + } - spec->format = test_format; - - /* Set the audio format */ - cparams.format.format = format; + if (!found) + { + test_format = SDL_NextAudioFormat(); + } + } - /* Set mono or stereo audio (currently only two channels supported) */ - cparams.format.voices = spec->channels; - - #ifdef DEBUG_AUDIO - fprintf(stderr,"intializing channels %d\n", cparams.format.voices); - #endif - - /* Set rate */ - cparams.format.rate = spec->freq ; - - /* Setup the transfer parameters according to cparams */ - rval = snd_pcm_plugin_params(audio_handle, &cparams); - if (rval < 0) { - SDL_SetError("snd_pcm_channel_params failed: %s\n", snd_strerror (rval)); - return(-1); - } + /* assumes test_format not 0 on success */ + if (test_format == 0) + { + SDL_SetError("NTO_OpenAudio(): Couldn't find any hardware audio formats"); + return (-1); + } - /* Make sure channel is setup right one last time */ - memset( &csetup, 0, sizeof( csetup ) ); - csetup.channel = SND_PCM_CHANNEL_PLAYBACK; - if ( snd_pcm_plugin_setup( audio_handle, &csetup ) < 0 ) - { - SDL_SetError("Unable to setup playback channel\n" ); - return(-1); - } - else - { - #ifdef DEBUG_AUDIO - fprintf(stderr,"requested format: %d\n",cparams.format.format); - fprintf(stderr,"requested frag size: %d\n",cparams.buf.block.frag_size); - fprintf(stderr,"requested max frags: %d\n\n",cparams.buf.block.frags_max); + spec->format = test_format; - fprintf(stderr,"real format: %d\n", csetup.format.format ); - fprintf(stderr,"real frag size : %d\n", csetup.buf.block.frag_size ); - fprintf(stderr,"real max frags : %d\n", csetup.buf.block.frags_max ); - #endif - } + /* Set the audio format */ + cparams.format.format = format; - /* - 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) - */ + /* Set mono or stereo audio (currently only two channels supported) */ + cparams.format.voices = spec->channels; - twidth = snd_pcm_format_width(format); - if (twidth < 0) { - printf("snd_pcm_format_width failed\n"); - twidth = 0; - } + /* Set rate */ + cparams.format.rate = spec->freq; - #ifdef DEBUG_AUDIO - fprintf(stderr,"format is %d bits wide\n",twidth); - #endif + /* Setup the transfer parameters according to cparams */ + rval = snd_pcm_plugin_params(audio_handle, &cparams); + if (rval < 0) + { + SDL_SetError("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", snd_strerror(rval)); + return (-1); + } - pcm_len = spec->size ; - - #ifdef DEBUG_AUDIO - fprintf(stderr,"pcm_len set to %d\n", pcm_len); - #endif + /* Make sure channel is setup right one last time */ + memset(&csetup, 0x00, 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 (pcm_len == 0){ - pcm_len = csetup.buf.block.frag_size; - } + /* Calculate the final parameters for this audio specification */ + SDL_CalculateAudioSpec(spec); + + pcm_len = spec->size; + + if (pcm_len==0) + { + pcm_len = csetup.buf.block.frag_size * spec->channels * (snd_pcm_format_width(format)/8); + } - pcm_buf = (Uint8*)malloc(pcm_len); - if (pcm_buf == NULL) { - SDL_SetError("pcm_buf malloc failed\n"); - return(-1); - } - memset(pcm_buf,spec->silence,pcm_len); - - #ifdef DEBUG_AUDIO - fprintf(stderr,"pcm_buf malloced and silenced.\n"); - #endif - - /* get the file descriptor */ - if( (audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0){ - fprintf(stderr, "snd_pcm_file_descriptor failed with error code: %d\n", audio_fd); - } + /* 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); + } + memset(pcm_buf, spec->silence, pcm_len); - /* Trigger audio playback */ - rval = snd_pcm_plugin_prepare( audio_handle, SND_PCM_CHANNEL_PLAYBACK); - if (rval < 0) { - SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror (rval)); - return(-1); - } + /* 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->enabled = 1; + /* Trigger audio playback */ + rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK); + if (rval < 0) + { + SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval)); + return (-1); + } - /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); + this->enabled = 1; - /* We're ready to rock and roll. :-) */ - return(0); + /* 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); }