75
75
#include <sys/socket.h>
76
76
#include <arpa/inet.h>
77
77
#include <netinet/in.h>
78
+ #include <netdb.h>
78
79
#include <errno.h>
79
80
80
81
@@ -131,7 +132,9 @@ static struct adev_s {
131
132
enum audio_in_type_e g_audio_in_type ;
132
133
enum audio_out_type_e g_audio_out_type ;
133
134
134
- int udp_sock ; /* UDP socket for receiving data */
135
+ int udp_in_sock ; /* UDP socket for receiving data */
136
+ int udp_out_sock ; /* UDP socket for sending data */
137
+ struct sockaddr_storage udp_dest_addr ; /* Destination address for UDP socket sending */
135
138
136
139
} adev [MAX_ADEVS ];
137
140
@@ -239,7 +242,7 @@ int audio_open (struct audio_s *pa)
239
242
#else
240
243
adev [a ].oss_audio_device_fd = -1 ;
241
244
#endif
242
- adev [a ].udp_sock = -1 ;
245
+ adev [a ].udp_in_sock = -1 ;
243
246
}
244
247
245
248
@@ -409,7 +412,7 @@ int audio_open (struct audio_s *pa)
409
412
//int data_size = 0;
410
413
411
414
//Create UDP Socket
412
- if ((adev [a ].udp_sock = socket (AF_INET , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
415
+ if ((adev [a ].udp_in_sock = socket (AF_INET , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
413
416
text_color_set (DW_COLOR_ERROR );
414
417
dw_printf ("Couldn't create socket, errno %d\n" , errno );
415
418
return -1 ;
@@ -421,7 +424,7 @@ int audio_open (struct audio_s *pa)
421
424
si_me .sin_addr .s_addr = htonl (INADDR_ANY );
422
425
423
426
//Bind to the socket
424
- if (bind (adev [a ].udp_sock , (const struct sockaddr * ) & si_me , sizeof (si_me ))== -1 ) {
427
+ if (bind (adev [a ].udp_in_sock , (const struct sockaddr * ) & si_me , sizeof (si_me ))== -1 ) {
425
428
text_color_set (DW_COLOR_ERROR );
426
429
dw_printf ("Couldn't bind socket, errno %d\n" , errno );
427
430
return -1 ;
@@ -450,7 +453,7 @@ int audio_open (struct audio_s *pa)
450
453
}
451
454
452
455
/*
453
- * Output device. Only "soundcard" and "stdout" are supported at this time.
456
+ * Output device. Soundcard, stdout, and UDP are supported at this time.
454
457
*/
455
458
if (strcasecmp (pa -> adev [a ].adevice_out , "stdout" ) == 0 || strcmp (pa -> adev [a ].adevice_out , "-" ) == 0 ) {
456
459
adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_STDOUT ;
@@ -459,6 +462,16 @@ int audio_open (struct audio_s *pa)
459
462
dw_printf ("stdout must only be used with the -O option\n" );
460
463
return (-1 );
461
464
}
465
+ } else if (strncasecmp (pa -> adev [a ].adevice_out , "udp:" , 4 ) == 0 ) {
466
+ adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_SDR_UDP ;
467
+ /* User must supply address and port */
468
+ if (strcasecmp (pa -> adev [a ].adevice_out ,"udp:" ) == 0 ||
469
+ strlen (pa -> adev [a ].adevice_out ) < 7 ||
470
+ strstr (pa -> adev [a ].adevice_out + 5 , ":" ) == 0 ) {
471
+ text_color_set (DW_COLOR_ERROR );
472
+ dw_printf ("Destination address and port must be supplied for UDP output\n" );
473
+ return (-1 );
474
+ }
462
475
} else {
463
476
adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD ;
464
477
}
@@ -506,7 +519,63 @@ int audio_open (struct audio_s *pa)
506
519
audio_out_name );
507
520
return (-1 );
508
521
}
522
+ break ;
509
523
#endif
524
+
525
+ case AUDIO_OUT_TYPE_SDR_UDP :;
526
+
527
+ struct addrinfo ai_out ;
528
+ struct addrinfo * ai_res ;
529
+ char udp_outhost [256 ];
530
+ char * udp_outport ;
531
+ int res ;
532
+
533
+ // Initialize structure for addrinfo restrictions
534
+ memset ((char * ) & ai_out , 0 , sizeof (ai_out ));
535
+ ai_out .ai_socktype = SOCK_DGRAM ;
536
+ ai_out .ai_protocol = IPPROTO_UDP ;
537
+
538
+ // Separate out the host and port strings
539
+ strncpy (udp_outhost , pa -> adev [a ].adevice_out + 4 , 255 );
540
+ udp_outhost [255 ] = 0 ;
541
+ udp_outport = strstr (udp_outhost ,":" );
542
+ * udp_outport ++ = 0 ;
543
+
544
+ if (strlen (udp_outport ) == 0 ) {
545
+ text_color_set (DW_COLOR_ERROR );
546
+ dw_printf ("UDP output destination port must be supplied\n" );
547
+ return -1 ;
548
+ }
549
+
550
+ // Get the sockaddr to represent the host/port provided
551
+ res = getaddrinfo (udp_outhost , udp_outport , & ai_out , & ai_res );
552
+ if (res != 0 ) {
553
+ text_color_set (DW_COLOR_ERROR );
554
+ dw_printf ("Error parsing/resolving UDP output address\n" );
555
+ return -1 ;
556
+ }
557
+
558
+ // IPv4 and IPv6 structs are different sizes
559
+ if (ai_res -> ai_family == AF_INET6 ) {
560
+ res = sizeof (struct sockaddr_in6 );
561
+ } else {
562
+ res = sizeof (struct sockaddr_in );
563
+ }
564
+
565
+ //Create UDP Socket for the right address family
566
+ if ((adev [a ].udp_out_sock = socket (ai_res -> ai_family , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
567
+ text_color_set (DW_COLOR_ERROR );
568
+ dw_printf ("Couldn't create socket, errno %d\n" , errno );
569
+ return -1 ;
570
+ }
571
+
572
+ // Save sockaddr needed later to send the data and set buffer size
573
+ memcpy (& adev [a ].udp_dest_addr , ai_res -> ai_addr , res );
574
+ adev [a ].outbuf_size_in_bytes = SDR_UDP_BUF_MAXLEN ;
575
+ freeaddrinfo (ai_res );
576
+
577
+ break ;
578
+
510
579
}
511
580
/*
512
581
* Finally allocate buffer for each direction.
@@ -1214,8 +1283,8 @@ int audio_get (int a)
1214
1283
while (adev [a ].inbuf_next >= adev [a ].inbuf_len ) {
1215
1284
int res ;
1216
1285
1217
- assert (adev [a ].udp_sock > 0 );
1218
- res = recv (adev [a ].udp_sock , adev [a ].inbuf_ptr , adev [a ].inbuf_size_in_bytes , 0 );
1286
+ assert (adev [a ].udp_in_sock > 0 );
1287
+ res = recv (adev [a ].udp_in_sock , adev [a ].inbuf_ptr , adev [a ].inbuf_size_in_bytes , 0 );
1219
1288
if (res < 0 ) {
1220
1289
text_color_set (DW_COLOR_ERROR );
1221
1290
dw_printf ("Can't read from udp socket, res=%d" , res );
@@ -1342,11 +1411,12 @@ int audio_put (int a, int c)
1342
1411
1343
1412
int audio_flush (int a )
1344
1413
{
1414
+ int res ;
1415
+ unsigned char * ptr ;
1416
+ int len ;
1417
+
1345
1418
switch (adev [a ].g_audio_out_type ) {
1346
1419
case AUDIO_OUT_TYPE_STDOUT :;
1347
- int res ;
1348
- unsigned char * ptr ;
1349
- int len ;
1350
1420
1351
1421
ptr = adev [a ].outbuf_ptr ;
1352
1422
len = adev [a ].outbuf_len ;
@@ -1536,6 +1606,32 @@ int audio_flush (int a)
1536
1606
adev [a ].outbuf_len = 0 ;
1537
1607
return (0 );
1538
1608
#endif
1609
+
1610
+ case AUDIO_OUT_TYPE_SDR_UDP :;
1611
+
1612
+ ptr = adev [a ].outbuf_ptr ;
1613
+ len = adev [a ].outbuf_len ;
1614
+
1615
+ while (len > 0 ) {
1616
+
1617
+ assert (adev [a ].udp_out_sock > 0 );
1618
+
1619
+ res = sendto (adev [a ].udp_out_sock , adev [a ].outbuf_ptr , len , 0 , (struct sockaddr * )& adev [a ].udp_dest_addr , sizeof (struct sockaddr_storage ));
1620
+
1621
+ if (res <= 0 ) {
1622
+ text_color_set (DW_COLOR_INFO );
1623
+ dw_printf ("\nError %d writing to UDP socket. Exiting.\n" , errno );
1624
+ exit (0 );
1625
+ }
1626
+
1627
+ ptr += res ;
1628
+ len -= res ;
1629
+
1630
+ }
1631
+
1632
+ adev [a ].outbuf_len = 0 ;
1633
+ return 0 ;
1634
+
1539
1635
}
1540
1636
return (0 );
1541
1637
} /* end audio_flush */
@@ -1581,7 +1677,7 @@ void audio_wait (int a)
1581
1677
{
1582
1678
audio_flush (a );
1583
1679
1584
- if (adev [a ].g_audio_out_type == AUDIO_OUT_TYPE_STDOUT ) {
1680
+ if (adev [a ].g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD ) {
1585
1681
return ;
1586
1682
}
1587
1683
0 commit comments