diff options
Diffstat (limited to 'p2pvr/devices/devices.cpp')
-rw-r--r-- | p2pvr/devices/devices.cpp | 258 |
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); + } +} + +} + |