00001 #include <unistd.h>
00002
00003 #include <QStringList>
00004
00005 #include "remoteencoder.h"
00006 #include "programinfo.h"
00007 #include "mythmiscutil.h"
00008 #include "mythcorecontext.h"
00009 #include "signalmonitor.h"
00010 #include "videooutbase.h"
00011 #include "mythdb.h"
00012 #include "mythsocket.h"
00013 #include "mythlogging.h"
00014
00015 using namespace std;
00016
00017 #define LOC QString("RemoteEncoder(%1): ").arg(recordernum)
00018
00019 RemoteEncoder::RemoteEncoder(int num, const QString &host, short port)
00020 : recordernum(num), controlSock(NULL), remotehost(host),
00021 remoteport(port), lastchannel(""), lastinput(""),
00022 backendError(false), cachedFramesWritten(0)
00023 {
00024 }
00025
00026 RemoteEncoder::~RemoteEncoder()
00027 {
00028 if (controlSock)
00029 controlSock->DownRef();
00030 }
00031
00032 bool RemoteEncoder::Setup(void)
00033 {
00034 if (!controlSock)
00035 {
00036 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Connecting...");
00037
00038 QString ann = QString("ANN Playback %1 %2")
00039 .arg(gCoreContext->GetHostName()).arg(false);
00040
00041 controlSock = gCoreContext->ConnectCommandSocket(
00042 remotehost, remoteport, ann);
00043
00044 if (controlSock)
00045 {
00046 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Connected");
00047 }
00048 else
00049 {
00050 LOG(VB_GENERAL, LOG_ERR,
00051 "RemoteEncoder::Setup(): Failed to connect to backend");
00052 }
00053 }
00054 else
00055 {
00056 LOG(VB_NETWORK, LOG_DEBUG, "RemoteEncoder::Setup(): Already connected");
00057 }
00058 return controlSock;
00059 }
00060
00061 bool RemoteEncoder::IsValidRecorder(void) const
00062 {
00063 return (recordernum >= 0);
00064 }
00065
00066 int RemoteEncoder::GetRecorderNumber(void) const
00067 {
00068 return recordernum;
00069 }
00070
00071 bool RemoteEncoder::SendReceiveStringList(
00072 QStringList &strlist, uint min_reply_length)
00073 {
00074 QMutexLocker locker(&lock);
00075 if (!controlSock)
00076 Setup();
00077
00078 backendError = false;
00079
00080 if (!controlSock)
00081 {
00082 LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): "
00083 "Failed to reconnect with backend.");
00084 backendError = true;
00085 return false;
00086 }
00087
00088 if (!controlSock->writeStringList(strlist))
00089 {
00090 LOG(VB_GENERAL, LOG_ERR, "RemoteEncoder::SendReceiveStringList(): "
00091 "Failed to write data.");
00092 backendError = true;
00093 }
00094
00095 if (!backendError &&
00096 !controlSock->readStringList(strlist, MythSocket::kShortTimeout))
00097 {
00098 LOG(VB_GENERAL, LOG_ERR,
00099 "RemoteEncoder::SendReceiveStringList(): No response.");
00100 backendError = true;
00101 }
00102
00103 if (!backendError &&
00104 min_reply_length && ((uint)strlist.size() < min_reply_length))
00105 {
00106 LOG(VB_GENERAL, LOG_ERR,
00107 "RemoteEncoder::SendReceiveStringList(): Response too short");
00108 backendError = true;
00109 }
00110
00111 if (backendError)
00112 {
00113 controlSock->DownRef();
00114 controlSock = NULL;
00115 return false;
00116 }
00117
00118 return true;
00119 }
00120
00121 bool RemoteEncoder::IsRecording(bool *ok)
00122 {
00123 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00124 strlist << "IS_RECORDING";
00125
00126 bool ret = SendReceiveStringList(strlist, 1);
00127 if (!ret)
00128 {
00129 if (ok)
00130 *ok = false;
00131
00132 return false;
00133 }
00134
00135 if (ok)
00136 *ok = true;
00137
00138 return strlist[0].toInt();
00139 }
00140
00141 ProgramInfo *RemoteEncoder::GetRecording(void)
00142 {
00143 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00144 strlist << "GET_RECORDING";
00145
00146 if (SendReceiveStringList(strlist))
00147 {
00148 ProgramInfo *proginfo = new ProgramInfo(strlist);
00149 if (proginfo->GetChanID())
00150 return proginfo;
00151 delete proginfo;
00152 }
00153
00154 return NULL;
00155 }
00156
00163 float RemoteEncoder::GetFrameRate(void)
00164 {
00165 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00166 strlist << "GET_FRAMERATE";
00167
00168 bool ok = false;
00169 float retval = 30.0f;
00170
00171 if (SendReceiveStringList(strlist, 1))
00172 {
00173 retval = strlist[0].toFloat(&ok);
00174
00175 if (!ok)
00176 {
00177 LOG(VB_GENERAL, LOG_ERR, LOC +
00178 QString("GetFrameRate() failed to parse response '%1'")
00179 .arg(strlist[0]));
00180 }
00181 }
00182 else
00183 {
00184 LOG(VB_GENERAL, LOG_ERR, LOC +
00185 "GetFrameRate(): SendReceiveStringList() failed");
00186 }
00187
00188 return (ok) ? retval : 30.0f;
00189 }
00190
00198 long long RemoteEncoder::GetFramesWritten(void)
00199 {
00200 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00201 strlist << "GET_FRAMES_WRITTEN";
00202
00203 if (!SendReceiveStringList(strlist, 1))
00204 {
00205 LOG(VB_GENERAL, LOG_ERR, LOC + "GetFramesWritten() -- network error");
00206 return -1;
00207 }
00208
00209 cachedFramesWritten = strlist[0].toLongLong();
00210 return cachedFramesWritten;
00211 }
00212
00219 long long RemoteEncoder::GetFilePosition(void)
00220 {
00221 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00222 strlist << "GET_FILE_POSITION";
00223
00224 if (SendReceiveStringList(strlist, 1))
00225 return strlist[0].toLongLong();
00226
00227 return -1;
00228 }
00229
00234 long long RemoteEncoder::GetMaxBitrate(void)
00235 {
00236 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00237 strlist << "GET_MAX_BITRATE";
00238
00239 if (SendReceiveStringList(strlist, 1))
00240 return strlist[0].toLongLong();
00241
00242 return 20200000LL;
00243 }
00244
00252 int64_t RemoteEncoder::GetKeyframePosition(uint64_t desired)
00253 {
00254 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00255 strlist << "GET_KEYFRAME_POS";
00256 strlist << QString::number(desired);
00257
00258 if (SendReceiveStringList(strlist, 1))
00259 return strlist[0].toLongLong();
00260
00261 return -1;
00262 }
00263
00264 void RemoteEncoder::FillPositionMap(long long start, long long end,
00265 QMap<long long, long long> &positionMap)
00266 {
00267 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00268 strlist << "FILL_POSITION_MAP";
00269 strlist << QString::number(start);
00270 strlist << QString::number(end);
00271
00272 if (!SendReceiveStringList(strlist))
00273 return;
00274
00275 QStringList::const_iterator it = strlist.begin();
00276 for (; it != strlist.end(); ++it)
00277 {
00278 bool ok;
00279 long long index = (*it).toLongLong(&ok);
00280 if (++it == strlist.end() || !ok)
00281 break;
00282
00283 long long pos = (*it).toLongLong(&ok);
00284 if (!ok)
00285 break;
00286
00287 positionMap[index] = pos;
00288 }
00289 }
00290
00291 void RemoteEncoder::CancelNextRecording(bool cancel)
00292 {
00293 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00294 strlist << "CANCEL_NEXT_RECORDING";
00295 strlist << QString::number((cancel) ? 1 : 0);
00296
00297 SendReceiveStringList(strlist);
00298 }
00299
00300 void RemoteEncoder::FrontendReady(void)
00301 {
00302 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00303 strlist << "FRONTEND_READY";
00304
00305 SendReceiveStringList(strlist);
00306 }
00307
00312 void RemoteEncoder::StopPlaying(void)
00313 {
00314 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00315 strlist << "STOP_PLAYING";
00316
00317 SendReceiveStringList(strlist);
00318 }
00319
00325 void RemoteEncoder::SpawnLiveTV(QString chainId, bool pip, QString startchan)
00326 {
00327 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00328 strlist << "SPAWN_LIVETV";
00329 strlist << chainId;
00330 strlist << QString::number((int)pip);
00331 strlist << startchan;
00332
00333 SendReceiveStringList(strlist);
00334 }
00335
00341 void RemoteEncoder::StopLiveTV(void)
00342 {
00343 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00344 strlist << "STOP_LIVETV";
00345
00346 SendReceiveStringList(strlist);
00347 }
00348
00354 void RemoteEncoder::PauseRecorder(void)
00355 {
00356 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00357 strlist << "PAUSE";
00358
00359 if (SendReceiveStringList(strlist))
00360 lastinput = "";
00361 }
00362
00363 void RemoteEncoder::FinishRecording(void)
00364 {
00365 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00366 strlist << "FINISH_RECORDING";
00367
00368 SendReceiveStringList(strlist);
00369 }
00370
00371 void RemoteEncoder::SetLiveRecording(bool recording)
00372 {
00373 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00374 strlist << "SET_LIVE_RECORDING";
00375 strlist << QString::number(recording);
00376
00377 SendReceiveStringList(strlist);
00378 }
00379
00380 QString RemoteEncoder::GetInput(void)
00381 {
00382 if (!lastinput.isEmpty())
00383 return lastinput;
00384
00385 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00386 strlist << "GET_INPUT";
00387
00388 if (SendReceiveStringList(strlist, 1))
00389 {
00390 lastinput = strlist[0];
00391 return lastinput;
00392 }
00393
00394 return "Error";
00395 }
00396
00397 QString RemoteEncoder::SetInput(QString input)
00398 {
00399 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00400 strlist << "SET_INPUT";
00401 strlist << input;
00402
00403 if (SendReceiveStringList(strlist, 1))
00404 {
00405 lastchannel = "";
00406 lastinput = "";
00407 return strlist[0];
00408 }
00409
00410 return (lastinput.isEmpty()) ? "Error" : lastinput;
00411 }
00412
00413 void RemoteEncoder::ToggleChannelFavorite(QString changroupname)
00414 {
00415 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00416 strlist << "TOGGLE_CHANNEL_FAVORITE";
00417 strlist << changroupname;
00418
00419 SendReceiveStringList(strlist);
00420 }
00421
00422 void RemoteEncoder::ChangeChannel(int channeldirection)
00423 {
00424 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00425 strlist << "CHANGE_CHANNEL";
00426 strlist << QString::number(channeldirection);
00427
00428 if (!SendReceiveStringList(strlist))
00429 return;
00430
00431 lastchannel = "";
00432 lastinput = "";
00433 }
00434
00435 void RemoteEncoder::SetChannel(QString channel)
00436 {
00437 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00438 strlist << "SET_CHANNEL";
00439 strlist << channel;
00440
00441 if (!SendReceiveStringList(strlist))
00442 return;
00443
00444 lastchannel = "";
00445 lastinput = "";
00446 }
00447
00464 int RemoteEncoder::SetSignalMonitoringRate(int rate, bool notifyFrontend)
00465 {
00466 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00467 strlist << "SET_SIGNAL_MONITORING_RATE";
00468 strlist << QString::number(rate);
00469 strlist << QString::number((int)notifyFrontend);
00470
00471 if (SendReceiveStringList(strlist, 1))
00472 return strlist[0].toInt();
00473
00474 return 0;
00475 }
00476
00477 uint RemoteEncoder::GetSignalLockTimeout(QString input)
00478 {
00479 QMutexLocker locker(&lock);
00480
00481 QMap<QString,uint>::const_iterator it = cachedTimeout.find(input);
00482 if (it != cachedTimeout.end())
00483 return *it;
00484
00485 uint cardid = recordernum;
00486 uint timeout = 0xffffffff;
00487 MSqlQuery query(MSqlQuery::InitCon());
00488 query.prepare(
00489 "SELECT channel_timeout, cardtype "
00490 "FROM cardinput, capturecard "
00491 "WHERE cardinput.inputname = :INNAME AND "
00492 " cardinput.cardid = :CARDID AND "
00493 " cardinput.cardid = capturecard.cardid");
00494 query.bindValue(":INNAME", input);
00495 query.bindValue(":CARDID", cardid);
00496 if (!query.exec() || !query.isActive())
00497 MythDB::DBError("Getting timeout", query);
00498 else if (query.next() &&
00499 SignalMonitor::IsRequired(query.value(1).toString()))
00500 timeout = max(query.value(0).toInt(), 500);
00501
00502 #if 0
00503 LOG(VB_PLAYBACK, LOG_DEBUG, "RemoteEncoder: " +
00504 QString("GetSignalLockTimeout(%1): Set lock timeout to %2 ms")
00505 .arg(cardid).arg(timeout));
00506 #endif
00507 cachedTimeout[input] = timeout;
00508 return timeout;
00509 }
00510
00511
00512 int RemoteEncoder::GetPictureAttribute(PictureAttribute attr)
00513 {
00514 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00515
00516 if (kPictureAttribute_Contrast == attr)
00517 strlist << "GET_CONTRAST";
00518 else if (kPictureAttribute_Brightness == attr)
00519 strlist << "GET_BRIGHTNESS";
00520 else if (kPictureAttribute_Colour == attr)
00521 strlist << "GET_COLOUR";
00522 else if (kPictureAttribute_Hue == attr)
00523 strlist << "GET_HUE";
00524 else
00525 return -1;
00526
00527 if (SendReceiveStringList(strlist, 1))
00528 return strlist[0].toInt();
00529
00530 return -1;
00531 }
00532
00540 int RemoteEncoder::ChangePictureAttribute(
00541 PictureAdjustType type, PictureAttribute attr, bool up)
00542 {
00543 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00544
00545 if (kPictureAttribute_Contrast == attr)
00546 strlist << "CHANGE_CONTRAST";
00547 else if (kPictureAttribute_Brightness == attr)
00548 strlist << "CHANGE_BRIGHTNESS";
00549 else if (kPictureAttribute_Colour == attr)
00550 strlist << "CHANGE_COLOUR";
00551 else if (kPictureAttribute_Hue == attr)
00552 strlist << "CHANGE_HUE";
00553 else
00554 return -1;
00555
00556 strlist << QString::number(type);
00557 strlist << QString::number((int)up);
00558
00559 if (SendReceiveStringList(strlist, 1))
00560 return strlist[0].toInt();
00561
00562 return -1;
00563 }
00564
00565 void RemoteEncoder::ChangeDeinterlacer(int deint_mode)
00566 {
00567 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00568 strlist << "CHANGE_DEINTERLACER";
00569 strlist << QString::number((int)deint_mode);
00570
00571 SendReceiveStringList(strlist);
00572 }
00573
00583 bool RemoteEncoder::CheckChannel(QString channel)
00584 {
00585 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00586 strlist << "CHECK_CHANNEL";
00587 strlist << channel;
00588
00589 if (SendReceiveStringList(strlist, 1))
00590 return strlist[0].toInt();
00591
00592 return false;
00593 }
00594
00604 bool RemoteEncoder::ShouldSwitchToAnotherCard(QString channelid)
00605 {
00606
00607
00608
00609 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00610 strlist << "SHOULD_SWITCH_CARD";
00611 strlist << channelid;
00612
00613 if (SendReceiveStringList(strlist, 1))
00614 return strlist[0].toInt();
00615
00616 return false;
00617 }
00618
00625 bool RemoteEncoder::CheckChannelPrefix(
00626 const QString &prefix,
00627 uint &is_complete_valid_channel_on_rec,
00628 bool &is_extra_char_useful,
00629 QString &needed_spacer)
00630 {
00631 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00632 strlist << "CHECK_CHANNEL_PREFIX";
00633 strlist << prefix;
00634
00635 if (!SendReceiveStringList(strlist, 4))
00636 return false;
00637
00638 is_complete_valid_channel_on_rec = strlist[1].toInt();
00639 is_extra_char_useful = strlist[2].toInt();
00640 needed_spacer = (strlist[3] == "X") ? "" : strlist[3];
00641
00642 return strlist[0].toInt();
00643 }
00644
00645 static QString cleanup(const QString &str)
00646 {
00647 if (str == " ")
00648 return "";
00649 return str;
00650 }
00651
00652 static QString make_safe(const QString &str)
00653 {
00654 if (str.isEmpty())
00655 return " ";
00656 return str;
00657 }
00658
00665 void RemoteEncoder::GetNextProgram(int direction,
00666 QString &title, QString &subtitle,
00667 QString &desc, QString &category,
00668 QString &starttime, QString &endtime,
00669 QString &callsign, QString &iconpath,
00670 QString &channelname, QString &chanid,
00671 QString &seriesid, QString &programid)
00672 {
00673 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) );
00674 strlist << "GET_NEXT_PROGRAM_INFO";
00675 strlist << channelname;
00676 strlist << chanid;
00677 strlist << QString::number((int)direction);
00678 strlist << starttime;
00679
00680 if (!SendReceiveStringList(strlist, 12))
00681 return;
00682
00683 title = cleanup(strlist[0]);
00684 subtitle = cleanup(strlist[1]);
00685 desc = cleanup(strlist[2]);
00686 category = cleanup(strlist[3]);
00687 starttime = cleanup(strlist[4]);
00688 endtime = cleanup(strlist[5]);
00689 callsign = cleanup(strlist[6]);
00690 iconpath = cleanup(strlist[7]);
00691 channelname = cleanup(strlist[8]);
00692 chanid = cleanup(strlist[9]);
00693 seriesid = cleanup(strlist[10]);
00694 programid = cleanup(strlist[11]);
00695 }
00696
00697 void RemoteEncoder::GetChannelInfo(InfoMap &infoMap, uint chanid)
00698 {
00699 QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum));
00700 strlist << "GET_CHANNEL_INFO";
00701 strlist << QString::number(chanid);
00702
00703 if (!SendReceiveStringList(strlist, 6))
00704 return;
00705
00706 infoMap["chanid"] = cleanup(strlist[0]);
00707 infoMap["sourceid"] = cleanup(strlist[1]);
00708 infoMap["callsign"] = cleanup(strlist[2]);
00709 infoMap["channum"] = cleanup(strlist[3]);
00710 infoMap["channame"] = cleanup(strlist[4]);
00711 infoMap["XMLTV"] = cleanup(strlist[5]);
00712
00713 infoMap["oldchannum"] = infoMap["channum"];
00714 }
00715
00716 bool RemoteEncoder::SetChannelInfo(const InfoMap &infoMap)
00717 {
00718 QStringList strlist( "SET_CHANNEL_INFO" );
00719 strlist << make_safe(infoMap["chanid"]);
00720 strlist << make_safe(infoMap["sourceid"]);
00721 strlist << make_safe(infoMap["oldchannum"]);
00722 strlist << make_safe(infoMap["callsign"]);
00723 strlist << make_safe(infoMap["channum"]);
00724 strlist << make_safe(infoMap["channame"]);
00725 strlist << make_safe(infoMap["XMLTV"]);
00726
00727 if (SendReceiveStringList(strlist, 1))
00728 return strlist[0].toInt();
00729
00730 return false;
00731 }