mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2024-11-21 19:55:17 -05:00
update
This commit is contained in:
parent
46faf838bc
commit
43cea876bb
@ -3,7 +3,7 @@ The purpose of this project is to transfer data (pictures...) via a 2,7kHz SSB c
|
|||||||
Now also including RTTY mode.
|
Now also including RTTY mode.
|
||||||
|
|
||||||
# this is work in progress
|
# this is work in progress
|
||||||
Version 0.64
|
Version 0.72
|
||||||
Windows 10 (should work on Win7, not tested)
|
Windows 10 (should work on Win7, not tested)
|
||||||
linux Desktop PC,
|
linux Desktop PC,
|
||||||
Odroid SBC
|
Odroid SBC
|
||||||
@ -18,7 +18,7 @@ Raspberry 4 (3B+)
|
|||||||
* Odroid C2 ... working
|
* Odroid C2 ... working
|
||||||
* Odroid C4 ... working
|
* Odroid C4 ... working
|
||||||
|
|
||||||
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required
|
* Raspberry: Raspian OS ist NOT working, instead Ubuntu 64bit is required. Or use the Beta Rapi-IO-64bit
|
||||||
|
|
||||||
* Application Software "oscardata.exe" running on Windows, Linux, (possibly MAC-OS, not tested)
|
* Application Software "oscardata.exe" running on Windows, Linux, (possibly MAC-OS, not tested)
|
||||||
|
|
||||||
@ -29,11 +29,12 @@ this software uses these programs:
|
|||||||
* libsoundio: https://github.com/andrewrk/libsoundio (MIT License)
|
* libsoundio: https://github.com/andrewrk/libsoundio (MIT License)
|
||||||
* fftw3: http://www.fftw.org (GPL V.2 or later)
|
* fftw3: http://www.fftw.org (GPL V.2 or later)
|
||||||
* libcodec2: https://github.com/drowe67/codec2 (LGPL 2.1, Linux: standard lib, Windows: from freeDV)
|
* libcodec2: https://github.com/drowe67/codec2 (LGPL 2.1, Linux: standard lib, Windows: from freeDV)
|
||||||
|
* portaudio: https://github.com/PortAudio/portaudio
|
||||||
|
|
||||||
# Download alternatives
|
# Download alternatives
|
||||||
* download from github and build from source
|
* download from github and build from source
|
||||||
* download windows installer and download Odroid and Raspberry images:
|
* download windows installer and download Odroid and Raspberry images:
|
||||||
https://dj0abr.de/german/technik/sat/modem/images.htm
|
https://hsmodem.dj0abr.de (Download section)
|
||||||
|
|
||||||
|
|
||||||
# building the software for Linux
|
# building the software for Linux
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -760,8 +760,8 @@ item: Install File
|
|||||||
Flags=0000000010000010
|
Flags=0000000010000010
|
||||||
end
|
end
|
||||||
item: Install File
|
item: Install File
|
||||||
Source=c:\tmp\WinRelease\libsoundio.dll
|
Source=c:\tmp\WinRelease\portaudio_x86.dll
|
||||||
Destination=%MAINDIR%\libsoundio.dll
|
Destination=%MAINDIR%\portaudio_x86.dll
|
||||||
Flags=0000000010000010
|
Flags=0000000010000010
|
||||||
end
|
end
|
||||||
item: Install File
|
item: Install File
|
||||||
|
@ -29,4 +29,5 @@ default: $(OBJ)
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o
|
rm -f *.o
|
||||||
|
rm -f libkmaudio/*.o
|
||||||
|
rm -f libkmaudio/*.o
|
||||||
|
@ -92,7 +92,6 @@ void playAudioPCM(char* fn, int destination)
|
|||||||
{
|
{
|
||||||
int to = 4000;
|
int to = 4000;
|
||||||
int res;
|
int res;
|
||||||
//while ((res = io_ls_fifo_usedspace()) > 10000)
|
|
||||||
while ((res = io_fifo_usedspace(voice_pbidx)) > 10000)
|
while ((res = io_fifo_usedspace(voice_pbidx)) > 10000)
|
||||||
{
|
{
|
||||||
if (--to == 0)
|
if (--to == 0)
|
||||||
|
@ -88,14 +88,18 @@ int marker = 1;
|
|||||||
int init_voice_result = 0;
|
int init_voice_result = 0;
|
||||||
|
|
||||||
// number of audio device in libkmaudio
|
// number of audio device in libkmaudio
|
||||||
int io_capidx = 0;
|
int io_capidx = -1;
|
||||||
int io_pbidx = 0;
|
int io_pbidx = -1;
|
||||||
int voice_capidx = 0;
|
int voice_capidx = -1;
|
||||||
int voice_pbidx = 0;
|
int voice_pbidx = -1;
|
||||||
|
|
||||||
int safemode = 0;
|
int safemode = 0;
|
||||||
int sendIntro = 0;
|
int sendIntro = 0;
|
||||||
|
|
||||||
|
char mycallsign[21];
|
||||||
|
char myqthloc[11];
|
||||||
|
char myname[21];
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int opt = 0;
|
int opt = 0;
|
||||||
@ -239,7 +243,7 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
// loop voice mic to LS, and record into PCM file
|
// loop voice mic to LS, and record into PCM file
|
||||||
float f[1100];
|
float f[1100];
|
||||||
while (1)
|
while (keeprunning)
|
||||||
{
|
{
|
||||||
int anz = kmaudio_readsamples(voice_capidx, f, 1000, micvol,0);
|
int anz = kmaudio_readsamples(voice_capidx, f, 1000, micvol,0);
|
||||||
if (anz > 0)
|
if (anz > 0)
|
||||||
@ -324,7 +328,8 @@ typedef struct {
|
|||||||
} SPEEDRATE;
|
} SPEEDRATE;
|
||||||
|
|
||||||
// AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, Codec-Rate
|
// AudioRate, TX-Resampler, RX-Resampler/4, bit/symbol, Codec-Rate
|
||||||
SPEEDRATE sr[11] = {
|
#define NUMSPEEDMODES 11
|
||||||
|
SPEEDRATE sr[NUMSPEEDMODES] = {
|
||||||
// BPSK modes
|
// BPSK modes
|
||||||
{48000, 40,10, 1, 1200, 800},
|
{48000, 40,10, 1, 1200, 800},
|
||||||
{48000, 20, 5, 1, 2400, 2000},
|
{48000, 20, 5, 1, 2400, 2000},
|
||||||
@ -351,6 +356,8 @@ void startModem()
|
|||||||
close_dsp();
|
close_dsp();
|
||||||
close_rtty();
|
close_rtty();
|
||||||
speedmode = set_speedmode;
|
speedmode = set_speedmode;
|
||||||
|
if (speedmode < 0 || speedmode >= NUMSPEEDMODES)
|
||||||
|
speedmode = 4;
|
||||||
|
|
||||||
bitsPerSymbol = sr[speedmode].bpsym;
|
bitsPerSymbol = sr[speedmode].bpsym;
|
||||||
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
|
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
|
||||||
@ -398,12 +405,32 @@ void initVoice()
|
|||||||
float f = 0.0f;
|
float f = 0.0f;
|
||||||
io_saveStream(&f, 1); // close recording
|
io_saveStream(&f, 1); // close recording
|
||||||
close_voiceproc();
|
close_voiceproc();
|
||||||
|
close_stream(voice_capidx);
|
||||||
|
close_stream(voice_pbidx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int srate = VOICE_SAMPRATE;
|
||||||
voice_capidx = kmaudio_startCapture(micDeviceName, VOICE_SAMPRATE);
|
|
||||||
voice_pbidx = kmaudio_startPlayback(lsDeviceName, VOICE_SAMPRATE);
|
// voice always runs with 48000 with one exception:
|
||||||
|
// if it is used for monitoring only and the digital audio
|
||||||
|
// stream runs with 44100, then also the monitoring voice audio
|
||||||
|
// must runs with 44100
|
||||||
|
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN && caprate == 44100)
|
||||||
|
srate = 44100;
|
||||||
|
|
||||||
|
voice_capidx = kmaudio_startCapture(micDeviceName, srate);
|
||||||
|
if (voice_capidx == -1)
|
||||||
|
{
|
||||||
|
printf("Voice CAP: cannot open device: %s\n", micDeviceName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
voice_pbidx = kmaudio_startPlayback(lsDeviceName, srate);
|
||||||
|
if (voice_pbidx == -1)
|
||||||
|
{
|
||||||
|
printf("Voice PB: cannot open device: %s\n", lsDeviceName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
init_voiceproc();
|
init_voiceproc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,12 +466,27 @@ void io_setAudioDevices(uint8_t pbvol, uint8_t capvol, uint8_t announce, uint8_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t *getDevList(int* plen)
|
||||||
|
{
|
||||||
|
uint8_t* txdata = io_getAudioDevicelist(plen);
|
||||||
|
txdata[0] = 3; // ID of this UDP message
|
||||||
|
|
||||||
|
txdata[1] = (io_capidx != -1 && devlist[io_capidx].working) ? '1' : '0';
|
||||||
|
txdata[2] = (io_pbidx != -1 && devlist[io_pbidx].working) ? '1' : '0';
|
||||||
|
txdata[3] = (voice_capidx != -1 && devlist[voice_capidx].working) ? '1' : '0';
|
||||||
|
txdata[4] = (voice_pbidx != -1 && devlist[voice_pbidx].working) ? '1' : '0';
|
||||||
|
|
||||||
|
return txdata;
|
||||||
|
}
|
||||||
|
|
||||||
// called from UDP RX thread for Broadcast-search from App
|
// called from UDP RX thread for Broadcast-search from App
|
||||||
void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||||
{
|
{
|
||||||
|
|
||||||
static uint64_t lastms = 0; // time of last received BC message
|
static uint64_t lastms = 0; // time of last received BC message
|
||||||
uint64_t actms = getms();
|
uint64_t actms = getms();
|
||||||
|
|
||||||
|
|
||||||
if (len > 0 && pdata[0] == 0x3c)
|
if (len > 0 && pdata[0] == 0x3c)
|
||||||
{
|
{
|
||||||
/* searchmodem message received
|
/* searchmodem message received
|
||||||
@ -462,6 +504,9 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
* 9 ... unused
|
* 9 ... unused
|
||||||
* 10 .. 109 ... PB device name
|
* 10 .. 109 ... PB device name
|
||||||
* 110 .. 209 ... CAP device name
|
* 110 .. 209 ... CAP device name
|
||||||
|
* 210 .. 229 ... Callsign
|
||||||
|
* 230 .. 239 ... qthloc
|
||||||
|
* 240 .. 259 ... Name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char rxip[20];
|
char rxip[20];
|
||||||
@ -491,7 +536,7 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
// App searches for the modem IP, mirror the received messages
|
// App searches for the modem IP, mirror the received messages
|
||||||
// so the app gets an UDP message with this local IP
|
// so the app gets an UDP message with this local IP
|
||||||
int alen;
|
int alen;
|
||||||
uint8_t* txdata = io_getAudioDevicelist(&alen);
|
uint8_t* txdata = getDevList(&alen);
|
||||||
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
|
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -503,13 +548,24 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
// App searches for the modem IP, mirror the received messages
|
// App searches for the modem IP, mirror the received messages
|
||||||
// so the app gets an UDP message with this local IP
|
// so the app gets an UDP message with this local IP
|
||||||
int alen;
|
int alen;
|
||||||
uint8_t* txdata = io_getAudioDevicelist(&alen);
|
uint8_t* txdata = getDevList(&alen);
|
||||||
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
|
sendUDP(appIP, UdpDataPort_ModemToApp, txdata, alen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(mycallsign, pdata + 210, sizeof(mycallsign));
|
||||||
|
mycallsign[sizeof(mycallsign) - 1] = 0;
|
||||||
|
|
||||||
|
memcpy(myqthloc, pdata + 230, sizeof(myqthloc));
|
||||||
|
myqthloc[sizeof(myqthloc) - 1] = 0;
|
||||||
|
|
||||||
|
memcpy(myname, pdata + 240, sizeof(myname));
|
||||||
|
myname[sizeof(myname) - 1] = 0;
|
||||||
|
|
||||||
|
//printf("<%s> <%s> <%s>\n", mycallsign, myqthloc, myname);
|
||||||
|
|
||||||
//printf("%d %d %d %d %d %d %d \n",pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]);
|
//printf("%d %d %d %d %d %d %d \n",pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], pdata[6], pdata[7]);
|
||||||
io_setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], (char*)(pdata + 10), (char*)(pdata + 110));
|
io_setAudioDevices(pdata[1], pdata[2], pdata[3], pdata[4], pdata[5], (char*)(pdata + 10), (char*)(pdata + 110));
|
||||||
safemode = pdata[6];
|
safemode = pdata[6];
|
||||||
@ -629,6 +685,18 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
//printf("LS:<%s> MIC:<%s> Mode:%d codec:%d\n", lsDeviceName, micDeviceName, VoiceAudioMode, codec);
|
//printf("LS:<%s> MIC:<%s> Mode:%d codec:%d\n", lsDeviceName, micDeviceName, VoiceAudioMode, codec);
|
||||||
|
|
||||||
init_voice = 1;
|
init_voice = 1;
|
||||||
|
|
||||||
|
if (!strcmp(micDeviceName, captureDeviceName))
|
||||||
|
{
|
||||||
|
printf("capture device already in use, ignoring: %s\n", micDeviceName);
|
||||||
|
init_voice = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(lsDeviceName, playbackDeviceName))
|
||||||
|
{
|
||||||
|
printf("playback device already in use, ignoring: %s\n", lsDeviceName);
|
||||||
|
init_voice = 0;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,10 +802,11 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
|
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
|
||||||
toGR_sendData(pdata + 2, type, minfo,0);
|
toGR_sendData(pdata + 2, type, minfo,0);
|
||||||
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
|
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
|
||||||
if (type == 1)// BER Test
|
//if (type == 1)// BER Test
|
||||||
numframespreamble = 1;
|
// numframespreamble = 1;
|
||||||
for (int i = 0; i < numframespreamble; i++)
|
for (int i = 0; i < numframespreamble; i++)
|
||||||
toGR_sendData(pdata + 2, type, minfo,1);
|
toGR_sendData(pdata + 2, type, minfo,1);
|
||||||
|
sendStationInfo();
|
||||||
}
|
}
|
||||||
else if ((len - 2) < PAYLOADLEN)
|
else if ((len - 2) < PAYLOADLEN)
|
||||||
{
|
{
|
||||||
@ -781,11 +850,29 @@ void toGR_sendData(uint8_t* data, int type, int status, int repeat)
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
uint8_t* txdata = Pack(data, type, status, &len, repeat);
|
uint8_t* txdata = Pack(data, type, status, &len, repeat);
|
||||||
|
|
||||||
//showbytestring((char *)"BERtx: ", txdata, len);
|
//showbytestring((char *)"TX: ", txdata, len);
|
||||||
|
|
||||||
if (txdata != NULL) sendToModulator(txdata, len);
|
if (txdata != NULL) sendToModulator(txdata, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendStationInfo()
|
||||||
|
{
|
||||||
|
uint8_t payload[PAYLOADLEN];
|
||||||
|
memcpy(payload, mycallsign, 20);
|
||||||
|
memcpy(payload+20, myqthloc, 10);
|
||||||
|
memcpy(payload+30, myname, 20);
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
uint8_t* txdata = Pack(payload, 7, 1, &len, 1);
|
||||||
|
|
||||||
|
//showbytestring((char *)"TX Userinfo: ", txdata, len);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
if (txdata != NULL) sendToModulator(txdata, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// called by liquid demodulator for received data
|
// called by liquid demodulator for received data
|
||||||
void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||||
{
|
{
|
||||||
@ -797,6 +884,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
if (pl != NULL)
|
if (pl != NULL)
|
||||||
{
|
{
|
||||||
// complete frame received
|
// complete frame received
|
||||||
|
//printf("type:%d\n", pl[0]);
|
||||||
// send payload to app
|
// send payload to app
|
||||||
uint8_t txpl[PAYLOADLEN + 10 + 1];
|
uint8_t txpl[PAYLOADLEN + 10 + 1];
|
||||||
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
|
memcpy(txpl + 1, pl, PAYLOADLEN + 10);
|
||||||
@ -862,7 +950,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
|||||||
rx_in_sync = 0;
|
rx_in_sync = 0;
|
||||||
if (speedmode < 10)
|
if (speedmode < 10)
|
||||||
{
|
{
|
||||||
printf("no signal detected, reset RX modem\n");
|
//printf("no signal detected, reset RX modem\n");
|
||||||
resetModem();
|
resetModem();
|
||||||
}
|
}
|
||||||
lasttime = acttm;
|
lasttime = acttm;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define _WIN32_
|
#define _WIN32_
|
||||||
// ignore senseless warnings invented by M$ to confuse developers
|
// ignore senseless warnings invented by M$ to confuse developers
|
||||||
|
// I love LINUX :-) which works 100000x better than Windows
|
||||||
#pragma warning( disable : 4091 )
|
#pragma warning( disable : 4091 )
|
||||||
#pragma warning( disable : 4003 )
|
#pragma warning( disable : 4003 )
|
||||||
#else
|
#else
|
||||||
@ -230,6 +231,7 @@ void clear_rtty_txfifo();
|
|||||||
void fmtest();
|
void fmtest();
|
||||||
void rtty_init_pipes();
|
void rtty_init_pipes();
|
||||||
void initVoice();
|
void initVoice();
|
||||||
|
void sendStationInfo();
|
||||||
|
|
||||||
|
|
||||||
extern int speedmode;
|
extern int speedmode;
|
||||||
|
@ -179,13 +179,33 @@ uint8_t* io_getAudioDevicelist(int* len);
|
|||||||
*/
|
*/
|
||||||
uint8_t kmaudio_maxlevel(int id);
|
uint8_t kmaudio_maxlevel(int id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* closes a stream which was started by
|
||||||
|
* kmaudio_startCapture or kmaudio_startPlayback
|
||||||
|
* id ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
|
||||||
|
*/
|
||||||
|
void close_stream(int id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handle the FIFO which is used to buffer audio data
|
||||||
|
* pipenum ... stream ID which was returned by kmaudio_startCapture or kmaudio_startPlayback
|
||||||
|
* IMPORTANT: this information MUST be used to synchonize the data flow into
|
||||||
|
* the fifo. The speed is always defined by the audio sample rate
|
||||||
|
* by checking the fifo an application knows when it has to put more audio samples
|
||||||
|
* into the fifo
|
||||||
|
*/
|
||||||
|
// returns number of remaining elements (audio 16 bit short values)
|
||||||
int io_fifo_freespace(int pipenum);
|
int io_fifo_freespace(int pipenum);
|
||||||
|
|
||||||
|
// returns number of used elements (audio 16 bit short values)
|
||||||
int io_fifo_usedspace(int pipenum);
|
int io_fifo_usedspace(int pipenum);
|
||||||
void io_fifo_clear(int pipenum);
|
|
||||||
|
// like before, but returns a number between 0 and 100 %
|
||||||
int io_fifo_usedpercent(int pipenum);
|
int io_fifo_usedpercent(int pipenum);
|
||||||
|
|
||||||
|
// clear the fifo
|
||||||
|
void io_fifo_clear(int pipenum);
|
||||||
|
|
||||||
|
|
||||||
// -------- functions for internal use only --------
|
// -------- functions for internal use only --------
|
||||||
|
|
||||||
@ -237,6 +257,8 @@ uint64_t getms();
|
|||||||
void init_maxarray();
|
void init_maxarray();
|
||||||
void kmaudio_detectDropouts(int id);
|
void kmaudio_detectDropouts(int id);
|
||||||
int io_read_fifo_num_short(int pipenum, int16_t* data, int num);
|
int io_read_fifo_num_short(int pipenum, int16_t* data, int num);
|
||||||
|
void close_capture_stream(int idx);
|
||||||
|
void close_playback_stream(int idx);
|
||||||
|
|
||||||
extern DEVLIST devlist[MAXDEVICES];
|
extern DEVLIST devlist[MAXDEVICES];
|
||||||
extern int devanz;
|
extern int devanz;
|
||||||
|
@ -40,6 +40,15 @@ int recordCallback(const void* inputBuffer, void* outputBuffer,
|
|||||||
PaStreamCallbackFlags statusFlags,
|
PaStreamCallbackFlags statusFlags,
|
||||||
void* userData);
|
void* userData);
|
||||||
|
|
||||||
|
void close_capture_stream(int idx)
|
||||||
|
{
|
||||||
|
if (devlist[idx].capStream != NULL)
|
||||||
|
{
|
||||||
|
Pa_CloseStream(devlist[idx].capStream);
|
||||||
|
devlist[idx].capStream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kmaudio_startCapture(char* devname, int samprate)
|
int kmaudio_startCapture(char* devname, int samprate)
|
||||||
{
|
{
|
||||||
printf("Start request for CAP stream:%s\n", devname);
|
printf("Start request for CAP stream:%s\n", devname);
|
||||||
@ -59,12 +68,8 @@ int kmaudio_startCapture(char* devname, int samprate)
|
|||||||
|
|
||||||
devlist[idx].working = 0;
|
devlist[idx].working = 0;
|
||||||
|
|
||||||
if (devlist[idx].capStream != NULL)
|
close_capture_stream(idx);
|
||||||
{
|
|
||||||
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
|
|
||||||
Pa_CloseStream(devlist[idx].capStream);
|
|
||||||
devlist[idx].capStream = NULL;
|
|
||||||
}
|
|
||||||
printf("Starting CAP stream:%s [%d]\n", devname, idx);
|
printf("Starting CAP stream:%s [%d]\n", devname, idx);
|
||||||
|
|
||||||
io_fifo_clear(idx);
|
io_fifo_clear(idx);
|
||||||
|
@ -112,6 +112,15 @@ void overflow_callback(struct SoundIoInStream* instream)
|
|||||||
printf("overflow %d\n", ++count);
|
printf("overflow %d\n", ++count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_capture_stream(int idx)
|
||||||
|
{
|
||||||
|
if (devlist[idx].instream != NULL)
|
||||||
|
{
|
||||||
|
soundio_instream_destroy(devlist[idx].instream);
|
||||||
|
devlist[idx].instream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kmaudio_startCapture(char* devname, int samprate)
|
int kmaudio_startCapture(char* devname, int samprate)
|
||||||
{
|
{
|
||||||
printf("Start request for CAP stream:%s\n", devname);
|
printf("Start request for CAP stream:%s\n", devname);
|
||||||
@ -127,12 +136,8 @@ int kmaudio_startCapture(char* devname, int samprate)
|
|||||||
if (capdevid == NULL) return -1;
|
if (capdevid == NULL) return -1;
|
||||||
|
|
||||||
// if an old stream is open, close it
|
// if an old stream is open, close it
|
||||||
if (devlist[idx].instream != NULL)
|
close_capture_stream(idx);
|
||||||
{
|
|
||||||
printf("Closing old CAP stream:%s [%d]\n", devname, idx);
|
|
||||||
soundio_instream_destroy(devlist[idx].instream);
|
|
||||||
devlist[idx].instream = NULL;
|
|
||||||
}
|
|
||||||
printf("Starting CAP stream:%s [%d]\n", devname, idx);
|
printf("Starting CAP stream:%s [%d]\n", devname, idx);
|
||||||
|
|
||||||
io_fifo_clear(idx);
|
io_fifo_clear(idx);
|
||||||
|
@ -82,6 +82,8 @@ void init_pipes()
|
|||||||
// ignore data if the fifo is full
|
// ignore data if the fifo is full
|
||||||
void io_write_fifo(int pipenum, float sample)
|
void io_write_fifo(int pipenum, float sample)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
|
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
|
||||||
{
|
{
|
||||||
@ -98,6 +100,8 @@ void io_write_fifo(int pipenum, float sample)
|
|||||||
|
|
||||||
void io_write_fifo_short(int pipenum, int16_t sample)
|
void io_write_fifo_short(int pipenum, int16_t sample)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
|
if (((io_wridx[pipenum] + 1) % AUDIO_FIFOFLEN) == io_rdidx[pipenum])
|
||||||
{
|
{
|
||||||
@ -114,6 +118,8 @@ void io_write_fifo_short(int pipenum, int16_t sample)
|
|||||||
|
|
||||||
int io_read_fifo(int pipenum, float* data)
|
int io_read_fifo(int pipenum, float* data)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
|
|
||||||
if (io_rdidx[pipenum] == io_wridx[pipenum])
|
if (io_rdidx[pipenum] == io_wridx[pipenum])
|
||||||
@ -136,6 +142,8 @@ int io_read_fifo(int pipenum, float* data)
|
|||||||
// if num elems not avail, return all what fifo has stored
|
// if num elems not avail, return all what fifo has stored
|
||||||
int io_read_fifo_num(int pipenum, float* data, int num)
|
int io_read_fifo_num(int pipenum, float* data, int num)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
|
|
||||||
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
|
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
|
||||||
@ -166,6 +174,8 @@ int io_read_fifo_num(int pipenum, float* data, int num)
|
|||||||
|
|
||||||
int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
|
int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
|
|
||||||
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
|
int elemInFifo = (io_wridx[pipenum] + AUDIO_FIFOFLEN - io_rdidx[pipenum]) % AUDIO_FIFOFLEN;
|
||||||
@ -193,11 +203,15 @@ int io_read_fifo_num_short(int pipenum, int16_t* data, int num)
|
|||||||
|
|
||||||
void io_fifo_clear(int pipenum)
|
void io_fifo_clear(int pipenum)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return;
|
||||||
|
|
||||||
io_wridx[pipenum] = io_rdidx[pipenum] = 0;
|
io_wridx[pipenum] = io_rdidx[pipenum] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int io_fifo_freespace(int pipenum)
|
int io_fifo_freespace(int pipenum)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
|
||||||
|
|
||||||
int freebuf = 0;
|
int freebuf = 0;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
@ -211,6 +225,8 @@ int io_fifo_freespace(int pipenum)
|
|||||||
|
|
||||||
int io_fifo_elems_avail(int pipenum)
|
int io_fifo_elems_avail(int pipenum)
|
||||||
{
|
{
|
||||||
|
if (pipenum < 0 || pipenum >= NUM_OF_PIPES) return 0;
|
||||||
|
|
||||||
int elems = 0;
|
int elems = 0;
|
||||||
|
|
||||||
LOCK(pipenum);
|
LOCK(pipenum);
|
||||||
|
@ -235,15 +235,17 @@ int getRealSamprate(int idx)
|
|||||||
// build string of audio device name, to be sent to application as response to Broadcast search
|
// build string of audio device name, to be sent to application as response to Broadcast search
|
||||||
// starting with PB devices, sperarator ^, capture devices
|
// starting with PB devices, sperarator ^, capture devices
|
||||||
// separator between devices: ~
|
// separator between devices: ~
|
||||||
// the first character is 0 or 1 and does not belong to the device name
|
|
||||||
// it shows if this device was sucessfully started and is currently running (="1")
|
|
||||||
#define MAXDEVSTRLEN (MAXDEVICES * (MAXDEVNAMELENGTH + 2) + 10)
|
#define MAXDEVSTRLEN (MAXDEVICES * (MAXDEVNAMELENGTH + 2) + 10)
|
||||||
uint8_t io_devstring[MAXDEVSTRLEN];
|
uint8_t io_devstring[MAXDEVSTRLEN];
|
||||||
|
|
||||||
void io_buildAudioDevString()
|
void io_buildAudioDevString()
|
||||||
{
|
{
|
||||||
memset(io_devstring, 0, sizeof(io_devstring));
|
memset(io_devstring, 0, sizeof(io_devstring));
|
||||||
io_devstring[0] = ' '; // placeholder for ID for this UDP message
|
io_devstring[0] = ' '; // placeholder for other data
|
||||||
|
io_devstring[1] = ' ';
|
||||||
|
io_devstring[2] = ' ';
|
||||||
|
io_devstring[3] = ' ';
|
||||||
|
io_devstring[4] = ' ';
|
||||||
|
|
||||||
// playback devices
|
// playback devices
|
||||||
for (int i = 0; i < devanz; i++)
|
for (int i = 0; i < devanz; i++)
|
||||||
@ -256,7 +258,6 @@ void io_buildAudioDevString()
|
|||||||
}
|
}
|
||||||
if (devlist[i].in_out == 1)
|
if (devlist[i].in_out == 1)
|
||||||
{
|
{
|
||||||
strcat((char*)io_devstring, devlist[i].working?"1":"0");
|
|
||||||
strcat((char*)io_devstring, devlist[i].name);
|
strcat((char*)io_devstring, devlist[i].name);
|
||||||
strcat((char*)io_devstring, "~"); // audio device separator
|
strcat((char*)io_devstring, "~"); // audio device separator
|
||||||
}
|
}
|
||||||
@ -275,15 +276,12 @@ void io_buildAudioDevString()
|
|||||||
}
|
}
|
||||||
if (devlist[i].in_out == 0)
|
if (devlist[i].in_out == 0)
|
||||||
{
|
{
|
||||||
strcat((char*)io_devstring, devlist[i].working ? "1" : "0");
|
|
||||||
strcat((char*)io_devstring, devlist[i].name);
|
strcat((char*)io_devstring, devlist[i].name);
|
||||||
strcat((char*)io_devstring, "~"); // audio device separator
|
strcat((char*)io_devstring, "~"); // audio device separator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("<%s>\n", (char *)io_devstring);
|
//printf("<%s>\n", (char *)io_devstring);
|
||||||
|
|
||||||
io_devstring[0] = 3; // ID for this message
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* io_getAudioDevicelist(int* len)
|
uint8_t* io_getAudioDevicelist(int* len)
|
||||||
|
@ -3,6 +3,21 @@
|
|||||||
|
|
||||||
void getMax(int id, float fv);
|
void getMax(int id, float fv);
|
||||||
|
|
||||||
|
void close_stream(int id)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
if (devlist[id].capStream != NULL)
|
||||||
|
close_capture_stream(id);
|
||||||
|
if (devlist[id].pbStream != NULL)
|
||||||
|
close_playback_stream(id);
|
||||||
|
#else
|
||||||
|
if (devlist[id].instream != NULL)
|
||||||
|
close_capture_stream(id);
|
||||||
|
if (devlist[id].outstream != NULL)
|
||||||
|
close_playback_stream(id);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reads len samples from device id into psamp
|
* reads len samples from device id into psamp
|
||||||
* returns: number of values written to psamp , -1=error
|
* returns: number of values written to psamp , -1=error
|
||||||
@ -124,7 +139,6 @@ uint8_t kmaudio_maxlevel(int id)
|
|||||||
|
|
||||||
void kmaudio_detectDropouts(int id)
|
void kmaudio_detectDropouts(int id)
|
||||||
{
|
{
|
||||||
int dropout = 0;
|
|
||||||
int stat = 0;
|
int stat = 0;
|
||||||
int drlen = 0;
|
int drlen = 0;
|
||||||
|
|
||||||
|
@ -42,6 +42,15 @@ int playCallback(const void* inputBuffer,
|
|||||||
PaStreamCallbackFlags statusFlags,
|
PaStreamCallbackFlags statusFlags,
|
||||||
void* userData);
|
void* userData);
|
||||||
|
|
||||||
|
void close_playback_stream(int idx)
|
||||||
|
{
|
||||||
|
if (devlist[idx].pbStream != NULL)
|
||||||
|
{
|
||||||
|
Pa_CloseStream(devlist[idx].pbStream);
|
||||||
|
devlist[idx].pbStream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kmaudio_startPlayback(char* devname, int samprate)
|
int kmaudio_startPlayback(char* devname, int samprate)
|
||||||
{
|
{
|
||||||
printf("Start request for PB stream:%s\n", devname);
|
printf("Start request for PB stream:%s\n", devname);
|
||||||
@ -61,12 +70,7 @@ int kmaudio_startPlayback(char* devname, int samprate)
|
|||||||
|
|
||||||
devlist[idx].working = 0;
|
devlist[idx].working = 0;
|
||||||
|
|
||||||
if (devlist[idx].pbStream != NULL)
|
close_playback_stream(idx);
|
||||||
{
|
|
||||||
printf("Closing old PB stream:%s [%d]\n", devname, idx);
|
|
||||||
Pa_CloseStream(devlist[idx].pbStream);
|
|
||||||
devlist[idx].pbStream = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Starting PB stream:%s [%d]\n", devname, idx);
|
printf("Starting PB stream:%s [%d]\n", devname, idx);
|
||||||
|
|
||||||
|
@ -136,6 +136,15 @@ void underflow_callback(struct SoundIoOutStream* outstream)
|
|||||||
printf("underflow %d\n", count++);
|
printf("underflow %d\n", count++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_playback_stream(int idx)
|
||||||
|
{
|
||||||
|
if (devlist[idx].outstream != NULL)
|
||||||
|
{
|
||||||
|
soundio_outstream_destroy(devlist[idx].outstream);
|
||||||
|
devlist[idx].outstream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int kmaudio_startPlayback(char* devname, int samprate)
|
int kmaudio_startPlayback(char* devname, int samprate)
|
||||||
{
|
{
|
||||||
printf("Start request for PB stream:%s\n", devname);
|
printf("Start request for PB stream:%s\n", devname);
|
||||||
@ -150,13 +159,7 @@ int kmaudio_startPlayback(char* devname, int samprate)
|
|||||||
char* pbdevid = getDevID(devname, 1, &idx);
|
char* pbdevid = getDevID(devname, 1, &idx);
|
||||||
if (pbdevid == NULL) return -1;
|
if (pbdevid == NULL) return -1;
|
||||||
|
|
||||||
// if an old stream is open, close it
|
close_playback_stream(idx);
|
||||||
if (devlist[idx].outstream != NULL)
|
|
||||||
{
|
|
||||||
printf("Closing old PB stream:%s [%d]\n", devname, idx);
|
|
||||||
soundio_outstream_destroy(devlist[idx].outstream);
|
|
||||||
devlist[idx].outstream = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Starting PB stream:%s [%d]\n", devname, idx);
|
printf("Starting PB stream:%s [%d]\n", devname, idx);
|
||||||
|
|
||||||
|
@ -202,12 +202,14 @@ void modulator(uint8_t sym_in)
|
|||||||
|
|
||||||
// adapt speed to soundcard samplerate
|
// adapt speed to soundcard samplerate
|
||||||
int fs;
|
int fs;
|
||||||
|
int to = 0;
|
||||||
while(keeprunning)
|
while(keeprunning)
|
||||||
{
|
{
|
||||||
fs = io_fifo_freespace(io_pbidx);
|
fs = io_fifo_freespace(io_pbidx);
|
||||||
// wait until there is space in fifo
|
// wait until there is space in fifo
|
||||||
if(fs > 10) break;
|
if(fs > 10) break;
|
||||||
sleep_ms(10);
|
sleep_ms(10);
|
||||||
|
if (++to >= 400) break; // give up after 4s
|
||||||
}
|
}
|
||||||
|
|
||||||
if (marker)
|
if (marker)
|
||||||
|
1209
hsmodem/soundio.h
1209
hsmodem/soundio.h
File diff suppressed because it is too large
Load Diff
@ -1,665 +0,0 @@
|
|||||||
/*
|
|
||||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
|
||||||
* =========================================================
|
|
||||||
* Author: DJ0ABR
|
|
||||||
*
|
|
||||||
* (c) DJ0ABR
|
|
||||||
* www.dj0abr.de
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*
|
|
||||||
* soundio.c ... interface to libsoundio
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hsmodem.h"
|
|
||||||
|
|
||||||
void io_cap_write_fifo(float sample);
|
|
||||||
|
|
||||||
#define MAXAUDIODEVICES 50
|
|
||||||
|
|
||||||
struct SoundIo* soundio = NULL;
|
|
||||||
struct SoundIoDevice* io_pb_device = NULL;
|
|
||||||
struct SoundIoDevice* io_cap_device = NULL;
|
|
||||||
struct SoundIoInStream* instream = NULL;
|
|
||||||
struct SoundIoOutStream* outstream = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _AUDIODEV_ {
|
|
||||||
int in_out = 0; // 0=in, 1=out
|
|
||||||
char name[1000] = { 0 };
|
|
||||||
char id[1000] = { 0 };
|
|
||||||
int minsamprate = 44100;
|
|
||||||
int maxsamprate = 48000;
|
|
||||||
int stereo_mono = 2; // 1=mono, 2=stereo
|
|
||||||
} AUDIODEV;
|
|
||||||
|
|
||||||
AUDIODEV audiodev[MAXAUDIODEVICES];
|
|
||||||
int audiodevidx = 0;
|
|
||||||
|
|
||||||
void print_devs()
|
|
||||||
{
|
|
||||||
printf("\n ==== AUDIO devices ====\n");
|
|
||||||
for (int i = 0; i < audiodevidx; i++)
|
|
||||||
{
|
|
||||||
if(i>0) printf(" -----------------\n");
|
|
||||||
printf("Name: %s\n", audiodev[i].name);
|
|
||||||
printf("ID : %s\n", audiodev[i].id);
|
|
||||||
printf("I/O : %s\n", (audiodev[i].in_out == 0) ? "record":"playback");
|
|
||||||
printf("Chan: %s\n", (audiodev[i].stereo_mono == 2) ? "stereo" : "mono");
|
|
||||||
printf("minR: %d\n", audiodev[i].minsamprate);
|
|
||||||
printf("maxR: %d\n", audiodev[i].maxsamprate);
|
|
||||||
}
|
|
||||||
printf("\n =======================\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_channel_layout(const struct SoundIoChannelLayout* layout)
|
|
||||||
{
|
|
||||||
if (layout->name)
|
|
||||||
{
|
|
||||||
if (strstr(layout->name, "ereo"))
|
|
||||||
audiodev[audiodevidx].stereo_mono = 2;
|
|
||||||
if (strstr(layout->name, "ono"))
|
|
||||||
audiodev[audiodevidx].stereo_mono = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int print_device(struct SoundIoDevice* device)
|
|
||||||
{
|
|
||||||
if (!device->probe_error)
|
|
||||||
{
|
|
||||||
/*#ifdef _WIN32_
|
|
||||||
// only use raw (exclusive) devices
|
|
||||||
if (device->is_raw == false) return 0;
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
// ignore if exists
|
|
||||||
for (int i = 0; i < audiodevidx; i++)
|
|
||||||
if (!strcmp(device->id, audiodev[i].id)) return 0;
|
|
||||||
|
|
||||||
if (strstr(device->name, "onitor")) return 0;
|
|
||||||
|
|
||||||
strncpy(audiodev[audiodevidx].id, device->id, 999);
|
|
||||||
audiodev[audiodevidx].id[999] = 0;
|
|
||||||
strncpy(audiodev[audiodevidx].name, device->name, 999);
|
|
||||||
audiodev[audiodevidx].name[999] = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < device->layout_count; i++)
|
|
||||||
get_channel_layout(&device->layouts[i]);
|
|
||||||
|
|
||||||
for (int i = 0; i < device->sample_rate_count; i++)
|
|
||||||
{
|
|
||||||
struct SoundIoSampleRateRange* range = &device->sample_rates[i];
|
|
||||||
if (range->min < audiodev[audiodevidx].minsamprate)
|
|
||||||
audiodev[audiodevidx].minsamprate = range->min;
|
|
||||||
|
|
||||||
if (range->max > audiodev[audiodevidx].maxsamprate)
|
|
||||||
audiodev[audiodevidx].maxsamprate = range->max;
|
|
||||||
}
|
|
||||||
if (audiodev[audiodevidx].minsamprate > 44100)
|
|
||||||
return 0;
|
|
||||||
if (audiodev[audiodevidx].maxsamprate < 48000)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int scan_devices(struct SoundIo* soundio)
|
|
||||||
{
|
|
||||||
audiodevidx = 0;
|
|
||||||
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
|
||||||
if (print_device(device) == 1)
|
|
||||||
{
|
|
||||||
audiodev[audiodevidx].in_out = 0;
|
|
||||||
audiodevidx++;
|
|
||||||
}
|
|
||||||
soundio_device_unref(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < soundio_output_device_count(soundio); i++)
|
|
||||||
{
|
|
||||||
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
|
|
||||||
if (print_device(device) == 1)
|
|
||||||
{
|
|
||||||
audiodev[audiodevidx].in_out = 1;
|
|
||||||
audiodevidx++;
|
|
||||||
}
|
|
||||||
soundio_device_unref(device);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build string of audio device name, to be sent to application as response to Broadcast search
|
|
||||||
// starting with PB devices, sperarator ^, capture devices
|
|
||||||
// separator between devices: ~
|
|
||||||
uint8_t io_devstring[MAXDEVSTRLEN + 100];
|
|
||||||
|
|
||||||
void io_buildUdpAudioList()
|
|
||||||
{
|
|
||||||
memset(io_devstring, 0, sizeof(io_devstring));
|
|
||||||
io_devstring[0] = ' '; // placeholder for ID for this UDP message
|
|
||||||
io_devstring[1] = '0' + init_audio_result;
|
|
||||||
io_devstring[2] = '0' + init_voice_result;
|
|
||||||
|
|
||||||
// playback devices
|
|
||||||
for (int i = 0; i < audiodevidx; i++)
|
|
||||||
{
|
|
||||||
if (audiodev[i].in_out == 1)
|
|
||||||
{
|
|
||||||
strcat((char*)io_devstring, audiodev[i].name);
|
|
||||||
strcat((char*)io_devstring, "~"); // audio device separator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat((char*)(io_devstring + 1), "^"); // PB, CAP separator
|
|
||||||
|
|
||||||
// capture devices
|
|
||||||
for (int i = 0; i < audiodevidx; i++)
|
|
||||||
{
|
|
||||||
if (audiodev[i].in_out == 0)
|
|
||||||
{
|
|
||||||
strcat((char*)io_devstring, audiodev[i].name);
|
|
||||||
strcat((char*)io_devstring, "~"); // audio device separator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
io_devstring[0] = 3; // ID for this UDP message
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* io_getAudioDevicelist(int* len)
|
|
||||||
{
|
|
||||||
// update Status
|
|
||||||
io_devstring[1] = '0' + init_audio_result;
|
|
||||||
io_devstring[2] = '0' + init_voice_result;
|
|
||||||
|
|
||||||
*len = strlen((char*)(io_devstring + 1)) + 1;
|
|
||||||
return io_devstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_readAudioDevices()
|
|
||||||
{
|
|
||||||
if (soundio == NULL) return;
|
|
||||||
// to get actual data
|
|
||||||
soundio_flush_events(soundio);
|
|
||||||
|
|
||||||
scan_devices(soundio); // read devices
|
|
||||||
io_buildUdpAudioList();
|
|
||||||
|
|
||||||
//print_devs();
|
|
||||||
}
|
|
||||||
|
|
||||||
char* getDevID(char* devname, int io)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < audiodevidx; i++)
|
|
||||||
{
|
|
||||||
if (!strcmp(devname, audiodev[i].name) && io == audiodev[i].in_out)
|
|
||||||
{
|
|
||||||
return audiodev[i].id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int min_int(int a, int b)
|
|
||||||
{
|
|
||||||
return (a < b) ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
|
||||||
{
|
|
||||||
|
|
||||||
int err;
|
|
||||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
|
||||||
//int chans = instream->layout.channel_count;
|
|
||||||
|
|
||||||
struct SoundIoChannelArea* areas;
|
|
||||||
// samples are in areas.ptr
|
|
||||||
int frames_left = frame_count_max; // take all
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int frame_count = frames_left;
|
|
||||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!frame_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
for (int frame = 0; frame < frame_count; frame += 1)
|
|
||||||
{
|
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1)
|
|
||||||
{
|
|
||||||
int16_t rxdata;
|
|
||||||
memcpy(&rxdata, areas[ch].ptr, instream->bytes_per_sample);
|
|
||||||
areas[ch].ptr += areas[ch].step;
|
|
||||||
if (ch == 0)
|
|
||||||
{
|
|
||||||
float f = rxdata;
|
|
||||||
f /= 32768;
|
|
||||||
f *= softwareCAPvolume;
|
|
||||||
io_cap_write_fifo(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//measure_speed_bps(frame_count);
|
|
||||||
|
|
||||||
if ((err = soundio_instream_end_read(instream)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
if (frames_left <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
void read_callback(struct SoundIoInStream* instream, int frame_count_min, int frame_count_max)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
//printf("cap: %d %d\n", frame_count_min, frame_count_max);
|
|
||||||
// bytes_per_frame == 4 because we use float
|
|
||||||
// instream->bytes_per_sample/bytes_per_frame = 1 (mono) or 2 (stereo)
|
|
||||||
int chans = instream->layout.channel_count;
|
|
||||||
|
|
||||||
struct SoundIoChannelArea* areas;
|
|
||||||
// samples are in areas.ptr
|
|
||||||
int frames_left = frame_count_max; // take all
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int frame_count = frames_left;
|
|
||||||
if ((err = soundio_instream_begin_read(instream, &areas, &frame_count)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "begin read error: %s", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!frame_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// do something with the data in *area.ptr
|
|
||||||
// take a float every chans*4 Bytes
|
|
||||||
int16_t* samples = (int16_t*)(areas[0].ptr);
|
|
||||||
int pos = 0;
|
|
||||||
for (int i = 0; i < frame_count; i++)
|
|
||||||
{
|
|
||||||
float f = samples[pos];
|
|
||||||
f /= 32768;
|
|
||||||
f *= softwareCAPvolume;
|
|
||||||
io_cap_write_fifo(f);
|
|
||||||
pos += chans;
|
|
||||||
}
|
|
||||||
|
|
||||||
//measure_speed_bps(frame_count);
|
|
||||||
|
|
||||||
if ((err = soundio_instream_end_read(instream))) {
|
|
||||||
fprintf(stderr, "end read error: %s", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
if (frames_left <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void overflow_callback(struct SoundIoInStream* instream)
|
|
||||||
{
|
|
||||||
static int count = 0;
|
|
||||||
printf("overflow %d\n", ++count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAXCAPCHUNKLEN 50000
|
|
||||||
|
|
||||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
|
||||||
{
|
|
||||||
struct SoundIoChannelArea* areas;
|
|
||||||
int err;
|
|
||||||
int frames_left = frame_count_max;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int frame_count = frames_left;
|
|
||||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frame_count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
float f[MAXCAPCHUNKLEN];
|
|
||||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
|
||||||
if (fiforet == 0)
|
|
||||||
{
|
|
||||||
// elements not available, fill with zeroes
|
|
||||||
//printf("not enough data, send zeroes\n");
|
|
||||||
memset(f, 0, sizeof(float) * frame_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct SoundIoChannelLayout* layout = &outstream->layout;
|
|
||||||
|
|
||||||
for (int frame = 0; frame < frame_count; frame++)
|
|
||||||
{
|
|
||||||
for (int channel = 0; channel < layout->channel_count; channel++)
|
|
||||||
{
|
|
||||||
write_sample_s16ne(areas[channel].ptr, f[frame]);
|
|
||||||
areas[channel].ptr += areas[channel].step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = soundio_outstream_end_write(outstream))) {
|
|
||||||
if (err == SoundIoErrorUnderflow)
|
|
||||||
return;
|
|
||||||
fprintf(stderr, "unrecoverable stream error: %s\n", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
if (frames_left <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
static void write_callback(struct SoundIoOutStream* outstream, int frame_count_min, int frame_count_max)
|
|
||||||
{
|
|
||||||
int chans = outstream->layout.channel_count;
|
|
||||||
struct SoundIoChannelArea* areas;
|
|
||||||
int err;
|
|
||||||
int frames_left = min_int(frame_count_max,MAXCAPCHUNKLEN);// frame_count_max;
|
|
||||||
//printf("\nmin: %d max:%d\n", frame_count_min, frame_count_max);
|
|
||||||
|
|
||||||
// we have to write frame_count_max, not less, or we get an underrun
|
|
||||||
// this has to be written in chunks requested by soundio_outstream_begin_write
|
|
||||||
float f[MAXCAPCHUNKLEN];
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
int frame_count = frames_left;
|
|
||||||
if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
|
|
||||||
printf("unrecoverable soundio_outstream_begin_write error: %s\n", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!frame_count) break; // will normally never happen
|
|
||||||
//printf("chunk: %d\n", frame_count);
|
|
||||||
|
|
||||||
// soundio_outstream_begin_write requested to write frame_count elements
|
|
||||||
int fiforet = io_pb_read_fifo_num(f, frame_count);
|
|
||||||
if (fiforet == 0)
|
|
||||||
{
|
|
||||||
// elements not available, fill with zeroes
|
|
||||||
//printf("not enough data, send zeroes\n");
|
|
||||||
memset(f, 0, sizeof(float) * frame_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply volume
|
|
||||||
for (int i = 0; i < frame_count; i++)
|
|
||||||
f[i] *= softwarePBvolume;
|
|
||||||
|
|
||||||
// put data into soundio buffer
|
|
||||||
for (int frame = 0; frame < frame_count; frame++)
|
|
||||||
{
|
|
||||||
for (int ch = 0; ch < chans; ch++)
|
|
||||||
{
|
|
||||||
int16_t* s = (int16_t*)areas[ch].ptr;
|
|
||||||
*s = (int16_t)(f[frame] * 32768.0);
|
|
||||||
areas[ch].ptr += areas[ch].step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and finalize this chunk
|
|
||||||
if ((err = soundio_outstream_end_write(outstream))) {
|
|
||||||
if (err == SoundIoErrorUnderflow)
|
|
||||||
return;
|
|
||||||
printf("unrecoverable soundio_outstream_end_write error: %s\n", soundio_strerror(err));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
frames_left -= frame_count;
|
|
||||||
if (frames_left <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void underflow_callback(struct SoundIoOutStream* outstream)
|
|
||||||
{
|
|
||||||
static int count = 0;
|
|
||||||
printf("underflow %d\n", count++);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int io_init_sound(char *pbname, char *capname)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
init_audio_result = 0;
|
|
||||||
|
|
||||||
printf("\n ==== IO INIT AUDIO devices ====\n");
|
|
||||||
printf("requested: <%s> <%s>\ncapture rate:%d\n",pbname,capname,caprate);
|
|
||||||
|
|
||||||
io_close_audio();
|
|
||||||
|
|
||||||
// prepare and connect to libsoundio
|
|
||||||
soundio = soundio_create();
|
|
||||||
if (!soundio) {
|
|
||||||
printf("soundio_create: out of memory\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32_
|
|
||||||
if ((err=soundio_connect_backend(soundio, SoundIoBackendWasapi))) {
|
|
||||||
printf("soundio_connect: %s\n", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef _LINUX_
|
|
||||||
if ((err = soundio_connect(soundio))) {
|
|
||||||
printf("soundio_connect: %s\n", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
io_readAudioDevices();
|
|
||||||
io_init_pipes();
|
|
||||||
|
|
||||||
if (pbname == NULL || capname == NULL || strlen(pbname) < 3 || strlen(capname) < 3) // no devices defined yet
|
|
||||||
{
|
|
||||||
printf("no devices specified\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* pbdevid = getDevID(pbname,1);
|
|
||||||
if (pbdevid == NULL) return 0;
|
|
||||||
|
|
||||||
char* capdevid = getDevID(capname,0);
|
|
||||||
if (capdevid == NULL) return 0;
|
|
||||||
|
|
||||||
// define the capture device
|
|
||||||
printf("selected CAP device:\nname:%s\nid :%s\n", capname, capdevid);
|
|
||||||
|
|
||||||
soundio_flush_events(soundio);
|
|
||||||
|
|
||||||
for (int i = 0; i < soundio_input_device_count(soundio); i++)
|
|
||||||
{
|
|
||||||
io_cap_device = NULL;
|
|
||||||
struct SoundIoDevice* device = soundio_get_input_device(soundio, i);
|
|
||||||
if (strcmp(device->id, capdevid) == 0
|
|
||||||
#ifdef _WIN32_
|
|
||||||
&& device->is_raw == true
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
io_cap_device = device;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
soundio_device_unref(device);
|
|
||||||
}
|
|
||||||
if (!io_cap_device)
|
|
||||||
{
|
|
||||||
printf("Invalid device id: %s\n", capdevid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (io_cap_device->probe_error)
|
|
||||||
{
|
|
||||||
printf("Unable to probe device: %s\n", soundio_strerror(io_cap_device->probe_error));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create capture callback
|
|
||||||
instream = soundio_instream_create(io_cap_device);
|
|
||||||
if (!instream) {
|
|
||||||
printf("out of memory\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
instream->format = SoundIoFormatS16NE;
|
|
||||||
instream->sample_rate = caprate;
|
|
||||||
instream->software_latency = 0.0;
|
|
||||||
instream->read_callback = read_callback;
|
|
||||||
instream->overflow_callback = overflow_callback;
|
|
||||||
instream->userdata = NULL;
|
|
||||||
|
|
||||||
if ((err = soundio_instream_open(instream))) {
|
|
||||||
printf("unable to open input stream: %s", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = soundio_instream_start(instream))) {
|
|
||||||
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
init_audio_result |= 2;
|
|
||||||
// the CAP callback is running now
|
|
||||||
|
|
||||||
// define the playback device
|
|
||||||
printf("selected PB device:\nname:%s\nid :%s\n", pbname, pbdevid);
|
|
||||||
|
|
||||||
for (int i = 0; i < soundio_output_device_count(soundio); i++)
|
|
||||||
{
|
|
||||||
io_pb_device = NULL;
|
|
||||||
struct SoundIoDevice* device = soundio_get_output_device(soundio, i);
|
|
||||||
if (strcmp(device->id, pbdevid) == 0
|
|
||||||
#ifdef _WIN32_
|
|
||||||
&& device->is_raw == true
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
io_pb_device = device;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
soundio_device_unref(device);
|
|
||||||
}
|
|
||||||
if (!io_pb_device)
|
|
||||||
{
|
|
||||||
printf("Invalid device id: %s\n", pbdevid);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (io_pb_device->probe_error)
|
|
||||||
{
|
|
||||||
printf("Unable to probe device: %s\n", soundio_strerror(io_pb_device->probe_error));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create playback callback
|
|
||||||
outstream = soundio_outstream_create(io_pb_device);
|
|
||||||
if (!outstream) {
|
|
||||||
printf("soundio_outstream_create: out of memory\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
outstream->format = SoundIoFormatS16NE;
|
|
||||||
outstream->sample_rate = caprate;
|
|
||||||
outstream->software_latency = 0.0;
|
|
||||||
outstream->write_callback = write_callback;
|
|
||||||
outstream->underflow_callback = underflow_callback;
|
|
||||||
outstream->userdata = NULL;
|
|
||||||
|
|
||||||
if ((err = soundio_outstream_open(outstream))) {
|
|
||||||
printf("unable to open output stream: %s", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = soundio_outstream_start(outstream))) {
|
|
||||||
fprintf(stderr, "unable to start output device: %s", soundio_strerror(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
init_audio_result |= 1;
|
|
||||||
|
|
||||||
printf("==== Audio init finished: %d ====\n", init_audio_result);
|
|
||||||
|
|
||||||
return init_audio_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_close_audio()
|
|
||||||
{
|
|
||||||
printf("close Audio\n");
|
|
||||||
if(instream) soundio_instream_destroy(instream);
|
|
||||||
instream = NULL;
|
|
||||||
|
|
||||||
if (outstream) soundio_outstream_destroy(outstream);
|
|
||||||
outstream = NULL;
|
|
||||||
|
|
||||||
if(io_pb_device) soundio_device_unref(io_pb_device);
|
|
||||||
io_pb_device = NULL;
|
|
||||||
|
|
||||||
if (io_cap_device) soundio_device_unref(io_cap_device);
|
|
||||||
io_cap_device = NULL;
|
|
||||||
|
|
||||||
if (soundio) soundio_destroy(soundio);
|
|
||||||
soundio = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_setPBvolume(int v)
|
|
||||||
{
|
|
||||||
// the volume comes in % 0..99
|
|
||||||
softwarePBvolume = ((float)v) / 50.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_setCAPvolume(int v)
|
|
||||||
{
|
|
||||||
// the volume comes in % 0..99
|
|
||||||
softwareCAPvolume = ((float)v) / 50.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set volume
|
|
||||||
void io_setVolume(int pbcap, int v)
|
|
||||||
{
|
|
||||||
if (pbcap == 0) io_setPBvolume(v);
|
|
||||||
else io_setCAPvolume(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_setLSvolume(int v)
|
|
||||||
{
|
|
||||||
// the volume comes in % 0..99
|
|
||||||
softwareLSvolume = ((float)v) / 50.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void io_setMICvolume(int v)
|
|
||||||
{
|
|
||||||
// the volume comes in % 0..99
|
|
||||||
softwareMICvolume = ((float)v) / 50.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVolume_voice(int pbcap, int v)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -74,7 +74,7 @@ void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockad
|
|||||||
memset(&sin, 0, sizeof(struct sockaddr_in));
|
memset(&sin, 0, sizeof(struct sockaddr_in));
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_port = htons(port);
|
sin.sin_port = htons(port);
|
||||||
sin.sin_addr.s_addr = INADDR_ANY;
|
sin.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
if (bind(*sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0)
|
if (bind(*sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0)
|
||||||
{
|
{
|
||||||
@ -102,13 +102,11 @@ void UdpRxInit(int *sock, int port, void (*rxfunc)(uint8_t *, int, struct sockad
|
|||||||
rxcfg_idx++;
|
rxcfg_idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef _LINUX_
|
#ifdef _LINUX_
|
||||||
void* threadfunction(void* param) {
|
void* threadfunction(void* param) {
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
pthread_detach(pthread_self());
|
pthread_detach(pthread_self());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32_
|
#ifdef _WIN32_
|
||||||
void threadfunction(void* param) {
|
void threadfunction(void* param) {
|
||||||
int fromlen;
|
int fromlen;
|
||||||
@ -116,18 +114,24 @@ void threadfunction(void* param) {
|
|||||||
RXCFG rxcfg;
|
RXCFG rxcfg;
|
||||||
memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG));
|
memcpy((uint8_t *)(&rxcfg), (uint8_t *)param, sizeof(RXCFG));
|
||||||
int recvlen;
|
int recvlen;
|
||||||
char rxbuf[256];
|
const int maxUDPpacketsize = 1024;
|
||||||
|
char rxbuf[maxUDPpacketsize];
|
||||||
struct sockaddr_in fromSock;
|
struct sockaddr_in fromSock;
|
||||||
fromlen = sizeof(struct sockaddr_in);
|
fromlen = sizeof(struct sockaddr_in);
|
||||||
while(*rxcfg.keeprunning)
|
while(*rxcfg.keeprunning)
|
||||||
{
|
{
|
||||||
recvlen = recvfrom(*rxcfg.sock, rxbuf, 256, 0, (struct sockaddr *)&fromSock, &fromlen);
|
recvlen = recvfrom(*rxcfg.sock, rxbuf, maxUDPpacketsize, 0, (struct sockaddr *)&fromSock, &fromlen);
|
||||||
if (recvlen > 0)
|
if (recvlen > 0)
|
||||||
{
|
{
|
||||||
// data received, send it to callback function
|
// data received, send it to callback function
|
||||||
(*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock);
|
(*rxcfg.rxfunc)((uint8_t *)rxbuf,recvlen, &fromSock);
|
||||||
}
|
}
|
||||||
|
if (recvlen < 0)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32_
|
||||||
|
printf("recvfrom error: %d", WSAGetLastError());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef _LINUX_
|
#ifdef _LINUX_
|
||||||
pthread_exit(NULL); // self terminate this thread
|
pthread_exit(NULL); // self terminate this thread
|
||||||
|
@ -170,7 +170,6 @@ void sendCodecToModulator(uint8_t *pdata, int len)
|
|||||||
while (keeprunning)
|
while (keeprunning)
|
||||||
{
|
{
|
||||||
// we have to check if the TX fifo has enough data. In case of an underrun the Q(8A)PSK signal will be distorted
|
// we have to check if the TX fifo has enough data. In case of an underrun the Q(8A)PSK signal will be distorted
|
||||||
//int us = io_pb_fifo_usedspace();
|
|
||||||
int us = io_fifo_usedspace(io_pbidx);
|
int us = io_fifo_usedspace(io_pbidx);
|
||||||
if (us < 20000)
|
if (us < 20000)
|
||||||
{
|
{
|
||||||
|
Binary file not shown.
Binary file not shown.
24
oscardata/oscardata/Form1.Designer.cs
generated
24
oscardata/oscardata/Form1.Designer.cs
generated
@ -37,6 +37,8 @@
|
|||||||
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.ts_ip = new System.Windows.Forms.ToolStripStatusLabel();
|
this.ts_ip = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.RXstatus = new System.Windows.Forms.ToolStripStatusLabel();
|
this.RXstatus = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
|
this.toolStrip_spacer = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
|
this.ts_userinfo = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.panel_constel = new System.Windows.Forms.Panel();
|
this.panel_constel = new System.Windows.Forms.Panel();
|
||||||
this.timer_qpsk = new System.Windows.Forms.Timer(this.components);
|
this.timer_qpsk = new System.Windows.Forms.Timer(this.components);
|
||||||
this.panel_txspectrum = new System.Windows.Forms.Panel();
|
this.panel_txspectrum = new System.Windows.Forms.Panel();
|
||||||
@ -253,7 +255,9 @@
|
|||||||
this.toolStrip_Type,
|
this.toolStrip_Type,
|
||||||
this.toolStripStatusLabel,
|
this.toolStripStatusLabel,
|
||||||
this.ts_ip,
|
this.ts_ip,
|
||||||
this.RXstatus});
|
this.RXstatus,
|
||||||
|
this.toolStrip_spacer,
|
||||||
|
this.ts_userinfo});
|
||||||
this.statusStrip1.Location = new System.Drawing.Point(0, 671);
|
this.statusStrip1.Location = new System.Drawing.Point(0, 671);
|
||||||
this.statusStrip1.Name = "statusStrip1";
|
this.statusStrip1.Name = "statusStrip1";
|
||||||
this.statusStrip1.Size = new System.Drawing.Size(1296, 22);
|
this.statusStrip1.Size = new System.Drawing.Size(1296, 22);
|
||||||
@ -286,6 +290,20 @@
|
|||||||
this.RXstatus.Size = new System.Drawing.Size(58, 17);
|
this.RXstatus.Size = new System.Drawing.Size(58, 17);
|
||||||
this.RXstatus.Text = "RX-Status";
|
this.RXstatus.Text = "RX-Status";
|
||||||
//
|
//
|
||||||
|
// toolStrip_spacer
|
||||||
|
//
|
||||||
|
this.toolStrip_spacer.Name = "toolStrip_spacer";
|
||||||
|
this.toolStrip_spacer.Size = new System.Drawing.Size(1156, 17);
|
||||||
|
this.toolStrip_spacer.Spring = true;
|
||||||
|
//
|
||||||
|
// ts_userinfo
|
||||||
|
//
|
||||||
|
this.ts_userinfo.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
|
||||||
|
this.ts_userinfo.ForeColor = System.Drawing.Color.Blue;
|
||||||
|
this.ts_userinfo.Name = "ts_userinfo";
|
||||||
|
this.ts_userinfo.Size = new System.Drawing.Size(16, 17);
|
||||||
|
this.ts_userinfo.Text = "...";
|
||||||
|
//
|
||||||
// panel_constel
|
// panel_constel
|
||||||
//
|
//
|
||||||
this.panel_constel.BackColor = System.Drawing.Color.AliceBlue;
|
this.panel_constel.BackColor = System.Drawing.Color.AliceBlue;
|
||||||
@ -2268,7 +2286,7 @@
|
|||||||
this.ForeColor = System.Drawing.SystemColors.ControlText;
|
this.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||||
this.Name = "Form1";
|
this.Name = "Form1";
|
||||||
this.Text = "AMSAT-DL Multimedia HS Modem V0.71 by DJ0ABR";
|
this.Text = "AMSAT-DL Multimedia HS Modem V0.72 by DJ0ABR";
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
||||||
this.statusStrip1.ResumeLayout(false);
|
this.statusStrip1.ResumeLayout(false);
|
||||||
this.statusStrip1.PerformLayout();
|
this.statusStrip1.PerformLayout();
|
||||||
@ -2498,6 +2516,8 @@
|
|||||||
private System.Windows.Forms.CheckBox cb_rx_autosync;
|
private System.Windows.Forms.CheckBox cb_rx_autosync;
|
||||||
private System.Windows.Forms.TextBox textBox6;
|
private System.Windows.Forms.TextBox textBox6;
|
||||||
private System.Windows.Forms.Button button6;
|
private System.Windows.Forms.Button button6;
|
||||||
|
private System.Windows.Forms.ToolStripStatusLabel toolStrip_spacer;
|
||||||
|
private System.Windows.Forms.ToolStripStatusLabel ts_userinfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +44,8 @@ namespace oscardata
|
|||||||
String old_tsip = "";
|
String old_tsip = "";
|
||||||
bool modemrunning = false;
|
bool modemrunning = false;
|
||||||
receivefile recfile = new receivefile();
|
receivefile recfile = new receivefile();
|
||||||
int last_initAudioStatus;
|
int last_initAudioStatus = -1;
|
||||||
int last_initVoiceStatus;
|
int last_initVoiceStatus = -1;
|
||||||
int recordStatus = 0;
|
int recordStatus = 0;
|
||||||
int recPhase = 0;
|
int recPhase = 0;
|
||||||
const int Rtty_deftext_anz = 20;
|
const int Rtty_deftext_anz = 20;
|
||||||
@ -220,8 +220,8 @@ namespace oscardata
|
|||||||
{
|
{
|
||||||
if (s.Length > 1)
|
if (s.Length > 1)
|
||||||
{
|
{
|
||||||
cb_audioPB.Items.Add(s.Substring(1));
|
cb_audioPB.Items.Add(s);
|
||||||
cb_loudspeaker.Items.Add(s.Substring(1));
|
cb_loudspeaker.Items.Add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cb_loudspeaker.EndUpdate();
|
cb_loudspeaker.EndUpdate();
|
||||||
@ -238,8 +238,8 @@ namespace oscardata
|
|||||||
{
|
{
|
||||||
if (s.Length > 1)
|
if (s.Length > 1)
|
||||||
{
|
{
|
||||||
cb_audioCAP.Items.Add(s.Substring(1));
|
cb_audioCAP.Items.Add(s);
|
||||||
cb_mic.Items.Add(s.Substring(1));
|
cb_mic.Items.Add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cb_mic.EndUpdate();
|
cb_mic.EndUpdate();
|
||||||
@ -315,21 +315,17 @@ namespace oscardata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// correct entries in the Audio Device Comboboxes if Devices have changed
|
// correct entries in the Audio Device Comboboxes if devices have changed
|
||||||
void findDevice(ComboBox cb)
|
void findDevice(ComboBox cb)
|
||||||
{
|
{
|
||||||
int pos = -1;
|
int pos = -1;
|
||||||
|
|
||||||
if (cb.Text.Length >= 4)
|
if (cb.Text.Length >= 4)
|
||||||
{
|
{
|
||||||
// Device Name starts at Index 3 in the string
|
|
||||||
String dn = cb.Text.Substring(3);
|
|
||||||
int anz = cb.Items.Count;
|
int anz = cb.Items.Count;
|
||||||
for (int i = 0; i < anz; i++)
|
for (int i = 0; i < anz; i++)
|
||||||
{
|
{
|
||||||
String name = cb.Items[i].ToString();
|
if (cb.Text == cb.Items[i].ToString())
|
||||||
name = name.Substring(3);
|
|
||||||
if (dn == name)
|
|
||||||
{
|
{
|
||||||
pos = i;
|
pos = i;
|
||||||
break;
|
break;
|
||||||
@ -349,7 +345,6 @@ namespace oscardata
|
|||||||
cb.Text = cb.Items[pos].ToString();
|
cb.Text = cb.Items[pos].ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
{
|
{
|
||||||
save_Setup();
|
save_Setup();
|
||||||
@ -443,6 +438,14 @@ namespace oscardata
|
|||||||
|
|
||||||
//Console.WriteLine("minfo:" + minfo + " data:" + rxdata[0].ToString("X2") + " " + rxdata[1].ToString("X2"));
|
//Console.WriteLine("minfo:" + minfo + " data:" + rxdata[0].ToString("X2") + " " + rxdata[1].ToString("X2"));
|
||||||
|
|
||||||
|
if (rxtype == statics.Userinfo)
|
||||||
|
{
|
||||||
|
String call = statics.ByteArrayToString(rxdata, 0, 20);
|
||||||
|
String qthloc = statics.ByteArrayToString(rxdata, 20, 10);
|
||||||
|
String name = statics.ByteArrayToString(rxdata, 30, 20);
|
||||||
|
ts_userinfo.Text = call + " " + name + " " + qthloc;
|
||||||
|
}
|
||||||
|
|
||||||
// ========= receive file ==========
|
// ========= receive file ==========
|
||||||
// handle file receive
|
// handle file receive
|
||||||
if (rxtype == statics.Image)
|
if (rxtype == statics.Image)
|
||||||
@ -1181,13 +1184,17 @@ namespace oscardata
|
|||||||
public String GetMyBroadcastIP()
|
public String GetMyBroadcastIP()
|
||||||
{
|
{
|
||||||
String ip = "255.255.255.255";
|
String ip = "255.255.255.255";
|
||||||
|
/*
|
||||||
|
// selective BCs fail if the computer has multiple IPs
|
||||||
|
// therefore use 255.255.255.255
|
||||||
|
|
||||||
String[] myips = statics.getOwnIPs();
|
String[] myips = statics.getOwnIPs();
|
||||||
//Console.WriteLine("BClen: " + myips.Length.ToString());
|
Console.WriteLine("BClen: " + myips.Length.ToString());
|
||||||
// if PC has multiple IPs then use 255.255.255.255
|
// if PC has multiple IPs then use 255.255.255.255
|
||||||
/*for (int i = 0; i < myips.Length; i++)
|
for (int i = 0; i < myips.Length; i++)
|
||||||
{
|
{
|
||||||
Console.WriteLine("ip:" + myips[i]);
|
Console.WriteLine("ip:" + myips[i]);
|
||||||
}*/
|
}
|
||||||
if (myips.Length >= 1)
|
if (myips.Length >= 1)
|
||||||
{
|
{
|
||||||
statics.MyIP = myips[0];
|
statics.MyIP = myips[0];
|
||||||
@ -1199,7 +1206,7 @@ namespace oscardata
|
|||||||
ip += ".255";
|
ip += ".255";
|
||||||
//Console.WriteLine("BCip: " + ip);
|
//Console.WriteLine("BCip: " + ip);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1231,7 +1238,7 @@ namespace oscardata
|
|||||||
if (cb_safemode.Text.Contains("medium")) safemode = 2;
|
if (cb_safemode.Text.Contains("medium")) safemode = 2;
|
||||||
else if (cb_safemode.Text.Contains("high")) safemode = 4;
|
else if (cb_safemode.Text.Contains("high")) safemode = 4;
|
||||||
|
|
||||||
Byte[] txb = new byte[210];
|
Byte[] txb = new byte[260];
|
||||||
txb[0] = 0x3c; // ID of this message
|
txb[0] = 0x3c; // ID of this message
|
||||||
txb[1] = (Byte)tb_PBvol.Value;
|
txb[1] = (Byte)tb_PBvol.Value;
|
||||||
txb[2] = (Byte)tb_CAPvol.Value;
|
txb[2] = (Byte)tb_CAPvol.Value;
|
||||||
@ -1248,6 +1255,7 @@ namespace oscardata
|
|||||||
//Byte[] bpb = statics.StringToByteArray(cb_audioPB.Text);
|
//Byte[] bpb = statics.StringToByteArray(cb_audioPB.Text);
|
||||||
//Byte[] bcap = statics.StringToByteArray(cb_audioCAP.Text);
|
//Byte[] bcap = statics.StringToByteArray(cb_audioCAP.Text);
|
||||||
|
|
||||||
|
// 200 Bytes (from 10..209) name of selected sound device
|
||||||
for (int i=0; i<100; i++)
|
for (int i=0; i<100; i++)
|
||||||
{
|
{
|
||||||
if (i >= bpb.Length)
|
if (i >= bpb.Length)
|
||||||
@ -1261,6 +1269,28 @@ namespace oscardata
|
|||||||
txb[i + 110] = bcap[i];
|
txb[i + 110] = bcap[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 210 .. 229 = Callsign
|
||||||
|
Byte[] callarr = statics.StringToByteArray(tb_callsign.Text);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
if (i >= callarr.Length) txb[i+210] = 0;
|
||||||
|
else txb[i + 210] = callarr[i];
|
||||||
|
}
|
||||||
|
// 230 .. 239 = qthloc
|
||||||
|
Byte[] qtharr = statics.StringToByteArray(tb_myqthloc.Text);
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (i >= qtharr.Length) txb[i + 230] = 0;
|
||||||
|
else txb[i+230] = qtharr[i];
|
||||||
|
}
|
||||||
|
// 240 .. 259 = Name
|
||||||
|
Byte[] namearr = statics.StringToByteArray(tb_myname.Text);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
if (i >= namearr.Length) txb[i+240] = 0;
|
||||||
|
else txb[i + 240] = namearr[i];
|
||||||
|
}
|
||||||
|
|
||||||
if (statics.ModemIP == "1.2.3.4")
|
if (statics.ModemIP == "1.2.3.4")
|
||||||
{
|
{
|
||||||
// still searching a modem
|
// still searching a modem
|
||||||
|
@ -137,7 +137,7 @@
|
|||||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
|
||||||
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA+
|
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA+
|
||||||
JQAAAk1TRnQBSQFMAgEBFwEAAaABDAGgAQwBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
JQAAAk1TRnQBSQFMAgEBFwEAAdgBDAHYAQwBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo
|
||||||
AwABQAMAAWADAAEBAQABCAYAARgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
AwABQAMAAWADAAEBAQABCAYAARgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA
|
||||||
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5
|
||||||
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace oscardata
|
namespace oscardata
|
||||||
{
|
{
|
||||||
class KmProgressBar : ProgressBar
|
class KmProgressBar : ProgressBar
|
||||||
|
Binary file not shown.
@ -23,6 +23,7 @@ namespace oscardata
|
|||||||
public static Byte HTMLFile = 4;
|
public static Byte HTMLFile = 4;
|
||||||
public static Byte BinaryFile = 5;
|
public static Byte BinaryFile = 5;
|
||||||
public static Byte Audio = 6;
|
public static Byte Audio = 6;
|
||||||
|
public static Byte Userinfo = 7;
|
||||||
|
|
||||||
// the upper values are for internal use
|
// the upper values are for internal use
|
||||||
public static Byte ResamplingRate = 16;
|
public static Byte ResamplingRate = 16;
|
||||||
@ -185,6 +186,23 @@ namespace oscardata
|
|||||||
return enc.GetString(ban);
|
return enc.GetString(ban);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string ByteArrayToString(byte[] arr, int offset, int length)
|
||||||
|
{
|
||||||
|
Byte[] ba = new byte[arr.Length];
|
||||||
|
int dst = 0;
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (i >= arr.Length) break;
|
||||||
|
if (arr[i+ offset] != 0) ba[dst++] = arr[i+ offset];
|
||||||
|
}
|
||||||
|
Byte[] ban = new byte[dst];
|
||||||
|
Array.Copy(ba, ban, dst);
|
||||||
|
|
||||||
|
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
|
||||||
|
|
||||||
|
return enc.GetString(ban);
|
||||||
|
}
|
||||||
|
|
||||||
public static string ByteArrayToStringUtf8(byte[] arr, int offset = 0)
|
public static string ByteArrayToStringUtf8(byte[] arr, int offset = 0)
|
||||||
{
|
{
|
||||||
Byte[] ba = new byte[arr.Length];
|
Byte[] ba = new byte[arr.Length];
|
||||||
|
@ -123,8 +123,13 @@ namespace oscardata
|
|||||||
searchtimeout = 0;
|
searchtimeout = 0;
|
||||||
// message b contains audio devices and init status
|
// message b contains audio devices and init status
|
||||||
|
|
||||||
//String s = statics.ByteArrayToString(b,0);
|
statics.initAudioStatus = (b[0] == '1') ? 2 : 0;
|
||||||
String s = statics.ByteArrayToStringUtf8(b, 0);
|
statics.initAudioStatus |= (b[1] == '1') ? 1 : 0;
|
||||||
|
statics.initVoiceStatus = (b[2] == '1') ? 2 : 0;
|
||||||
|
statics.initVoiceStatus |= (b[3] == '1') ? 1 : 0;
|
||||||
|
|
||||||
|
//String s = statics.ByteArrayToString(b,4);
|
||||||
|
String s = statics.ByteArrayToStringUtf8(b, 4);
|
||||||
String[] sa1 = s.Split(new char[] { '^' });
|
String[] sa1 = s.Split(new char[] { '^' });
|
||||||
statics.AudioPBdevs = sa1[0].Split(new char[] { '~' });
|
statics.AudioPBdevs = sa1[0].Split(new char[] { '~' });
|
||||||
statics.AudioCAPdevs = sa1[1].Split(new char[] { '~' });
|
statics.AudioCAPdevs = sa1[1].Split(new char[] { '~' });
|
||||||
@ -143,18 +148,19 @@ namespace oscardata
|
|||||||
// FFT data
|
// FFT data
|
||||||
if (rxtype == statics.udp_fft)
|
if (rxtype == statics.udp_fft)
|
||||||
{
|
{
|
||||||
statics.PBfifousage = b[0];
|
int idx = 0;
|
||||||
statics.CAPfifousage = b[1];
|
statics.PBfifousage = b[idx++];
|
||||||
statics.RXlevelDetected = b[2];
|
statics.CAPfifousage = b[idx++];
|
||||||
statics.RXinSync = b[3];
|
statics.RXlevelDetected = b[idx++];
|
||||||
statics.maxRXlevel = b[4];
|
statics.RXinSync = b[idx++];
|
||||||
statics.maxTXlevel = b[5];
|
statics.maxRXlevel = b[idx++];
|
||||||
statics.tune_frequency = b[6];
|
statics.maxTXlevel = b[idx++];
|
||||||
|
statics.tune_frequency = b[idx++];
|
||||||
statics.tune_frequency <<= 8;
|
statics.tune_frequency <<= 8;
|
||||||
statics.tune_frequency += b[7];
|
statics.tune_frequency += b[idx++];
|
||||||
//Console.WriteLine("f:" + statics.tune_frequency);
|
//Console.WriteLine("f:" + statics.tune_frequency);
|
||||||
Byte[] b1 = new byte[b.Length - 6];
|
Byte[] b1 = new byte[b.Length - idx];
|
||||||
Array.Copy(b, 6, b1, 0, b1.Length);
|
Array.Copy(b, idx, b1, 0, b1.Length);
|
||||||
drawFftBitmap(b1);
|
drawFftBitmap(b1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user