Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f1fcb8c

Browse files
committedSep 25, 2023
Add stdout option for audio output
1 parent 58652df commit f1fcb8c

File tree

2 files changed

+199
-156
lines changed

2 files changed

+199
-156
lines changed
 

‎src/audio.c

Lines changed: 195 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static struct adev_s {
129129
int outbuf_len;
130130

131131
enum audio_in_type_e g_audio_in_type;
132+
enum audio_out_type_e g_audio_out_type;
132133

133134
int udp_sock; /* UDP socket for receiving data */
134135

@@ -453,52 +454,63 @@ int audio_open (struct audio_s *pa)
453454
}
454455

455456
/*
456-
* Output device. Only "soundcard" is supported at this time.
457+
* Output device. Only "soundcard" and "stdout" are supported at this time.
457458
*/
459+
if (strcasecmp(pa->adev[a].adevice_out, "stdout") == 0 || strcmp(pa->adev[a].adevice_out, "-") == 0) {
460+
adev[a].g_audio_out_type = AUDIO_OUT_TYPE_STDOUT;
461+
} else {
462+
adev[a].g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD;
463+
}
464+
465+
switch (adev[a].g_audio_out_type) {
466+
case AUDIO_OUT_TYPE_STDOUT:
467+
adev[a].outbuf_size_in_bytes = 1024;
468+
break;
458469

470+
case AUDIO_OUT_TYPE_SOUNDCARD:
459471
#if USE_ALSA
460-
err = snd_pcm_open (&(adev[a].audio_out_handle), audio_out_name, SND_PCM_STREAM_PLAYBACK, 0);
472+
err = snd_pcm_open (&(adev[a].audio_out_handle), audio_out_name, SND_PCM_STREAM_PLAYBACK, 0);
461473

462-
if (err < 0) {
463-
text_color_set(DW_COLOR_ERROR);
464-
dw_printf ("Could not open audio device %s for output\n%s\n",
465-
audio_out_name, snd_strerror(err));
466-
if (err == -EBUSY) {
467-
dw_printf ("This means that some other application is using that device.\n");
468-
dw_printf ("The solution is to identify that other application and stop it.\n");
469-
}
470-
return (-1);
471-
}
474+
if (err < 0) {
475+
text_color_set(DW_COLOR_ERROR);
476+
dw_printf ("Could not open audio device %s for output\n%s\n",
477+
audio_out_name, snd_strerror(err));
478+
if (err == -EBUSY) {
479+
dw_printf ("This means that some other application is using that device.\n");
480+
dw_printf ("The solution is to identify that other application and stop it.\n");
481+
}
482+
return (-1);
483+
}
472484

473-
adev[a].outbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_out_handle, pa, audio_out_name, "output");
485+
adev[a].outbuf_size_in_bytes = set_alsa_params (a, adev[a].audio_out_handle, pa, audio_out_name, "output");
474486

475-
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
476-
return (-1);
477-
}
487+
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
488+
return (-1);
489+
}
478490

479491
#elif USE_SNDIO
480-
adev[a].sndio_out_handle = sio_open (audio_out_name, SIO_PLAY, 0);
481-
if (adev[a].sndio_out_handle == NULL) {
482-
text_color_set(DW_COLOR_ERROR);
483-
dw_printf ("Could not open audio device %s for output\n",
484-
audio_out_name);
485-
return (-1);
486-
}
492+
adev[a].sndio_out_handle = sio_open (audio_out_name, SIO_PLAY, 0);
493+
if (adev[a].sndio_out_handle == NULL) {
494+
text_color_set(DW_COLOR_ERROR);
495+
dw_printf ("Could not open audio device %s for output\n",
496+
audio_out_name);
497+
return (-1);
498+
}
487499

488-
adev[a].outbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_out_handle, pa, audio_out_name, "output");
500+
adev[a].outbuf_size_in_bytes = set_sndio_params (a, adev[a].sndio_out_handle, pa, audio_out_name, "output");
489501

490-
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
491-
return (-1);
492-
}
502+
if (adev[a].inbuf_size_in_bytes <= 0 || adev[a].outbuf_size_in_bytes <= 0) {
503+
return (-1);
504+
}
493505

494-
if (!sio_start (adev[a].sndio_out_handle)) {
495-
text_color_set(DW_COLOR_ERROR);
496-
dw_printf ("Could not start audio device %s for output\n",
497-
audio_out_name);
498-
return (-1);
499-
}
506+
if (!sio_start (adev[a].sndio_out_handle)) {
507+
text_color_set(DW_COLOR_ERROR);
508+
dw_printf ("Could not start audio device %s for output\n",
509+
audio_out_name);
510+
return (-1);
511+
}
500512
#endif
501-
513+
}
502514
/*
503515
* Finally allocate buffer for each direction.
504516
*/
@@ -1333,13 +1345,36 @@ int audio_put (int a, int c)
13331345

