From b44f78f19b925952bc28141dbbbedea44da896dd Mon Sep 17 00:00:00 2001 From: Barry <870709864@qq.com> Date: Tue, 18 Jun 2019 20:25:38 +0800 Subject: [PATCH] =?UTF-8?q?update:=E8=A7=86=E9=A2=91=E4=BC=A0=E8=BE=93?= =?UTF-8?q?=E5=92=8C=E6=8E=A7=E5=88=B6=E6=8C=87=E4=BB=A4=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E4=B8=8D=E5=90=8C=E7=9A=84socket=20videosock?= =?UTF-8?q?et=E8=B4=9F=E8=B4=A3=E8=A7=86=E9=A2=91=E6=8E=A5=E6=94=B6=20cont?= =?UTF-8?q?rolsocket=E8=B4=9F=E8=B4=A3=E6=8C=87=E4=BB=A4=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/common/qscrcpyevent.h | 8 +- QtScrcpy/inputcontrol/controller.cpp | 10 +- QtScrcpy/inputcontrol/controller.h | 6 +- QtScrcpy/inputcontrol/inputconvertbase.cpp | 4 +- QtScrcpy/inputcontrol/inputconvertbase.h | 2 +- QtScrcpy/server/server.cpp | 101 +++++++++++------- QtScrcpy/server/server.h | 13 ++- QtScrcpy/server/server.pri | 8 +- QtScrcpy/server/tcpserver.cpp | 17 ++- QtScrcpy/server/tcpserver.h | 3 + .../{devicesocket.cpp => videosocket.cpp} | 24 ++--- .../server/{devicesocket.h => videosocket.h} | 12 +-- QtScrcpy/stream/stream.cpp | 12 +-- QtScrcpy/stream/stream.h | 6 +- QtScrcpy/videoform.cpp | 4 +- .../genymobile/scrcpy/DesktopConnection.java | 74 ++++++++----- .../java/com/genymobile/scrcpy/Server.java | 2 +- third_party/scrcpy-server.jar | Bin 49588 -> 72408 bytes 18 files changed, 181 insertions(+), 125 deletions(-) rename QtScrcpy/server/{devicesocket.cpp => videosocket.cpp} (66%) rename QtScrcpy/server/{devicesocket.h => videosocket.h} (71%) diff --git a/QtScrcpy/common/qscrcpyevent.h b/QtScrcpy/common/qscrcpyevent.h index 3f31da2..7365fb6 100644 --- a/QtScrcpy/common/qscrcpyevent.h +++ b/QtScrcpy/common/qscrcpyevent.h @@ -6,16 +6,16 @@ class QScrcpyEvent : public QEvent { public: enum Type { - DeviceSocket = QEvent::User + 1, + VideoSocket = QEvent::User + 1, Control, }; QScrcpyEvent(Type type) : QEvent(QEvent::Type(type)){} }; -// DeviceSocketEvent -class DeviceSocketEvent : public QScrcpyEvent +// VideoSocketEvent +class VideoSocketEvent : public QScrcpyEvent { public: - DeviceSocketEvent() : QScrcpyEvent(DeviceSocket){} + VideoSocketEvent() : QScrcpyEvent(VideoSocket){} }; #endif // QSCRCPYEVENT_H diff --git a/QtScrcpy/inputcontrol/controller.cpp b/QtScrcpy/inputcontrol/controller.cpp index 5af9c96..53f030a 100644 --- a/QtScrcpy/inputcontrol/controller.cpp +++ b/QtScrcpy/inputcontrol/controller.cpp @@ -1,7 +1,7 @@ #include #include "controller.h" -#include "devicesocket.h" +#include "videosocket.h" #include "controlevent.h" Controller::Controller(QObject* parent) : QObject(parent) @@ -14,9 +14,9 @@ Controller::~Controller() } -void Controller::setDeviceSocket(DeviceSocket *deviceSocket) +void Controller::setControlSocket(QTcpSocket* controlSocket) { - m_deviceSocket = deviceSocket; + m_controlSocket = controlSocket; } void Controller::postControlEvent(ControlEvent *controlEvent) @@ -51,8 +51,8 @@ bool Controller::sendControl(const QByteArray &buffer) return false; } qint32 len = 0; - if (m_deviceSocket) { - len = m_deviceSocket->write(buffer.data(), buffer.length()); + if (m_controlSocket) { + len = m_controlSocket->write(buffer.data(), buffer.length()); } return len == buffer.length() ? true : false; } diff --git a/QtScrcpy/inputcontrol/controller.h b/QtScrcpy/inputcontrol/controller.h index 43ac5cc..2fb4c2f 100644 --- a/QtScrcpy/inputcontrol/controller.h +++ b/QtScrcpy/inputcontrol/controller.h @@ -4,7 +4,7 @@ #include #include -class DeviceSocket; +class QTcpSocket; class ControlEvent; class Controller : public QObject { @@ -13,7 +13,7 @@ public: Controller(QObject* parent = Q_NULLPTR); virtual ~Controller(); - void setDeviceSocket(DeviceSocket* deviceSocket); + void setControlSocket(QTcpSocket* controlSocket); void postControlEvent(ControlEvent* controlEvent); void test(QRect rc); @@ -24,7 +24,7 @@ private: bool sendControl(const QByteArray& buffer); private: - QPointer m_deviceSocket; + QPointer m_controlSocket; }; #endif // CONTROLLER_H diff --git a/QtScrcpy/inputcontrol/inputconvertbase.cpp b/QtScrcpy/inputcontrol/inputconvertbase.cpp index e0a49e3..44bda0b 100644 --- a/QtScrcpy/inputcontrol/inputconvertbase.cpp +++ b/QtScrcpy/inputcontrol/inputconvertbase.cpp @@ -10,9 +10,9 @@ InputConvertBase::~InputConvertBase() } -void InputConvertBase::setDeviceSocket(DeviceSocket *deviceSocket) +void InputConvertBase::setControlSocket(QTcpSocket *controlSocket) { - m_controller.setDeviceSocket(deviceSocket); + m_controller.setControlSocket(controlSocket); } void InputConvertBase::sendControlEvent(ControlEvent *event) diff --git a/QtScrcpy/inputcontrol/inputconvertbase.h b/QtScrcpy/inputcontrol/inputconvertbase.h index b2bf654..123c6ec 100644 --- a/QtScrcpy/inputcontrol/inputconvertbase.h +++ b/QtScrcpy/inputcontrol/inputconvertbase.h @@ -20,7 +20,7 @@ public: virtual void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize) = 0; virtual void keyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize) = 0; - void setDeviceSocket(DeviceSocket* deviceSocket); + void setControlSocket(QTcpSocket* controlSocket); void sendControlEvent(ControlEvent* event); private: diff --git a/QtScrcpy/server/server.cpp b/QtScrcpy/server/server.cpp index 1336beb..f042ba1 100644 --- a/QtScrcpy/server/server.cpp +++ b/QtScrcpy/server/server.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -17,25 +16,30 @@ Server::Server(QObject *parent) : QObject(parent) connect(&m_workProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult); connect(&m_serverProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult); - connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){ - m_deviceSocket = dynamic_cast(m_serverSocket.nextPendingConnection()); - - QString deviceName; - QSize deviceSize; - - if (m_deviceSocket->isValid() && readInfo(deviceName, deviceSize)) { - // we don't need the server socket anymore - // just m_deviceSocket is ok - m_serverSocket.close(); - // we don't need the adb tunnel anymore - disableTunnelReverse(); - m_tunnelEnabled = false; - emit connectToResult(true, deviceName, deviceSize); + connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){ + QTcpSocket* tmp = m_serverSocket.nextPendingConnection(); + if (dynamic_cast(tmp)) { + m_videoSocket = dynamic_cast(tmp); + if (!m_videoSocket->isValid() || !readInfo(m_deviceName, m_deviceSize)) { + stop(); + emit connectToResult(false); + } } else { - stop(); - emit connectToResult(false, deviceName, deviceSize); + m_controlSocket = tmp; + if (m_controlSocket && m_controlSocket->isValid()) { + // we don't need the server socket anymore + // just m_videoSocket is ok + m_serverSocket.close(); + // we don't need the adb tunnel anymore + disableTunnelReverse(); + m_tunnelEnabled = false; + emit connectToResult(true, m_deviceName, m_deviceSize); + } else { + stop(); + emit connectToResult(false); + } + stopAcceptTimeoutTimer(); } - stopAcceptTimeoutTimer(); }); } @@ -159,7 +163,7 @@ bool Server::connectTo() return false; } - if (!m_tunnelForward && !m_deviceSocket) { + if (!m_tunnelForward && !m_videoSocket) { startAcceptTimeoutTimer(); return true; } @@ -167,39 +171,49 @@ bool Server::connectTo() // device server need time to start // TODO:电脑配置太低的话,这里有可能时间不够导致连接太早,安卓监听socket还没有建立 // 后续研究其他办法 + // wait for devices server start QTimer::singleShot(1000, this, [this](){ QString deviceName; QSize deviceSize; bool success = false; - m_deviceSocket = new DeviceSocket(); - - // wait for devices server start - m_deviceSocket->connectToHost(QHostAddress::LocalHost, m_localPort); - if (!m_deviceSocket->waitForConnected(1000)) { + // video socket + m_videoSocket = new VideoSocket(); + m_videoSocket->connectToHost(QHostAddress::LocalHost, m_localPort); + if (!m_videoSocket->waitForConnected(1000)) { stop(); - qWarning("connect to server failed"); + qWarning("video socket connect to server failed"); emit connectToResult(false, "", QSize()); return false; } - if (QTcpSocket::ConnectedState == m_deviceSocket->state()) { + if (QTcpSocket::ConnectedState == m_videoSocket->state()) { // connect will success even if devices offline, recv data is real connect success // because connect is to pc adb server - m_deviceSocket->waitForReadyRead(1000); + m_videoSocket->waitForReadyRead(1000); // devices will send 1 byte first on tunnel forward mode - QByteArray data = m_deviceSocket->read(1); + QByteArray data = m_videoSocket->read(1); if (!data.isEmpty() && readInfo(deviceName, deviceSize)) { success = true; } else { - qWarning("connect to server read device info failed"); + qWarning("video socket connect to server read device info failed"); success = false; } } else { qWarning("connect to server failed"); - m_deviceSocket->deleteLater(); + m_videoSocket->deleteLater(); success = false; } + // control socket + m_controlSocket = new QTcpSocket(); + m_controlSocket->connectToHost(QHostAddress::LocalHost, m_localPort); + if (!m_controlSocket->waitForConnected(1000)) { + stop(); + qWarning("control socket connect to server failed"); + emit connectToResult(false, "", QSize()); + return false; + } + if (success) { // we don't need the adb tunnel anymore disableTunnelForward(); @@ -221,16 +235,25 @@ void Server::timerEvent(QTimerEvent *event) } } -DeviceSocket* Server::getDeviceSocket() +VideoSocket* Server::getVideoSocket() { - return m_deviceSocket; + return m_videoSocket; +} + +QTcpSocket *Server::getControlSocket() +{ + return m_controlSocket; } void Server::stop() { - if (m_deviceSocket) { - m_deviceSocket->close(); - m_deviceSocket->deleteLater(); + if (m_videoSocket) { + m_videoSocket->close(); + m_videoSocket->deleteLater(); + } + if (m_controlSocket) { + m_controlSocket->close(); + m_controlSocket->deleteLater(); } // ignore failure m_serverProcess.kill(); @@ -270,7 +293,7 @@ bool Server::startServerByStep() // client listens and the server connects to the client. That way, the // client can listen before starting the server app, so there is no need to // try to connect until the server socket is listening on the device. - m_serverSocket.setMaxPendingConnections(1); + m_serverSocket.setMaxPendingConnections(2); if (!m_serverSocket.listen(QHostAddress::LocalHost, m_localPort)) { qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str()); m_serverStartStep = SSS_NULL; @@ -300,11 +323,11 @@ bool Server::startServerByStep() bool Server::readInfo(QString &deviceName, QSize &size) { unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4]; - if (m_deviceSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) { - m_deviceSocket->waitForReadyRead(300); + if (m_videoSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) { + m_videoSocket->waitForReadyRead(300); } - qint64 len = m_deviceSocket->read((char*)buf, sizeof(buf)); + qint64 len = m_videoSocket->read((char*)buf, sizeof(buf)); if (len < DEVICE_NAME_FIELD_LENGTH + 4) { qInfo("Could not retrieve device information"); return false; diff --git a/QtScrcpy/server/server.h b/QtScrcpy/server/server.h index 8a9f4be..bccad71 100644 --- a/QtScrcpy/server/server.h +++ b/QtScrcpy/server/server.h @@ -3,9 +3,10 @@ #include #include +#include #include "tcpserver.h" -#include "devicesocket.h" +#include "videosocket.h" #include "adbprocess.h" class Server : public QObject @@ -27,13 +28,14 @@ public: bool start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta = false); bool connectTo(); - DeviceSocket* getDeviceSocket(); + VideoSocket* getVideoSocket(); + QTcpSocket* getControlSocket(); void stop(); signals: void serverStartResult(bool success); - void connectToResult(bool success, const QString &deviceName, const QSize &size); + void connectToResult(bool success, const QString &deviceName = "", const QSize &size = QSize()); void onServerStop(); private slots: @@ -62,7 +64,8 @@ private: QString m_serial = ""; AdbProcess m_serverProcess; TcpServer m_serverSocket; // only used if !tunnel_forward - QPointer m_deviceSocket = Q_NULLPTR; + QPointer m_videoSocket = Q_NULLPTR; + QPointer m_controlSocket = Q_NULLPTR; quint16 m_localPort = 0; bool m_tunnelEnabled = false; bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse" @@ -71,6 +74,8 @@ private: quint32 m_bitRate = 0; QString m_crop = ""; quint32 m_acceptTimeoutTimer = 0; + QString m_deviceName = ""; + QSize m_deviceSize = QSize(); SERVER_START_STEP m_serverStartStep = SSS_NULL; }; diff --git a/QtScrcpy/server/server.pri b/QtScrcpy/server/server.pri index 428d8e4..d890771 100644 --- a/QtScrcpy/server/server.pri +++ b/QtScrcpy/server/server.pri @@ -1,9 +1,9 @@ HEADERS += \ - $$PWD/devicesocket.h \ $$PWD/server.h \ - $$PWD/tcpserver.h + $$PWD/tcpserver.h \ + $$PWD/videosocket.h SOURCES += \ - $$PWD/devicesocket.cpp \ $$PWD/server.cpp \ - $$PWD/tcpserver.cpp + $$PWD/tcpserver.cpp \ + $$PWD/videosocket.cpp diff --git a/QtScrcpy/server/tcpserver.cpp b/QtScrcpy/server/tcpserver.cpp index bddb56d..c341a6b 100644 --- a/QtScrcpy/server/tcpserver.cpp +++ b/QtScrcpy/server/tcpserver.cpp @@ -1,5 +1,5 @@ #include "tcpserver.h" -#include "devicesocket.h" +#include "videosocket.h" TcpServer::TcpServer(QObject *parent) : QTcpServer(parent) { @@ -13,7 +13,16 @@ TcpServer::~TcpServer() void TcpServer::incomingConnection(qintptr handle) { - DeviceSocket *socket = new DeviceSocket(); - socket->setSocketDescriptor(handle); - addPendingConnection(socket); + if (m_isVideoSocket) { + VideoSocket *socket = new VideoSocket(); + socket->setSocketDescriptor(handle); + addPendingConnection(socket); + + // next is control socket + m_isVideoSocket = false; + } else { + QTcpSocket *socket = new QTcpSocket(); + socket->setSocketDescriptor(handle); + addPendingConnection(socket); + } } diff --git a/QtScrcpy/server/tcpserver.h b/QtScrcpy/server/tcpserver.h index d8e52be..96b4e34 100644 --- a/QtScrcpy/server/tcpserver.h +++ b/QtScrcpy/server/tcpserver.h @@ -12,6 +12,9 @@ public: protected: virtual void incomingConnection(qintptr handle); + +private: + bool m_isVideoSocket = true; }; #endif // TCPSERVER_H diff --git a/QtScrcpy/server/devicesocket.cpp b/QtScrcpy/server/videosocket.cpp similarity index 66% rename from QtScrcpy/server/devicesocket.cpp rename to QtScrcpy/server/videosocket.cpp index cac5bd4..46798f0 100644 --- a/QtScrcpy/server/devicesocket.cpp +++ b/QtScrcpy/server/videosocket.cpp @@ -3,21 +3,21 @@ #include #include "qscrcpyevent.h" -#include "devicesocket.h" +#include "videosocket.h" -DeviceSocket::DeviceSocket(QObject *parent) : QTcpSocket(parent) +VideoSocket::VideoSocket(QObject *parent) : QTcpSocket(parent) { - connect(this, &DeviceSocket::readyRead, this, &DeviceSocket::onReadyRead); - connect(this, &DeviceSocket::aboutToClose, this, &DeviceSocket::quitNotify); - connect(this, &DeviceSocket::disconnected, this, &DeviceSocket::quitNotify); + connect(this, &VideoSocket::readyRead, this, &VideoSocket::onReadyRead); + connect(this, &VideoSocket::aboutToClose, this, &VideoSocket::quitNotify); + connect(this, &VideoSocket::disconnected, this, &VideoSocket::quitNotify); } -DeviceSocket::~DeviceSocket() +VideoSocket::~VideoSocket() { quitNotify(); } -qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize) +qint32 VideoSocket::subThreadRecvData(quint8 *buf, qint32 bufSize) { // this function cant call in main thread Q_ASSERT(QCoreApplication::instance()->thread() != QThread::currentThread()); @@ -31,7 +31,7 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize) m_dataSize = 0; // post event - DeviceSocketEvent* getDataEvent = new DeviceSocketEvent(); + VideoSocketEvent* getDataEvent = new VideoSocketEvent(); QCoreApplication::postEvent(this, getDataEvent); // wait @@ -43,16 +43,16 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize) return m_dataSize; } -bool DeviceSocket::event(QEvent *event) +bool VideoSocket::event(QEvent *event) { - if (event->type() == QScrcpyEvent::DeviceSocket) { + if (event->type() == QScrcpyEvent::VideoSocket) { onReadyRead(); return true; } return QTcpSocket::event(event); } -void DeviceSocket::onReadyRead() +void VideoSocket::onReadyRead() { QMutexLocker locker(&m_mutex); if (m_buffer && 0 < bytesAvailable()) { @@ -67,7 +67,7 @@ void DeviceSocket::onReadyRead() } } -void DeviceSocket::quitNotify() +void VideoSocket::quitNotify() { m_quit = true; QMutexLocker locker(&m_mutex); diff --git a/QtScrcpy/server/devicesocket.h b/QtScrcpy/server/videosocket.h similarity index 71% rename from QtScrcpy/server/devicesocket.h rename to QtScrcpy/server/videosocket.h index b7a303c..ef6e6d2 100644 --- a/QtScrcpy/server/devicesocket.h +++ b/QtScrcpy/server/videosocket.h @@ -1,17 +1,17 @@ -#ifndef DEVICESOCKET_H -#define DEVICESOCKET_H +#ifndef VIDEOSOCKET_H +#define VIDEOSOCKET_H #include #include #include #include -class DeviceSocket : public QTcpSocket +class VideoSocket : public QTcpSocket { Q_OBJECT public: - explicit DeviceSocket(QObject *parent = nullptr); - virtual ~DeviceSocket(); + explicit VideoSocket(QObject *parent = nullptr); + virtual ~VideoSocket(); qint32 subThreadRecvData(quint8* buf, qint32 bufSize); @@ -32,4 +32,4 @@ private: bool m_quit = false; }; -#endif // DEVICESOCKET_H +#endif // VIDEOSOCKET_H diff --git a/QtScrcpy/stream/stream.cpp b/QtScrcpy/stream/stream.cpp index 21f93af..46110c3 100644 --- a/QtScrcpy/stream/stream.cpp +++ b/QtScrcpy/stream/stream.cpp @@ -4,7 +4,7 @@ #include "compat.h" #include "stream.h" #include "decoder.h" -#include "devicesocket.h" +#include "videosocket.h" #include "recorder.h" #define BUFSIZE 0x10000 @@ -199,9 +199,9 @@ static qint32 readRawPacket(void *opaque, quint8 *buf, qint32 bufSize) { return AVERROR_EOF; } -void Stream::setDeviceSocket(DeviceSocket* deviceSocket) +void Stream::setVideoSocket(VideoSocket* videoSocket) { - m_deviceSocket = deviceSocket; + m_videoSocket = videoSocket; } void Stream::setRecoder(Recorder *recorder) @@ -214,8 +214,8 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize) if (!buf) { return 0; } - if (m_deviceSocket) { - qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize); + if (m_videoSocket) { + qint32 len = m_videoSocket->subThreadRecvData(buf, bufSize); return len; } return 0; @@ -223,7 +223,7 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize) bool Stream::startDecode() { - if (!m_deviceSocket) { + if (!m_videoSocket) { return false; } m_quit.store(0); diff --git a/QtScrcpy/stream/stream.h b/QtScrcpy/stream/stream.h index 1f0b043..f10d3f8 100644 --- a/QtScrcpy/stream/stream.h +++ b/QtScrcpy/stream/stream.h @@ -12,7 +12,7 @@ extern "C" #include "libavformat/avformat.h" } -class DeviceSocket; +class VideoSocket; class Recorder; class Decoder; class Stream : public QThread @@ -38,7 +38,7 @@ public: static void deInit(); void setDecoder(Decoder* vb); - void setDeviceSocket(DeviceSocket* deviceSocket); + void setVideoSocket(VideoSocket* deviceSocket); void setRecoder(Recorder* recorder); qint32 recvData(quint8* buf, qint32 bufSize); bool startDecode(); @@ -52,7 +52,7 @@ protected: void run(); private: - QPointer m_deviceSocket; + QPointer m_videoSocket; QAtomicInteger m_quit; // for recorder diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index f3278ee..d8c2364 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -171,11 +171,11 @@ void VideoForm::initSignals() } // init decoder - m_stream.setDeviceSocket(m_server->getDeviceSocket()); + m_stream.setVideoSocket(m_server->getVideoSocket()); m_stream.startDecode(); // init controller - m_inputConvert.setDeviceSocket(m_server->getDeviceSocket()); + m_inputConvert.setControlSocket(m_server->getControlSocket()); } }); diff --git a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java index f8c3ba6..e7237fa 100644 --- a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java +++ b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java @@ -16,16 +16,20 @@ public final class DesktopConnection implements Closeable { private static final String SOCKET_NAME = "qtscrcpy"; - private final LocalSocket socket; - private final InputStream inputStream; - private final FileDescriptor fd; + private final LocalSocket videoSocket; + private final FileDescriptor videoFd; + + private final LocalSocket controlSocket; + private final InputStream controlInputStream; + private final ControlEventReader reader = new ControlEventReader(); - private DesktopConnection(LocalSocket socket) throws IOException { - this.socket = socket; - inputStream = socket.getInputStream(); - fd = socket.getFileDescriptor(); + private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException { + this.videoSocket = videoSocket; + this.controlSocket = controlSocket; + controlInputStream = controlSocket.getInputStream(); + videoFd = videoSocket.getFileDescriptor(); } private static LocalSocket connect(String abstractName) throws IOException { @@ -34,35 +38,47 @@ public final class DesktopConnection implements Closeable { return localSocket; } - private static LocalSocket listenAndAccept(String abstractName) throws IOException { - LocalServerSocket localServerSocket = new LocalServerSocket(abstractName); - try { - return localServerSocket.accept(); - } finally { - localServerSocket.close(); - } - } - public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException { - LocalSocket socket; + LocalSocket videoSocket; + LocalSocket controlSocket; if (tunnelForward) { - socket = listenAndAccept(SOCKET_NAME); - // send one byte so the client may read() to detect a connection error - socket.getOutputStream().write(0); + LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME); + try { + videoSocket = localServerSocket.accept(); + // send one byte so the client may read() to detect a connection error + videoSocket.getOutputStream().write(0); + try { + controlSocket = localServerSocket.accept(); + } catch (IOException | RuntimeException e) { + videoSocket.close(); + throw e; + } + } finally { + localServerSocket.close(); + } } else { - socket = connect(SOCKET_NAME); + videoSocket = connect(SOCKET_NAME); + try { + controlSocket = connect(SOCKET_NAME); + } catch (IOException | RuntimeException e) { + videoSocket.close(); + throw e; + } } - DesktopConnection connection = new DesktopConnection(socket); + DesktopConnection connection = new DesktopConnection(videoSocket, controlSocket); Size videoSize = device.getScreenInfo().getVideoSize(); connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight()); return connection; } public void close() throws IOException { - socket.shutdownInput(); - socket.shutdownOutput(); - socket.close(); + videoSocket.shutdownInput(); + videoSocket.shutdownOutput(); + videoSocket.close(); + controlSocket.shutdownInput(); + controlSocket.shutdownOutput(); + controlSocket.close(); } @SuppressWarnings("checkstyle:MagicNumber") @@ -78,17 +94,17 @@ public final class DesktopConnection implements Closeable { buffer[DEVICE_NAME_FIELD_LENGTH + 1] = (byte) width; buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8); buffer[DEVICE_NAME_FIELD_LENGTH + 3] = (byte) height; - IO.writeFully(fd, buffer, 0, buffer.length); + IO.writeFully(videoFd, buffer, 0, buffer.length); } - public FileDescriptor getFd() { - return fd; + public FileDescriptor getVideoFd() { + return videoFd; } public ControlEvent receiveControlEvent() throws IOException { ControlEvent event = reader.next(); while (event == null) { - reader.readFrom(inputStream); + reader.readFrom(controlInputStream); event = reader.next(); } return event; diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 9f4556d..479e6b6 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -25,7 +25,7 @@ public final class Server { try { // synchronous - screenEncoder.streamScreen(device, connection.getFd()); + screenEncoder.streamScreen(device, connection.getVideoFd()); } catch (IOException e) { // this is expected on close Ln.d("Screen streaming stopped"); diff --git a/third_party/scrcpy-server.jar b/third_party/scrcpy-server.jar index b9c9afdcd9ae91d5c025869e94bd4701be7a7805..4637040d3dc39973767c20324a51ea9a8d185dd1 100644 GIT binary patch delta 24074 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