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