mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
New XBMC checker functionality: 3D video detection (filename based) and screensaver detection
Former-commit-id: ea95e4ecde3ab9378bdf9c4c60950713947bd0ac
This commit is contained in:
@@ -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;
|
||||
}
|
||||
disconnected();
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::receiveReply()
|
||||
@@ -54,62 +52,195 @@ 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;
|
||||
|
||||
// try to connect
|
||||
_socket.connectToHost(_address, _port);
|
||||
}
|
||||
|
||||
void XBMCVideoChecker::connectionError(QAbstractSocket::SocketError)
|
||||
{
|
||||
std::cout << "XBMC Connection error" << std::endl;
|
||||
|
||||
// try to connect again in 1 second
|
||||
QTimer::singleShot(1000, this, SLOT(disconnected()));
|
||||
}
|
||||
|
||||
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