update:视频传输和控制指令改为两个不同的socket videosocket负责视频接收 controlsocket负责指令发送

This commit is contained in:
Barry 2019-06-18 20:25:38 +08:00
parent 7220d91ed3
commit b44f78f19b
18 changed files with 181 additions and 125 deletions

View file

@ -6,16 +6,16 @@ class QScrcpyEvent : public QEvent
{ {
public: public:
enum Type { enum Type {
DeviceSocket = QEvent::User + 1, VideoSocket = QEvent::User + 1,
Control, Control,
}; };
QScrcpyEvent(Type type) : QEvent(QEvent::Type(type)){} QScrcpyEvent(Type type) : QEvent(QEvent::Type(type)){}
}; };
// DeviceSocketEvent // VideoSocketEvent
class DeviceSocketEvent : public QScrcpyEvent class VideoSocketEvent : public QScrcpyEvent
{ {
public: public:
DeviceSocketEvent() : QScrcpyEvent(DeviceSocket){} VideoSocketEvent() : QScrcpyEvent(VideoSocket){}
}; };
#endif // QSCRCPYEVENT_H #endif // QSCRCPYEVENT_H

View file

@ -1,7 +1,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "controller.h" #include "controller.h"
#include "devicesocket.h" #include "videosocket.h"
#include "controlevent.h" #include "controlevent.h"
Controller::Controller(QObject* parent) : QObject(parent) 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) void Controller::postControlEvent(ControlEvent *controlEvent)
@ -51,8 +51,8 @@ bool Controller::sendControl(const QByteArray &buffer)
return false; return false;
} }
qint32 len = 0; qint32 len = 0;
if (m_deviceSocket) { if (m_controlSocket) {
len = m_deviceSocket->write(buffer.data(), buffer.length()); len = m_controlSocket->write(buffer.data(), buffer.length());
} }
return len == buffer.length() ? true : false; return len == buffer.length() ? true : false;
} }

View file

@ -4,7 +4,7 @@
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
class DeviceSocket; class QTcpSocket;
class ControlEvent; class ControlEvent;
class Controller : public QObject class Controller : public QObject
{ {
@ -13,7 +13,7 @@ public:
Controller(QObject* parent = Q_NULLPTR); Controller(QObject* parent = Q_NULLPTR);
virtual ~Controller(); virtual ~Controller();
void setDeviceSocket(DeviceSocket* deviceSocket); void setControlSocket(QTcpSocket* controlSocket);
void postControlEvent(ControlEvent* controlEvent); void postControlEvent(ControlEvent* controlEvent);
void test(QRect rc); void test(QRect rc);
@ -24,7 +24,7 @@ private:
bool sendControl(const QByteArray& buffer); bool sendControl(const QByteArray& buffer);
private: private:
QPointer<DeviceSocket> m_deviceSocket; QPointer<QTcpSocket> m_controlSocket;
}; };
#endif // CONTROLLER_H #endif // CONTROLLER_H

View file

@ -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) void InputConvertBase::sendControlEvent(ControlEvent *event)

View file

@ -20,7 +20,7 @@ public:
virtual void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize) = 0; 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; 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); void sendControlEvent(ControlEvent* event);
private: private:

View file

