mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
Audio fade on notifications and optimisations
This commit is contained in:
+18
-16
@@ -30,6 +30,12 @@ Connector::~Connector()
|
||||
{
|
||||
stop();
|
||||
|
||||
if (_cipher)
|
||||
{
|
||||
delete _cipher;
|
||||
_cipher = nullptr;
|
||||
}
|
||||
|
||||
if (_device)
|
||||
{
|
||||
libusb_release_interface(_device, 0);
|
||||
@@ -53,7 +59,6 @@ void Connector::start(IProtocol *protocol)
|
||||
|
||||
_active = true;
|
||||
_write_thread = std::thread(&Connector::write_loop, this);
|
||||
_read_thread = std::thread(&Connector::read_loop, this);
|
||||
}
|
||||
|
||||
void Connector::stop()
|
||||
@@ -234,7 +239,7 @@ void Connector::printBytes(uint32_t length, uint8_t *data, uint16_t max)
|
||||
std::cout << " > ";
|
||||
for (size_t i = 0; (i < length) & (i < max); ++i)
|
||||
{
|
||||
std::cout << data[i];
|
||||
std::cout << std::setw(4) << (uint32_t)(data[i]);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
@@ -299,16 +304,8 @@ void Connector::read_loop()
|
||||
|
||||
// Set thread name
|
||||
setThreadName("protocol-reader");
|
||||
while (_active)
|
||||
while (_active && _connected)
|
||||
{
|
||||
if (!_connected)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait_for(lock, std::chrono::seconds(1), [&]()
|
||||
{ return !_active.load(); });
|
||||
continue;
|
||||
}
|
||||
|
||||
int result = libusb_bulk_transfer(_device, _endpoint_in, reinterpret_cast<uint8_t *>(&header), sizeof(Header), &transferred, READ_TIMEOUT);
|
||||
|
||||
if (result == LIBUSB_ERROR_NO_DEVICE)
|
||||
@@ -322,6 +319,7 @@ void Connector::read_loop()
|
||||
|
||||
if (result != LIBUSB_SUCCESS || transferred != sizeof(Header))
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -337,10 +335,6 @@ void Connector::read_loop()
|
||||
libusb_bulk_transfer(_device, _endpoint_in, data, header.length, &transferred, READ_TIMEOUT);
|
||||
}
|
||||
|
||||
#ifdef PROTOCOL_DEBUG
|
||||
printMessage(header.type, header.length, data, header.magic == MAGIC_ENC, false);
|
||||
#endif
|
||||
|
||||
if (!_protocol)
|
||||
{
|
||||
free(data);
|
||||
@@ -349,7 +343,6 @@ void Connector::read_loop()
|
||||
|
||||
if (header.magic == MAGIC_ENC)
|
||||
{
|
||||
|
||||
if (!_cipher)
|
||||
{
|
||||
std::cout << "[Connection] Received encrypted command " << header.type << " but cipher is not initialised" << std::endl;
|
||||
@@ -362,6 +355,13 @@ void Connector::read_loop()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROTOCOL_DEBUG
|
||||
printMessage(header.type, header.length, data, header.magic == MAGIC_ENC, false);
|
||||
|
||||
if (header.type == 7 && header.length < 100)
|
||||
printBytes(header.length, data, 30);
|
||||
#endif
|
||||
|
||||
if (padding > 0)
|
||||
std::fill(data + header.length, data + header.length + padding, 0);
|
||||
_protocol->onData(header.type, header.length, data);
|
||||
@@ -383,6 +383,8 @@ void Connector::write_loop()
|
||||
{
|
||||
status("Initialising dongle");
|
||||
std::cout << "[Connection] Device connected" << std::endl;
|
||||
|
||||
_read_thread = std::thread(&Connector::read_loop, this);
|
||||
if (_protocol)
|
||||
_protocol->onDevice(true);
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
struct Header
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t length;
|
||||
int32_t length;
|
||||
uint32_t type;
|
||||
uint32_t typecheck;
|
||||
};
|
||||
|
||||
+21
-15
@@ -179,16 +179,16 @@ void processEvents(Protocol &protocol, bool processMouse)
|
||||
}
|
||||
}
|
||||
|
||||
if(processMouse && (downX>=0 || upX>=0 || motionX>=0))
|
||||
if (processMouse && (downX >= 0 || upX >= 0 || motionX >= 0))
|
||||
{
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||
if(downX>=0)
|
||||
if (downX >= 0)
|
||||
protocol.sendClick(1.0 * downX / window_width, 1.0 * downY / window_height, true);
|
||||
if(motionX>=0)
|
||||
if (motionX >= 0)
|
||||
protocol.sendMove(1.0 * motionX / window_width, 1.0 * motionY / window_height);
|
||||
if(upX>=0)
|
||||
protocol.sendClick(1.0 * upX / window_width, 1.0 * upY / window_height, false);
|
||||
if (upX >= 0)
|
||||
protocol.sendClick(1.0 * upX / window_width, 1.0 * upY / window_height, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,11 +208,10 @@ void application()
|
||||
VideoBuffer videoBuffer;
|
||||
Protocol protocol(Settings::sourceWidth, Settings::sourceHeight, Settings::sourceFps, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
Decoder decoder;
|
||||
PcmAudio audio0, audio1, audio2;
|
||||
PcmAudio audioMain("Main"), audioAux("Aux");
|
||||
decoder.start(&protocol.videoData, &videoBuffer, AV_CODEC_ID_H264);
|
||||
audio0.start(&protocol.audioStream0);
|
||||
audio1.start(&protocol.audioStream1);
|
||||
audio2.start(&protocol.audioStream2);
|
||||
audioMain.start(&protocol.audioStreamMain);
|
||||
audioAux.start(&protocol.audioStreamAux, &audioMain);
|
||||
protocol.start(onStatus);
|
||||
|
||||
UFont textFont(font, font_len, Settings::fontSize);
|
||||
@@ -236,9 +235,9 @@ void application()
|
||||
uint32_t frameDelay = inactiveDelay;
|
||||
active = true;
|
||||
uint32_t latestid = 0;
|
||||
Uint32 frameStart = SDL_GetTicks();
|
||||
while (active)
|
||||
{
|
||||
Uint32 frameStart = SDL_GetTicks();
|
||||
processEvents(protocol, videoPrepared);
|
||||
|
||||
if (connected != protocol.phoneConnected)
|
||||
@@ -266,8 +265,8 @@ void application()
|
||||
SDL_RenderCopy(renderer, videoRenderer.texture, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
if(frameid!=latestid+1)
|
||||
std::cout << "[Main] Fram drop from " << frameid - latestid - 1 << std::endl;
|
||||
if (frameid != latestid + 1)
|
||||
std::cout << "[Main] Frame drop " << frameid - latestid - 1 << " on " << frameid << std::endl;
|
||||
latestid = frameid;
|
||||
videoBuffer.consume();
|
||||
}
|
||||
@@ -291,11 +290,15 @@ void application()
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 frameTime = SDL_GetTicks() - frameStart;
|
||||
Uint32 frameEnd = SDL_GetTicks();
|
||||
Uint32 frameTime = frameEnd - frameStart;
|
||||
if (frameTime < frameDelay)
|
||||
{
|
||||
SDL_Delay(frameDelay - frameTime); // Sleep only the remaining time
|
||||
frameStart = frameStart + frameDelay;
|
||||
}
|
||||
else
|
||||
frameStart = frameEnd;
|
||||
}
|
||||
std::cout << "[Main] Stopping" << std::endl;
|
||||
SDL_HideWindow(window);
|
||||
@@ -344,7 +347,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
// Create SDL window centered on screen
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
|
||||
if (Settings::fastScale)
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
|
||||
else
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
|
||||
window = SDL_CreateWindow(title,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED,
|
||||
@@ -361,7 +367,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
// Create accelerated renderer for the window
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
renderer = SDL_CreateRenderer(window, -1, (Settings::vsync ? (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) : SDL_RENDERER_ACCELERATED));
|
||||
if (renderer)
|
||||
{
|
||||
std::cout << "[Main] Started" << std::endl;
|
||||
|
||||
+68
-27
@@ -11,11 +11,52 @@ ChannelConfig PcmAudio::_configTable[] = {
|
||||
};
|
||||
|
||||
// Implementation
|
||||
PcmAudio::PcmAudio() {}
|
||||
PcmAudio::PcmAudio(const char *name)
|
||||
{
|
||||
if (!name || strlen(name) < 1)
|
||||
{
|
||||
_name = "[Audio]";
|
||||
return;
|
||||
}
|
||||
_name = "[Audio ";
|
||||
_name = _name + name + "]";
|
||||
_fade = false;
|
||||
_faded = false;
|
||||
_volume = 1.0;
|
||||
_fadeVolume = Settings::audioFade;
|
||||
if (_fadeVolume < 0)
|
||||
_fadeVolume = 0;
|
||||
if (_fadeVolume > 1)
|
||||
_fadeVolume = 1;
|
||||
}
|
||||
|
||||
PcmAudio::~PcmAudio()
|
||||
{
|
||||
stop();
|
||||
if (_thread.joinable())
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
void PcmAudio::fadecpy(uint8_t *target, uint8_t *source, size_t len)
|
||||
{
|
||||
int16_t *src = reinterpret_cast<int16_t *>(source);
|
||||
int16_t *dst = reinterpret_cast<int16_t *>(target);
|
||||
_faded = true;
|
||||
for (size_t i = 0; i < len / 2; i++)
|
||||
{
|
||||
if (_fade)
|
||||
{
|
||||
if (_volume - FADE_OUT_SPEED >= _fadeVolume)
|
||||
_volume = _volume - FADE_OUT_SPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_volume + FADE_IN_SPEED <= 1)
|
||||
_volume = _volume + FADE_IN_SPEED;
|
||||
}
|
||||
dst[i] = src[i] * _volume;
|
||||
}
|
||||
_faded = _volume + FADE_IN_SPEED <= 1;
|
||||
}
|
||||
|
||||
void PcmAudio::callback(void *userdata, Uint8 *stream, int len)
|
||||
@@ -32,26 +73,31 @@ void PcmAudio::callback(void *userdata, Uint8 *stream, int len)
|
||||
if (segment == nullptr || self->_reconfig)
|
||||
{
|
||||
std::fill_n(stream, len, 0);
|
||||
if (self->_nodata++ > NO_DATA_FRAMES)
|
||||
{
|
||||
self->_reconfig = true;
|
||||
self->_cv.notify_one();
|
||||
}
|
||||
self->_faded = self->_fade;
|
||||
self->_volume = self->_faded ? Settings::audioFade : 1;
|
||||
self->_reconfig = true;
|
||||
self->_cv.notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
self->_nodata = 0;
|
||||
int remain = segment->length() - self->_offset;
|
||||
uint8_t *data = segment->data() + self->_offset;
|
||||
|
||||
if (remain > len)
|
||||
{
|
||||
std::memcpy(stream, data, len);
|
||||
if (self->_fade || self->_faded)
|
||||
self->fadecpy(stream, data, len);
|
||||
else
|
||||
std::memcpy(stream, data, len);
|
||||
self->_offset = self->_offset + len;
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(stream, data, remain);
|
||||
if (self->_fade || self->_faded)
|
||||
self->fadecpy(stream, data, remain);
|
||||
else
|
||||
std::memcpy(stream, data, remain);
|
||||
|
||||
len = len - remain;
|
||||
stream = stream + remain;
|
||||
self->_data->pop();
|
||||
@@ -72,25 +118,16 @@ ChannelConfig PcmAudio::getConfig(int type)
|
||||
return {44100, 2};
|
||||
}
|
||||
|
||||
void PcmAudio::setVolume(float vol)
|
||||
void PcmAudio::Fade(bool enable)
|
||||
{
|
||||
if (vol < 0)
|
||||
{
|
||||
_volume = 0;
|
||||
return;
|
||||
}
|
||||
if (vol > 1)
|
||||
{
|
||||
_volume = 1;
|
||||
return;
|
||||
}
|
||||
_volume = vol;
|
||||
_fade = enable;
|
||||
}
|
||||
|
||||
void PcmAudio::start(AtomicQueue<Message> *data)
|
||||
void PcmAudio::start(AtomicQueue<Message> *data, PcmAudio *fader)
|
||||
{
|
||||
if (_active)
|
||||
stop();
|
||||
_fader = fader;
|
||||
_data = data;
|
||||
_active = true;
|
||||
_thread = std::thread(&PcmAudio::runner, this);
|
||||
@@ -114,13 +151,11 @@ void PcmAudio::runner()
|
||||
|
||||
while (_active)
|
||||
{
|
||||
printf("AUDIO - WAIT BUFFER\n");
|
||||
_data->wait(_active, Settings::audioDelay);
|
||||
const Message *segment = _data->peek();
|
||||
if (!segment)
|
||||
continue;
|
||||
|
||||
printf("AUDIO - START\n");
|
||||
_config = getConfig(segment->getInt(OFFSET_AUDIO_FORMAT));
|
||||
if (device != 0)
|
||||
{
|
||||
@@ -140,21 +175,27 @@ void PcmAudio::runner()
|
||||
|
||||
_reconfig = false;
|
||||
_offset = 0;
|
||||
_nodata = 0;
|
||||
|
||||
device = SDL_OpenAudioDevice(nullptr, 0, &spec, nullptr, 0);
|
||||
if (device == 0)
|
||||
{
|
||||
std::cerr << "[Audio] Failed to open audio: " << SDL_GetError() << std::endl;
|
||||
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)
|
||||
_fader->Fade(true);
|
||||
|
||||
printf("AUDIO - SLEED %b\n", _reconfig.load() || !_active.load());
|
||||
std::unique_lock<std::mutex> lock(_mtx);
|
||||
_cv.wait(lock, [&]
|
||||
{ return _reconfig.load() || !_active.load(); });
|
||||
|
||||
SDL_PauseAudioDevice(device, 1);
|
||||
std::cout << _name << " Stop playing" << std::endl;
|
||||
if (_fader)
|
||||
_fader->Fade(false);
|
||||
}
|
||||
|
||||
if (device)
|
||||
|
||||
+12
-7
@@ -11,7 +11,8 @@
|
||||
#include "struct/message.h"
|
||||
#include "helper/error.h"
|
||||
|
||||
#define NO_DATA_FRAMES 20
|
||||
#define FADE_IN_SPEED 0.00001
|
||||
#define FADE_OUT_SPEED 0.0001
|
||||
|
||||
struct ChannelConfig
|
||||
{
|
||||
@@ -32,35 +33,39 @@ struct ChannelConfig
|
||||
class PcmAudio
|
||||
{
|
||||
public:
|
||||
PcmAudio();
|
||||
PcmAudio(const char *name = "");
|
||||
~PcmAudio();
|
||||
|
||||
// Start playing raw PCM data from queue
|
||||
void start(AtomicQueue<Message> *data);
|
||||
void start(AtomicQueue<Message> *data, PcmAudio *fader = nullptr);
|
||||
void stop();
|
||||
|
||||
void setVolume(float vol);
|
||||
void Fade(bool enble);
|
||||
|
||||
private:
|
||||
void runner();
|
||||
void loop(SDL_AudioDeviceID device);
|
||||
void fadecpy(uint8_t *target, uint8_t *source, size_t len);
|
||||
|
||||
static void callback(void *userdata, Uint8 *stream, int len);
|
||||
static ChannelConfig _configTable[];
|
||||
static ChannelConfig getConfig(int type);
|
||||
|
||||
float _volume = 1.0f;
|
||||
|
||||
AtomicQueue<Message> *_data;
|
||||
ChannelConfig _config;
|
||||
int _offset;
|
||||
int _nodata;
|
||||
PcmAudio *_fader;
|
||||
bool _fade;
|
||||
bool _faded;
|
||||
float _volume;
|
||||
float _fadeVolume;
|
||||
|
||||
std::thread _thread;
|
||||
std::mutex _mtx;
|
||||
std::condition_variable _cv;
|
||||
std::atomic<bool> _reconfig{false};
|
||||
std::atomic<bool> _active{false};
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
#endif /* SRC_PCM_AUDIO */
|
||||
|
||||
+5
-14
@@ -9,9 +9,8 @@
|
||||
Protocol::Protocol(uint16_t width, uint16_t height, uint16_t fps, uint16_t padding)
|
||||
: connector(padding),
|
||||
videoData(Settings::videoQueue),
|
||||
audioStream0(Settings::audioQueue),
|
||||
audioStream1(Settings::audioQueue),
|
||||
audioStream2(Settings::audioQueue),
|
||||
audioStreamMain(Settings::audioQueue),
|
||||
audioStreamAux(Settings::audioQueue),
|
||||
phoneConnected(false),
|
||||
_width(width),
|
||||
_height(height),
|
||||
@@ -51,8 +50,6 @@ void Protocol::sendInit(int width, int height, int fps)
|
||||
|
||||
void Protocol::sendKey(int key)
|
||||
{
|
||||
printf("Send key %d", key);
|
||||
|
||||
uint8_t buf[4];
|
||||
write_uint32_le(&buf[0], key);
|
||||
|
||||
@@ -211,27 +208,21 @@ void Protocol::onData(uint32_t cmd, uint32_t length, uint8_t *data)
|
||||
}
|
||||
case CMD_AUDIO_DATA:
|
||||
{
|
||||
if (length <= 13)
|
||||
if (length <= 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
int channel = 0;
|
||||
memcpy(&channel, data + 8, sizeof(int));
|
||||
if (channel == 0)
|
||||
{
|
||||
audioStream0.pushDiscard(std::make_unique<Message>(data, length, 12));
|
||||
dispose = false;
|
||||
break;
|
||||
}
|
||||
if (channel == 1)
|
||||
{
|
||||
audioStream1.pushDiscard(std::make_unique<Message>(data, length, 12));
|
||||
audioStreamMain.pushDiscard(std::make_unique<Message>(data, length, 12));
|
||||
dispose = false;
|
||||
break;
|
||||
}
|
||||
if (channel == 2)
|
||||
{
|
||||
audioStream2.pushDiscard(std::make_unique<Message>(data, length, 12));
|
||||
audioStreamAux.pushDiscard(std::make_unique<Message>(data, length, 12));
|
||||
dispose = false;
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-3
@@ -32,9 +32,8 @@ public:
|
||||
|
||||
Connector connector;
|
||||
AtomicQueue<Message> videoData;
|
||||
AtomicQueue<Message> audioStream0;
|
||||
AtomicQueue<Message> audioStream1;
|
||||
AtomicQueue<Message> audioStream2;
|
||||
AtomicQueue<Message> audioStreamMain;
|
||||
AtomicQueue<Message> audioStreamAux;
|
||||
bool phoneConnected;
|
||||
|
||||
private:
|
||||
|
||||
+8
-4
@@ -13,21 +13,25 @@ public:
|
||||
static inline Setting<int> dpi{"dpi", 0};
|
||||
static inline Setting<int> width{"width", 720};
|
||||
static inline Setting<int> height{"height", 576};
|
||||
static inline Setting<int> fps{"fps", 60};
|
||||
static inline Setting<int> fps{"fps", 50};
|
||||
static inline Setting<bool> vsync{"vsync", false};
|
||||
static inline Setting<int> sourceWidth{"source-width", 720};
|
||||
static inline Setting<int> sourceHeight{"source-height", 576};
|
||||
static inline Setting<int> sourceFps{"source-fps", 30};
|
||||
static inline Setting<int> sourceFps{"source-fps", 50};
|
||||
static inline Setting<bool> logging{"logging", false};
|
||||
static inline Setting<int> scaler{"scaler", 2};
|
||||
static inline Setting<bool> fastScale{"fast-render-scale", false};
|
||||
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> audioDelay{"audio-buffer-wait", 2};
|
||||
static inline Setting<float> audioFade{"audio-fade", 0.3};
|
||||
static inline Setting<int> fontSize{"font-size", 30};
|
||||
static inline Setting<bool> encryption{"encryption", false};
|
||||
static inline Setting<bool> autoconnect{"autoconnect", true};
|
||||
static inline Setting<std::string> onConnect{"on-connect-script", ""};
|
||||
static inline Setting<std::string> onDisconnect{"on-disconnect-script", ""};
|
||||
static inline Setting<int> protocolDebug{"protocol-debug", 0};
|
||||
static inline Setting<int> protocolDebug{"protocol-debug", 0};
|
||||
|
||||
|
||||
static void load(const std::string &filename);
|
||||
static void print();
|
||||
|
||||
Reference in New Issue
Block a user