@@ -147,11 +147,13 @@ static struct adev_s {
147
147
int stream_next ;
148
148
149
149
/*
150
- * Buffer and index for stdout.
150
+ * UDP socket for transmitting audio stream.
151
+ * Buffer and index for stdout or UDP.
151
152
*/
152
-
153
- unsigned char stream_out_data [SDR_UDP_BUF_MAXLEN ];
153
+ SOCKET udp_out_sock ;
154
+ char stream_out_data [SDR_UDP_BUF_MAXLEN ];
154
155
int stream_out_next ;
156
+ struct sockaddr_storage udp_dest_addr ;
155
157
156
158
/* For sound output. */
157
159
/* out_wavehdr.dwUser is used to keep track of output buffer state. */
@@ -292,6 +294,7 @@ int audio_open (struct audio_s *pa)
292
294
293
295
294
296
A -> udp_sock = INVALID_SOCKET ;
297
+ A -> udp_out_sock = INVALID_SOCKET ;
295
298
296
299
in_dev_no [a ] = WAVE_MAPPER ; /* = ((UINT)-1) in mmsystem.h */
297
300
out_dev_no [a ] = WAVE_MAPPER ;
@@ -349,8 +352,7 @@ int audio_open (struct audio_s *pa)
349
352
350
353
/*
351
354
* Select output device.
352
- * Only soundcard and stdout at this point.
353
- * Purhaps we'd like to add UDP for an SDR transmitter.
355
+ * Soundcard, UDP, and stdout supported.
354
356
*/
355
357
if (strcasecmp (pa -> adev [a ].adevice_out , "stdout" ) == 0 || strcmp (pa -> adev [a ].adevice_out , "-" ) == 0 ) {
356
358
A -> g_audio_out_type = AUDIO_OUT_TYPE_STDOUT ;
@@ -361,6 +363,16 @@ int audio_open (struct audio_s *pa)
361
363
}
362
364
/* Change - to stdout for readability. */
363
365
strlcpy (pa -> adev [a ].adevice_out , "stdout" , sizeof (pa -> adev [a ].adevice_out ));
366
+ } else if (strncasecmp (pa -> adev [a ].adevice_out , "udp:" , 4 ) == 0 ) {
367
+ A -> g_audio_out_type = AUDIO_OUT_TYPE_SDR_UDP ;
368
+ // User must supply address and port
369
+ if (strcasecmp (pa -> adev [a ].adevice_out , "udp:" ) == 0 ||
370
+ strlen (pa -> adev [a ].adevice_out ) < 7 ||
371
+ strstr (pa -> adev [a ].adevice_out + 5 , ":" ) == 0 ) {
372
+ text_color_set (DW_COLOR_ERROR );
373
+ dw_printf ("Destination address and port must be supplied for UDP output\n" );
374
+ return (-1 );
375
+ }
364
376
} else {
365
377
A -> g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD ;
366
378
@@ -524,7 +536,7 @@ int audio_open (struct audio_s *pa)
524
536
525
537
struct adev_s * A = & (adev [a ]);
526
538
527
- /* Display stdin or udp:port if appropriate. */
539
+ /* Display stdout or udp:port if appropriate. */
528
540
529
541
if (A -> g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD ) {
530
542
@@ -600,6 +612,71 @@ int audio_open (struct audio_s *pa)
600
612
}
601
613
A -> out_current = 0 ;
602
614
615
+ case AUDIO_OUT_TYPE_SDR_UDP :;
616
+
617
+ WSADATA wsadata ;
618
+ struct addrinfo ai_out ;
619
+ struct addrinfo * ai_res ;
620
+ char udp_outhost [256 ];
621
+ char * udp_outport ;
622
+ int err , res ;
623
+
624
+ err = WSAStartup (MAKEWORD (2 ,2 ), & wsadata );
625
+ if (err != 0 ) {
626
+ text_color_set (DW_COLOR_ERROR );
627
+ dw_printf ("WSAStartup failed: %d\n" , err );
628
+ return (-1 );
629
+ }
630
+
631
+ if (LOBYTE (wsadata .wVersion ) != 2 || HIBYTE (wsadata .wVersion ) != 2 ) {
632
+ text_color_set (DW_COLOR_ERROR );
633
+ dw_printf ("Could not find a usable version of Winsock.dll\n" );
634
+ WSACleanup ();
635
+ return (-1 );
636
+ }
637
+
638
+ memset ((char * ) & ai_out , 0 , sizeof (ai_out ));
639
+ ai_out .ai_socktype = SOCK_DGRAM ;
640
+ ai_out .ai_protocol = IPPROTO_UDP ;
641
+
642
+ strncpy (udp_outhost , pa -> adev [a ].adevice_out + 4 , 255 );
643
+ udp_outhost [255 ] = 0 ;
644
+ udp_outport = strstr (udp_outhost , ":" );
645
+ * udp_outport ++ = 0 ;
646
+
647
+ if (strlen (udp_outport ) == 0 ) {
648
+ text_color_set (DW_COLOR_ERROR );
649
+ dw_printf ("UDP output destination port must be supplied\n" );
650
+ return -1 ;
651
+ }
652
+
653
+ err = getaddrinfo (udp_outhost , udp_outport , & ai_out , & ai_res );
654
+ if (err != 0 ) {
655
+ text_color_set (DW_COLOR_ERROR );
656
+ dw_printf ("Error parsing/resolving UDP output address\n" );
657
+ return -1 ;
658
+ }
659
+
660
+ if (ai_res -> ai_family == AF_INET6 ) {
661
+ res = sizeof (struct sockaddr_in6 );
662
+ } else {
663
+ res = sizeof (struct sockaddr_in );
664
+ }
665
+
666
+ // Create UDP Socket
667
+
668
+ A -> udp_out_sock = socket (ai_res -> ai_family , SOCK_DGRAM , IPPROTO_UDP );
669
+ if (A -> udp_out_sock == INVALID_SOCKET ) {
670
+ text_color_set (DW_COLOR_ERROR );
671
+ dw_printf ("Couldn't create socket, errno %d\n" , WSAGetLastError ());
672
+ return -1 ;
673
+ }
674
+
675
+ memcpy (& A -> udp_dest_addr , ai_res -> ai_addr , res );
676
+ A -> stream_out_next = 0 ;
677
+
678
+ break ;
679
+
603
680
case AUDIO_OUT_TYPE_STDOUT :
604
681
605
682
setmode (STDOUT_FILENO , _O_BINARY );
@@ -1056,6 +1133,8 @@ int audio_put (int a, int c)
1056
1133
}
1057
1134
break ;
1058
1135
1136
+
1137
+ case AUDIO_OUT_TYPE_SDR_UDP :
1059
1138
case AUDIO_OUT_TYPE_STDOUT :
1060
1139
1061
1140
A -> stream_out_data [A -> stream_out_next ++ ] = c ;
@@ -1095,6 +1174,10 @@ int audio_flush (int a)
1095
1174
WAVEHDR * p ;
1096
1175
MMRESULT e ;
1097
1176
struct adev_s * A ;
1177
+ int res ;
1178
+ char * ptr ;
1179
+ unsigned int len ;
1180
+
1098
1181
1099
1182
A = & (adev [a ]);
1100
1183
@@ -1123,11 +1206,7 @@ int audio_flush (int a)
1123
1206
}
1124
1207
break ;
1125
1208
1126
- case AUDIO_OUT_TYPE_STDOUT :;
1127
-
1128
- int res ;
1129
- unsigned char * ptr ;
1130
- unsigned int len ;
1209
+ case AUDIO_OUT_TYPE_STDOUT :
1131
1210
1132
1211
ptr = A -> stream_out_data ;
1133
1212
len = A -> stream_out_next ;
@@ -1145,6 +1224,27 @@ int audio_flush (int a)
1145
1224
1146
1225
A -> stream_out_next = 0 ;
1147
1226
break ;
1227
+
1228
+ case AUDIO_OUT_TYPE_SDR_UDP :
1229
+
1230
+ ptr = A -> stream_out_data ;
1231
+ len = A -> stream_out_next ;
1232
+
1233
+ while (len > 0 ) {
1234
+ res = sendto (A -> udp_out_sock , ptr , len , 0 , (struct sockaddr * )& A -> udp_dest_addr , sizeof (struct sockaddr_storage ));
1235
+ if (res < 0 ) {
1236
+ text_color_set (DW_COLOR_ERROR );
1237
+ dw_printf ("Error %d writing to UDP socket.\n" , res );
1238
+ return (-1 );
1239
+ }
1240
+
1241
+ ptr += res ;
1242
+ len -= res ;
1243
+ }
1244
+
1245
+ A -> stream_out_next = 0 ;
1246
+ break ;
1247
+
1148
1248
}
1149
1249
return (0 );
1150
1250
0 commit comments