@ -1,7 +1,6 @@
#include <QDebug> #include <QDebug>
#include <QTimer> #include <QTimer>
#include <QThread> #include <QThread>
#include <QSize>
#include <QTimerEvent> #include <QTimerEvent>
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
@ -18,24 +17,29 @@ Server::Server(QObject *parent) : QObject(parent)
connect(&m_serverProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult); connect(&m_serverProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult);
connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){ connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){
m_deviceSocket = dynamic_cast<DeviceSocket*>(m_serverSocket.nextPendingConnection()); QTcpSocket* tmp = m_serverSocket.nextPendingConnection();
if (dynamic_cast<VideoSocket*>(tmp)) {
QString deviceName; m_videoSocket = dynamic_cast<VideoSocket*>(tmp);
QSize deviceSize; if (!m_videoSocket->isValid() || !readInfo(m_deviceName, m_deviceSize)) {
stop();
if (m_deviceSocket->isValid() && readInfo(deviceName, deviceSize)) { emit connectToResult(false);
// 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);
} else { } else {
stop(); m_controlSocket = tmp;
emit connectToResult(false, deviceName, deviceSize); 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; return false;
} }
if (!m_tunnelForward && !m_deviceSocket) { if (!m_tunnelForward && !m_videoSocket) {
startAcceptTimeoutTimer(); startAcceptTimeoutTimer();
return true; return true;
} }
@ -167,39 +171,49 @@ bool Server::connectTo()
// device server need time to start // device server need time to start
// TODO:电脑配置太低的话这里有可能时间不够导致连接太早安卓监听socket还没有建立 // TODO:电脑配置太低的话这里有可能时间不够导致连接太早安卓监听socket还没有建立
// 后续研究其他办法 // 后续研究其他办法
// wait for devices server start
QTimer::singleShot(1000, this, [this](){ QTimer::singleShot(1000, this, [this](){
QString deviceName; QString deviceName;
QSize deviceSize; QSize deviceSize;
bool success = false; bool success = false;
m_deviceSocket = new DeviceSocket(); // video socket
m_videoSocket = new VideoSocket();
// wait for devices server start m_videoSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
m_deviceSocket->connectToHost(QHostAddress::LocalHost, m_localPort); if (!m_videoSocket->waitForConnected(1000)) {
if (!m_deviceSocket->waitForConnected(1000)) {
stop(); stop();
qWarning("connect to server failed"); qWarning("video socket connect to server failed");
emit connectToResult(false, "", QSize()); emit connectToResult(false, "", QSize());
return false; 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 // connect will success even if devices offline, recv data is real connect success
// because connect is to pc adb server // 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 // 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)) { if (!data.isEmpty() && readInfo(deviceName, deviceSize)) {
success = true; success = true;
} else { } else {
qWarning("connect to server read device info failed"); qWarning("video socket connect to server read device info failed");
success = false; success = false;
} }
} else { } else {
qWarning("connect to server failed"); qWarning("connect to server failed");
m_deviceSocket->deleteLater(); m_videoSocket->deleteLater();
success = false; 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) { if (success) {
// we don't need the adb tunnel anymore // we don't need the adb tunnel anymore
disableTunnelForward(); 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() void Server::stop()
{ {
if (m_deviceSocket) { if (m_videoSocket) {
m_deviceSocket->close(); m_videoSocket->close();
m_deviceSocket->deleteLater(); m_videoSocket->deleteLater();
}
if (m_controlSocket) {
m_controlSocket->close();
m_controlSocket->deleteLater();
} }
// ignore failure // ignore failure
m_serverProcess.kill(); m_serverProcess.kill();
@ -270,7 +293,7 @@ bool Server::startServerByStep()
// client listens and the server connects to the client. That way, the // 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 // 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. // 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)) { if (!m_serverSocket.listen(QHostAddress::LocalHost, m_localPort)) {
qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str()); qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str());
m_serverStartStep = SSS_NULL; m_serverStartStep = SSS_NULL;
@ -300,11 +323,11 @@ bool Server::startServerByStep()
bool Server::readInfo(QString &deviceName, QSize &size) bool Server::readInfo(QString &deviceName, QSize &size)
{ {
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4]; unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
if (m_deviceSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) { if (m_videoSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) {
m_deviceSocket->waitForReadyRead(300); 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) { if (len < DEVICE_NAME_FIELD_LENGTH + 4) {
qInfo("Could not retrieve device information"); qInfo("Could not retrieve device information");
return false; return false;

View file

@ -3,9 +3,10 @@
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QSize>
#include "tcpserver.h" #include "tcpserver.h"
#include "devicesocket.h" #include "videosocket.h"
#include "adbprocess.h" #include "adbprocess.h"
class Server : public QObject 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 start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta = false);
bool connectTo(); bool connectTo();
DeviceSocket* getDeviceSocket(); VideoSocket* getVideoSocket();
QTcpSocket* getControlSocket();
void stop(); void stop();
signals: signals:
void serverStartResult(bool success); 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(); void onServerStop();
private slots: private slots:
@ -62,7 +64,8 @@ private:
QString m_serial = ""; QString m_serial = "";
AdbProcess m_serverProcess; AdbProcess m_serverProcess;
TcpServer m_serverSocket; // only used if !tunnel_forward TcpServer m_serverSocket; // only used if !tunnel_forward
QPointer<DeviceSocket> m_deviceSocket = Q_NULLPTR; QPointer<VideoSocket> m_videoSocket = Q_NULLPTR;
QPointer<QTcpSocket> m_controlSocket = Q_NULLPTR;
quint16 m_localPort = 0; quint16 m_localPort = 0;
bool m_tunnelEnabled = false; bool m_tunnelEnabled = false;
bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse" bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse"
@ -71,6 +74,8 @@ private:
quint32 m_bitRate = 0; quint32 m_bitRate = 0;
QString m_crop = ""; QString m_crop = "";
quint32 m_acceptTimeoutTimer = 0; quint32 m_acceptTimeoutTimer = 0;
QString m_deviceName = "";
QSize m_deviceSize = QSize();
SERVER_START_STEP m_serverStartStep = SSS_NULL; SERVER_START_STEP m_serverStartStep = SSS_NULL;
}; };

View file

@ -1,9 +1,9 @@
HEADERS += \ HEADERS += \
$$PWD/devicesocket.h \
$$PWD/server.h \ $$PWD/server.h \
$$PWD/tcpserver.h $$PWD/tcpserver.h \
$$PWD/videosocket.h
SOURCES += \ SOURCES += \
$$PWD/devicesocket.cpp \
$$PWD/server.cpp \ $$PWD/server.cpp \
$$PWD/tcpserver.cpp $$PWD/tcpserver.cpp \
$$PWD/videosocket.cpp

View file

@ -1,5 +1,5 @@
#include "tcpserver.h" #include "tcpserver.h"
#include "devicesocket.h" #include "videosocket.h"
TcpServer::TcpServer(QObject *parent) : QTcpServer(parent) TcpServer::TcpServer(QObject *parent) : QTcpServer(parent)
{ {
@ -13,7 +13,16 @@ TcpServer::~TcpServer()
void TcpServer::incomingConnection(qintptr handle) void TcpServer::incomingConnection(qintptr handle)
{ {
DeviceSocket *socket = new DeviceSocket(); if (m_isVideoSocket) {
socket->setSocketDescriptor(handle); VideoSocket *socket = new VideoSocket();
addPendingConnection(socket); socket->setSocketDescriptor(handle);
addPendingConnection(socket);
// next is control socket
m_isVideoSocket = false;
} else {
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(handle);
addPendingConnection(socket);
}
} }

View file

@ -12,6 +12,9 @@ public:
protected: protected:
virtual void incomingConnection(qintptr handle); virtual void incomingConnection(qintptr handle);
private:
bool m_isVideoSocket = true;
}; };
#endif // TCPSERVER_H #endif // TCPSERVER_H

View file

@ -3,21 +3,21 @@
#include <QDebug> #include <QDebug>
#include "qscrcpyevent.h" #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, &VideoSocket::readyRead, this, &VideoSocket::onReadyRead);
connect(this, &DeviceSocket::aboutToClose, this, &DeviceSocket::quitNotify); connect(this, &VideoSocket::aboutToClose, this, &VideoSocket::quitNotify);
connect(this, &DeviceSocket::disconnected, this, &DeviceSocket::quitNotify); connect(this, &VideoSocket::disconnected, this, &VideoSocket::quitNotify);
} }
DeviceSocket::~DeviceSocket() VideoSocket::~VideoSocket()
{ {
quitNotify(); quitNotify();
} }
qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize) qint32 VideoSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
{ {
// this function cant call in main thread // this function cant call in main thread
Q_ASSERT(QCoreApplication::instance()->thread() != QThread::currentThread()); Q_ASSERT(QCoreApplication::instance()->thread() != QThread::currentThread());
@ -31,7 +31,7 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
m_dataSize = 0; m_dataSize = 0;
// post event // post event
DeviceSocketEvent* getDataEvent = new DeviceSocketEvent(); VideoSocketEvent* getDataEvent = new VideoSocketEvent();
QCoreApplication::postEvent(this, getDataEvent); QCoreApplication::postEvent(this, getDataEvent);
// wait // wait
@ -43,16 +43,16 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
return m_dataSize; return m_dataSize;
} }
bool DeviceSocket::event(QEvent *event) bool VideoSocket::event(QEvent *event)
{ {
if (event->type() == QScrcpyEvent::DeviceSocket) { if (event->type() == QScrcpyEvent::VideoSocket) {
onReadyRead(); onReadyRead();
return true; return true;
} }
return QTcpSocket::event(event); return QTcpSocket::event(event);
} }
void DeviceSocket::onReadyRead() void VideoSocket::onReadyRead()
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
if (m_buffer && 0 < bytesAvailable()) { if (m_buffer && 0 < bytesAvailable()) {
@ -67,7 +67,7 @@ void DeviceSocket::onReadyRead()
} }
} }
void DeviceSocket::quitNotify() void VideoSocket::quitNotify()
{ {
m_quit = true; m_quit = true;
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);

View file

@ -1,17 +1,17 @@
#ifndef DEVICESOCKET_H #ifndef VIDEOSOCKET_H
#define DEVICESOCKET_H #define VIDEOSOCKET_H
#include <QEvent> #include <QEvent>
#include <QTcpSocket> #include <QTcpSocket>
#include <QMutex> #include <QMutex>
#include <QWaitCondition> #include <QWaitCondition>
class DeviceSocket : public QTcpSocket class VideoSocket : public QTcpSocket
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DeviceSocket(QObject *parent = nullptr); explicit VideoSocket(QObject *parent = nullptr);
virtual ~DeviceSocket(); virtual ~VideoSocket();
qint32 subThreadRecvData(quint8* buf, qint32 bufSize); qint32 subThreadRecvData(quint8* buf, qint32 bufSize);
@ -32,4 +32,4 @@ private:
bool m_quit = false; bool m_quit = false;
}; };
#endif // DEVICESOCKET_H #endif // VIDEOSOCKET_H

View file

@ -4,7 +4,7 @@
#include "compat.h" #include "compat.h"
#include "stream.h" #include "stream.h"
#include "decoder.h" #include "decoder.h"
#include "devicesocket.h" #include "videosocket.h"
#include "recorder.h" #include "recorder.h"
#define BUFSIZE 0x10000 #define BUFSIZE 0x10000
@ -199,9 +199,9 @@ static qint32 readRawPacket(void *opaque, quint8 *buf, qint32 bufSize) {
return AVERROR_EOF; return AVERROR_EOF;
} }
void Stream::setDeviceSocket(DeviceSocket* deviceSocket) void Stream::setVideoSocket(VideoSocket* videoSocket)
{ {
m_deviceSocket = deviceSocket; m_videoSocket = videoSocket;
} }
void Stream::setRecoder(Recorder *recorder) void Stream::setRecoder(Recorder *recorder)
@ -214,8 +214,8 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize)
if (!buf) { if (!buf) {
return 0; return 0;
} }
if (m_deviceSocket) { if (m_videoSocket) {
qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize); qint32 len = m_videoSocket->subThreadRecvData(buf, bufSize);
return len; return len;
} }
return 0; return 0;
@ -223,7 +223,7 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize)
bool Stream::startDecode() bool Stream::startDecode()
{ {
if (!m_deviceSocket) { if (!m_videoSocket) {
return false; return false;
} }
m_quit.store(0); m_quit.store(0);

View file

@ -12,7 +12,7 @@ extern "C"
#include "libavformat/avformat.h" #include "libavformat/avformat.h"
} }
class DeviceSocket; class VideoSocket;
class Recorder; class Recorder;
class Decoder; class Decoder;
class Stream : public QThread class Stream : public QThread
@ -38,7 +38,7 @@ public:
static void deInit(); static void deInit();
void setDecoder(Decoder* vb); void setDecoder(Decoder* vb);
void setDeviceSocket(DeviceSocket* deviceSocket); void setVideoSocket(VideoSocket* deviceSocket);
void setRecoder(Recorder* recorder); void setRecoder(Recorder* recorder);
qint32 recvData(quint8* buf, qint32 bufSize); qint32 recvData(quint8* buf, qint32 bufSize);
bool startDecode(); bool startDecode();
@ -52,7 +52,7 @@ protected:
void run(); void run();
private: private:
QPointer<DeviceSocket> m_deviceSocket; QPointer<VideoSocket> m_videoSocket;
QAtomicInteger<qint8> m_quit; QAtomicInteger<qint8> m_quit;
// for recorder // for recorder

View file

@ -171,11 +171,11 @@ void VideoForm::initSignals()
} }
// init decoder // init decoder
m_stream.setDeviceSocket(m_server->getDeviceSocket()); m_stream.setVideoSocket(m_server->getVideoSocket());
m_stream.startDecode(); m_stream.startDecode();
// init controller // init controller
m_inputConvert.setDeviceSocket(m_server->getDeviceSocket()); m_inputConvert.setControlSocket(m_server->getControlSocket());
} }
}); });

View file

@ -16,16 +16,20 @@ public final class DesktopConnection implements Closeable {
private static final String SOCKET_NAME = "qtscrcpy"; private static final String SOCKET_NAME = "qtscrcpy";
private final LocalSocket socket; private final LocalSocket videoSocket;
private final InputStream inputStream; private final FileDescriptor videoFd;
private final FileDescriptor fd;
private final LocalSocket controlSocket;
private final InputStream controlInputStream;
private final ControlEventReader reader = new ControlEventReader(); private final ControlEventReader reader = new ControlEventReader();
private DesktopConnection(LocalSocket socket) throws IOException { private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException {
this.socket = socket; this.videoSocket = videoSocket;
inputStream = socket.getInputStream(); this.controlSocket = controlSocket;
fd = socket.getFileDescriptor(); controlInputStream = controlSocket.getInputStream();
videoFd = videoSocket.getFileDescriptor();
} }
private static LocalSocket connect(String abstractName) throws IOException { private static LocalSocket connect(String abstractName) throws IOException {
@ -34,35 +38,47 @@ public final class DesktopConnection implements Closeable {
return localSocket; 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 { public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
LocalSocket socket; LocalSocket videoSocket;
LocalSocket controlSocket;
if (tunnelForward) { if (tunnelForward) {
socket = listenAndAccept(SOCKET_NAME); LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
// send one byte so the client may read() to detect a connection error try {
socket.getOutputStream().write(0); 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 { } 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(); Size videoSize = device.getScreenInfo().getVideoSize();
connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight()); connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
return connection; return connection;
} }
public void close() throws IOException { public void close() throws IOException {
socket.shutdownInput(); videoSocket.shutdownInput();
socket.shutdownOutput(); videoSocket.shutdownOutput();
socket.close(); videoSocket.close();
controlSocket.shutdownInput();
controlSocket.shutdownOutput();
controlSocket.close();
} }
@SuppressWarnings("checkstyle:MagicNumber") @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 + 1] = (byte) width;
buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8); buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8);
buffer[DEVICE_NAME_FIELD_LENGTH + 3] = (byte) height; 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() { public FileDescriptor getVideoFd() {
return fd; return videoFd;
} }
public ControlEvent receiveControlEvent() throws IOException { public ControlEvent receiveControlEvent() throws IOException {
ControlEvent event = reader.next(); ControlEvent event = reader.next();
while (event == null) { while (event == null) {
reader.readFrom(inputStream); reader.readFrom(controlInputStream);
event = reader.next(); event = reader.next();
} }
return event; return event;

View file

@ -25,7 +25,7 @@ public final class Server {
try { try {
// synchronous // synchronous
screenEncoder.streamScreen(device, connection.getFd()); screenEncoder.streamScreen(device, connection.getVideoFd());
} catch (IOException e) { } catch (IOException e) {
// this is expected on close // this is expected on close
Ln.d("Screen streaming stopped"); Ln.d("Screen streaming stopped");

Binary file not shown.