diff --git a/settings.txt b/settings.txt index 408fec0..c6117ef 100644 --- a/settings.txt +++ b/settings.txt @@ -122,6 +122,12 @@ # Reduction level from 1 (no reduction) to 0 (fully silenced) #audio-fade = 0.3 +# Basic number of audio sample frames in the output buffer that is scaled by sample rate. +# This controls the size of the audio buffer used by the audio device. +# The buffer time is ~ 1/10 buffer size in ms, depending on sample rate e.g. 2048 = ~200ms +# Preferably use power of 2 for the values or check your audio driver documentation +#audio-buffer-samples = 2048 + # Force application to use following audio driver as audio output, if empty use default driver # See SDL documentation for options. Some of them are # alsa - Not supporting multiple channels, navigation over music will not work diff --git a/src/connector.cpp b/src/connector.cpp index 222b68c..833ad15 100644 --- a/src/connector.cpp +++ b/src/connector.cpp @@ -32,7 +32,7 @@ Connector::~Connector() _active = false; if (_write_thread.joinable()) - _write_thread.join(); + _write_thread.join(); if (_cipher) { @@ -154,7 +154,7 @@ bool Connector::nextState(u_int8_t state) _state = state; return true; } - + if (state == PROTOCOL_STATUS_NO_DEVICE && (_nodeviceCount++ > 10 || _state >= PROTOCOL_STATUS_ONLINE)) { _failCount = 0; @@ -336,7 +336,7 @@ void Connector::readLoop() if (result != LIBUSB_SUCCESS || transferred != sizeof(Header)) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } @@ -357,11 +357,15 @@ void Connector::readLoop() if (!_cipher) { std::cout << "[Connection] Received encrypted command " << header.type << " but cipher is not initialised" << std::endl; + if (data) + free(data); continue; } if (!_cipher->Decrypt(data, header.length)) { std::cout << "[Connection] Can't decrypt command " << header.type << std::endl; + if (data) + free(data); continue; } } @@ -383,7 +387,7 @@ void Connector::writeLoop() // Set thread name setThreadName("protocol-writer"); - state(PROTOCOL_STATUS_LINKING); + state(PROTOCOL_STATUS_LINKING); while (_active) { diff --git a/src/main.cpp b/src/main.cpp index fb236e5..cd78209 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ extern "C" #include "pipe_listener.h" #define FRAME_DELAY_INACTIVE 200 +#define MAX_EVENTS_PER_FRAME 5 static const char *title = "Fast Car Play v0.6"; static SDL_Window *window = nullptr; @@ -153,8 +154,9 @@ bool processEvents(Protocol &protocol, RunParams ¶ms, Renderer &renderer) int downY = -1; int upX = -1; int upY = -1; + int processed = 0; - while (SDL_PollEvent(&e)) + while (SDL_PollEvent(&e) && processed++ < MAX_EVENTS_PER_FRAME) { switch (e.type) { @@ -268,6 +270,7 @@ void application() std::cout << "[Main] Loop" << std::endl; uint32_t latestid = 0; Uint32 frameStart = SDL_GetTicks(); + uint32_t FrameRequest = 0; while (active) { if (processEvents(protocol, p, interface)) @@ -294,6 +297,17 @@ void application() p.dirty = false; } videoBuffer.consume(); + FrameRequest = 0; + } + else + { + if (Settings::forceRedraw) + { + if (protocol.checkKey()) + FrameRequest = 3; + else if (FrameRequest-- > 0) + protocol.requestKeyframe(); + } } } @@ -303,16 +317,23 @@ void application() p.dirty = false; } - Uint32 frameEnd = SDL_GetTicks(); - Uint32 frameTime = frameEnd - frameStart; - if (active && frameTime < p.frameDelay) + if (active) { - SDL_Delay(p.frameDelay - frameTime); // Sleep only the remaining time - frameStart = frameStart + p.frameDelay; + Uint32 frameEnd = SDL_GetTicks(); + Uint32 frameTime = frameEnd - frameStart; + if (frameTime < p.frameDelay) + { + SDL_Delay(p.frameDelay - frameTime); + frameStart += p.frameDelay; + } + else + { + SDL_Delay(1); + frameStart += 1; + } } - else - frameStart = frameEnd; } + std::cout << "[Main] Stopping" << std::endl; SDL_HideWindow(window); } @@ -388,7 +409,7 @@ int start() return 1; } - if(!Settings::cursor) + if (!Settings::cursor) SDL_ShowCursor(SDL_DISABLE); // Create accelerated renderer for the window diff --git a/src/pcm_audio.cpp b/src/pcm_audio.cpp index 5fdbeb7..799812c 100644 --- a/src/pcm_audio.cpp +++ b/src/pcm_audio.cpp @@ -2,12 +2,13 @@ #include "helper/functions.h" #include "settings.h" +// Add sample size (buffer size in samples) to ChannelConfig ChannelConfig PcmAudio::_configTable[] = { - {8000, 1}, // type = 3 - {48000, 2}, // type = 4 - {16000, 1}, // type = 5 - {24000, 1}, // type = 6 - {16000, 2}, // type = 7 + {8000, 1, 1}, // type = 3, ~256ms + {48000, 2, 4}, // type = 4, ~170ms + {16000, 1, 2}, // type = 5, ~256ms + {24000, 1, 2}, // type = 6, ~170ms + {16000, 2, 2}, // type = 7, ~256ms }; // Implementation @@ -139,7 +140,8 @@ ChannelConfig PcmAudio::getConfig(int type) { if (type >= 3 && type <= 7) return _configTable[type - 3]; - return {44100, 2}; + // Default: 44100Hz, stereo, 4096 samples + return {44100, 2, 4}; } void PcmAudio::Fade(bool enable) @@ -194,7 +196,7 @@ void PcmAudio::runner() spec.freq = config.rate; spec.format = AUDIO_S16SYS; spec.channels = config.channels; - spec.samples = 4096; + spec.samples = Settings::audioBuffer*config.scale; spec.callback = callback; spec.userdata = this; @@ -202,7 +204,7 @@ void PcmAudio::runner() if (device == 0) { std::cerr << _name << " Failed to open audio: " << SDL_GetError() << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + SDL_Delay(100); continue; } _config = config; diff --git a/src/pcm_audio.h b/src/pcm_audio.h index 0f9c1d1..8795d71 100644 --- a/src/pcm_audio.h +++ b/src/pcm_audio.h @@ -18,6 +18,7 @@ struct ChannelConfig { int rate; uint8_t channels; + uint8_t scale; bool operator==(ChannelConfig const &other) const { diff --git a/src/protocol.cpp b/src/protocol.cpp index 83bca8f..015639b 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -15,6 +15,7 @@ Protocol::Protocol(uint16_t width, uint16_t height, uint16_t fps, uint16_t paddi _width(width), _height(height), _fps(fps), + _keySent(false), _phoneConnected(false) { } @@ -113,18 +114,22 @@ void Protocol::sendConfig() sendInt(CMD_CONTROL, 1002); } +bool Protocol::checkKey() +{ + bool result = _keySent; + _keySent = false; + return result; +} + void Protocol::sendKey(int key) { - uint8_t buf[4]; - write_uint32_le(&buf[0], key); + sendInt(CMD_CONTROL, key, false); + _keySent = true; +} - send(CMD_CONTROL, false, buf, 4); - - if(Settings::forceRedraw) - { - write_uint32_le(&buf[0], BTN_SCREEN_REFRESH); - send(CMD_CONTROL, false, buf, 4); - } +void Protocol::requestKeyframe() +{ + sendInt(CMD_CONTROL, BTN_SCREEN_REFRESH, false); } void Protocol::sendFile(const char *filename, const char *value) @@ -323,7 +328,6 @@ void Protocol::onData(uint32_t cmd, uint32_t length, uint8_t *data) memcpy(&cmd, data, sizeof(int)); onControl(cmd); } - break; case CMD_PLUGGED: diff --git a/src/protocol.h b/src/protocol.h index 65c7a39..a8d488c 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -22,7 +22,10 @@ public: void start(uint32_t evtStatus, uint32_t evtPhone); void stop(); + + bool checkKey(); void sendKey(int key); + void requestKeyframe(); void sendFile(const char *filename, const uint8_t *data, uint32_t length); void sendFile(const char *filename, const char *value); void sendFile(const char *filename, int value); @@ -54,6 +57,7 @@ private: uint16_t _width; uint16_t _height; uint16_t _fps; + bool _keySent; bool _phoneConnected; uint32_t _evtStatusId = (uint32_t)-1; diff --git a/src/renderer.cpp b/src/renderer.cpp index 7d647b2..5444a05 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -174,7 +174,6 @@ bool Renderer::render(AVFrame *frame) return false; } (this->*_render)(frame); - SDL_RenderClear(_renderer); SDL_RenderCopy(_renderer, _texture, &_sourceRect, nullptr); SDL_RenderPresent(_renderer); return true; @@ -250,9 +249,10 @@ bool Renderer::prepare(AVFrame *frame, int targetWidth, int targetHeight) if (!prepareTexture(SDL_PIXELFORMAT_IYUV, frame->width, frame->height)) return false; + int swsFlags = Settings::fastScale ? SWS_FAST_BILINEAR : SWS_BILINEAR; _sws = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format, frame->width, frame->height, AV_PIX_FMT_YUV420P, - SWS_BILINEAR, nullptr, nullptr, nullptr); + swsFlags, nullptr, nullptr, nullptr); if (!_sws) { std::cerr << "[UX] Can't create sws context" << std::endl; diff --git a/src/settings.h b/src/settings.h index a94e1ed..cc27e05 100644 --- a/src/settings.h +++ b/src/settings.h @@ -43,6 +43,7 @@ public: static inline Setting audioDelay{"audio-buffer-wait", 2}; static inline Setting audioDelayCall{"audio-buffer-wait-call", 8}; static inline Setting audioFade{"audio-fade", 0.3}; + static inline Setting audioBuffer{"audio-buffer-samples", 2048}; static inline Setting audioDriver{"audio-driver", ""}; static inline Setting onConnect{"on-connect-script", ""}; static inline Setting onDisconnect{"on-disconnect-script", ""};