Implemented multi-device support for streamdev client (closes #1207)

This commit is contained in:
Frank Schmirler 2013-01-29 00:02:17 +01:00
parent 9135cde712
commit 525edc1ccf
20 changed files with 154 additions and 156 deletions

View File

@ -1,6 +1,7 @@
VDR Plugin 'streamdev' Revision History VDR Plugin 'streamdev' Revision History
--------------------------------------- ---------------------------------------
- Implemented multi-device support for streamdev client (suggested by johns)
- Basic support for HTTP streaming of recordings - Basic support for HTTP streaming of recordings
- Close writer when streamer is finished - Close writer when streamer is finished
- Don't abort VTP connection if filter stream is broken - Don't abort VTP connection if filter stream is broken

46
README
View File

@ -376,29 +376,26 @@ type "127001<OK>" on your remote. If you want to enter "192.168.1.12", type
"1921681<Right>12<OK>". "1921681<Right>12<OK>".
The parameters "Remote IP" and "Remote Port" in the client's setup specify the The parameters "Remote IP" and "Remote Port" in the client's setup specify the
address of the remote VDR-to-VDR server to connect to. Activate the client by address of the remote VDR-to-VDR server to connect to. The client is disabled
setting "Start Client" to yes. It is disabled by default, because it wouldn't by default, because it wouldn't make much sense to start the client without
make much sense to start the client without specifying a server anyway. The specifying a server anyway. Activate the client by setting "Simultaneously used
client is activated after you push the OK button, so there's no need to restart Devices" to at least 1. Streamdev-client will allocate as many VDR devices as
VDR. Deactivation on-the-fly is not possible, so in order to deactivate the you configure here. Each of these devices opens one connection to the server
client, you will have to restart VDR. However requests to switch channels will and becomes associated with one of the server's devices (typically a DVB card)
be refused by streamdev-client once it has been deactivated. All other settings on demand.
can be changed without restarting VDR.
The client will try to connect to the server (in case it isn't yet) whenever
a remote channel is requested. Just activate the client and switch to a
channel that's not available by local devices. If anything goes wrong with the
connection between the two, you will see it in the logfile instantly. If you
now switch the client to a channel which isn't covered by it's own local
devices, it will ask the server for it. If the server can (currently) receive
that channel, the client will show it until you switch again, or until the
server needs that card (if no other is free) for a recording on a different
transponder.
Only the needed PIDs are transferred, and additional PIDs can be turned on Only the needed PIDs are transferred, and additional PIDs can be turned on
during an active transfer. This makes it possible to switch languages, receive during an active transfer. This makes it possible to switch languages, receive
additional channels (for recording on the client) and use plugins that use additional channels on the same transponder and use plugins that use receivers
receivers themselves (like osdteletext). themselves (like osdteletext).
So for viewing live TV a single device is sufficient. But if the client needs
to receive channels from different transponders simultaneously (e.g. for PiP or
client side recordings) a second device becomes necessary.
To allocate additional devices, just increase the number and push the OK button.
There's no need to restart VDR. Deleting VDR devices on-the-fly is not possible.
However requests to switch channels will be refused by redundant devices.
The default timeout of 2 seconds for network operations should be sufficient in The default timeout of 2 seconds for network operations should be sufficient in
most cases. Increase "Timeout" if you get frequent timeout errors in the log. most cases. Increase "Timeout" if you get frequent timeout errors in the log.
@ -435,12 +432,9 @@ higher, live TV will use your DVB card until a recordings kicks in. Then the
recording will take the DVB card and live TV will be shifted to streamdev recording will take the DVB card and live TV will be shifted to streamdev
(you'll notice a short interruption of live TV). (you'll notice a short interruption of live TV).
Note that streamdev-client acts similar to a DVB card. It is possible to receive To receive channels from multiple servers, create additional instances of the
multiple channels simultaneously, but only from the same transponder. Just add streamdev-client plugin. Simply copy (don't link!) the binary to a different
additional instances of streamdev-client and you will be able to receive as many name (e.g. streamdev-client2):
transponders at a time. The same trick allows a client to receive channels from
different servers. To create an additional instance, copy the streamdev-client
binary to a different name (e.g. streamdev-client2):
cd VDRPLUGINLIBDIR cd VDRPLUGINLIBDIR
cp libvdr-streamdev-client.so.1.X.X libvdr-streamdev-client2.so.1.X.X cp libvdr-streamdev-client.so.1.X.X libvdr-streamdev-client2.so.1.X.X

View File

@ -29,30 +29,28 @@ using namespace std;
#define VIDEOBUFSIZE MEGABYTE(3) #define VIDEOBUFSIZE MEGABYTE(3)
cStreamdevDevice *cStreamdevDevice::m_Device = NULL;
const cChannel *cStreamdevDevice::m_DenyChannel = NULL; const cChannel *cStreamdevDevice::m_DenyChannel = NULL;
cStreamdevDevice::cStreamdevDevice(void) { cStreamdevDevice::cStreamdevDevice(void) {
m_Channel = NULL; m_Disabled = false;
m_TSBuffer = NULL; m_ClientSocket = new cClientSocket();
m_Channel = NULL;
m_TSBuffer = NULL;
m_Filters = new cStreamdevFilters; m_Filters = new cStreamdevFilters(m_ClientSocket);
StartSectionHandler(); StartSectionHandler();
isyslog("streamdev-client: got device number %d", CardIndex() + 1); isyslog("streamdev-client: got device number %d", CardIndex() + 1);
m_Device = this;
m_Pids = 0; m_Pids = 0;
m_Priority = -100;
} }
cStreamdevDevice::~cStreamdevDevice() { cStreamdevDevice::~cStreamdevDevice() {
Dprintf("Device gets destructed\n"); Dprintf("Device gets destructed\n");
Lock(); Lock();
m_Device = NULL;
m_Filters->SetConnection(-1); m_Filters->SetConnection(-1);
ClientSocket.Quit(); m_ClientSocket->Quit();
ClientSocket.Reset(); m_ClientSocket->Reset();
Unlock(); Unlock();
Cancel(3); Cancel(3);
@ -60,6 +58,7 @@ cStreamdevDevice::~cStreamdevDevice() {
StopSectionHandler(); StopSectionHandler();
DELETENULL(m_Filters); DELETENULL(m_Filters);
DELETENULL(m_TSBuffer); DELETENULL(m_TSBuffer);
delete m_ClientSocket;
} }
#if APIVERSNUM >= 10700 #if APIVERSNUM >= 10700
@ -84,7 +83,7 @@ bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel) const
bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel) bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel)
#endif #endif
{ {
return ClientSocket.DataSocket(siLive) != NULL && return m_ClientSocket->DataSocket(siLive) != NULL &&
m_Channel != NULL && m_Channel != NULL &&
Channel->Transponder() == m_Channel->Transponder(); Channel->Transponder() == m_Channel->Transponder();
} }
@ -92,14 +91,14 @@ bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel)
bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
bool *NeedsDetachReceivers) const { bool *NeedsDetachReceivers) const {
#if APIVERSNUM >= 10725 #if APIVERSNUM >= 10725
bool prio = Priority == IDLEPRIORITY || Priority >= this->Priority(); bool prio = Priority == IDLEPRIORITY || Priority >= m_ClientSocket->Priority();
#else #else
bool prio = Priority < 0 || Priority > this->Priority(); bool prio = Priority < 0 || Priority > m_ClientSocket->Priority();
#endif #endif
bool res = prio; bool res = prio;
bool ndr = false; bool ndr = false;
if (!StreamdevClientSetup.StartClient || Channel == m_DenyChannel) if (m_Disabled || Channel == m_DenyChannel)
return false; return false;
Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority); Dprintf("ProvidesChannel, Channel=%s, Prio=%d\n", Channel->Name(), Priority);
@ -131,7 +130,7 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
} }
else if (prio) { else if (prio) {
if (Priority == LIVEPRIORITY) { if (Priority == LIVEPRIORITY) {
if (ClientSocket.ServerVersion() >= 100) { if (m_ClientSocket->ServerVersion() >= 100) {
Priority = StreamdevClientSetup.LivePriority; Priority = StreamdevClientSetup.LivePriority;
UpdatePriority(true); UpdatePriority(true);
} }
@ -141,10 +140,10 @@ bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority,
} }
} }
res = ClientSocket.ProvidesChannel(Channel, Priority); res = m_ClientSocket->ProvidesChannel(Channel, Priority);
ndr = Receiving(); ndr = Receiving();
if (ClientSocket.ServerVersion() >= 100) if (m_ClientSocket->ServerVersion() >= 100)
UpdatePriority(false); UpdatePriority(false);
} }
@ -175,9 +174,9 @@ bool cStreamdevDevice::SetChannelDevice(const cChannel *Channel,
m_Channel = Channel; m_Channel = Channel;
// Old servers delete cStreamdevLiveStreamer in ABRT. // Old servers delete cStreamdevLiveStreamer in ABRT.
// Delete it now or it will happen after we tuned to new channel // Delete it now or it will happen after we tuned to new channel
if (ClientSocket.ServerVersion() < 100) if (m_ClientSocket->ServerVersion() < 100)
CloseDvr(); CloseDvr();
res = ClientSocket.SetChannelDevice(m_Channel); res = m_ClientSocket->SetChannelDevice(m_Channel);
} }
Dprintf("setchanneldevice res=%d\n", res); Dprintf("setchanneldevice res=%d\n", res);
return res; return res;
@ -189,7 +188,7 @@ bool cStreamdevDevice::SetPid(cPidHandle *Handle, int Type, bool On) {
bool res = true; bool res = true;
if (Handle->pid && (On || !Handle->used)) { if (Handle->pid && (On || !Handle->used)) {
res = ClientSocket.SetPid(Handle->pid, On); res = m_ClientSocket->SetPid(Handle->pid, On);
m_Pids += (!res) ? 0 : On ? 1 : -1; m_Pids += (!res) ? 0 : On ? 1 : -1;
if (m_Pids < 0) if (m_Pids < 0)
@ -203,8 +202,8 @@ bool cStreamdevDevice::OpenDvr(void) {
LOCK_THREAD; LOCK_THREAD;
CloseDvr(); CloseDvr();
if (ClientSocket.CreateDataConnection(siLive)) { if (m_ClientSocket->CreateDataConnection(siLive)) {
m_TSBuffer = new cTSBuffer(*ClientSocket.DataSocket(siLive), MEGABYTE(2), CardIndex() + 1); m_TSBuffer = new cTSBuffer(*m_ClientSocket->DataSocket(siLive), MEGABYTE(2), CardIndex() + 1);
} }
else { else {
esyslog("cStreamdevDevice::OpenDvr(): DVR connection FAILED"); esyslog("cStreamdevDevice::OpenDvr(): DVR connection FAILED");
@ -217,26 +216,26 @@ void cStreamdevDevice::CloseDvr(void) {
Dprintf("CloseDvr\n"); Dprintf("CloseDvr\n");
LOCK_THREAD; LOCK_THREAD;
ClientSocket.CloseDvr(); m_ClientSocket->CloseDvr();
DELETENULL(m_TSBuffer); DELETENULL(m_TSBuffer);
} }
bool cStreamdevDevice::GetTSPacket(uchar *&Data) { bool cStreamdevDevice::GetTSPacket(uchar *&Data) {
if (m_TSBuffer && m_Device) { if (m_TSBuffer) {
Data = m_TSBuffer->Get(); Data = m_TSBuffer->Get();
#if 1 // TODO: this should be fixed in vdr cTSBuffer #if 1 // TODO: this should be fixed in vdr cTSBuffer
// simple disconnect detection // simple disconnect detection
static int m_TSFails = 0; static int m_TSFails = 0;
if (!Data) { if (!Data) {
LOCK_THREAD; LOCK_THREAD;
if(!ClientSocket.DataSocket(siLive)) { if(!m_ClientSocket->DataSocket(siLive)) {
return false; // triggers CloseDvr() + OpenDvr() in cDevice return false; // triggers CloseDvr() + OpenDvr() in cDevice
} }
cPoller Poller(*ClientSocket.DataSocket(siLive)); cPoller Poller(*m_ClientSocket->DataSocket(siLive));
errno = 0; errno = 0;
if (Poller.Poll() && !errno) { if (Poller.Poll() && !errno) {
char tmp[1]; char tmp[1];
if (recv(*ClientSocket.DataSocket(siLive), tmp, 1, MSG_PEEK) == 0 && !errno) { if (recv(*m_ClientSocket->DataSocket(siLive), tmp, 1, MSG_PEEK) == 0 && !errno) {
esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails); esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails);
m_TSFails++; m_TSFails++;
if (m_TSFails > 10) { if (m_TSFails > 10) {
@ -264,61 +263,50 @@ int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
return -1; return -1;
if (!ClientSocket.DataSocket(siLiveFilter)) { if (!m_ClientSocket->DataSocket(siLiveFilter)) {
if (ClientSocket.CreateDataConnection(siLiveFilter)) { if (m_ClientSocket->CreateDataConnection(siLiveFilter)) {
m_Filters->SetConnection(*ClientSocket.DataSocket(siLiveFilter)); m_Filters->SetConnection(*m_ClientSocket->DataSocket(siLiveFilter));
} else { } else {
isyslog("cStreamdevDevice::OpenFilter: connect failed: %m"); isyslog("cStreamdevDevice::OpenFilter: connect failed: %m");
return -1; return -1;
} }
} }
if (ClientSocket.SetFilter(Pid, Tid, Mask, true)) if (m_ClientSocket->SetFilter(Pid, Tid, Mask, true))
return m_Filters->OpenFilter(Pid, Tid, Mask); return m_Filters->OpenFilter(Pid, Tid, Mask);
return -1; return -1;
} }
bool cStreamdevDevice::Init(void) { bool cStreamdevDevice::ReInit(bool Disable) {
if (m_Device == NULL && StreamdevClientSetup.StartClient) LOCK_THREAD;
new cStreamdevDevice; m_Disabled = Disable;
m_Filters->SetConnection(-1);
m_Pids = 0;
m_ClientSocket->Quit();
m_ClientSocket->Reset();
//DELETENULL(m_TSBuffer);
return true; return true;
} }
bool cStreamdevDevice::ReInit(void) { void cStreamdevDevice::UpdatePriority(bool SwitchingChannels) const {
if(m_Device) { if (!m_Disabled) {
m_Device->Lock(); //LOCK_THREAD;
m_Device->m_Filters->SetConnection(-1); const_cast<cStreamdevDevice*>(this)->Lock();
m_Device->m_Pids = 0; if (m_ClientSocket->SupportsPrio() && m_ClientSocket->DataSocket(siLive)) {
} int Priority = this->Priority();
ClientSocket.Quit();
ClientSocket.Reset();
if (m_Device != NULL) {
//DELETENULL(m_Device->m_TSBuffer);
m_Device->Unlock();
}
return StreamdevClientSetup.StartClient ? Init() : true;
}
void cStreamdevDevice::UpdatePriority(bool SwitchingChannels) {
if (m_Device) {
m_Device->Lock();
if (ClientSocket.SupportsPrio() && ClientSocket.DataSocket(siLive)) {
int Priority = m_Device->Priority();
// override TRANSFERPRIORITY (-1) with live TV priority from setup // override TRANSFERPRIORITY (-1) with live TV priority from setup
if (m_Device == cDevice::ActualDevice() && Priority == TRANSFERPRIORITY) { if (this == cDevice::ActualDevice() && m_ClientSocket->Priority() == TRANSFERPRIORITY) {
Priority = StreamdevClientSetup.LivePriority; int Priority = StreamdevClientSetup.LivePriority;
// temporarily lower priority // temporarily lower priority
if (SwitchingChannels) if (SwitchingChannels)
Priority--; Priority--;
if (Priority < 0 && ClientSocket.ServerVersion() < 100) if (Priority < 0 && m_ClientSocket->ServerVersion() < 100)
Priority = 0; Priority = 0;
} }
if (m_Device->m_Priority != Priority && ClientSocket.SetPriority(Priority)) m_ClientSocket->SetPriority(Priority);
m_Device->m_Priority = Priority;
} }
m_Device->Unlock(); const_cast<cStreamdevDevice*>(this)->Unlock();
} }
} }
@ -330,8 +318,8 @@ cString cStreamdevDevice::DeviceType(void) const {
static int dev = -1; static int dev = -1;
static cString devType("STRDev"); static cString devType("STRDev");
int d = -1; int d = -1;
if (ClientSocket.DataSocket(siLive) != NULL) if (m_ClientSocket->DataSocket(siLive) != NULL)
ClientSocket.GetSignal(NULL, NULL, &d); m_ClientSocket->GetSignal(NULL, NULL, &d);
if (d != dev) { if (d != dev) {
dev = d; dev = d;
devType = d < 0 ? "STRDev" : *cString::sprintf("STRD%2d", d); devType = d < 0 ? "STRDev" : *cString::sprintf("STRD%2d", d);
@ -341,15 +329,15 @@ cString cStreamdevDevice::DeviceType(void) const {
int cStreamdevDevice::SignalStrength(void) const { int cStreamdevDevice::SignalStrength(void) const {
int strength = -1; int strength = -1;
if (ClientSocket.DataSocket(siLive) != NULL) if (m_ClientSocket->DataSocket(siLive) != NULL)
ClientSocket.GetSignal(&strength, NULL, NULL); m_ClientSocket->GetSignal(&strength, NULL, NULL);
return strength; return strength;
} }
int cStreamdevDevice::SignalQuality(void) const { int cStreamdevDevice::SignalQuality(void) const {
int quality = -1; int quality = -1;
if (ClientSocket.DataSocket(siLive) != NULL) if (m_ClientSocket->DataSocket(siLive) != NULL)
ClientSocket.GetSignal(NULL, &quality, NULL); m_ClientSocket->GetSignal(NULL, &quality, NULL);
return quality; return quality;
} }

View File

@ -17,13 +17,13 @@ class cTBString;
class cStreamdevDevice: public cDevice { class cStreamdevDevice: public cDevice {
private: private:
bool m_Disabled;
cClientSocket *m_ClientSocket;
const cChannel *m_Channel; const cChannel *m_Channel;
cTSBuffer *m_TSBuffer; cTSBuffer *m_TSBuffer;
cStreamdevFilters *m_Filters; cStreamdevFilters *m_Filters;
int m_Pids; int m_Pids;
int m_Priority;
static cStreamdevDevice *m_Device;
static const cChannel *m_DenyChannel; static const cChannel *m_DenyChannel;
protected: protected:
@ -67,12 +67,10 @@ public:
virtual int SignalStrength(void) const; virtual int SignalStrength(void) const;
virtual int SignalQuality(void) const; virtual int SignalQuality(void) const;
static void UpdatePriority(bool SwitchingChannels = false); bool ReInit(bool Disable);
void UpdatePriority(bool SwitchingChannels = false) const;
bool SuspendServer() { return m_ClientSocket->SuspendServer(); }
static void DenyChannel(const cChannel *Channel) { m_DenyChannel = Channel; } static void DenyChannel(const cChannel *Channel) { m_DenyChannel = Channel; }
static bool Init(void);
static bool ReInit(void);
static cStreamdevDevice *GetDevice(void) { return m_Device; }
}; };
#endif // VDR_STREAMDEV_DEVICE_H #endif // VDR_STREAMDEV_DEVICE_H

View File

@ -144,8 +144,9 @@ bool cStreamdevFilter::IsClosed(void) {
// --- cStreamdevFilters ----------------------------------------------------- // --- cStreamdevFilters -----------------------------------------------------
cStreamdevFilters::cStreamdevFilters(void): cStreamdevFilters::cStreamdevFilters(cClientSocket *ClientSocket):
cThread("streamdev-client: sections assembler") { cThread("streamdev-client: sections assembler") {
m_ClientSocket = ClientSocket;
m_TSBuffer = NULL; m_TSBuffer = NULL;
} }
@ -173,7 +174,7 @@ void cStreamdevFilters::CarbageCollect(void) {
if (errno == ECONNREFUSED || if (errno == ECONNREFUSED ||
errno == ECONNRESET || errno == ECONNRESET ||
errno == EPIPE) { errno == EPIPE) {
ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), false); m_ClientSocket->SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), false);
Dprintf("cStreamdevFilters::CarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)", Dprintf("cStreamdevFilters::CarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)",
(int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1); (int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
@ -200,7 +201,7 @@ bool cStreamdevFilters::ReActivateFilters(void)
bool res = true; bool res = true;
CarbageCollect(); CarbageCollect();
for (cStreamdevFilter *fi = First(); fi; fi = Next(fi)) { for (cStreamdevFilter *fi = First(); fi; fi = Next(fi)) {
res = ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), true) && res; res = m_ClientSocket->SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), true) && res;
Dprintf("ReActivateFilters(%d, %d, %d) -> %s", fi->Pid(), fi->Tid(), fi->Mask(), res ? "Ok" :"FAIL"); Dprintf("ReActivateFilters(%d, %d, %d) -> %s", fi->Pid(), fi->Tid(), fi->Mask(), res ? "Ok" :"FAIL");
} }
return res; return res;
@ -251,7 +252,7 @@ void cStreamdevFilters::Action(void) {
Dprintf("FATAL ERROR: %m\n"); Dprintf("FATAL ERROR: %m\n");
esyslog("streamdev-client: couldn't send section packet: %m"); esyslog("streamdev-client: couldn't send section packet: %m");
} }
ClientSocket.SetFilter(f->Pid(), f->Tid(), f->Mask(), false); m_ClientSocket->SetFilter(f->Pid(), f->Tid(), f->Mask(), false);
Del(f); Del(f);
// Filter was closed. // Filter was closed.
// - need to check remaining filters for another match // - need to check remaining filters for another match
@ -261,7 +262,7 @@ void cStreamdevFilters::Action(void) {
} else { } else {
#if 1 // TODO: this should be fixed in vdr cTSBuffer #if 1 // TODO: this should be fixed in vdr cTSBuffer
// Check disconnection // Check disconnection
int fd = *ClientSocket.DataSocket(siLiveFilter); int fd = *m_ClientSocket->DataSocket(siLiveFilter);
if(fd < 0) if(fd < 0)
break; break;
cPoller Poller(fd); cPoller Poller(fd);
@ -273,7 +274,7 @@ void cStreamdevFilters::Action(void) {
++fails; ++fails;
if (fails >= 10) { if (fails >= 10) {
esyslog("cStreamdevFilters::Action(): stream disconnected ?"); esyslog("cStreamdevFilters::Action(): stream disconnected ?");
ClientSocket.CloseDataConnection(siLiveFilter); m_ClientSocket->CloseDataConnection(siLiveFilter);
break; break;
} }
} else { } else {

View File

@ -11,9 +11,11 @@
class cTSBuffer; class cTSBuffer;
class cStreamdevFilter; class cStreamdevFilter;
class cClientSocket;
class cStreamdevFilters: public cList<cStreamdevFilter>, public cThread { class cStreamdevFilters: public cList<cStreamdevFilter>, public cThread {
private: private:
cClientSocket *m_ClientSocket;
cTSBuffer *m_TSBuffer; cTSBuffer *m_TSBuffer;
protected: protected:
@ -23,7 +25,7 @@ protected:
bool ReActivateFilters(void); bool ReActivateFilters(void);
public: public:
cStreamdevFilters(void); cStreamdevFilters(cClientSocket *ClientSocket);
virtual ~cStreamdevFilters(); virtual ~cStreamdevFilters();
void SetConnection(int Handle); void SetConnection(int Handle);

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-20 23:46+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n" "Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n" "Language-Team: German <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "Konnte Server nicht pausieren!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Hauptmenüeintrag verstecken" msgstr "Hauptmenüeintrag verstecken"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Client starten" msgstr "Gleichzeitig genutzte DVB-Karten"
msgid "Remote IP" msgid "Remote IP"
msgstr "IP der Gegenseite" msgstr "IP der Gegenseite"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2010-06-19 03:58+0100\n" "PO-Revision-Date: 2010-06-19 03:58+0100\n"
"Last-Translator: Javier Bradineras <jbradi@hotmail.com>\n" "Last-Translator: Javier Bradineras <jbradi@hotmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n" "Language-Team: Spanish <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "Imposible suspender el servidor!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Ocultar entrada en menú principal" msgstr "Ocultar entrada en menú principal"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Iniciar Cliente" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Indicar IP del Servidor" msgstr "Indicar IP del Servidor"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Rolf Ahrenberg\n" "Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n" "Language-Team: Finnish <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "Palvelinta ei onnistuttu pysäyttämään!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Piilota valinta päävalikosta" msgstr "Piilota valinta päävalikosta"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Käynnistä VDR-asiakas" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Etäkoneen IP-osoite" msgstr "Etäkoneen IP-osoite"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n" "PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: micky979 <micky979@free.fr>\n" "Last-Translator: micky979 <micky979@free.fr>\n"
"Language-Team: French <vdr@linuxtv.org>\n" "Language-Team: French <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "Impossible de suspendre le serveur!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Masquer dans le menu principal" msgstr "Masquer dans le menu principal"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Démarrage du client" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Adresse IP du serveur" msgstr "Adresse IP du serveur"

View File

@ -9,14 +9,14 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-06-13 08:50+0200\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2012-06-10 20:34+0100\n" "PO-Revision-Date: 2012-06-10 20:34+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n" "Language-Team: Italian <vdr@linuxtv.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
msgid "VTP Streaming Client" msgid "VTP Streaming Client"
msgstr "Client trasmissione VTP" msgstr "Client trasmissione VTP"
@ -33,8 +33,8 @@ msgstr "Impossibile sospendere il server!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Nascondi voce menu principale" msgstr "Nascondi voce menu principale"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Avvia Client" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Indirizzo IP del Server" msgstr "Indirizzo IP del Server"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2009-11-26 21:57+0200\n" "PO-Revision-Date: 2009-11-26 21:57+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n" "Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n" "Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "Negali sustabdyti serverio!"
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Paslėpti pagrindinio meniu įrašą" msgstr "Paslėpti pagrindinio meniu įrašą"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Paleisti klientą" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Nuotolinis IP adresas" msgstr "Nuotolinis IP adresas"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev 0.5.0\n" "Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: 2008-06-26 15:36+0100\n" "PO-Revision-Date: 2008-06-26 15:36+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n" "Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n" "Language-Team: Russian <vdr@linuxtv.org>\n"
@ -31,8 +31,8 @@ msgstr "
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "ÁßàïâÐâì Ò ÓÛÐÒÝÞÜ ÜÕÝî" msgstr "ÁßàïâÐâì Ò ÓÛÐÒÝÞÜ ÜÕÝî"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "ÁâÐàâ ÚÛØÕÝâÐ" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "ÃÔÐÛÕÝÝëÙ IP" msgstr "ÃÔÐÛÕÝÝëÙ IP"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: streamdev_SK\n" "Project-Id-Version: streamdev_SK\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n" "Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2012-03-03 23:57+0100\n" "POT-Creation-Date: 2013-01-28 22:16+0100\n"
"PO-Revision-Date: \n" "PO-Revision-Date: \n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n" "Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <hrala.milan@gmail.com>\n" "Language-Team: Slovak <hrala.milan@gmail.com>\n"
@ -33,8 +33,8 @@ msgstr "Nepodarilo sa pozastavi
msgid "Hide Mainmenu Entry" msgid "Hide Mainmenu Entry"
msgstr "Schova» polo¾ku v hlavnom menu" msgstr "Schova» polo¾ku v hlavnom menu"
msgid "Start Client" msgid "Simultaneously used Devices"
msgstr "Spusti» Klienta" msgstr ""
msgid "Remote IP" msgid "Remote IP"
msgstr "Vzdialená IP" msgstr "Vzdialená IP"

View File

@ -5,7 +5,7 @@
#include <vdr/menuitems.h> #include <vdr/menuitems.h>
#include "client/setup.h" #include "client/setup.h"
#include "client/device.h" #include "client/streamdev-client.h"
#ifndef MINPRIORITY #ifndef MINPRIORITY
#define MINPRIORITY -MAXPRIORITY #define MINPRIORITY -MAXPRIORITY
@ -50,11 +50,12 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
return true; return true;
} }
cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) { cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(cPluginStreamdevClient *Plugin) {
m_Plugin = Plugin;
m_NewSetup = StreamdevClientSetup; m_NewSetup = StreamdevClientSetup;
Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"), &m_NewSetup.HideMenuEntry)); Add(new cMenuEditBoolItem(tr("Hide Mainmenu Entry"), &m_NewSetup.HideMenuEntry));
Add(new cMenuEditBoolItem(tr("Start Client"), &m_NewSetup.StartClient)); Add(new cMenuEditIntItem (tr("Simultaneously used Devices"), &m_NewSetup.StartClient, 0, STREAMDEV_MAXDEVICES));
Add(new cMenuEditIpItem (tr("Remote IP"), m_NewSetup.RemoteIp)); Add(new cMenuEditIpItem (tr("Remote IP"), m_NewSetup.RemoteIp));
Add(new cMenuEditIntItem (tr("Remote Port"), &m_NewSetup.RemotePort, 0, 65535)); Add(new cMenuEditIntItem (tr("Remote Port"), &m_NewSetup.RemotePort, 0, 65535));
Add(new cMenuEditIntItem (tr("Timeout (s)"), &m_NewSetup.Timeout, 1, 15)); Add(new cMenuEditIntItem (tr("Timeout (s)"), &m_NewSetup.Timeout, 1, 15));
@ -74,11 +75,6 @@ cStreamdevClientMenuSetupPage::~cStreamdevClientMenuSetupPage() {
} }
void cStreamdevClientMenuSetupPage::Store(void) { void cStreamdevClientMenuSetupPage::Store(void) {
if (m_NewSetup.StartClient != StreamdevClientSetup.StartClient) {
if (m_NewSetup.StartClient)
cStreamdevDevice::Init();
}
SetupStore("StartClient", m_NewSetup.StartClient); SetupStore("StartClient", m_NewSetup.StartClient);
if (strcmp(m_NewSetup.RemoteIp, "") == 0) if (strcmp(m_NewSetup.RemoteIp, "") == 0)
SetupStore("RemoteIp", "-none-"); SetupStore("RemoteIp", "-none-");
@ -97,6 +93,6 @@ void cStreamdevClientMenuSetupPage::Store(void) {
StreamdevClientSetup = m_NewSetup; StreamdevClientSetup = m_NewSetup;
cStreamdevDevice::ReInit(); m_Plugin->Initialize();
} }

View File

@ -28,15 +28,18 @@ struct cStreamdevClientSetup {
extern cStreamdevClientSetup StreamdevClientSetup; extern cStreamdevClientSetup StreamdevClientSetup;
class cPluginStreamdevClient;
class cStreamdevClientMenuSetupPage: public cMenuSetupPage { class cStreamdevClientMenuSetupPage: public cMenuSetupPage {
private: private:
cStreamdevClientSetup m_NewSetup; cPluginStreamdevClient *m_Plugin;
cStreamdevClientSetup m_NewSetup;
protected: protected:
virtual void Store(void); virtual void Store(void);
public: public:
cStreamdevClientMenuSetupPage(void); cStreamdevClientMenuSetupPage(cPluginStreamdevClient *Plugin);
virtual ~cStreamdevClientMenuSetupPage(); virtual ~cStreamdevClientMenuSetupPage();
}; };

View File

@ -18,12 +18,11 @@
#include "client/socket.h" #include "client/socket.h"
#include "common.h" #include "common.h"
cClientSocket ClientSocket;
cClientSocket::cClientSocket(void) cClientSocket::cClientSocket(void)
{ {
memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count); memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count);
m_ServerVersion = 0; m_ServerVersion = 0;
m_Priority = -100;
m_Prio = false; m_Prio = false;
m_Abort = false; m_Abort = false;
m_LastSignalUpdate = 0; m_LastSignalUpdate = 0;
@ -284,12 +283,19 @@ bool cClientSocket::SetChannelDevice(const cChannel *Channel) {
} }
bool cClientSocket::SetPriority(int Priority) { bool cClientSocket::SetPriority(int Priority) {
if (Priority == m_Priority)
return true;
if (!CheckConnection()) return false; if (!CheckConnection()) return false;
CMD_LOCK; CMD_LOCK;
std::string command = (std::string)"PRIO " + (const char*)itoa(Priority); std::string command = (std::string)"PRIO " + (const char*)itoa(Priority);
return Command(command, 220); if (!Command(command, 220))
return false;
m_Priority = Priority;
return true;
} }
bool cClientSocket::GetSignal(int *SignalStrength, int *SignalQuality, int *Dev) { bool cClientSocket::GetSignal(int *SignalStrength, int *SignalQuality, int *Dev) {

View File

@ -23,6 +23,7 @@ private:
char m_Buffer[BUFSIZ + 1]; // various uses char m_Buffer[BUFSIZ + 1]; // various uses
unsigned int m_ServerVersion; unsigned int m_ServerVersion;
bool m_Prio; // server supports command PRIO bool m_Prio; // server supports command PRIO
int m_Priority; // current device priority
bool m_Abort; // quit command pending bool m_Abort; // quit command pending
time_t m_LastSignalUpdate; time_t m_LastSignalUpdate;
@ -55,6 +56,7 @@ public:
bool SetChannelDevice(const cChannel *Channel); bool SetChannelDevice(const cChannel *Channel);
bool SupportsPrio() { return m_Prio; } bool SupportsPrio() { return m_Prio; }
unsigned int ServerVersion() { return m_ServerVersion; } unsigned int ServerVersion() { return m_ServerVersion; }
int Priority() const { return m_Priority; }
bool SetPriority(int Priority); bool SetPriority(int Priority);
bool SetPid(int Pid, bool On); bool SetPid(int Pid, bool On);
bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On); bool SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On);
@ -66,6 +68,4 @@ public:
cTBSocket *DataSocket(eSocketId Id) const; cTBSocket *DataSocket(eSocketId Id) const;
}; };
extern class cClientSocket ClientSocket;
#endif // VDR_STREAMDEV_CLIENT_CONNECTION_H #endif // VDR_STREAMDEV_CLIENT_CONNECTION_H

View File

@ -16,7 +16,7 @@
const char *cPluginStreamdevClient::DESCRIPTION = trNOOP("VTP Streaming Client"); const char *cPluginStreamdevClient::DESCRIPTION = trNOOP("VTP Streaming Client");
cPluginStreamdevClient::cPluginStreamdevClient(void) { cPluginStreamdevClient::cPluginStreamdevClient(void): m_Devices() {
} }
cPluginStreamdevClient::~cPluginStreamdevClient() { cPluginStreamdevClient::~cPluginStreamdevClient() {
@ -26,9 +26,13 @@ const char *cPluginStreamdevClient::Description(void) {
return tr(DESCRIPTION); return tr(DESCRIPTION);
} }
bool cPluginStreamdevClient::Start(void) { bool cPluginStreamdevClient::Initialize(void) {
I18nRegister(PLUGIN_NAME_I18N); for (int i = 0; i < STREAMDEV_MAXDEVICES; i++) {
cStreamdevDevice::Init(); if (m_Devices[i])
m_Devices[i]->ReInit(i >= StreamdevClientSetup.StartClient);
else if (i < StreamdevClientSetup.StartClient)
m_Devices[i] = new cStreamdevDevice();
}
return true; return true;
} }
@ -37,7 +41,7 @@ const char *cPluginStreamdevClient::MainMenuEntry(void) {
} }
cOsdObject *cPluginStreamdevClient::MainMenuAction(void) { cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
if (ClientSocket.SuspendServer()) if (StreamdevClientSetup.StartClient && m_Devices[0]->SuspendServer())
Skins.Message(mtInfo, tr("Server is suspended")); Skins.Message(mtInfo, tr("Server is suspended"));
else else
Skins.Message(mtError, tr("Couldn't suspend Server!")); Skins.Message(mtError, tr("Couldn't suspend Server!"));
@ -45,7 +49,7 @@ cOsdObject *cPluginStreamdevClient::MainMenuAction(void) {
} }
cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) { cMenuSetupPage *cPluginStreamdevClient::SetupMenu(void) {
return new cStreamdevClientMenuSetupPage; return new cStreamdevClientMenuSetupPage(this);
} }
bool cPluginStreamdevClient::SetupParse(const char *Name, const char *Value) { bool cPluginStreamdevClient::SetupParse(const char *Name, const char *Value) {
@ -61,7 +65,8 @@ bool cPluginStreamdevClient::Service(const char *Id, void *Data) {
} }
void cPluginStreamdevClient::MainThreadHook(void) { void cPluginStreamdevClient::MainThreadHook(void) {
cStreamdevDevice::UpdatePriority(); for (int i = 0; i < StreamdevClientSetup.StartClient; i++)
m_Devices[i]->UpdatePriority();
} }
VDRPLUGINCREATOR(cPluginStreamdevClient); // Don't touch this! VDRPLUGINCREATOR(cPluginStreamdevClient); // Don't touch this!

View File

@ -9,16 +9,20 @@
#include <vdr/plugin.h> #include <vdr/plugin.h>
#define STREAMDEV_MAXDEVICES 8
class cStreamdevDevice;
class cPluginStreamdevClient : public cPlugin { class cPluginStreamdevClient : public cPlugin {
private: private:
static const char *DESCRIPTION; static const char *DESCRIPTION;
cStreamdevDevice *m_Devices[STREAMDEV_MAXDEVICES];
public: public:
cPluginStreamdevClient(void); cPluginStreamdevClient(void);
virtual ~cPluginStreamdevClient(); virtual ~cPluginStreamdevClient();
virtual const char *Version(void) { return VERSION; } virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void); virtual const char *Description(void);
virtual bool Start(void); virtual bool Initialize(void);
virtual const char *MainMenuEntry(void); virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void); virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void); virtual cMenuSetupPage *SetupMenu(void);