Cerberus/sound.cpp
wheelchairy 118875234a upd
2025-01-28 22:33:54 +03:00

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();
}