summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/connection.c212
-rw-r--r--server/connection.h13
-rw-r--r--server/connectionHTTP.c21
-rw-r--r--server/connectionIGMP.c6
-rw-r--r--server/connectionVTP.c48
-rw-r--r--server/connectionVTP.h6
-rw-r--r--server/livestreamer.c31
-rw-r--r--server/livestreamer.h1
-rw-r--r--server/menuHTTP.c19
-rw-r--r--server/menuHTTP.h12
-rw-r--r--server/streamer.c8
11 files changed, 281 insertions, 96 deletions
diff --git a/server/connection.c b/server/connection.c
index 956c42a..2ba99f3 100644
--- a/server/connection.c
+++ b/server/connection.c
@@ -1,5 +1,5 @@
/*
- * $Id: connection.c,v 1.14 2010/07/19 13:49:31 schmirl Exp $
+ * $Id: connection.c,v 1.16 2010/08/03 10:51:53 schmirl Exp $
*/
#include "server/connection.h"
@@ -8,6 +8,7 @@
#include "common.h"
#include <vdr/tools.h>
+#include <vdr/transfer.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
@@ -184,75 +185,172 @@ bool cServerConnection::Respond(const char *Message, bool Last, ...)
m_Pending = !Last;
return true;
}
-
+
+#if APIVERSNUM >= 10700
+static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
+{
+ int MaxNumProvidedSystems = 1 << AvailableBits;
+ int NumProvidedSystems = Device->NumProvidedSystems();
+ if (NumProvidedSystems > MaxNumProvidedSystems) {
+ esyslog("ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed", Device->CardIndex() + 1, NumProvidedSystems, MaxNumProvidedSystems);
+ NumProvidedSystems = MaxNumProvidedSystems;
+ }
+ else if (NumProvidedSystems <= 0) {
+ esyslog("ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1", Device->CardIndex() + 1, NumProvidedSystems);
+ NumProvidedSystems = 1;
+ }
+ return NumProvidedSystems;
+}
+#endif
+
+/*
+ * copy of cDevice::GetDevice(...) but without side effects (not detaching receivers)
+ */
+cDevice* cServerConnection::CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice)
+{
+ //cDevice *AvoidDevice = avoidDevice;
+ //avoidDevice = NULL;
+ // Collect the current priorities of all CAM slots that can decrypt the channel:
+ int NumCamSlots = CamSlots.Count();
+ int SlotPriority[NumCamSlots];
+ int NumUsableSlots = 0;
+ if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
+ for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
+ SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
+ if (CamSlot->ModuleStatus() == msReady) {
+ if (CamSlot->ProvidesCa(Channel->Caids())) {
+ if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->SlotNumber())) {
+ SlotPriority[CamSlot->Index()] = CamSlot->Priority();
+ NumUsableSlots++;
+ }
+ }
+ }
+ }
+ if (!NumUsableSlots)
+ return NULL; // no CAM is able to decrypt this channel
+ }
+
+ bool NeedsDetachReceivers = false;
+ cDevice *d = NULL;
+ //cCamSlot *s = NULL;
+
+ uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
+ for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
+ if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
+ continue; // there is no CAM available in this slot
+ for (int i = 0; i < cDevice::NumDevices(); i++) {
+ cDevice *device = cDevice::GetDevice(i);
+ if (device == AvoidDevice)
+ continue; // we've been asked to skip this device
+ if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device->CardIndex() + 1)
+ continue; // a specific card was requested, but not this one
+ if (NumUsableSlots && !CamSlots.Get(j)->Assign(device, true))
+ continue; // CAM slot can't be used with this device
+ bool ndr;
+ if (device->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
+ if (NumUsableSlots && device->CamSlot() && device->CamSlot() != CamSlots.Get(j))
+ ndr = true; // using a different CAM slot requires detaching receivers
+ // Put together an integer number that reflects the "impact" using
+ // this device would have on the overall system. Each condition is represented
+ // by one bit in the number (or several bits, if the condition is actually
+ // a numeric value). The sequence in which the conditions are listed corresponds
+ // to their individual severity, where the one listed first will make the most
+ // difference, because it results in the most significant bit of the result.
+ uint32_t imp = 0;
+ imp <<= 1; imp |= LiveView ? !device->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
+ imp <<= 1; imp |= !device->Receiving() && (device != cTransferControl::ReceiverDevice() || device->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
+ imp <<= 1; imp |= device->Receiving(); // avoid devices that are receiving
+#if APIVERSNUM >= 10700
+ imp <<= 2; imp |= GetClippedNumProvidedSystems(2, device) - 1; // avoid cards which support multiple delivery systems
+#endif
+ imp <<= 1; imp |= device == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
+ imp <<= 8; imp |= min(max(device->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+ imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
+ imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
+ imp <<= 1; imp |= device->IsPrimaryDevice(); // avoid the primary device
+ imp <<= 1; imp |= NumUsableSlots ? 0 : device->HasCi(); // avoid cards with Common Interface for FTA channels
+ imp <<= 1; imp |= device->HasDecoder(); // avoid full featured cards
+ imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
+ if (imp < Impact) {
+ // This device has less impact than any previous one, so we take it.
+ Impact = imp;
+ d = device;
+ NeedsDetachReceivers = ndr;
+ }
+ }
+ }
+ if (!NumUsableSlots)
+ break; // no CAM necessary, so just one loop over the devices
+ }
+ return d;
+}
+
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
{
- cDevice *device = NULL;
-
- /*Dprintf("+ Statistics:\n");
- Dprintf("+ Current Channel: %d\n", cDevice::CurrentChannel());
- Dprintf("+ Current Device: %d\n", cDevice::ActualDevice()->CardIndex());
- Dprintf("+ Transfer Mode: %s\n", cDevice::ActualDevice()
- == cDevice::PrimaryDevice() ? "false" : "true");
- Dprintf("+ Replaying: %s\n", cDevice::PrimaryDevice()->Replaying() ? "true"
- : "false");*/
-
- Dprintf(" * GetDevice(const cChannel*, int)\n");
- Dprintf(" * -------------------------------\n");
-
- device = cDevice::GetDevice(Channel, Priority, false);
-
- Dprintf(" * Found following device: %p (%d)\n", device,
- device ? device->CardIndex() + 1 : 0);
- if (device == cDevice::ActualDevice())
- Dprintf(" * is actual device\n");
- if (!cSuspendCtl::IsActive() && StreamdevServerSetup.SuspendMode != smAlways)
- Dprintf(" * NOT suspended\n");
-
- if (!device || (device == cDevice::ActualDevice()
+ const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
+
+ // turn off the streams of this connection
+ Detach();
+ // This call may detach receivers of the device it returns
+ cDevice *device = cDevice::GetDevice(Channel, Priority, false);
+
+ if (device && device == cDevice::ActualDevice()
&& !cSuspendCtl::IsActive()
- && StreamdevServerSetup.SuspendMode != smAlways)) {
+ && StreamdevServerSetup.SuspendMode != smAlways
+ && current != NULL
+ && !TRANSPONDER(Channel, current)) {
+ // now we would have to switch away live tv...let's see if live tv
+ // can be handled by another device
+#if VDRVERSNUM >= 10516
+ cDevice::SetAvoidDevice(device);
+ cDevice *newdev = cDevice::GetDevice(current, 0, true);
+#else
+ cDevice *newdev = CheckDevice(current, 0, true, device);
+#endif
+ if (newdev)
+ newdev->SwitchChannel(current, true);
+ else
+ device = NULL;
+ }
+
+ if (!device) {
+ // can't switch - continue the current stream
+ Attach();
+ dsyslog("streamdev: GetDevice failed for channel %s at priority %d", Channel->Name(), Priority);
+ }
+ return device;
+}
+
+bool cServerConnection::ProvidesChannel(const cChannel *Channel, int Priority)
+{
+ const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
+
+ cDevice *device = CheckDevice(Channel, Priority, false);
+ if (!device || (device == cDevice::ActualDevice()
+ && !cSuspendCtl::IsActive()
+ && StreamdevServerSetup.SuspendMode != smAlways
+ && current != NULL
+ && !TRANSPONDER(Channel, current))) {
// mustn't switch actual device
// maybe a device would be free if THIS connection did turn off its streams?
- Dprintf(" * trying again...\n");
- const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
- isyslog("streamdev-server: Detaching current receiver");
Detach();
- device = cDevice::GetDevice(Channel, Priority, false);
+ device = CheckDevice(Channel, Priority, false);
Attach();
- Dprintf(" * Found following device: %p (%d)\n", device,
- device ? device->CardIndex() + 1 : 0);
- if (device == cDevice::ActualDevice())
- Dprintf(" * is actual device\n");
- if (!cSuspendCtl::IsActive()
- && StreamdevServerSetup.SuspendMode != smAlways)
- Dprintf(" * NOT suspended\n");
- if (current && !TRANSPONDER(Channel, current))
- Dprintf(" * NOT same transponder\n");
- if (device && (device == cDevice::ActualDevice()
- && !cSuspendCtl::IsActive()
+ if (device && device == cDevice::ActualDevice()
+ && !cSuspendCtl::IsActive()
&& StreamdevServerSetup.SuspendMode != smAlways
&& current != NULL
- && !TRANSPONDER(Channel, current))) {
+ && !TRANSPONDER(Channel, current)) {
// now we would have to switch away live tv...let's see if live tv
// can be handled by another device
- cDevice *newdev = NULL;
- for (int i = 0; i < cDevice::NumDevices(); ++i) {
- cDevice *dev = cDevice::GetDevice(i);
- if (dev->ProvidesChannel(current, 0) && dev != device) {
- newdev = dev;
- break;
- }
- }
- Dprintf(" * Found device for live tv: %p (%d)\n", newdev,
- newdev ? newdev->CardIndex() + 1 : 0);
- if (newdev == NULL || newdev == device)
- // no suitable device to continue live TV, giving up...
+ cDevice *newdev = CheckDevice(current, 0, true, device);
+ if (!newdev) {
device = NULL;
- else
- newdev->SwitchChannel(current, true);
+ dsyslog("streamdev: Not providing channel %s at priority %d - live TV not suspended", Channel->Name(), Priority);
+ }
}
+ else if (!device)
+ dsyslog("streamdev: No device provides channel %s at priority %d", Channel->Name(), Priority);
}
-
return device;
}
diff --git a/server/connection.h b/server/connection.h
index ff5ee98..22301b1 100644
--- a/server/connection.h
+++ b/server/connection.h
@@ -1,5 +1,5 @@
/*
- * $Id: connection.h,v 1.9 2010/07/19 13:49:31 schmirl Exp $
+ * $Id: connection.h,v 1.10 2010/08/03 10:46:41 schmirl Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
@@ -35,6 +35,11 @@ private:
tStrStrMap m_Headers;
+ /* Check if a device would be available for transfering the given
+ channel. This call has no side effects except for temporarily
+ detaching this connection's receivers. */
+ cDevice *CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice = NULL);
+
protected:
/* Will be called when a command terminated by a newline has been
received */
@@ -91,10 +96,14 @@ public:
/* Will make the socket close after sending all queued output data */
void DeferClose(void) { m_DeferClose = true; }
- /* Will retrieve an unused device for transmitting data. Use the returned
+ /* Will retrieve an unused device for transmitting data. Receivers have
+ already been attached from the device if necessary. Use the returned
cDevice in a following call to StartTransfer */
cDevice *GetDevice(const cChannel *Channel, int Priority);
+ /* Test if a call to GetDevice would return a usable device. */
+ bool ProvidesChannel(const cChannel *Channel, int Priority);
+
virtual void Flushed(void) {}
virtual void Detach(void) = 0;
diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c
index 028b9ea..54ccf5a 100644
--- a/server/connectionHTTP.c
+++ b/server/connectionHTTP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionHTTP.c,v 1.19 2010/07/20 12:26:29 schmirl Exp $
+ * $Id: connectionHTTP.c,v 1.21 2010/08/03 10:46:41 schmirl Exp $
*/
#include <ctype.h>
@@ -140,11 +140,18 @@ bool cConnectionHTTP::ProcessRequest(void)
}
}
- if (Headers().at(REQUEST_METHOD).compare("GET") == 0 && ProcessURI(Headers().at(PATH_INFO))) {
+ tStrStrMap::const_iterator it_method = Headers().find(REQUEST_METHOD);
+ tStrStrMap::const_iterator it_pathinfo = Headers().find(PATH_INFO);
+ if (it_method == Headers().end() || it_pathinfo == Headers().end()) {
+ // should never happen
+ esyslog("streamdev-server connectionHTTP: Missing method or pathinfo");
+ } else if (it_method->second.compare("GET") == 0 && ProcessURI(it_pathinfo->second)) {
if (m_ChannelList)
return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
else if (m_Channel != NULL) {
- cDevice *device = GetDevice(m_Channel, 0);
+ cDevice *device = NULL;
+ if (ProvidesChannel(m_Channel, 0))
+ device = GetDevice(m_Channel, 0);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
@@ -176,13 +183,12 @@ bool cConnectionHTTP::ProcessRequest(void)
return Respond("HTTP/1.0 404 not found")
&& Respond("");
}
- } else if (Headers().at(REQUEST_METHOD).compare("HEAD") == 0 && ProcessURI(Headers().at(PATH_INFO))) {
+ } else if (it_method->second.compare("HEAD") == 0 && ProcessURI(it_pathinfo->second)) {
DeferClose();
if (m_ChannelList)
return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
else if (m_Channel != NULL) {
- cDevice *device = GetDevice(m_Channel, 0);
- if (device != NULL) {
+ if (ProvidesChannel(m_Channel, 0)) {
if (m_StreamType == stEXT) {
// TODO
return Respond("HTTP/1.0 200 OK")
@@ -249,7 +255,8 @@ cChannelList* cConnectionHTTP::ChannelListFromString(const std::string& Path, co
const static std::string QUERY_STRING("QUERY_STRING");
const static std::string HOST("HTTP_HOST");
- const std::string query = Headers().at(QUERY_STRING);
+ tStrStrMap::const_iterator it_query = Headers().find(QUERY_STRING);
+ const std::string& query = it_query == Headers().end() ? "" : it_query->second;
std::string groupTarget;
cChannelIterator *iterator = NULL;
diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c
index 50db15b..708f41c 100644
--- a/server/connectionIGMP.c
+++ b/server/connectionIGMP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionIGMP.c,v 1.2 2010/07/19 13:49:31 schmirl Exp $
+ * $Id: connectionIGMP.c,v 1.3 2010/08/03 10:46:41 schmirl Exp $
*/
#include <ctype.h>
@@ -25,7 +25,9 @@ cConnectionIGMP::~cConnectionIGMP()
bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
{
if (Channel != NULL) {
- cDevice *device = GetDevice(Channel, 0);
+ cDevice *device = NULL;
+ if (ProvidesChannel(Channel, 0))
+ device = GetDevice(Channel, 0);
if (device != NULL) {
device->SwitchChannel(Channel, false);
struct in_addr ip;
diff --git a/server/connectionVTP.c b/server/connectionVTP.c
index 861bc83..0f92db0 100644
--- a/server/connectionVTP.c
+++ b/server/connectionVTP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionVTP.c,v 1.28 2010/07/19 13:49:31 schmirl Exp $
+ * $Id: connectionVTP.c,v 1.31 2010/08/18 10:26:54 schmirl Exp $
*/
#include "server/connectionVTP.h"
@@ -746,6 +746,8 @@ cConnectionVTP::cConnectionVTP(void):
m_StreamType(stTSPIDS),
m_FiltersSupport(false),
m_RecPlayer(NULL),
+ m_TuneChannel(NULL),
+ m_TunePriority(0),
m_LSTEHandler(NULL),
m_LSTCHandler(NULL),
m_LSTTHandler(NULL),
@@ -836,6 +838,7 @@ bool cConnectionVTP::Command(char *Cmd)
else if (strcasecmp(Cmd, "READ") == 0) return CmdREAD(param);
else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(param);
else if (strcasecmp(Cmd, "PLAY") == 0) return CmdPLAY(param);
+ else if (strcasecmp(Cmd, "PRIO") == 0) return CmdPRIO(param);
else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(param);
else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(param);
else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param);
@@ -894,6 +897,11 @@ bool cConnectionVTP::CmdCAPS(char *Opts)
return Respond(220, "Capability \"%s\" accepted", Opts);
}
+ // Command PRIO is known
+ if (strcasecmp(Opts, "PRIO") == 0) {
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
return Respond(561, "Capability \"%s\" not known", Opts);
}
@@ -911,9 +919,15 @@ bool cConnectionVTP::CmdPROV(char *Opts)
if ((chan = ChannelFromString(Opts)) == NULL)
return Respond(550, "Undefined channel \"%s\"", Opts);
- return GetDevice(chan, prio) != NULL
- ? Respond(220, "Channel available")
- : Respond(560, "Channel not available");
+ if (ProvidesChannel(chan, prio)) {
+ m_TuneChannel = chan;
+ m_TunePriority = prio;
+ return Respond(220, "Channel available");
+ }
+ else {
+ m_TuneChannel = NULL;
+ return Respond(560, "Channel not available");
+ }
}
bool cConnectionVTP::CmdPORT(char *Opts)
@@ -1067,18 +1081,23 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
{
const cChannel *chan;
cDevice *dev;
+ int prio = m_TunePriority;
if ((chan = ChannelFromString(Opts)) == NULL)
return Respond(550, "Undefined channel \"%s\"", Opts);
- if ((dev = GetDevice(chan, 0)) == NULL)
+ if (chan != m_TuneChannel) {
+ esyslog("streamdev-server TUNE %s: Priority unknown - using 0", Opts);
+ prio = 0;
+ }
+ if ((dev = GetDevice(chan, prio)) == NULL)
return Respond(560, "Channel not available");
if (!dev->SwitchChannel(chan, false))
return Respond(560, "Channel not available");
delete m_LiveStreamer;
- m_LiveStreamer = new cStreamdevLiveStreamer(1, this);
+ m_LiveStreamer = new cStreamdevLiveStreamer(prio, this);
m_LiveStreamer->SetChannel(chan, m_StreamType);
m_LiveStreamer->SetDevice(dev);
if(m_LiveSocket)
@@ -1119,6 +1138,22 @@ bool cConnectionVTP::CmdPLAY(char *Opts)
}
}
+bool cConnectionVTP::CmdPRIO(char *Opts)
+{
+ int prio;
+ char *end;
+
+ prio = strtoul(Opts, &end, 10);
+ if (end == Opts || (*end != '\0' && *end != ' '))
+ return Respond(500, "Use: PRIO Priority");
+
+ if (m_LiveStreamer) {
+ m_LiveStreamer->SetPriority(prio);
+ return Respond(220, "Priority changed to %d", prio);
+ }
+ return Respond(550, "Priority not applicable");
+}
+
bool cConnectionVTP::CmdADDP(char *Opts)
{
int pid;
@@ -1243,6 +1278,7 @@ bool cConnectionVTP::CmdSUSP(void)
else if (StreamdevServerSetup.SuspendMode == smOffer
&& StreamdevServerSetup.AllowSuspend) {
cControl::Launch(new cSuspendCtl);
+ cControl::Attach();
return Respond(220, "Server is suspended");
} else
return Respond(550, "Client may not suspend server");
diff --git a/server/connectionVTP.h b/server/connectionVTP.h
index b938fe6..ee842fe 100644
--- a/server/connectionVTP.h
+++ b/server/connectionVTP.h
@@ -31,6 +31,11 @@ private:
bool m_FiltersSupport;
RecPlayer *m_RecPlayer;
+ // Priority is only known in PROV command
+ // Store in here for later use in TUNE call
+ const cChannel *m_TuneChannel;
+ int m_TunePriority;
+
// Members adopted for SVDRP
cLSTEHandler *m_LSTEHandler;
cLSTCHandler *m_LSTCHandler;
@@ -59,6 +64,7 @@ public:
bool CmdREAD(char *Opts);
bool CmdTUNE(char *Opts);
bool CmdPLAY(char *Opts);
+ bool CmdPRIO(char *Opts);
bool CmdADDP(char *Opts);
bool CmdDELP(char *Opts);
bool CmdADDF(char *Opts);
diff --git a/server/livestreamer.c b/server/livestreamer.c
index 2b0065c..1286abd 100644
--- a/server/livestreamer.c
+++ b/server/livestreamer.c
@@ -289,7 +289,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i
if (written != TS_SIZE)
siBuffer.ReportOverflow(TS_SIZE - written);
if (pmtPid != prevPmtPid) {
- m_Streamer->SetPids(pmtPid);
+ m_Streamer->SetPid(pmtPid, true);
Add(pmtPid, 0x02);
pmtVersion = -1;
}
@@ -434,17 +434,24 @@ bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2
return true;
}
+void cStreamdevLiveStreamer::SetPriority(int Priority)
+{
+ m_Priority = Priority;
+ StartReceiver();
+}
+
void cStreamdevLiveStreamer::StartReceiver(void)
{
- DELETENULL(m_Receiver);
- if (m_NumPids > 0) {
+ if (m_Device != NULL && m_NumPids > 0 && IsRunning()) {
Dprintf("Creating Receiver to respect changed pids\n");
+ cReceiver *current = m_Receiver;
m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
- if (IsRunning() && m_Device != NULL) {
- Dprintf("Attaching new receiver\n");
- Attach();
- }
+ cThreadLock ThreadLock(m_Device);
+ Attach();
+ delete current;
}
+ else
+ DELETENULL(m_Receiver);
}
bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, const int* Apid, const int *Dpid)
@@ -631,12 +638,10 @@ void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
{
Dprintf("cStreamdevFilterStreamer::SetDevice()\n");
LOCK_THREAD;
- if(Device != m_Device) {
- Detach();
- m_Device = Device;
- //m_Channel = NULL;
- Attach();
- }
+ Detach();
+ m_Device = Device;
+ //m_Channel = NULL;
+ Attach();
}
bool cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On)
diff --git a/server/livestreamer.h b/server/livestreamer.h
index 283a395..71feb4c 100644
--- a/server/livestreamer.h
+++ b/server/livestreamer.h
@@ -38,6 +38,7 @@ public:
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);
virtual int Put(const uchar *Data, int Count);
virtual uchar *Get(int &Count);
diff --git a/server/menuHTTP.c b/server/menuHTTP.c
index 5fb5010..d7fb817 100644
--- a/server/menuHTTP.c
+++ b/server/menuHTTP.c
@@ -2,7 +2,7 @@
#include "server/menuHTTP.h"
//**************************** cChannelIterator **************
-cChannelIterator::cChannelIterator(cChannel *First): channel(First)
+cChannelIterator::cChannelIterator(const cChannel *First): channel(First)
{}
const cChannel* cChannelIterator::Next()
@@ -19,7 +19,7 @@ cListAll::cListAll(): cChannelIterator(Channels.First())
const cChannel* cListAll::NextChannel(const cChannel *Channel)
{
if (Channel)
- Channel = Channels.Next(Channel);
+ Channel = SkipFakeGroups(Channels.Next(Channel));
return Channel;
}
@@ -46,14 +46,19 @@ const cChannel* cListGroups::NextChannel(const cChannel *Channel)
}
//
// ********************* cListGroup ****************
-cListGroup::cListGroup(const cChannel *Group): cChannelIterator((Group && Group->GroupSep() && Channels.Next(Group) && !Channels.Next(Group)->GroupSep()) ? Channels.Next(Group) : NULL)
+cListGroup::cListGroup(const cChannel *Group): cChannelIterator(GetNextChannelInGroup(Group))
{}
-const cChannel* cListGroup::NextChannel(const cChannel *Channel)
+const cChannel* cListGroup::GetNextChannelInGroup(const cChannel *Channel)
{
if (Channel)
- Channel = Channels.Next(Channel);
- return (Channel && !Channel->GroupSep()) ? Channel : NULL;
+ Channel = SkipFakeGroups(Channels.Next(Channel));
+ return Channel && !Channel->GroupSep() ? Channel : NULL;
+}
+
+const cChannel* cListGroup::NextChannel(const cChannel *Channel)
+{
+ return GetNextChannelInGroup(Channel);
}
//
// ********************* cListTree ****************
@@ -68,7 +73,7 @@ const cChannel* cListTree::NextChannel(const cChannel *Channel)
if (currentGroup == selectedGroup)
{
if (Channel)
- Channel = Channels.Next(Channel);
+ Channel = SkipFakeGroups(Channels.Next(Channel));
if (Channel && Channel->GroupSep())
currentGroup = Channel;
}
diff --git a/server/menuHTTP.h b/server/menuHTTP.h
index cbd7b59..4ef6363 100644
--- a/server/menuHTTP.h
+++ b/server/menuHTTP.h
@@ -13,9 +13,10 @@ class cChannelIterator
const cChannel *channel;
protected:
virtual const cChannel* NextChannel(const cChannel *Channel) = 0;
+ static inline const cChannel* SkipFakeGroups(const cChannel *Channel);
public:
const cChannel* Next();
- cChannelIterator(cChannel *First);
+ cChannelIterator(const cChannel *First);
virtual ~cChannelIterator() {};
};
@@ -48,6 +49,8 @@ class cListGroups: public cChannelIterator
class cListGroup: public cChannelIterator
{
+ private:
+ static const cChannel* GetNextChannelInGroup(const cChannel *Channel);
protected:
virtual const cChannel* NextChannel(const cChannel *Channel);
public:
@@ -140,4 +143,11 @@ class cM3uChannelList: public cChannelList
virtual ~cM3uChannelList();
};
+inline const cChannel* cChannelIterator::SkipFakeGroups(const cChannel* Group)
+{
+ while (Group && Group->GroupSep() && !*Group->Name())
+ Group = Channels.Next(Group);
+ return Group;
+}
+
#endif
diff --git a/server/streamer.c b/server/streamer.c
index c92e7ee..ec7d3c3 100644
--- a/server/streamer.c
+++ b/server/streamer.c
@@ -1,5 +1,5 @@
/*
- * $Id: streamer.c,v 1.20 2010/07/19 13:49:32 schmirl Exp $
+ * $Id: streamer.c,v 1.21 2010/07/30 10:01:11 schmirl Exp $
*/
#include <vdr/ringbuffer.h>
@@ -46,6 +46,9 @@ void cStreamdevWriter::Action(void)
uchar *block = NULL;
int count, offset = 0;
+#if APIVERSNUM >= 10705
+ SetPriority(-3);
+#endif
sel.Clear();
sel.Add(*m_Socket, true);
while (Running()) {
@@ -149,6 +152,9 @@ void cStreamdevStreamer::Stop(void)
void cStreamdevStreamer::Action(void)
{
+#if APIVERSNUM >= 10705
+ SetPriority(-3);
+#endif
while (Running()) {
int got;
uchar *block = m_RingBuffer->Get(got);