From 9dd8477a21ec768d5dd7b3f9c2521d407b5ca6fc Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:57:41 -0400 Subject: [PATCH] bsdaudio: first shot at audio capture support! (untested, uncompiled...for now.) --- src/audio/bsd/SDL_bsdaudio.c | 137 +++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 37 deletions(-) diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index 07fd7fadc..d55a9d3c3 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -63,13 +63,17 @@ BSDAUDIO_Status(_THIS) #ifdef DEBUG_AUDIO /* *INDENT-OFF* */ audio_info_t info; + const audio_prinfo *prinfo; if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { fprintf(stderr, "AUDIO_GETINFO failed.\n"); return; } + + prinfo = this->iscapture ? &info.play : &info.record; + fprintf(stderr, "\n" - "[play/record info]\n" + "[%s info]\n" "buffer size : %d bytes\n" "sample rate : %i Hz\n" "channels : %i\n" @@ -83,18 +87,19 @@ BSDAUDIO_Status(_THIS) "waiting : %s\n" "active : %s\n" "", - info.play.buffer_size, - info.play.sample_rate, - info.play.channels, - info.play.precision, - info.play.encoding, - info.play.seek, - info.play.samples, - info.play.eof, - info.play.pause ? "yes" : "no", - info.play.error ? "yes" : "no", - info.play.waiting ? "yes" : "no", - info.play.active ? "yes" : "no"); + this->iscapture ? "record" : "play", + prinfo->buffer_size, + prinfo->sample_rate, + prinfo->channels, + prinfo->precision, + prinfo->encoding, + prinfo->seek, + prinfo->samples, + prinfo->eof, + prinfo->pause ? "yes" : "no", + prinfo->error ? "yes" : "no", + prinfo->waiting ? "yes" : "no", + prinfo->active ? "yes" : "no"); fprintf(stderr, "\n" "[audio info]\n" @@ -209,6 +214,57 @@ BSDAUDIO_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } + +static int +BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen) +{ + Uint8 *buffer = (Uint8 *) _buffer; + int br, p = 0; + + /* Write the audio data, checking for EAGAIN on broken audio drivers */ + do { + br = read(this->hidden->audio_fd, buffer + p, buflen - p); + if (br > 0) + p += br; + if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) { + /* Non recoverable error has occurred. It should be reported!!! */ + perror("audio"); + return p ? p : -1; + } + +#ifdef DEBUG_AUDIO + fprintf(stderr, "Captured %d bytes of audio data\n", br); +#endif + + if (p < buflen + || ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) { + SDL_Delay(1); /* Let a little CPU time go by */ + } + } while (p < buflen); +} + +static void +BSDAUDIO_FlushCapture(_THIS) +{ + audio_info_t info; + size_t remain; + Uint8 buf[512]; + + if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { + return; /* oh well. */ + } + + remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8)); + while (remain > 0) { + const size_t len = SDL_min(sizeof (buf), remain); + const int br = read(this->hidden->audio_fd, buf, len); + if (br <= 0) { + return; /* oh well. */ + } + remain -= br; + } +} + static void BSDAUDIO_CloseDevice(_THIS) { @@ -227,9 +283,10 @@ BSDAUDIO_CloseDevice(_THIS) static int BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { - const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT; SDL_AudioFormat format = 0; audio_info_t info; + audio_prinfo *prinfo = iscapture ? &info.play : &info.record; /* We don't care what the devname is...we'll try to open anything. */ /* ...but default to first name in the list... */ @@ -260,7 +317,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Set to play mode */ - info.mode = AUMODE_PLAY; + info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) { BSDAUDIO_CloseDevice(this); return SDL_SetError("Couldn't put device into play mode"); @@ -271,28 +328,28 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) format; format = SDL_NextAudioFormat()) { switch (format) { case AUDIO_U8: - info.play.encoding = AUDIO_ENCODING_ULINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_ULINEAR; + prinfo->precision = 8; break; case AUDIO_S8: - info.play.encoding = AUDIO_ENCODING_SLINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_SLINEAR; + prinfo->precision = 8; break; case AUDIO_S16LSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; + prinfo->precision = 16; break; case AUDIO_S16MSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; + prinfo->precision = 16; break; case AUDIO_U16LSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE; + prinfo->precision = 16; break; case AUDIO_U16MSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE; + prinfo->precision = 16; break; default: continue; @@ -311,26 +368,29 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.format = format; AUDIO_INITINFO(&info); - info.play.channels = this->spec.channels; + prinfo->channels = this->spec.channels; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) { this->spec.channels = 1; } AUDIO_INITINFO(&info); - info.play.sample_rate = this->spec.freq; + prinfo->sample_rate = this->spec.freq; info.blocksize = this->spec.size; info.hiwat = 5; info.lowat = 3; (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info); - this->spec.freq = info.play.sample_rate; - /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - BSDAUDIO_CloseDevice(this); - return SDL_OutOfMemory(); + this->spec.freq = prinfo->sample_rate; + + if (!iscapture) { + /* Allocate mixing buffer */ + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + BSDAUDIO_CloseDevice(this); + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); BSDAUDIO_Status(this); @@ -348,7 +408,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = BSDAUDIO_WaitDevice; impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->CloseDevice = BSDAUDIO_CloseDevice; + impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice; + impl->FlushCapture = BSDAUDIO_FlushCapture; + impl->HasCaptureSupport = SDL_TRUE; impl->AllowsArbitraryDeviceNames = 1; return 1; /* this audio target is available. */