mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Merge branch 'master' into macos_compile
Conflicts: libsrc/leddevice/CMakeLists.txt libsrc/leddevice/LedDeviceFactory.cpp test/TestRs232HighSpeed.cpp Former-commit-id: 5583f2f881afd1a9b0c8ec3a52d7d3b54fe1dff7
This commit is contained in:
@@ -61,10 +61,29 @@ void DispmanxFrameGrabber::setFlags(const int vc_flags)
|
||||
_vc_flags = vc_flags;
|
||||
}
|
||||
|
||||
void DispmanxFrameGrabber::setVideoMode(const VideoMode videoMode)
|
||||
{
|
||||
switch (videoMode) {
|
||||
case VIDEO_3DSBS:
|
||||
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width/2, _height);
|
||||
break;
|
||||
case VIDEO_3DTAB:
|
||||
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height/2);
|
||||
break;
|
||||
case VIDEO_2D:
|
||||
default:
|
||||
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
|
||||
{
|
||||
// Sanity check of the given image size
|
||||
assert(image.width() == _width && image.height() == _height);
|
||||
// resize the given image if needed
|
||||
if (image.width() != unsigned(_rectangle.width) || image.height() != unsigned(_rectangle.height))
|
||||
{
|
||||
image.resize(_rectangle.width, _rectangle.height);
|
||||
}
|
||||
|
||||
// Open the connection to the display
|
||||
_vc_display = vc_dispmanx_display_open(0);
|
||||
@@ -74,7 +93,7 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
|
||||
|
||||
// Read the snapshot into the memory
|
||||
void* image_ptr = image.memptr();
|
||||
const unsigned destPitch = _width * sizeof(ColorRgba);
|
||||
const unsigned destPitch = _rectangle.width * sizeof(ColorRgba);
|
||||
vc_dispmanx_resource_read_data(_vc_resource, &_rectangle, image_ptr, destPitch);
|
||||
|
||||
// Close the displaye
|
||||
|
@@ -10,6 +10,7 @@
|
||||
// Utils includes
|
||||
#include <utils/Image.h>
|
||||
#include <utils/ColorRgba.h>
|
||||
#include <utils/VideoMode.h>
|
||||
|
||||
///
|
||||
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a
|
||||
@@ -34,6 +35,12 @@ public:
|
||||
///
|
||||
void setFlags(const int vc_flags);
|
||||
|
||||
///
|
||||
/// Set the video mode (2D/3D)
|
||||
/// @param[in] mode The new video mode
|
||||
///
|
||||
void setVideoMode(const VideoMode videoMode);
|
||||
|
||||
///
|
||||
/// Captures a single snapshot of the display and writes the data to the given image. The
|
||||
/// provided image should have the same dimensions as the configured values (_width and
|
||||
@@ -58,8 +65,7 @@ private:
|
||||
int _vc_flags;
|
||||
|
||||
/// With of the captured snapshot [pixels]
|
||||
unsigned _width;
|
||||
const unsigned _width;
|
||||
/// Height of the captured snapshot [pixels]
|
||||
unsigned _height;
|
||||
|
||||
const unsigned _height;
|
||||
};
|
||||
|
@@ -81,3 +81,8 @@ void DispmanxWrapper::setGrabbingMode(const GrabbingMode mode)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DispmanxWrapper::setVideoMode(const VideoMode mode)
|
||||
{
|
||||
_frameGrabber->setVideoMode(mode);
|
||||
}
|
||||
|
@@ -255,6 +255,14 @@
|
||||
"grabMenu" : {
|
||||
"type" : "boolean",
|
||||
"required" : true
|
||||
},
|
||||
"grabScreensaver" : {
|
||||
"type" : "boolean",
|
||||
"required" : false
|
||||
},
|
||||
"enable3DDetection" : {
|
||||
"type" : "boolean",
|
||||
"required" : false
|
||||
}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
|
@@ -24,6 +24,8 @@ SET(Leddevice_HEADERS
|
||||
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceTest.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceSedu.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceLightpack.h
|
||||
${CURRENT_SOURCE_DIR}/LedDevicePaintpack.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.h
|
||||
@@ -37,6 +39,9 @@ SET(Leddevice_SOURCES
|
||||
${CURRENT_SOURCE_DIR}/LedRs232Device.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceSedu.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDevicePaintpack.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp
|
||||
|
@@ -7,11 +7,12 @@
|
||||
#include "LedDeviceLpd6803.h"
|
||||
#include "LedDeviceLpd8806.h"
|
||||
#include "LedDeviceWs2801.h"
|
||||
#include "LedDeviceWs2811.h"
|
||||
#endif
|
||||
|
||||
#include "LedDeviceSedu.h"
|
||||
#include "LedDeviceTest.h"
|
||||
#include "LedDeviceWs2811.h"
|
||||
#include "LedDeviceWs2812b.h"
|
||||
#include "LedDeviceAdalight.h"
|
||||
#include "LedDevicePaintpack.h"
|
||||
#include "LedDeviceLightpack.h"
|
||||
@@ -37,23 +38,6 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
|
||||
|
||||
device = deviceWs2801;
|
||||
}
|
||||
// else if (type == "ws2811")
|
||||
// {
|
||||
// const std::string output = deviceConfig["output"].asString();
|
||||
// const std::string outputSpeed = deviceConfig["output"].asString();
|
||||
// const std::string timingOption = deviceConfig["timingOption"].asString();
|
||||
|
||||
// ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
|
||||
// if (outputSpeed != "high" && outputSpeed != "low")
|
||||
// {
|
||||
// std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
|
||||
// }
|
||||
|
||||
// LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
|
||||
// deviceWs2811->open();
|
||||
|
||||
// device = deviceWs2811;
|
||||
// }
|
||||
else if (type == "lpd6803" || type == "ldp6803")
|
||||
{
|
||||
const std::string output = deviceConfig["output"].asString();
|
||||
@@ -75,6 +59,30 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
|
||||
device = deviceLpd8806;
|
||||
}
|
||||
#endif
|
||||
// else if (type == "ws2811")
|
||||
// {
|
||||
// const std::string output = deviceConfig["output"].asString();
|
||||
// const std::string outputSpeed = deviceConfig["output"].asString();
|
||||
// const std::string timingOption = deviceConfig["timingOption"].asString();
|
||||
|
||||
// ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
|
||||
// if (outputSpeed != "high" && outputSpeed != "low")
|
||||
// {
|
||||
// std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
|
||||
// }
|
||||
|
||||
// LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
|
||||
// deviceWs2811->open();
|
||||
|
||||
// device = deviceWs2811;
|
||||
// }
|
||||
else if (type == "ws2812b")
|
||||
{
|
||||
LedDeviceWs2812b * deviceWs2812b = new LedDeviceWs2812b();
|
||||
deviceWs2812b->open();
|
||||
|
||||
device = deviceWs2812b;
|
||||
}
|
||||
else if (type == "adalight")
|
||||
{
|
||||
const std::string output = deviceConfig["output"].asString();
|
||||
|
114
libsrc/leddevice/LedDeviceWs2812b.cpp
Normal file
114
libsrc/leddevice/LedDeviceWs2812b.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
// Linux includes
|
||||
#include <unistd.h>
|
||||
|
||||
// Local Hyperion-Leddevice includes
|
||||
#include "LedDeviceWs2812b.h"
|
||||
|
||||
LedDeviceWs2812b::LedDeviceWs2812b() :
|
||||
LedRs232Device("/dev/ttyAMA0", 4000000)
|
||||
{
|
||||
fillTable();
|
||||
}
|
||||
|
||||
int LedDeviceWs2812b::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
// Ensure the size of the led-buffer
|
||||
if (_ledBuffer.size() != ledValues.size()*3)
|
||||
{
|
||||
_ledBuffer.resize(ledValues.size()*3);
|
||||
}
|
||||
|
||||
// Translate the channel of each color to a signal
|
||||
for (unsigned iLed=0; iLed<ledValues.size(); ++iLed)
|
||||
{
|
||||
const ColorRgb & color = ledValues[iLed];
|
||||
|
||||
_ledBuffer[3*iLed] = _byte2signalTable[color.red];
|
||||
_ledBuffer[3*iLed + 1] = _byte2signalTable[color.green];
|
||||
_ledBuffer[3*iLed + 2] = _byte2signalTable[color.blue];
|
||||
}
|
||||
|
||||
const int result = writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
|
||||
// Official latch time is 50us (lets give it 50us more)
|
||||
usleep(100);
|
||||
return result;
|
||||
}
|
||||
|
||||
int LedDeviceWs2812b::switchOff()
|
||||
{
|
||||
// Set all bytes in the signal buffer to zero
|
||||
for (ByteSignal & signal : _ledBuffer)
|
||||
{
|
||||
signal = _byte2signalTable[0];
|
||||
}
|
||||
|
||||
return writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
|
||||
}
|
||||
|
||||
void LedDeviceWs2812b::fillTable()
|
||||
{
|
||||
_byte2signalTable.clear();
|
||||
for (int byte=0; byte<256; ++byte)
|
||||
{
|
||||
const ByteSignal signal = byte2Signal(uint8_t(byte));
|
||||
_byte2signalTable.push_back(signal);
|
||||
}
|
||||
}
|
||||
|
||||
LedDeviceWs2812b::ByteSignal LedDeviceWs2812b::byte2Signal(const uint8_t byte) const
|
||||
{
|
||||
ByteSignal result;
|
||||
result.bit_12 = bits2Signal(byte & 0x80, byte & 0x40);
|
||||
result.bit_34 = bits2Signal(byte & 0x20, byte & 0x10);
|
||||
result.bit_56 = bits2Signal(byte & 0x08, byte & 0x04);
|
||||
result.bit_78 = bits2Signal(byte & 0x02, byte & 0x01);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t LedDeviceWs2812b::bits2Signal(const bool bit1, const bool bit2) const
|
||||
{
|
||||
// See https://github.com/tvdzwan/hyperion/wiki/Ws2812b for the explanation of the given
|
||||
// translations
|
||||
|
||||
// Encoding scheme 1
|
||||
// 00 1 1000 1100 0 1 0111 0011 0 1 1100 1110 0 0xCE
|
||||
// 01 1 1000 1110 0 1 0111 0001 0 1 1000 1110 0 0x8E
|
||||
// 10 1 1100 1100 0 1 0011 0011 0 1 1100 1100 0 0xCC
|
||||
// 11 1 1100 1110 0 1 0011 0001 0 1 1000 1100 0 0x8C
|
||||
|
||||
// Encoding schem 2
|
||||
// 00 - 1 0000 1000 0 - 1 1111 0111 0 - 1 1110 1111 0 - 0xEF
|
||||
// 01 - 1 0000 1111 0 - 1 1111 0000 0 - 1 0000 1111 0 - 0x0F
|
||||
// 10 - 1 1110 1000 0 - 1 0001 0111 0 - 1 1110 1000 0 - 0xE8
|
||||
// 11 - 1 1110 1111 0 - 1 0001 0000 0 - 1 0000 1000 0 - 0x08
|
||||
|
||||
if (bit1)
|
||||
{
|
||||
if (bit2)
|
||||
{
|
||||
// return 0x08;
|
||||
return 0x8C;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return 0xE8;
|
||||
return 0xCC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bit2)
|
||||
{
|
||||
// return 0x0F;
|
||||
return 0x8E;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return 0xEF;
|
||||
return 0xCE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
76
libsrc/leddevice/LedDeviceWs2812b.h
Normal file
76
libsrc/leddevice/LedDeviceWs2812b.h
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Hyperion leddevice includes
|
||||
#include "LedRs232Device.h"
|
||||
|
||||
///
|
||||
/// The LedDevice for controlling a string of WS2812B leds. These are controlled over the mini-UART
|
||||
/// of the RPi (/dev/ttyAMA0).
|
||||
///
|
||||
class LedDeviceWs2812b : public LedRs232Device
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs the device (all required parameters are hardcoded)
|
||||
///
|
||||
LedDeviceWs2812b();
|
||||
|
||||
///
|
||||
/// Write the color data the the WS2812B led string
|
||||
///
|
||||
/// @param ledValues The color data
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
|
||||
///
|
||||
/// Write zero to all leds(that have been written by a previous write operation)
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int switchOff();
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Structure holding the four output-bytes corresponding to a single input byte
|
||||
///
|
||||
struct ByteSignal
|
||||
{
|
||||
uint8_t bit_12;
|
||||
uint8_t bit_34;
|
||||
uint8_t bit_56;
|
||||
uint8_t bit_78;
|
||||
};
|
||||
/// Translation table from single input-byte to output-bytes
|
||||
std::vector<ByteSignal> _byte2signalTable;
|
||||
|
||||
///
|
||||
/// Fills the translation table (_byte2signalTable)
|
||||
///
|
||||
void fillTable();
|
||||
|
||||
///
|
||||
/// Computes the output bytes that belong to a given input-byte (no table lookup)
|
||||
///
|
||||
/// @param byte The input byte
|
||||
/// @return The four bytes (ByteSignal) for the output signal
|
||||
///
|
||||
ByteSignal byte2Signal(const uint8_t byte) const;
|
||||
|
||||
///
|
||||
/// Translates two bits to a single byte
|
||||
///
|
||||
/// @param bit1 The value of the first bit (1=true, zero=false)
|
||||
/// @param bit1 The value of the ssecond bit (1=true, zero=false)
|
||||
///
|
||||
/// @return The output-byte for the given two bit
|
||||
///
|
||||
uint8_t bits2Signal(const bool bit1, const bool bit2) const;
|
||||
|
||||
///
|
||||
/// The output buffer for writing bytes to the output
|
||||
///
|
||||
std::vector<ByteSignal> _ledBuffer;
|
||||
};
|
@@ -57,7 +57,9 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
||||
try
|
||||
{
|
||||
_rs232Port.flushOutput();
|
||||
_rs232Port.write(data, size);
|
||||
_rs232Port.flush();
|
||||
}
|
||||
catch (const serial::SerialException & serialExc)
|
||||
{
|
||||
@@ -77,6 +79,7 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
|
||||
{
|
||||
_rs232Port.open();
|
||||
_rs232Port.write(data, size);
|
||||
_rs232Port.flush();
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
|
@@ -1,52 +1,50 @@
|
||||
// Qt includes
|
||||
#include <QUrl>
|
||||
#include <QRegExp>
|
||||
#include <QStringRef>
|
||||
|
||||
#include <xbmcvideochecker/XBMCVideoChecker.h>
|
||||
|
||||
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval_ms, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu) :
|
||||
// Request player example:
|
||||
// {"id":666,"jsonrpc":"2.0","method":"Player.GetActivePlayers"}
|
||||
// {"id":666,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
|
||||
|
||||
// Request playing item example:
|
||||
// {"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":1,"properties":["file"]}}
|
||||
// {"id":667,"jsonrpc":"2.0","result":{"item":{"file":"smb://xbmc:xbmc@192.168.53.12/video/Movies/Avatar (2009)/Avatar.mkv","label":"Avatar","type":"unknown"}}}
|
||||
|
||||
// Request if screensaver is on
|
||||
// {"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}}
|
||||
// {"id":668,"jsonrpc":"2.0","result":{"System.ScreenSaverActive":false}}
|
||||
|
||||
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection) :
|
||||
QObject(),
|
||||
_address(QString::fromStdString(address)),
|
||||
_port(port),
|
||||
_request(R"({"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":666})"),
|
||||
_timer(),
|
||||
_activePlayerRequest(R"({"id":666,"jsonrpc":"2.0","method":"Player.GetActivePlayers"})"),
|
||||
_currentPlayingItemRequest(R"({"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":%1,"properties":["file"]}})"),
|
||||
_checkScreensaverRequest(R"({"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}})"),
|
||||
_socket(),
|
||||
_grabVideo(grabVideo),
|
||||
_grabPhoto(grabPhoto),
|
||||
_grabAudio(grabAudio),
|
||||
_grabMenu(grabMenu),
|
||||
_previousMode(GRABBINGMODE_INVALID)
|
||||
_grabScreensaver(grabScreensaver),
|
||||
_enable3DDetection(enable3DDetection),
|
||||
_previousScreensaverMode(false),
|
||||
_previousGrabbingMode(GRABBINGMODE_INVALID),
|
||||
_previousVideoMode(VIDEO_2D)
|
||||
{
|
||||
// setup timer
|
||||
_timer.setSingleShot(false);
|
||||
_timer.setInterval(interval_ms);
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(sendRequest()));
|
||||
|
||||
// setup socket
|
||||
connect(&_socket, SIGNAL(readyRead()), this, SLOT(receiveReply()));
|
||||
connect(&_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
|
||||
connect(&_socket, SIGNAL(connected()), this, SLOT(connected()));
|
||||
connect(&_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::start()
|
||||
{
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::sendRequest()
|
||||
{
|
||||
switch (_socket.state())
|
||||
{
|
||||
case QTcpSocket::UnconnectedState:
|
||||
// not connected. try to connect
|
||||
std::cout << "Connecting to " << _address.toStdString() << ":" << _port << " to check XBMC player status" << std::endl;
|
||||
_socket.connectToHost(_address, _port);
|
||||
break;
|
||||
case QTcpSocket::ConnectedState:
|
||||
// write the request on the socket
|
||||
_socket.write(_request);
|
||||
break;
|
||||
default:
|
||||
// whatever. let's check again at the next timer tick
|
||||
break;
|
||||
}
|
||||
reconnect();
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::receiveReply()
|
||||
@@ -54,62 +52,220 @@ void XBMCVideoChecker::receiveReply()
|
||||
// expect that the reply is received as a single message. Probably oke considering the size of the expected reply
|
||||
QString reply(_socket.readAll());
|
||||
|
||||
// check if the resply is a reply to one of my requests
|
||||
if (!reply.contains("\"id\":666"))
|
||||
std::cout << "Message from XBMC: " << reply.toStdString() << std::endl;
|
||||
|
||||
if (reply.contains("\"method\":\"Player.OnPlay\""))
|
||||
{
|
||||
// probably not. Leave this mreply as is and don't act on it
|
||||
// send a request for the current player state
|
||||
_socket.write(_activePlayerRequest.toUtf8());
|
||||
return;
|
||||
}
|
||||
else if (reply.contains("\"method\":\"Player.OnStop\""))
|
||||
{
|
||||
// the player has stopped
|
||||
setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
|
||||
setVideoMode(VIDEO_2D);
|
||||
}
|
||||
else if (reply.contains("\"method\":\"GUI.OnScreensaverActivated\""))
|
||||
{
|
||||
setScreensaverMode(!_grabScreensaver);
|
||||
}
|
||||
else if (reply.contains("\"method\":\"GUI.OnScreensaverDeactivated\""))
|
||||
{
|
||||
setScreensaverMode(false);
|
||||
}
|
||||
else if (reply.contains("\"id\":666"))
|
||||
{
|
||||
// Result of Player.GetActivePlayers
|
||||
|
||||
GrabbingMode newMode = GRABBINGMODE_INVALID;
|
||||
if (reply.contains("video"))
|
||||
{
|
||||
// video is playing
|
||||
newMode = _grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF;
|
||||
}
|
||||
else if (reply.contains("picture"))
|
||||
{
|
||||
// picture viewer is playing
|
||||
newMode = _grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF;
|
||||
}
|
||||
else if (reply.contains("audio"))
|
||||
{
|
||||
// audio is playing
|
||||
newMode = _grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing is playing.
|
||||
newMode = _grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF;
|
||||
}
|
||||
// always start a new video in 2D mode
|
||||
emit videoMode(VIDEO_2D);
|
||||
|
||||
// emit new state if applicable
|
||||
if (newMode != _previousMode && newMode != GRABBINGMODE_INVALID)
|
||||
{
|
||||
switch (newMode)
|
||||
if (reply.contains("video"))
|
||||
{
|
||||
case GRABBINGMODE_VIDEO:
|
||||
std::cout << "XBMC checker: switching to VIDEO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_PHOTO:
|
||||
std::cout << "XBMC checker: switching to PHOTO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_AUDIO:
|
||||
std::cout << "XBMC checker: switching to AUDIO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_MENU:
|
||||
std::cout << "XBMC checker: switching to MENU mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_OFF:
|
||||
std::cout << "XBMC checker: switching to OFF mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_INVALID:
|
||||
std::cout << "XBMC checker: switching to INVALID mode" << std::endl;
|
||||
break;
|
||||
}
|
||||
// video is playing
|
||||
setGrabbingMode(_grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF);
|
||||
|
||||
emit grabbingMode(newMode);
|
||||
_previousMode = newMode;
|
||||
// we need to get the filename
|
||||
// first retrieve the playerid
|
||||
QString key = "\"playerid\":";
|
||||
QRegExp regex(key + "(\\d+)");
|
||||
int pos = regex.indexIn(reply);
|
||||
if (pos > 0)
|
||||
{
|
||||
// now request info of the playing item
|
||||
QStringRef idText(&reply, pos + key.length(), regex.matchedLength() - key.length());
|
||||
_socket.write(_currentPlayingItemRequest.arg(idText.toString()).toUtf8());
|
||||
}
|
||||
}
|
||||
else if (reply.contains("picture"))
|
||||
{
|
||||
// picture viewer is playing
|
||||
setGrabbingMode(_grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF);
|
||||
}
|
||||
else if (reply.contains("audio"))
|
||||
{
|
||||
// audio is playing
|
||||
setGrabbingMode(_grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing is playing.
|
||||
setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
|
||||
}
|
||||
}
|
||||
else if (reply.contains("\"id\":667"))
|
||||
{
|
||||
// result of Player.GetItem
|
||||
// TODO: what if the filename contains a '"'. In Json this should have been escaped
|
||||
QRegExp regex("\"file\":\"((?!\").)*\"");
|
||||
int pos = regex.indexIn(reply);
|
||||
if (pos > 0)
|
||||
{
|
||||
QStringRef filename = QStringRef(&reply, pos+8, regex.matchedLength()-9);
|
||||
if (filename.contains("3DSBS", Qt::CaseInsensitive) || filename.contains("HSBS", Qt::CaseInsensitive))
|
||||
{
|
||||
setVideoMode(VIDEO_3DSBS);
|
||||
}
|
||||
else if (filename.contains("3DTAB", Qt::CaseInsensitive) || filename.contains("HTAB", Qt::CaseInsensitive))
|
||||
{
|
||||
setVideoMode(VIDEO_3DTAB);
|
||||
}
|
||||
else
|
||||
{
|
||||
setVideoMode(VIDEO_2D);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (reply.contains("\"id\":668"))
|
||||
{
|
||||
// result of System.ScreenSaverActive
|
||||
bool active = reply.contains("\"System.ScreenSaverActive\":true");
|
||||
setScreensaverMode(!_grabScreensaver && active);
|
||||
}
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::connected()
|
||||
{
|
||||
std::cout << "XBMC Connected" << std::endl;
|
||||
|
||||
// send a request for the current player state
|
||||
_socket.write(_activePlayerRequest.toUtf8());
|
||||
_socket.write(_checkScreensaverRequest.toUtf8());
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::disconnected()
|
||||
{
|
||||
std::cout << "XBMC Disconnected" << std::endl;
|
||||
reconnect();
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::reconnect()
|
||||
{
|
||||
if (_socket.state() == QTcpSocket::ConnectedState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// try to connect
|
||||
switch (_socket.state())
|
||||
{
|
||||
case QTcpSocket::ConnectingState:
|
||||
// Somehow when XBMC restarts we get stuck in connecting state
|
||||
// If we get here we tried to connect already for 5 seconds. abort and try again in 1 second.
|
||||
_socket.reset();
|
||||
_socket.waitForDisconnected(50);
|
||||
QTimer::singleShot(1000, this, SLOT(reconnect()));
|
||||
break;
|
||||
case QTcpSocket::UnconnectedState:
|
||||
_socket.connectToHost(_address, _port);
|
||||
QTimer::singleShot(10000, this, SLOT(reconnect()));
|
||||
break;
|
||||
default:
|
||||
QTimer::singleShot(10000, this, SLOT(reconnect()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::connectionError(QAbstractSocket::SocketError error)
|
||||
{
|
||||
std::cout << "XBMC Connection error (" << error << ")" << std::endl;
|
||||
|
||||
// close the socket
|
||||
_socket.close();
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::setGrabbingMode(GrabbingMode newGrabbingMode)
|
||||
{
|
||||
if (newGrabbingMode == _previousGrabbingMode)
|
||||
{
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
|
||||
switch (newGrabbingMode)
|
||||
{
|
||||
case GRABBINGMODE_VIDEO:
|
||||
std::cout << "XBMC checker: switching to VIDEO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_PHOTO:
|
||||
std::cout << "XBMC checker: switching to PHOTO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_AUDIO:
|
||||
std::cout << "XBMC checker: switching to AUDIO mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_MENU:
|
||||
std::cout << "XBMC checker: switching to MENU mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_OFF:
|
||||
std::cout << "XBMC checker: switching to OFF mode" << std::endl;
|
||||
break;
|
||||
case GRABBINGMODE_INVALID:
|
||||
std::cout << "XBMC checker: switching to INVALID mode" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// only emit the new state when we want to grab in screensaver mode or when the screensaver is deactivated
|
||||
if (!_previousScreensaverMode)
|
||||
{
|
||||
emit grabbingMode(newGrabbingMode);
|
||||
}
|
||||
_previousGrabbingMode = newGrabbingMode;
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::setScreensaverMode(bool isOnScreensaver)
|
||||
{
|
||||
if (isOnScreensaver == _previousScreensaverMode)
|
||||
{
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
|
||||
emit grabbingMode(isOnScreensaver ? GRABBINGMODE_OFF : _previousGrabbingMode);
|
||||
_previousScreensaverMode = isOnScreensaver;
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::setVideoMode(VideoMode newVideoMode)
|
||||
{
|
||||
if (newVideoMode == _previousVideoMode)
|
||||
{
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
|
||||
switch (newVideoMode)
|
||||
{
|
||||
case VIDEO_2D:
|
||||
std::cout << "XBMC checker: switching to 2D mode" << std::endl;
|
||||
break;
|
||||
case VIDEO_3DSBS:
|
||||
std::cout << "XBMC checker: switching to 3D SBS mode" << std::endl;
|
||||
break;
|
||||
case VIDEO_3DTAB:
|
||||
std::cout << "XBMC checker: switching to 3D TAB mode" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
emit videoMode(newVideoMode);
|
||||
_previousVideoMode = newVideoMode;
|
||||
}
|
||||
|
Reference in New Issue
Block a user