diff -u -r SDL12/include/SDL.h SDL12-unmod/include/SDL.h --- SDL12/include/SDL.h 2004-02-22 22:53:36.000000000 -0600 +++ SDL12-unmod/include/SDL.h 2005-09-05 16:57:05.000000000 -0600 @@ -60,6 +60,7 @@ #define SDL_INIT_VIDEO 0x00000020 #define SDL_INIT_CDROM 0x00000100 #define SDL_INIT_JOYSTICK 0x00000200 +#define SDL_INIT_AUDIOIN 0x00001000 #define SDL_INIT_NOPARACHUTE 0x00100000 /* Don't catch fatal signals */ #define SDL_INIT_EVENTTHREAD 0x01000000 /* Not supported on all OS's */ #define SDL_INIT_EVERYTHING 0x0000FFFF diff -u -r SDL12/include/SDL_audio.h SDL12-unmod/include/SDL_audio.h --- SDL12/include/SDL_audio.h 2004-11-30 12:52:46.000000000 -0600 +++ SDL12-unmod/include/SDL_audio.h 2005-09-05 16:57:05.000000000 -0600 @@ -158,6 +158,18 @@ extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained); /* + * SDL_OpenAudio must be called first, since input and output use the + * same audio device. SDL_OpenAudioIn is needed to associate the audio + * devie with yet another callback, this one for audio input. The audio + * input begins paused when associated and should be enabled for recording + * by calling SDL_PauseAudioIn(0) when you are ready for your audio + * callback function to be called. + */ +extern DECLSPEC int SDLCALL SDL_OpenAudioIn( + void (SDLCALL *callback)(void *userdata, Uint8 *stream, int len), + void *userdata); + +/* * Get the current audio state: */ typedef enum { @@ -168,6 +180,11 @@ extern DECLSPEC SDL_audiostatus SDLCALL SDL_GetAudioStatus(void); /* + * Get the current audio recording state + */ +extern DECLSPEC SDL_audiostatus SDLCALL SDL_GetAudioInStatus(void); + +/* * This function pauses and unpauses the audio callback processing. * It should be called with a parameter of 0 after opening the audio * device to start playing sound. This is so you can safely initialize @@ -177,6 +194,14 @@ extern DECLSPEC void SDLCALL SDL_PauseAudio(int pause_on); /* + * This function pauses and unpauses audio input callback processing. + * It should be called with a parameter of 0 after calling + * SDL_OpenAudioIn. This is so you can safely initialize data for your + * callback function after opening the audio input device. + */ +extern DECLSPEC void SDLCALL SDL_PauseAudioIn(int pause_on); + +/* * This function loads a WAVE from the data source, automatically freeing * that source if 'freesrc' is non-zero. For example, to load a WAVE file, * you could do: @@ -245,6 +270,15 @@ extern DECLSPEC void SDLCALL SDL_UnlockAudio(void); /* + * The lock manipulated by these functions protects the audio input + * callback function. During a LockAudioIn/UnlockAudioIn pair, you can + * be guaranteed that the callback function is not running. Do not call + * these from the callback function or you will cause a deadlock. + */ +extern DECLSPEC void SDLCALL SDL_LockAudioIn(void); +extern DECLSPEC void SDLCALL SDL_UnlockAudioIn(void); + +/* * This function shuts down audio processing and closes the audio device. */ extern DECLSPEC void SDLCALL SDL_CloseAudio(void); diff -u -r SDL12/src/SDL.c SDL12-unmod/src/SDL.c --- SDL12/src/SDL.c 2004-02-22 22:53:37.000000000 -0600 +++ SDL12-unmod/src/SDL.c 2005-09-05 16:57:04.000000000 -0600 @@ -85,9 +85,28 @@ #endif #ifndef DISABLE_AUDIO +# ifdef DISABLE_AUDIOIN + if(flags&SDL_INIT_AUDIOIN) + { + SDL_SetError("SDL_INIT_AUDIOIN disabled"); + return(-1); + } +# else + if(flags&SDL_INIT_AUDIOIN) + { + if(!(flags&SDL_INIT_AUDIO)) + { + SDL_SetError("SDL_INIT_AUDIOIN needs SDL_INIT_AUDIO"); + return(-1); + } + SDL_initialized |= SDL_INIT_AUDIOIN; + } +# endif + /* Initialize the audio subsystem */ if ( (flags & SDL_INIT_AUDIO) && !(SDL_initialized & SDL_INIT_AUDIO) ) { if ( SDL_AudioInit(getenv("SDL_AUDIODRIVER")) < 0 ) { + SDL_initialized&=~SDL_INIT_AUDIOIN; return(-1); } SDL_initialized |= SDL_INIT_AUDIO; diff -u -r SDL12/src/audio/SDL_audio.c SDL12-unmod/src/audio/SDL_audio.c --- SDL12/src/audio/SDL_audio.c 2004-11-30 12:52:46.000000000 -0600 +++ SDL12-unmod/src/audio/SDL_audio.c 2005-09-05 16:57:04.000000000 -0600 @@ -120,6 +120,70 @@ static int audio_configured = 0; #endif +/* The general audio input thread function */ +int SDL_RunAudioIn(void *audiop) +{ + SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop; + Uint8 *stream; + int stream_len; + void *udata; + /* shoving is the answer. */ + void (*shove)(void *userdata,Uint8 *stream, int len); + + /* Perform any thread setup */ + /* TODO: Add an InThreadInit */ +/* if ( audio->ThreadInit ) { + audio->ThreadInit(audio); + }*/ + audio->rdthreadid = SDL_ThreadID(); + + /* Set up the mixing function */ + shove = audio->rdcallback; + udata = audio->rduserdata; + + if ( audio->convert.needed ) { + stream_len = audio->rdconv.len; + } else { + stream_len = audio->spec.size; + } + + stream = audio->rdfakestream; + + /* Loop, reading into audio buffers */ + while ( audio->reading ) { + + /* Fill current buffer */ + if ( stream != audio->fake_stream ) { + audio->ReadAudio(audio); + } + + stream = audio->GetReadBuf(audio); + if(stream == NULL) { + stream = audio->rdfakestream; + } + + /* Convert the audio if necessary */ + if ( audio->convert.needed ) { + memcpy(stream, audio->convert.buf, + audio->convert.len_cvt); + SDL_ConvertAudio(&audio->rdconv); + } + + if ( ! audio->readingpaused ) { + SDL_mutexP(audio->rdlock); + (*shove)(udata, stream, stream_len); + SDL_mutexV(audio->rdlock); + } + } + + /* Wait for the audio to drain.. */ + /* TODO: Add an audioin equivalent */ +/* if ( audio->WaitDone ) { + audio->WaitDone(audio); + }*/ + return(0); +} + /* The general mixing thread function */ int SDL_RunAudio(void *audiop) { @@ -252,6 +316,22 @@ return(0); } +static void SDL_LockAudioIn_Default(SDL_AudioDevice *audio) +{ + if ( audio->rdthread && (SDL_ThreadID() == audio->rdthreadid)) { + return; + } + SDL_mutexP(audio->rdlock); +} + +static void SDL_UnlockAudioIn_Default(SDL_AudioDevice *audio) +{ + if ( audio->rdthread && (SDL_ThreadID() == audio->rdthreadid)) { + return; + } + SDL_mutexV(audio->rdlock); +} + static void SDL_LockAudio_Default(SDL_AudioDevice *audio) { if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) { @@ -351,6 +431,12 @@ current_audio->LockAudio = SDL_LockAudio_Default; current_audio->UnlockAudio = SDL_UnlockAudio_Default; } + + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + if ( !current_audio->LockAudioIn && !current_audio->UnlockAudioIn) { + current_audio->LockAudioIn = SDL_LockAudioIn_Default; + current_audio->UnlockAudioIn = SDL_UnlockAudioIn_Default; + } } return(0); } @@ -365,6 +451,51 @@ return(NULL); } +int SDL_OpenAudioIn( + void (SDLCALL *rdcallback)(void *userdata, Uint8 *stream, int len), + void *rduserdata) +{ + SDL_AudioDevice *audio; + + /* Attempt to initialize audio if not already initialized */ + if ( ! current_audio ) { + if ( (SDL_InitSubSystem(SDL_INIT_AUDIO|SDL_INIT_AUDIOIN) < 0) || + (current_audio == NULL) ) { + return(-1); + } + } + + audio = current_audio; + + if (!(audio->opened)) { + SDL_SetError("Audio device not opened"); + return(-1); + } + + if(audio->GetReadBuf == NULL) + { + char buf[10]; + SDL_SetError("Audio input unimplimented for driver \"%s\"", + SDL_AudioDriverName(buf,10)); + return(-1); + } + + audio->rduserdata=rduserdata; + audio->rdcallback=rdcallback; + audio->reading=1; + audio->readingpaused=1; + audio->rdlock=SDL_CreateMutex(); + + audio->rdthread=SDL_CreateThread(SDL_RunAudioIn,audio); + if(audio->rdthread==NULL) + { + audio->reading=0; + return(-1); + } + + return(0); +} + int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained) { SDL_AudioDevice *audio; @@ -423,6 +554,10 @@ audio->convert.needed = 0; audio->enabled = 1; audio->paused = 1; + audio->reading = 0; + audio->readingpaused=1; + audio->rdcallback=NULL; + audio->rduserdata=NULL; #ifndef ENABLE_AHI @@ -465,6 +600,18 @@ return(-1); } + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + { + audio->rdfakestream=SDL_AllocAudioMem(desired->size); +// audio->rdfakesize=desired->size; + if(audio->rdfakestream==NULL) + { + SDL_CloseAudio(); + SDL_OutOfMemory(); + return(-1); + } + } + /* See if we need to do any conversion */ if ( obtained != NULL ) { memcpy(obtained, &audio->spec, sizeof(audio->spec)); @@ -480,6 +627,18 @@ SDL_CloseAudio(); return(-1); } + + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + if(SDL_BuildAudioCVT(&audio->rdconv, + audio->spec.format,audio->spec.channels, + audio->spec.freq, + desired->format,desired->channels, + desired->freq)<0) + { + SDL_CloseAudio(); + return(-1); + } + if ( audio->convert.needed ) { audio->convert.len = desired->size; audio->convert.buf =(Uint8 *)SDL_AllocAudioMem( @@ -489,6 +648,19 @@ SDL_OutOfMemory(); return(-1); } + + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + { + audio->rdconv.len=audio->spec.size; + audio->rdconv.buf=(Uint8 *)SDL_AllocAudioMem( + audio->rdconv.len*audio->rdconv.len_mult); + if( audio->rdconv.buf == NULL) + { + SDL_CloseAudio(); + SDL_OutOfMemory(); + return(-1); + } + } } } @@ -518,6 +690,23 @@ return(0); } +SDL_audiostatus SDL_GetAudioInStatus(void) +{ + SDL_AudioDevice *audio=current_audio; + SDL_audiostatus status; + + status=SDL_AUDIO_STOPPED; + if(audio && audio->reading) + { + if(audio->readingpaused) + status=SDL_AUDIO_PAUSED; + else + status=SDL_AUDIO_PLAYING; + } + + return(status); +} + SDL_audiostatus SDL_GetAudioStatus(void) { SDL_AudioDevice *audio = current_audio; @@ -534,6 +723,15 @@ return(status); } +void SDL_PauseAudioIn(int pause_on) +{ + SDL_AudioDevice *audio = current_audio; + + if ( audio ) { + audio->readingpaused = pause_on; + } +} + void SDL_PauseAudio (int pause_on) { SDL_AudioDevice *audio = current_audio; @@ -543,6 +741,16 @@ } } +void SDL_LockAudioIn (void) +{ + SDL_AudioDevice *audio = current_audio; + + /* Obtain a lock on the input buffers */ + if ( audio && audio->LockAudioIn ) { + audio->LockAudioIn(audio); + } +} + void SDL_LockAudio (void) { SDL_AudioDevice *audio = current_audio; @@ -553,6 +761,16 @@ } } +void SDL_UnlockAudioIn (void) +{ + SDL_AudioDevice *audio = current_audio; + + /* Release lock on the mixing buffers */ + if ( audio && audio->UnlockAudioIn ) { + audio->UnlockAudioIn(audio); + } +} + void SDL_UnlockAudio (void) { SDL_AudioDevice *audio = current_audio; @@ -574,18 +792,31 @@ if ( audio ) { audio->enabled = 0; + audio->reading = 0; + if ( audio->thread != NULL ) { SDL_WaitThread(audio->thread, NULL); } + if ( audio->rdthread != NULL) { + SDL_WaitThread(audio->rdthread,NULL); + } + if ( audio->rdlock != NULL) { + SDL_DestroyMutex(audio->rdlock); + } if ( audio->mixer_lock != NULL ) { SDL_DestroyMutex(audio->mixer_lock); } if ( audio->fake_stream != NULL ) { SDL_FreeAudioMem(audio->fake_stream); } + + if ( audio->rdfakestream != NULL) { + SDL_FreeAudioMem(audio->rdfakestream); + } if ( audio->convert.needed ) { SDL_FreeAudioMem(audio->convert.buf); - + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + SDL_FreeAudioMem(audio->rdconv.buf); } #ifndef ENABLE_AHI if ( audio->opened ) { diff -u -r SDL12/src/audio/SDL_sysaudio.h SDL12-unmod/src/audio/SDL_sysaudio.h --- SDL12/src/audio/SDL_sysaudio.h 2004-11-30 12:52:47.000000000 -0600 +++ SDL12-unmod/src/audio/SDL_sysaudio.h 2005-09-05 16:57:04.000000000 -0600 @@ -58,11 +58,18 @@ void (*WaitDone)(_THIS); void (*CloseAudio)(_THIS); + void (*ReadAudio)(_THIS); + Uint8 *(*GetReadBuf)(_THIS); + /* * * */ /* Lock / Unlock functions added for the Mac port */ void (*LockAudio)(_THIS); void (*UnlockAudio)(_THIS); + /* Lock / Unlock functions for audio input */ + void (*LockAudioIn)(_THIS); + void (*UnlockAudioIn)(_THIS); + /* * * */ /* Data common to all devices */ @@ -77,6 +84,23 @@ int paused; int opened; + /* State flags for audio recording */ + int reading; + int readingpaused; + int rdthreadid; + + /* Audio conversion block, inverse of 'convert' */ + SDL_AudioCVT rdconv; + /* Thread for audio recording */ + SDL_Thread *rdthread; + /* Mutex for audio recording */ + SDL_mutex *rdlock; + /* Internal data for audio recording */ + void (SDLCALL *rdcallback)(void *userdata, Uint8 *stream, int len); + void *rduserdata; + /* Fake audio buffer for when audio input hardware is busy */ + Uint8 *rdfakestream; + /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; diff -u -r SDL12/src/audio/dsp/SDL_dspaudio.c SDL12-unmod/src/audio/dsp/SDL_dspaudio.c --- SDL12/src/audio/dsp/SDL_dspaudio.c 2005-08-28 22:16:30.000000000 -0600 +++ SDL12-unmod/src/audio/dsp/SDL_dspaudio.c 2005-09-05 17:02:37.000000000 -0600 @@ -48,6 +48,7 @@ #include #endif +#include "SDL.h" #include "SDL_audio.h" #include "SDL_error.h" #include "SDL_audiomem.h" @@ -61,6 +62,8 @@ /* Open the audio device for playback, and don't block if busy */ #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) +/* For opening the audio device in R/W mode */ +#define OPEN_AUDIOIN_FLAGS (O_RDWR|O_NONBLOCK) /* Audio driver functions */ static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); @@ -68,16 +71,22 @@ static void DSP_PlayAudio(_THIS); static Uint8 *DSP_GetAudioBuf(_THIS); static void DSP_CloseAudio(_THIS); +static void DSP_ReadAudio(_THIS); +static Uint8 *DSP_GetReadBuf(_THIS); /* Audio driver bootstrap functions */ static int Audio_Available(void) { + int fileflags=OPEN_FLAGS; int fd; int available; + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + fileflags=OPEN_AUDIOIN_FLAGS; + available = 0; - fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); + fd = SDL_OpenAudioPath(NULL, 0, fileflags, 0); if ( fd >= 0 ) { available = 1; close(fd); @@ -118,6 +127,8 @@ this->PlayAudio = DSP_PlayAudio; this->GetAudioBuf = DSP_GetAudioBuf; this->CloseAudio = DSP_CloseAudio; + this->ReadAudio=DSP_ReadAudio; + this->GetReadBuf=DSP_GetReadBuf; this->free = Audio_DeleteDevice; @@ -135,6 +146,18 @@ /* Not needed at all since OSS handles waiting automagically */ } +static void DSP_ReadAudio(_THIS) +{ + if(read(audio_fd, recordbuf, mixlen) <=0) + { + perror("Audio read"); + this->reading=0; + } +#ifdef DEBUG_AUDIO + fprintf(stderr, "Read %d bytes of audio data\n", mixlen); +#endif +} + static void DSP_PlayAudio(_THIS) { if (write(audio_fd, mixbuf, mixlen)==-1) @@ -148,6 +171,11 @@ #endif } +static Uint8 *DSP_GetReadBuf(_THIS) +{ + return(recordbuf); +} + static Uint8 *DSP_GetAudioBuf(_THIS) { return(mixbuf); @@ -159,6 +187,10 @@ SDL_FreeAudioMem(mixbuf); mixbuf = NULL; } + if(recordbuf != NULL) { + SDL_FreeAudioMem(recordbuf); + recordbuf=NULL; + } if ( audio_fd >= 0 ) { close(audio_fd); audio_fd = -1; @@ -171,10 +203,14 @@ int format; int value; int frag_spec; + int fileflags=OPEN_FLAGS; Uint16 test_format; + if(SDL_WasInit(SDL_INIT_AUDIOIN)) + fileflags=OPEN_AUDIOIN_FLAGS; + /* Open the audio device */ - audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); + audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), fileflags, 0); if ( audio_fd < 0 ) { SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); return(-1); @@ -328,6 +364,12 @@ return(-1); } memset(mixbuf, spec->silence, spec->size); + recordbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); + if( recordbuf == NULL) + { + DSP_CloseAudio(this); + return(-1); + } /* Get the parent process id (we're the parent of the audio thread) */ parent = getpid(); diff -u -r SDL12/src/audio/dsp/SDL_dspaudio.h SDL12-unmod/src/audio/dsp/SDL_dspaudio.h --- SDL12/src/audio/dsp/SDL_dspaudio.h 2004-11-30 12:52:47.000000000 -0600 +++ SDL12-unmod/src/audio/dsp/SDL_dspaudio.h 2005-09-05 16:57:04.000000000 -0600 @@ -43,6 +43,7 @@ /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; + Uint8 *recordbuf; }; #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ @@ -53,5 +54,6 @@ #define mixlen (this->hidden->mixlen) #define frame_ticks (this->hidden->frame_ticks) #define next_frame (this->hidden->next_frame) +#define recordbuf (this->hidden->recordbuf) #endif /* _SDL_dspaudio_h */ Only in SDL12-unmod/src/audio/dsp: dspaudio.c.patch