MythTV  0.26-pre
remoteencoder.cpp
Go to the documentation of this file.
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; // Peek bit rate for HD-PVR
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     // this function returns true if the channelid is not a valid
00607     // channel on the current recorder. It queries to server in order
00608     // to determine this.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends