summaryrefslogtreecommitdiff
path: root/p2pvr/devices/devices.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'p2pvr/devices/devices.cpp')
-rw-r--r--p2pvr/devices/devices.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/p2pvr/devices/devices.cpp b/p2pvr/devices/devices.cpp
new file mode 100644
index 0000000..541cfa5
--- /dev/null
+++ b/p2pvr/devices/devices.cpp
@@ -0,0 +1,258 @@
+#include "devices.h"
+#include <Ice/Ice.h>
+#include "tuner.h"
+#include "bindTimerTask.h"
+#include <lockHelpers.h>
+
+namespace P2PVR {
+template<typename T>
+T *
+get_pointer(const IceInternal::Handle<T> & t) BOOST_NOEXCEPT
+{
+ return t.get();
+}
+
+class DLL_PRIVATE OpenTuner {
+ public:
+ OpenTuner(DVBSI::DeliveryPtr, TunerPtr);
+
+ const DVBSI::DeliveryPtr delivery;
+ const TunerPtr tuner;
+
+ unsigned int clients;
+};
+
+DevicesI::Options::Options() :
+ IceTray::Options("P2PVR Devices")
+{
+}
+
+ICETRAY_OPTIONS(DevicesI::Options,
+ ("p2pvr.localdevices.frontend", boost::program_options::value(&devices), "Frontend of DVB device(s) to use (/dev/dvb/adapterX/frontendY)")
+);
+
+IceTray::Logging::LoggerPtr DevicesI::logger(LOGMANAGER()->getLogger<DevicesI>());
+
+DevicesI::DevicesI()
+{
+ devices = options->devices;
+ logger->message(LOG::DEBUG, __PRETTY_FUNCTION__);
+}
+
+DevicesI::~DevicesI()
+{
+ logger->message(LOG::DEBUG, __PRETTY_FUNCTION__);
+}
+
+TunerPtr
+DevicesI::getTuner()
+{
+ if (devices.empty()) {
+ throw NoSuitableDeviceAvailable();
+ }
+ for (auto devItr = devices.begin(); devItr != devices.end(); devItr++) {
+ try {
+ return new DVB::TunerI(*devItr);
+ }
+ catch (...) {
+ logger->messagebf(LOG::DEBUG, "%s: Failed to open device %s", __PRETTY_FUNCTION__,
+ *devItr);
+ }
+ }
+ throw NoSuitableDeviceAvailable();
+}
+
+TunerPtr
+DevicesI::getTuner(const DVBSI::DeliveryPtr & delivery)
+{
+ logger->messagebf(LOG::DEBUG, "%s: Searching for an open sharable tuner (frequency %d)", __PRETTY_FUNCTION__, delivery->Frequency);
+ Lock(lock);
+ // Check for an already open tuner which is correctly tuned.
+ auto existingItr = openDevices.find(delivery->TransportStreamId);
+ if (existingItr != openDevices.end()) {
+ existingItr->second->clients += 1;
+ return existingItr->second->tuner;
+ }
+ // Open a tuner and tune it as required.
+ if (devices.empty()) {
+ throw NoSuitableDeviceAvailable();
+ }
+ for (auto devItr = devices.begin(); devItr != devices.end(); devItr++) {
+ try {
+ TunerPtr tuner = new DVB::TunerI(*devItr);
+ tuner->TuneTo(delivery);
+ openDevices.insert({ delivery->TransportStreamId, OpenTunerPtr(new OpenTuner(delivery, tuner)) });
+ devices.erase(devItr);
+ return tuner;
+ }
+ catch (...) {
+ logger->messagebf(LOG::DEBUG, "%s: Failed to open and tune device %s to frequency %d", __PRETTY_FUNCTION__,
+ *devItr, delivery->Frequency);
+ }
+ }
+ logger->messagebf(LOG::DEBUG, "%s: Failed to open and tune any device to frequency %d", __PRETTY_FUNCTION__,
+ delivery->Frequency);
+ throw NoSuitableDeviceAvailable();
+}
+
+TunerPtr
+DevicesI::getTuner(const DeliveryProvider & provider)
+{
+ ScopeLock(lock) {
+ if (!openDevices.empty()) {
+ auto openDevice = openDevices.begin()->second;
+ openDevice->clients++;
+ return openDevice->tuner;
+ }
+
+ }
+ return getTuner(provider());
+}
+
+void
+DevicesI::releaseTuner(const TunerPtr & tuner)
+{
+ Lock(lock);
+ logger->messagebf(LOG::DEBUG, "%s", __PRETTY_FUNCTION__);
+ auto openTuner = std::find_if(openDevices.begin(), openDevices.end(), [&tuner](const auto & ot) {
+ return ot.second->tuner == tuner;
+ });
+ if (openTuner == openDevices.end()) {
+ logger->messagebf(LOG::DEBUG, "%s: Not one of mine", __PRETTY_FUNCTION__);
+ throw DeviceError();
+ }
+ logger->messagebf(LOG::DEBUG, "%s: Locally owned deivce %s", __PRETTY_FUNCTION__, openTuner->first);
+ openTuner->second->clients -= 1;
+ if (openTuner->second->clients == 0) {
+ openDevices.erase(openTuner);
+ devices.push_back(openTuner->second->tuner->GetDevice());
+ }
+}
+
+void
+DevicesI::Scan(const std::string &, const Ice::Current &)
+{
+ Lock(lock);
+}
+
+void
+DevicesI::Add(const std::string & frontend, const Ice::Current &)
+{
+ Lock(lock);
+ devices.push_back(frontend);
+}
+
+void
+DevicesI::Remove(const std::string & frontend, const Ice::Current &)
+{
+ Lock(lock);
+ devices.erase(std::remove(devices.begin(), devices.end(), frontend), devices.end());
+}
+
+::Ice::Int
+DevicesI::TunerCount(const Ice::Current &)
+{
+ Lock(lock);
+ return devices.size() + openDevices.size();
+}
+
+OpenTuner::OpenTuner(DVBSI::DeliveryPtr d, TunerPtr t) :
+ delivery(d),
+ tuner(t),
+ clients(1)
+{
+}
+
+void
+DevicesI::finiteTunerOperation(TunerPtr && tuner, const Target & target)
+{
+ try {
+ target(tuner);
+ releaseTuner(tuner);
+ }
+ catch (...) {
+ releaseTuner(tuner);
+ throw;
+ }
+}
+
+void
+DevicesI::ScanAndSendNetworkInformation(const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(), boost::bind(&Tuner::ScanAndSendNetworkInformation, _1, target));
+}
+
+void
+DevicesI::SendNetworkInformation(const ::DVBSI::DeliveryPtr & del, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendNetworkInformation, _1, target));
+}
+
+void
+DevicesI::SendBouquetAssociations(const ::DVBSI::DeliveryPtr & del, const RawDataClientPrx & target, const ::Ice::Current &)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendBouquetAssociations, _1, target));
+}
+
+void
+DevicesI::SendServiceDescriptions(const ::DVBSI::DeliveryPtr & del, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendServiceDescriptions, _1, target));
+}
+
+void
+DevicesI::SendProgramAssociationTable(const ::DVBSI::DeliveryPtr & del, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendProgramAssociationTable, _1, target));
+}
+
+void
+DevicesI::SendProgramMap(const ::DVBSI::DeliveryPtr & del, ::Ice::Int pids, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendProgramMap, _1, pids, target));
+}
+
+void
+DevicesI::SendEventInformation(const ::DVBSI::DeliveryPtr & del, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ finiteTunerOperation(getTuner(del), boost::bind(&Tuner::SendEventInformation, _1, target));
+}
+
+::Ice::Int
+DevicesI::StartSendingTS(const ::DVBSI::DeliveryPtr & del, const PacketIds & pids, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ auto tuner = getTuner(del);
+ try {
+ return backgroundOperations.insert({ tuner->StartSendingTS(pids, target), tuner }).first->first;
+ }
+ catch (...) {
+ releaseTuner(tuner);
+ throw;
+ }
+}
+
+::Ice::Int
+DevicesI::StartSendingSection(const ::DVBSI::DeliveryPtr & del, ::Ice::Int sid, const RawDataClientPrx & target, const ::Ice::Current&)
+{
+ auto tuner = getTuner(del);
+ try {
+ return backgroundOperations.insert({ tuner->StartSendingSection(sid, target), tuner }).first->first;
+ }
+ catch (...) {
+ releaseTuner(tuner);
+ throw;
+ }
+}
+
+void
+DevicesI::StopSending(::Ice::Int handle, const ::Ice::Current&)
+{
+ auto tunerItr = backgroundOperations.find(handle);
+ if (tunerItr != backgroundOperations.end()) {
+ tunerItr->second->StopSending(handle);
+ backgroundOperations.erase(handle);
+ }
+}
+
+}
+