Audio input, Audio optimisation

This commit is contained in:
Niellun
2025-06-02 17:53:50 +03:00
committed by Niellune
parent cb13925433
commit 5e97501c0c
17 changed files with 304 additions and 68 deletions
+4 -1
View File
@@ -29,7 +29,10 @@ Connector::Connector(uint16_t videoPadding)
Connector::~Connector()
{
stop();
_active = false;
if (_write_thread.joinable())
_write_thread.join();
if (_cipher)
{
+12
View File
@@ -0,0 +1,12 @@
#ifndef SRC_HELPER_IAUDIO_SENDER
#define SRC_HELPER_IAUDIO_SENDER
#include <cstdint>
class IAudioSender {
public:
virtual ~IAudioSender() = default;
virtual void sendAudio(uint8_t* data, uint32_t length) = 0;
};
#endif /* SRC_HELPER_IAUDIO_SENDER */
+3
View File
@@ -35,6 +35,9 @@
#define CMD_VERSION 204
#define CMD_ENCRYPTION 240
#define AUDIO_BUFFER_SIZE 2560
#define AUDIO_BUFFER_OFFSET 12
struct ProtocolCmdEntry
{
int cmd;
+1 -1
View File
@@ -1,7 +1,7 @@
#include "interface.h"
#include "resource/background.h"
#include "resource/font.h"
#include "resource/colors.h"
#include "resource/colours.h"
#include "settings.h"
#include "helper/protocol_const.h"
#include <iostream>
+1 -1
View File
@@ -23,7 +23,7 @@ extern "C"
#define FRAME_DELAY_INACTIVE 200
static const char *title = "Fast Car Play v0.4";
static const char *title = "Fast Car Play v0.5";
static SDL_Window *window = nullptr;
static SDL_Renderer *renderer = nullptr;
Uint32 evtStatus = (Uint32)-1;
+48 -25
View File
@@ -24,6 +24,8 @@ PcmAudio::PcmAudio(const char *name)
_faded = false;
_volume = 1.0;
_fadeVolume = Settings::audioFade;
_config.channels = 0;
_config.rate = 0;
if (_fadeVolume < 0)
_fadeVolume = 0;
if (_fadeVolume > 1)
@@ -64,17 +66,31 @@ void PcmAudio::callback(void *userdata, Uint8 *stream, int len)
PcmAudio *self = static_cast<PcmAudio *>(userdata);
const Message *segment = self->_data->peek();
if (segment && self->_offset == 0 && getConfig(segment->getInt(OFFSET_AUDIO_FORMAT)) != self->_config)
{
self->_reconfig = true;
self->_cv.notify_one();
bool underflow;
if (self->_data->has(self->_underflowSize))
{
underflow = false;
self->_underflowCount = 0;
}
else
{
underflow = true;
}
while (len > 0)
{
if (segment == nullptr || self->_reconfig)
if (segment == nullptr || self->_reconfig || underflow)
{
std::fill_n(stream, len, 0);
self->_faded = self->_fade;
self->_volume = self->_faded ? Settings::audioFade : 1;
if (underflow && self->_underflowCount++ < 20)
{
self->_data->clear();
return;
}
self->_reconfig = true;
self->_cv.notify_one();
return;
@@ -155,33 +171,40 @@ void PcmAudio::runner()
if (!segment)
continue;
_config = getConfig(segment->getInt(OFFSET_AUDIO_FORMAT));
if (device != 0)
ChannelConfig config = getConfig(segment->getInt(OFFSET_AUDIO_FORMAT));
if (_config != config)
{
SDL_PauseAudioDevice(device, 1);
SDL_CloseAudioDevice(device);
device = 0;
if (device != 0)
{
SDL_PauseAudioDevice(device, 1);
SDL_CloseAudioDevice(device);
device = 0;
}
// Configure new spec
SDL_zero(spec);
spec.freq = config.rate;
spec.format = AUDIO_S16SYS;
spec.channels = config.channels;
spec.samples = 4096;
spec.callback = callback;
spec.userdata = this;
device = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, 0);
if (device == 0)
{
std::cerr << _name << " Failed to open audio: " << SDL_GetError() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
_config = config;
}
// Configure new spec
SDL_zero(spec);
spec.freq = _config.rate;
spec.format = AUDIO_S16SYS;
spec.channels = _config.channels;
spec.samples = 4096;
spec.callback = callback;
spec.userdata = this;
_reconfig = false;
_offset = 0;
_reconfig = false;
_underflowCount = 0;
_underflowSize = spec.channels == 1 ? Settings::audioDelayCall : Settings::audioDelay;
device = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, 0);
if (device == 0)
{
std::cerr << _name << " Failed to open audio: " << SDL_GetError() << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
SDL_PauseAudioDevice(device, 0);
std::cout << _name << " Start playing " << _config.rate << "kHz " << (_config.channels == 2 ? "stereo" : "mono") << std::endl;
if (_fader)
+2
View File
@@ -58,6 +58,8 @@ private:
bool _faded;
float _volume;
float _fadeVolume;
int _underflowCount;
int _underflowSize;
std::thread _thread;
std::mutex _mtx;
+37 -1
View File
@@ -11,11 +11,11 @@ Protocol::Protocol(uint16_t width, uint16_t height, uint16_t fps, uint16_t paddi
videoData(Settings::videoQueue),
audioStreamMain(Settings::audioQueue),
audioStreamAux(Settings::audioQueue),
_recorder(Settings::audioQueue),
_width(width),
_height(height),
_fps(fps),
_phoneConnected(false)
{
}
@@ -163,6 +163,14 @@ void Protocol::sendMove(float dx, float dy)
send(CMD_TOUCH, false, buf, 16);
}
void Protocol::sendAudio(uint8_t *data, uint32_t length)
{
write_uint32_le(data, 5);
write_uint32_le(data + 4, 0);
write_uint32_le(data + 8, 3);
send(CMD_AUDIO_DATA, false, data, length);
}
void Protocol::sendFile(const char *filename, const uint8_t *data, uint32_t length)
{
// filename is assumed nullterminated, so strlen + 1 to include the '\0'
@@ -248,6 +256,9 @@ void Protocol::onPhone(bool connected)
std::cout << (connected ? "[Protocol] Phone connected" : "[Protocol] Phone disconnected") << std::endl;
if (!connected)
_recorder.stop();
pushEvent(_evtPhoneId, connected ? 1 : 0);
if (connected && Settings::onConnect.value.length() > 1)
@@ -257,11 +268,36 @@ void Protocol::onPhone(bool connected)
execute(Settings::onDisconnect.value.c_str());
}
void Protocol::onControl(int cmd)
{
switch (cmd)
{
case 1:
_recorder.start(this);
break;
case 2:
_recorder.stop();
break;
}
}
void Protocol::onData(uint32_t cmd, uint32_t length, uint8_t *data)
{
bool dispose = true;
switch (cmd)
{
case CMD_CONTROL:
if (length == 4)
{
int cmd = 0;
memcpy(&cmd, data, sizeof(int));
onControl(cmd);
}
break;
case CMD_PLUGGED:
onPhone(true);
break;
+8 -4
View File
@@ -3,11 +3,12 @@
#include "struct/atomic_queue.h"
#include "struct/message.h"
#include "helper/iaudio_sender.h"
#include "settings.h"
#include "connector.h"
#include "recorder.h"
class Protocol : private Connector
class Protocol : private Connector, public IAudioSender
{
public:
@@ -26,6 +27,7 @@ public:
void sendFile(const char *filename, int value);
void sendClick(float x, float y, bool down);
void sendMove(float dx, float dy);
void sendAudio(uint8_t *data, uint32_t length) override;
AtomicQueue<Message> videoData;
AtomicQueue<Message> audioStreamMain;
@@ -40,15 +42,17 @@ private:
void onStatus(uint8_t status) override;
void onDevice(bool connected) override;
void onControl(int cmd);
void onData(uint32_t cmd, uint32_t length, uint8_t *data) override;
void onPhone(bool connected);
static const char *cmdString(int cmd);
static const char *cmdString(int cmd);
Recorder _recorder;
uint16_t _width;
uint16_t _height;
uint16_t _fps;
bool _phoneConnected;
bool _phoneConnected;
uint32_t _evtStatusId = (uint32_t)-1;
uint32_t _evtPhoneId = (uint32_t)-1;
+89
View File
@@ -0,0 +1,89 @@
#include "recorder.h"
#include <iostream>
#include <cstring>
#include "helper/protocol_const.h"
#include "helper/functions.h"
#include "settings.h"
Recorder::Recorder(uint16_t buffSize)
: _sender(nullptr), _active(false), _device(0), _data(buffSize)
{
}
Recorder::~Recorder()
{
stop();
if (_thread.joinable())
_thread.join();
}
void Recorder::start(IAudioSender *sender)
{
if (_active)
return;
if (_thread.joinable())
_thread.join();
_sender = sender;
_active = true;
_thread = std::thread(&Recorder::runner, this);
}
void Recorder::stop()
{
if (!_active)
return;
_active = false;
_data.notify();
}
void Recorder::AudioCallback(void *userdata, Uint8 *stream, int len)
{
Recorder *self = static_cast<Recorder *>(userdata);
std::unique_ptr<AudioChunk> frame(new AudioChunk(AUDIO_BUFFER_OFFSET + len));
std::memcpy(frame.get()->data + AUDIO_BUFFER_OFFSET, stream, len);
self->_data.pushDiscard(std::move(frame));
}
void Recorder::runner()
{
setThreadName("recorder");
SDL_AudioDeviceID device = 0;
SDL_AudioSpec spec;
SDL_zero(spec);
spec.freq = 16000;
spec.format = AUDIO_S16LSB;
spec.channels = 1;
spec.samples = AUDIO_BUFFER_SIZE / 2; // = 2560 bytes (1280 samples * 2 bytes)
spec.callback = AudioCallback;
spec.userdata = this;
device = SDL_OpenAudioDevice(nullptr, SDL_TRUE, &spec, nullptr, 0);
if (device == 0)
{
std::cerr << "[Recording] Failed to open audio: " << SDL_GetError() << std::endl;
_active = false;
return;
}
SDL_PauseAudioDevice(device, 0);
while (_active)
{
std::unique_ptr<AudioChunk> buffer = _data.pop();
if (buffer && _sender)
_sender->sendAudio(buffer.get()->data, buffer.get()->size);
else if (_active)
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
SDL_PauseAudioDevice(device, 1);
SDL_CloseAudioDevice(device);
}
+53
View File
@@ -0,0 +1,53 @@
#ifndef SRC_RECORDER
#define SRC_RECORDER
#include <thread>
#include <atomic>
#include <SDL2/SDL.h>
#include "helper/iaudio_sender.h"
#include "struct/atomic_queue.h"
class AudioChunk
{
public:
AudioChunk(uint16_t size)
: data(new uint8_t[size]), size(size)
{
}
~AudioChunk()
{
delete[] data;
}
// Deleted copy constructor/assignment
AudioChunk(const AudioChunk &) = delete;
AudioChunk &operator=(const AudioChunk &) = delete;
uint8_t *data;
size_t size;
};
class Recorder
{
public:
Recorder(uint16_t buffSize);
~Recorder();
void start(IAudioSender *sender);
void stop();
private:
static void AudioCallback(void *userdata, Uint8 *stream, int len);
void runner();
IAudioSender *_sender;
std::atomic<bool> _active;
std::thread _thread;
SDL_AudioDeviceID _device;
AtomicQueue<AudioChunk> _data;
};
#endif /* SRC_RECORDER */
+1
View File
@@ -40,6 +40,7 @@ public:
static inline Setting<int> videoQueue{"video-buffer-size", 32};
static inline Setting<int> audioQueue{"audio-buffer-size", 16};
static inline Setting<int> audioDelay{"audio-buffer-wait", 2};
static inline Setting<int> audioDelayCall{"audio-buffer-wait-call", 8};
static inline Setting<float> audioFade{"audio-fade", 0.3};
static inline Setting<std::string> audioDriver{"audio-driver", ""};
static inline Setting<std::string> onConnect{"on-connect-script", ""};
+5
View File
@@ -68,6 +68,11 @@ public:
return item;
}
bool has(uint8_t count)
{
return _count >= count;
}
bool wait(atomic<bool> &waitFlag, uint8_t count = 0)
{
unique_lock<std::mutex> lock(_mtx);