diff --git a/device.c b/device.c index 681049b..c758390 100644 --- a/device.c +++ b/device.c @@ -72,12 +72,21 @@ cDevice *cDevice::device[MAXDEVICES] = { NULL }; cDevice *cDevice::primaryDevice = NULL; cDevice *cDevice::avoidDevice = NULL; cList cDevice::deviceHooks; +cDevice *cDevice::nextParentDevice = NULL; -cDevice::cDevice(void) +cDevice::cDevice(cDevice *ParentDevice) :patPmtParser(true) -{ - cardIndex = nextCardIndex++; - dsyslog("new device number %d", CardIndex() + 1); +,parentDevice(ParentDevice) +,subDevice(NULL) +{ + if (!ParentDevice) + parentDevice = nextParentDevice; + cDevice::nextParentDevice = NULL; + if (parentDevice) + cardIndex = parentDevice->cardIndex; + else + cardIndex = nextCardIndex++; + dsyslog("new %sdevice number %d", parentDevice ? "sub-" : "", CardIndex() + 1); SetDescription("receiver on device %d", CardIndex() + 1); @@ -108,10 +117,14 @@ cDevice::cDevice(void) for (int i = 0; i < MAXRECEIVERS; i++) receiver[i] = NULL; - if (numDevices < MAXDEVICES) - device[numDevices++] = this; + if (!parentDevice) { + if (numDevices < MAXDEVICES) + device[numDevices++] = this; + else + esyslog("ERROR: too many devices or \"dynamite\"-unpatched device creator!"); + } else - esyslog("ERROR: too many devices!"); + parentDevice->subDevice = this; } cDevice::~cDevice() @@ -120,6 +133,8 @@ cDevice::~cDevice() DetachAllReceivers(); delete liveSubtitle; delete dvbSubtitleConverter; + if (parentDevice && (parentDevice->subDevice == this)) + parentDevice->subDevice = NULL; } bool cDevice::WaitForAllDevicesReady(int Timeout) @@ -158,6 +173,8 @@ int cDevice::NextCardIndex(int n) int cDevice::DeviceNumber(void) const { + if (parentDevice) + return parentDevice->DeviceNumber(); for (int i = 0; i < numDevices; i++) { if (device[i] == this) return i; @@ -328,6 +345,10 @@ bool cDevice::HasCi(void) void cDevice::SetCamSlot(cCamSlot *CamSlot) { + if (parentDevice) { + parentDevice->SetCamSlot(CamSlot); + return; + } camSlot = CamSlot; } @@ -531,6 +552,10 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On) void cDevice::StartSectionHandler(void) { + if (parentDevice) { + parentDevice->StartSectionHandler(); + return; + } if (!sectionHandler) { sectionHandler = new cSectionHandler(this); AttachFilter(eitFilter = new cEitFilter); @@ -542,6 +567,10 @@ void cDevice::StartSectionHandler(void) void cDevice::StopSectionHandler(void) { + if (parentDevice) { + parentDevice->StopSectionHandler(); + return; + } if (sectionHandler) { delete nitFilter; delete sdtFilter; @@ -568,12 +597,20 @@ void cDevice::CloseFilter(int Handle) void cDevice::AttachFilter(cFilter *Filter) { + if (parentDevice) { + parentDevice->AttachFilter(Filter); + return; + } if (sectionHandler) sectionHandler->Attach(Filter); } void cDevice::Detach(cFilter *Filter) { + if (parentDevice) { + parentDevice->Detach(Filter); + return; + } if (sectionHandler) sectionHandler->Detach(Filter); } @@ -1461,6 +1498,8 @@ bool cDevice::Ready(void) bool cDevice::Receiving(bool CheckAny) const { + if (parentDevice) + return parentDevice->Receiving(CheckAny); for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count return true; @@ -1690,3 +1729,25 @@ uchar *cTSBuffer::Get(void) } return NULL; } + +// --- cDynamicDeviceProbe ------------------------------------------------------- + +cList DynamicDeviceProbes; + +cList cDynamicDeviceProbe::commandQueue; + +void cDynamicDeviceProbe::QueueDynamicDeviceCommand(eDynamicDeviceProbeCommand Cmd, const char *DevPath) +{ + if (DevPath) + commandQueue.Add(new cDynamicDeviceProbeItem(Cmd, new cString(DevPath))); +} + +cDynamicDeviceProbe::cDynamicDeviceProbe(void) +{ + DynamicDeviceProbes.Add(this); +} + +cDynamicDeviceProbe::~cDynamicDeviceProbe() +{ + DynamicDeviceProbes.Del(this, false); +} diff --git a/device.h b/device.h index cb3bc2c..8364e73 100644 --- a/device.h +++ b/device.h @@ -163,7 +163,6 @@ private: static int nextCardIndex; int cardIndex; protected: - cDevice(void); virtual ~cDevice(); virtual bool Ready(void); ///< Returns true if this device is ready. Devices with conditional @@ -190,9 +189,6 @@ protected: ///< A derived class must call the MakePrimaryDevice() function of its ///< base class. public: - bool IsPrimaryDevice(void) const { return this == primaryDevice; } - int CardIndex(void) const { return cardIndex; } - ///< Returns the card index of this device (0 ... MAXDEVICES - 1). int DeviceNumber(void) const; ///< Returns the number of this device (0 ... numDevices). virtual bool HasDecoder(void) const; @@ -365,9 +361,6 @@ public: ///< Returns true if this device has a Common Interface. void SetCamSlot(cCamSlot *CamSlot); ///< Sets the given CamSlot to be used with this device. - cCamSlot *CamSlot(void) const { return camSlot; } - ///< Returns the CAM slot that is currently used with this device, - ///< or NULL if no CAM slot is in use. // Image Grab facilities @@ -524,9 +517,6 @@ private: cTsToPes tsToPesSubtitle; bool isPlayingVideo; protected: - const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; } - ///< Returns a pointer to the patPmtParser, so that a derived device - ///< can use the stream information from it. virtual bool CanReplay(void) const; ///< Returns true if this device can currently start a replay session. virtual bool SetPlayMode(ePlayMode PlayMode); @@ -712,6 +702,31 @@ public: ///< Detaches all receivers from this device for this pid. void DetachAllReceivers(void); ///< Detaches all receivers from this device. + +// --- dynamite subdevice patch start --- + friend class cDynamicDevice; +private: + static cDevice *nextParentDevice; + ///< Holds the parent device for the next subdevice + ///< so the dynamite-plugin can work with unpatched plugins +protected: + cDevice *parentDevice; + cDevice *subDevice; + cDevice(cDevice *ParentDevice = NULL); + const cPatPmtParser *PatPmtParser(void) const { if (parentDevice) return parentDevice->PatPmtParser(); return &patPmtParser; } + ///< Returns a pointer to the patPmtParser, so that a derived device + ///< can use the stream information from it. +public: + bool IsPrimaryDevice(void) const { if (parentDevice) return parentDevice->IsPrimaryDevice(); return this == primaryDevice; } + int CardIndex(void) const { if (parentDevice) return parentDevice->cardIndex; return cardIndex; } + ///< Returns the card index of this device (0 ... MAXDEVICES - 1). + cCamSlot *CamSlot(void) const { if (parentDevice) return parentDevice->CamSlot(); return camSlot; } + ///< Returns the CAM slot that is currently used with this device, + ///< or NULL if no CAM slot is in use. + bool IsSubDevice(void) const { return (parentDevice != NULL); } + bool HasSubDevice(void) const { return (subDevice != NULL); } + cDevice *SubDevice(void) const { return subDevice; } + // --- dynamite subdevice patch end --- }; /// Derived cDevice classes that can receive channels will have to provide @@ -735,4 +750,47 @@ public: uchar *Get(void); }; +/// A plugin that want to create devices handled by the dynamite-plugin needs to create +/// a cDynamicDeviceProbe derived object on the heap in order to have its Probe() +/// function called, where it can actually create the appropriate device. +/// The cDynamicDeviceProbe object must be created in the plugin's constructor, +/// and deleted in its destructor. +/// The "DevPath" hasn't to be a physical device or a path in the filesystem. +/// It can be any string a plugin may react on. + +#define __DYNAMIC_DEVICE_PROBE + +enum eDynamicDeviceProbeCommand { ddpcAttach, ddpcDetach }; + +class cDynamicDeviceProbe : public cListObject { + friend class cDynamicDevice; +private: + class cDynamicDeviceProbeItem : public cListObject { + public: + eDynamicDeviceProbeCommand cmd; + cString *devpath; + cDynamicDeviceProbeItem(eDynamicDeviceProbeCommand Cmd, cString *DevPath):cmd(Cmd),devpath(DevPath) {} + virtual ~cDynamicDeviceProbeItem() { if (devpath) delete devpath; } + }; + static cList commandQueue; + ///< A list where all attach/detach commands are queued + ///< so they can be processed in the MainThreadHook of + ///< the dynamite plugin. +public: + static void QueueDynamicDeviceCommand(eDynamicDeviceProbeCommand Cmd, const char *DevPath); + ///< Plugins which support cDynamicDeviceProbe must use this function + ///< to queue the devices they normally create in their Initialize method. + ///< These devices are created as subdevices in the Start-method of the dynamite-plugin. + cDynamicDeviceProbe(void); + virtual ~cDynamicDeviceProbe(); + virtual cDevice *Attach(cDevice *ParentDevice, const char *DevPath) = 0; + ///< Probes for a device at the given device-path like /dev/dvb/adapter0/frontend0 + ///< or /dev/video0 etc. and creates the appropriate + ///< object derived from cDevice if applicable. + ///< Returns the device that has been created or NULL if not. + ///< The dynamite-plugin will delete the device if it is detached. + }; + +extern cList DynamicDeviceProbes; + #endif //__DEVICE_H diff --git a/dvbci.c b/dvbci.c index 5289bbd..ea54bdb 100644 --- a/dvbci.c +++ b/dvbci.c @@ -41,6 +41,8 @@ cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd) cDvbCiAdapter::~cDvbCiAdapter() { Cancel(3); + if (device->IsSubDevice() || device->HasSubDevice()) + close(fd); } int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength) diff --git a/dvbdevice.c b/dvbdevice.c index f32b350..df2e679 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -259,6 +259,7 @@ private: int device; int fd_frontend; int adapter, frontend; + cDvbDevice *dvbdevice; int tuneTimeout; int lockTimeout; time_t lastTimeoutReport; @@ -273,7 +274,7 @@ private: bool SetFrontend(void); virtual void Action(void); public: - cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType); + cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType, cDvbDevice *Dvbdevice); virtual ~cDvbTuner(); const cChannel *GetTransponder(void) const { return &channel; } bool IsTunedTo(const cChannel *Channel) const; @@ -281,13 +282,14 @@ public: bool Locked(int TimeoutMs = 0); }; -cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType) +cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType, cDvbDevice *Dvbdevice) { device = Device; fd_frontend = Fd_Frontend; adapter = Adapter; frontend = Frontend; frontendType = FrontendType; + dvbdevice = Dvbdevice; tuneTimeout = 0; lockTimeout = 0; lastTimeoutReport = 0; @@ -305,6 +307,8 @@ cDvbTuner::~cDvbTuner() newSet.Broadcast(); locked.Broadcast(); Cancel(3); + if (dvbdevice && dvbdevice->IsSubDevice()) + close(fd_frontend); } bool cDvbTuner::IsTunedTo(const cChannel *Channel) const @@ -661,7 +665,8 @@ const char *DeliverySystems[] = { NULL }; -cDvbDevice::cDvbDevice(int Adapter, int Frontend) +cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice) +:cDevice(ParentDevice) { adapter = Adapter; frontend = Frontend; @@ -678,7 +683,7 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend) fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR); if (fd_ca >= 0) - ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca); + ciAdapter = cDvbCiAdapter::CreateCiAdapter(parentDevice ? parentDevice : this, fd_ca); // The DVR device (will be opened and closed as needed): @@ -718,7 +723,7 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend) else p = (char *)"unknown modulations"; isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], p, frontendInfo.name); - dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType); + dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType, this); } } else diff --git a/dvbdevice.h b/dvbdevice.h index ff606fd..0ac3a24 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -123,7 +123,7 @@ private: fe_delivery_system frontendType; int fd_dvr, fd_ca; public: - cDvbDevice(int Adapter, int Frontend); + cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice = NULL); virtual ~cDvbDevice(); virtual bool Ready(void);