bsdaudio: first shot at audio capture support!

(untested, uncompiled...for now.)
This commit is contained in:
Ryan C. Gordon 2016-08-03 01:57:41 -04:00
parent d30a2f5ad8
commit 9dd8477a21
1 changed files with 100 additions and 37 deletions

View File

@ -63,13 +63,17 @@ BSDAUDIO_Status(_THIS)
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
/* *INDENT-OFF* */ /* *INDENT-OFF* */
audio_info_t info; audio_info_t info;
const audio_prinfo *prinfo;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n"); fprintf(stderr, "AUDIO_GETINFO failed.\n");
return; return;
} }
prinfo = this->iscapture ? &info.play : &info.record;
fprintf(stderr, "\n" fprintf(stderr, "\n"
"[play/record info]\n" "[%s info]\n"
"buffer size : %d bytes\n" "buffer size : %d bytes\n"
"sample rate : %i Hz\n" "sample rate : %i Hz\n"
"channels : %i\n" "channels : %i\n"
@ -83,18 +87,19 @@ BSDAUDIO_Status(_THIS)
"waiting : %s\n" "waiting : %s\n"
"active : %s\n" "active : %s\n"
"", "",
info.play.buffer_size, this->iscapture ? "record" : "play",
info.play.sample_rate, prinfo->buffer_size,
info.play.channels, prinfo->sample_rate,
info.play.precision, prinfo->channels,
info.play.encoding, prinfo->precision,
info.play.seek, prinfo->encoding,
info.play.samples, prinfo->seek,
info.play.eof, prinfo->samples,
info.play.pause ? "yes" : "no", prinfo->eof,
info.play.error ? "yes" : "no", prinfo->pause ? "yes" : "no",
info.play.waiting ? "yes" : "no", prinfo->error ? "yes" : "no",
info.play.active ? "yes" : "no"); prinfo->waiting ? "yes" : "no",
prinfo->active ? "yes" : "no");
fprintf(stderr, "\n" fprintf(stderr, "\n"
"[audio info]\n" "[audio info]\n"
@ -209,6 +214,57 @@ BSDAUDIO_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf); 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 static void
BSDAUDIO_CloseDevice(_THIS) BSDAUDIO_CloseDevice(_THIS)
{ {
@ -227,9 +283,10 @@ BSDAUDIO_CloseDevice(_THIS)
static int static int
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 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; SDL_AudioFormat format = 0;
audio_info_t info; 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. */ /* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */ /* ...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); SDL_CalculateAudioSpec(&this->spec);
/* Set to play mode */ /* 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) { if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
BSDAUDIO_CloseDevice(this); BSDAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't put device into play mode"); 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()) { format; format = SDL_NextAudioFormat()) {
switch (format) { switch (format) {
case AUDIO_U8: case AUDIO_U8:
info.play.encoding = AUDIO_ENCODING_ULINEAR; prinfo->encoding = AUDIO_ENCODING_ULINEAR;
info.play.precision = 8; prinfo->precision = 8;
break; break;
case AUDIO_S8: case AUDIO_S8:
info.play.encoding = AUDIO_ENCODING_SLINEAR; prinfo->encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = 8; prinfo->precision = 8;
break; break;
case AUDIO_S16LSB: case AUDIO_S16LSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
info.play.precision = 16; prinfo->precision = 16;
break; break;
case AUDIO_S16MSB: case AUDIO_S16MSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE; prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
info.play.precision = 16; prinfo->precision = 16;
break; break;
case AUDIO_U16LSB: case AUDIO_U16LSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE; prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
info.play.precision = 16; prinfo->precision = 16;
break; break;
case AUDIO_U16MSB: case AUDIO_U16MSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE; prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
info.play.precision = 16; prinfo->precision = 16;
break; break;
default: default:
continue; continue;
@ -311,26 +368,29 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.format = format; this->spec.format = format;
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
info.play.channels = this->spec.channels; prinfo->channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) { if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1; this->spec.channels = 1;
} }
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
info.play.sample_rate = this->spec.freq; prinfo->sample_rate = this->spec.freq;
info.blocksize = this->spec.size; info.blocksize = this->spec.size;
info.hiwat = 5; info.hiwat = 5;
info.lowat = 3; info.lowat = 3;
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
this->spec.freq = info.play.sample_rate; this->spec.freq = prinfo->sample_rate;
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size; if (!iscapture) {
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); /* Allocate mixing buffer */
if (this->hidden->mixbuf == NULL) { this->hidden->mixlen = this->spec.size;
BSDAUDIO_CloseDevice(this); this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
return SDL_OutOfMemory(); 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); BSDAUDIO_Status(this);
@ -348,7 +408,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = BSDAUDIO_WaitDevice; impl->WaitDevice = BSDAUDIO_WaitDevice;
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice; impl->CloseDevice = BSDAUDIO_CloseDevice;
impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice;
impl->FlushCapture = BSDAUDIO_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
impl->AllowsArbitraryDeviceNames = 1; impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */ return 1; /* this audio target is available. */