diff --git a/settings.txt b/settings.txt index 0f45f10..1ae37d3 100644 --- a/settings.txt +++ b/settings.txt @@ -8,7 +8,7 @@ #product-id = 5408 # 0x1520 # Requested image resolution -#width = 720 +#width = 1024 #height = 576 # Requested image refresh rate @@ -98,7 +98,7 @@ ############################################################################## # Font size for messgaes on screen. Set to 0 is you do not want any -#font-size = 30 +#font-size = 40 # Enable vsync. This reduce tearing but can dramatically affect performance on low end systems #vsync = false diff --git a/src/application.cpp b/src/application.cpp index decb125..d95efdf 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -288,7 +288,7 @@ void Application::loop() { // Prepare home screen Interface interface(_renderer); - interface.drawHome(true, PROTOCOL_STATUS_UNKNOWN); + interface.drawHome(true, PROTOCOL_STATUS_UNKNOWN, ""); // Process full screen, do not do this in headless to avoid blinking if (Settings::isFullscreen()) @@ -301,7 +301,7 @@ void Application::loop() // Show window, do not do this in headless to avoid blinking if (!Settings::isHeadless()) SDL_ShowWindow(_window); - interface.drawHome(true, PROTOCOL_STATUS_UNKNOWN); + interface.drawHome(true, PROTOCOL_STATUS_UNKNOWN, ""); Connection protocol; Decoder decoder; @@ -310,7 +310,7 @@ void Application::loop() decoder.start(&protocol.videoStream, AV_CODEC_ID_H264); audioMain.start(&protocol.audioStreamMain); audioAux.start(&protocol.audioStreamAux, &audioMain); - protocol.start(&_state.deviceStatus); + protocol.start(); log_v("Loop"); Uint32 frameStart = SDL_GetTicks(); @@ -322,29 +322,32 @@ void Application::loop() uint32_t dropframes = 0; int skipEvents = 0; int frameTime = 0; + Uint32 debugLast = SDL_GetTicks(); + int debugSpeed = 0; + int debugLastCount = 0; while (_active) { bool late = false; - if (_state.deviceStatus != _state.previousdeviceStatus) + if (protocol.state() != _state.latestState) { // On connect/disconnect - if (_state.previousdeviceStatus == PROTOCOL_STATUS_CONNECTED || _state.deviceStatus == PROTOCOL_STATUS_CONNECTED) + if (protocol.state() == PROTOCOL_STATUS_CONNECTED || _state.latestState == PROTOCOL_STATUS_CONNECTED) { _state.frameRendered = false; _state.dirty = true; _state.requestFrame = 0; } // On connect - if (_state.deviceStatus == PROTOCOL_STATUS_CONNECTED) + if (protocol.state() == PROTOCOL_STATUS_CONNECTED) { decoder.flush(); decoder.buffer.reset(); } - _state.previousdeviceStatus = _state.deviceStatus; + _state.latestState = protocol.state(); } - if (_state.deviceStatus == PROTOCOL_STATUS_CONNECTED && _state.showVideo) + if (_state.latestState == PROTOCOL_STATUS_CONNECTED && _state.showVideo) { delay = 0; while (!_state.dirty && decoder.buffer.latestId() == latestFrameid && ++delay < frameTargetTime) @@ -382,7 +385,7 @@ void Application::loop() if (!_state.frameRendered || !_state.showVideo) { - interface.drawHome(_state.dirty, _state.deviceStatus); + interface.drawHome(_state.dirty, _state.latestState, protocol.phoneName()); _state.dirty = false; SDL_Event e; while (SDL_PollEvent(&e)) @@ -403,14 +406,18 @@ void Application::loop() if (_debug) { - char debugBuffer[512]; + if (SDL_GetTicks() - debugLast >= 1000) + { + debugSpeed = (protocol.transfered() - debugLastCount) / (SDL_GetTicks() - debugLast); + debugLastCount = protocol.transfered(); + debugLast = SDL_GetTicks(); + } + char debugBuffer[2048]; std::snprintf(debugBuffer, sizeof(debugBuffer), "%s\n" "FRAME: %u / %u [%d] dropped: %d render: %dms / %dms\n" - "VIDEO: %u\n" - "AUDIO-MAIN: %u\n" - "AUDIO-AUX: %u\n" - "OUT: %u", + "USB: %s ~%dKB/s\n" + "BUFF: video [%u] audio[main %u aux %u] out [%u]", status().c_str(), latestFrameid, decoder.buffer.latestId(), @@ -418,6 +425,8 @@ void Application::loop() dropframes, frameTime, delay, + protocol.status().c_str(), + debugSpeed, protocol.videoStream.count(), protocol.audioStreamMain.count(), protocol.audioStreamAux.count(), diff --git a/src/application.h b/src/application.h index 2b82a72..64571f0 100644 --- a/src/application.h +++ b/src/application.h @@ -27,8 +27,7 @@ private: bool showVideo = true; bool fullscreen = false; bool mouseDown = false; - int8_t previousdeviceStatus = PROTOCOL_STATUS_INITIALISING; - atomic deviceStatus = PROTOCOL_STATUS_INITIALISING; + int8_t latestState = PROTOCOL_STATUS_UNKNOWN; }; bool setAudioDriver(); diff --git a/src/common/functions.h b/src/common/functions.h index 5a25dcb..cbdc0b7 100644 --- a/src/common/functions.h +++ b/src/common/functions.h @@ -51,17 +51,87 @@ inline void pushEvent(Uint32 evt, int code) inline std::string bytes(uint8_t *data, uint32_t length, uint16_t max) { - std::ostringstream out; + std::ostringstream oss; - if (data && length >= 4) + if (data && length > 0) { - for (size_t i = 0; (i < length) && (i < max); ++i) + for (uint32_t i = 0; (i < length) && (i < max); ++i) { - out << std::setw(4) << static_cast(data[i]); + oss << std::setw(4) << static_cast(data[i]); } } - return out.str(); + return oss.str(); +} + +inline std::string ascii(uint8_t *data, uint32_t length) +{ + std::ostringstream oss; + + if (data && length > 0) + { + for (uint32_t i = 0; i < length; ++i) + { + char ch = static_cast(data[i]); + if (ch == '\n' || ch == '\r') + oss << '.'; + else + oss << (std::isprint(static_cast(ch)) ? ch : '.'); + } + } + + return oss.str(); +} + +inline bool jsonFindString(const uint8_t *data, int size, const char *key, char *result, int len) +{ + const char *p = reinterpret_cast(data); + const char *end = p + size; + + int keyLen = strlen(key); + + while (p < end) + { + while (p < end && *p != '"') + ++p; + if (p >= end) + break; + ++p; + + if ((end - p) > keyLen && + strncmp(p, key, keyLen) == 0 && + p[keyLen] == '"') + { + p += keyLen + 1; + while (p < end && isspace((unsigned char)*p)) + ++p; + if (p >= end || *p != ':') + continue; + ++p; + while (p < end && isspace((unsigned char)*p)) + ++p; + if (p >= end || *p != '"') + continue; + ++p; + + int i = 0; + while (p < end && *p != '"' && i + 1 < len) + result[i++] = *p++; + result[i] = '\0'; + return p < end && *p == '"'; + } + + while (p < end && *p != '"') + { + if (*p == '\\') + ++p; + ++p; + } + if (p < end) + ++p; + } + + return false; } #endif /* SRC_COMMON_FUNCTIONS */ diff --git a/src/common/logger.cpp b/src/common/logger.cpp index 67a2177..4b963b4 100644 --- a/src/common/logger.cpp +++ b/src/common/logger.cpp @@ -57,8 +57,10 @@ void Logger::vlog(Level level, const char *context, const char *fmt, std::va_lis char message[LOGGER_MESSAGE_SIZE]; std::vsnprintf(message, LOGGER_MESSAGE_SIZE, fmt, args); + FILE *stream = (level <= Level::Error) ? stderr : stdout; + std::fprintf( - (level <= Level::Warning) ? stderr : stdout, + stream, "%s%s %s[%s] %s%s\n", LOGGER_COLOR_GRAY, timebuf, @@ -66,6 +68,8 @@ void Logger::vlog(Level level, const char *context, const char *fmt, std::va_lis className(context).c_str(), message, LOGGER_COLOR_RESET); + + std::fflush(stream); } const char *Logger::levelColor(Level level) @@ -95,7 +99,8 @@ std::string Logger::className(const char *context) return "Global"; std::string signature(context); - const std::size_t scopePos = signature.rfind("::"); + const std::size_t argsPos = signature.find('('); + const std::size_t scopePos = signature.rfind("::", argsPos); if (scopePos == std::string::npos) return "Global"; diff --git a/src/interface.cpp b/src/interface.cpp index 67b2f1d..3315eda 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -9,10 +9,7 @@ Interface::Interface(SDL_Renderer *renderer) : Renderer(renderer), _state(0), _debug(false), - _textDongle(font, font_len, Settings::fontSize), - _textInit(font, font_len, Settings::fontSize), - _textConnect(font, font_len, Settings::fontSize), - _textLaunch(font, font_len, Settings::fontSize), + _textStatus(font, font_len, Settings::fontSize), _textDebug(font, font_len, 15), _mainImage(background, background_len) { @@ -47,7 +44,7 @@ bool Interface::render(AVFrame *frame) return true; } -bool Interface::drawHome(bool force, int state) +bool Interface::drawHome(bool force, int state, std::string name) { if (state == _state && !force) return false; @@ -57,22 +54,34 @@ bool Interface::drawHome(bool force, int state) SDL_GetRendererOutputSize(_renderer, &width, &height); _mainImage.draw(_renderer, width, height); + bool drawText = false; + if (state == PROTOCOL_STATUS_ERROR) - { - if (_textDongle.prepare(_renderer, "Connection error", colorError)) - _textDongle.draw(_renderer, 0.05 * width, 0.2 * height - _textDongle.height / 2); - } - else - { - if (_textDongle.prepare(_renderer, "Insert dongle", state == PROTOCOL_STATUS_NO_DEVICE ? color1 : color1_inactive)) - _textDongle.draw(_renderer, 0.05 * width, 0.2 * height - _textDongle.height / 2); - } - if (_textInit.prepare(_renderer, "Initialising", state == PROTOCOL_STATUS_LINKING ? color2 : color2_inactive)) - _textInit.draw(_renderer, 0.05 * width, 0.4 * height - _textInit.height / 2); - if (_textConnect.prepare(_renderer, "Connect phone", state == PROTOCOL_STATUS_ONLINE ? color3 : color3_inactive)) - _textConnect.draw(_renderer, 0.05 * width, 0.6 * height - _textConnect.height / 2); - if (_textLaunch.prepare(_renderer, "Launching", state == PROTOCOL_STATUS_CONNECTED ? color4 : color4_inactive)) - _textLaunch.draw(_renderer, 0.05 * width, 0.8 * height - _textLaunch.height / 2); + if (_textStatus.prepare(_renderer, "Dongle error", colorError)) + drawText = true; + + if (state == PROTOCOL_STATUS_NO_DEVICE) + if (_textStatus.prepare(_renderer, "Insert dongle", colorError)) + drawText = true; + + if (state == PROTOCOL_STATUS_INITIALISING) + if (_textStatus.prepare(_renderer, "Initialising", color2)) + drawText = true; + + if (state == PROTOCOL_STATUS_LINKING) + if (_textStatus.prepare(_renderer, "Initialising", color2)) + drawText = true; + + if (state == PROTOCOL_STATUS_ONLINE) + if (_textStatus.prepare(_renderer, "Connect phone", color4)) + drawText = true; + + if (state == PROTOCOL_STATUS_CONNECTED) + if (_textStatus.prepare(_renderer, "Connecting to "+name, color3)) + drawText = true; + + if (drawText) + _textStatus.draw(_renderer, (width - _textStatus.width) / 2, height * 0.85 - _textStatus.height); SDL_RenderPresent(_renderer); return true; diff --git a/src/interface.h b/src/interface.h index 1e44ee2..5b2acd1 100644 --- a/src/interface.h +++ b/src/interface.h @@ -10,7 +10,7 @@ public: Interface(SDL_Renderer *renderer); ~Interface(); bool render(AVFrame *frame); - bool drawHome(bool force, int state); + bool drawHome(bool force, int state, std::string name); void debug(const char *text); private: @@ -18,10 +18,7 @@ private: int _state; bool _debug; - RendererText _textDongle; - RendererText _textInit; - RendererText _textConnect; - RendererText _textLaunch; + RendererText _textStatus; RendererText _textDebug; RendererImage _mainImage; std::string _debugText; diff --git a/src/main.cpp b/src/main.cpp index 8cc2124..50662cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,7 @@ #include "pipe_listener.h" #include "settings.h" -static const char *title = "Fast Car Play v0.8"; +static const char *title = "Fast Car Play v0.9"; void start() { diff --git a/src/pcm_audio.cpp b/src/pcm_audio.cpp index 2d65cec..85e9260 100644 --- a/src/pcm_audio.cpp +++ b/src/pcm_audio.cpp @@ -263,7 +263,6 @@ void PcmAudio::loop() if (device != 0) { - SDL_PauseAudioDevice(device, 1); SDL_ClearQueuedAudio(device); SDL_CloseAudioDevice(device); } diff --git a/src/pcm_audio.h b/src/pcm_audio.h index 1518a24..d11c94a 100644 --- a/src/pcm_audio.h +++ b/src/pcm_audio.h @@ -1,9 +1,9 @@ #ifndef SRC_PCM_AUDIO #define SRC_PCM_AUDIO -#include -#include #include +#include +#include #include diff --git a/src/protocol/aes_cipher.cpp b/src/protocol/aes_cipher.cpp index 50cfb92..08b7905 100644 --- a/src/protocol/aes_cipher.cpp +++ b/src/protocol/aes_cipher.cpp @@ -31,52 +31,52 @@ AESCipher::AESCipher(const std::string &baseKey) _initVec[12] = static_cast(_seed >> 24); } -Status AESCipher::Encrypt(uint8_t *data, uint32_t length) const +bool AESCipher::encrypt(uint8_t *data, uint32_t length, char *err) const { if (!data || length == 0) - return Status::Error("Empty data"); + return error(err, "Empty data"); auto ctx = std::unique_ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); if (!ctx) - return Status::Error("Failed to create cipher context"); + return error(err, "Failed to create cipher context"); if (EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_cfb(), nullptr, _encKey.data(), _initVec.data()) != 1) - return Status::Error("Encryption initialization failed"); + return error(err, "Encryption initialization failed"); std::unique_ptr temp(new uint8_t[length + AES_BLOCK_SIZE]); int out_len = 0; if (EVP_EncryptUpdate(ctx.get(), temp.get(), &out_len, data, length) != 1) - return Status::Error("Encryption failed during update"); + return error(err, "Encryption failed during update"); int final_len = 0; if (EVP_EncryptFinal_ex(ctx.get(), temp.get() + out_len, &final_len) != 1) - return Status::Error("Encryption failed during final"); + return error(err, "Encryption failed during final"); std::copy_n(temp.get(), length, data); - return Status::Success(); + return true; } -Status AESCipher::Decrypt(uint8_t *data, uint32_t length) const +bool AESCipher::decrypt(uint8_t *data, uint32_t length, char *err) const { if (!data || length == 0) - return Status::Error("Empty data"); + return error(err, "Empty data"); auto ctx = std::unique_ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); if (!ctx) - return Status::Error("Failed to create cipher context"); + return error(err, "Failed to create cipher context"); if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cfb(), nullptr, _encKey.data(), _initVec.data()) != 1) - return Status::Error(" Decryption initialization failed"); + return error(err, "Decryption initialization failed"); std::unique_ptr temp(new uint8_t[length + AES_BLOCK_SIZE]); int out_len = 0; if (EVP_DecryptUpdate(ctx.get(), temp.get(), &out_len, data, length) != 1) - return Status::Error("Decryption failed during update"); + return error(err, "Decryption failed during update"); int final_len = 0; if (EVP_DecryptFinal_ex(ctx.get(), temp.get() + out_len, &final_len) != 1) - return Status::Error("Decryption failed during final"); + return error(err, "Decryption failed during final"); std::copy_n(temp.get(), length, data); - return Status::Success(); + return true; } diff --git a/src/protocol/aes_cipher.h b/src/protocol/aes_cipher.h index 9bc6218..846dc34 100644 --- a/src/protocol/aes_cipher.h +++ b/src/protocol/aes_cipher.h @@ -4,10 +4,9 @@ #include #include #include +#include #include -#include "common/status.h" - class AESCipher { public: @@ -16,11 +15,18 @@ public: AESCipher(const std::string &base_key); ~AESCipher() = default; - Status Encrypt(uint8_t *data, uint32_t length) const; - Status Decrypt(uint8_t *data, uint32_t length) const; + bool encrypt(uint8_t *data, uint32_t length, char *err) const; + bool decrypt(uint8_t *data, uint32_t length, char *err) const; - uint32_t Seed() const { return _seed; } - const std::string& Key() const { return _baseKey; } + uint32_t seed() const { return _seed; } + const std::string &key() const { return _baseKey; } + + static bool error(char *error, const char *message) + { + if (error) + strcpy(error, message); + return false; + } private: std::string _baseKey; diff --git a/src/protocol/connection.cpp b/src/protocol/connection.cpp index 3e06fc4..d51785d 100644 --- a/src/protocol/connection.cpp +++ b/src/protocol/connection.cpp @@ -1,8 +1,11 @@ #include "connection.h" +#include +#include +#include #include -#include -#include + +#include "libavcodec/defs.h" #include "protocol/message.h" #include "common/logger.h" @@ -12,19 +15,22 @@ Connection::Connection() : writeQueue(WRITE_QUEUE_SIZE), - videoStream(Settings::videoQueue), - audioStreamMain(Settings::audioQueue), - audioStreamAux(Settings::audioQueue), - _recorder(Settings::audioQueue), + videoStream(VIDEO_QUEUE_SIZE), + audioStreamMain(AUDIO_QUEUE_SIZE), + audioStreamAux(AUDIO_QUEUE_SIZE), + _processQueue(Settings::usbBuffer, Settings::usbTransferSize), + _transfers(Settings::usbQueue), + _statusHandler(nullptr), _cipher(nullptr), _context(nullptr), _active(false), _connected(false), + _phoneConnected(false), _ecnrypt(false), _state(PROTOCOL_STATUS_INITIALISING), - _failCount(0), - _nodeviceCount(0), - _statusHandler(nullptr) + _method("unknown"), + _phoneName("phone"), + _transfered(0) { int result = libusb_init(&_context); if (result < 0) @@ -44,6 +50,14 @@ Connection::Connection() _cipher = nullptr; log_w("Can't initialise cypher for encryption > Unknown error"); } + + for (Context &context : _transfers) + { + context.owner = this; + context.transfer = nullptr; + context.slot = nullptr; + } + log_v("Created"); } @@ -58,6 +72,15 @@ Connection::~Connection() _cipher = nullptr; } + for (Context &context : _transfers) + { + if (context.transfer) + { + libusb_free_transfer(context.transfer); + context.transfer = nullptr; + } + } + if (_context) { libusb_exit(_context); @@ -66,17 +89,31 @@ Connection::~Connection() log_v("Destroyed"); } -void Connection::start(atomic *statusHandler) +void Connection::start() { - _statusHandler = statusHandler; - if (_active) return; + _state = PROTOCOL_STATUS_INITIALISING; + log_v("Starting"); + // Prepare usb transfers + for (Context &context : _transfers) + { + if (!context.transfer) + { + context.transfer = libusb_alloc_transfer(0); + if (context.transfer == nullptr) + { + log_e("Can't allocate usb transfer"); + return; + } + } + } + _active = true; - _thread = std::thread(&Connection::mainLoop, this); + _writeThread = std::thread(&Connection::mainLoop, this); } void Connection::stop() @@ -87,72 +124,285 @@ void Connection::stop() log_v("Stopping"); _active = false; + _connected = false; + _state = PROTOCOL_STATUS_UNKNOWN; + + _processQueue.notify(); writeQueue.notify(); - state(PROTOCOL_STATUS_INITIALISING); - if (_thread.joinable()) - _thread.join(); + if (_writeThread.joinable()) + _writeThread.join(); + log_v("Stopped"); _statusHandler = nullptr; } +void Connection::onTransfer(libusb_transfer *transfer) +{ + if (!transfer || !transfer->user_data) + return; + + Context *c = static_cast(transfer->user_data); + if (!c->owner->_connected) + return; + + c->owner->_transfered.fetch_add(transfer->actual_length, std::memory_order_relaxed); + log_p("Transfer %d [%d] > %s", transfer->actual_length, transfer->status, bytes(transfer->buffer, transfer->actual_length, 40).c_str()); + + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) + return; + + if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) + { + c->owner->_connected = false; + return; + } + + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + c->slot->commit(transfer->actual_length); + c->slot = c->owner->_processQueue.get(); + if (!c->slot) + { + log_e("Can't allocate data slot for next usb transfer, increase usb buffer slots"); + c->owner->_connected = false; + return; + } + c->transfer->buffer = c->slot->data; + } + int status = libusb_submit_transfer(c->transfer); + if (status != LIBUSB_SUCCESS) + { + log_w("USB transfer re-submit failed with status %d", status); + c->owner->_connected = false; + } +} + void Connection::mainLoop() { // Set thread name setThreadName("usb-write"); - state(PROTOCOL_STATUS_LINKING); log_d("USB writing thread started"); + int connectCount = 0; + while (_active) { + int linkCount = 0; libusb_device_handle *handler = libusb_open_device_with_vid_pid(_context, Settings::vendorid, Settings::productid); if (handler) { - uint8_t epIn = 0; - uint8_t epOut = 0; - int retry = 0; + if (_state != PROTOCOL_STATUS_LINKING && _state != PROTOCOL_STATUS_ERROR) + connectCount = 0; + _state = PROTOCOL_STATUS_LINKING; + linkCount = 1; + uint8_t endpointIn = 0; + uint8_t endpointOut = 0; libusb_device *device = nullptr; _ecnrypt = false; writeQueue.clear(); - while (!device && retry++ < LINK_RETRY) + while (!device && linkCount++ < LINK_RETRY) { - device = link(handler, &epIn, &epOut); + device = link(handler, &endpointIn, &endpointOut); writeQueue.waitFor(_active, LINK_RETRY_TIMEOUT); } if (device) { - _connected = true; - state(PROTOCOL_STATUS_ONLINE); - log_i("Device connected %d:%d speed: %d", libusb_get_bus_number(device), libusb_get_device_address(device), libusb_get_device_speed(device)); - _reader.start(_context, handler, epIn, this); - onDeviceConnect(); - - writeLoop(handler, epOut); - - _connected = false; + _state = PROTOCOL_STATUS_ONLINE; + onDeviceConnect(handler, device, endpointIn); + writeLoop(handler, endpointOut); + _state = PROTOCOL_STATUS_LINKING; onDeviceDisconnect(); - _reader.stop(); } libusb_release_interface(handler, 0); libusb_close(handler); } - state(PROTOCOL_STATUS_NO_DEVICE); + if (linkCount == 0) + { + if (_state != PROTOCOL_STATUS_NO_DEVICE && connectCount++ > CONNECT_RETRY) + _state = PROTOCOL_STATUS_NO_DEVICE; + } + else + { + if (_state != PROTOCOL_STATUS_ERROR && connectCount++ > CONNECT_RETRY) + _state = PROTOCOL_STATUS_ERROR; + } writeQueue.waitFor(_active, RECONNECT_TIMEOUT); } + + log_v("USB writing thread stopped"); +} + +void Connection::onDeviceConnect(libusb_device_handle *handler, libusb_device *device, uint8_t endpointIn) +{ + _connected = true; + _phoneConnected = false; + log_i("Device connected %d:%d speed: %d", libusb_get_bus_number(device), libusb_get_device_address(device), libusb_get_device_speed(device)); + writeQueue.clear(); + videoStream.clear(); + audioStreamMain.clear(); + audioStreamAux.clear(); + _processQueue.reset(); + + _processThread = std::thread(&Connection::processLoop, this); + _readThread = std::thread(&Connection::readLoop, this); + + for (Context &context : _transfers) + { + context.owner = this; + context.slot = _processQueue.get(); + if (context.slot == nullptr) + { + log_e("Can't allocate data slot for usb transfer, increase usb buffer slots"); + _connected = false; + return; + } + libusb_fill_bulk_transfer(context.transfer, handler, endpointIn, context.slot->data, context.slot->size, Connection::onTransfer, &context, 0); + int status = libusb_submit_transfer(context.transfer); + if (status != LIBUSB_SUCCESS) + { + log_w("USB transfer submit failed with code %d", status); + _connected = false; + return; + } + } + + sendInit(); +} + +void Connection::onDeviceDisconnect() +{ + onPhoneDisconnect(); + + log_i("Device disconnected"); + _connected = false; + _state = PROTOCOL_STATUS_ERROR; + _processQueue.notify(); + + if (_readThread.joinable()) + _readThread.join(); + + if (_processThread.joinable()) + _processThread.join(); +} + +void Connection::onPhoneConnect() +{ + if (_phoneConnected) + return; + _state = PROTOCOL_STATUS_CONNECTED; + log_i("Phone connected"); + _phoneConnected = true; + + if (Settings::onConnect.value.length() > 1) + execute(Settings::onConnect.value.c_str()); +} + +void Connection::onPhoneDisconnect() +{ + if (!_phoneConnected) + return; + _state = PROTOCOL_STATUS_ONLINE; + log_i("Phone disconnected"); + _phoneConnected = false; + + _recorder.stop(); + if (Settings::onDisconnect.value.length() > 1) + execute(Settings::onDisconnect.value.c_str()); + + _method = "unknown"; + _phoneName = "phone"; +} + +void Connection::readLoop() +{ + setThreadName("usb-read"); + setThreadPriority(ThreadPriority::Realtime); + timeval timeout{0, 1000}; + + log_d("USB reading thread started"); + + while (_connected) + { + libusb_handle_events_timeout_completed(_context, &timeout, nullptr); + } + + log_v("Canceling transfer requests"); + + for (Context &context : _transfers) + { + if (context.transfer) + libusb_cancel_transfer(context.transfer); + libusb_handle_events_timeout_completed(_context, &timeout, nullptr); + } + + log_v("USB reading thread stopped"); +} + +void Connection::processLoop() +{ + setThreadName("usb-process"); + log_d("USB processing thread started"); + + while (_connected) + { + std::unique_ptr message = std::make_unique(); + + if (!_processQueue.read(message->header(), message->headerSize(), _connected)) + break; + + if (message->invalidMagic()) + { + log_w("Header read failed > invalid magic"); + _processQueue.discard(); + continue; + } + + if (message->invalidChecksum()) + { + log_w("Header read failed > invalid checksum"); + _processQueue.discard(); + continue; + } + + if (message->invalidLength()) + { + log_w("Header read failed > invalid length"); + _processQueue.discard(); + continue; + } + + if (message->length() > 0) + { + uint32_t padding = message->type() == CMD_VIDEO_DATA ? AV_INPUT_BUFFER_PADDING_SIZE : 0; + uint8_t *buff = message->allocate(padding); + if (!_processQueue.read(buff, message->length(), _connected)) + continue; + if (!buff) + { + log_w("Message discarded > can't allocate memory %d", message->length() + padding); + continue; + } + } + + onMessage(std::move(message)); + } + + log_v("USB processing thread stopped"); } void Connection::writeLoop(libusb_device_handle *handler, uint8_t ep) { - while (_active && _reader.active()) + while (_connected) { std::unique_ptr message = writeQueue.pop(); if (!message) { - if (!writeQueue.waitFor(_active, PROTOCOL_HEARTBEAT_DELAY)) + if (!writeQueue.waitFor(_connected, PROTOCOL_HEARTBEAT_DELAY)) break; message = writeQueue.pop(); } @@ -160,7 +410,7 @@ void Connection::writeLoop(libusb_device_handle *handler, uint8_t ep) if (!message) message = Message::HeartBeat(); - if (!_active || !_reader.active()) + if (!_connected) break; if (!message->allocated()) @@ -173,26 +423,26 @@ void Connection::writeLoop(libusb_device_handle *handler, uint8_t ep) if (_ecnrypt) { - Status s = message->encrypt(_cipher); - if (s.failed()) + char error[256]; + if (!message->encrypt(_cipher, error)) { - log_w("Message encryption failed > %s", s.error()); + log_w("Message encryption failed > %s", error); continue; } } int transferred; - libusb_bulk_transfer(handler, ep, message->header(), message->headerSize(), &transferred, 0); + int status = libusb_bulk_transfer(handler, ep, message->header(), message->headerSize(), &transferred, PROTOCOL_HEARTBEAT_DELAY); message->setOffset(0); - if (message->length() > 0) - libusb_bulk_transfer(handler, ep, message->data(), message->length(), &transferred, 0); + if (status == LIBUSB_SUCCESS && message->length() > 0) + { + libusb_bulk_transfer(handler, ep, message->data(), message->length(), &transferred, PROTOCOL_HEARTBEAT_DELAY); + } } } libusb_device *Connection::link(libusb_device_handle *handler, uint8_t *epIn, uint8_t *epOut) { - state(PROTOCOL_STATUS_LINKING); - if (fail(libusb_reset_device(handler), " Can't reset device")) return nullptr; @@ -242,51 +492,10 @@ bool Connection::fail(int status, const char *msg) if (status == 0) return false; log_w("%s > %s", msg, libusb_error_name(status)); - state(PROTOCOL_STATUS_ERROR); return true; } -bool Connection::state(u_int8_t state) -{ - if (state == _state) - return false; - - if (state == PROTOCOL_STATUS_ERROR && _failCount++ < 10) - { - return false; - } - - if (state > _state || state == PROTOCOL_STATUS_INITIALISING) - { - _nodeviceCount = 0; - _failCount = 0; - _state = state; - if (_statusHandler) - *_statusHandler = state; - return true; - } - - if (state == PROTOCOL_STATUS_NO_DEVICE && (_nodeviceCount++ > 30 || _state >= PROTOCOL_STATUS_ONLINE)) - { - _failCount = 0; - _state = state; - if (_statusHandler) - *_statusHandler = state; - return true; - } - - if (state == PROTOCOL_STATUS_ONLINE && _state == PROTOCOL_STATUS_CONNECTED) - { - _state = state; - if (_statusHandler) - *_statusHandler = state; - return true; - } - - return false; -} - -void Connection::onDeviceConnect() +void Connection::sendInit() { int syncTime = std::time(nullptr); int drivePosition = Settings::leftDrive ? 0 : 1; // 0==left, 1==right @@ -329,7 +538,7 @@ void Connection::onDeviceConnect() if (Settings::encryption) { if (_cipher) - send(Message::Encryption(_cipher->Seed())); + send(Message::Encryption(_cipher->seed())); else log_w("Can't request encryption > Cypher is not initalised"); } @@ -359,79 +568,99 @@ void Connection::onDeviceConnect() send(Message::Control(1002)); } -void Connection::onDeviceDisconnect() -{ - _recorder.stop(); - if (Settings::onDisconnect.value.length() > 1) - execute(Settings::onDisconnect.value.c_str()); -} - void Connection::onMessage(std::unique_ptr message) { - Status s = message->decrypt(_cipher); - if (s.failed()) + char error[256]; + if (!message->decrypt(_cipher, error)) { - log_w("Can't decrypt message %d > %s", message->type(), s.error()); + log_w("Can't decrypt message %d > %s", message->type(), error); return; } - switch (message->type()) + if (message->type() == CMD_VIDEO_DATA && message->setOffset(20)) { - - case CMD_CONTROL: - if (message->length() == 4) - { - switch (message->getInt(0)) - { - case 1: - _recorder.start(&writeQueue); - break; - - case 2: - _recorder.stop(); - break; - } - } - break; - - case CMD_PLUGGED: - { - state(PROTOCOL_STATUS_CONNECTED); - if (Settings::onConnect.value.length() > 1) - execute(Settings::onConnect.value.c_str()); - break; + if (!videoStream.pushDiscard(std::move(message))) + log_w("Discard message > video queue is full"); + return; } - case CMD_UNPLUGGED: + if (message->type() == CMD_AUDIO_DATA && message->length() > 16) { - state(PROTOCOL_STATUS_ONLINE); - _recorder.stop(); - if (Settings::onDisconnect.value.length() > 1) - execute(Settings::onDisconnect.value.c_str()); - break; - } - - case CMD_VIDEO_DATA: - { - if (message->setOffset(20)) - videoStream.pushDiscard(std::move(message)); - break; - } - case CMD_AUDIO_DATA: - { - if (message->length() <= 16) - break; int channel = message->getInt(8); message->setOffset(12); if (channel == 1) - audioStreamMain.pushDiscard(std::move(message)); + { + if (!audioStreamMain.pushDiscard(std::move(message))) + log_w("Discard message > main audio queue is full"); + return; + } if (channel == 2) - audioStreamAux.pushDiscard(std::move(message)); - break; + { + if (!audioStreamAux.pushDiscard(std::move(message))) + log_w("Discard message > aux audio queue is full"); + return; + } } - case CMD_ENCRYPTION: - if (message->length() == 0) - setEncryption(true); - break; + + if (message->type() == CMD_CONTROL && message->length() == 4) + { + switch (message->getInt(0)) + { + case 1: + _recorder.start(&writeQueue); + return; + + case 2: + _recorder.stop(); + return; + } } + + if (message->type() == CMD_PLUGGED) + { + onPhoneConnect(); + return; + } + + if (message->type() == CMD_UNPLUGGED) + { + onPhoneDisconnect(); + return; + } + + if (message->type() == CMD_ENCRYPTION && message->length() == 0) + { + setEncryption(true); + return; + } + + if (message->type() == CMD_JSON_CONTROL) + { + char buf[64]; + log_d("Controll message %d [%d] > %s", message->type(), message->length(), ascii(message->data(), message->length()).c_str()); + if (jsonFindString(message->data(), message->length(), "MDLinkType", buf, 64)) + _method = buf; + if (jsonFindString(message->data(), message->length(), "btName", buf, 64)) + _phoneName = buf; + return; + } + + log_v("Unknown message %d [%d] > %s", message->type(), message->length(), bytes(message->data(), message->length(), 40).c_str()); +} + +const std::string Connection::status() const +{ + std::ostringstream out; + + const libusb_version *version = libusb_get_version(); + out << "v" + << static_cast(version->major) << '.' + << static_cast(version->minor) << '.' + << static_cast(version->micro) << '.' + << static_cast(version->nano) << " " + << " queue " << _processQueue.count() << " / " << Settings::usbBuffer << " " + << (_ecnrypt.load(std::memory_order_acquire) ? "encrypt" : "simple") << " " + << _phoneName << " via " << _method; + + return out.str(); } diff --git a/src/protocol/connection.h b/src/protocol/connection.h index 6eaa4f1..9a45278 100644 --- a/src/protocol/connection.h +++ b/src/protocol/connection.h @@ -1,72 +1,96 @@ -#ifndef SRC_CONNECTOR -#define SRC_CONNECTOR +#ifndef SRC_PROTOCOL_CONNECTION +#define SRC_PROTOCOL_CONNECTION #include #include #include -#include -#include +#include -#include "protocol/imessage_sender.h" #include "struct/atomic_queue.h" -#include "struct/usb_buffer.h" #include "protocol/aes_cipher.h" -#include "protocol/connection_reader.h" +#include "protocol/usb_buffer.h" #include "recorder.h" -#define LINK_RETRY 5 +#define LINK_RETRY 3 +#define CONNECT_RETRY 20 #define LINK_RETRY_TIMEOUT 100 -#define RECONNECT_TIMEOUT 100 +#define RECONNECT_TIMEOUT 200 #define PROTOCOL_HEARTBEAT_DELAY 3000 -#define WRITE_QUEUE_SIZE 256 +#define WRITE_QUEUE_SIZE 128 +#define VIDEO_QUEUE_SIZE 128 +#define AUDIO_QUEUE_SIZE 128 +#define PROCESS_QUEUE_SIZE 128 + #define ENCRYPTION_BASE "SkBRDy3gmrw1ieH0" -class Connection : public IMessageReceiver +class Connection { public: Connection(); virtual ~Connection(); - void start(atomic *statusHandler); + void start(); void stop(); bool inline send(std::unique_ptr message) { return writeQueue.pushDiscard(std::move(message)); } + uint32_t transfered() const { return _transfered.load(std::memory_order_acquire); } + + int8_t state() const { return _state.load(); } + std::string connectionMethod() const { return _method; } + std::string phoneName() const { return _phoneName; } + const std::string status() const; AtomicQueue writeQueue; AtomicQueue videoStream; AtomicQueue audioStreamMain; AtomicQueue audioStreamAux; - virtual void onMessage(std::unique_ptr message) override; - private: + struct Context + { + Connection *owner = nullptr; + DataSlot *slot = nullptr; + libusb_transfer *transfer = nullptr; + }; + + static void onTransfer(libusb_transfer *transfer); void mainLoop(); + void readLoop(); + void processLoop(); void writeLoop(libusb_device_handle *handler, uint8_t ep); libusb_device *link(libusb_device_handle *handler, uint8_t *epIn, uint8_t *epOut); void setEncryption(bool enabled); bool fail(int status, const char *msg); - bool state(u_int8_t state); - void onDeviceConnect(); + void sendInit(); + void onDeviceConnect(libusb_device_handle *handler, libusb_device *device, uint8_t endpointIn); void onDeviceDisconnect(); + void onPhoneConnect(); + void onPhoneDisconnect(); + void onMessage(std::unique_ptr message); + + std::thread _writeThread; + std::thread _readThread; + std::thread _processThread; Recorder _recorder; + UsbBuffer _processQueue; + std::vector _transfers; + atomic *_statusHandler; AESCipher *_cipher; - ConnectionReader _reader; libusb_context *_context; - std::thread _thread; std::atomic _active; std::atomic _connected; + std::atomic _phoneConnected; std::atomic _ecnrypt; + std::atomic _state; - uint8_t _state; - uint8_t _failCount; - uint8_t _nodeviceCount; - - atomic *_statusHandler; + std::string _method; + std::string _phoneName; + std::atomic _transfered; }; -#endif /* SRC_CONNECTOR */ +#endif /* SRC_PROTOCOL_CONNECTION */ diff --git a/src/protocol/connection_reader.cpp b/src/protocol/connection_reader.cpp deleted file mode 100644 index 1e33557..0000000 --- a/src/protocol/connection_reader.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "protocol/connection_reader.h" - -#include -#include -#include -#include -#include -#include - -#include "settings.h" -#include "common/logger.h" -#include "common/threading.h" -#include "protocol/protocol_const.h" -#include "libavcodec/defs.h" -#include "common/functions.h" - -ConnectionReader::ConnectionReader() - : _active(false), - _buffer(Settings::usbBuffer, Settings::usbTransferSize), - _transfers(Settings::usbQueue), - _receiver(nullptr), - _usbContext(nullptr) -{ - log_v("Created"); -} - -ConnectionReader::~ConnectionReader() -{ - stop(); - - for (Context &context : _transfers) - { - if (context.transfer) - { - libusb_free_transfer(context.transfer); - context.transfer = nullptr; - } - } - log_v("Destroyed"); -} - -bool ConnectionReader::start(libusb_context *context, libusb_device_handle *device, uint8_t endpoint, IMessageReceiver *receiver) -{ - if (_active || !context || !device) - return false; - - _receiver = receiver; - _usbContext = context; - - log_i("Starting to read endpoint %d with %d requests", endpoint, _transfers.size()); - - // Prepare usb transfers - for (Context &context : _transfers) - { - context.owner = this; - if (!context.transfer) - { - context.transfer = libusb_alloc_transfer(0); - if (context.transfer == nullptr) - { - log_e("Can't allocate usb transfer"); - return false; - } - } - } - - // Start processing thread - _buffer.reset(); - _active = true; - _processThread = std::thread(&ConnectionReader::processLoop, this); - _readThread = std::thread(&ConnectionReader::readLoop, this); - - // Start usb reading thread - for (Context &context : _transfers) - { - context.slot = _buffer.get(); - if (context.slot == nullptr) - { - log_e("Can't allocate data slot for usb transfer"); - return false; - } - context.owner = this; - libusb_fill_bulk_transfer(context.transfer, device, endpoint, context.slot->data, context.slot->size, ConnectionReader::onUsbRead, &context, 0); - int status = libusb_submit_transfer(context.transfer); - if (status != LIBUSB_SUCCESS) - { - log_w("USB transfer submit failed with code %d", status); - return false; - } - } - - return true; -} - -void ConnectionReader::stop() -{ - log_v("Stopping"); - - _active = false; - - if (_usbContext) - { - for (Context &context : _transfers) - { - if (context.transfer) - libusb_cancel_transfer(context.transfer); - } - - timeval timeout{0, 100000}; - libusb_handle_events_timeout_completed(_usbContext, &timeout, nullptr); - - log_v("Events canceled"); - } - - _buffer.notify(); - - if (_readThread.joinable()) - _readThread.join(); - - if (_processThread.joinable()) - _processThread.join(); - - _usbContext = nullptr; - - log_v("Threads stopped"); -} - -void ConnectionReader::onUsbRead(libusb_transfer *transfer) -{ - if (!transfer || !transfer->user_data) - return; - - Context *c = static_cast(transfer->user_data); - if (!c->owner->_active) - return; - - log_p("Read %d [%d]: %s", transfer->actual_length, transfer->status, bytes(transfer->buffer, transfer->actual_length, 40).c_str()); - - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) - return; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - { - log_w("USB read failed with status %d", transfer->status); - c->owner->_active = false; - return; - } - - c->slot->commit(transfer->actual_length); - - c->slot = c->owner->_buffer.get(); - if (!c->slot) - { - log_e("Can't allocate data slot for next usb transfer"); - c->owner->_active = false; - return; - } - c->transfer->buffer = c->slot->data; - - if (!c->owner->_active) - return; - - int status = libusb_submit_transfer(c->transfer); - if (status != LIBUSB_SUCCESS) - { - log_w("USB transfer re-submit failed with status %d", status); - c->owner->_active = false; - } -} - -void ConnectionReader::readLoop() -{ - setThreadName("usb-read"); - setThreadPriority(ThreadPriority::Realtime); - timeval timeout{0, 100000}; - - log_d("USB reading thread started"); - - while (_active) - { - libusb_handle_events_timeout_completed(_usbContext, &timeout, nullptr); - } - - log_v("USB reading thread stopped"); -} - -void ConnectionReader::processLoop() -{ - setThreadName("usb-process"); - log_d("USB processing thread started"); - - while (_active) - { - std::unique_ptr message = std::make_unique(); - - if (!_buffer.read(message->header(), message->headerSize(), _active)) - break; - - if (!message->valid()) - { - log_w("Mallformed message %s", message->toString(20).c_str()); - continue; - } - - if (message->length() >= 0) - { - uint8_t *buff = message->allocate(message->type() == CMD_VIDEO_DATA ? AV_INPUT_BUFFER_PADDING_SIZE : 0); - if (!_buffer.read(buff, message->length(), _active)) - break; - } - - if (_receiver && message->allocated()) - _receiver->onMessage(std::move(message)); - } - - log_v("USB processing thread stopped"); -} diff --git a/src/protocol/connection_reader.h b/src/protocol/connection_reader.h deleted file mode 100644 index 8258ac4..0000000 --- a/src/protocol/connection_reader.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef SRC_PROTOCOL_CONNECTION_READER -#define SRC_PROTOCOL_CONNECTION_READER - -#include - -#include -#include -#include -#include -#include - -#include "struct/usb_buffer.h" -#include "protocol/aes_cipher.h" -#include "protocol/message.h" - -class IMessageReceiver -{ -public: - virtual ~IMessageReceiver() = default; - virtual void onMessage(std::unique_ptr message) = 0; -}; - -class ConnectionReader -{ -public: - ConnectionReader(); - ~ConnectionReader(); - - ConnectionReader(const ConnectionReader &) = delete; - ConnectionReader &operator=(const ConnectionReader &) = delete; - - bool start(libusb_context *context, libusb_device_handle *device, uint8_t endpoint, IMessageReceiver *receiver); - void stop(); - - int bufferCount() const { return _buffer.count(); } - bool active() const { return _active; } - -private: - struct Context - { - ConnectionReader *owner = nullptr; - DataSlot *slot = nullptr; - libusb_transfer *transfer = nullptr; - }; - - static void onUsbRead(libusb_transfer *transfer); - void readLoop(); - void processLoop(); - - void cancelTransfers(); - - std::atomic _active; - UsbBuffer _buffer; - std::vector _transfers; - IMessageReceiver *_receiver; - std::thread _readThread; - std::thread _processThread; - libusb_context *_usbContext; -}; - -#endif /* SRC_PROTOCOL_CONNECTION_READER */ diff --git a/src/protocol/imessage_sender.h b/src/protocol/imessage_sender.h deleted file mode 100644 index 617e882..0000000 --- a/src/protocol/imessage_sender.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SRC_HELPER_ISENDER -#define SRC_HELPER_ISENDER - -#include - -#include "protocol/message.h" - -class IMessageSender -{ -public: - virtual ~IMessageSender() = default; - virtual bool send(std::unique_ptr packet) = 0; -}; - -#endif /* SRC_HELPER_ISENDER */ diff --git a/src/protocol/message.h b/src/protocol/message.h index 50de96b..e2c862d 100644 --- a/src/protocol/message.h +++ b/src/protocol/message.h @@ -99,51 +99,40 @@ public: return true; } - bool valid() const + bool encrypt(AESCipher *cipher, char *err = nullptr) { - if (_header.magic != MAGIC_ENC && _header.magic != MAGIC) - return false; - if (_header.typecheck != ~_header.type) - return false; - if (_header.length < 0 || _header.length > MESSAGE_MAX_PAYLOAD_SIZE) + if (!_encrypt || _header.magic == MAGIC_ENC) + return true; + + if (!cipher) + return AESCipher::error(err, "Cipher is not initialised"); + + if (!allocated()) + return AESCipher::error(err, "Message data is not allocated"); + + if (!cipher->encrypt(_data, _header.length, err)) return false; + + _header.magic = MAGIC_ENC; return true; } - Status encrypt(AESCipher *cipher) - { - if (!_encrypt) - return Status::Success(); - - if (_header.magic == MAGIC_ENC) - return Status::Success(); - - if (!cipher) - return Status::Error("Cipher is not initialised"); - - if (!allocated()) - return Status::Error("Message data is not allocated"); - - Status result = cipher->Encrypt(_data, _header.length); - - if (result.succeed()) - _header.magic = MAGIC_ENC; - - return result; - } - - Status decrypt(AESCipher *cipher) + bool decrypt(AESCipher *cipher, char *err = nullptr) { if (_header.magic != MAGIC_ENC) - return Status::Success(); + return true; if (!cipher) - return Status::Error("Cipher is not initialised"); + return AESCipher::error(err, "Cipher is not initialised"); if (!allocated()) - return Status::Error("Message data is not allocated"); + return AESCipher::error(err, "Message data is not allocated"); - return cipher->Decrypt(_data, _header.length); + if (!cipher->decrypt(_data, _header.length, err)) + return false; + + _header.magic = MAGIC; + return true; } bool isMotion() const @@ -299,7 +288,11 @@ public: int32_t length() const { return _header.length - _offset; } uint8_t *data() const { return _data ? _data + _offset : nullptr; } - const std::string toString(int count) const + bool invalidMagic() const { return _header.magic != MAGIC_ENC && _header.magic != MAGIC; } + bool invalidChecksum() const { return _header.typecheck != ~_header.type; } + bool invalidLength() const { return _header.length < 0 || _header.length > MESSAGE_MAX_PAYLOAD_SIZE; } + + const std::string toString(int count) const { const char *cmds = "Unknown"; for (size_t i = 0; i < sizeof(protocolCmdList) / sizeof(protocolCmdList[0]); ++i) diff --git a/src/struct/usb_buffer.cpp b/src/protocol/usb_buffer.cpp similarity index 92% rename from src/struct/usb_buffer.cpp rename to src/protocol/usb_buffer.cpp index 7602ed2..886cff2 100644 --- a/src/struct/usb_buffer.cpp +++ b/src/protocol/usb_buffer.cpp @@ -1,4 +1,4 @@ -#include "struct/usb_buffer.h" +#include "protocol/usb_buffer.h" #include #include @@ -129,6 +129,17 @@ bool UsbBuffer::read(uint8_t *dst, uint32_t length, std::atomic &active) return active.load(); } +void UsbBuffer::discard() +{ + if (!_slots[_readSlot].ready.load()) + return; + + _slots[_readSlot].ready.store(false); + _readSlot++; + if (_readSlot >= _size) + _readSlot = 0; +} + void UsbBuffer::reset() { _readSlot = 0; diff --git a/src/struct/usb_buffer.h b/src/protocol/usb_buffer.h similarity index 98% rename from src/struct/usb_buffer.h rename to src/protocol/usb_buffer.h index b50db93..be63717 100644 --- a/src/struct/usb_buffer.h +++ b/src/protocol/usb_buffer.h @@ -40,6 +40,7 @@ public: DataSlot *get(); bool read(uint8_t *dst, uint32_t length, std::atomic &active); + void discard(); void reset(); void notify(); diff --git a/src/recorder.cpp b/src/recorder.cpp index e48fea7..d5a829a 100644 --- a/src/recorder.cpp +++ b/src/recorder.cpp @@ -4,12 +4,8 @@ #include #include "protocol/protocol_const.h" -#include "common/functions.h" -#include "settings.h" -#include "protocol/message.h" - -Recorder::Recorder(uint16_t buffSize) +Recorder::Recorder() : _queue(nullptr), _active(false), _device(0) { } diff --git a/src/recorder.h b/src/recorder.h index 3869c4c..8d2078f 100644 --- a/src/recorder.h +++ b/src/recorder.h @@ -1,7 +1,6 @@ #ifndef SRC_RECORDER #define SRC_RECORDER -#include #include #include @@ -12,7 +11,7 @@ class Recorder { public: - Recorder(uint16_t buffSize); + Recorder(); ~Recorder(); void start(AtomicQueue *queue); @@ -20,11 +19,10 @@ public: private: static void AudioCallback(void *userdata, Uint8 *stream, int len); - void runner(); AtomicQueue *_queue; std::atomic _active; - SDL_AudioDeviceID _device; + SDL_AudioDeviceID _device; }; #endif /* SRC_RECORDER */ diff --git a/src/resource/background.bmp b/src/resource/background.bmp index 6d94d00..b50f55b 100644 Binary files a/src/resource/background.bmp and b/src/resource/background.bmp differ diff --git a/src/settings.cpp b/src/settings.cpp index 8257203..4023d19 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,6 +1,7 @@ #include "settings.h" -#include +#include +#include #include #include "common/logger.h" @@ -10,7 +11,7 @@ bool Settings::load(const std::string &filename) std::ifstream file(filename); if (!file.is_open()) { - log_e( "Cannot open file > %s", filename.c_str()); + log_e("Cannot open file > %s", filename.c_str()); return false; } @@ -57,7 +58,7 @@ void Settings::print() { for (ISetting *setting : _settings()) { - log_d("%s = %s",setting->name.c_str(), setting->asString().c_str()); + log_d("%s = %s", setting->name.c_str(), setting->asString().c_str()); } } diff --git a/src/settings.h b/src/settings.h index 7514aad..309772f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -14,7 +14,7 @@ public: // General section static inline Setting vendorid{"vendor-id", 4884}; static inline Setting productid{"product-id", 5408}; - static inline Setting width{"width", 720}; + static inline Setting width{"width", 1024}; static inline Setting height{"height", 576}; static inline Setting sourceFps{"source-fps", 60}; static inline Setting fps{"fps", 60}; @@ -36,7 +36,7 @@ public: static inline Setting mediaDelay{"android-media-delay", 300}; // Application configuration section - static inline Setting fontSize{"font-size", 30}; + static inline Setting fontSize{"font-size", 40}; static inline Setting vsync{"vsync", false}; static inline Setting hwDecode{"hw-decode", true}; static inline Setting renderingBuffer{"rendering-buffer", 5}; @@ -44,14 +44,12 @@ public: static inline Setting forceRedraw{"force-redraw", 0}; static inline Setting forceRedrawTimeout{"force-redraw-timeout", 0}; static inline Setting aspectCorrection{"aspect-correction", 1}; - static inline Setting renderDriver{"renderer-driver", ""}; - static inline Setting alternativeRendering{"alternative-rendering", false}; + static inline Setting renderDriver{"renderer-driver", ""}; + static inline Setting alternativeRendering{"alternative-rendering", false}; static inline Setting fastScale{"fast-render-scale", false}; - static inline Setting usbQueue{"async-usb-calls", 16}; - static inline Setting usbTransferSize{"usb-buffer-size", 20480}; - static inline Setting usbBuffer{"usb-buffer", 64}; - static inline Setting videoQueue{"video-buffer-size", 64}; - static inline Setting audioQueue{"audio-buffer-size", 64}; + static inline Setting usbQueue{"async-usb-calls", 32}; + static inline Setting usbTransferSize{"usb-buffer-size", 2048}; + static inline Setting usbBuffer{"usb-buffer", 128}; static inline Setting audioDelay{"audio-buffer-wait", 2}; static inline Setting audioDelayCall{"audio-buffer-wait-call", 6}; static inline Setting audioFade{"audio-fade", 0.3}; diff --git a/src/struct/atomic_queue.h b/src/struct/atomic_queue.h index b270451..80472b9 100644 --- a/src/struct/atomic_queue.h +++ b/src/struct/atomic_queue.h @@ -104,7 +104,7 @@ public: _lock.notify_all(); } - uint16_t count() { return _count.load(std::memory_order_acquire); } + uint16_t count() const { return _count.load(std::memory_order_acquire); } private: uint16_t _size;