Mercurial > sdl-ios-xcode
diff src/audio/paudio/SDL_paudio.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 | 3b4ce57c6215 |
children | 866052b01ee5 |
line wrap: on
line diff
--- a/src/audio/paudio/SDL_paudio.c Sun Oct 01 16:10:41 2006 +0000 +++ b/src/audio/paudio/SDL_paudio.c Tue Oct 17 09:15:21 2006 +0000 @@ -30,16 +30,17 @@ #include <fcntl.h> #include <sys/time.h> #include <sys/ioctl.h> +#include <sys/types.h> #include <sys/stat.h> #include "SDL_timer.h" #include "SDL_audio.h" +#include "SDL_stdinc.h" #include "../SDL_audiomem.h" #include "../SDL_audio_c.h" -#include "../SDL_audiodev_c.h" #include "SDL_paudio.h" -#define DEBUG_AUDIO 1 +#define DEBUG_AUDIO 0 /* A conflict within AIX 4.3.3 <sys/> headers and probably others as well. * I guess nobody ever uses audio... Shame over AIX header files. */ @@ -48,94 +49,95 @@ #include <sys/audio.h> /* The tag name used by paud audio */ -#define Paud_DRIVER_NAME "paud" +#define PAUDIO_DRIVER_NAME "paud" /* Open the audio device for playback, and don't block if busy */ /* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */ #define OPEN_FLAGS O_WRONLY -/* Audio driver functions */ -static int Paud_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void Paud_WaitAudio(_THIS); -static void Paud_PlayAudio(_THIS); -static Uint8 *Paud_GetAudioBuf(_THIS); -static void Paud_CloseAudio(_THIS); +/* Get the name of the audio device we use for output */ + +#ifndef _PATH_DEV_DSP +#define _PATH_DEV_DSP "/dev/%caud%c/%c" +#endif -/* Audio driver bootstrap functions */ +static char devsettings[][3] = { + {'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'}, + {'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'}, + {'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'}, + {'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'}, + {'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'}, + {'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'}, + {'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'}, + {'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'}, + {'\0', '\0', '\0'} +}; static int -Audio_Available(void) +OpenUserDefinedDevice(char *path, int maxlen, int flags) { + const char *audiodev; int fd; - int available; - available = 0; - fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); - if (fd >= 0) { - available = 1; - close(fd); + /* Figure out what our audio device is */ + if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) { + audiodev = SDL_getenv("AUDIODEV"); + } + if (audiodev == NULL) { + return -1; } - return (available); -} - -static void -Audio_DeleteDevice(SDL_AudioDevice * device) -{ - SDL_free(device->hidden); - SDL_free(device); + fd = open(audiodev, flags, 0); + if (path != NULL) { + SDL_strlcpy(path, audiodev, maxlen); + path[maxlen - 1] = '\0'; + } + return fd; } -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) +static int +OpenAudioPath(char *path, int maxlen, int flags, int classic) { - SDL_AudioDevice *this; + struct stat sb; + int cycle = 0; + int fd = OpenUserDefinedDevice(path, maxlen, flags); - /* Initialize all variables that we clean on shutdown */ - this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); - if (this) { - SDL_memset(this, 0, (sizeof *this)); - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc((sizeof *this->hidden)); - } - if ((this == NULL) || (this->hidden == NULL)) { - SDL_OutOfMemory(); - if (this) { - SDL_free(this); - } - return (0); + if (fd != -1) { + return fd; } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - audio_fd = -1; - /* Set the function pointers */ - this->OpenAudio = Paud_OpenAudio; - this->WaitAudio = Paud_WaitAudio; - this->PlayAudio = Paud_PlayAudio; - this->GetAudioBuf = Paud_GetAudioBuf; - this->CloseAudio = Paud_CloseAudio; + /* !!! FIXME: do we really need a table here? */ + while (devsettings[cycle][0] != '\0') { + char audiopath[1024]; + SDL_snprintf(audiopath, SDL_arraysize(audiopath), + _PATH_DEV_DSP, + devsettings[cycle][0], + devsettings[cycle][1], devsettings[cycle][2]); - this->free = Audio_DeleteDevice; - - return this; + if (stat(audiopath, &sb) == 0) { + fd = open(audiopath, flags, 0); + if (fd > 0) { + if (path != NULL) { + SDL_strlcpy(path, audiopath, maxlen); + } + return fd; + } + } + } + return -1; } -AudioBootStrap Paud_bootstrap = { - Paud_DRIVER_NAME, "AIX Paudio", - Audio_Available, Audio_CreateDevice -}; - /* This function waits until it is possible to write a full sound buffer */ static void -Paud_WaitAudio(_THIS) +PAUDIO_WaitDevice(_THIS) { fd_set fdset; /* See if we need to use timed audio synchronization */ - if (frame_ticks) { + if (this->hidden->frame_ticks) { /* Use timer for general audio synchronization */ Sint32 ticks; - ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; + ticks = ((Sint32)(this->hidden->next_frame-SDL_GetTicks()))-FUDGE_TICKS; if (ticks > 0) { SDL_Delay(ticks); } @@ -145,9 +147,9 @@ /* Use select() for audio synchronization */ struct timeval timeout; FD_ZERO(&fdset); - FD_SET(audio_fd, &fdset); + FD_SET(this->hidden->audio_fd, &fdset); - if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { + if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { #ifdef DEBUG_AUDIO fprintf(stderr, "Couldn't get audio buffer information\n"); #endif @@ -168,7 +170,7 @@ #ifdef DEBUG_AUDIO fprintf(stderr, "Waiting for audio to get ready\n"); #endif - if (select(audio_fd + 1, NULL, &fdset, NULL, &timeout) <= 0) { + if (select(this->hidden->audio_fd+1,NULL,&fdset,NULL,&timeout) <= 0) { const char *message = "Audio timeout - buggy audio driver? (disabled)"; /* @@ -179,7 +181,7 @@ fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); this->enabled = 0; /* Don't try to close - may hang */ - audio_fd = -1; + this->hidden->audio_fd = -1; #ifdef DEBUG_AUDIO fprintf(stderr, "Done disabling audio\n"); #endif @@ -191,13 +193,15 @@ } static void -Paud_PlayAudio(_THIS) +PAUDIO_PlayDevice(_THIS) { - int written; + int written = 0; + const Uint8 *mixbuf = this->hidden->mixbuf; + const size_t mixlen = this->hidden->mixlen; /* Write the audio data, checking for EAGAIN on broken audio drivers */ do { - written = write(audio_fd, mixbuf, mixlen); + written = write(this->hidden->audio_fd, mixbuf, mixlen); if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) { SDL_Delay(1); /* Let a little CPU time go by */ } @@ -206,8 +210,8 @@ ((errno == 0) || (errno == EAGAIN) || (errno == EINTR))); /* If timer synchronization is enabled, set the next write frame */ - if (frame_ticks) { - next_frame += frame_ticks; + if (this->hidden->frame_ticks) { + this->hidden->next_frame += this->hidden->frame_ticks; } /* If we couldn't write, assume fatal error for now */ @@ -220,28 +224,34 @@ } static Uint8 * -Paud_GetAudioBuf(_THIS) +PAUDIO_GetDeviceBuf(_THIS) { - return mixbuf; + return this->hidden->mixbuf; } static void -Paud_CloseAudio(_THIS) +PAUDIO_CloseDevice(_THIS) { - if (mixbuf != NULL) { - SDL_FreeAudioMem(mixbuf); - mixbuf = NULL; - } - if (audio_fd >= 0) { - close(audio_fd); - audio_fd = -1; + if (this->hidden != NULL) { + if (this->hidden->mixbuf != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + this->hidden->mixbuf = NULL; + } + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); + this->hidden->audio_fd = -1; + } + SDL_free(this->hidden); + this->hidden = NULL; } } static int -Paud_OpenAudio(_THIS, SDL_AudioSpec * spec) +PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) { + const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); char audiodev[1024]; + const char *err = NULL; int format; int bytes_per_sample; SDL_AudioFormat test_format; @@ -250,32 +260,40 @@ audio_status paud_status; audio_control paud_control; audio_change paud_change; + int fd = -1; - /* Reset the timer synchronization flag */ - frame_ticks = 0.0; + /* 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)); /* Open the audio device */ - audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); - if (audio_fd < 0) { + fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); + this->hidden->audio_fd = fd; + if (fd < 0) { + PAUDIO_CloseDevice(this); SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); - return -1; + return 0; } /* * We can't set the buffer size - just ask the device for the maximum * that we can have. */ - if (ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { + if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { + PAUDIO_CloseDevice(this); SDL_SetError("Couldn't get audio buffer information"); - return -1; + return 0; } - mixbuf = NULL; - - if (spec->channels > 1) - spec->channels = 2; + if (this->spec.channels > 1) + this->spec.channels = 2; else - spec->channels = 1; + this->spec.channels = 1; /* * Fields in the audio_init structure: @@ -322,14 +340,14 @@ * paud.position_resolution; * smallest increment for position */ - paud_init.srate = spec->freq; + paud_init.srate = this->spec.freq; paud_init.mode = PCM; paud_init.operation = PLAY; - paud_init.channels = spec->channels; + paud_init.channels = this->spec.channels; /* Try for a closest match on audio format */ format = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); + for (test_format = SDL_FirstAudioFormat(this->spec.format); !format && test_format;) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); @@ -382,31 +400,32 @@ #ifdef DEBUG_AUDIO fprintf(stderr, "Couldn't find any hardware audio formats\n"); #endif + PAUDIO_CloseDevice(this); SDL_SetError("Couldn't find any hardware audio formats"); - return -1; + return 0; } - spec->format = test_format; + this->spec.format = test_format; /* * We know the buffer size and the max number of subsequent writes - * that can be pending. If more than one can pend, allow the application - * to do something like double buffering between our write buffer and - * the device's own buffer that we are filling with write() anyway. + * that can be pending. If more than one can pend, allow the application + * to do something like double buffering between our write buffer and + * the device's own buffer that we are filling with write() anyway. * - * We calculate spec->samples like this because SDL_CalculateAudioSpec() - * will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2) - * into spec->size in return. + * We calculate this->spec.samples like this because + * SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap + * (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return. */ if (paud_bufinfo.request_buf_cap == 1) { - spec->samples = paud_bufinfo.write_buf_cap - / bytes_per_sample / spec->channels; + this->spec.samples = paud_bufinfo.write_buf_cap + / bytes_per_sample / this->spec.channels; } else { - spec->samples = paud_bufinfo.write_buf_cap - / bytes_per_sample / spec->channels / 2; + this->spec.samples = paud_bufinfo.write_buf_cap + / bytes_per_sample / this->spec.channels / 2; } - paud_init.bsize = bytes_per_sample * spec->channels; + paud_init.bsize = bytes_per_sample * this->spec.channels; - SDL_CalculateAudioSpec(spec); + SDL_CalculateAudioSpec(&this->spec); /* * The AIX paud device init can't modify the values of the audio_init @@ -416,47 +435,44 @@ * /dev/paud supports all of the encoding formats, so we don't need * to do anything like reopening the device, either. */ - if (ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0) { + if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) { switch (paud_init.rc) { case 1: - SDL_SetError - ("Couldn't set audio format: DSP can't do play requests"); - return -1; + err = "Couldn't set audio format: DSP can't do play requests"; break; case 2: - SDL_SetError - ("Couldn't set audio format: DSP can't do record requests"); - return -1; + err = "Couldn't set audio format: DSP can't do record requests"; break; case 4: - SDL_SetError("Couldn't set audio format: request was invalid"); - return -1; + err = "Couldn't set audio format: request was invalid"; break; case 5: - SDL_SetError - ("Couldn't set audio format: conflict with open's flags"); - return -1; + err = "Couldn't set audio format: conflict with open's flags"; break; case 6: - SDL_SetError - ("Couldn't set audio format: out of DSP MIPS or memory"); - return -1; + err = "Couldn't set audio format: out of DSP MIPS or memory"; break; default: - SDL_SetError - ("Couldn't set audio format: not documented in sys/audio.h"); - return -1; + err = "Couldn't set audio format: not documented in sys/audio.h"; break; } } + if (err != NULL) { + PAUDIO_CloseDevice(this); + SDL_SetError("Paudio: %s", err); + return 0; + } + /* Allocate mixing buffer */ - mixlen = spec->size; - mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); - if (mixbuf == NULL) { - return -1; + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + PAUDIO_CloseDevice(this); + SDL_OutOfMemory(); + return 0; } - SDL_memset(mixbuf, spec->silence, spec->size); + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* * Set some paramters: full volume, first speaker that we can find. @@ -475,7 +491,7 @@ paud_control.ioctl_request = AUDIO_CHANGE; paud_control.request_info = (char *) &paud_change; - if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) { + if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { #ifdef DEBUG_AUDIO fprintf(stderr, "Can't change audio display settings\n"); #endif @@ -487,29 +503,49 @@ */ paud_control.ioctl_request = AUDIO_START; paud_control.position = 0; - if (ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0) { + if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { + PAUDIO_CloseDevice(this); #ifdef DEBUG_AUDIO fprintf(stderr, "Can't start audio play\n"); #endif SDL_SetError("Can't start audio play"); - return -1; + return 0; } /* Check to see if we need to use select() workaround */ - { - char *workaround; - workaround = SDL_getenv("SDL_DSP_NOSELECT"); - if (workaround) { - frame_ticks = (float) (spec->samples * 1000) / spec->freq; - next_frame = SDL_GetTicks() + frame_ticks; - } + if (workaround != NULL) { + this->hidden->frame_ticks = (float) (this->spec.samples * 1000) / + this->spec.freq; + this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks; } - /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); - /* We're ready to rock and roll. :-) */ - return 0; + return 1; } +static int +PAUDIO_Init(SDL_AudioDriverImpl *impl) +{ + int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); + if (fd < 0) { + SDL_SetError("PAUDIO: Couldn't open audio device"); + return 0; + } + close(fd); + + /* Set the function pointers */ + impl->OpenDevice = DSP_OpenDevice; + impl->PlayDevice = DSP_PlayDevice; + impl->PlayDevice = DSP_WaitDevice; + impl->GetDeviceBuf = DSP_GetDeviceBuf; + impl->CloseDevice = DSP_CloseDevice; + impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */ + + return 1; +} + +AudioBootStrap PAUDIO_bootstrap = { + PAUDIO_DRIVER_NAME, "AIX Paudio", PAUDIO_Init, 0 +}; + /* vi: set ts=4 sw=4 expandtab: */