13341346
int audio_flush (int a)
13351347
{
1348+
switch (adev[a].g_audio_out_type) {
1349+
case AUDIO_OUT_TYPE_STDOUT:;
1350+
int res;
1351+
unsigned char *ptr;
1352+
int len;
1353+
1354+
ptr = adev[a].outbuf_ptr;
1355+
len = adev[a].outbuf_len;
1356+
1357+
while (len > 0) {
1358+
res = write(STDOUT_FILENO, ptr, (size_t) len);
1359+
if (res <= 0) {
1360+
text_color_set(DW_COLOR_INFO);
1361+
dw_printf ("\nError writing to stdout. Exiting.\n");
1362+
exit (0);
1363+
}
1364+
ptr += res;
1365+
len -= res;
1366+
}
1367+
adev[a].outbuf_len = 0;
1368+
return 0;
1369+
1370+
case AUDIO_OUT_TYPE_SOUNDCARD:;
13361371
#if USE_ALSA
1337-
int k;
1338-
unsigned char *psound;
1339-
int retries = 10;
1340-
snd_pcm_status_t *status;
1372+
int k;
1373+
unsigned char *psound;
1374+
int retries = 10;
1375+
snd_pcm_status_t *status;
13411376

1342-
assert (adev[a].audio_out_handle != NULL);
1377+
assert (adev[a].audio_out_handle != NULL);
13431378

13441379

13451380
/*
@@ -1352,159 +1387,160 @@ int audio_flush (int a)
13521387
*/
13531388

13541389

1355-
snd_pcm_status_alloca(&status);
1390+
snd_pcm_status_alloca(&status);
13561391

1357-
k = snd_pcm_status (adev[a].audio_out_handle, status);
1358-
if (k != 0) {
1359-
text_color_set(DW_COLOR_ERROR);
1360-
dw_printf ("Audio output get status error.\n%s\n", snd_strerror(k));
1361-
}
1392+
k = snd_pcm_status (adev[a].audio_out_handle, status);
1393+
if (k != 0) {
1394+
text_color_set(DW_COLOR_ERROR);
1395+
dw_printf ("Audio output get status error.\n%s\n", snd_strerror(k));
1396+
}
13621397

1363-
if ((k = snd_pcm_status_get_state(status)) != SND_PCM_STATE_RUNNING) {
1398+
if ((k = snd_pcm_status_get_state(status)) != SND_PCM_STATE_RUNNING) {
13641399

1365-
//text_color_set(DW_COLOR_DEBUG);
1366-
//dw_printf ("Audio output state = %d. Try to start.\n", k);
1400+
//text_color_set(DW_COLOR_DEBUG);
1401+
//dw_printf ("Audio output state = %d. Try to start.\n", k);
13671402

1368-
k = snd_pcm_prepare (adev[a].audio_out_handle);
1403+
k = snd_pcm_prepare (adev[a].audio_out_handle);
13691404

1370-
if (k != 0) {
1371-
text_color_set(DW_COLOR_ERROR);
1372-
dw_printf ("Audio output start error.\n%s\n", snd_strerror(k));
1373-
}
1374-
}
1405+
if (k != 0) {
1406+
text_color_set(DW_COLOR_ERROR);
1407+
dw_printf ("Audio output start error.\n%s\n", snd_strerror(k));
1408+
}
1409+
}
13751410

13761411

1377-
psound = adev[a].outbuf_ptr;
1412+
psound = adev[a].outbuf_ptr;
13781413

1379-
while (retries-- > 0) {
1414+
while (retries-- > 0) {
13801415

1381-
k = snd_pcm_writei (adev[a].audio_out_handle, psound, adev[a].outbuf_len / adev[a].bytes_per_frame);
1416+
k = snd_pcm_writei (adev[a].audio_out_handle, psound, adev[a].outbuf_len / adev[a].bytes_per_frame);
13821417
#if DEBUGx
1383-
text_color_set(DW_COLOR_DEBUG);
1384-
dw_printf ("audio_flush(): snd_pcm_writei %d frames returns %d\n",
1385-
adev[a].outbuf_len / adev[a].bytes_per_frame, k);
1386-
fflush (stdout);
1418+
text_color_set(DW_COLOR_DEBUG);
1419+
dw_printf ("audio_flush(): snd_pcm_writei %d frames returns %d\n",
1420+
adev[a].outbuf_len / adev[a].bytes_per_frame, k);
1421+
fflush (stdout);
13871422
#endif
1388-
if (k == -EPIPE) {
1389-
text_color_set(DW_COLOR_ERROR);
1390-
dw_printf ("Audio output data underrun.\n");
1423+
if (k == -EPIPE) {
1424+
text_color_set(DW_COLOR_ERROR);
1425+
dw_printf ("Audio output data underrun.\n");
13911426

1392-
/* No problemo. Recover and go around again. */
1427+
/* No problemo. Recover and go around again. */
13931428

1394-
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
1395-
}
1396-
else if (k == -ESTRPIPE) {
1397-
text_color_set(DW_COLOR_ERROR);
1398-
dw_printf ("Driver suspended, recovering\n");
1399-
snd_pcm_recover(adev[a].audio_out_handle, k, 1);
1400-
}
1401-
else if (k == -EBADFD) {
1402-
k = snd_pcm_prepare (adev[a].audio_out_handle);
1403-
if(k < 0) {
1404-
dw_printf ("Error preparing after bad state: %s\n", snd_strerror(k));
1405-
}
1406-
}
1407-
else if (k < 0) {
1408-
text_color_set(DW_COLOR_ERROR);
1409-
dw_printf ("Audio write error: %s\n", snd_strerror(k));
1429+
snd_pcm_recover (adev[a].audio_out_handle, k, 1);
1430+
}
1431+
else if (k == -ESTRPIPE) {
1432+
text_color_set(DW_COLOR_ERROR);
1433+
dw_printf ("Driver suspended, recovering\n");
1434+
snd_pcm_recover(adev[a].audio_out_handle, k, 1);
1435+
}
1436+
else if (k == -EBADFD) {
1437+
k = snd_pcm_prepare (adev[a].audio_out_handle);
1438+
if(k < 0) {
1439+
dw_printf ("Error preparing after bad state: %s\n", snd_strerror(k));
1440+
}
1441+
}
1442+
else if (k < 0) {
1443+
text_color_set(DW_COLOR_ERROR);
1444+
dw_printf ("Audio write error: %s\n", snd_strerror(k));
14101445

1411-
/* Some other error condition. */
1412-
/* Try again. What do we have to lose? */
1446+
/* Some other error condition. */
1447+
/* Try again. What do we have to lose? */
14131448

1414-
k = snd_pcm_prepare (adev[a].audio_out_handle);
1415-
if(k < 0) {
1416-
dw_printf ("Error preparing after error: %s\n", snd_strerror(k));
1417-
}
1418-
}
1419-
else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) {
1420-
text_color_set(DW_COLOR_ERROR);
1421-
dw_printf ("Audio write took %d frames rather than %d.\n",
1422-
k, adev[a].outbuf_len / adev[a].bytes_per_frame);
1423-
1424-
/* Go around again with the rest of it. */
1449+
k = snd_pcm_prepare (adev[a].audio_out_handle);
1450+
if(k < 0) {
1451+
dw_printf ("Error preparing after error: %s\n", snd_strerror(k));
1452+
}
1453+
}
1454+
else if (k != adev[a].outbuf_len / adev[a].bytes_per_frame) {
1455+
text_color_set(DW_COLOR_ERROR);
1456+
dw_printf ("Audio write took %d frames rather than %d.\n",
1457+
k, adev[a].outbuf_len / adev[a].bytes_per_frame);
14251458

1426-
psound += k * adev[a].bytes_per_frame;
1427-
adev[a].outbuf_len -= k * adev[a].bytes_per_frame;
1428-
}
1429-
else {
1430-
/* Success! */
1431-
adev[a].outbuf_len = 0;
1432-
return (0);
1433-
}
1434-
}
1459+
/* Go around again with the rest of it. */
1460+
1461+
psound += k * adev[a].bytes_per_frame;
1462+
adev[a].outbuf_len -= k * adev[a].bytes_per_frame;
1463+
}
1464+
else {
1465+
/* Success! */
1466+
adev[a].outbuf_len = 0;
1467+
return (0);
1468+
}
1469+
}
14351470

1436-
text_color_set(DW_COLOR_ERROR);
1437-
dw_printf ("Audio write error retry count exceeded.\n");
1471+
text_color_set(DW_COLOR_ERROR);
1472+
dw_printf ("Audio write error retry count exceeded.\n");
14381473

1439-
adev[a].outbuf_len = 0;
1440-
return (-1);
1474+
adev[a].outbuf_len = 0;
1475+
return (-1);
14411476

14421477
#elif USE_SNDIO
14431478

1444-
int k;
1445-
unsigned char *ptr;
1446-
int len;
1479+
int k;
1480+
unsigned char *ptr;
1481+
int len;
14471482

1448-
ptr = adev[a].outbuf_ptr;
1449-
len = adev[a].outbuf_len;
1483+
ptr = adev[a].outbuf_ptr;
1484+
len = adev[a].outbuf_len;
14501485

1451-
while (len > 0) {
1452-
assert (adev[a].sndio_out_handle != NULL);
1453-
if (poll_sndio (adev[a].sndio_out_handle, POLLOUT) < 0) {
1454-
text_color_set(DW_COLOR_ERROR);
1455-
perror("Can't write to audio device");
1456-
adev[a].outbuf_len = 0;
1457-
return (-1);
1458-
}
1486+
while (len > 0) {
1487+
assert (adev[a].sndio_out_handle != NULL);
1488+
if (poll_sndio (adev[a].sndio_out_handle, POLLOUT) < 0) {
1489+
text_color_set(DW_COLOR_ERROR);
1490+
perror("Can't write to audio device");
1491+
adev[a].outbuf_len = 0;
1492+
return (-1);
1493+
}
14591494

1460-
k = sio_write (adev[a].sndio_out_handle, ptr, len);
1495+
k = sio_write (adev[a].sndio_out_handle, ptr, len);
14611496
#if DEBUGx
1462-
text_color_set(DW_COLOR_DEBUG);
1463-
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
1464-
fflush (stdout);
1497+
text_color_set(DW_COLOR_DEBUG);
1498+
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
1499+
fflush (stdout);
14651500
#endif
1466-
ptr += k;
1467-
len -= k;
1468-
}
1501+
ptr += k;
1502+
len -= k;
1503+
}
14691504

1470-
adev[a].outbuf_len = 0;
1471-
return (0);
1505+
adev[a].outbuf_len = 0;
1506+
return (0);
14721507

14731508
#else /* OSS */
14741509

1475-
int k;
1476-
unsigned char *ptr;
1477-
int len;
1510+
int k;
1511+
unsigned char *ptr;
1512+
int len;
14781513

1479-
ptr = adev[a].outbuf_ptr;
1480-
len = adev[a].outbuf_len;
1514+
ptr = adev[a].outbuf_ptr;
1515+
len = adev[a].outbuf_len;
14811516

1482-
while (len > 0) {
1483-
assert (adev[a].oss_audio_device_fd > 0);
1484-
k = write (adev[a].oss_audio_device_fd, ptr, len);
1517+
while (len > 0) {
1518+
assert (adev[a].oss_audio_device_fd > 0);
1519+
k = write (adev[a].oss_audio_device_fd, ptr, len);
14851520
#if DEBUGx
1486-
text_color_set(DW_COLOR_DEBUG);
1487-
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
1488-
fflush (stdout);
1521+
text_color_set(DW_COLOR_DEBUG);
1522+
dw_printf ("audio_flush(): write %d returns %d\n", len, k);
1523+
fflush (stdout);
14891524
#endif
1490-
if (k < 0) {
1491-
text_color_set(DW_COLOR_ERROR);
1492-
perror("Can't write to audio device");
1525+
if (k < 0) {
1526+
text_color_set(DW_COLOR_ERROR);
1527+
perror("Can't write to audio device");
1528+
adev[a].outbuf_len = 0;
1529+
return (-1);
1530+
}
1531+
if (k < len) {
1532+
/* presumably full but didn't block. */
1533+
usleep (10000);
1534+
}
1535+
ptr += k;
1536+
len -= k;
1537+
}
1538+
14931539
adev[a].outbuf_len = 0;
1494-
return (-1);
1495-
}
1496-
if (k < len) {
1497-
/* presumably full but didn't block. */
1498-
usleep (10000);
1499-
}
1500-
ptr += k;
1501-
len -= k;
1540+
return (0);
1541+
#endif
15021542
}
1503-
1504-
adev[a].outbuf_len = 0;
15051543
return (0);
1506-
#endif
1507-
15081544
} /* end audio_flush */
15091545

15101546

@@ -1546,9 +1582,12 @@ int audio_flush (int a)
15461582

15471583
void audio_wait (int a)
15481584
{
1549-
15501585
audio_flush (a);
15511586

1587+
if (adev[a].g_audio_out_type == AUDIO_OUT_TYPE_STDOUT) {
1588+
return;
1589+
}
1590+
15521591
#if USE_ALSA
15531592

15541593
/* For playback, this should wait for all pending frames */

‎src/audio.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ enum audio_in_type_e {
4343
AUDIO_IN_TYPE_SDR_UDP,
4444
AUDIO_IN_TYPE_STDIN };
4545

46+
enum audio_out_type_e {
47+
AUDIO_OUT_TYPE_SOUNDCARD,
48+
AUDIO_OUT_TYPE_STDOUT };
49+
4650
/* For option to try fixing frames with bad CRC. */
4751

4852
typedef enum retry_e {

0 commit comments

Comments
 (0)
Please sign in to comment.