Add stdout audio for Windows

This commit is contained in:
ars-ka0s 2023-01-17 18:06:22 -06:00
parent f1fcb8cd95
commit 6ac840ca4d
2 changed files with 185 additions and 80 deletions

View File

@ -134,7 +134,7 @@ static int calcbufsize(int rate, int chans, int bits)
static struct adev_s {
enum audio_in_type_e g_audio_in_type;
enum audio_out_type_e g_audio_out_type;
/*
* UDP socket for receiving audio stream.
* Buffer, length, and pointer for UDP or stdin.
@ -146,6 +146,12 @@ static struct adev_s {
int stream_len;
int stream_next;
/*
* Buffer and index for stdout.
*/
unsigned char stream_out_data[SDR_UDP_BUF_MAXLEN];
int stream_out_next;
/* For sound output. */
/* out_wavehdr.dwUser is used to keep track of output buffer state. */
@ -343,9 +349,16 @@ int audio_open (struct audio_s *pa)
/*
* Select output device.
* Only soundcard at this point.
* Only soundcard and stdout at this point.
* Purhaps we'd like to add UDP for an SDR transmitter.
*/
if (strcasecmp(pa->adev[a].adevice_out, "stdout") == 0 || strcmp(pa->adev[a].adevice_out, "-") == 0) {
A->g_audio_out_type = AUDIO_OUT_TYPE_STDOUT;
/* Change - to stdout for readability. */
strlcpy (pa->adev[a].adevice_out, "stdout", sizeof(pa->adev[a].adevice_out));
} else {
A->g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD;
if (strlen(pa->adev[a].adevice_out) == 1 && isdigit(pa->adev[a].adevice_out[0])) {
out_dev_no[a] = atoi(pa->adev[a].adevice_out);
}
@ -367,6 +380,7 @@ int audio_open (struct audio_s *pa)
dw_printf ("\"%s\" doesn't match any of the output devices.\n", pa->adev[a].adevice_out);
}
}
}
} /* if defined */
} /* for each device */
@ -498,6 +512,36 @@ int audio_open (struct audio_s *pa)
}
}
// Add UDP or stdout to end of device list if used.
for (a=0; a<MAX_ADEVS; a++) {
if (pa->adev[a].defined) {
struct adev_s *A = &(adev[a]);
/* Display stdin or udp:port if appropriate. */
if (A->g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD) {
int aaa;
for (aaa=0; aaa<MAX_ADEVS; aaa++) {
if (pa->adev[aaa].defined) {
dw_printf (" %c", a == aaa ? '*' : ' ');
}
}
dw_printf (" %s ", pa->adev[a].adevice_out); /* should be UDP:nnnn or stdout */
if (pa->adev[a].num_channels == 2) {
dw_printf (" (channels %d & %d)", ADEVFIRSTCHAN(a), ADEVFIRSTCHAN(a)+1);
}
else {
dw_printf (" (channel %d)", ADEVFIRSTCHAN(a));
}
dw_printf ("\n");
}
}
}
/*
* Open for each audio device input/output pair.
@ -523,17 +567,20 @@ int audio_open (struct audio_s *pa)
/*
* Open the audio output device.
* Soundcard is only possibility at this time.
* Soundcard and stdout are only possibility at this time.
*/
switch (A->g_audio_out_type) {
case AUDIO_OUT_TYPE_SOUNDCARD:
err = waveOutOpen (&(A->audio_out_handle), out_dev_no[a], &wf, (DWORD_PTR)out_callback, a, CALLBACK_FUNCTION);
if (err != MMSYSERR_NOERROR) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Could not open audio device for output.\n");
return (-1);
}
break;
/*
* Set up the output buffers.
* We use dwUser to indicate it is available for filling.
@ -548,6 +595,18 @@ int audio_open (struct audio_s *pa)
}
A->out_current = 0;
case AUDIO_OUT_TYPE_STDOUT:
setmode (STDOUT_FILENO, _O_BINARY);
A->stream_out_next= 0;
break;
default:
text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error, invalid audio_out_type\n");
return (-1);
}
/*
* Open audio input device.
@ -943,6 +1002,10 @@ int audio_put (int a, int c)
struct adev_s *A;
A = &(adev[a]);
switch (A->g_audio_out_type) {
case AUDIO_OUT_TYPE_SOUNDCARD:
/*
* Wait if no buffers are available.
* Don't use p yet because compiler might might consider dwFlags a loop invariant.
@ -986,6 +1049,20 @@ int audio_put (int a, int c)
if (p->dwBufferLength == (DWORD)(A->outbuf_size)) {
return (audio_flush(a));
}
break;
case AUDIO_OUT_TYPE_STDOUT:
A->stream_out_data[A->stream_out_next++] = c;
assert(A->stream_out_next > 0);
assert(A->stream_out_next <= SDR_UDP_BUF_MAXLEN);
if (A->stream_out_next == SDR_UDP_BUF_MAXLEN) {
return (audio_flush(a));
}
break;
}
return (0);
@ -1016,6 +1093,8 @@ int audio_flush (int a)
A = &(adev[a]);
switch (A->g_audio_out_type) {
case AUDIO_OUT_TYPE_SOUNDCARD:
p = (LPWAVEHDR)(&(A->out_wavehdr[A->out_current]));
if (p->dwUser == DWU_FILLING && p->dwBufferLength > 0) {
@ -1037,6 +1116,31 @@ int audio_flush (int a)
}
A->out_current = (A->out_current + 1) % NUM_OUT_BUF;
}
break;
case AUDIO_OUT_TYPE_STDOUT:;
int res;
unsigned char *ptr;
unsigned int len;
ptr = A->stream_out_data;
len = A->stream_out_next;
while (len > 0) {
res = write(STDOUT_FILENO, ptr, len);
if (res < 0) {
text_color_set (DW_COLOR_ERROR);
dw_printf ("stdout audio write error %d\n", res);
return (-1);
}
ptr += res;
len -= res;
}
A->stream_out_next = 0;
break;
}
return (0);
} /* end audio_flush */

View File

@ -384,6 +384,7 @@ int dw_printf (const char *fmt, ...)
// TODO: other possible destinations...
fputs (buffer, g_dw_printf_dest);
fflush (g_dw_printf_dest);
return (len);
}