12#include <QCoreApplication>
24#include "libmythbase/mythversion.h"
31static constexpr const char*
VERSION {
"1.0.0" };
32#define LOC QString("File(%1): ").arg(m_fileName)
35 int data_rate,
bool loopinput) :
36 m_parent(parent), m_fileName(
std::move(fname)),
37 m_loop(loopinput), m_dataRate(data_rate)
39 setObjectName(
"Streamer");
46 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::dtor -- begin");
48 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::dtor -- end");
56 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Failed to open '%1' - ")
63 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::Close -- begin");
71 LOG(VB_RECORD, LOG_INFO,
LOC +
"Streamer::Close -- end");
79 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- start");
83 LOG(VB_GENERAL, LOG_ERR,
LOC +
"SendBytes -- file not open");
103 read_sz = std::min(rate, read_sz);
104#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
112 QByteArray buffer =
m_file->read(read_sz);
114 pkt_size = buffer.size();
121 LOG(VB_RECORD, LOG_WARNING,
LOC +
122 QString(
"SendBytes -- Overflow: %1 > %2, "
123 "dropping first %3 bytes.")
134 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- Buffer is empty.");
139 LOG(VB_RECORD, LOG_DEBUG,
LOC +
140 QString(
"SendBytes -- Read %1 from file. %2 bytes buffered")
141 .arg(pkt_size).arg(buf_size));
144 write_len = std::min(write_len, buf_size);
145 LOG(VB_RECORD, LOG_DEBUG,
LOC +
146 QString(
"SendBytes -- writing %1 bytes").arg(write_len));
150 LOG(VB_RECORD, LOG_DEBUG,
LOC +
151 QString(
"SendBytes -- wrote %1 bytes").arg(wrote));
153 if (wrote < buf_size)
156 LOG(VB_RECORD, LOG_WARNING,
LOC +
157 QString(
"%1 bytes unwritten").arg(
m_buffer.size()));
164 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"SendBytes -- end");
170 setObjectName(
"Command");
175 QByteArray buf = status.toLatin1() +
'\n';
176 int len =
write(2, buf.constData(), buf.size());
177 if (len != buf.size())
179 LOG(VB_RECORD, LOG_ERR,
LOC +
180 QString(
"Status -- Wrote %1 of %2 bytes of status '%3'")
181 .arg(len).arg(status.size()).arg(status));
184 LOG(VB_RECORD, LOG_DEBUG,
"Status: " + status);
190 LOG(VB_RECORD, LOG_DEBUG,
LOC + cmd);
192 if (cmd.startsWith(
"Version?"))
197 if (cmd.startsWith(
"APIVersion?"))
202 if (cmd.startsWith(
"APIVersion:1"))
204 QString reply = (
API_VERSION == 1) ?
"OK:Yes":
"OK:No";
208 if (cmd.startsWith(
"HasLock?"))
213 if (cmd.startsWith(
"SignalStrengthPercent"))
218 if (cmd.startsWith(
"LockTimeout"))
223 if (cmd.startsWith(
"HasTuner?"))
228 if (cmd.startsWith(
"HasPictureAttributes?"))
237 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"%1 failed - not initialized!")
242 if (cmd.startsWith(
"SendBytes"))
247 LOG(VB_RECORD, LOG_ERR,
LOC +
"SendBytes - file not open.");
251 if (
m_eof.loadAcquire() != 0)
261 else if (cmd.startsWith(
"XON"))
265 else if (cmd.startsWith(
"XOFF"))
269 else if (cmd.startsWith(
"TuneChannel"))
278 else if (cmd.startsWith(
"IsOpen?"))
286 else if (cmd.startsWith(
"CloseRecorder"))
292 else if (cmd.startsWith(
"FlowControl?"))
296 else if (cmd.startsWith(
"BlockSize"))
301 else if (cmd.startsWith(
"StartStreaming"))
305 else if (cmd.startsWith(
"StopStreaming"))
314 send_status(QString(
"ERR:Unknown command '%1'").arg(cmd));
315 LOG(VB_RECORD, LOG_ERR,
LOC + QString(
"Unknown command '%1'")
327 std::array<struct pollfd,2> polls {};
330 polls[0].events = POLLIN | POLLPRI;
331 polls[0].revents = 0;
336 auto *streamThread =
new QThread(
this);
339 connect(streamThread, &QThread::finished,
345 streamThread->start();
348 input.open(stdin, QIODevice::ReadOnly);
349 QTextStream qtin(&input);
351 LOG(VB_RECORD, LOG_INFO,
LOC +
"Listening for commands");
355 int ret = poll(polls.data(), poll_cnt,
m_timeout);
357 if (polls[0].revents & POLLHUP)
359 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
362 if (polls[0].revents & POLLNVAL)
364 LOG(VB_RECORD, LOG_ERR,
LOC +
"poll error");
368 if (polls[0].revents & POLLIN)
372 cmd = qtin.readLine();
375 streamThread->quit();
376 streamThread->wait();
378 streamThread =
nullptr;
385 if ((EOVERFLOW == errno))
387 LOG(VB_RECORD, LOG_ERR,
LOC +
"command overflow.");
391 if ((EAGAIN == errno) || (EINTR == errno))
393 LOG(VB_RECORD, LOG_ERR,
LOC +
"retry command read.");
397 LOG(VB_RECORD, LOG_ERR,
LOC +
"unknown error reading command.");
406int main(
int argc,
char *argv[])
431 QCoreApplication a(argc, argv);
432 QCoreApplication::setApplicationName(
"mythfilerecorder");
bool process_command(QString &cmd)
bool send_status(const QString &status) const
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
static void PrintVersion(void)
Print application version information.
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
void PrintHelp(void) const
Print command line option help.
QString ErrorString(void) const
Streamer(Commands *parent, QString fname, int data_rate, bool loopinput)
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
MythCommFlagCommandLineParser cmdline
int main(int argc, char *argv[])
static constexpr int API_VERSION
static constexpr const char * VERSION
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
def write(text, progress=True)