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
@@ -413,7 +416,7 @@ int audio_open (struct audio_s *pa)
413
416
//int data_size = 0;
414
417
415
418
//Create UDP Socket
416
- if ((adev [a ].udp_sock = socket (AF_INET , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
419
+ if ((adev [a ].udp_in_sock = socket (AF_INET , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
417
420
text_color_set (DW_COLOR_ERROR );
418
421
dw_printf ("Couldn't create socket, errno %d\n" , errno );
419
422
return -1 ;
@@ -425,7 +428,7 @@ int audio_open (struct audio_s *pa)
425
428
si_me .sin_addr .s_addr = htonl (INADDR_ANY );
426
429
427
430
//Bind to the socket
428
- if (bind (adev [a ].udp_sock , (const struct sockaddr * ) & si_me , sizeof (si_me ))== -1 ) {
431
+ if (bind (adev [a ].udp_in_sock , (const struct sockaddr * ) & si_me , sizeof (si_me ))== -1 ) {
429
432
text_color_set (DW_COLOR_ERROR );
430
433
dw_printf ("Couldn't bind socket, errno %d\n" , errno );
431
434
return -1 ;
@@ -454,7 +457,7 @@ int audio_open (struct audio_s *pa)
454
457
}
455
458
456
459
/*
457
- * Output device. Only "soundcard" and "stdout" are supported at this time.
460
+ * Output device. Soundcard, stdout, and UDP are supported at this time.
458
461
*/
459
462
if (strcasecmp (pa -> adev [a ].adevice_out , "stdout" ) == 0 || strcmp (pa -> adev [a ].adevice_out , "-" ) == 0 ) {
460
463
adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_STDOUT ;
@@ -463,6 +466,16 @@ int audio_open (struct audio_s *pa)
463
466
dw_printf ("stdout must only be used with the -O option\n" );
464
467
return (-1 );
465
468
}
469
+ } else if (strncasecmp (pa -> adev [a ].adevice_out , "udp:" , 4 ) == 0 ) {
470
+ adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_SDR_UDP ;
471
+ /* User must supply address and port */
472
+ if (strcasecmp (pa -> adev [a ].adevice_out ,"udp:" ) == 0 ||
473
+ strlen (pa -> adev [a ].adevice_out ) < 7 ||
474
+ strstr (pa -> adev [a ].adevice_out + 5 , ":" ) == 0 ) {
475
+ text_color_set (DW_COLOR_ERROR );
476
+ dw_printf ("Destination address and port must be supplied for UDP output\n" );
477
+ return (-1 );
478
+ }
466
479
} else {
467
480
adev [a ].g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD ;
468
481
}
@@ -514,7 +527,63 @@ int audio_open (struct audio_s *pa)
514
527
audio_out_name );
515
528
return (-1 );
516
529
}
530
+ break ;
517
531
#endif
532
+
533
+ case AUDIO_OUT_TYPE_SDR_UDP :;
534
+
535
+ struct addrinfo ai_out ;
536
+ struct addrinfo * ai_res ;
537
+ char udp_outhost [256 ];
538
+ char * udp_outport ;
539
+ int res ;
540
+
541
+ // Initialize structure for addrinfo restrictions
542
+ memset ((char * ) & ai_out , 0 , sizeof (ai_out ));
543
+ ai_out .ai_socktype = SOCK_DGRAM ;
544
+ ai_out .ai_protocol = IPPROTO_UDP ;
545
+
546
+ // Separate out the host and port strings
547
+ strncpy (udp_outhost , pa -> adev [a ].adevice_out + 4 , 255 );
548
+ udp_outhost [255 ] = 0 ;
549
+ udp_outport = strstr (udp_outhost ,":" );
550
+ * udp_outport ++ = 0 ;
551
+
552
+ if (strlen (udp_outport ) == 0 ) {
553
+ text_color_set (DW_COLOR_ERROR );
554
+ dw_printf ("UDP output destination port must be supplied\n" );
555
+ return -1 ;
556
+ }
557
+
558
+ // Get the sockaddr to represent the host/port provided
559
+ res = getaddrinfo (udp_outhost , udp_outport , & ai_out , & ai_res );
560
+ if (res != 0 ) {
561
+ text_color_set (DW_COLOR_ERROR );
562
+ dw_printf ("Error parsing/resolving UDP output address\n" );
563
+ return -1 ;
564
+ }
565
+
566
+ // IPv4 and IPv6 structs are different sizes
567
+ if (ai_res -> ai_family == AF_INET6 ) {
568
+ res = sizeof (struct sockaddr_in6 );
569
+ } else {
570
+ res = sizeof (struct sockaddr_in );
571
+ }
572
+
573
+ //Create UDP Socket for the right address family
574
+ if ((adev [a ].udp_out_sock = socket (ai_res -> ai_family , SOCK_DGRAM , IPPROTO_UDP ))== -1 ) {
575
+ text_color_set (DW_COLOR_ERROR );
576
+ dw_printf ("Couldn't create socket, errno %d\n" , errno );
577
+ return -1 ;
578
+ }
579
+
580
+ // Save sockaddr needed later to send the data and set buffer size
581
+ memcpy (& adev [a ].udp_dest_addr , ai_res -> ai_addr , res );
582
+ adev [a ].outbuf_size_in_bytes = SDR_UDP_BUF_MAXLEN ;
583
+ freeaddrinfo (ai_res );
584
+
585
+ break ;
586
+
518
587
}
519
588
/*
520
589
* Finally allocate buffer for each direction.
@@ -1222,8 +1291,8 @@ int audio_get (int a)
1222
1291
while (adev [a ].inbuf_next >= adev [a ].inbuf_len ) {
1223
1292
int res ;
1224
1293
1225
- assert (adev [a ].udp_sock > 0 );
1226
- res = recv (adev [a ].udp_sock , adev [a ].inbuf_ptr , adev [a ].inbuf_size_in_bytes , 0 );
1294
+ assert (adev [a ].udp_in_sock > 0 );
1295
+ res = recv (adev [a ].udp_in_sock , adev [a ].inbuf_ptr , adev [a ].inbuf_size_in_bytes , 0 );
1227
1296
if (res < 0 ) {
1228
1297
text_color_set (DW_COLOR_ERROR );
1229
1298
dw_printf ("Can't read from udp socket, res=%d" , res );
@@ -1350,11 +1419,12 @@ int audio_put (int a, int c)
1350
1419
1351
1420
int audio_flush (int a )
1352
1421
{
1422
+ int res ;
1423
+ unsigned char * ptr ;
1424
+ int len ;
1425
+
1353
1426
switch (adev [a ].g_audio_out_type ) {
1354
1427
case AUDIO_OUT_TYPE_STDOUT :;
1355
- int res ;
1356
- unsigned char * ptr ;
1357
- int len ;
1358
1428
1359
1429
ptr = adev [a ].outbuf_ptr ;
1360
1430
len = adev [a ].outbuf_len ;
@@ -1544,6 +1614,32 @@ int audio_flush (int a)
1544
1614
adev [a ].outbuf_len = 0 ;
1545
1615
return (0 );
1546
1616
#endif
1617
+
1618
+ case AUDIO_OUT_TYPE_SDR_UDP :;
1619
+
1620
+ ptr = adev [a ].outbuf_ptr ;
1621
+ len = adev [a ].outbuf_len ;
1622
+
1623
+ while (len > 0 ) {
1624
+
1625
+ assert (adev [a ].udp_out_sock > 0 );
1626
+
1627
+ res = sendto (adev [a ].udp_out_sock , adev [a ].outbuf_ptr , len , 0 , (struct sockaddr * )& adev [a ].udp_dest_addr , sizeof (struct sockaddr_storage ));
1628
+
1629
+ if (res <= 0 ) {
1630
+ text_color_set (DW_COLOR_INFO );
1631
+ dw_printf ("\nError %d writing to UDP socket. Exiting.\n" , errno );
1632
+ exit (0 );
1633
+ }
1634
+
1635
+ ptr += res ;
1636
+ len -= res ;
1637
+
1638
+ }
1639
+
1640
+ adev [a ].outbuf_len = 0 ;
1641
+ return 0 ;
1642
+
1547
1643
}
1548
1644
return (0 );
1549
1645
} /* end audio_flush */
@@ -1589,7 +1685,7 @@ void audio_wait (int a)
1589
1685
{
1590
1686
audio_flush (a );
1591
1687
1592
- if (adev [a ].g_audio_out_type == AUDIO_OUT_TYPE_STDOUT ) {
1688
+ if (adev [a ].g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD ) {
1593
1689
return ;
1594
1690
}
1595
1691
0 commit comments