Skip to content

Commit 7982134

Browse files
committed
Add UDP audio output for Windows
1 parent 81fe3a0 commit 7982134

File tree

1 file changed

+111
-11
lines changed

1 file changed

+111
-11
lines changed

Diff for: src/audio_win.c

+111-11
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,13 @@ static struct adev_s {
147147
int stream_next;
148148

149149
/*
150-
* Buffer and index for stdout.
150+
* UDP socket for transmitting audio stream.
151+
* Buffer and index for stdout or UDP.
151152
*/
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];
154155
int stream_out_next;
156+
struct sockaddr_storage udp_dest_addr;
155157

156158
/* For sound output. */
157159
/* out_wavehdr.dwUser is used to keep track of output buffer state. */
@@ -292,6 +294,7 @@ int audio_open (struct audio_s *pa)
292294

293295

294296
A->udp_sock = INVALID_SOCKET;
297+
A->udp_out_sock = INVALID_SOCKET;
295298

296299
in_dev_no[a] = WAVE_MAPPER; /* = ((UINT)-1) in mmsystem.h */
297300
out_dev_no[a] = WAVE_MAPPER;
@@ -349,8 +352,7 @@ int audio_open (struct audio_s *pa)
349352

350353
/*
351354
* 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.
354356
*/
355357
if (strcasecmp(pa->adev[a].adevice_out, "stdout") == 0 || strcmp(pa->adev[a].adevice_out, "-") == 0) {
356358
A->g_audio_out_type = AUDIO_OUT_TYPE_STDOUT;
@@ -361,6 +363,16 @@ int audio_open (struct audio_s *pa)
361363
}
362364
/* Change - to stdout for readability. */
363365
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+
}
364376
} else {
365377
A->g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD;
366378

@@ -524,7 +536,7 @@ int audio_open (struct audio_s *pa)
524536

525537
struct adev_s *A = &(adev[a]);
526538

527-
/* Display stdin or udp:port if appropriate. */
539+
/* Display stdout or udp:port if appropriate. */
528540

529541
if (A->g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD) {
530542

@@ -600,6 +612,71 @@ int audio_open (struct audio_s *pa)
600612
}
601613
A->out_current = 0;
602614

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+
603680
case AUDIO_OUT_TYPE_STDOUT:
604681

605682
setmode (STDOUT_FILENO, _O_BINARY);
@@ -1056,6 +1133,8 @@ int audio_put (int a, int c)
10561133
}
10571134
break;
10581135

1136+
1137+
case AUDIO_OUT_TYPE_SDR_UDP:
10591138
case AUDIO_OUT_TYPE_STDOUT:
10601139

10611140
A->stream_out_data[A->stream_out_next++] = c;
@@ -1095,6 +1174,10 @@ int audio_flush (int a)
10951174
WAVEHDR *p;
10961175
MMRESULT e;
10971176
struct adev_s *A;
1177+
int res;
1178+
char *ptr;
1179+
unsigned int len;
1180+
10981181

10991182
A = &(adev[a]);
11001183

@@ -1123,11 +1206,7 @@ int audio_flush (int a)
11231206
}
11241207
break;
11251208

1126-
case AUDIO_OUT_TYPE_STDOUT:;
1127-
1128-
int res;
1129-
unsigned char *ptr;
1130-
unsigned int len;
1209+
case AUDIO_OUT_TYPE_STDOUT:
11311210

11321211
ptr = A->stream_out_data;
11331212
len = A->stream_out_next;
@@ -1145,6 +1224,27 @@ int audio_flush (int a)
11451224

11461225
A->stream_out_next = 0;
11471226
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+
11481248
}
11491249
return (0);
11501250

0 commit comments

Comments
 (0)