96 lines
3.2 KiB
C++
96 lines
3.2 KiB
C++
#include "sound.hpp"
|
|
#include "bfsk.hpp"
|
|
#include "config.hpp"
|
|
#include "x25519_handshake.hpp"
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include <atomic>
|
|
#include <vector>
|
|
#include <cmath>
|
|
#include <portaudio.h>
|
|
|
|
constexpr int CAPTURE_SECONDS=3;
|
|
static std::atomic<bool> gSoundActive{false};
|
|
static std::thread gSoundThread;
|
|
static std::vector<float> gInputBuffer;
|
|
static size_t gWritePos=0;
|
|
static std::vector<float> gOutputBuffer;
|
|
static size_t gReadPos=0;
|
|
|
|
static int audioCallback(const void *input,void *output,unsigned long frameCount,const PaStreamCallbackTimeInfo*,PaStreamCallbackFlags,void*){
|
|
const float *in=(const float*)input;
|
|
float *out=(float*)output;
|
|
for(unsigned long i=0;i<frameCount;i++){
|
|
if(gWritePos<gInputBuffer.size()){
|
|
gInputBuffer[gWritePos++]=in?in[i]:0.0f;
|
|
}
|
|
float sample=0.0f;
|
|
if(gReadPos<gOutputBuffer.size()){
|
|
sample=gOutputBuffer[gReadPos++];
|
|
}
|
|
out[i*2+0]=sample;
|
|
out[i*2+1]=sample;
|
|
}
|
|
return paContinue;
|
|
}
|
|
|
|
static void soundThreadFunc(AppConfig config){
|
|
PaError err=Pa_Initialize();
|
|
if(err!=paNoError)return;
|
|
PaStreamParameters inParams,outParams;
|
|
inParams.device=Pa_GetDefaultInputDevice();
|
|
if(inParams.device==paNoDevice){Pa_Terminate();return;}
|
|
inParams.channelCount=1;
|
|
inParams.sampleFormat=paFloat32;
|
|
inParams.suggestedLatency=Pa_GetDeviceInfo(inParams.device)->defaultLowInputLatency;
|
|
inParams.hostApiSpecificStreamInfo=nullptr;
|
|
outParams.device=Pa_GetDefaultOutputDevice();
|
|
if(outParams.device==paNoDevice){Pa_Terminate();return;}
|
|
outParams.channelCount=2;
|
|
outParams.sampleFormat=paFloat32;
|
|
outParams.suggestedLatency=Pa_GetDeviceInfo(outParams.device)->defaultLowOutputLatency;
|
|
outParams.hostApiSpecificStreamInfo=nullptr;
|
|
PaStream* stream=nullptr;
|
|
err=Pa_OpenStream(&stream,&inParams,&outParams,SAMPLE_RATE,256,paNoFlag,audioCallback,nullptr);
|
|
if(err!=paNoError){Pa_Terminate();return;}
|
|
err=Pa_StartStream(stream);
|
|
if(err!=paNoError){Pa_CloseStream(stream);Pa_Terminate();return;}
|
|
Pa_Sleep(CAPTURE_SECONDS*1000);
|
|
Pa_StopStream(stream);
|
|
Pa_CloseStream(stream);
|
|
Pa_Terminate();
|
|
auto received=bfskDemodulate(gInputBuffer);
|
|
if(!received.empty()){
|
|
if(received.size()>=33 && received[0]=='E'){
|
|
uint8_t otherPub[32];
|
|
for(int i=0;i<32;i++){
|
|
otherPub[i]=received[1+i];
|
|
}
|
|
x25519ComputeShared(config,otherPub);
|
|
}
|
|
}
|
|
gSoundActive=false;
|
|
}
|
|
|
|
void soundFind(AppConfig &config){
|
|
if(config.soundExchangeActive)return;
|
|
config.soundExchangeActive=true;
|
|
gSoundActive=true;
|
|
x25519GenerateEphemeral(config);
|
|
std::vector<uint8_t> packet;packet.push_back('E');
|
|
packet.insert(packet.end(),config.ephemeralPub,config.ephemeralPub+32);
|
|
gOutputBuffer=bfskModulate(packet);
|
|
gReadPos=0;
|
|
gInputBuffer.clear();
|
|
gInputBuffer.resize(SAMPLE_RATE*CAPTURE_SECONDS,0.0f);
|
|
gWritePos=0;
|
|
gSoundThread=std::thread(soundThreadFunc,config);
|
|
}
|
|
|
|
void soundLose(AppConfig &config){
|
|
if(!config.soundExchangeActive)return;
|
|
config.soundExchangeActive=false;
|
|
if(gSoundActive)gSoundActive=false;
|
|
if(gSoundThread.joinable())gSoundThread.join();
|
|
}
|