diff --git a/examples/ggwave-cli/main.cpp b/examples/ggwave-cli/main.cpp index 2bd2cb9..bd53cc5 100644 --- a/examples/ggwave-cli/main.cpp +++ b/examples/ggwave-cli/main.cpp @@ -33,8 +33,6 @@ int main(int argc, char** argv) { auto ggWave = GGWave_instance(); - ggWave->setTxMode(GGWave::TxMode::VariableLength); - printf("Selecting Tx protocol %d\n", txProtocol); std::mutex mutex; diff --git a/examples/ggwave-common-sdl2.cpp b/examples/ggwave-common-sdl2.cpp index 2cdc39a..ba4242e 100644 --- a/examples/ggwave-common-sdl2.cpp +++ b/examples/ggwave-common-sdl2.cpp @@ -73,12 +73,6 @@ extern "C" { int doInit() { return GGWave_init(-1, -1); } - - EMSCRIPTEN_KEEPALIVE - int setTxMode(int txMode) { - g_ggWave->setTxMode((GGWave::TxMode)(txMode)); - return 0; - } } void GGWave_setDefaultCaptureDeviceName(std::string name) { diff --git a/examples/ggwave-gui/main.cpp b/examples/ggwave-gui/main.cpp index 18cdbef..fff1df8 100644 --- a/examples/ggwave-gui/main.cpp +++ b/examples/ggwave-gui/main.cpp @@ -69,8 +69,6 @@ int main(int argc, char** argv) { auto ggWave = GGWave_instance(); - ggWave->setTxMode(GGWave::TxMode::VariableLength); - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { fprintf(stderr, "Error: %s\n", SDL_GetError()); return -1; diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index 3496c90..e1eba88 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -12,19 +12,12 @@ class ReedSolomon; class GGWave { public: - enum TxMode { - FixedLength = 0, - VariableLength, - }; - static constexpr auto kMaxSamplesPerFrame = 1024; static constexpr auto kMaxDataBits = 256; static constexpr auto kMaxDataSize = 256; static constexpr auto kMaxLength = 140; static constexpr auto kMaxSpectrumHistory = 4; static constexpr auto kMaxRecordedFrames = 1024; - static constexpr auto kDefaultFixedLength = 82; - static constexpr auto kDefaultFixedECCBytes = 32; struct TxProtocol { const char * name; @@ -53,11 +46,6 @@ public: int aSampleSizeBytesOut); ~GGWave(); - void setTxMode(TxMode aTxMode) { - txMode = aTxMode; - init(0, "", getDefultTxProtocol()); - } - bool init(int textLength, const char * stext, const TxProtocol & aProtocol); void send(const CBQueueAudio & cbQueueAudio); void receive(const CBDequeueAudio & CBDequeueAudio); @@ -175,7 +163,6 @@ private: std::string textToSend; - TxMode txMode = TxMode::FixedLength; TxProtocol txProtocol; AmplitudeData outputBlock; diff --git a/src/ggwave.cpp b/src/ggwave.cpp index 4ba6d65..92c56e5 100644 --- a/src/ggwave.cpp +++ b/src/ggwave.cpp @@ -121,7 +121,17 @@ GGWave::GGWave( sampleSizeBytesIn = aSampleSizeBytesIn; sampleSizeBytesOut = aSampleSizeBytesOut; - setTxMode(TxMode::VariableLength); + isamplesPerFrame = 1.0f/samplesPerFrame; + hzPerSample = sampleRateIn/samplesPerFrame; + ihzPerSample = 1.0/hzPerSample; + freqDelta_bin = 1; + freqDelta_hz = 2*hzPerSample; + + nBitsInMarker = 16; + nMarkerFrames = 16; + nPostMarkerFrames = 0; + + init(0, "", getDefultTxProtocol()); } GGWave::~GGWave() { @@ -138,36 +148,69 @@ bool GGWave::init(int textLength, const char * stext, const TxProtocol & aProtoc txProtocol = aProtocol; const uint8_t * text = reinterpret_cast(stext); - frameId = 0; - nIterations = 0; + + nECCBytesPerTx = getECCBytesForLength(textLength); + sendDataLength = textLength + 3; + + if (rsData) delete rsData; + if (rsLength) delete rsLength; + + rsData = new RS::ReedSolomon(textLength, nECCBytesPerTx); + rsLength = new RS::ReedSolomon(1, 2); + hasData = false; + txData.fill(0); + txDataEncoded.fill(0); - isamplesPerFrame = 1.0f/samplesPerFrame; - sendVolume = ((double)(txProtocol.paramVolume))/100.0f; - hzPerSample = sampleRateIn/samplesPerFrame; - ihzPerSample = 1.0/hzPerSample; + if (textLength > 0) { + txData[0] = textLength; + for (int i = 0; i < textLength; ++i) txData[i + 1] = text[i]; + rsLength->Encode(txData.data(), txDataEncoded.data()); + rsData->Encode(txData.data() + 1, txDataEncoded.data() + 3); - nDataBitsPerTx = 8*txProtocol.paramBytesPerTx; - nECCBytesPerTx = (txMode == TxMode::FixedLength) ? kDefaultFixedECCBytes : getECCBytesForLength(textLength); + hasData = true; + } + + // Rx + receivingData = false; + analyzingData = false; framesToAnalyze = 0; framesLeftToAnalyze = 0; framesToRecord = 0; framesLeftToRecord = 0; - nBitsInMarker = 16; - nMarkerFrames = 16; - nPostMarkerFrames = 0; - sendDataLength = (txMode == TxMode::FixedLength) ? kDefaultFixedLength : textLength + 3; - freqDelta_bin = 1; - freqDelta_hz = 2*hzPerSample; + sampleAmplitude.fill(0); + sampleSpectrum.fill(0); + for (auto & s : sampleAmplitudeHistory) { + s.fill(0); + } + + rxData.fill(0); + + for (int i = 0; i < samplesPerFrame; ++i) { + fftOut[i].real(0.0f); + fftOut[i].imag(0.0f); + } + + return true; +} + +void GGWave::send(const CBQueueAudio & cbQueueAudio) { + int samplesPerFrameOut = (sampleRateOut/sampleRateIn)*samplesPerFrame; + if (sampleRateOut != sampleRateIn) { + printf("Resampling from %d Hz to %d Hz\n", (int) sampleRateIn, (int) sampleRateOut); + } + + frameId = 0; + nIterations = 0; + + nDataBitsPerTx = 8*txProtocol.paramBytesPerTx; + sendVolume = ((double)(txProtocol.paramVolume))/100.0f; freqStart_hz = hzPerSample*txProtocol.paramFreqStart; outputBlock.fill(0); - txData.fill(0); - txDataEncoded.fill(0); - for (int k = 0; k < (int) phaseOffsets.size(); ++k) { phaseOffsets[k] = (M_PI*k)/(nDataBitsPerTx); } @@ -195,57 +238,6 @@ bool GGWave::init(int textLength, const char * stext, const TxProtocol & aProtoc } } - if (rsData) delete rsData; - if (rsLength) delete rsLength; - - if (txMode == TxMode::FixedLength) { - rsData = new RS::ReedSolomon(kDefaultFixedLength, kDefaultFixedLength); - rsLength = nullptr; - } else { - rsData = new RS::ReedSolomon(textLength, nECCBytesPerTx); - rsLength = new RS::ReedSolomon(1, 2); - } - - if (textLength > 0) { - if (txMode == TxMode::FixedLength) { - for (int i = 0; i < textLength; ++i) txData[i] = text[i]; - rsData->Encode(txData.data(), txDataEncoded.data()); - } else { - txData[0] = textLength; - for (int i = 0; i < textLength; ++i) txData[i + 1] = text[i]; - rsData->Encode(txData.data() + 1, txDataEncoded.data() + 3); - rsLength->Encode(txData.data(), txDataEncoded.data()); - } - - hasData = true; - } - - // Rx - receivingData = false; - analyzingData = false; - - sampleAmplitude.fill(0); - sampleSpectrum.fill(0); - for (auto & s : sampleAmplitudeHistory) { - s.fill(0); - } - - rxData.fill(0); - - for (int i = 0; i < samplesPerFrame; ++i) { - fftOut[i].real(0.0f); - fftOut[i].imag(0.0f); - } - - return true; -} - -void GGWave::send(const CBQueueAudio & cbQueueAudio) { - int samplesPerFrameOut = (sampleRateOut/sampleRateIn)*samplesPerFrame; - if (sampleRateOut != sampleRateIn) { - printf("Resampling from %d Hz to %d Hz\n", (int) sampleRateIn, (int) sampleRateOut); - } - while (hasData) { int nBytesPerTx = nDataBitsPerTx/8; std::fill(outputBlock.begin(), outputBlock.end(), 0.0f); @@ -320,7 +312,7 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) { ::addAmplitudeSmooth(bit1Amplitude[k/2], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, txProtocol.paramFramesPerTx); } } - } else if (txMode == TxMode::VariableLength && frameId < + } else if (frameId < (nMarkerFrames + nPostMarkerFrames) + ((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*txProtocol.paramFramesPerTx + (nMarkerFrames)) { @@ -364,7 +356,6 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { // todo : support for non-float input auto nBytesRecorded = CBDequeueAudio(sampleAmplitude.data(), samplesPerFrame*sampleSizeBytesIn); - if (nBytesRecorded != 0) { { sampleAmplitudeHistory[historyId] = sampleAmplitude; @@ -373,7 +364,7 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { historyId = 0; } - if (historyId == 0 && (receivingData == false || (receivingData && txMode == TxMode::VariableLength))) { + if (historyId == 0 && (receivingData == false || receivingData)) { std::fill(sampleAmplitudeAverage.begin(), sampleAmplitudeAverage.end(), 0.0f); for (auto & s : sampleAmplitudeHistory) { for (int i = 0; i < samplesPerFrame; ++i) { @@ -423,6 +414,7 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { const int stepsPerFrame = 16; const int step = samplesPerFrame/stepsPerFrame; + const int encodedOffset = 3; bool isValid = false; for (const auto & rxProtocol : txProtocols) { @@ -431,11 +423,9 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { framesToAnalyze = nMarkerFrames*stepsPerFrame; framesLeftToAnalyze = framesToAnalyze; for (int ii = nMarkerFrames*stepsPerFrame - 1; ii >= nMarkerFrames*stepsPerFrame/2; --ii) { - bool knownLength = txMode == TxMode::FixedLength; + bool knownLength = false; const int offsetStart = ii; - const int encodedOffset = (knownLength) ? 0 : 3; - for (int itx = 0; itx < 1024; ++itx) { int offsetTx = offsetStart + itx*rxProtocol.paramFramesPerTx*stepsPerFrame; if (offsetTx >= recvDuration_frames*stepsPerFrame || (itx + 1)*rxProtocol.paramBytesPerTx >= (int) txDataEncoded.size()) { @@ -484,48 +474,30 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { } } - if (txMode == TxMode::VariableLength) { - if (itx*rxProtocol.paramBytesPerTx > 3 && knownLength == false) { - if ((rsLength->Decode(txDataEncoded.data(), rxData.data()) == 0) && (rxData[0] > 0 && rxData[0] <= 140)) { - knownLength = true; - } else { - break; - } + if (itx*rxProtocol.paramBytesPerTx > 3 && knownLength == false) { + if ((rsLength->Decode(txDataEncoded.data(), rxData.data()) == 0) && (rxData[0] > 0 && rxData[0] <= 140)) { + knownLength = true; + } else { + break; } } } - if (txMode == TxMode::VariableLength && knownLength) { + if (knownLength) { if (rsData) delete rsData; rsData = new RS::ReedSolomon(rxData[0], ::getECCBytesForLength(rxData[0])); - } - if (knownLength) { - if (txMode == FixedLength) { - if (rsData->Decode(txDataEncoded.data() + encodedOffset, rxData.data()) == 0) { - if (rxData[0] == 'A') { - printf("[ANSWER] Received sound data successfully!\n"); - } else if (rxData[0] == 'O') { - printf("[OFFER] Received sound data successfully!\n"); - } + int decodedLength = rxData[0]; + if (rsData->Decode(txDataEncoded.data() + encodedOffset, rxData.data()) == 0) { + if (rxData[0] != 0) { + std::string s((char *) rxData.data(), decodedLength); + + printf("Decoded length = %d\n", decodedLength); + printf("Received sound data successfully: '%s'\n", s.c_str()); isValid = true; hasNewRxData = true; - lastRxDataLength = kDefaultFixedLength; - } - } else { - int decodedLength = rxData[0]; - if (rsData->Decode(txDataEncoded.data() + encodedOffset, rxData.data()) == 0) { - if (rxData[0] != 0) { - std::string s((char *) rxData.data(), decodedLength); - - printf("Decoded length = %d\n", decodedLength); - printf("Received sound data successfully: '%s'\n", s.c_str()); - - isValid = true; - hasNewRxData = true; - lastRxDataLength = decodedLength; - } + lastRxDataLength = decodedLength; } } } @@ -585,17 +557,17 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) { if (isReceiving) { std::time_t timestamp = std::time(nullptr); printf("%sReceiving sound data ...\n", std::asctime(std::localtime(×tamp))); + rxData.fill(0); receivingData = true; - if (txMode == TxMode::FixedLength) { - recvDuration_frames = 2*nMarkerFrames + nPostMarkerFrames + maxFramesPerTx()*((kDefaultFixedLength + kDefaultFixedECCBytes)/minBytesPerTx() + 1); - } else { - recvDuration_frames = 2*nMarkerFrames + nPostMarkerFrames + maxFramesPerTx()*((kMaxLength + ::getECCBytesForLength(kMaxLength))/minBytesPerTx() + 1); - } + + // max recieve duration + recvDuration_frames = 2*nMarkerFrames + nPostMarkerFrames + maxFramesPerTx()*((kMaxLength + ::getECCBytesForLength(kMaxLength))/minBytesPerTx() + 1); + framesToRecord = recvDuration_frames; framesLeftToRecord = recvDuration_frames; } - } else if (txMode == TxMode::VariableLength) { + } else { bool isEnded = false; for (const auto & rxProtocol : txProtocols) {