18 #define LOC QString("CetonRTSP(%1): ").arg(m_requestUrl.toString()) 46 const QString &method,
const QStringList* headers,
47 bool use_control,
bool waitforanswer,
const QString &alternative)
66 QAbstractSocket::ReadWrite);
67 bool ok =
m_socket->waitForConnected();
71 LOG(VB_GENERAL, LOG_ERR,
LOC +
72 QString(
"Could not connect to server %1:%2")
87 trash.resize(std::max((
uint)trash.size(), avail));
91 while (
m_socket->bytesAvailable() > 0);
94 QStringList requestHeaders;
95 requestHeaders.append(QString(
"%1 %2 RTSP/1.0")
97 .arg(alternative.size() ? alternative :
99 requestHeaders.append(QString(
"User-Agent: MythTV Ceton Recorder"));
102 requestHeaders.append(QString(
"Session: %1").arg(
m_sessionId));
103 if (headers !=
nullptr)
105 for(
int i = 0; i < headers->count(); i++)
107 const QString& header = headers->at(i);
108 requestHeaders.append(header);
111 requestHeaders.append(QString(
"\r\n"));
112 QString request = requestHeaders.join(
"\r\n");
115 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"write: %1").arg(request));
116 m_socket->write(request.toLatin1());
124 QRegExp firstLineRegex(
125 "^RTSP/1.0 (\\d+) ([^\r\n]+)", Qt::CaseSensitive, QRegExp::RegExp2);
127 "^([^:]+):\\s*([^\\r\\n]+)", Qt::CaseSensitive, QRegExp::RegExp2);
128 QRegExp blankLineRegex(
129 "^[\\r\\n]*$", Qt::CaseSensitive, QRegExp::RegExp2);
131 bool firstLine =
true;
136 bool ready =
m_socket->waitForReadyRead(30 * 1000);
139 LOG(VB_RECORD, LOG_ERR,
LOC +
"RTSP server did not respond after 30s");
145 QString line =
m_socket->readLine();
146 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"read: %1").arg(line));
150 if (firstLineRegex.indexIn(line) == -1)
154 QString(
"Could not parse first line of response: '%1'")
159 QStringList parts = firstLineRegex.capturedTexts();
166 QString(
"Server couldn't process the request: '%1'")
174 if (blankLineRegex.indexIn(line) != -1)
break;
176 if (headerRegex.indexIn(line) == -1)
183 QStringList parts = headerRegex.capturedTexts();
199 if (key.compare(
"CSeq", Qt::CaseInsensitive) == 0)
208 LOG(VB_RECORD, LOG_WARNING,
LOC +
209 QString(
"Expected CSeq of %1 but got %2")
215 if (contentLength > 0)
220 while (bytesRead < contentLength)
222 if (
m_socket->bytesAvailable() == 0)
225 int count =
m_socket->read(data+bytesRead, contentLength-bytesRead);
234 LOG(VB_RECORD, LOG_DEBUG,
LOC +
258 QTextStream stream(lines);
263 line = stream.readLine();
269 while (!line.isNull());
289 for (
int i = 0; i < header.size(); i++)
291 QString entry = header[i].trimmed();
298 QStringList
args = entry.split(
"=");
300 parameters.insert(
args[0].trimmed(),
301 args.size() > 1 ?
args[1].trimmed() : QString());
326 headers.append(
"Accept: application/sdp");
336 foreach (QString line, lines)
338 if (line.startsWith(
"m="))
345 if (!line.startsWith(
"m=video"))
350 QStringList
args = line.split(
" ");
351 if (
args[2] ==
"RTP/AVP" &&
args[3] ==
"33")
357 if (line.startsWith(
"c="))
363 if (line.startsWith(
"a=control:"))
368 QString url = line.mid(10).trimmed();
384 LOG(VB_RECORD, LOG_ERR,
LOC +
"expected content to be type " 385 "\"m=video 0 RTP/AVP 33\" but it appears not to be");
394 ushort &rtpPort, ushort &rtcpPort,
397 LOG(VB_GENERAL, LOG_INFO, QString(
"CetonRTSP: ") +
398 QString(
"Transport: RTP/AVP;unicast;client_port=%1-%2")
399 .arg(clientPort1).arg(clientPort2));
401 QStringList extraHeaders;
403 QString(
"Transport: RTP/AVP;unicast;client_port=%1-%2")
404 .arg(clientPort1).arg(clientPort2));
412 if (session.isEmpty())
414 LOG(VB_RECORD, LOG_ERR,
LOC +
415 "session id not found in SETUP response");
418 if (session.size() < 8)
420 LOG(VB_RECORD, LOG_WARNING,
LOC +
421 "invalid session id received");
425 if (params.contains(
"timeout"))
432 if (params.contains(
"ssrc"))
435 ssrc = params[
"ssrc"].toUInt(&ok, 16);
437 if (params.contains(
"server_port"))
439 QString line = params[
"server_port"];
440 QStringList val = line.split(
"-");
442 rtpPort = val[0].toInt();
443 rtcpPort = val.size() > 1 ? val[1].toInt() : 0;
477 LOG(VB_RECORD, LOG_DEBUG,
LOC +
478 QString(
"Start KeepAlive, every %1s").arg(
timeout));
487 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Stop KeepAlive");
496 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Sending KeepAlive");
QUrl GetBaseUrl(void)
Return the base URL for the last DESCRIBE answer.
QString readParameters(const QString &key, Params ¶meters)
readParameters.
bool Setup(ushort clientPort1, ushort clientPort2, ushort &rtpPort, ushort &rtcpPort, uint32_t &ssrc)
QString m_responseMessage
void timerEvent(QTimerEvent *) override
static QStringList splitLines(const QByteArray &lines)
splitLines.
bool GetOptions(QStringList &options)
CetonRTSP(const QString &ip, uint tuner, ushort port)
QByteArray m_responseContent
#define LOG(_MASK_, _LEVEL_, _STRING_)
bool ProcessRequest(const QString &method, const QStringList *headers=nullptr, bool use_control=false, bool waitforanswer=true, const QString &alternative=QString())
#define LOC
-*- Mode: c++ -*- CetonRTSP Copyright (c) 2011 Ronald Frazier Distributed as part of MythTV under GPL...
QMap< QString, QString > Params
void StartKeepAlive(void)
static QMutex s_rtspMutex