diff --git a/src/dialogs/confdialog.cxx b/src/dialogs/confdialog.cxx index 6b6aec92..fd8bbe13 100644 --- a/src/dialogs/confdialog.cxx +++ b/src/dialogs/confdialog.cxx @@ -3922,25 +3922,43 @@ Fl_Tabs *tabsSoundCard=(Fl_Tabs *)0; Fl_Group *tabAudio=(Fl_Group *)0; -Fl_Group *AudioOSS=(Fl_Group *)0; +Fl_Group *AudioTCP=(Fl_Group *)0; static void cb_btnAudioIO(Fl_Round_Button*, void*) { - sound_update(SND_IDX_OSS); + sound_update(SND_IDX_TCP); progdefaults.changed = true; resetSoundCard(); } -Fl_Input_Choice *menuOSSDev=(Fl_Input_Choice *)0; +Fl_Input2 *inpIPServerHost=(Fl_Input2 *)0; -static void cb_menuOSSDev(Fl_Input_Choice* o, void*) { - scDevice[0] = scDevice[1] = progdefaults.OSSdevice = o->value(); -resetSoundCard(); +static void cb_inpIPServerHost(Fl_Input2* o, void*) { + scDevice[0] = progdefaults.IPServerHost = o->value(); progdefaults.changed = true; +resetSoundCard(); +} + +Fl_Input2 *inpIPServerPort=(Fl_Input2 *)0; + +static void cb_inpIPServerPort(Fl_Input2* o, void*) { + scDevice[0] = progdefaults.IPServerPort = o->value(); +progdefaults.changed = true; +resetSoundCard(); +} + +Fl_Group *AudioUDP=(Fl_Group *)0; + +Fl_Round_Button *btnAudioIO[5]={(Fl_Round_Button *)0}; + +static void cb_btnAudioIO1(Fl_Round_Button*, void*) { + sound_update(SND_IDX_UDP); +progdefaults.changed = true; +resetSoundCard(); } Fl_Group *AudioPort=(Fl_Group *)0; -static void cb_btnAudioIO1(Fl_Round_Button*, void*) { +static void cb_btnAudioIO2(Fl_Round_Button*, void*) { sound_update(SND_IDX_PORT); progdefaults.changed = true; resetSoundCard(); @@ -3966,7 +3984,7 @@ progdefaults.changed = true; Fl_Group *AudioPulse=(Fl_Group *)0; -static void cb_btnAudioIO2(Fl_Round_Button*, void*) { +static void cb_btnAudioIO3(Fl_Round_Button*, void*) { sound_update(SND_IDX_PULSE); progdefaults.changed = true; resetSoundCard(); @@ -3982,9 +4000,7 @@ progdefaults.changed = true; Fl_Group *AudioNull=(Fl_Group *)0; -Fl_Round_Button *btnAudioIO[4]={(Fl_Round_Button *)0}; - -static void cb_btnAudioIO3(Fl_Round_Button*, void*) { +static void cb_btnAudioIO4(Fl_Round_Button*, void*) { sound_update(SND_IDX_NULL); progdefaults.changed = true; resetSoundCard(); @@ -7949,7 +7965,7 @@ i on a\ntouch screen device such as a tablet.")); o->value(progdefaults.DOMINOEX_BW); o->labelsize(FL_NORMAL_SIZE); } // Fl_Counter2* valDominoEX_BW - { Fl_Counter2* o = valDominoEX_ADJ = new Fl_Counter2(156, 166, 63, 20, _("Tone-spacing adjust")); + { Fl_Counter2* o = valDominoEX_ADJ = new Fl_Counter2(206, 166, 63, 20, _("Tone-spacing adjust")); valDominoEX_ADJ->tooltip(_("Tone-spacing adjust")); valDominoEX_ADJ->type(1); valDominoEX_ADJ->box(FL_UP_BOX); @@ -9637,28 +9653,63 @@ definition")); { tabsSoundCard = new Fl_Tabs(0, 25, 600, 355); tabsSoundCard->selection_color(FL_LIGHT1); { tabAudio = new Fl_Group(0, 50, 600, 330, _("Devices")); - { AudioOSS = new Fl_Group(55, 65, 490, 45); - AudioOSS->box(FL_ENGRAVED_FRAME); - { btnAudioIO[0] = new Fl_Round_Button(65, 75, 53, 25, _("OSS")); - btnAudioIO[0]->tooltip(_("Use OSS audio server")); + { AudioTCP = new Fl_Group(55, 65, 380, 45); + AudioTCP->box(FL_ENGRAVED_FRAME); + { btnAudioIO[0] = new Fl_Round_Button(65, 75, 53, 25, _("TCP")); + btnAudioIO[0]->tooltip(_("Use TCP audio server")); btnAudioIO[0]->down_box(FL_DOWN_BOX); btnAudioIO[0]->selection_color((Fl_Color)1); btnAudioIO[0]->callback((Fl_Callback*)cb_btnAudioIO); } // Fl_Round_Button* btnAudioIO[0] - { Fl_Input_Choice* o = menuOSSDev = new Fl_Input_Choice(424, 75, 110, 25, _("Device:")); - menuOSSDev->tooltip(_("Select device")); - menuOSSDev->callback((Fl_Callback*)cb_menuOSSDev); - o->value(progdefaults.OSSdevice.c_str()); - } // Fl_Input_Choice* menuOSSDev - AudioOSS->end(); - } // Fl_Group* AudioOSS + { Fl_Input2* o = inpIPServerHost = new Fl_Input2(180, 75, 90, 25, _("Host:")); + inpIPServerHost->tooltip(_("TCP/UDP Server Host")); + inpIPServerHost->box(FL_DOWN_BOX); + inpIPServerHost->color(FL_BACKGROUND2_COLOR); + inpIPServerHost->selection_color(FL_SELECTION_COLOR); + inpIPServerHost->labeltype(FL_NORMAL_LABEL); + inpIPServerHost->labelfont(0); + inpIPServerHost->labelsize(14); + inpIPServerHost->labelcolor(FL_FOREGROUND_COLOR); + inpIPServerHost->callback((Fl_Callback*)cb_inpIPServerHost); + inpIPServerHost->align(Fl_Align(FL_ALIGN_LEFT)); + inpIPServerHost->when(FL_WHEN_RELEASE); + o->value(progdefaults.IPServerHost.c_str()); + inpIPServerHost->labelsize(FL_NORMAL_SIZE); + } // Fl_Input2* inpIPServerHost + { Fl_Input2* o = inpIPServerPort = new Fl_Input2(320, 75, 90, 25, _("Port:")); + inpIPServerPort->tooltip(_("TCP/UDP Server Port")); + inpIPServerPort->box(FL_DOWN_BOX); + inpIPServerPort->color(FL_BACKGROUND2_COLOR); + inpIPServerPort->selection_color(FL_SELECTION_COLOR); + inpIPServerPort->labeltype(FL_NORMAL_LABEL); + inpIPServerPort->labelfont(0); + inpIPServerPort->labelsize(14); + inpIPServerPort->labelcolor(FL_FOREGROUND_COLOR); + inpIPServerPort->callback((Fl_Callback*)cb_inpIPServerPort); + inpIPServerPort->align(Fl_Align(FL_ALIGN_LEFT)); + inpIPServerPort->when(FL_WHEN_RELEASE); + o->value(progdefaults.IPServerPort.c_str()); + inpIPServerPort->labelsize(FL_NORMAL_SIZE); + } // Fl_Input2* inpIPServerPort + AudioTCP->end(); + } // Fl_Group* AudioTCP + { AudioUDP = new Fl_Group(435, 65, 110, 45); + AudioUDP->box(FL_ENGRAVED_FRAME); + { btnAudioIO[4] = new Fl_Round_Button(450, 75, 53, 25, _("UDP")); + btnAudioIO[4]->tooltip(_("Use UDP audio server")); + btnAudioIO[4]->down_box(FL_DOWN_BOX); + btnAudioIO[4]->selection_color((Fl_Color)1); + btnAudioIO[4]->callback((Fl_Callback*)cb_btnAudioIO1); + } // Fl_Round_Button* btnAudioIO[4] + AudioUDP->end(); + } // Fl_Group* AudioUDP { AudioPort = new Fl_Group(55, 110, 490, 80); AudioPort->box(FL_ENGRAVED_FRAME); { btnAudioIO[1] = new Fl_Round_Button(65, 138, 95, 25, _("PortAudio")); btnAudioIO[1]->tooltip(_("Use Port Audio server")); btnAudioIO[1]->down_box(FL_DOWN_BOX); btnAudioIO[1]->selection_color((Fl_Color)1); - btnAudioIO[1]->callback((Fl_Callback*)cb_btnAudioIO1); + btnAudioIO[1]->callback((Fl_Callback*)cb_btnAudioIO2); } // Fl_Round_Button* btnAudioIO[1] { menuPortInDev = new Fl_Choice(244, 121, 290, 25, _("Capture:")); menuPortInDev->tooltip(_("Audio input device")); @@ -9678,7 +9729,7 @@ definition")); btnAudioIO[2]->tooltip(_("Use Pulse Audio server")); btnAudioIO[2]->down_box(FL_DOWN_BOX); btnAudioIO[2]->selection_color((Fl_Color)1); - btnAudioIO[2]->callback((Fl_Callback*)cb_btnAudioIO2); + btnAudioIO[2]->callback((Fl_Callback*)cb_btnAudioIO3); } // Fl_Round_Button* btnAudioIO[2] { Fl_Input2* o = inpPulseServer = new Fl_Input2(310, 201, 225, 24, _("Server string:")); inpPulseServer->tooltip(_("Leave this blank or refer to\nhttp://www.pulseaudio.org/wiki/ServerStrings")); @@ -9703,7 +9754,7 @@ definition")); btnAudioIO[3]->tooltip(_("NO AUDIO DEVICE AVAILABLE (or testing)")); btnAudioIO[3]->down_box(FL_DOWN_BOX); btnAudioIO[3]->selection_color((Fl_Color)1); - btnAudioIO[3]->callback((Fl_Callback*)cb_btnAudioIO3); + btnAudioIO[3]->callback((Fl_Callback*)cb_btnAudioIO4); } // Fl_Round_Button* btnAudioIO[3] AudioNull->end(); } // Fl_Group* AudioNull diff --git a/src/dialogs/confdialog.fl b/src/dialogs/confdialog.fl index c4599d35..79a0427e 100644 --- a/src/dialogs/confdialog.fl +++ b/src/dialogs/confdialog.fl @@ -3343,7 +3343,7 @@ progdefaults.changed = true;} callback {progdefaults.DOMINOEX_ADJ = o->value(); resetDOMEX(); progdefaults.changed = true;} - tooltip {Tone-spacing adjust} xywh {156 166 63 20} type Simple align 8 minimum -100 maximum 100 value 0 + tooltip {Tone-spacing adjust} xywh {206 166 63 20} type Simple align 8 minimum -100 maximum 100 value 0 code0 {o->value(progdefaults.DOMINOEX_ADJ);} code1 {o->labelsize(FL_NORMAL_SIZE);} class Fl_Counter2 @@ -4857,24 +4857,47 @@ when both in same macro definition} xywh {210 239 90 21} type Simple align 8 min label Devices open xywh {0 50 600 330} } { - Fl_Group AudioOSS {open - xywh {55 65 490 45} box ENGRAVED_FRAME + Fl_Group AudioTCP {open + xywh {55 65 380 45} box ENGRAVED_FRAME } { Fl_Round_Button {btnAudioIO[0]} { - label OSS - callback {sound_update(SND_IDX_OSS); + label TCP + callback {sound_update(SND_IDX_TCP); progdefaults.changed = true; resetSoundCard();} - tooltip {Use OSS audio server} xywh {65 75 53 25} down_box DOWN_BOX selection_color 1 + tooltip {Use TCP audio server} xywh {65 75 53 25} down_box DOWN_BOX selection_color 1 + } + Fl_Input inpIPServerHost { + label {Host:} + callback {scDevice[0] = progdefaults.IPServerHost = o->value(); +progdefaults.changed = true; +resetSoundCard();} + tooltip {TCP/UDP Server Host} xywh {180 75 90 25} + code0 {o->value(progdefaults.IPServerHost.c_str());} + code1 {inpIPServerHost->labelsize(FL_NORMAL_SIZE);} + class Fl_Input2 + } + Fl_Input inpIPServerPort { + label {Port:} + callback {scDevice[0] = progdefaults.IPServerPort = o->value(); +progdefaults.changed = true; +resetSoundCard();} + tooltip {TCP/UDP Server Port} xywh {320 75 90 25} + code0 {o->value(progdefaults.IPServerPort.c_str());} + code1 {inpIPServerPort->labelsize(FL_NORMAL_SIZE);} + class Fl_Input2 + } + } + Fl_Group AudioUDP {open + xywh {435 65 110 45} box ENGRAVED_FRAME + } { + Fl_Round_Button {btnAudioIO[4]} { + label UDP + callback {sound_update(SND_IDX_UDP); +progdefaults.changed = true; +resetSoundCard();} + tooltip {Use UDP audio server} xywh {450 75 53 25} down_box DOWN_BOX selection_color 1 } - Fl_Input_Choice menuOSSDev { - label {Device:} - callback {scDevice[0] = scDevice[1] = progdefaults.OSSdevice = o->value(); -resetSoundCard(); -progdefaults.changed = true;} open - tooltip {Select device} xywh {424 75 110 25} - code0 {o->value(progdefaults.OSSdevice.c_str());} - } {} } Fl_Group AudioPort {open xywh {55 110 490 80} box ENGRAVED_FRAME diff --git a/src/dialogs/confdialog.h b/src/dialogs/confdialog.h index 468ad2ef..361cae55 100644 --- a/src/dialogs/confdialog.h +++ b/src/dialogs/confdialog.h @@ -460,16 +460,17 @@ extern Fl_Counter *mbw_delay; extern Fl_Group *tabSoundCard; extern Fl_Tabs *tabsSoundCard; extern Fl_Group *tabAudio; -extern Fl_Group *AudioOSS; -#include -extern Fl_Input_Choice *menuOSSDev; +extern Fl_Group *AudioTCP; +extern Fl_Input2 *inpIPServerHost; +extern Fl_Input2 *inpIPServerPort; +extern Fl_Group *AudioUDP; +extern Fl_Round_Button *btnAudioIO[5]; extern Fl_Group *AudioPort; extern Fl_Choice *menuPortInDev; extern Fl_Choice *menuPortOutDev; extern Fl_Group *AudioPulse; extern Fl_Input2 *inpPulseServer; extern Fl_Group *AudioNull; -extern Fl_Round_Button *btnAudioIO[4]; extern Fl_Group *tabAudioOpt; extern Fl_Group *grpAudioSampleRate; extern Fl_ListBox *menuInSampleRate; @@ -591,6 +592,7 @@ extern Fl_Counter2 *cntTrackFreqMax; #include extern Fl_Float_Input *stationary_lat; extern Fl_Float_Input *stationary_lon; +#include extern Fl_Input_Choice *inpGPSdev; #include extern Fl_Output *gps_pos_lat; diff --git a/src/include/confdialog.h b/src/include/confdialog.h index c0bc3962..f3375850 100644 --- a/src/include/confdialog.h +++ b/src/include/confdialog.h @@ -462,16 +462,17 @@ extern Fl_Counter *mbw_delay; extern Fl_Group *tabSoundCard; extern Fl_Tabs *tabsSoundCard; extern Fl_Group *tabAudio; -extern Fl_Group *AudioOSS; +extern Fl_Group *AudioIP; +extern Fl_Input2 *inpIPServerHost; +extern Fl_Input2 *inpIPServerPort; #include -extern Fl_Input_Choice *menuOSSDev; extern Fl_Group *AudioPort; extern Fl_Choice *menuPortInDev; extern Fl_Choice *menuPortOutDev; extern Fl_Group *AudioPulse; extern Fl_Input2 *inpPulseServer; extern Fl_Group *AudioNull; -extern Fl_Round_Button *btnAudioIO[4]; +extern Fl_Round_Button *btnAudioIO[5]; extern Fl_Group *tabAudioOpt; extern Fl_Group *grpAudioSampleRate; extern Fl_ListBox *menuInSampleRate; diff --git a/src/include/configuration.h b/src/include/configuration.h index 74596844..5280ab3b 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -1019,11 +1019,17 @@ /* Sound card */ \ ELEM_(int, btnAudioIOis, "AUDIOIO", \ "Audio subsystem. Values are as follows:\n" \ - " 0: OSS; 1: PortAudio; 2: PulseAudio; 3: File I/O", \ + " 0: TCP; 1: PortAudio; 2: PulseAudio; 3: File I/O", \ SND_IDX_NULL) \ ELEM_(std::string, OSSdevice, "OSSDEVICE", \ "OSS device name", \ "") \ + ELEM_(std::string, IPServerHost, "IPHOST", \ + "IP stream host", \ + "localhost") \ + ELEM_(std::string, IPServerPort, "IPPORT", \ + "IP stream port", \ + "7355") \ ELEM_(std::string, PAdevice, "PADEVICE", \ "For compatibility with older versions", \ "") \ diff --git a/src/include/sound.h b/src/include/sound.h index fb1d2887..4660d5a7 100644 --- a/src/include/sound.h +++ b/src/include/sound.h @@ -30,6 +30,7 @@ #include #include #include +#include #if USE_SNDFILE # include @@ -349,4 +350,38 @@ public: void flush(unsigned) { } }; + +class SoundIP : public SoundBase +{ +public: + SoundIP(const char* host="", const char* port="9999", bool udp_flag=false); + ~SoundIP(); + + int Open(int mode, int freq = 8000); + void Close(unsigned); + void Abort(unsigned); + size_t Write(double* buf, size_t count); + size_t Write_stereo(double* bufleft, double* bufright, size_t count); + size_t Read(float *buf, size_t count); + bool must_close(int dir = 0) { return false; } + void flush(unsigned) { } +private: + void readport(); + int remote_connect(const char *, const char *, struct addrinfo); + int timeout_connect(int, const struct sockaddr *, socklen_t); + int getstream(); + void closestream(); + int readstream(uint8_t *buffer); + + int portmode_udp; + int resamplerate; + int stream; + bool udp_connected; + const char *m_host, *m_port; + + int buffptr, buffend; + uint8_t *cbuff; + float *snd_buffer; + float m_step; +}; #endif // SOUND_H diff --git a/src/include/soundconf.h b/src/include/soundconf.h index d0459649..2519442d 100644 --- a/src/include/soundconf.h +++ b/src/include/soundconf.h @@ -21,8 +21,8 @@ #ifndef SOUNDCONF_H #define SOUNDCONF_H -enum { SND_IDX_UNKNOWN = -1, SND_IDX_OSS, SND_IDX_PORT, - SND_IDX_PULSE, SND_IDX_NULL, SND_IDX_END +enum { SND_IDX_UNKNOWN = -1, SND_IDX_TCP, SND_IDX_PORT, + SND_IDX_PULSE, SND_IDX_NULL, SND_IDX_UDP, SND_IDX_END }; enum { diff --git a/src/soundcard/netcat.c b/src/soundcard/netcat.c new file mode 100644 index 00000000..6c0a4269 --- /dev/null +++ b/src/soundcard/netcat.c @@ -0,0 +1,188 @@ +/* $OpenBSD: netcat.c,v 1.103 2011/10/04 08:34:34 fgsch Exp $ */ +/* + * Copyright (c) 2001 Eric Jackson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Re-written nc(1) for OpenBSD. Original implementation by + * *Hobbit* . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int SoundIP::getstream() +{ + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = portmode_udp ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = portmode_udp ? IPPROTO_UDP : IPPROTO_TCP; + + if (portmode_udp) { + hints.ai_flags = AI_PASSIVE; + udp_connected = false; + stream = remote_connect(NULL, m_port, hints); + } else + stream = remote_connect(m_host, m_port, hints); + return stream; +} + +void SoundIP::closestream() +{ + if (stream >= 0) + close(stream); + stream = -1; +} + +/* + * remote_connect() + * Returns a socket connected to a remote host. Properly binds to a local + * port or source address if needed. Returns -1 on failure. + */ +int +SoundIP::remote_connect(const char *host, const char *port, struct addrinfo hints) +{ + struct addrinfo *res, *res0; + int s, x, ret; + + if ( getaddrinfo(host, port, &hints, &res) ) + return -1; + + res0 = res; + do { + if ((s = socket(res0->ai_family, res0->ai_socktype, + res0->ai_protocol)) < 0) + continue; + + if (portmode_udp) { + x = 1; + ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x)); + if (ret > -1) + if (bind(s, (struct sockaddr *)res0->ai_addr, res0->ai_addrlen) == 0) + break; + } else { + if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) + break; + } + + close(s); + s = -1; + } while ((res0 = res0->ai_next) != NULL); + + freeaddrinfo(res); + + return (s); +} + +int +SoundIP::timeout_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ + struct pollfd pfd; + socklen_t optlen; + int ret, optval; + + if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { + pfd.fd = s; + pfd.events = POLLOUT; + if ((ret = poll(&pfd, 1, -1)) == 1) { + optlen = sizeof(optval); + if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, + &optval, &optlen)) == 0) { + ret = optval == 0 ? 0 : -1; + } + } else + return -1; + } + + return (ret); +} + +/* + * readport() + * Loop that polls on the network file descriptor + */ +int +SoundIP::readstream(uint8_t *buffer) +{ + struct pollfd pfd; + int n, plen, rv; + struct sockaddr_storage z; + socklen_t len = sizeof(z); + + plen = 4096; + + if (stream < 0) + return 0; + + if (portmode_udp) { + rv = recvfrom(stream, buffer, plen, MSG_PEEK | MSG_DONTWAIT, (struct sockaddr *)&z, &len); + if (rv < 0) + return 0; + //rv = connect(stream, (struct sockaddr *)&z, len); + //udp_connected = true; + return ( read(stream, buffer, plen) ); + } + + /* Setup Network FD */ + pfd.fd = stream; + pfd.events = POLLIN; + + n = poll(&pfd, 1, -1); + if (n <= 0) { + closestream(); + return n; + } + + if (pfd.revents & POLLIN) { + n = read(stream, buffer, plen); + if (n == 0) { + closestream(); + } + } else + n = 0; + return n; +} diff --git a/src/soundcard/sound.cxx b/src/soundcard/sound.cxx index 609dcdbb..8b5f1b9d 100644 --- a/src/soundcard/sound.cxx +++ b/src/soundcard/sound.cxx @@ -2238,3 +2238,117 @@ size_t SoundNull::Read(float *buf, size_t count) return count; } + +#include "netcat.c" +SoundIP::SoundIP(const char* inithost, const char* initport, bool udp_flag) +{ + stream = -1; + m_host = inithost; + m_port = initport; + portmode_udp = udp_flag; + udp_connected = false; + + snd_buffer = new float[SND_BUF_LEN]; // floats out for fldigi + cbuff = new uint8_t[SND_BUF_LEN]; // 64K, max tcp/ip packet size + buffend = buffptr = 0; +} + +SoundIP::~SoundIP() +{ + SoundIP::closestream(); + + delete [] snd_buffer; + delete [] cbuff; +} + +int SoundIP::Open(int mode, int freq) +{ + resamplerate = freq; + m_step = 0.0; + + if (stream < 0) + SoundIP::getstream(); + return 0; +} + +void SoundIP::Close(unsigned unused) +{ + SoundIP::closestream(); +} + +void SoundIP::Abort(unsigned unused) +{ + SoundIP::closestream(); +} + +size_t SoundIP::Write(double* buf, size_t count) +{ + return count; +} + +size_t SoundIP::Write_stereo(double* bufleft, double* bufright, size_t count) +{ + return count; +} + +size_t SoundIP::Read(float *buff, size_t count) +{ + int n, s, out, rate, idlecount; + unsigned i, j, c; + float ratio; + + rate = progdefaults.in_sample_rate; + if (rate < 8000) + rate = 48000; // unset / native default + ratio = 1.0 * rate / resamplerate; + + if (stream < 0) { + // keep trying to open stream + MilliSleep(1000); + SoundIP::getstream(); + for (i = 0; i < count; i++) + buff[i] = 0.0f; + return count; + } + + idlecount = 10; + out = 0; + c = count; + for (;;) { + i = buffend - buffptr; + if ( i > c ) + i = c; + if ( i > 0) { + for ( j = 0; j < i; j++) + buff[out + j] = snd_buffer[buffptr + j]; + } + buffptr += i; + out += i; + c -= i; + if ( 0 == c) + return count; + + n = readstream(cbuff); + if (n <= 0) { + MilliSleep(100); + if (--idlecount < 0) { + for (i = 0; i < count; i++) + buff[i] = 0.0f; + return count; + } + } + + buffend = buffptr = 0; + // S16LE to float, resampled + for (s = 0; s * 2 < n; s++) { + m_step = m_step - 1.0; + if (m_step < 0) { + short s16le = cbuff[2*s] | ( cbuff[2*s+1] << 8); + snd_buffer[buffend++] = (1.0 / 32768) * s16le; + m_step += ratio; + } + } + } + return count; +} + diff --git a/src/soundcard/soundconf.cxx b/src/soundcard/soundconf.cxx index f43d4948..6dc6a257 100644 --- a/src/soundcard/soundconf.cxx +++ b/src/soundcard/soundconf.cxx @@ -304,7 +304,7 @@ static void sound_init_options(void) } } - menuOSSDev->value(progdefaults.OSSdevice.c_str()); + //menuOSSDev->value(progdefaults.OSSdevice.c_str()); inpPulseServer->value(progdefaults.PulseServer.c_str()); char sr[6+1]; @@ -389,7 +389,7 @@ void sound_init(void) init_portaudio(); // set the Sound Card configuration tab to the correct initial values -#if !USE_OSS +#if 0 AudioOSS->deactivate(); btnAudioIO[SND_IDX_OSS]->deactivate(); #endif @@ -403,7 +403,7 @@ void sound_init(void) #endif if (progdefaults.btnAudioIOis == SND_IDX_UNKNOWN || !btnAudioIO[progdefaults.btnAudioIOis]->active()) { // or saved sound api now disabled - int io[4] = { SND_IDX_PORT, SND_IDX_PULSE, SND_IDX_OSS, SND_IDX_NULL }; + int io[5] = { SND_IDX_PORT, SND_IDX_PULSE, SND_IDX_NULL, SND_IDX_TCP, SND_IDX_UDP }; if (probe_pulseaudio()) { // prefer pulseaudio io[0] = SND_IDX_PULSE; io[1] = SND_IDX_PORT; @@ -419,7 +419,6 @@ void sound_init(void) sound_init_options(); sound_update(progdefaults.btnAudioIOis); - } void sound_close(void) @@ -436,10 +435,12 @@ void sound_update(unsigned idx) btnAudioIO[i]->value(i == idx); // devices - menuOSSDev->deactivate(); + //menuOSSDev->deactivate(); menuPortInDev->deactivate(); menuPortOutDev->deactivate(); inpPulseServer->deactivate(); + inpIPServerHost->deactivate(); + inpIPServerPort->deactivate(); // settings menuInSampleRate->deactivate(); @@ -447,7 +448,18 @@ void sound_update(unsigned idx) progdefaults.btnAudioIOis = idx; switch (idx) { -#if USE_OSS + case SND_IDX_TCP: + inpIPServerHost->activate(); + if (inpIPServerHost->value()) + scDevice[0] = inpIPServerHost->value(); + //no break; + case SND_IDX_UDP: + inpIPServerPort->activate(); + if (inpIPServerPort->value()) + scDevice[1] = inpIPServerPort->value(); + menuInSampleRate->activate(); + break; +#if 0 case SND_IDX_OSS: menuOSSDev->activate(); scDevice[0] = scDevice[1] = menuOSSDev->value(); diff --git a/src/trx/trx.cxx b/src/trx/trx.cxx index b385ea8e..c4385a47 100644 --- a/src/trx/trx.cxx +++ b/src/trx/trx.cxx @@ -570,6 +570,13 @@ void trx_reset_loop() } switch (progdefaults.btnAudioIOis) { + + case SND_IDX_UDP: + scard = new SoundIP(scDevice[0].c_str(), scDevice[1].c_str(), true); + break; + case SND_IDX_TCP: + scard = new SoundIP(scDevice[0].c_str(), scDevice[1].c_str(), false); + break; #if USE_OSS case SND_IDX_OSS: scard = new SoundOSS(scDevice[0].c_str()); @@ -618,6 +625,13 @@ void trx_start(void) switch (progdefaults.btnAudioIOis) { + + case SND_IDX_UDP: + scard = new SoundIP(scDevice[0].c_str(), scDevice[1].c_str(), true); + break; + case SND_IDX_TCP: + scard = new SoundIP(scDevice[0].c_str(), scDevice[1].c_str(), false); + break; #if USE_OSS case SND_IDX_OSS: scard = new SoundOSS(scDevice[0].c_str());