Only in SDL-1.2.3: SDL.spec Only in SDL-1.2.3-record/include: .SDL_audio.h.swp diff -rc --exclude=Makefile SDL-1.2.3/include/SDL_audio.h SDL-1.2.3-record/include/SDL_audio.h *** SDL-1.2.3/include/SDL_audio.h Sun Sep 23 10:39:30 2001 --- SDL-1.2.3-record/include/SDL_audio.h Thu Apr 4 17:52:10 2002 *************** *** 60,65 **** --- 60,73 ---- Stereo samples are stored in a LRLRLR ordering. */ void (*callback)(void *userdata, Uint8 *stream, int len); + /* This function is called when the audio device has a chunk of + recorded data to provide. + 'stream' is a pointer to the recorded audio data buffer + 'len' is the length of that buffer in bytes. + Once the callback returns, the buffer will no longer be valid. + Stereo samples are stored in a LRLRLR ordering. + */ + void (*callback_record)(void* userdata, Uint8 *stream, int len); void *userdata; } SDL_AudioSpec; diff -rc --exclude=Makefile SDL-1.2.3/src/audio/SDL_audio.c SDL-1.2.3-record/src/audio/SDL_audio.c *** SDL-1.2.3/src/audio/SDL_audio.c Thu Aug 9 06:09:47 2001 --- SDL-1.2.3-record/src/audio/SDL_audio.c Tue Apr 9 17:00:16 2002 *************** *** 103,112 **** --- 103,116 ---- { SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop; Uint8 *stream; + Uint8 *stream_record; int stream_len; + int stream_record_len; void *udata; void (*fill)(void *userdata,Uint8 *stream, int len); + void (*empty)(void *userdata,Uint8 *stream, int len); int silence; + int silence_record; #ifdef ENABLE_AHI int started = 0; *************** *** 131,136 **** --- 135,141 ---- /* Set up the mixing function */ fill = audio->spec.callback; + empty = audio->spec.callback_record; udata = audio->spec.userdata; #ifdef ENABLE_AHI *************** *** 154,159 **** --- 159,177 ---- } stream = audio->fake_stream; + if ( audio->convert_record.needed ) { + if ( audio->convert_record.src_format == AUDIO_U8 ) { + silence_record = 0x80; + } else { + silence_record = 0; + } + stream_record_len = audio->convert_record.len; + } else { + silence_record = audio->spec.silence; + stream_record_len = audio->spec.size; + } + stream_record = audio->fake_stream; + #ifdef ENABLE_AHI SDL_mutexV(audio->mixer_lock); D(bug("Entering audio loop...\n")); *************** *** 162,217 **** /* Loop, filling the audio buffers */ while ( audio->enabled ) { ! ! /* Wait for new current buffer to finish playing */ ! if ( stream == audio->fake_stream ) { ! SDL_Delay((audio->spec.samples*1000)/audio->spec.freq); ! } else { #ifdef ENABLE_AHI ! if ( started > 1 ) #endif ! audio->WaitAudio(audio); ! } ! /* Fill the current buffer with sound */ ! if ( audio->convert.needed ) { ! if ( audio->convert.buf ) { ! stream = audio->convert.buf; } else { ! continue; } ! } else { ! stream = audio->GetAudioBuf(audio); ! if ( stream == NULL ) { ! stream = audio->fake_stream; } - } - memset(stream, silence, stream_len); ! if ( ! audio->paused ) { ! SDL_mutexP(audio->mixer_lock); ! (*fill)(udata, stream, stream_len); ! SDL_mutexV(audio->mixer_lock); ! } ! /* Convert the audio if necessary */ ! if ( audio->convert.needed ) { ! SDL_ConvertAudio(&audio->convert); ! stream = audio->GetAudioBuf(audio); ! if ( stream == NULL ) { ! stream = audio->fake_stream; ! } ! memcpy(stream, audio->convert.buf, ! audio->convert.len_cvt); } ! /* Ready current buffer for play and change current buffer */ ! if ( stream != audio->fake_stream ) { ! audio->PlayAudio(audio); #ifdef ENABLE_AHI ! /* AmigaOS don't have to wait the first time audio is played! */ ! started++; #endif } } /* Wait for the audio to drain.. */ --- 180,288 ---- /* Loop, filling the audio buffers */ while ( audio->enabled ) { ! /* If there is a callback for filling the playback buffer */ ! if (fill) { ! /* Wait for new current buffer to finish playing */ ! if ( stream == audio->fake_stream ) { ! SDL_Delay((audio->spec.samples*1000)/audio->spec.freq); ! } else { #ifdef ENABLE_AHI ! if ( started > 1 ) #endif ! audio->WaitAudio(audio); ! } ! /* Fill the current buffer with sound */ ! if ( audio->convert.needed ) { ! if ( audio->convert.buf ) { ! stream = audio->convert.buf; ! } else { ! continue; ! } } else { ! stream = audio->GetAudioBuf(audio); ! if ( stream == NULL ) { ! stream = audio->fake_stream; ! } } ! memset(stream, silence, stream_len); ! ! if ( ! audio->paused ) { ! SDL_mutexP(audio->mixer_lock); ! (*fill)(udata, stream, stream_len); ! SDL_mutexV(audio->mixer_lock); } ! /* Convert the audio if necessary */ ! if ( audio->convert.needed ) { ! SDL_ConvertAudio(&audio->convert); ! stream = audio->GetAudioBuf(audio); ! if ( stream == NULL ) { ! stream = audio->fake_stream; ! } ! memcpy(stream, audio->convert.buf, ! audio->convert.len_cvt); ! } ! /* Ready current buffer for play and change current buffer */ ! if ( stream != audio->fake_stream ) { ! audio->PlayAudio(audio); ! #ifdef ENABLE_AHI ! /* AmigaOS don't have to wait the first time audio is played! */ ! started++; ! #endif ! } } ! /* If there is a callback for emptying the record buffer */ ! if (empty) { ! /* Wait for new current buffer to finish playing */ ! if ( stream_record == audio->fake_stream ) { ! SDL_Delay((audio->spec.samples*1000)/audio->spec.freq); ! } else { #ifdef ENABLE_AHI ! if ( started > 1 ) #endif + audio->WaitAudioRecord(audio); + } + + /* Clear the current record buffer */ + if ( audio->convert_record.needed ) { + if ( audio->convert_record.buf ) { + stream = audio->convert_record.buf; + } else { + continue; + } + } else { + stream_record = audio->GetAudioRecordBuf(audio); + if ( stream_record == NULL ) { + stream_record = audio->fake_stream; + } + } + memset(stream_record, silence_record, stream_record_len); + + /* Ready current buffer for record and change current buffer */ + if ( stream_record != audio->fake_stream ) { + audio->RecordAudio(audio); + } + + /* Convert the audio if necessary */ + if ( audio->convert_record.needed ) { + SDL_ConvertAudio(&audio->convert_record); + stream_record = audio->GetAudioRecordBuf(audio); + if ( stream_record == NULL ) { + stream_record = audio->fake_stream; + } + memcpy(stream_record, audio->convert_record.buf, + audio->convert_record.len_cvt); + } + + /* Recorded sound is now available for use */ + if ( ! audio->paused ) { + SDL_mutexP(audio->mixer_lock); + (*empty)(udata, stream_record, stream_record_len); + SDL_mutexV(audio->mixer_lock); + } } } /* Wait for the audio to drain.. */ *************** *** 337,344 **** audio = current_audio; /* Verify some parameters */ ! if ( desired->callback == NULL ) { ! SDL_SetError("SDL_OpenAudio() passed a NULL callback"); return(-1); } switch ( desired->channels ) { --- 408,415 ---- audio = current_audio; /* Verify some parameters */ ! if ( desired->callback == NULL && desired->callback_record == NULL) { ! SDL_SetError("SDL_OpenAudio() passed NULL callbacks"); return(-1); } switch ( desired->channels ) { *************** *** 368,373 **** --- 439,445 ---- /* Open the audio subsystem */ memcpy(&audio->spec, desired, sizeof(audio->spec)); audio->convert.needed = 0; + audio->convert_record.needed = 0; audio->enabled = 1; audio->paused = 1; *************** *** 423,429 **** if ( obtained != NULL ) { memcpy(obtained, &audio->spec, sizeof(audio->spec)); } else { ! /* Build an audio conversion block */ if ( SDL_BuildAudioCVT(&audio->convert, desired->format, desired->channels, desired->freq, --- 495,501 ---- if ( obtained != NULL ) { memcpy(obtained, &audio->spec, sizeof(audio->spec)); } else { ! /* Build an audio conversion block for playback */ if ( SDL_BuildAudioCVT(&audio->convert, desired->format, desired->channels, desired->freq, *************** *** 442,447 **** --- 514,541 ---- return(-1); } } + + /* Build an audio conversion block for recording */ + if ( SDL_BuildAudioCVT(&audio->convert_record, + audio->spec.format, audio->spec.channels, + audio->spec.freq, + desired->format, desired->channels, + desired->freq) < 0 ) { + SDL_CloseAudio(); + return(-1); + } + if ( audio->convert_record.needed ) { + audio->convert_record.len = audio->spec.size; + audio->convert_record.buf = + (Uint8 *)SDL_AllocAudioMem( + audio->convert_record.len * + audio->convert_record.len_mult); + if ( audio->convert_record.buf == NULL ) { + SDL_CloseAudio(); + SDL_OutOfMemory(); + return(-1); + } + } } } *************** *** 544,550 **** } if ( audio->convert.needed ) { SDL_FreeAudioMem(audio->convert.buf); ! } #ifndef ENABLE_AHI if ( audio->opened ) { --- 638,646 ---- } if ( audio->convert.needed ) { SDL_FreeAudioMem(audio->convert.buf); ! } ! if ( audio->convert_record.needed ) { ! SDL_FreeAudioMem(audio->convert_record.buf); } #ifndef ENABLE_AHI if ( audio->opened ) { diff -rc --exclude=Makefile SDL-1.2.3/src/audio/SDL_sysaudio.h SDL-1.2.3-record/src/audio/SDL_sysaudio.h *** SDL-1.2.3/src/audio/SDL_sysaudio.h Thu Aug 9 06:09:47 2001 --- SDL-1.2.3-record/src/audio/SDL_sysaudio.h Tue Apr 9 16:13:28 2002 *************** *** 53,60 **** --- 53,63 ---- int (*OpenAudio)(_THIS, SDL_AudioSpec *spec); void (*ThreadInit)(_THIS); /* Called by audio thread at start */ void (*WaitAudio)(_THIS); + void (*WaitAudioRecord)(_THIS); void (*PlayAudio)(_THIS); + void (*RecordAudio)(_THIS); Uint8 *(*GetAudioBuf)(_THIS); + Uint8 *(*GetAudioRecordBuf)(_THIS); void (*WaitDone)(_THIS); void (*CloseAudio)(_THIS); *************** *** 66,71 **** --- 69,75 ---- /* An audio conversion block for audio format emulation */ SDL_AudioCVT convert; + SDL_AudioCVT convert_record; /* Current state flags */ int enabled; diff -rc --exclude=Makefile SDL-1.2.3/src/audio/dsp/SDL_dspaudio.c SDL-1.2.3-record/src/audio/dsp/SDL_dspaudio.c *** SDL-1.2.3/src/audio/dsp/SDL_dspaudio.c Mon Jul 9 08:47:40 2001 --- SDL-1.2.3-record/src/audio/dsp/SDL_dspaudio.c Thu Apr 4 17:52:10 2002 *************** *** 56,70 **** /* The tag name used by DSP audio */ #define DSP_DRIVER_NAME "dsp" ! /* Open the audio device for playback, and don't block if busy */ /*#define USE_BLOCKING_WRITES*/ ! #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) /* Audio driver functions */ static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); static void DSP_WaitAudio(_THIS); static void DSP_PlayAudio(_THIS); static Uint8 *DSP_GetAudioBuf(_THIS); static void DSP_CloseAudio(_THIS); /* Audio driver bootstrap functions */ --- 56,73 ---- /* The tag name used by DSP audio */ #define DSP_DRIVER_NAME "dsp" ! /* Don't block the audio device if busy */ /*#define USE_BLOCKING_WRITES*/ ! #define OPEN_FLAGS (O_NONBLOCK) /* Audio driver functions */ static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec); static void DSP_WaitAudio(_THIS); + static void DSP_WaitAudioRecord(_THIS); static void DSP_PlayAudio(_THIS); + static void DSP_RecordAudio(_THIS); static Uint8 *DSP_GetAudioBuf(_THIS); + static Uint8 *DSP_GetAudioRecordBuf(_THIS); static void DSP_CloseAudio(_THIS); /* Audio driver bootstrap functions */ *************** *** 75,81 **** int available; available = 0; ! fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); if ( fd >= 0 ) { available = 1; close(fd); --- 78,84 ---- int available; available = 0; ! fd = SDL_OpenAudioPath(NULL, 0, O_WRONLY | OPEN_FLAGS, 0); if ( fd >= 0 ) { available = 1; close(fd); *************** *** 113,120 **** --- 116,126 ---- /* Set the function pointers */ this->OpenAudio = DSP_OpenAudio; this->WaitAudio = DSP_WaitAudio; + this->WaitAudioRecord = DSP_WaitAudioRecord; this->PlayAudio = DSP_PlayAudio; + this->RecordAudio = DSP_RecordAudio; this->GetAudioBuf = DSP_GetAudioBuf; + this->GetAudioRecordBuf = DSP_GetAudioRecordBuf; this->CloseAudio = DSP_CloseAudio; this->free = Audio_DeleteDevice; *************** *** 186,191 **** --- 192,287 ---- #endif /* !USE_BLOCKING_WRITES */ } + /* This function waits until it is possible to read a full sound buffer */ + static void DSP_WaitAudioRecord(_THIS) + { + /* Check to see if the thread-parent process is still alive */ + { static int cnt = 0; + /* Note that this only works with thread implementations + that use a different process id for each thread. + */ + if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */ + if ( kill(parent, 0) < 0 ) { + this->enabled = 0; + } + } + } + + #ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */ + /* See if we need to use timed audio synchronization */ + if ( frame_ticks ) { + /* Use timer for general audio synchronization */ + Sint32 ticks; + + ticks = ((Sint32)(next_record_frame - SDL_GetTicks()))-FUDGE_TICKS; + if ( ticks > 0 ) { + SDL_Delay(ticks); + } + } else { + /* Use select() for audio synchronization */ + fd_set fdset; + struct timeval timeout; + + FD_ZERO(&fdset); + FD_SET(audio_fd, &fdset); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + #ifdef DEBUG_AUDIO + fprintf(stderr, "Waiting for audio to get ready\n"); + #endif + if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) { + const char *message = + "Audio timeout - buggy audio driver? (disabled)"; + /* In general we should never print to the screen, + but in this case we have no other way of letting + the user know what happened. + */ + fprintf(stderr, "SDL: %s\n", message); + this->enabled = 0; + /* Don't try to close - may hang */ + audio_fd = -1; + #ifdef DEBUG_AUDIO + fprintf(stderr, "Done disabling audio\n"); + #endif + } + #ifdef DEBUG_AUDIO + fprintf(stderr, "Ready!\n"); + #endif + } + #endif /* !USE_BLOCKING_WRITES */ + } + + static void DSP_RecordAudio(_THIS) + { + int read_size, p=0; + + /* Read the audio data, checking for EAGAIN on broken audio drivers */ + do { + read_size = read(audio_fd, &mixbuf_record[p], mixlen_record-p); + if (read_size>0) + p += read_size; + if (read_size == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) + { + /* Non recoverable error has occurred. It should be reported!!! */ + perror("audio"); + break; + } + + if ( p < read_size || ((read_size < 0) && ((errno == 0) || (errno == EAGAIN))) ) { + SDL_Delay(1); /* Let a little CPU time go by */ + } + } while ( p < read_size ); + + /* If timer synchronization is enabled, set the next read frame */ + if ( frame_ticks ) { + next_record_frame += frame_ticks; + } + + #ifdef DEBUG_AUDIO + fprintf(stderr, "Read %d bytes of audio data\n", read_size); + #endif + } + static void DSP_PlayAudio(_THIS) { int written, p=0; *************** *** 226,237 **** --- 322,342 ---- return(mixbuf); } + static Uint8 *DSP_GetAudioRecordBuf(_THIS) + { + return(mixbuf_record); + } + static void DSP_CloseAudio(_THIS) { if ( mixbuf != NULL ) { SDL_FreeAudioMem(mixbuf); mixbuf = NULL; } + if ( mixbuf_record != NULL ) { + SDL_FreeAudioMem(mixbuf_record); + mixbuf_record = NULL; + } if ( audio_fd >= 0 ) { close(audio_fd); audio_fd = -1; *************** *** 243,252 **** { int frag_spec; int value; /* Close and then reopen the audio device */ close(audio_fd); ! audio_fd = open(audiodev, O_WRONLY, 0); if ( audio_fd < 0 ) { SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); return(-1); --- 348,367 ---- { int frag_spec; int value; + int open_flags = OPEN_FLAGS; + + /* Determine the proper file open flags */ + if (spec->callback && spec->callback_record) { + open_flags |= O_RDWR; + } else if (spec->callback) { + open_flags |= O_WRONLY; + } else if (spec->callback_record) { + open_flags |= O_RDONLY; + } /* Close and then reopen the audio device */ close(audio_fd); ! audio_fd = open(audiodev, open_flags, 0); if ( audio_fd < 0 ) { SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); return(-1); *************** *** 274,283 **** #ifdef DEBUG_AUDIO { audio_buf_info info; ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); ! fprintf(stderr, "fragments = %d\n", info.fragments); ! fprintf(stderr, "fragstotal = %d\n", info.fragstotal); ! fprintf(stderr, "fragsize = %d\n", info.fragsize); ! fprintf(stderr, "bytes = %d\n", info.bytes); } #endif --- 389,405 ---- #ifdef DEBUG_AUDIO { audio_buf_info info; ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info); ! fprintf(stderr, "playback fragments = %d\n", info.fragments); ! fprintf(stderr, "playback fragstotal = %d\n", info.fragstotal); ! fprintf(stderr, "playback fragsize = %d\n", info.fragsize); ! fprintf(stderr, "playback bytes = %d\n", info.bytes); ! } ! { audio_buf_info info; ! ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info); ! fprintf(stderr, "record fragments = %d\n", info.fragments); ! fprintf(stderr, "record fragstotal = %d\n", info.fragstotal); ! fprintf(stderr, "record fragsize = %d\n", info.fragsize); ! fprintf(stderr, "record bytes = %d\n", info.bytes); } #endif *************** *** 323,339 **** int format; int value; Uint16 test_format; /* Reset the timer synchronization flag */ frame_ticks = 0.0; /* Open the audio device */ ! audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); if ( audio_fd < 0 ) { SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); return(-1); } mixbuf = NULL; #ifdef USE_BLOCKING_WRITES /* Make the file descriptor use blocking writes with fcntl() */ --- 445,472 ---- int format; int value; Uint16 test_format; + int open_flags = OPEN_FLAGS; /* Reset the timer synchronization flag */ frame_ticks = 0.0; + /* Determine the proper file open flags */ + if (spec->callback && spec->callback_record) { + open_flags |= O_RDWR; + } else if (spec->callback) { + open_flags |= O_WRONLY; + } else if (spec->callback_record) { + open_flags |= O_RDONLY; + } + /* Open the audio device */ ! audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), open_flags, 0); if ( audio_fd < 0 ) { SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); return(-1); } mixbuf = NULL; + mixbuf_record = NULL; #ifdef USE_BLOCKING_WRITES /* Make the file descriptor use blocking writes with fcntl() */ *************** *** 434,446 **** return(-1); } ! /* Allocate mixing buffer */ ! mixlen = spec->size; ! mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); ! if ( mixbuf == NULL ) { ! return(-1); } ! memset(mixbuf, spec->silence, spec->size); #ifndef USE_BLOCKING_WRITES /* Check to see if we need to use select() workaround */ --- 567,589 ---- return(-1); } ! /* Allocate mixing buffers */ ! if (spec->callback) { ! mixlen = spec->size; ! mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); ! if ( mixbuf == NULL ) { ! return(-1); ! } ! memset(mixbuf, spec->silence, spec->size); } ! if (spec->callback_record) { ! mixlen_record = spec->size; ! mixbuf_record = (Uint8 *)SDL_AllocAudioMem(mixlen_record); ! if ( mixbuf_record == NULL ) { ! return(-1); ! } ! memset(mixbuf_record, spec->silence, spec->size); ! } #ifndef USE_BLOCKING_WRITES /* Check to see if we need to use select() workaround */ *************** *** 449,454 **** --- 592,598 ---- if ( workaround ) { frame_ticks = (float)(spec->samples*1000)/spec->freq; next_frame = SDL_GetTicks()+frame_ticks; + next_record_frame = SDL_GetTicks()+frame_ticks; } } #endif /* !USE_BLOCKING_WRITES */ diff -rc --exclude=Makefile SDL-1.2.3/src/audio/dsp/SDL_dspaudio.h SDL-1.2.3-record/src/audio/dsp/SDL_dspaudio.h *** SDL-1.2.3/src/audio/dsp/SDL_dspaudio.h Thu Apr 26 09:50:17 2001 --- SDL-1.2.3-record/src/audio/dsp/SDL_dspaudio.h Thu Apr 4 17:52:10 2002 *************** *** 40,52 **** /* The parent process id, to detect when application quits */ pid_t parent; ! /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; /* Support for audio timing using a timer, in addition to select() */ float frame_ticks; float next_frame; }; #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ --- 40,57 ---- /* The parent process id, to detect when application quits */ pid_t parent; ! /* Raw mixing buffer for playback */ Uint8 *mixbuf; int mixlen; + /* Raw mixing buffer for recording */ + Uint8 *mixbuf_record; + int mixlen_record; + /* Support for audio timing using a timer, in addition to select() */ float frame_ticks; float next_frame; + float next_record_frame; }; #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ *************** *** 55,61 **** --- 60,69 ---- #define parent (this->hidden->parent) #define mixbuf (this->hidden->mixbuf) #define mixlen (this->hidden->mixlen) + #define mixbuf_record (this->hidden->mixbuf_record) + #define mixlen_record (this->hidden->mixlen_record) #define frame_ticks (this->hidden->frame_ticks) #define next_frame (this->hidden->next_frame) + #define next_record_frame (this->hidden->next_record_frame) #endif /* _SDL_dspaudio_h */