mirror of https://github.com/wb2osz/direwolf.git
Add UDP audio output for Windows
This commit is contained in:
parent
81fe3a0643
commit
7982134983
122
src/audio_win.c
122
src/audio_win.c
|
@ -147,11 +147,13 @@ static struct adev_s {
|
||||||
int stream_next;
|
int stream_next;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buffer and index for stdout.
|
* UDP socket for transmitting audio stream.
|
||||||
|
* Buffer and index for stdout or UDP.
|
||||||
*/
|
*/
|
||||||
|
SOCKET udp_out_sock;
|
||||||
unsigned char stream_out_data[SDR_UDP_BUF_MAXLEN];
|
char stream_out_data[SDR_UDP_BUF_MAXLEN];
|
||||||
int stream_out_next;
|
int stream_out_next;
|
||||||
|
struct sockaddr_storage udp_dest_addr;
|
||||||
|
|
||||||
/* For sound output. */
|
/* For sound output. */
|
||||||
/* out_wavehdr.dwUser is used to keep track of output buffer state. */
|
/* out_wavehdr.dwUser is used to keep track of output buffer state. */
|
||||||
|
@ -292,6 +294,7 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
|
|
||||||
A->udp_sock = INVALID_SOCKET;
|
A->udp_sock = INVALID_SOCKET;
|
||||||
|
A->udp_out_sock = INVALID_SOCKET;
|
||||||
|
|
||||||
in_dev_no[a] = WAVE_MAPPER; /* = ((UINT)-1) in mmsystem.h */
|
in_dev_no[a] = WAVE_MAPPER; /* = ((UINT)-1) in mmsystem.h */
|
||||||
out_dev_no[a] = WAVE_MAPPER;
|
out_dev_no[a] = WAVE_MAPPER;
|
||||||
|
@ -349,8 +352,7 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Select output device.
|
* Select output device.
|
||||||
* Only soundcard and stdout at this point.
|
* Soundcard, UDP, and stdout supported.
|
||||||
* Purhaps we'd like to add UDP for an SDR transmitter.
|
|
||||||
*/
|
*/
|
||||||
if (strcasecmp(pa->adev[a].adevice_out, "stdout") == 0 || strcmp(pa->adev[a].adevice_out, "-") == 0) {
|
if (strcasecmp(pa->adev[a].adevice_out, "stdout") == 0 || strcmp(pa->adev[a].adevice_out, "-") == 0) {
|
||||||
A->g_audio_out_type = AUDIO_OUT_TYPE_STDOUT;
|
A->g_audio_out_type = AUDIO_OUT_TYPE_STDOUT;
|
||||||
|
@ -361,6 +363,16 @@ int audio_open (struct audio_s *pa)
|
||||||
}
|
}
|
||||||
/* Change - to stdout for readability. */
|
/* Change - to stdout for readability. */
|
||||||
strlcpy (pa->adev[a].adevice_out, "stdout", sizeof(pa->adev[a].adevice_out));
|
strlcpy (pa->adev[a].adevice_out, "stdout", sizeof(pa->adev[a].adevice_out));
|
||||||
|
} else if (strncasecmp(pa->adev[a].adevice_out, "udp:", 4) == 0) {
|
||||||
|
A->g_audio_out_type = AUDIO_OUT_TYPE_SDR_UDP;
|
||||||
|
// User must supply address and port
|
||||||
|
if (strcasecmp(pa->adev[a].adevice_out, "udp:") == 0 ||
|
||||||
|
strlen(pa->adev[a].adevice_out) < 7 ||
|
||||||
|
strstr(pa->adev[a].adevice_out+5, ":") == 0) {
|
||||||
|
text_color_set (DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Destination address and port must be supplied for UDP output\n");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
A->g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD;
|
A->g_audio_out_type = AUDIO_OUT_TYPE_SOUNDCARD;
|
||||||
|
|
||||||
|
@ -524,7 +536,7 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
struct adev_s *A = &(adev[a]);
|
struct adev_s *A = &(adev[a]);
|
||||||
|
|
||||||
/* Display stdin or udp:port if appropriate. */
|
/* Display stdout or udp:port if appropriate. */
|
||||||
|
|
||||||
if (A->g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD) {
|
if (A->g_audio_out_type != AUDIO_OUT_TYPE_SOUNDCARD) {
|
||||||
|
|
||||||
|
@ -600,6 +612,71 @@ int audio_open (struct audio_s *pa)
|
||||||
}
|
}
|
||||||
A->out_current = 0;
|
A->out_current = 0;
|
||||||
|
|
||||||
|
case AUDIO_OUT_TYPE_SDR_UDP:;
|
||||||
|
|
||||||
|
WSADATA wsadata;
|
||||||
|
struct addrinfo ai_out;
|
||||||
|
struct addrinfo *ai_res;
|
||||||
|
char udp_outhost[256];
|
||||||
|
char *udp_outport;
|
||||||
|
int err, res;
|
||||||
|
|
||||||
|
err = WSAStartup (MAKEWORD(2,2), &wsadata);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("WSAStartup failed: %d\n", err);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Could not find a usable version of Winsock.dll\n");
|
||||||
|
WSACleanup();
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((char *) &ai_out, 0, sizeof(ai_out));
|
||||||
|
ai_out.ai_socktype = SOCK_DGRAM;
|
||||||
|
ai_out.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
strncpy(udp_outhost, pa->adev[a].adevice_out + 4, 255);
|
||||||
|
udp_outhost[255] = 0;
|
||||||
|
udp_outport = strstr(udp_outhost, ":");
|
||||||
|
*udp_outport++ = 0;
|
||||||
|
|
||||||
|
if (strlen(udp_outport) == 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("UDP output destination port must be supplied\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = getaddrinfo(udp_outhost, udp_outport, &ai_out, &ai_res);
|
||||||
|
if (err != 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Error parsing/resolving UDP output address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ai_res->ai_family == AF_INET6) {
|
||||||
|
res = sizeof(struct sockaddr_in6);
|
||||||
|
} else {
|
||||||
|
res = sizeof(struct sockaddr_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create UDP Socket
|
||||||
|
|
||||||
|
A->udp_out_sock = socket(ai_res->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (A->udp_out_sock == INVALID_SOCKET) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Couldn't create socket, errno %d\n", WSAGetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&A->udp_dest_addr, ai_res->ai_addr, res);
|
||||||
|
A->stream_out_next = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case AUDIO_OUT_TYPE_STDOUT:
|
case AUDIO_OUT_TYPE_STDOUT:
|
||||||
|
|
||||||
setmode (STDOUT_FILENO, _O_BINARY);
|
setmode (STDOUT_FILENO, _O_BINARY);
|
||||||
|
@ -1056,6 +1133,8 @@ int audio_put (int a, int c)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case AUDIO_OUT_TYPE_SDR_UDP:
|
||||||
case AUDIO_OUT_TYPE_STDOUT:
|
case AUDIO_OUT_TYPE_STDOUT:
|
||||||
|
|
||||||
A->stream_out_data[A->stream_out_next++] = c;
|
A->stream_out_data[A->stream_out_next++] = c;
|
||||||
|
@ -1095,6 +1174,10 @@ int audio_flush (int a)
|
||||||
WAVEHDR *p;
|
WAVEHDR *p;
|
||||||
MMRESULT e;
|
MMRESULT e;
|
||||||
struct adev_s *A;
|
struct adev_s *A;
|
||||||
|
int res;
|
||||||
|
char *ptr;
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
|
||||||
A = &(adev[a]);
|
A = &(adev[a]);
|
||||||
|
|
||||||
|
@ -1123,11 +1206,7 @@ int audio_flush (int a)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_OUT_TYPE_STDOUT:;
|
case AUDIO_OUT_TYPE_STDOUT:
|
||||||
|
|
||||||
int res;
|
|
||||||
unsigned char *ptr;
|
|
||||||
unsigned int len;
|
|
||||||
|
|
||||||
ptr = A->stream_out_data;
|
ptr = A->stream_out_data;
|
||||||
len = A->stream_out_next;
|
len = A->stream_out_next;
|
||||||
|
@ -1145,6 +1224,27 @@ int audio_flush (int a)
|
||||||
|
|
||||||
A->stream_out_next = 0;
|
A->stream_out_next = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AUDIO_OUT_TYPE_SDR_UDP:
|
||||||
|
|
||||||
|
ptr = A->stream_out_data;
|
||||||
|
len = A->stream_out_next;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
res = sendto(A->udp_out_sock, ptr, len, 0, (struct sockaddr *)&A->udp_dest_addr, sizeof(struct sockaddr_storage));
|
||||||
|
if (res < 0) {
|
||||||
|
text_color_set (DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Error %d writing to UDP socket.\n", res);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += res;
|
||||||
|
len -= res;
|
||||||
|
}
|
||||||
|
|
||||||
|
A->stream_out_next = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue