diff --git a/include/grabber/X11Grabber.h b/include/grabber/X11Grabber.h index 5c2dd3b2..7715299f 100644 --- a/include/grabber/X11Grabber.h +++ b/include/grabber/X11Grabber.h @@ -19,7 +19,11 @@ public: virtual ~X11Grabber(); - int open(); + /// + /// Set the video mode (2D/3D) + /// @param[in] mode The new video mode + /// + void setVideoMode(const VideoMode videoMode); bool Setup(); diff --git a/include/protoserver/ProtoConnection.h b/include/protoserver/ProtoConnection.h index a6480eb6..54586ecc 100644 --- a/include/protoserver/ProtoConnection.h +++ b/include/protoserver/ProtoConnection.h @@ -13,6 +13,8 @@ // hyperion util #include #include +#include +#include // jsoncpp includes #include @@ -82,6 +84,18 @@ private slots: /// Try to connect to the Hyperion host void connectToHost(); + /// + /// Slot called when new data has arrived + /// + void readData(); + +signals: + + /// + /// XBMC Video Checker Message + /// + void setGrabbingMode(const GrabbingMode mode); + void setVideoMode(const VideoMode videoMode); private: @@ -109,4 +123,7 @@ private: QTimer _timer; QAbstractSocket::SocketState _prevSocketState; + + /// The buffer used for reading data from the socket + QByteArray _receiveBuffer; }; diff --git a/include/protoserver/ProtoConnectionWrapper.h b/include/protoserver/ProtoConnectionWrapper.h index 7d2f3f6c..62ce0f35 100644 --- a/include/protoserver/ProtoConnectionWrapper.h +++ b/include/protoserver/ProtoConnectionWrapper.h @@ -4,11 +4,13 @@ // hyperion includes #include #include +#include +#include // hyperion proto includes #include "protoserver/ProtoConnection.h" -/// This class handles callbacks from the V4L2 grabber +/// This class handles callbacks from the V4L2 and X11 grabber class ProtoConnectionWrapper : public QObject { Q_OBJECT @@ -16,6 +18,13 @@ class ProtoConnectionWrapper : public QObject public: ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply); virtual ~ProtoConnectionWrapper(); + +signals: + /// + /// Forwarding XBMC Video Checker Message + /// + void setGrabbingMode(const GrabbingMode mode); + void setVideoMode(const VideoMode videoMode); public slots: /// Handle a single image diff --git a/include/protoserver/ProtoServer.h b/include/protoserver/ProtoServer.h index 520848a9..f62425a3 100644 --- a/include/protoserver/ProtoServer.h +++ b/include/protoserver/ProtoServer.h @@ -15,6 +15,8 @@ // hyperion includes #include #include +#include +#include // forward decl class ProtoClientConnection; @@ -50,6 +52,13 @@ public: public slots: void sendImageToProtoSlaves(int priority, const Image & image, int duration_ms); +signals: + /// + /// Forwarding XBMC Checker + /// + void grabbingMode(const GrabbingMode mode); + void videoMode(const VideoMode VideoMode); + private slots: /// /// Slot which is called when a client tries to create a new connection diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index fb860136..9aa56232 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -40,6 +40,11 @@ X11Grabber::~X11Grabber() } } +void X11Grabber::setVideoMode(const VideoMode videoMode) +{ + _imageResampler.set3D(videoMode); +} + void X11Grabber::freeResources() { // Cleanup allocated resources of the X11 grab diff --git a/libsrc/protoserver/ProtoClientConnection.cpp b/libsrc/protoserver/ProtoClientConnection.cpp index d1f087cd..9082635e 100644 --- a/libsrc/protoserver/ProtoClientConnection.cpp +++ b/libsrc/protoserver/ProtoClientConnection.cpp @@ -79,6 +79,32 @@ void ProtoClientConnection::socketClosed() emit connectionClosed(this); } +void ProtoClientConnection::setGrabbingMode(const GrabbingMode mode) +{ + int grabbing_mode = (int)mode; + proto::HyperionReply gMode; + + // create proto message + gMode.set_type(proto::HyperionReply::GRABBING); + gMode.set_grabbing(grabbing_mode); + + // send message + sendMessage(gMode); +} + +void ProtoClientConnection::setVideoMode(const VideoMode videoMode) +{ + int video_Mode = (int)videoMode; + proto::HyperionReply vMode; + + // create proto message + vMode.set_type(proto::HyperionReply::VIDEO); + vMode.set_grabbing(video_Mode); + + // send message + sendMessage(vMode); +} + void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message) { // forward messages @@ -208,6 +234,7 @@ void ProtoClientConnection::sendSuccessReply() { // create reply proto::HyperionReply reply; + reply.set_type(proto::HyperionReply::REPLY); reply.set_success(true); // send reply @@ -218,6 +245,7 @@ void ProtoClientConnection::sendErrorReply(const std::string &error) { // create reply proto::HyperionReply reply; + reply.set_type(proto::HyperionReply::REPLY); reply.set_success(false); reply.set_error(error); diff --git a/libsrc/protoserver/ProtoClientConnection.h b/libsrc/protoserver/ProtoClientConnection.h index c68f56e0..ca22e778 100644 --- a/libsrc/protoserver/ProtoClientConnection.h +++ b/libsrc/protoserver/ProtoClientConnection.h @@ -11,6 +11,10 @@ // Hyperion includes #include +//Utils includes +#include +#include + // proto includes #include "message.pb.h" #include "protoserver/ProtoConnection.h" @@ -18,7 +22,7 @@ class ImageProcessor; /// -/// The Connection object created by \a ProtoServer when a new connection is establshed +/// The Connection object created by a ProtoServer when a new connection is establshed /// class ProtoClientConnection : public QObject { @@ -36,6 +40,13 @@ public: /// Destructor /// ~ProtoClientConnection(); + +public slots: + /// + /// Send XBMC Video Checker message to connected client + /// + void setGrabbingMode(const GrabbingMode mode); + void setVideoMode(const VideoMode videoMode); signals: /// diff --git a/libsrc/protoserver/ProtoConnection.cpp b/libsrc/protoserver/ProtoConnection.cpp index d4850d48..3492a7ec 100644 --- a/libsrc/protoserver/ProtoConnection.cpp +++ b/libsrc/protoserver/ProtoConnection.cpp @@ -35,7 +35,8 @@ ProtoConnection::ProtoConnection(const std::string & a) : _timer.setInterval(5000); _timer.setSingleShot(false); - connect(&_timer,SIGNAL(timeout()), this, SLOT(connectToHost()) ); + connect(&_timer,SIGNAL(timeout()), this, SLOT(connectToHost())); + connect(&_socket, SIGNAL(readyRead()), this, SLOT(readData())); _timer.start(); } @@ -45,6 +46,44 @@ ProtoConnection::~ProtoConnection() _socket.close(); } +void ProtoConnection::readData() +{ + _receiveBuffer += _socket.readAll(); + + // check if we can read a message size + if (_receiveBuffer.size() <= 4) + { + return; + } + + // read the message size + uint32_t messageSize = + ((_receiveBuffer[0]<<24) & 0xFF000000) | + ((_receiveBuffer[1]<<16) & 0x00FF0000) | + ((_receiveBuffer[2]<< 8) & 0x0000FF00) | + ((_receiveBuffer[3] ) & 0x000000FF); + + // check if we can read a complete message + if ((uint32_t) _receiveBuffer.size() < messageSize + 4) + { + return; + } + + // read a message + proto::HyperionReply reply; + + if (!reply.ParseFromArray(_receiveBuffer.data() + 4, messageSize)) + { + std::cerr << "PROTOCONNECTION ERROR: Unable to parse message" << std::endl; + return; + } + + parseReply(reply); + + // remove message data from buffer + _receiveBuffer = _receiveBuffer.mid(messageSize + 4); +} + void ProtoConnection::setSkipReply(bool skip) { _skipReply = skip; @@ -157,58 +196,51 @@ void ProtoConnection::sendMessage(const proto::HyperionRequest &message) std::cerr << "PROTOCONNECTION ERROR: Error while writing data to host" << std::endl; return; } - - if (!_skipReply) - { - // read reply data - QByteArray serializedReply; - length = -1; - while (length < 0 && serializedReply.size() < length+4) - { - // receive reply - if (!_socket.waitForReadyRead()) - { - std::cerr << "PROTOCONNECTION ERROR: Error while reading data from host" << std::endl; - return; - } - - serializedReply += _socket.readAll(); - - if (length < 0 && serializedReply.size() >= 4) - { - // read the message size - length = - ((serializedReply[0]<<24) & 0xFF000000) | - ((serializedReply[1]<<16) & 0x00FF0000) | - ((serializedReply[2]<< 8) & 0x0000FF00) | - ((serializedReply[3] ) & 0x000000FF); - } - } - - // parse reply data - proto::HyperionReply reply; - reply.ParseFromArray(serializedReply.constData()+4, length); - - // parse reply message - parseReply(reply); - } } bool ProtoConnection::parseReply(const proto::HyperionReply &reply) { bool success = false; - - if (!reply.success()) + + switch (reply.type()) { - if (reply.has_error()) + case proto::HyperionReply::REPLY: { - throw std::runtime_error("PROTOCONNECTION ERROR: " + reply.error()); + if (!_skipReply) + { + if (!reply.success()) + { + if (reply.has_error()) + { + throw std::runtime_error("PROTOCONNECTION ERROR: " + reply.error()); + } + else + { + throw std::runtime_error("PROTOCONNECTION ERROR: No error info"); + } + } + else + { + success = true; + } + } + break; } - else + case proto::HyperionReply::GRABBING: { - throw std::runtime_error("PROTOCONNECTION ERROR: No error info"); + int grabbing = reply.has_grabbing() ? reply.grabbing() : 6; + GrabbingMode gMode = (GrabbingMode)grabbing; + emit setGrabbingMode(gMode); + break; + } + case proto::HyperionReply::VIDEO: + { + int video = reply.has_video() ? reply.video() : 0; + VideoMode vMode = (VideoMode)video; + emit setVideoMode(vMode); + break; } } - + return success; } diff --git a/libsrc/protoserver/ProtoConnectionWrapper.cpp b/libsrc/protoserver/ProtoConnectionWrapper.cpp index e1c5b8d4..3c2ad0cd 100644 --- a/libsrc/protoserver/ProtoConnectionWrapper.cpp +++ b/libsrc/protoserver/ProtoConnectionWrapper.cpp @@ -7,6 +7,8 @@ ProtoConnectionWrapper::ProtoConnectionWrapper(const std::string & address, int _connection(address) { _connection.setSkipReply(skipProtoReply); + connect(&_connection, SIGNAL(setGrabbingMode(GrabbingMode)), this, SIGNAL(setGrabbingMode(GrabbingMode))); + connect(&_connection, SIGNAL(setVideoMode(VideoMode)), this, SIGNAL(setVideoMode(VideoMode))); } ProtoConnectionWrapper::~ProtoConnectionWrapper() diff --git a/libsrc/protoserver/ProtoServer.cpp b/libsrc/protoserver/ProtoServer.cpp index 1abafb0c..eef471bf 100644 --- a/libsrc/protoserver/ProtoServer.cpp +++ b/libsrc/protoserver/ProtoServer.cpp @@ -64,6 +64,10 @@ void ProtoServer::newConnection() // register slot for cleaning up after the connection closed connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*))); connect(connection, SIGNAL(newMessage(const proto::HyperionRequest*)), this, SLOT(newMessage(const proto::HyperionRequest*))); + + // register forward signal for xbmc checker + connect(this, SIGNAL(grabbingMode(GrabbingMode)), connection, SLOT(setGrabbingMode(GrabbingMode))); + connect(this, SIGNAL(videoMode(VideoMode)), connection, SLOT(setVideoMode(VideoMode))); } } diff --git a/libsrc/protoserver/message.proto b/libsrc/protoserver/message.proto index 33c995b3..aff897bd 100644 --- a/libsrc/protoserver/message.proto +++ b/libsrc/protoserver/message.proto @@ -61,9 +61,24 @@ message ClearRequest { } message HyperionReply { + enum Type { + REPLY = 1; + GRABBING = 2; + VIDEO = 3; + } + + // Identifies which field is filled in. + required Type type = 1; + // flag indication success or failure - required bool success = 1; + optional bool success = 2; // string indicating the reason for failure (if applicable) - optional string error = 2; + optional string error = 3; + + // XBMC Video Checker Proto Messages for Grabbing mode + optional int32 grabbing = 4; + + // XBMC Video Checker Proto Messages for Video mode + optional int32 video = 5; } diff --git a/src/hyperion-x11/X11Wrapper.cpp b/src/hyperion-x11/X11Wrapper.cpp index e417a07b..66c74693 100644 --- a/src/hyperion-x11/X11Wrapper.cpp +++ b/src/hyperion-x11/X11Wrapper.cpp @@ -39,3 +39,26 @@ void X11Wrapper::capture() const Image & screenshot = _grabber.grab(); emit sig_screenshot(screenshot); } + +void X11Wrapper::setGrabbingMode(const GrabbingMode mode) +{ + switch (mode) + { + case GRABBINGMODE_VIDEO: + case GRABBINGMODE_PAUSE: + case GRABBINGMODE_AUDIO: + case GRABBINGMODE_PHOTO: + case GRABBINGMODE_MENU: + case GRABBINGMODE_INVALID: + start(); + break; + case GRABBINGMODE_OFF: + stop(); + break; + } +} + +void X11Wrapper::setVideoMode(const VideoMode mode) +{ + _grabber.setVideoMode(mode); +} diff --git a/src/hyperion-x11/X11Wrapper.h b/src/hyperion-x11/X11Wrapper.h index b672c3a0..c16487eb 100644 --- a/src/hyperion-x11/X11Wrapper.h +++ b/src/hyperion-x11/X11Wrapper.h @@ -5,6 +5,10 @@ // Hyperion-X11 includes #include +//Utils includes +#include +#include + class X11Wrapper : public QObject { Q_OBJECT @@ -25,6 +29,19 @@ public: signals: void sig_screenshot(const Image & screenshot); +public slots: + /// + /// Set the grabbing mode + /// @param[in] mode The new grabbing mode + /// + void setGrabbingMode(const GrabbingMode mode); + + /// + /// Set the video mode (2D/3D) + /// @param[in] mode The new video mode + /// + void setVideoMode(const VideoMode videoMode); + private slots: /// /// Performs a single screenshot capture and publishes the capture screenshot on the screenshot diff --git a/src/hyperion-x11/hyperion-x11.cpp b/src/hyperion-x11/hyperion-x11.cpp index c308828e..855a3ab1 100644 --- a/src/hyperion-x11/hyperion-x11.cpp +++ b/src/hyperion-x11/hyperion-x11.cpp @@ -104,6 +104,10 @@ int main(int argc, char ** argv) // Connect the screen capturing to the proto processing QObject::connect(&x11Wrapper, SIGNAL(sig_screenshot(const Image &)), &protoWrapper, SLOT(receiveImage(Image))); + + // Connect the XBMC Video Checker to the proto processing + QObject::connect(&protoWrapper, SIGNAL(setGrabbingMode(GrabbingMode)), &x11Wrapper, SLOT(setGrabbingMode(GrabbingMode))); + QObject::connect(&protoWrapper, SIGNAL(setVideoMode(VideoMode)), &x11Wrapper, SLOT(setVideoMode(VideoMode))); // Start the capturing x11Wrapper.start(); diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index a8e7a466..b2b0c1b8 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -187,7 +187,7 @@ void startXBMCVideoChecker(const Json::Value &config, XBMCVideoChecker* &xbmcVid } } -void startNetworkServices(const Json::Value &config, Hyperion &hyperion, JsonServer* &jsonServer, ProtoServer* &protoServer, BoblightServer* &boblightServer) +void startNetworkServices(const Json::Value &config, Hyperion &hyperion, JsonServer* &jsonServer, ProtoServer* &protoServer, BoblightServer* &boblightServer, XBMCVideoChecker* &xbmcVideoChecker) { // Create Json server if configuration is present if (config.isMember("jsonServer")) @@ -216,6 +216,11 @@ void startNetworkServices(const Json::Value &config, Hyperion &hyperion, JsonSer { const Json::Value & protoServerConfig = config["protoServer"]; protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt() ); + if (xbmcVideoChecker != nullptr) + { + QObject::connect(xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), protoServer, SIGNAL(grabbingMode(GrabbingMode))); + QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), protoServer, SIGNAL(videoMode(VideoMode))); + } std::cout << "INFO: Proto server created and started on port " << protoServer->getPort() << std::endl; #ifdef ENABLE_ZEROCONF @@ -481,7 +486,7 @@ int main(int argc, char** argv) JsonServer * jsonServer = nullptr; ProtoServer * protoServer = nullptr; BoblightServer * boblightServer = nullptr; - startNetworkServices(config, hyperion, jsonServer, protoServer, boblightServer); + startNetworkServices(config, hyperion, jsonServer, protoServer, boblightServer, xbmcVideoChecker); // ---- grabber -----