mirror of
https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
synced 2023-10-10 19:16:51 +02:00
Revised class responsibilities: Moved live TV related functions to livestreamer
This commit is contained in:
parent
7be0c81a81
commit
e555017565
@ -9,17 +9,10 @@
|
||||
|
||||
#include <vdr/tools.h>
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/transfer.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
// device occupied timeout to prevent VDR main loop to immediately switch back
|
||||
// when streamdev switched the live TV channel.
|
||||
// Note that there is still a gap between the GetDevice() and SetOccupied()
|
||||
// calls where the VDR main loop could strike
|
||||
#define STREAMDEVTUNETIMEOUT 5
|
||||
|
||||
cServerConnection::cServerConnection(const char *Protocol, int Type):
|
||||
cTBSocket(Type),
|
||||
m_Protocol(Protocol),
|
||||
@ -28,9 +21,7 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
|
||||
m_ReadBytes(0),
|
||||
m_WriteBytes(0),
|
||||
m_WriteIndex(0),
|
||||
m_Streamer(NULL),
|
||||
m_OccupiedDev(NULL),
|
||||
m_SwitchTo(NULL)
|
||||
m_Streamer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@ -206,66 +197,5 @@ bool cServerConnection::Close()
|
||||
return cTBSocket::Close();
|
||||
}
|
||||
|
||||
bool cServerConnection::UsedByLiveTV(cDevice *device)
|
||||
{
|
||||
return device == cTransferControl::ReceiverDevice() ||
|
||||
(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
|
||||
}
|
||||
|
||||
cDevice *cServerConnection::SwitchDevice(const cChannel *Channel, int Priority)
|
||||
{
|
||||
// turn off the streams of this connection
|
||||
Detach();
|
||||
|
||||
cDevice *device = cDevice::GetDevice(Channel, Priority, false);
|
||||
if (!device) {
|
||||
// can't switch - continue the current stream
|
||||
Attach();
|
||||
dsyslog("streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
|
||||
}
|
||||
else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
|
||||
// make sure VDR main loop doesn't switch back
|
||||
device->SetOccupied(STREAMDEVTUNETIMEOUT);
|
||||
if (device->SwitchChannel(Channel, false)) {
|
||||
// switched away live TV
|
||||
m_OccupiedDev = device;
|
||||
m_SwitchTo = Channel;
|
||||
}
|
||||
else {
|
||||
dsyslog("streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
|
||||
device->SetOccupied(0);
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
else if (!device->SwitchChannel(Channel, false)) {
|
||||
dsyslog("streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
|
||||
device = NULL;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
bool cServerConnection::ProvidesChannel(const cChannel *Channel, int Priority)
|
||||
{
|
||||
cDevice *device = cDevice::GetDevice(Channel, Priority, false, true);
|
||||
if (!device)
|
||||
dsyslog("streamdev: No device provides channel %d (%s) at priority %d", Channel->Number(), Channel->Name(), Priority);
|
||||
return device;
|
||||
}
|
||||
|
||||
void cServerConnection::MainThreadHook()
|
||||
{
|
||||
if (m_SwitchTo)
|
||||
{
|
||||
// switched away live TV. Try previous channel on other device first
|
||||
if (!Channels.SwitchTo(cDevice::CurrentChannel())) {
|
||||
// switch to streamdev channel otherwise
|
||||
Channels.SwitchTo(m_SwitchTo->Number());
|
||||
Skins.Message(mtInfo, tr("Streaming active"));
|
||||
}
|
||||
m_OccupiedDev->SetOccupied(0);
|
||||
m_SwitchTo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cString cServerConnection::ToText() const
|
||||
{ return cString::sprintf("%s\t%s:%d", Protocol(), RemoteIp().c_str(), RemotePort()); }
|
||||
|
@ -16,7 +16,6 @@ typedef std::map<std::string,std::string> tStrStrMap;
|
||||
typedef std::pair<std::string,std::string> tStrStr;
|
||||
|
||||
class cChannel;
|
||||
class cDevice;
|
||||
|
||||
/* Basic capabilities of a straight text-based protocol, most functions
|
||||
virtual to support more complicated protocols */
|
||||
@ -37,17 +36,8 @@ private:
|
||||
|
||||
cStreamdevStreamer *m_Streamer;
|
||||
|
||||
/* Set to occupied device when live TV was interrupted */
|
||||
cDevice *m_OccupiedDev;
|
||||
/* Set to this connection's current channel when live TV was interrupted */
|
||||
const cChannel *m_SwitchTo;
|
||||
|
||||
tStrStrMap m_Headers;
|
||||
|
||||
/* Test if device is in use as the transfer mode receiver device
|
||||
or a FF card, displaying live TV from internal tuner */
|
||||
static bool UsedByLiveTV(cDevice *device);
|
||||
|
||||
protected:
|
||||
/* Will be called when a command terminated by a newline has been
|
||||
received */
|
||||
@ -113,24 +103,8 @@ public:
|
||||
/* Close the socket */
|
||||
virtual bool Close(void);
|
||||
|
||||
/* Check if a device would be available for transferring the given
|
||||
channel. This call has no side effects. */
|
||||
static cDevice *CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice = NULL);
|
||||
|
||||
/* Find a suitable device and tune it to the requested channel. */
|
||||
cDevice *SwitchDevice(const cChannel *Channel, int Priority);
|
||||
|
||||
/* Test if a call to GetDevice would return a usable device. */
|
||||
bool ProvidesChannel(const cChannel *Channel, int Priority);
|
||||
|
||||
/* Do things which must be done in VDR's main loop */
|
||||
void MainThreadHook();
|
||||
|
||||
virtual void Flushed(void) {}
|
||||
|
||||
virtual void Attach(void) { if (m_Streamer != NULL) m_Streamer->Attach(); }
|
||||
virtual void Detach(void) { if (m_Streamer != NULL) m_Streamer->Detach(); }
|
||||
|
||||
/* This connections protocol name */
|
||||
virtual const char* Protocol(void) const { return m_Protocol; }
|
||||
|
||||
|
@ -173,14 +173,10 @@ bool cConnectionHTTP::ProcessRequest(void)
|
||||
if (m_MenuList)
|
||||
return Respond("%s", true, m_MenuList->HttpHeader().c_str());
|
||||
else if (m_Channel != NULL) {
|
||||
cDevice *device = NULL;
|
||||
if (ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority))
|
||||
device = SwitchDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
|
||||
if (device != NULL) {
|
||||
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.HTTPPriority, this);
|
||||
SetStreamer(liveStreamer);
|
||||
if (liveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {
|
||||
liveStreamer->SetDevice(device);
|
||||
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority)) {
|
||||
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, StreamdevServerSetup.HTTPPriority, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
|
||||
if (liveStreamer->GetDevice()) {
|
||||
SetStreamer(liveStreamer);
|
||||
if (!SetDSCP())
|
||||
LOG_ERROR_STR("unable to set DSCP sockopt");
|
||||
if (m_StreamType == stEXT) {
|
||||
@ -194,6 +190,7 @@ bool cConnectionHTTP::ProcessRequest(void)
|
||||
}
|
||||
}
|
||||
SetStreamer(NULL);
|
||||
delete liveStreamer;
|
||||
}
|
||||
return HttpResponse(503, true);
|
||||
}
|
||||
@ -233,10 +230,9 @@ bool cConnectionHTTP::ProcessRequest(void)
|
||||
return Respond("%s", true, m_MenuList->HttpHeader().c_str());
|
||||
}
|
||||
else if (m_Channel != NULL) {
|
||||
if (ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority)) {
|
||||
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority)) {
|
||||
if (m_StreamType == stEXT) {
|
||||
cStreamdevLiveStreamer *liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.HTTPPriority, this);
|
||||
liveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
|
||||
cStreamdevLiveStreamer *liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, IDLEPRIORITY, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL);
|
||||
SetStreamer(liveStreamer);
|
||||
return Respond("HTTP/1.0 200 OK");
|
||||
} else if (m_StreamType == stES && (m_Apid[0] || m_Dpid[0] || ISRADIO(m_Channel))) {
|
||||
|
@ -40,22 +40,19 @@ bool cConnectionIGMP::SetChannel(cChannel *Channel, in_addr_t Dst)
|
||||
|
||||
void cConnectionIGMP::Welcome()
|
||||
{
|
||||
cDevice *device = NULL;
|
||||
if (ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority))
|
||||
device = SwitchDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
|
||||
if (device != NULL) {
|
||||
cStreamdevLiveStreamer * liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.IGMPPriority, this);
|
||||
SetStreamer(liveStreamer);
|
||||
if (liveStreamer->SetChannel(m_Channel, m_StreamType)) {
|
||||
liveStreamer->SetDevice(device);
|
||||
if (cStreamdevLiveStreamer::ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority)) {
|
||||
cStreamdevLiveStreamer * liveStreamer = new cStreamdevLiveStreamer(this, m_Channel, StreamdevServerSetup.IGMPPriority, m_StreamType);
|
||||
if (liveStreamer->GetDevice()) {
|
||||
SetStreamer(liveStreamer);
|
||||
if (!SetDSCP())
|
||||
LOG_ERROR_STR("unable to set DSCP sockopt");
|
||||
Dprintf("streamer start\n");
|
||||
liveStreamer->Start(this);
|
||||
}
|
||||
else {
|
||||
esyslog("streamdev-server IGMP: SetChannel failed");
|
||||
SetStreamer(NULL);
|
||||
delete liveStreamer;
|
||||
esyslog("streamdev-server IGMP: SetChannel failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -787,12 +787,12 @@ void cConnectionVTP::Reject(void)
|
||||
void cConnectionVTP::Detach(void)
|
||||
{
|
||||
if (m_FilterStreamer) m_FilterStreamer->Detach();
|
||||
cServerConnection::Detach();
|
||||
if (m_LiveSocket && Streamer()) ((cStreamdevLiveStreamer *) Streamer())->Detach();
|
||||
}
|
||||
|
||||
void cConnectionVTP::Attach(void)
|
||||
{
|
||||
cServerConnection::Attach();
|
||||
if (m_LiveSocket && Streamer()) ((cStreamdevLiveStreamer *) Streamer())->Attach();
|
||||
if (m_FilterStreamer) m_FilterStreamer->Attach();
|
||||
}
|
||||
|
||||
@ -936,7 +936,7 @@ bool cConnectionVTP::CmdPROV(char *Opts)
|
||||
|
||||
LOOP_PREVENTION(chan);
|
||||
|
||||
if (ProvidesChannel(chan, prio)) {
|
||||
if (cStreamdevLiveStreamer::ProvidesChannel(chan, prio)) {
|
||||
m_TuneChannel = chan;
|
||||
m_TunePriority = prio;
|
||||
return Respond(220, "Channel available");
|
||||
@ -945,7 +945,7 @@ bool cConnectionVTP::CmdPROV(char *Opts)
|
||||
// so get our own receiver temporarily out of the way
|
||||
if (m_ClientVersion == 0) {
|
||||
Detach();
|
||||
bool provided = ProvidesChannel(chan, prio);
|
||||
bool provided = cStreamdevLiveStreamer::ProvidesChannel(chan, prio);
|
||||
Attach();
|
||||
if (provided) {
|
||||
m_TuneChannel = chan;
|
||||
@ -1117,16 +1117,18 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
|
||||
if (chan != m_TuneChannel) {
|
||||
isyslog("streamdev-server TUNE %s: Priority unknown - using 0", Opts);
|
||||
prio = 0;
|
||||
if (!ProvidesChannel(chan, prio))
|
||||
if (!cStreamdevLiveStreamer::ProvidesChannel(chan, prio))
|
||||
return Respond(560, "Channel not available (ProvidesChannel)");
|
||||
}
|
||||
if ((dev = SwitchDevice(chan, prio)) == NULL)
|
||||
return Respond(560, "Channel not available (SwitchDevice)");
|
||||
|
||||
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(prio, this);
|
||||
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(this, chan, prio, m_StreamType);
|
||||
if ((dev = liveStreamer->GetDevice()) == NULL) {
|
||||
SetStreamer(NULL);
|
||||
delete liveStreamer;
|
||||
return Respond(560, "Channel not available (SwitchDevice)");
|
||||
}
|
||||
SetStreamer(liveStreamer);
|
||||
liveStreamer->SetChannel(chan, m_StreamType);
|
||||
liveStreamer->SetDevice(dev);
|
||||
|
||||
if(m_LiveSocket)
|
||||
liveStreamer->Start(m_LiveSocket);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "remux/ts2es.h"
|
||||
#include "remux/extern.h"
|
||||
|
||||
#include <vdr/transfer.h>
|
||||
#include <vdr/ringbuffer.h>
|
||||
|
||||
#include "server/livestreamer.h"
|
||||
@ -16,6 +17,12 @@
|
||||
|
||||
using namespace Streamdev;
|
||||
|
||||
// device occupied timeout to prevent VDR main loop to immediately switch back
|
||||
// when streamdev switched the live TV channel.
|
||||
// Note that there is still a gap between the GetDevice() and SetOccupied()
|
||||
// calls where the VDR main loop could strike
|
||||
#define STREAMDEVTUNETIMEOUT 5
|
||||
|
||||
// --- cStreamdevLiveReceiver -------------------------------------------------
|
||||
|
||||
class cStreamdevLiveReceiver: public cReceiver {
|
||||
@ -328,19 +335,28 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
|
||||
|
||||
// --- cStreamdevLiveStreamer -------------------------------------------------
|
||||
|
||||
cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection):
|
||||
cStreamdevLiveStreamer::cStreamdevLiveStreamer(const cServerConnection *Connection, const cChannel *Channel, int Priority, eStreamType StreamType, const int* Apid, const int *Dpid) :
|
||||
cStreamdevStreamer("streamdev-livestreaming", Connection),
|
||||
m_Priority(Priority),
|
||||
m_NumPids(0),
|
||||
m_StreamType(stTSPIDS),
|
||||
m_Channel(NULL),
|
||||
m_Channel(Channel),
|
||||
m_Device(NULL),
|
||||
m_Receiver(NULL),
|
||||
m_PatFilter(NULL),
|
||||
m_Remux(NULL)
|
||||
m_Remux(NULL),
|
||||
m_SwitchLive(false)
|
||||
{
|
||||
m_ReceiveBuffer = new cStreamdevBuffer(LIVEBUFSIZE, TS_SIZE *2, true, "streamdev-livestreamer"),
|
||||
m_ReceiveBuffer->SetTimeouts(0, 100);
|
||||
if (Priority == IDLEPRIORITY) {
|
||||
SetChannel(Channel, StreamType, Apid, Dpid);
|
||||
}
|
||||
else {
|
||||
m_Device = SwitchDevice(Channel, Priority);
|
||||
if (m_Device)
|
||||
SetChannel(Channel, StreamType, Apid, Dpid);
|
||||
}
|
||||
}
|
||||
|
||||
cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
|
||||
@ -613,6 +629,66 @@ void cStreamdevLiveStreamer::Detach(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool cStreamdevLiveStreamer::UsedByLiveTV(cDevice *device)
|
||||
{
|
||||
return device == cTransferControl::ReceiverDevice() ||
|
||||
(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
|
||||
}
|
||||
|
||||
cDevice *cStreamdevLiveStreamer::SwitchDevice(const cChannel *Channel, int Priority)
|
||||
{
|
||||
// turn off the streams of this connection
|
||||
Detach();
|
||||
|
||||
cDevice *device = cDevice::GetDevice(Channel, Priority, false);
|
||||
if (!device) {
|
||||
// can't switch - continue the current stream
|
||||
Attach();
|
||||
dsyslog("streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
|
||||
}
|
||||
else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
|
||||
// make sure VDR main loop doesn't switch back
|
||||
device->SetOccupied(STREAMDEVTUNETIMEOUT);
|
||||
if (device->SwitchChannel(Channel, false)) {
|
||||
// switched away live TV
|
||||
m_SwitchLive = true;
|
||||
}
|
||||
else {
|
||||
dsyslog("streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
|
||||
device->SetOccupied(0);
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
else if (!device->SwitchChannel(Channel, false)) {
|
||||
dsyslog("streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
|
||||
device = NULL;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
bool cStreamdevLiveStreamer::ProvidesChannel(const cChannel *Channel, int Priority)
|
||||
{
|
||||
cDevice *device = cDevice::GetDevice(Channel, Priority, false, true);
|
||||
if (!device)
|
||||
dsyslog("streamdev: No device provides channel %d (%s) at priority %d", Channel->Number(), Channel->Name(), Priority);
|
||||
return device;
|
||||
}
|
||||
|
||||
void cStreamdevLiveStreamer::MainThreadHook()
|
||||
{
|
||||
if (m_SwitchLive) {
|
||||
// switched away live TV. Try previous channel on other device first
|
||||
if (!Channels.SwitchTo(cDevice::CurrentChannel())) {
|
||||
// switch to streamdev channel otherwise
|
||||
Channels.SwitchTo(m_Channel->Number());
|
||||
Skins.Message(mtInfo, tr("Streaming active"));
|
||||
}
|
||||
if (m_Device)
|
||||
m_Device->SetOccupied(0);
|
||||
m_SwitchLive = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string cStreamdevLiveStreamer::Report(void)
|
||||
{
|
||||
std::string result;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vdr/receiver.h>
|
||||
|
||||
#include "server/streamer.h"
|
||||
#include "server/streamdev-server.h"
|
||||
#include "common.h"
|
||||
|
||||
#define LIVEBUFSIZE (20000 * TS_SIZE)
|
||||
@ -17,7 +18,7 @@ class cStreamdevLiveReceiver;
|
||||
|
||||
// --- cStreamdevLiveStreamer -------------------------------------------------
|
||||
|
||||
class cStreamdevLiveStreamer: public cStreamdevStreamer {
|
||||
class cStreamdevLiveStreamer: public cStreamdevStreamer, public cMainThreadHookSubscriber {
|
||||
private:
|
||||
int m_Priority;
|
||||
int m_Pids[MAXRECEIVEPIDS + 1];
|
||||
@ -29,10 +30,22 @@ private:
|
||||
cStreamdevBuffer *m_ReceiveBuffer;
|
||||
cStreamdevPatFilter *m_PatFilter;
|
||||
Streamdev::cTSRemux *m_Remux;
|
||||
bool m_SwitchLive;
|
||||
|
||||
void StartReceiver(void);
|
||||
bool HasPid(int Pid);
|
||||
|
||||
/* Test if device is in use as the transfer mode receiver device
|
||||
or a FF card, displaying live TV from internal tuner */
|
||||
static bool UsedByLiveTV(cDevice *device);
|
||||
|
||||
/* Find a suitable device and tune it to the requested channel. */
|
||||
cDevice *SwitchDevice(const cChannel *Channel, int Priority);
|
||||
|
||||
void SetDevice(cDevice *Device) { m_Device = Device; }
|
||||
|
||||
bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
|
||||
|
||||
protected:
|
||||
virtual uchar* GetFromReceiver(int &Count) { return m_ReceiveBuffer->Get(Count); }
|
||||
virtual void DelFromReceiver(int Count) { m_ReceiveBuffer->Del(Count); }
|
||||
@ -41,13 +54,11 @@ protected:
|
||||
virtual void Action(void);
|
||||
|
||||
public:
|
||||
cStreamdevLiveStreamer(int Priority, const cServerConnection *Connection);
|
||||
cStreamdevLiveStreamer(const cServerConnection *Connection, const cChannel *Channel, int Priority, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
|
||||
virtual ~cStreamdevLiveStreamer();
|
||||
|
||||
void SetDevice(cDevice *Device) { m_Device = Device; }
|
||||
bool SetPid(int Pid, bool On);
|
||||
bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
|
||||
bool SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid = NULL, const int* Dpid = NULL);
|
||||
void SetPriority(int Priority);
|
||||
void GetSignal(int *DevNum, int *Strength, int *Quality) const;
|
||||
virtual cString ToText() const;
|
||||
@ -61,6 +72,14 @@ public:
|
||||
virtual void Attach(void);
|
||||
virtual void Detach(void);
|
||||
|
||||
cDevice *GetDevice() const { return m_Device; }
|
||||
|
||||
/* Test if a call to GetDevice would return a usable device. */
|
||||
static bool ProvidesChannel(const cChannel *Channel, int Priority);
|
||||
|
||||
/* Do things which must be done in VDR's main loop */
|
||||
void MainThreadHook();
|
||||
|
||||
// Statistical purposes:
|
||||
virtual std::string Report(void);
|
||||
};
|
||||
|
@ -18,6 +18,29 @@
|
||||
#error "VDR-1.7.25 or greater required to compile server! Use 'make client' to compile client only."
|
||||
#endif
|
||||
|
||||
cList<cMainThreadHookSubscriber> cMainThreadHookSubscriber::m_Subscribers;
|
||||
cMutex cMainThreadHookSubscriber::m_Mutex;
|
||||
|
||||
const cList<cMainThreadHookSubscriber>& cMainThreadHookSubscriber::Subscribers(cMutexLock& Lock)
|
||||
{
|
||||
Lock.Lock(&m_Mutex);
|
||||
return m_Subscribers;
|
||||
}
|
||||
|
||||
cMainThreadHookSubscriber::cMainThreadHookSubscriber()
|
||||
{
|
||||
m_Mutex.Lock();
|
||||
m_Subscribers.Add(this);
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
cMainThreadHookSubscriber::~cMainThreadHookSubscriber()
|
||||
{
|
||||
m_Mutex.Lock();
|
||||
m_Subscribers.Del(this, false);
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
const char *cPluginStreamdevServer::DESCRIPTION = trNOOP("VDR Streaming Server");
|
||||
|
||||
cPluginStreamdevServer::cPluginStreamdevServer(void)
|
||||
@ -139,9 +162,9 @@ void cPluginStreamdevServer::MainThreadHook(void)
|
||||
m_Suspend = false;
|
||||
}
|
||||
|
||||
cThreadLock lock;
|
||||
const cList<cServerConnection>& clients = cStreamdevServer::Clients(lock);
|
||||
for (cServerConnection *s = clients.First(); s; s = clients.Next(s))
|
||||
cMutexLock lock;
|
||||
const cList<cMainThreadHookSubscriber>& subs = cMainThreadHookSubscriber::Subscribers(lock);
|
||||
for (cMainThreadHookSubscriber *s = subs.First(); s; s = subs.Next(s))
|
||||
s->MainThreadHook();
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,22 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <vdr/tools.h>
|
||||
#include <vdr/plugin.h>
|
||||
|
||||
class cMainThreadHookSubscriber: public cListObject {
|
||||
private:
|
||||
static cList<cMainThreadHookSubscriber> m_Subscribers;
|
||||
static cMutex m_Mutex;
|
||||
public:
|
||||
static const cList<cMainThreadHookSubscriber>& Subscribers(cMutexLock& Lock);
|
||||
|
||||
virtual void MainThreadHook() = 0;
|
||||
|
||||
cMainThreadHookSubscriber();
|
||||
virtual ~cMainThreadHookSubscriber();
|
||||
};
|
||||
|
||||
class cPluginStreamdevServer : public cPlugin {
|
||||
private:
|
||||
static const char *DESCRIPTION;
|
||||
|
Loading…
Reference in New Issue
Block a user