Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a bit different from stream handlers used for other recorders because the stream handler is tied to a bind address and port[s] instead of a recording device. The purpose is the same, to allow overlapping records. But in this case the stream handler is changed on every channel change.
- Loading branch information
1 parent
715c18c
commit 02768bd
Showing
5 changed files
with
257 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// -*- Mode: c++ -*- | ||
|
||
// Qt headers | ||
#include <QUdpSocket> | ||
|
||
// MythTV headers | ||
#include "iptvstreamhandler.h" | ||
#include "mythlogging.h" | ||
|
||
#define LOC QString("IPTVSH(%1): ").arg(_device) | ||
|
||
QMap<QString,IPTVStreamHandler*> IPTVStreamHandler::_handlers; | ||
QMap<QString,uint> IPTVStreamHandler::_handlers_refcnt; | ||
QMutex IPTVStreamHandler::_handlers_lock; | ||
|
||
IPTVStreamHandler *IPTVStreamHandler::Get(const QString &devname) | ||
{ | ||
QMutexLocker locker(&_handlers_lock); | ||
|
||
QString devkey = devname.toUpper(); | ||
|
||
QMap<QString,IPTVStreamHandler*>::iterator it = _handlers.find(devkey); | ||
|
||
if (it == _handlers.end()) | ||
{ | ||
IPTVStreamHandler *newhandler = new IPTVStreamHandler(devkey); | ||
newhandler->Open(); | ||
_handlers[devkey] = newhandler; | ||
_handlers_refcnt[devkey] = 1; | ||
|
||
LOG(VB_RECORD, LOG_INFO, | ||
QString("IPTVSH: Creating new stream handler %1 for %2") | ||
.arg(devkey).arg(devname)); | ||
} | ||
else | ||
{ | ||
_handlers_refcnt[devkey]++; | ||
uint rcount = _handlers_refcnt[devkey]; | ||
LOG(VB_RECORD, LOG_INFO, | ||
QString("IPTVSH: Using existing stream handler %1 for %2") | ||
.arg(devkey) | ||
.arg(devname) + QString(" (%1 in use)").arg(rcount)); | ||
} | ||
|
||
return _handlers[devkey]; | ||
} | ||
|
||
void IPTVStreamHandler::Return(IPTVStreamHandler * & ref) | ||
{ | ||
QMutexLocker locker(&_handlers_lock); | ||
|
||
QString devname = ref->_device; | ||
|
||
QMap<QString,uint>::iterator rit = _handlers_refcnt.find(devname); | ||
if (rit == _handlers_refcnt.end()) | ||
return; | ||
|
||
if (*rit > 1) | ||
{ | ||
ref = NULL; | ||
(*rit)--; | ||
return; | ||
} | ||
|
||
QMap<QString,IPTVStreamHandler*>::iterator it = _handlers.find(devname); | ||
if ((it != _handlers.end()) && (*it == ref)) | ||
{ | ||
LOG(VB_RECORD, LOG_INFO, QString("IPTVSH: Closing handler for %1") | ||
.arg(devname)); | ||
ref->Close(); | ||
delete *it; | ||
_handlers.erase(it); | ||
} | ||
else | ||
{ | ||
LOG(VB_GENERAL, LOG_ERR, | ||
QString("IPTVSH Error: Couldn't find handler for %1") | ||
.arg(devname)); | ||
} | ||
|
||
_handlers_refcnt.erase(rit); | ||
ref = NULL; | ||
} | ||
|
||
IPTVStreamHandler::IPTVStreamHandler(const QString &device) : | ||
StreamHandler(device) | ||
{ | ||
QStringList parts = device.split("!"); | ||
if (parts.size() >= 4) | ||
{ | ||
m_addr = QHostAddress(parts[0]); | ||
m_ports[0] = parts[1].toInt(); | ||
m_ports[1] = parts[2].toInt(); | ||
m_ports[2] = parts[3].toInt(); | ||
} | ||
else | ||
{ | ||
m_ports[0] = -1; | ||
m_ports[1] = -1; | ||
m_ports[2] = -1; | ||
} | ||
} | ||
|
||
void IPTVStreamHandler::run(void) | ||
{ | ||
RunProlog(); | ||
|
||
// Open our ports... | ||
// TODO Error handling.. | ||
for (uint i = 0; i < sizeof(m_ports)/sizeof(int); i++) | ||
{ | ||
if (m_ports[i] >= 0) | ||
{ | ||
m_sockets[i] = new QUdpSocket(); | ||
m_helpers[i] = new IPTVStreamHandlerHelper(this, m_sockets[i]); | ||
m_sockets[i]->bind(m_addr, m_ports[i]); | ||
} | ||
} | ||
|
||
exec(); | ||
|
||
// Clean up | ||
for (uint i = 0; i < sizeof(m_ports)/sizeof(int); i++) | ||
{ | ||
if (m_sockets[i]) | ||
{ | ||
delete m_sockets[i]; | ||
m_sockets[i] = NULL; | ||
delete m_helpers[i]; | ||
m_helpers[i] = NULL; | ||
} | ||
} | ||
|
||
RunEpilog(); | ||
} | ||
|
||
void IPTVStreamHandlerHelper::ReadPending(void) | ||
{ | ||
QByteArray datagram; | ||
QHostAddress sender; | ||
quint16 senderPort; | ||
|
||
while (m_socket->hasPendingDatagrams()) | ||
{ | ||
datagram.resize(m_socket->pendingDatagramSize()); | ||
m_socket->readDatagram(datagram.data(), datagram.size(), | ||
&sender, &senderPort); | ||
// TODO actually do something with the data.. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// -*- Mode: c++ -*- | ||
|
||
#ifndef _IPTVSTREAMHANDLER_H_ | ||
#define _IPTVSTREAMHANDLER_H_ | ||
|
||
#include <vector> | ||
using namespace std; | ||
|
||
#include <QUdpSocket> | ||
#include <QString> | ||
#include <QMutex> | ||
#include <QMap> | ||
|
||
#include "util.h" | ||
#include "DeviceReadBuffer.h" | ||
#include "mpegstreamdata.h" | ||
#include "streamhandler.h" | ||
#include "dtvconfparserhelpers.h" | ||
|
||
class IPTVStreamHandler; | ||
class DTVSignalMonitor; | ||
class IPTVChannel; | ||
|
||
class IPTVStreamHandlerHelper : QObject | ||
{ | ||
public: | ||
IPTVStreamHandlerHelper(IPTVStreamHandler *p, QUdpSocket *s) : | ||
m_parent(p), m_socket(s) | ||
{ | ||
connect(m_socket, SIGNAL(readyRead()), | ||
this, SLOT(ReadPending())); | ||
} | ||
|
||
public slots: | ||
void ReadPending(void); | ||
|
||
private: | ||
IPTVStreamHandler *m_parent; | ||
QUdpSocket *m_socket; | ||
}; | ||
|
||
class IPTVStreamHandler : public StreamHandler | ||
{ | ||
public: | ||
static IPTVStreamHandler *Get(const QString &devicename); | ||
static void Return(IPTVStreamHandler * & ref); | ||
|
||
virtual void AddListener(MPEGStreamData *data, | ||
bool allow_section_reader = false, | ||
bool needs_drb = false, | ||
QString output_file = QString()) | ||
{ | ||
StreamHandler::AddListener(data, false, false, output_file); | ||
} // StreamHandler | ||
|
||
private: | ||
IPTVStreamHandler(const QString &); | ||
|
||
bool Open(void) { return true; } | ||
void Close(void) { MThread::exit(0); } | ||
|
||
virtual void run(void); // MThread | ||
|
||
private: | ||
mutable QMutex m_lock; | ||
// TODO should we care about who is broadcasting to us? | ||
QHostAddress m_addr; | ||
int m_ports[3]; | ||
QUdpSocket *m_sockets[3]; | ||
IPTVStreamHandlerHelper *m_helpers[3]; | ||
|
||
// for implementing Get & Return | ||
static QMutex _handlers_lock; | ||
static QMap<QString, IPTVStreamHandler*> _handlers; | ||
static QMap<QString, uint> _handlers_refcnt; | ||
}; | ||
|
||
#endif // _IPTVSTREAMHANDLER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters