00001 #include <QStringList>
00002
00003 using namespace std;
00004
00005 #include "compat.h"
00006 #include "playbacksock.h"
00007 #include "programinfo.h"
00008 #include "mainserver.h"
00009
00010 #include "mythcorecontext.h"
00011 #include "mythmiscutil.h"
00012 #include "inputinfo.h"
00013
00014 #define LOC QString("PlaybackSock: ")
00015 #define LOC_ERR QString("PlaybackSock, Error: ")
00016
00017 PlaybackSock::PlaybackSock(MainServer *parent, MythSocket *lsock,
00018 QString lhostname, PlaybackSockEventsMode eventsMode)
00019 {
00020 m_parent = parent;
00021 QString localhostname = gCoreContext->GetHostName();
00022
00023 refCount = 0;
00024
00025 sock = lsock;
00026 hostname = lhostname;
00027 m_eventsMode = eventsMode;
00028 ip = "";
00029 backend = false;
00030 mediaserver = false;
00031 expectingreply = false;
00032
00033 disconnected = false;
00034 blockshutdown = true;
00035
00036 if (hostname == localhostname)
00037 local = true;
00038 else
00039 local = false;
00040 }
00041
00042 PlaybackSock::~PlaybackSock()
00043 {
00044 sock->DownRef();
00045 }
00046
00047 void PlaybackSock::UpRef(void)
00048 {
00049 QMutexLocker locker(&refLock);
00050 refCount++;
00051 }
00052
00053 bool PlaybackSock::DownRef(void)
00054 {
00055 QMutexLocker locker(&refLock);
00056
00057 refCount--;
00058 if (refCount < 0)
00059 {
00060 m_parent->DeletePBS(this);
00061 return true;
00062 }
00063 return false;
00064 }
00065
00066 bool PlaybackSock::wantsEvents(void) const
00067 {
00068 return (m_eventsMode != kPBSEvents_None);
00069 }
00070
00071 bool PlaybackSock::wantsNonSystemEvents(void) const
00072 {
00073 return ((m_eventsMode == kPBSEvents_Normal) ||
00074 (m_eventsMode == kPBSEvents_NonSystem));
00075 }
00076
00077 bool PlaybackSock::wantsSystemEvents(void) const
00078 {
00079 return ((m_eventsMode == kPBSEvents_Normal) ||
00080 (m_eventsMode == kPBSEvents_SystemOnly));
00081 }
00082
00083 bool PlaybackSock::wantsOnlySystemEvents(void) const
00084 {
00085 return (m_eventsMode == kPBSEvents_SystemOnly);
00086 }
00087
00088 PlaybackSockEventsMode PlaybackSock::eventsMode(void) const
00089 {
00090 return m_eventsMode;
00091 }
00092
00093 bool PlaybackSock::SendReceiveStringList(
00094 QStringList &strlist, uint min_reply_length)
00095 {
00096 bool ok = false;
00097
00098 sock->Lock();
00099 sock->UpRef();
00100
00101 {
00102 QMutexLocker locker(&sockLock);
00103 expectingreply = true;
00104
00105 sock->writeStringList(strlist);
00106 ok = sock->readStringList(strlist);
00107
00108 while (ok && strlist[0] == "BACKEND_MESSAGE")
00109 {
00110
00111 if (strlist.size() >= 2)
00112 {
00113 QString message = strlist[1];
00114 strlist.pop_front();
00115 strlist.pop_front();
00116 MythEvent me(message, strlist);
00117 gCoreContext->dispatch(me);
00118 }
00119
00120 ok = sock->readStringList(strlist);
00121 }
00122
00123 expectingreply = false;
00124 }
00125
00126 sock->Unlock();
00127 sock->DownRef();
00128
00129 if (!ok)
00130 {
00131 LOG(VB_GENERAL, LOG_ERR,
00132 "PlaybackSock::SendReceiveStringList(): No response.");
00133 return false;
00134 }
00135
00136 if (min_reply_length && ((uint)strlist.size() < min_reply_length))
00137 {
00138 LOG(VB_GENERAL, LOG_ERR,
00139 "PlaybackSock::SendReceiveStringList(): Response too short");
00140 return false;
00141 }
00142
00143 return true;
00144 }
00145
00148 bool PlaybackSock::GoToSleep(void)
00149 {
00150 QStringList strlist(QString("GO_TO_SLEEP"));
00151
00152 return SendReceiveStringList(strlist, 1) && (strlist[0] == "OK");
00153 }
00154
00158 void PlaybackSock::GetDiskSpace(QStringList &o_strlist)
00159 {
00160 QStringList strlist(QString("QUERY_FREE_SPACE"));
00161
00162 SendReceiveStringList(strlist);
00163
00164 o_strlist += strlist;
00165
00166 }
00167
00168 int PlaybackSock::CheckRecordingActive(const ProgramInfo *pginfo)
00169 {
00170 QStringList strlist(QString("CHECK_RECORDING"));
00171 pginfo->ToStringList(strlist);
00172
00173 if (SendReceiveStringList(strlist, 1))
00174 return strlist[0].toInt();
00175
00176 return 0;
00177 }
00178
00179 int PlaybackSock::DeleteFile(const QString &filename, const QString &sgroup)
00180 {
00181 QStringList strlist("DELETE_FILE");
00182 strlist << filename;
00183 strlist << sgroup;
00184
00185 if (SendReceiveStringList(strlist, 1))
00186 return strlist[0].toInt();
00187
00188 return 0;
00189 }
00190
00191 int PlaybackSock::StopRecording(const ProgramInfo *pginfo)
00192 {
00193 QStringList strlist(QString("STOP_RECORDING"));
00194 pginfo->ToStringList(strlist);
00195
00196 if (SendReceiveStringList(strlist, 1))
00197 return strlist[0].toInt();
00198
00199 return 0;
00200 }
00201
00202 int PlaybackSock::DeleteRecording(const ProgramInfo *pginfo,
00203 bool forceMetadataDelete)
00204 {
00205 QStringList strlist;
00206
00207 if (forceMetadataDelete)
00208 strlist = QStringList( QString("FORCE_DELETE_RECORDING"));
00209 else
00210 strlist = QStringList( QString("DELETE_RECORDING"));
00211
00212 pginfo->ToStringList(strlist);
00213
00214 if (SendReceiveStringList(strlist, 1))
00215 return strlist[0].toInt();
00216
00217 return 0;
00218 }
00219
00220 bool PlaybackSock::FillProgramInfo(ProgramInfo &pginfo,
00221 const QString &playbackhost)
00222 {
00223 QStringList strlist(QString("FILL_PROGRAM_INFO"));
00224 strlist << playbackhost;
00225 pginfo.ToStringList(strlist);
00226
00227 if (SendReceiveStringList(strlist))
00228 {
00229 ProgramInfo tmp(strlist);
00230 if (tmp.HasPathname() || tmp.GetChanID())
00231 {
00232 pginfo.clone(tmp, true);
00233 return true;
00234 }
00235 }
00236
00237 return false;
00238 }
00239
00240 QStringList PlaybackSock::GetSGFileList(QString &host, QString &groupname,
00241 QString &directory, bool fileNamesOnly)
00242 {
00243 QStringList strlist(QString("QUERY_SG_GETFILELIST"));
00244 strlist << host;
00245 strlist << groupname;
00246 strlist << directory;
00247 strlist << QString::number(fileNamesOnly);
00248
00249 SendReceiveStringList(strlist);
00250
00251 return strlist;
00252 }
00253
00254 QStringList PlaybackSock::GetSGFileQuery(QString &host, QString &groupname,
00255 QString &filename)
00256 {
00257 QStringList strlist(QString("QUERY_SG_FILEQUERY"));
00258 strlist << host;
00259 strlist << groupname;
00260 strlist << filename;
00261
00262 SendReceiveStringList(strlist);
00263
00264 return strlist;
00265 }
00266
00267 QString PlaybackSock::GetFileHash(QString filename, QString storageGroup)
00268 {
00269 QStringList strlist(QString("QUERY_FILE_HASH"));
00270 strlist << filename
00271 << storageGroup;
00272
00273 SendReceiveStringList(strlist);
00274 return strlist[0];
00275 }
00276
00277 QStringList PlaybackSock::GenPreviewPixmap(const QString &token,
00278 const ProgramInfo *pginfo)
00279 {
00280 QStringList strlist(QString("QUERY_GENPIXMAP2"));
00281 strlist += token;
00282 pginfo->ToStringList(strlist);
00283
00284 SendReceiveStringList(strlist);
00285
00286 return strlist;
00287 }
00288
00289 QStringList PlaybackSock::GenPreviewPixmap(const QString &token,
00290 const ProgramInfo *pginfo,
00291 bool time_fmt_sec,
00292 long long time,
00293 const QString &outputFile,
00294 const QSize &outputSize)
00295 {
00296 QStringList strlist(QString("QUERY_GENPIXMAP2"));
00297 strlist += token;
00298 pginfo->ToStringList(strlist);
00299 strlist.push_back(time_fmt_sec ? "s" : "f");
00300 strlist.push_back(QString::number(time));
00301 strlist.push_back((outputFile.isEmpty()) ? "<EMPTY>" : outputFile);
00302 strlist.push_back(QString::number(outputSize.width()));
00303 strlist.push_back(QString::number(outputSize.height()));
00304
00305 SendReceiveStringList(strlist);
00306
00307 return strlist;
00308 }
00309
00310 QDateTime PlaybackSock::PixmapLastModified(const ProgramInfo *pginfo)
00311 {
00312 QStringList strlist(QString("QUERY_PIXMAP_LASTMODIFIED"));
00313 pginfo->ToStringList(strlist);
00314
00315 SendReceiveStringList(strlist);
00316
00317 QDateTime datetime;
00318 if (!strlist.empty() && strlist[0] != "BAD")
00319 {
00320 uint timet = strlist[0].toUInt();
00321 datetime.setTime_t(timet);
00322 }
00323 return datetime;
00324 }
00325
00326 bool PlaybackSock::CheckFile(ProgramInfo *pginfo)
00327 {
00328 QStringList strlist("QUERY_CHECKFILE");
00329 strlist << QString::number(0);
00330 pginfo->ToStringList(strlist);
00331
00332 if (SendReceiveStringList(strlist, 2))
00333 {
00334 pginfo->SetPathname(strlist[1]);
00335 return strlist[0].toInt();
00336 }
00337
00338 return false;
00339 }
00340
00341 bool PlaybackSock::IsBusy(int capturecardnum, InputInfo *busy_input,
00342 int time_buffer)
00343 {
00344 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00345
00346 strlist << "IS_BUSY";
00347 strlist << QString::number(time_buffer);
00348
00349 if (!SendReceiveStringList(strlist, 1))
00350 {
00351 LOG(VB_GENERAL, LOG_ERR, LOC + "IsBusy: " +
00352 QString("QUERY_REMOTEENCODER %1").arg(capturecardnum) +
00353 " gave us no response.");
00354 }
00355
00356 bool state = false;
00357
00358 if (!strlist.isEmpty())
00359 {
00360 QStringList::const_iterator it = strlist.begin();
00361 state = (*it).toInt();
00362
00363 if (busy_input)
00364 {
00365 ++it;
00366 if (!busy_input->FromStringList(it, strlist.end()))
00367 {
00368 LOG(VB_GENERAL, LOG_ERR, LOC + "IsBusy: "
00369 "Failed to parse response to " +
00370 QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00371 state = false;
00372
00373 }
00374 }
00375 }
00376
00377 return state;
00378 }
00379
00384 int PlaybackSock::GetEncoderState(int capturecardnum)
00385 {
00386 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00387 strlist << "GET_STATE";
00388
00389 if (!SendReceiveStringList(strlist, 1))
00390 {
00391 LOG(VB_GENERAL, LOG_ERR, LOC + "GetEncoderState: " +
00392 QString("QUERY_REMOTEENCODER %1").arg(capturecardnum) +
00393 " gave us no response.");
00394
00395 return kState_Error;
00396 }
00397
00398 return strlist[0].toInt();
00399 }
00400
00401 long long PlaybackSock::GetMaxBitrate(int capturecardnum)
00402 {
00403 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00404 strlist << "GET_MAX_BITRATE";
00405
00406 if (SendReceiveStringList(strlist, 2))
00407 return strlist[0].toLongLong();
00408
00409 return 20200000LL;
00410 }
00411
00416 ProgramInfo *PlaybackSock::GetRecording(uint cardid)
00417 {
00418 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(cardid));
00419 strlist << "GET_CURRENT_RECORDING";
00420
00421 if (!SendReceiveStringList(strlist))
00422 return NULL;
00423
00424 ProgramInfo *pginfo = new ProgramInfo(strlist);
00425 if (!pginfo->HasPathname() && !pginfo->GetChanID())
00426 {
00427 delete pginfo;
00428 pginfo = NULL;
00429 }
00430
00431 return pginfo;
00432 }
00433
00434 bool PlaybackSock::EncoderIsRecording(int capturecardnum,
00435 const ProgramInfo *pginfo)
00436 {
00437 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00438 strlist << "MATCHES_RECORDING";
00439 pginfo->ToStringList(strlist);
00440
00441 if (SendReceiveStringList(strlist, 1))
00442 return (bool) strlist[0].toInt();
00443
00444 return false;
00445 }
00446
00447 RecStatusType PlaybackSock::StartRecording(int capturecardnum,
00448 const ProgramInfo *pginfo)
00449 {
00450 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00451 strlist << "START_RECORDING";
00452 pginfo->ToStringList(strlist);
00453
00454 if (SendReceiveStringList(strlist, 1))
00455 return RecStatusType(strlist[0].toInt());
00456
00457 return rsUnknown;
00458 }
00459
00460 RecStatusType PlaybackSock::GetRecordingStatus(int capturecardnum)
00461 {
00462 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00463 strlist << "GET_RECORDING_STATUS";
00464
00465 if (!SendReceiveStringList(strlist, 1))
00466 {
00467 LOG(VB_GENERAL, LOG_ERR, LOC + "GetRecordingStatus: " +
00468 QString("QUERY_REMOTEENCODER %1").arg(capturecardnum) +
00469 " did not respond.");
00470
00471 return rsUnknown;
00472 }
00473
00474 return RecStatusType(strlist[0].toInt());
00475 }
00476
00477 void PlaybackSock::RecordPending(int capturecardnum, const ProgramInfo *pginfo,
00478 int secsleft, bool hasLater)
00479 {
00480 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00481 strlist << "RECORD_PENDING";
00482 strlist << QString::number(secsleft);
00483 strlist << QString::number(hasLater);
00484 pginfo->ToStringList(strlist);
00485
00486 SendReceiveStringList(strlist);
00487 }
00488
00489 int PlaybackSock::SetSignalMonitoringRate(int capturecardnum,
00490 int rate, int notifyFrontend)
00491 {
00492 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00493 strlist << "SET_SIGNAL_MONITORING_RATE";
00494 strlist << QString::number(rate);
00495 strlist << QString::number(notifyFrontend);
00496
00497 if (SendReceiveStringList(strlist, 1))
00498 return strlist[0].toInt();
00499
00500 return -1;
00501 }
00502
00503 void PlaybackSock::SetNextLiveTVDir(int capturecardnum, QString dir)
00504 {
00505 QStringList strlist(QString("SET_NEXT_LIVETV_DIR %1 %2")
00506 .arg(capturecardnum)
00507 .arg(dir));
00508
00509 SendReceiveStringList(strlist);
00510 }
00511
00512 vector<InputInfo> PlaybackSock::GetFreeInputs(int capturecardnum,
00513 const vector<uint> &excluded_cardids)
00514 {
00515 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(capturecardnum));
00516 strlist << "GET_FREE_INPUTS";
00517
00518 for (uint i = 0; i < excluded_cardids.size(); i++)
00519 strlist << QString::number(excluded_cardids[i]);
00520
00521 SendReceiveStringList(strlist);
00522
00523 vector<InputInfo> list;
00524
00525 QStringList::const_iterator it = strlist.begin();
00526 if ((it == strlist.end()) || (*it == "EMPTY_LIST"))
00527 return list;
00528
00529 while (it != strlist.end())
00530 {
00531 InputInfo info;
00532 if (!info.FromStringList(it, strlist.end()))
00533 break;
00534 list.push_back(info);
00535 }
00536
00537 return list;
00538 }
00539
00540 void PlaybackSock::CancelNextRecording(int capturecardnum, bool cancel)
00541 {
00542 QStringList strlist(QString("QUERY_REMOTEENCODER %1")
00543 .arg(capturecardnum));
00544
00545 strlist << "CANCEL_NEXT_RECORDING";
00546 strlist << QString::number(cancel);
00547
00548 SendReceiveStringList(strlist);
00549 }
00550
00551 QStringList PlaybackSock::ForwardRequest(const QStringList &slist)
00552 {
00553 QStringList strlist = slist;
00554
00555 if (SendReceiveStringList(strlist))
00556 return strlist;
00557
00558 return QStringList();
00559 }
00560
00561