#include "sound.hpp" #include "bfsk.hpp" #include "config.hpp" #include "x25519_handshake.hpp" #include #include #include #include #include #include extern "C" { #include "monocypher.h" } constexpr int CAPTURE_SECONDS = 3; static std::atomic gSoundActive{false}; static std::thread gSoundThread; static std::vector gInputBuffer; static size_t gWritePos = 0; static std::vector gOutputBuffer; static size_t gReadPos = 0; static int audioCallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) { (void)timeInfo; (void)statusFlags; (void)userData; const float *in = static_cast(input); float *out = static_cast(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) { std::cerr << CLR_RED "[sound] Pa_Initialize error: " << Pa_GetErrorText(err) << CLR_RESET "\n"; return; } PaStreamParameters inParams, outParams; inParams.device = Pa_GetDefaultInputDevice(); if (inParams.device == paNoDevice) { std::cerr << CLR_RED "[sound] Нет устройства ввода.\n" CLR_RESET; 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) { std::cerr << CLR_RED "[sound] Нет устройства вывода.\n" CLR_RESET; 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) { std::cerr << CLR_RED "[sound] Pa_OpenStream error: " << Pa_GetErrorText(err) << CLR_RESET "\n"; Pa_Terminate(); return; } err = Pa_StartStream(stream); if (err != paNoError) { std::cerr << CLR_RED "[sound] Pa_StartStream error: " << Pa_GetErrorText(err) << CLR_RESET "\n"; Pa_CloseStream(stream); Pa_Terminate(); return; } std::cout << CLR_BLUE "[sound] Старт записи/воспроизведения (3 сек)...\n" CLR_RESET; Pa_Sleep(CAPTURE_SECONDS * 1000); Pa_StopStream(stream); Pa_CloseStream(stream); Pa_Terminate(); std::cout << CLR_BLUE "[sound] Остановка аудиопотока...\n" CLR_RESET; auto received = bfskDemodulate(gInputBuffer); if (!received.empty()) { if (received.size() >= 33 && received[0] == 'E') { uint8_t otherPub[32]; std::memcpy(otherPub, received.data() + 1, 32); x25519ComputeShared(config, otherPub); std::cout << CLR_GREEN "[x25519] Общий сеансовый ключ вычислен!\n" CLR_RESET; } else { std::cout << CLR_YELLOW "[sound] Получены " << received.size() << " байт, но не формат 'E' + 32 байта.\n" CLR_RESET; } } else { std::cout << CLR_YELLOW "[sound] Ничего не демодулировано.\n" CLR_RESET; } gSoundActive = false; } void soundFind(AppConfig &config) { if (config.soundExchangeActive) { std::cout << CLR_YELLOW "[sound] Уже идёт процесс.\n" CLR_RESET; return; } config.soundExchangeActive = true; gSoundActive = true; x25519GenerateEphemeral(config); std::vector 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); std::cout << CLR_GREEN "[sound] Отправляем свой публичный ключ X25519 и слушаем!\n" CLR_RESET; } void soundLose(AppConfig &config) { if (!config.soundExchangeActive) { std::cout << CLR_YELLOW "[sound] Процесс не активен.\n" CLR_RESET; return; } config.soundExchangeActive = false; if (gSoundActive) { gSoundActive = false; } if (gSoundThread.joinable()) { gSoundThread.join(); } std::cout << CLR_GREEN "[sound] Процесс остановлен.\n" CLR_RESET; }