mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
Message queue for sending
This commit is contained in:
+7
-7
@@ -109,6 +109,13 @@
|
|||||||
# Corrects aspect of UI
|
# Corrects aspect of UI
|
||||||
#aspect-correction = 1
|
#aspect-correction = 1
|
||||||
|
|
||||||
|
# Force SDL renderer backend, leave empty for automatic
|
||||||
|
# Examples: opengles2, opengl, software
|
||||||
|
#renderer-driver =
|
||||||
|
|
||||||
|
# Use alternative video rendering method. May reduce CPU load and increase smoothness.
|
||||||
|
#alternative-rendering = false
|
||||||
|
|
||||||
# Select faster method of scaling image to window size (nearest) or better quality (linear)
|
# Select faster method of scaling image to window size (nearest) or better quality (linear)
|
||||||
#fast-render-scale = false
|
#fast-render-scale = false
|
||||||
|
|
||||||
@@ -139,13 +146,6 @@
|
|||||||
# pipewire
|
# pipewire
|
||||||
#audio-driver =
|
#audio-driver =
|
||||||
|
|
||||||
# Force SDL renderer backend, leave empty for automatic
|
|
||||||
# Examples: opengles2, opengl, software
|
|
||||||
#renderer-driver =
|
|
||||||
|
|
||||||
# Use alternative video rendering method. May reduce CPU load and increase smoothness.
|
|
||||||
#alternative-rendering = false
|
|
||||||
|
|
||||||
# Run script or app on phone connected and disconnected.
|
# Run script or app on phone connected and disconnected.
|
||||||
# This script/app should be fast, otherwise it will block system.
|
# This script/app should be fast, otherwise it will block system.
|
||||||
# If you need to start application in background use scripts with fork
|
# If you need to start application in background use scripts with fork
|
||||||
|
|||||||
+6
-6
@@ -270,7 +270,7 @@ bool Application::processFrameEvents(Protocol &protocol, Renderer &renderer)
|
|||||||
int key = processKey(e.key.keysym);
|
int key = processKey(e.key.keysym);
|
||||||
if (key > 0)
|
if (key > 0)
|
||||||
{
|
{
|
||||||
protocol.sendKey(key);
|
protocol.send(Command::Control(key));
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -279,7 +279,7 @@ bool Application::processFrameEvents(Protocol &protocol, Renderer &renderer)
|
|||||||
{
|
{
|
||||||
if (e.key.keysym.sym == Settings::keyEnter)
|
if (e.key.keysym.sym == Settings::keyEnter)
|
||||||
{
|
{
|
||||||
protocol.sendKey(Settings::keyEnterUp.key);
|
protocol.send(Command::Control(Settings::keyEnterUp.key));
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -290,11 +290,11 @@ bool Application::processFrameEvents(Protocol &protocol, Renderer &renderer)
|
|||||||
if (_state.frameRendered && (downX >= 0 || upX >= 0 || motionX >= 0))
|
if (_state.frameRendered && (downX >= 0 || upX >= 0 || motionX >= 0))
|
||||||
{
|
{
|
||||||
if (downX >= 0)
|
if (downX >= 0)
|
||||||
protocol.sendClick(renderer.xScale * downX / _width, renderer.yScale * downY / _height, true);
|
protocol.send(Command::Click(renderer.xScale * downX / _width, renderer.yScale * downY / _height, true));
|
||||||
if (motionX >= 0)
|
if (motionX >= 0)
|
||||||
protocol.sendMove(renderer.xScale * motionX / _width, renderer.yScale * motionY / _height);
|
protocol.send(Command::Move(renderer.xScale * motionX / _width, renderer.yScale * motionY / _height));
|
||||||
if (upX >= 0)
|
if (upX >= 0)
|
||||||
protocol.sendClick(renderer.xScale * upX / _width, renderer.yScale * upY / _height, false);
|
protocol.send(Command::Click(renderer.xScale * upX / _width, renderer.yScale * upY / _height, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -358,7 +358,7 @@ void Application::loop()
|
|||||||
{
|
{
|
||||||
if (latestFrameid == requestFrameId)
|
if (latestFrameid == requestFrameId)
|
||||||
{
|
{
|
||||||
protocol.requestKeyframe();
|
protocol.send(Command::Control(BTN_SCREEN_REFRESH));
|
||||||
_state.requestFrame = 1;
|
_state.requestFrame = 1;
|
||||||
requestFrameId = latestFrameid;
|
requestFrameId = latestFrameid;
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-11
@@ -30,6 +30,7 @@ Connector::Connector(uint16_t videoPadding)
|
|||||||
Connector::~Connector()
|
Connector::~Connector()
|
||||||
{
|
{
|
||||||
_active = false;
|
_active = false;
|
||||||
|
_queue.notify();
|
||||||
|
|
||||||
if (_write_thread.joinable())
|
if (_write_thread.joinable())
|
||||||
_write_thread.join();
|
_write_thread.join();
|
||||||
@@ -69,6 +70,7 @@ void Connector::stop()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_active = false;
|
_active = false;
|
||||||
|
_queue.notify();
|
||||||
|
|
||||||
state(PROTOCOL_STATUS_INITIALISING);
|
state(PROTOCOL_STATUS_INITIALISING);
|
||||||
|
|
||||||
@@ -181,7 +183,15 @@ bool Connector::linkFail(int status, const char *msg)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connector::send(int cmd, bool encrypt, uint8_t *data, uint32_t size)
|
bool Connector::send(std::unique_ptr<Command> packet)
|
||||||
|
{
|
||||||
|
if (!_connected || !packet)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _queue.pushDiscard(std::move(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Connector::write(int cmd, bool encrypt, uint8_t *data, uint32_t size)
|
||||||
{
|
{
|
||||||
if (!_connected)
|
if (!_connected)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -380,9 +390,6 @@ void Connector::readLoop()
|
|||||||
|
|
||||||
void Connector::writeLoop()
|
void Connector::writeLoop()
|
||||||
{
|
{
|
||||||
std::mutex mtx;
|
|
||||||
std::condition_variable cv;
|
|
||||||
|
|
||||||
// Set thread name
|
// Set thread name
|
||||||
setThreadName("protocol-writer");
|
setThreadName("protocol-writer");
|
||||||
state(PROTOCOL_STATUS_LINKING);
|
state(PROTOCOL_STATUS_LINKING);
|
||||||
@@ -400,10 +407,18 @@ void Connector::writeLoop()
|
|||||||
state(PROTOCOL_STATUS_ONLINE);
|
state(PROTOCOL_STATUS_ONLINE);
|
||||||
while (_connected && _active)
|
while (_connected && _active)
|
||||||
{
|
{
|
||||||
send(170);
|
std::unique_ptr<Command> message = _queue.pop();
|
||||||
std::unique_lock<std::mutex> lock(mtx);
|
if (!message)
|
||||||
cv.wait_for(lock, std::chrono::seconds(2), [&]()
|
{
|
||||||
{ return !_active.load(); });
|
if (!_queue.waitFor(_active, 2000))
|
||||||
|
break;
|
||||||
|
message = _queue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message)
|
||||||
|
write(message->command, message->encryption, message->data, message->length);
|
||||||
|
else
|
||||||
|
write(CMD_HEARTBEAT, false, nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_active)
|
if (_active)
|
||||||
@@ -412,11 +427,11 @@ void Connector::writeLoop()
|
|||||||
onDevice(false);
|
onDevice(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_queue.clear();
|
||||||
|
|
||||||
if (_read_thread.joinable())
|
if (_read_thread.joinable())
|
||||||
_read_thread.join();
|
_read_thread.join();
|
||||||
}
|
}
|
||||||
std::unique_lock<std::mutex> lock(mtx);
|
_queue.waitFor(_active, 1000);
|
||||||
cv.wait_for(lock, std::chrono::seconds(1), [&]()
|
|
||||||
{ return !_active.load(); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-4
@@ -8,7 +8,10 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "helper/isender.h"
|
||||||
#include "aes_cipher.h"
|
#include "aes_cipher.h"
|
||||||
|
#include "struct/atomic_queue.h"
|
||||||
|
#include "struct/command.h"
|
||||||
|
|
||||||
#define READ_TIMEOUT 3000
|
#define READ_TIMEOUT 3000
|
||||||
#define ENCRYPTION_BASE "SkBRDy3gmrw1ieH0"
|
#define ENCRYPTION_BASE "SkBRDy3gmrw1ieH0"
|
||||||
@@ -29,7 +32,7 @@ struct Header
|
|||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
class Connector
|
class Connector : public ISender
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -38,10 +41,9 @@ public:
|
|||||||
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
bool send(std::unique_ptr<Command> packet) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
int send(int cmd, bool encrypt = true, uint8_t *data = nullptr, uint32_t size = 0);
|
|
||||||
virtual void onData(uint32_t cmd, uint32_t length, uint8_t *data) = 0;
|
virtual void onData(uint32_t cmd, uint32_t length, uint8_t *data) = 0;
|
||||||
virtual void onStatus(u_int8_t status) = 0;
|
virtual void onStatus(u_int8_t status) = 0;
|
||||||
virtual void onDevice(bool connected) = 0;
|
virtual void onDevice(bool connected) = 0;
|
||||||
@@ -66,12 +68,13 @@ private:
|
|||||||
void state(u_int8_t state);
|
void state(u_int8_t state);
|
||||||
bool nextState(u_int8_t state);
|
bool nextState(u_int8_t state);
|
||||||
bool linkFail(int status, const char *msg);
|
bool linkFail(int status, const char *msg);
|
||||||
|
int write(int cmd, bool encrypt, uint8_t *data, uint32_t size);
|
||||||
|
|
||||||
libusb_context *_context = nullptr;
|
libusb_context *_context = nullptr;
|
||||||
libusb_device_handle *_device = nullptr;
|
libusb_device_handle *_device = nullptr;
|
||||||
uint8_t _endpoint_in;
|
uint8_t _endpoint_in;
|
||||||
uint8_t _endpoint_out;
|
uint8_t _endpoint_out;
|
||||||
bool _connected;
|
std::atomic<bool> _connected = false;
|
||||||
std::atomic<bool> _ecnrypt = false;
|
std::atomic<bool> _ecnrypt = false;
|
||||||
|
|
||||||
uint8_t _state;
|
uint8_t _state;
|
||||||
@@ -83,6 +86,7 @@ private:
|
|||||||
std::thread _write_thread;
|
std::thread _write_thread;
|
||||||
std::mutex _write_mutex;
|
std::mutex _write_mutex;
|
||||||
std::atomic<bool> _active = false;
|
std::atomic<bool> _active = false;
|
||||||
|
AtomicQueue<Command> _queue{256};
|
||||||
|
|
||||||
u_int16_t _videoPadding;
|
u_int16_t _videoPadding;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#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 */
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef SRC_HELPER_ISENDER
|
||||||
|
#define SRC_HELPER_ISENDER
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "struct/command.h"
|
||||||
|
|
||||||
|
class ISender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISender() = default;
|
||||||
|
virtual bool send(std::unique_ptr<Command> packet) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SRC_HELPER_ISENDER */
|
||||||
+24
-180
@@ -15,7 +15,6 @@ Protocol::Protocol(uint16_t width, uint16_t height, uint16_t fps, uint16_t paddi
|
|||||||
_width(width),
|
_width(width),
|
||||||
_height(height),
|
_height(height),
|
||||||
_fps(fps),
|
_fps(fps),
|
||||||
_keySent(false),
|
|
||||||
_phoneConnected(false)
|
_phoneConnected(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -37,20 +36,6 @@ void Protocol::stop()
|
|||||||
Connector::stop();
|
Connector::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::sendInit(int width, int height, int fps)
|
|
||||||
{
|
|
||||||
uint8_t buf[28];
|
|
||||||
write_uint32_le(&buf[0], width);
|
|
||||||
write_uint32_le(&buf[4], height);
|
|
||||||
write_uint32_le(&buf[8], fps);
|
|
||||||
write_uint32_le(&buf[12], 5);
|
|
||||||
write_uint32_le(&buf[16], 49152);
|
|
||||||
write_uint32_le(&buf[20], 2);
|
|
||||||
write_uint32_le(&buf[24], 2);
|
|
||||||
|
|
||||||
send(CMD_OPEN, true, buf, 28);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendConfig()
|
void Protocol::sendConfig()
|
||||||
{
|
{
|
||||||
int syncTime = std::time(nullptr);
|
int syncTime = std::time(nullptr);
|
||||||
@@ -91,171 +76,25 @@ void Protocol::sendConfig()
|
|||||||
|
|
||||||
std::cout << "[Protocol] Request android image " << width << "x" << height << std::endl;
|
std::cout << "[Protocol] Request android image " << width << "x" << height << std::endl;
|
||||||
|
|
||||||
char buffer[512];
|
send(Command::String(
|
||||||
snprintf(buffer, sizeof(buffer),
|
CMD_JSON_CONTROL,
|
||||||
"{\"syncTime\":%d,\"mediaDelay\":%d,\"drivePosition\":%d,"
|
"{\"syncTime\":%d,\"mediaDelay\":%d,\"drivePosition\":%d,"
|
||||||
"\"androidAutoSizeW\":%d,\"androidAutoSizeH\":%d,\"HiCarConnectMode\":0,"
|
"\"androidAutoSizeW\":%d,\"androidAutoSizeH\":%d,\"HiCarConnectMode\":0,"
|
||||||
"\"GNSSCapability\":7,\"DashboardInfo\":1,\"UseBTPhone\":0}",
|
"\"GNSSCapability\":7,\"DashboardInfo\":1,\"UseBTPhone\":0}",
|
||||||
syncTime, Settings::mediaDelay.value, drivePosition, width, height);
|
syncTime, Settings::mediaDelay.value, drivePosition, width, height));
|
||||||
|
|
||||||
sendString(CMD_JSON_CONTROL, buffer);
|
send(Command::String(CMD_DAYNIGHT, "{\"DayNightMode\":%d}", nightMode));
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "{\"DayNightMode\":%d}", nightMode);
|
send(Command::File("/tmp/night_mode", nightMode));
|
||||||
sendString(CMD_DAYNIGHT, buffer);
|
send(Command::File("/tmp/charge_mode", Settings::weakCharge ? 0 : 2)); // Weak charge 0, other 2
|
||||||
|
send(Command::File("/etc/box_name", "CarPlay"));
|
||||||
|
send(Command::File("/tmp/hand_drive_mode", drivePosition));
|
||||||
|
|
||||||
sendFile("/tmp/night_mode", nightMode);
|
send(Command::Control(mic));
|
||||||
sendFile("/tmp/charge_mode", Settings::weakCharge ? 0 : 2); // Weak charge 0, other 2
|
send(Command::Control(Settings::wifi5 ? 25 : 24));
|
||||||
sendFile("/etc/box_name", "CarPlay");
|
send(Command::Control(Settings::bluetoothAudio ? 22 : 23));
|
||||||
sendFile("/tmp/hand_drive_mode", drivePosition);
|
|
||||||
|
|
||||||
sendInt(CMD_CONTROL, mic);
|
|
||||||
sendInt(CMD_CONTROL, Settings::wifi5 ? 25 : 24);
|
|
||||||
sendInt(CMD_CONTROL, Settings::bluetoothAudio ? 22 : 23);
|
|
||||||
if (Settings::autoconnect)
|
if (Settings::autoconnect)
|
||||||
sendInt(CMD_CONTROL, 1002);
|
send(Command::Control(1002));
|
||||||
}
|
|
||||||
|
|
||||||
bool Protocol::checkKey()
|
|
||||||
{
|
|
||||||
bool result = _keySent;
|
|
||||||
_keySent = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendKey(int key)
|
|
||||||
{
|
|
||||||
sendInt(CMD_CONTROL, key, false);
|
|
||||||
_keySent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::requestKeyframe()
|
|
||||||
{
|
|
||||||
sendInt(CMD_CONTROL, BTN_SCREEN_REFRESH, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendFile(const char *filename, const char *value)
|
|
||||||
{
|
|
||||||
uint32_t len = strlen(value);
|
|
||||||
if (len > 16)
|
|
||||||
{
|
|
||||||
throw std::invalid_argument("String too long (max 16 bytes)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: we send only the ASCII bytes, no trailing '\0'
|
|
||||||
sendFile(filename,
|
|
||||||
reinterpret_cast<const uint8_t *>(value),
|
|
||||||
static_cast<uint32_t>(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
// overload for a single 32‑bit integer
|
|
||||||
void Protocol::sendFile(const char *filename, int value)
|
|
||||||
{
|
|
||||||
uint8_t buf[4];
|
|
||||||
write_uint32_le(buf, value);
|
|
||||||
sendFile(filename, buf, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendClick(float x, float y, bool down)
|
|
||||||
{
|
|
||||||
uint8_t buf[16];
|
|
||||||
write_uint32_le(buf, down ? 14 : 16);
|
|
||||||
write_uint32_le(buf + 4, int(10000 * x));
|
|
||||||
write_uint32_le(buf + 8, int(10000 * y));
|
|
||||||
write_uint32_le(buf + 12, 0);
|
|
||||||
send(CMD_TOUCH, false, buf, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendMultiTouch(const Multitouch &touches)
|
|
||||||
{
|
|
||||||
int count = touches.size();
|
|
||||||
if (count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint8_t buf[MUTLITOUCH_MAX_TOUCH * sizeof(Multitouch::Touch)];
|
|
||||||
uint8_t *p = buf;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
const Multitouch::Touch &t = touches[i];
|
|
||||||
write_float_le(p + 0, t.x);
|
|
||||||
write_float_le(p + 4, t.y);
|
|
||||||
write_uint32_le(p + 8, static_cast<uint32_t>(t.state));
|
|
||||||
write_uint32_le(p + 12, static_cast<uint32_t>(t.id));
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
send(CMD_MULTI_TOUCH, false, buf, 16 * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendMove(float dx, float dy)
|
|
||||||
{
|
|
||||||
uint8_t buf[16];
|
|
||||||
write_uint32_le(buf, 15);
|
|
||||||
write_uint32_le(buf + 4, int(10000 * dx));
|
|
||||||
write_uint32_le(buf + 8, int(10000 * dy));
|
|
||||||
write_uint32_le(buf + 12, 0);
|
|
||||||
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 null‑terminated, so strlen + 1 to include the '\0'
|
|
||||||
uint32_t fn_len = strlen(filename) + 1;
|
|
||||||
|
|
||||||
// Total buffer size: 4 (fn_len) + fn_len + 4 (content_len) + content_len
|
|
||||||
uint32_t total = 4 + fn_len + 4 + length;
|
|
||||||
std::vector<uint8_t> result(total);
|
|
||||||
uint8_t *buf = result.data();
|
|
||||||
|
|
||||||
// 1) filename length (LE)
|
|
||||||
write_uint32_le(buf, fn_len);
|
|
||||||
buf += 4;
|
|
||||||
|
|
||||||
// 2) filename bytes (including the '\0')
|
|
||||||
std::memcpy(buf, filename, fn_len);
|
|
||||||
buf += fn_len;
|
|
||||||
|
|
||||||
// 3) content length (LE)
|
|
||||||
write_uint32_le(buf, length);
|
|
||||||
buf += 4;
|
|
||||||
|
|
||||||
// 4) content bytes
|
|
||||||
std::memcpy(buf, data, length);
|
|
||||||
|
|
||||||
send(CMD_SEND_FILE, true, result.data(), total);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendInt(uint32_t cmd, uint32_t value, bool encryption)
|
|
||||||
{
|
|
||||||
uint8_t buf[4];
|
|
||||||
write_uint32_le(buf, value);
|
|
||||||
send(cmd, encryption, buf, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendString(uint32_t cmd, char *str, bool encryption)
|
|
||||||
{
|
|
||||||
uint32_t total = strlen(str);
|
|
||||||
send(cmd, true, (uint8_t *)str, total);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::sendEncryption()
|
|
||||||
{
|
|
||||||
if (!_cipher)
|
|
||||||
{
|
|
||||||
std::cout << "[Protocol] Can't enable encryption: cypher is not initalised" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint8_t buf[4];
|
|
||||||
write_uint32_le(buf, _cipher->Seed());
|
|
||||||
send(CMD_ENCRYPTION, false, buf, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Protocol::onStatus(uint8_t status)
|
void Protocol::onStatus(uint8_t status)
|
||||||
@@ -269,11 +108,16 @@ void Protocol::onDevice(bool connected)
|
|||||||
if (connected)
|
if (connected)
|
||||||
{
|
{
|
||||||
if (Settings::encryption)
|
if (Settings::encryption)
|
||||||
sendEncryption();
|
{
|
||||||
|
if (_cipher)
|
||||||
|
send(Command::Encryption(_cipher->Seed()));
|
||||||
|
else
|
||||||
|
std::cout << "[Protocol] Can't enable encryption: cypher is not initalised" << std::endl;
|
||||||
|
}
|
||||||
if (Settings::dpi > 0)
|
if (Settings::dpi > 0)
|
||||||
sendFile("/tmp/screen_dpi", Settings::dpi);
|
send(Command::File("/tmp/screen_dpi", Settings::dpi));
|
||||||
sendFile("/etc/android_work_mode", 1);
|
send(Command::File("/etc/android_work_mode", 1));
|
||||||
sendInit(_width, _height, _fps);
|
send(Command::Init(_width, _height, _fps));
|
||||||
sendConfig();
|
sendConfig();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-19
@@ -4,12 +4,11 @@
|
|||||||
#include "struct/atomic_queue.h"
|
#include "struct/atomic_queue.h"
|
||||||
#include "struct/message.h"
|
#include "struct/message.h"
|
||||||
#include "struct/multitouch.h"
|
#include "struct/multitouch.h"
|
||||||
#include "helper/iaudio_sender.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "connector.h"
|
#include "connector.h"
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
|
|
||||||
class Protocol : private Connector, public IAudioSender
|
class Protocol : public Connector
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -22,27 +21,11 @@ public:
|
|||||||
void start(uint32_t evtStatus, uint32_t evtPhone);
|
void start(uint32_t evtStatus, uint32_t evtPhone);
|
||||||
void stop();
|
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);
|
|
||||||
void sendClick(float x, float y, bool down);
|
|
||||||
void sendMultiTouch(const Multitouch &touches);
|
|
||||||
void sendMove(float dx, float dy);
|
|
||||||
void sendAudio(uint8_t *data, uint32_t length) override;
|
|
||||||
|
|
||||||
AtomicQueue<Message> videoData;
|
AtomicQueue<Message> videoData;
|
||||||
AtomicQueue<Message> audioStreamMain;
|
AtomicQueue<Message> audioStreamMain;
|
||||||
AtomicQueue<Message> audioStreamAux;
|
AtomicQueue<Message> audioStreamAux;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendInt(uint32_t cmd, uint32_t value, bool encryption = true);
|
|
||||||
void sendString(uint32_t cmd, char *str, bool encryption = true);
|
|
||||||
void sendEncryption();
|
|
||||||
void sendInit(int width, int height, int fps);
|
|
||||||
void sendConfig();
|
void sendConfig();
|
||||||
|
|
||||||
void onStatus(uint8_t status) override;
|
void onStatus(uint8_t status) override;
|
||||||
@@ -57,7 +40,6 @@ private:
|
|||||||
uint16_t _width;
|
uint16_t _width;
|
||||||
uint16_t _height;
|
uint16_t _height;
|
||||||
uint16_t _fps;
|
uint16_t _fps;
|
||||||
bool _keySent;
|
|
||||||
bool _phoneConnected;
|
bool _phoneConnected;
|
||||||
|
|
||||||
uint32_t _evtStatusId = (uint32_t)-1;
|
uint32_t _evtStatusId = (uint32_t)-1;
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,7 @@
|
|||||||
#include "helper/protocol_const.h"
|
#include "helper/protocol_const.h"
|
||||||
#include "helper/functions.h"
|
#include "helper/functions.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "struct/command.h"
|
||||||
|
|
||||||
|
|
||||||
Recorder::Recorder(uint16_t buffSize)
|
Recorder::Recorder(uint16_t buffSize)
|
||||||
@@ -20,7 +21,7 @@ Recorder::~Recorder()
|
|||||||
_thread.join();
|
_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Recorder::start(IAudioSender *sender)
|
void Recorder::start(ISender *sender)
|
||||||
{
|
{
|
||||||
if (_active)
|
if (_active)
|
||||||
return;
|
return;
|
||||||
@@ -78,7 +79,7 @@ void Recorder::runner()
|
|||||||
{
|
{
|
||||||
std::unique_ptr<AudioChunk> buffer = _data.pop();
|
std::unique_ptr<AudioChunk> buffer = _data.pop();
|
||||||
if (buffer && _sender)
|
if (buffer && _sender)
|
||||||
_sender->sendAudio(buffer.get()->data, buffer.get()->size);
|
_sender->send(Command::Audio(std::move(buffer)));
|
||||||
else if (_active)
|
else if (_active)
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
|
||||||
|
|||||||
+4
-24
@@ -6,44 +6,24 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include "helper/iaudio_sender.h"
|
#include "helper/isender.h"
|
||||||
|
#include "struct/audio_chunk.h"
|
||||||
#include "struct/atomic_queue.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
|
class Recorder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Recorder(uint16_t buffSize);
|
Recorder(uint16_t buffSize);
|
||||||
~Recorder();
|
~Recorder();
|
||||||
|
|
||||||
void start(IAudioSender *sender);
|
void start(ISender *sender);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void AudioCallback(void *userdata, Uint8 *stream, int len);
|
static void AudioCallback(void *userdata, Uint8 *stream, int len);
|
||||||
void runner();
|
void runner();
|
||||||
|
|
||||||
IAudioSender *_sender;
|
ISender *_sender;
|
||||||
std::atomic<bool> _active;
|
std::atomic<bool> _active;
|
||||||
std::thread _thread;
|
std::thread _thread;
|
||||||
AtomicQueue<AudioChunk> _data;
|
AtomicQueue<AudioChunk> _data;
|
||||||
|
|||||||
+3
-2
@@ -41,8 +41,9 @@ public:
|
|||||||
static inline Setting<bool> hwDecode{"hw-decode", true};
|
static inline Setting<bool> hwDecode{"hw-decode", true};
|
||||||
static inline Setting<int> forceRedraw{"force-redraw", 0};
|
static inline Setting<int> forceRedraw{"force-redraw", 0};
|
||||||
static inline Setting<float> aspectCorrection{"aspect-correction", 1};
|
static inline Setting<float> aspectCorrection{"aspect-correction", 1};
|
||||||
static inline Setting<bool> fastScale{"fast-render-scale", false};
|
static inline Setting<std::string> renderDriver{"renderer-driver", ""};
|
||||||
static inline Setting<bool> alternativeRendering{"alternative-rendering", false};
|
static inline Setting<bool> alternativeRendering{"alternative-rendering", false};
|
||||||
|
static inline Setting<bool> fastScale{"fast-render-scale", false};
|
||||||
static inline Setting<int> videoQueue{"video-buffer-size", 32};
|
static inline Setting<int> videoQueue{"video-buffer-size", 32};
|
||||||
static inline Setting<int> audioQueue{"audio-buffer-size", 16};
|
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};
|
||||||
@@ -50,7 +51,7 @@ public:
|
|||||||
static inline Setting<float> audioFade{"audio-fade", 0.3};
|
static inline Setting<float> audioFade{"audio-fade", 0.3};
|
||||||
static inline Setting<int> audioBuffer{"audio-buffer-samples", 2048};
|
static inline Setting<int> audioBuffer{"audio-buffer-samples", 2048};
|
||||||
static inline Setting<std::string> audioDriver{"audio-driver", ""};
|
static inline Setting<std::string> audioDriver{"audio-driver", ""};
|
||||||
static inline Setting<std::string> renderDriver{"renderer-driver", "auto"};
|
|
||||||
static inline Setting<std::string> onConnect{"on-connect-script", ""};
|
static inline Setting<std::string> onConnect{"on-connect-script", ""};
|
||||||
static inline Setting<std::string> onDisconnect{"on-disconnect-script", ""};
|
static inline Setting<std::string> onDisconnect{"on-disconnect-script", ""};
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,14 @@ public:
|
|||||||
return waitFlag.load();
|
return waitFlag.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool waitFor(atomic<bool> &waitFlag, uint32_t timeoutMs, uint8_t count = 0)
|
||||||
|
{
|
||||||
|
unique_lock<std::mutex> lock(_mtx);
|
||||||
|
_lock.wait_for(lock, std::chrono::milliseconds(timeoutMs), [&]
|
||||||
|
{ return _count > count || !waitFlag.load(); });
|
||||||
|
return waitFlag.load();
|
||||||
|
}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
_data = std::make_unique<std::unique_ptr<T>[]>(_size);
|
_data = std::make_unique<std::unique_ptr<T>[]>(_size);
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef SRC_STRUCT_AUDIO_CHUNK
|
||||||
|
#define SRC_STRUCT_AUDIO_CHUNK
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class AudioChunk
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AudioChunk(uint16_t size)
|
||||||
|
: data(nullptr), size(size)
|
||||||
|
{
|
||||||
|
if (size > 0)
|
||||||
|
data = static_cast<uint8_t *>(malloc(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
~AudioChunk()
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleted copy constructor/assignment
|
||||||
|
AudioChunk(const AudioChunk &) = delete;
|
||||||
|
AudioChunk &operator=(const AudioChunk &) = delete;
|
||||||
|
|
||||||
|
uint8_t *data;
|
||||||
|
uint16_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SRC_STRUCT_AUDIO_CHUNK */
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
#ifndef SRC_STRUCT_COMMAND
|
||||||
|
#define SRC_STRUCT_COMMAND
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "helper/functions.h"
|
||||||
|
#include "helper/protocol_const.h"
|
||||||
|
#include "struct/audio_chunk.h"
|
||||||
|
#include "struct/multitouch.h"
|
||||||
|
|
||||||
|
class Command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Command(const Command &) = delete;
|
||||||
|
Command &operator=(const Command &) = delete;
|
||||||
|
|
||||||
|
Command(int cmd, bool encrypt = true, uint32_t size = 0)
|
||||||
|
: command(cmd), encryption(encrypt), length(size), data(nullptr)
|
||||||
|
{
|
||||||
|
if (size > 0)
|
||||||
|
data = static_cast<uint8_t *>(malloc(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Command(int cmd, uint32_t value, bool encrypt = true)
|
||||||
|
: Command(cmd, encrypt, 4)
|
||||||
|
{
|
||||||
|
write_uint32_le(data, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command(int cmd, bool encrypt, uint8_t *buffer, uint32_t size)
|
||||||
|
: command(cmd), encryption(encrypt), length(size), data(buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Command()
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Init(int width, int height, int fps)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Command> result(new Command(CMD_OPEN, true, 28));
|
||||||
|
write_uint32_le(result->data + 0, width);
|
||||||
|
write_uint32_le(result->data + 4, height);
|
||||||
|
write_uint32_le(result->data + 8, fps);
|
||||||
|
write_uint32_le(result->data + 12, 5);
|
||||||
|
write_uint32_le(result->data + 16, 49152);
|
||||||
|
write_uint32_le(result->data + 20, 2);
|
||||||
|
write_uint32_le(result->data + 24, 2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> File(const char *filename, const uint8_t *data, uint32_t length)
|
||||||
|
{
|
||||||
|
// filename is assumed null‑terminated, so strlen + 1 to include the '\0'
|
||||||
|
uint32_t fn_len = strlen(filename) + 1;
|
||||||
|
|
||||||
|
// Total buffer size: 4 (fn_len) + fn_len + 4 (content_len) + content_len
|
||||||
|
std::unique_ptr<Command> result(new Command(CMD_SEND_FILE, true, 4 + fn_len + 4 + length));
|
||||||
|
uint8_t *buf = result->data;
|
||||||
|
|
||||||
|
// 1) filename length (LE)
|
||||||
|
write_uint32_le(buf, fn_len);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
// 2) filename bytes (including the '\0')
|
||||||
|
std::memcpy(buf, filename, fn_len);
|
||||||
|
buf += fn_len;
|
||||||
|
|
||||||
|
// 3) content length (LE)
|
||||||
|
write_uint32_le(buf, length);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
// 4) content bytes
|
||||||
|
if (length > 0 && data)
|
||||||
|
std::memcpy(buf, data, length);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> File(const char *filename, const char *value)
|
||||||
|
{
|
||||||
|
uint32_t len = std::strlen(value);
|
||||||
|
if (len > 16)
|
||||||
|
throw std::invalid_argument("String too long (max 16 bytes)");
|
||||||
|
// note: we send only the ASCII bytes, no trailing '\0'
|
||||||
|
return File(filename, reinterpret_cast<const uint8_t *>(value), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overload for a single 32‑bit integer
|
||||||
|
static std::unique_ptr<Command> File(const char *filename, int value)
|
||||||
|
{
|
||||||
|
uint8_t buffer[4];
|
||||||
|
write_uint32_le(buffer, value);
|
||||||
|
return File(filename, buffer, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Control(uint32_t value, bool encrypt = false)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<Command>(new Command(CMD_CONTROL, value, encrypt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Encryption(uint32_t seed)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<Command>(new Command(CMD_ENCRYPTION, seed, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> String(uint32_t cmd, const char *str, bool encrypt = true)
|
||||||
|
{
|
||||||
|
uint32_t length = std::strlen(str);
|
||||||
|
std::unique_ptr<Command> result(new Command(cmd, encrypt, length));
|
||||||
|
if (length > 0)
|
||||||
|
std::memcpy(result->data, str, length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static std::unique_ptr<Command> String(uint32_t cmd, const char *format, Args... args)
|
||||||
|
{
|
||||||
|
char buffer[512];
|
||||||
|
std::snprintf(buffer, sizeof(buffer), format, args...);
|
||||||
|
return String(cmd, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Touch(uint32_t action, float x, float y)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Command> result(new Command(CMD_TOUCH, false, 16));
|
||||||
|
write_uint32_le(result->data, action);
|
||||||
|
write_uint32_le(result->data + 4, int(10000 * x));
|
||||||
|
write_uint32_le(result->data + 8, int(10000 * y));
|
||||||
|
write_uint32_le(result->data + 12, 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Click(float x, float y, bool down)
|
||||||
|
{
|
||||||
|
return Touch(down ? 14 : 16, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Move(float x, float y)
|
||||||
|
{
|
||||||
|
return Touch(15, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> Audio(std::unique_ptr<AudioChunk> chunk)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Command> result(new Command(CMD_AUDIO_DATA, false, chunk->data, chunk->size));
|
||||||
|
chunk->data = nullptr;
|
||||||
|
write_uint32_le(result->data, 5);
|
||||||
|
write_uint32_le(result->data + 4, 0);
|
||||||
|
write_uint32_le(result->data + 8, 3);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Command> MultiTouch(const Multitouch &touches)
|
||||||
|
{
|
||||||
|
int count = touches.size();
|
||||||
|
if (count == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<Command> result(new Command(CMD_MULTI_TOUCH, false, sizeof(Multitouch::Touch) * count));
|
||||||
|
uint8_t *buf = result->data;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const Multitouch::Touch &t = touches[i];
|
||||||
|
write_float_le(buf + 0, t.x);
|
||||||
|
write_float_le(buf + 4, t.y);
|
||||||
|
write_uint32_le(buf + 8, static_cast<uint32_t>(t.state));
|
||||||
|
write_uint32_le(buf + 12, static_cast<uint32_t>(t.id));
|
||||||
|
buf += 16;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command;
|
||||||
|
bool encryption;
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SRC_STRUCT_COMMAND */
|
||||||
Reference in New Issue
Block a user