From ab1eee942e75874739ce5f0b4ba289aac5cc3faf Mon Sep 17 00:00:00 2001 From: randomdan Date: Thu, 13 Mar 2014 19:42:07 +0000 Subject: Restructure into more sensibly arranged libs --- p2pvr/Jamfile.jam | 3 +- p2pvr/carddaemon/Jamfile.jam | 6 +- p2pvr/daemon/Jamfile.jam | 17 +- p2pvr/daemon/dbClient.cpp | 56 +++ p2pvr/daemon/dbClient.h | 103 +++++ p2pvr/daemon/globalDevices.cpp | 86 ++++ p2pvr/daemon/globalDevices.h | 25 ++ p2pvr/daemon/maintenance.cpp | 97 +++++ p2pvr/daemon/maintenance.h | 39 ++ p2pvr/daemon/maintenance/events.cpp | 92 ++++ p2pvr/daemon/maintenance/network.cpp | 107 +++++ p2pvr/daemon/maintenance/programAssociations.cpp | 80 ++++ p2pvr/daemon/maintenance/programMap.cpp | 133 ++++++ p2pvr/daemon/maintenance/services.cpp | 68 +++ p2pvr/daemon/pch.hpp | 24 + p2pvr/daemon/recorder.cpp | 100 +++++ p2pvr/daemon/recorder.h | 51 +++ p2pvr/daemon/recordings.cpp | 82 ++++ p2pvr/daemon/recordings.h | 16 + p2pvr/daemon/schedulers/bitDumbScheduler.cpp | 55 +++ p2pvr/daemon/schedules.cpp | 484 +++++++++++++++++++++ p2pvr/daemon/schedules.h | 85 ++++ p2pvr/daemon/si.cpp | 127 ++++++ p2pvr/daemon/si.h | 23 + p2pvr/daemon/sql/Recordings_delete.sql | 2 + p2pvr/daemon/sql/Recordings_getAll.sql | 3 + p2pvr/daemon/sql/Recordings_getStorage.sql | 4 + p2pvr/daemon/sql/Recordings_insert.sql | 2 + p2pvr/daemon/sql/Recordings_insertNewId.sql | 2 + p2pvr/daemon/sql/SI_eventById.sql | 28 ++ p2pvr/daemon/sql/SI_eventsInRange.sql | 28 ++ p2pvr/daemon/sql/SI_eventsOnNow.sql | 27 ++ p2pvr/daemon/sql/SI_serviceNextUsed.sql | 12 + p2pvr/daemon/sql/SI_servicesSelectAll.sql | 3 + p2pvr/daemon/sql/SI_servicesSelectById.sql | 3 + p2pvr/daemon/sql/Schedules_GetCandidates.sql | 25 ++ p2pvr/daemon/sql/Schedules_delete.sql | 1 + p2pvr/daemon/sql/Schedules_insert.sql | 2 + p2pvr/daemon/sql/Schedules_insertNewId.sql | 1 + p2pvr/daemon/sql/Schedules_pendingRecord.sql | 13 + p2pvr/daemon/sql/Schedules_scheduledToRecord.sql | 8 + p2pvr/daemon/sql/Schedules_selectAll.sql | 3 + p2pvr/daemon/sql/Schedules_selectById.sql | 5 + p2pvr/daemon/sql/Schedules_update.sql | 10 + p2pvr/daemon/sqlContainerCreator.h | 28 ++ p2pvr/daemon/storage.cpp | 275 ++++++++++++ p2pvr/daemon/storage.h | 38 ++ p2pvr/daemonbase/Jamfile.jam | 21 + p2pvr/daemonbase/daemonBase.cpp | 64 +++ p2pvr/daemonbase/daemonBase.h | 31 ++ p2pvr/daemonbase/p2LoggerWrapper.cpp | 39 ++ p2pvr/daemonbase/p2LoggerWrapper.h | 23 + p2pvr/daemonbase/pch.hpp | 13 + p2pvr/devices/Jamfile.jam | 27 ++ p2pvr/devices/frontend.cpp | 39 ++ p2pvr/devices/frontend.h | 32 ++ p2pvr/devices/frontends/ofdm.cpp | 159 +++++++ p2pvr/devices/localDevices.cpp | 189 ++++++++ p2pvr/devices/localDevices.h | 52 +++ p2pvr/devices/pch.hpp | 24 + p2pvr/devices/tuner.cpp | 421 ++++++++++++++++++ p2pvr/devices/tuner.h | 83 ++++ p2pvr/devices/tunerSendSi.cpp | 81 ++++ p2pvr/devices/tunerSendSi.h | 24 + p2pvr/devices/tunerSendTs.cpp | 77 ++++ p2pvr/devices/tunerSendTs.h | 22 + p2pvr/dvb/Jamfile.jam | 14 + p2pvr/dvb/pch.hpp | 23 + p2pvr/dvb/siParsers/event.cpp | 260 +++++++++++ p2pvr/dvb/siParsers/event.h | 35 ++ p2pvr/dvb/siParsers/network.cpp | 281 ++++++++++++ p2pvr/dvb/siParsers/network.h | 35 ++ p2pvr/dvb/siParsers/programAssociation.cpp | 30 ++ p2pvr/dvb/siParsers/programAssociation.h | 23 + p2pvr/dvb/siParsers/programMap.cpp | 48 ++ p2pvr/dvb/siParsers/programMap.h | 37 ++ p2pvr/dvb/siParsers/service.cpp | 70 +++ p2pvr/dvb/siParsers/service.h | 25 ++ p2pvr/dvb/siParsers/table.cpp | 84 ++++ p2pvr/dvb/siParsers/table.h | 212 +++++++++ p2pvr/ice/Jamfile.jam | 3 +- p2pvr/lib/Jamfile.jam | 6 +- p2pvr/lib/containerCreator.h | 33 ++ p2pvr/lib/containerIterator.h | 41 ++ p2pvr/lib/daemonBase.cpp | 64 --- p2pvr/lib/daemonBase.h | 31 -- p2pvr/lib/dbClient.cpp | 56 --- p2pvr/lib/dbClient.h | 103 ----- p2pvr/lib/dvbsiHelpers.h | 23 + p2pvr/lib/dvbsiHelpers/cableDelivery.cpp | 39 ++ p2pvr/lib/dvbsiHelpers/event.cpp | 94 ++++ p2pvr/lib/dvbsiHelpers/network.cpp | 21 + p2pvr/lib/dvbsiHelpers/networkService.cpp | 22 + p2pvr/lib/dvbsiHelpers/networkTransportStream.cpp | 23 + p2pvr/lib/dvbsiHelpers/programMap.cpp | 24 + p2pvr/lib/dvbsiHelpers/satelliteDelivery.cpp | 51 +++ p2pvr/lib/dvbsiHelpers/service.cpp | 49 +++ p2pvr/lib/dvbsiHelpers/terrestrialDelivery.cpp | 59 +++ p2pvr/lib/fileHandle.cpp | 28 ++ p2pvr/lib/fileHandle.h | 19 + p2pvr/lib/frontend.cpp | 39 -- p2pvr/lib/frontend.h | 32 -- p2pvr/lib/frontends/ofdm.cpp | 159 ------- p2pvr/lib/globalDevices.cpp | 86 ---- p2pvr/lib/globalDevices.h | 25 -- p2pvr/lib/localDevices.cpp | 189 -------- p2pvr/lib/localDevices.h | 52 --- p2pvr/lib/maintenance.cpp | 97 ----- p2pvr/lib/maintenance.h | 39 -- p2pvr/lib/maintenance/events.cpp | 92 ---- p2pvr/lib/maintenance/network.cpp | 107 ----- p2pvr/lib/maintenance/programAssociations.cpp | 80 ---- p2pvr/lib/maintenance/programMap.cpp | 133 ------ p2pvr/lib/maintenance/services.cpp | 68 --- p2pvr/lib/mapIterator.cpp | 11 + p2pvr/lib/mapIterator.h | 45 ++ p2pvr/lib/objectRowState.h | 45 ++ p2pvr/lib/p2Helpers.cpp | 43 ++ p2pvr/lib/p2Helpers.h | 71 +++ p2pvr/lib/p2LoggerWrapper.cpp | 39 -- p2pvr/lib/p2LoggerWrapper.h | 23 - p2pvr/lib/p2pvrHelpers/schedule.cpp | 51 +++ p2pvr/lib/recorder.cpp | 100 ----- p2pvr/lib/recorder.h | 51 --- p2pvr/lib/recordings.cpp | 82 ---- p2pvr/lib/recordings.h | 16 - p2pvr/lib/schedulers/bitDumbScheduler.cpp | 55 --- p2pvr/lib/schedules.cpp | 484 --------------------- p2pvr/lib/schedules.h | 85 ---- p2pvr/lib/si.cpp | 127 ------ p2pvr/lib/si.h | 23 - p2pvr/lib/siParsers/event.cpp | 260 ----------- p2pvr/lib/siParsers/event.h | 35 -- p2pvr/lib/siParsers/network.cpp | 281 ------------ p2pvr/lib/siParsers/network.h | 35 -- p2pvr/lib/siParsers/programAssociation.cpp | 30 -- p2pvr/lib/siParsers/programAssociation.h | 23 - p2pvr/lib/siParsers/programMap.cpp | 48 -- p2pvr/lib/siParsers/programMap.h | 37 -- p2pvr/lib/siParsers/service.cpp | 70 --- p2pvr/lib/siParsers/service.h | 25 -- p2pvr/lib/siParsers/table.cpp | 84 ---- p2pvr/lib/siParsers/table.h | 212 --------- p2pvr/lib/singleIterator.h | 39 ++ p2pvr/lib/sql/Recordings_delete.sql | 2 - p2pvr/lib/sql/Recordings_getAll.sql | 3 - p2pvr/lib/sql/Recordings_getStorage.sql | 4 - p2pvr/lib/sql/Recordings_insert.sql | 2 - p2pvr/lib/sql/Recordings_insertNewId.sql | 2 - p2pvr/lib/sql/SI_eventById.sql | 28 -- p2pvr/lib/sql/SI_eventsInRange.sql | 28 -- p2pvr/lib/sql/SI_eventsOnNow.sql | 27 -- p2pvr/lib/sql/SI_serviceNextUsed.sql | 12 - p2pvr/lib/sql/SI_servicesSelectAll.sql | 3 - p2pvr/lib/sql/SI_servicesSelectById.sql | 3 - p2pvr/lib/sql/Schedules_GetCandidates.sql | 25 -- p2pvr/lib/sql/Schedules_delete.sql | 1 - p2pvr/lib/sql/Schedules_insert.sql | 2 - p2pvr/lib/sql/Schedules_insertNewId.sql | 1 - p2pvr/lib/sql/Schedules_pendingRecord.sql | 13 - p2pvr/lib/sql/Schedules_scheduledToRecord.sql | 8 - p2pvr/lib/sql/Schedules_selectAll.sql | 3 - p2pvr/lib/sql/Schedules_selectById.sql | 5 - p2pvr/lib/sql/Schedules_update.sql | 10 - p2pvr/lib/sqlContainerCreator.h | 28 -- p2pvr/lib/storage.cpp | 275 ------------ p2pvr/lib/storage.h | 38 -- p2pvr/lib/tuner.cpp | 421 ------------------ p2pvr/lib/tuner.h | 83 ---- p2pvr/lib/tunerSendSi.cpp | 81 ---- p2pvr/lib/tunerSendSi.h | 24 - p2pvr/lib/tunerSendTs.cpp | 77 ---- p2pvr/lib/tunerSendTs.h | 22 - p2pvr/streamer/Jamfile.jam | 3 - p2pvr/util/Jamfile.jam | 19 - p2pvr/util/containerCreator.h | 33 -- p2pvr/util/containerIterator.h | 41 -- p2pvr/util/dvbsiHelpers.h | 23 - p2pvr/util/dvbsiHelpers/cableDelivery.cpp | 39 -- p2pvr/util/dvbsiHelpers/event.cpp | 94 ---- p2pvr/util/dvbsiHelpers/network.cpp | 21 - p2pvr/util/dvbsiHelpers/networkService.cpp | 22 - p2pvr/util/dvbsiHelpers/networkTransportStream.cpp | 23 - p2pvr/util/dvbsiHelpers/programMap.cpp | 24 - p2pvr/util/dvbsiHelpers/satelliteDelivery.cpp | 51 --- p2pvr/util/dvbsiHelpers/service.cpp | 49 --- p2pvr/util/dvbsiHelpers/terrestrialDelivery.cpp | 59 --- p2pvr/util/fileHandle.cpp | 28 -- p2pvr/util/fileHandle.h | 19 - p2pvr/util/mapIterator.cpp | 11 - p2pvr/util/mapIterator.h | 45 -- p2pvr/util/objectRowState.h | 45 -- p2pvr/util/p2Helpers.cpp | 43 -- p2pvr/util/p2Helpers.h | 71 --- p2pvr/util/p2pvrHelpers/schedule.cpp | 51 --- p2pvr/util/pch.hpp | 23 - p2pvr/util/singleIterator.h | 39 -- 197 files changed, 5904 insertions(+), 5800 deletions(-) create mode 100644 p2pvr/daemon/dbClient.cpp create mode 100644 p2pvr/daemon/dbClient.h create mode 100644 p2pvr/daemon/globalDevices.cpp create mode 100644 p2pvr/daemon/globalDevices.h create mode 100644 p2pvr/daemon/maintenance.cpp create mode 100644 p2pvr/daemon/maintenance.h create mode 100644 p2pvr/daemon/maintenance/events.cpp create mode 100644 p2pvr/daemon/maintenance/network.cpp create mode 100644 p2pvr/daemon/maintenance/programAssociations.cpp create mode 100644 p2pvr/daemon/maintenance/programMap.cpp create mode 100644 p2pvr/daemon/maintenance/services.cpp create mode 100644 p2pvr/daemon/pch.hpp create mode 100644 p2pvr/daemon/recorder.cpp create mode 100644 p2pvr/daemon/recorder.h create mode 100644 p2pvr/daemon/recordings.cpp create mode 100644 p2pvr/daemon/recordings.h create mode 100644 p2pvr/daemon/schedulers/bitDumbScheduler.cpp create mode 100644 p2pvr/daemon/schedules.cpp create mode 100644 p2pvr/daemon/schedules.h create mode 100644 p2pvr/daemon/si.cpp create mode 100644 p2pvr/daemon/si.h create mode 100644 p2pvr/daemon/sql/Recordings_delete.sql create mode 100644 p2pvr/daemon/sql/Recordings_getAll.sql create mode 100644 p2pvr/daemon/sql/Recordings_getStorage.sql create mode 100644 p2pvr/daemon/sql/Recordings_insert.sql create mode 100644 p2pvr/daemon/sql/Recordings_insertNewId.sql create mode 100644 p2pvr/daemon/sql/SI_eventById.sql create mode 100644 p2pvr/daemon/sql/SI_eventsInRange.sql create mode 100644 p2pvr/daemon/sql/SI_eventsOnNow.sql create mode 100644 p2pvr/daemon/sql/SI_serviceNextUsed.sql create mode 100644 p2pvr/daemon/sql/SI_servicesSelectAll.sql create mode 100644 p2pvr/daemon/sql/SI_servicesSelectById.sql create mode 100644 p2pvr/daemon/sql/Schedules_GetCandidates.sql create mode 100644 p2pvr/daemon/sql/Schedules_delete.sql create mode 100644 p2pvr/daemon/sql/Schedules_insert.sql create mode 100644 p2pvr/daemon/sql/Schedules_insertNewId.sql create mode 100644 p2pvr/daemon/sql/Schedules_pendingRecord.sql create mode 100644 p2pvr/daemon/sql/Schedules_scheduledToRecord.sql create mode 100644 p2pvr/daemon/sql/Schedules_selectAll.sql create mode 100644 p2pvr/daemon/sql/Schedules_selectById.sql create mode 100644 p2pvr/daemon/sql/Schedules_update.sql create mode 100644 p2pvr/daemon/sqlContainerCreator.h create mode 100644 p2pvr/daemon/storage.cpp create mode 100644 p2pvr/daemon/storage.h create mode 100644 p2pvr/daemonbase/Jamfile.jam create mode 100644 p2pvr/daemonbase/daemonBase.cpp create mode 100644 p2pvr/daemonbase/daemonBase.h create mode 100644 p2pvr/daemonbase/p2LoggerWrapper.cpp create mode 100644 p2pvr/daemonbase/p2LoggerWrapper.h create mode 100644 p2pvr/daemonbase/pch.hpp create mode 100644 p2pvr/devices/Jamfile.jam create mode 100644 p2pvr/devices/frontend.cpp create mode 100644 p2pvr/devices/frontend.h create mode 100644 p2pvr/devices/frontends/ofdm.cpp create mode 100644 p2pvr/devices/localDevices.cpp create mode 100644 p2pvr/devices/localDevices.h create mode 100644 p2pvr/devices/pch.hpp create mode 100644 p2pvr/devices/tuner.cpp create mode 100644 p2pvr/devices/tuner.h create mode 100644 p2pvr/devices/tunerSendSi.cpp create mode 100644 p2pvr/devices/tunerSendSi.h create mode 100644 p2pvr/devices/tunerSendTs.cpp create mode 100644 p2pvr/devices/tunerSendTs.h create mode 100644 p2pvr/dvb/Jamfile.jam create mode 100644 p2pvr/dvb/pch.hpp create mode 100644 p2pvr/dvb/siParsers/event.cpp create mode 100644 p2pvr/dvb/siParsers/event.h create mode 100644 p2pvr/dvb/siParsers/network.cpp create mode 100644 p2pvr/dvb/siParsers/network.h create mode 100644 p2pvr/dvb/siParsers/programAssociation.cpp create mode 100644 p2pvr/dvb/siParsers/programAssociation.h create mode 100644 p2pvr/dvb/siParsers/programMap.cpp create mode 100644 p2pvr/dvb/siParsers/programMap.h create mode 100644 p2pvr/dvb/siParsers/service.cpp create mode 100644 p2pvr/dvb/siParsers/service.h create mode 100644 p2pvr/dvb/siParsers/table.cpp create mode 100644 p2pvr/dvb/siParsers/table.h create mode 100644 p2pvr/lib/containerCreator.h create mode 100644 p2pvr/lib/containerIterator.h delete mode 100644 p2pvr/lib/daemonBase.cpp delete mode 100644 p2pvr/lib/daemonBase.h delete mode 100644 p2pvr/lib/dbClient.cpp delete mode 100644 p2pvr/lib/dbClient.h create mode 100644 p2pvr/lib/dvbsiHelpers.h create mode 100644 p2pvr/lib/dvbsiHelpers/cableDelivery.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/event.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/network.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/networkService.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/networkTransportStream.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/programMap.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/satelliteDelivery.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/service.cpp create mode 100644 p2pvr/lib/dvbsiHelpers/terrestrialDelivery.cpp create mode 100644 p2pvr/lib/fileHandle.cpp create mode 100644 p2pvr/lib/fileHandle.h delete mode 100644 p2pvr/lib/frontend.cpp delete mode 100644 p2pvr/lib/frontend.h delete mode 100644 p2pvr/lib/frontends/ofdm.cpp delete mode 100644 p2pvr/lib/globalDevices.cpp delete mode 100644 p2pvr/lib/globalDevices.h delete mode 100644 p2pvr/lib/localDevices.cpp delete mode 100644 p2pvr/lib/localDevices.h delete mode 100644 p2pvr/lib/maintenance.cpp delete mode 100644 p2pvr/lib/maintenance.h delete mode 100644 p2pvr/lib/maintenance/events.cpp delete mode 100644 p2pvr/lib/maintenance/network.cpp delete mode 100644 p2pvr/lib/maintenance/programAssociations.cpp delete mode 100644 p2pvr/lib/maintenance/programMap.cpp delete mode 100644 p2pvr/lib/maintenance/services.cpp create mode 100644 p2pvr/lib/mapIterator.cpp create mode 100644 p2pvr/lib/mapIterator.h create mode 100644 p2pvr/lib/objectRowState.h create mode 100644 p2pvr/lib/p2Helpers.cpp create mode 100644 p2pvr/lib/p2Helpers.h delete mode 100644 p2pvr/lib/p2LoggerWrapper.cpp delete mode 100644 p2pvr/lib/p2LoggerWrapper.h create mode 100644 p2pvr/lib/p2pvrHelpers/schedule.cpp delete mode 100644 p2pvr/lib/recorder.cpp delete mode 100644 p2pvr/lib/recorder.h delete mode 100644 p2pvr/lib/recordings.cpp delete mode 100644 p2pvr/lib/recordings.h delete mode 100644 p2pvr/lib/schedulers/bitDumbScheduler.cpp delete mode 100644 p2pvr/lib/schedules.cpp delete mode 100644 p2pvr/lib/schedules.h delete mode 100644 p2pvr/lib/si.cpp delete mode 100644 p2pvr/lib/si.h delete mode 100644 p2pvr/lib/siParsers/event.cpp delete mode 100644 p2pvr/lib/siParsers/event.h delete mode 100644 p2pvr/lib/siParsers/network.cpp delete mode 100644 p2pvr/lib/siParsers/network.h delete mode 100644 p2pvr/lib/siParsers/programAssociation.cpp delete mode 100644 p2pvr/lib/siParsers/programAssociation.h delete mode 100644 p2pvr/lib/siParsers/programMap.cpp delete mode 100644 p2pvr/lib/siParsers/programMap.h delete mode 100644 p2pvr/lib/siParsers/service.cpp delete mode 100644 p2pvr/lib/siParsers/service.h delete mode 100644 p2pvr/lib/siParsers/table.cpp delete mode 100644 p2pvr/lib/siParsers/table.h create mode 100644 p2pvr/lib/singleIterator.h delete mode 100644 p2pvr/lib/sql/Recordings_delete.sql delete mode 100644 p2pvr/lib/sql/Recordings_getAll.sql delete mode 100644 p2pvr/lib/sql/Recordings_getStorage.sql delete mode 100644 p2pvr/lib/sql/Recordings_insert.sql delete mode 100644 p2pvr/lib/sql/Recordings_insertNewId.sql delete mode 100644 p2pvr/lib/sql/SI_eventById.sql delete mode 100644 p2pvr/lib/sql/SI_eventsInRange.sql delete mode 100644 p2pvr/lib/sql/SI_eventsOnNow.sql delete mode 100644 p2pvr/lib/sql/SI_serviceNextUsed.sql delete mode 100644 p2pvr/lib/sql/SI_servicesSelectAll.sql delete mode 100644 p2pvr/lib/sql/SI_servicesSelectById.sql delete mode 100644 p2pvr/lib/sql/Schedules_GetCandidates.sql delete mode 100644 p2pvr/lib/sql/Schedules_delete.sql delete mode 100644 p2pvr/lib/sql/Schedules_insert.sql delete mode 100644 p2pvr/lib/sql/Schedules_insertNewId.sql delete mode 100644 p2pvr/lib/sql/Schedules_pendingRecord.sql delete mode 100644 p2pvr/lib/sql/Schedules_scheduledToRecord.sql delete mode 100644 p2pvr/lib/sql/Schedules_selectAll.sql delete mode 100644 p2pvr/lib/sql/Schedules_selectById.sql delete mode 100644 p2pvr/lib/sql/Schedules_update.sql delete mode 100644 p2pvr/lib/sqlContainerCreator.h delete mode 100644 p2pvr/lib/storage.cpp delete mode 100644 p2pvr/lib/storage.h delete mode 100644 p2pvr/lib/tuner.cpp delete mode 100644 p2pvr/lib/tuner.h delete mode 100644 p2pvr/lib/tunerSendSi.cpp delete mode 100644 p2pvr/lib/tunerSendSi.h delete mode 100644 p2pvr/lib/tunerSendTs.cpp delete mode 100644 p2pvr/lib/tunerSendTs.h delete mode 100644 p2pvr/util/Jamfile.jam delete mode 100644 p2pvr/util/containerCreator.h delete mode 100644 p2pvr/util/containerIterator.h delete mode 100644 p2pvr/util/dvbsiHelpers.h delete mode 100644 p2pvr/util/dvbsiHelpers/cableDelivery.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/event.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/network.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/networkService.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/networkTransportStream.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/programMap.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/satelliteDelivery.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/service.cpp delete mode 100644 p2pvr/util/dvbsiHelpers/terrestrialDelivery.cpp delete mode 100644 p2pvr/util/fileHandle.cpp delete mode 100644 p2pvr/util/fileHandle.h delete mode 100644 p2pvr/util/mapIterator.cpp delete mode 100644 p2pvr/util/mapIterator.h delete mode 100644 p2pvr/util/objectRowState.h delete mode 100644 p2pvr/util/p2Helpers.cpp delete mode 100644 p2pvr/util/p2Helpers.h delete mode 100644 p2pvr/util/p2pvrHelpers/schedule.cpp delete mode 100644 p2pvr/util/pch.hpp delete mode 100644 p2pvr/util/singleIterator.h diff --git a/p2pvr/Jamfile.jam b/p2pvr/Jamfile.jam index 565da4e..9a4baac 100644 --- a/p2pvr/Jamfile.jam +++ b/p2pvr/Jamfile.jam @@ -25,11 +25,10 @@ alias p2daemonlib : glibmm : : : "-I /usr/include/project2/daemon/lib" "-lp2daemonlib" ; -build-project streamer ; build-project daemon ; build-project carddaemon ; -install debuginstall : lib//p2pvrlib util//p2pvrutil carddaemon daemon ice streamer//streamer : ./testing ; +install debuginstall : dvb//p2pvrdvb devices//p2pvrdevices lib//p2pvrlib carddaemon//p2pvrcarddaemon daemonbase//p2pvrdaemonbase daemon//p2pvrdaemon ice//p2pvrice : ./testing ; package.install install : : : carddaemon daemon ; import type ; diff --git a/p2pvr/carddaemon/Jamfile.jam b/p2pvr/carddaemon/Jamfile.jam index 5efeb01..3598c3b 100644 --- a/p2pvr/carddaemon/Jamfile.jam +++ b/p2pvr/carddaemon/Jamfile.jam @@ -1,9 +1,7 @@ -lib boost_filesystem ; -lib boost_system ; - lib p2pvrcarddaemon : [ glob *.cpp ] : ../ice//p2pvrice - ../lib//p2pvrlib + ../devices//p2pvrdevices + ../daemonbase//p2pvrdaemonbase ; diff --git a/p2pvr/daemon/Jamfile.jam b/p2pvr/daemon/Jamfile.jam index 8a6ee8c..338f65e 100644 --- a/p2pvr/daemon/Jamfile.jam +++ b/p2pvr/daemon/Jamfile.jam @@ -1,9 +1,20 @@ -lib Ice ; -lib IceUtil ; +cpp-pch pch : pch.hpp : + ../ice//p2pvrice + ../lib//p2pvrlib + ../dvb//p2pvrdvb + ..//p2sql + ../devices//p2pvrdevices + ../daemonbase//p2pvrdaemonbase +; lib p2pvrdaemon : - [ glob *.cpp ] + pch + [ glob-tree *.cpp *.sql ] : ../ice//p2pvrice ../lib//p2pvrlib + ../dvb//p2pvrdvb + ..//p2sql + ../devices//p2pvrdevices + ../daemonbase//p2pvrdaemonbase ; diff --git a/p2pvr/daemon/dbClient.cpp b/p2pvr/daemon/dbClient.cpp new file mode 100644 index 0000000..8267584 --- /dev/null +++ b/p2pvr/daemon/dbClient.cpp @@ -0,0 +1,56 @@ +#include +#include "dbClient.h" +#include + +void +DatabaseClient::SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key) +{ + merge->cols.insert(new SqlMergeTask::TargetColumn(name, key)); + if (key) { + merge->keys.insert(name); + } +} + +void +DatabaseClient::onAllDatasources(const DataSourceCall & call) const +{ + BOOST_FOREACH(const CommonObjects::DataSources::value_type & ds, CommonObjects::datasources) { + call(ds.second); + } +} + +DatabaseClient::TxHelper::TxHelper(const DatabaseClient * dbc) : + client(dbc), + so(NULL, + boost::bind(&DatabaseClient::onAllDatasources, dbc, DataSourceCall(boost::bind(&DataSource::commit, _1))), + boost::bind(&DatabaseClient::onAllDatasources, dbc, DataSourceCall(boost::bind(&DataSource::rollback, _1)))) +{ +} + +void +DatabaseClient::TxHelper::Commit() const +{ + client->onAllDatasources(boost::bind(&DataSource::commit, _1)); +} + +DatabaseClient::NoRowsFoundException::NoRowsFoundException() : + std::runtime_error("No rows found") +{ +} + +VariableType +operator/(const DatabaseClient::SelectPtr & cmd, unsigned int col) +{ + HandleAsVariableType vt; + (*cmd)[col].apply(vt); + return vt.variable; +} + +VariableType +operator/(const DatabaseClient::SelectPtr & cmd, const std::string & col) +{ + HandleAsVariableType vt; + (*cmd)[col].apply(vt); + return vt.variable; +} + diff --git a/p2pvr/daemon/dbClient.h b/p2pvr/daemon/dbClient.h new file mode 100644 index 0000000..84cf5e7 --- /dev/null +++ b/p2pvr/daemon/dbClient.h @@ -0,0 +1,103 @@ +#ifndef DBCLIENT_H +#define DBCLIENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "p2Helpers.h" + +class SqlMergeTask; + +class DatabaseClient : public virtual CommonObjects { + public: + typedef boost::shared_ptr SelectPtr; + typedef boost::shared_ptr ModifyPtr; + + static void SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key); + + class TxHelper { + public: + TxHelper(const DatabaseClient *); + void Commit() const; + + private: + const DatabaseClient * client; + ScopeObject so; + }; + + template + std::pair Modify(const std::string & sql, const Args & ... args) const + { + auto db = dataSource("postgres")->getWritable(); + auto cmd = ModifyPtr(db->newModifyCommand(sql)); + Bind(cmd.get(), 0, args...); + return {db, cmd}; + } + + template + std::pair Select(const std::string & sql, const Args & ... args) const + { + auto db = dataSource("postgres")->getReadonly(); + auto cmd = SelectPtr(db->newSelectCommand(sql)); + Bind(cmd.get(), 0, args...); + return {db, cmd}; + } + + class NoRowsFoundException : public std::runtime_error { + public: + NoRowsFoundException(); + }; + + template + Rtn SelectScalar(const std::string & sql, const Args & ... args) const + { + auto db = dataSource("postgres"); + auto cmd = SelectPtr(db->getReadonly()->newSelectCommand(sql)); + Bind(cmd.get(), 0, args...); + while (cmd->fetch()) { + HandleAsVariableType h; + (*cmd)[0].apply(h); + Rtn r; + h.variable >> r; + return r; + } + throw NoRowsFoundException(); + } + + private: + static void Bind(DB::Command *, unsigned int) { } + + template + static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg) + { + VariableType v; + v << arg; + boost::apply_visitor(SqlVariableBinder(cmd, offset), v); + } + + template + static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg, const Args & ... args) + { + Bind(cmd, offset, arg); + Bind(cmd, offset + 1, args...); + } + + friend class TxHelper; + typedef boost::function DataSourceCall; + void onAllDatasources(const DataSourceCall &) const; +}; + +VariableType +operator/(const DatabaseClient::SelectPtr & cmd, unsigned int col); + +VariableType +operator/(const DatabaseClient::SelectPtr & cmd, const std::string & col); + +#endif + diff --git a/p2pvr/daemon/globalDevices.cpp b/p2pvr/daemon/globalDevices.cpp new file mode 100644 index 0000000..4368cea --- /dev/null +++ b/p2pvr/daemon/globalDevices.cpp @@ -0,0 +1,86 @@ +#include +#include "globalDevices.h" +#include + +std::vector GlobalDevices::Devices; + +DECLARE_OPTIONS(GlobalDevices, "P2PVR Devices") +("p2pvr.globaldevices.carddaemon", + Options::functions( + [](const VariableType & df) { Devices.push_back(df); }, + []{ Devices.clear(); }), + "ICE address of remote device pools (:)") +END_OPTIONS(GlobalDevices); + +P2PVR::TunerPrx +GlobalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + BOOST_FOREACH(const auto & pool, Devices) { + try { + auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); + return poolprx->GetTunerSpecific(delivery); + } + catch (...) { + } + } + throw P2PVR::NoSuitableDeviceAvailable(); +} + +P2PVR::TunerPrx +GlobalDevices::GetTunerAny(short type, const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + BOOST_FOREACH(const auto & pool, Devices) { + try { + auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); + return poolprx->GetTunerAny(type, delivery); + } + catch (...) { + } + } + throw P2PVR::NoSuitableDeviceAvailable(); +} + +P2PVR::PrivateTunerPrx +GlobalDevices::GetPrivateTuner(short type, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + BOOST_FOREACH(const auto & pool, Devices) { + try { + auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); + return poolprx->GetPrivateTuner(type); + } + catch (...) { + } + } + throw P2PVR::NoSuitableDeviceAvailable(); +} + +void +GlobalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + BOOST_FOREACH(const auto & pool, Devices) { + auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); + poolprx->ReleaseTuner(tuner); + } +} + +int +GlobalDevices::TunerCount(const Ice::Current & ice) +{ + int total = 0; + auto ic = ice.adapter->getCommunicator(); + BOOST_FOREACH(const auto & pool, Devices) { + try { + auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); + total += poolprx->TunerCount(); + } + catch (...) { + // Not available, don't count 'em + } + } + return total; +} + diff --git a/p2pvr/daemon/globalDevices.h b/p2pvr/daemon/globalDevices.h new file mode 100644 index 0000000..da27c95 --- /dev/null +++ b/p2pvr/daemon/globalDevices.h @@ -0,0 +1,25 @@ +#ifndef GLOBALDEVICES_H +#define GLOBALDEVICES_H + +// Global devices implements a device collection (P2PVR::Devices) for any devices known +// throughout the system through other Devices interfaces + +#include +#include + +class GlobalDevices : public P2PVR::Devices { + public: + P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, const Ice::Current &); + P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, const Ice::Current &); + P2PVR::PrivateTunerPrx GetPrivateTuner(short type, const Ice::Current &); + void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &); + int TunerCount(const Ice::Current &); + + INITOPTIONS; + private: + static std::vector Devices; +}; + +#endif + + diff --git a/p2pvr/daemon/maintenance.cpp b/p2pvr/daemon/maintenance.cpp new file mode 100644 index 0000000..3475544 --- /dev/null +++ b/p2pvr/daemon/maintenance.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include "maintenance.h" +#include +#include "bindTimerTask.h" +#include +#include + +time_t Maintenance::periodUpdateNetwork; +time_t Maintenance::periodUpdateServices; +time_t Maintenance::periodUpdateEvents; + +DECLARE_OPTIONS(Maintenance, "P2PVR Maintenance options") +("p2pvr.maintenance.periodUpdateNetwork", Options::value(&periodUpdateNetwork, 86400 * 7), + "Period between automated updates of DVB network (1 week)") +("p2pvr.maintenance.periodUpdateServices", Options::value(&periodUpdateServices, 86400 * 7), + "Period between automated updates of DVB services (1 week)") +("p2pvr.maintenance.periodUpdateEvents", Options::value(&periodUpdateEvents, 3600 * 12), + "Period between automated updates of DVB events (12 hours)") +END_OPTIONS(Maintenance); + +Maintenance::Maintenance(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr t) : + adapter(a), + timer(t), + clientCheck(new BindTimerTask(boost::bind(&Maintenance::ScheduledUpdate, this))), + lastUpdateNetwork(0), + lastUpdateServices(0), + lastUpdateEvents(0), + updateRunning(false) +{ + timer->scheduleRepeated(clientCheck, IceUtil::Time::seconds(5 * 60)); +#ifdef NDEBUG + ScheduledUpdate(); +#endif +} + +void +Maintenance::UpdateAll(const Ice::Current & ice) +{ + UpdateAll(FE_OFDM, ice); + UpdateAll(FE_QPSK, ice); + UpdateAll(FE_ATSC, ice); + UpdateAll(FE_QAM, ice); +} + +void +Maintenance::UpdateAll(short type, const Ice::Current & ice) +{ + UpdateNetwork(type, ice); + UpdateServices(type, ice); + UpdateProgramAssociations(type, ice); + UpdateProgramMaps(type, ice); + UpdateEvents(type, ice); +} + +void +Maintenance::ScheduledUpdate() +{ + Logger()->messagebf(LOG_DEBUG, "%s: triggered", __PRETTY_FUNCTION__); + if (!updateRunning) { + std::thread update([this] { + try { + ScopeObject notRunning([this]{ updateRunning = false; }); + updateRunning = true; + auto si = P2PVR::MaintenancePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Maintenance"))); + time_t now = time(NULL); + if (lastUpdateNetwork < now - periodUpdateNetwork) { + Logger()->messagebf(LOG_INFO, "%s: updating network", __PRETTY_FUNCTION__); + si->UpdateNetwork(FE_OFDM); + time(&lastUpdateNetwork); + } + if (lastUpdateServices < now - periodUpdateServices) { + Logger()->messagebf(LOG_INFO, "%s: updating services", __PRETTY_FUNCTION__); + si->UpdateServices(FE_OFDM); + time(&lastUpdateServices); + } + if (lastUpdateEvents < now - periodUpdateEvents) { + Logger()->messagebf(LOG_INFO, "%s: updating events", __PRETTY_FUNCTION__); + si->UpdateEvents(FE_OFDM); + time(&lastUpdateEvents); + } + Logger()->messagebf(LOG_DEBUG, "%s: completed", __PRETTY_FUNCTION__); + } + catch (const std::exception & ex) { + char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); + Logger()->messagebf(LOG_ERR, "%s: failed %s: %s", __PRETTY_FUNCTION__, buf, ex.what()); + free(buf); + } + catch (...) { + Logger()->messagebf(LOG_ERR, "%s: failed (unknown exception)", __PRETTY_FUNCTION__); + } + }); + update.detach(); + } +} + diff --git a/p2pvr/daemon/maintenance.h b/p2pvr/daemon/maintenance.h new file mode 100644 index 0000000..563455a --- /dev/null +++ b/p2pvr/daemon/maintenance.h @@ -0,0 +1,39 @@ +#ifndef P2PVR_MAINTENANCE_H +#define P2PVR_MAINTENANCE_H + +#include +#include "dbClient.h" + +class Maintenance : public P2PVR::Maintenance, public DatabaseClient { + public: + Maintenance(Ice::ObjectAdapterPtr, IceUtil::TimerPtr); + + void UpdateAll(const Ice::Current &); + void UpdateAll(short type, const Ice::Current &); + void UpdateNetwork(short type, const Ice::Current &); + void UpdateServices(short type, const Ice::Current &); + void UpdateProgramAssociations(short type, const Ice::Current &); + void UpdateProgramMaps(short type, const Ice::Current &); + void UpdateEvents(short type, const Ice::Current &); + + INITOPTIONS; + + private: + void ScheduledUpdate(); + + Ice::ObjectAdapterPtr adapter; + IceUtil::TimerPtr timer; + IceUtil::TimerTaskPtr clientCheck; + + time_t lastUpdateNetwork; + time_t lastUpdateServices; + time_t lastUpdateEvents; + bool updateRunning; + + static time_t periodUpdateNetwork; + static time_t periodUpdateServices; + static time_t periodUpdateEvents; +}; + +#endif + diff --git a/p2pvr/daemon/maintenance/events.cpp b/p2pvr/daemon/maintenance/events.cpp new file mode 100644 index 0000000..b0c8b74 --- /dev/null +++ b/p2pvr/daemon/maintenance/events.cpp @@ -0,0 +1,92 @@ +#include +#include "../maintenance.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SiEventsHandler : public SiEpgParser { + public: + SiEventsHandler(const RowProcessorCallback & cb) : + callBack(cb) {} + + void HandleTable(DVBSI::EventPtr e) + { + Logger()->messagebf(LOG_DEBUG, "Service Id: %d Program Id: %d Title: %s Time: %s - %s", + e->ServiceId, e->EventId, e->Title, e->StartTime, e->StopTime); + BindColumns(rowState, e); + rowState.process(callBack); + } + + private: + ObjectRowState rowState; + const RowProcessorCallback callBack; +}; + +class SiEventsMerger : public IHaveSubTasks { + public: + SiEventsMerger(short t, const Ice::Current & i) : + SourceObject(__PRETTY_FUNCTION__), + IHaveSubTasks(NULL), + type(t), + ice(i) { } + + void execute(ExecContext * ec) const + { + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); + + if (!devs || !si) { + throw std::runtime_error("bad proxy(s)"); + } + + TemporarayIceAdapterObject parser(ice.adapter, + new SiEventsHandler(boost::bind(&SiEventsMerger::executeChildren, this, ec))); + + auto delivery = si->GetDeliveryForSi(); + if (!delivery) { + throw std::runtime_error("no delivery methods"); + } + + Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); + auto tuner = devs->GetTunerAny(type, delivery); + Logger()->messagebf(LOG_DEBUG, "%s: Fetching events", __PRETTY_FUNCTION__); + tuner->SendEventInformation(parser); + devs->ReleaseTuner(tuner); + } + + private: + const short type; + const Ice::Current & ice; + + void executeChildren(ExecContext * ec) const + { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(ec); + } + } +}; + +void +Maintenance::UpdateEvents(short type, const Ice::Current & ice) +{ + TxHelper tx(this); + SqlMergeTask mergeEvents("postgres", "events"); + CreateColumns(boost::bind(SqlMergeColumnsInserter, &mergeEvents, _1, _2)); + mergeEvents.sources.insert(new SiEventsMerger(type, ice)); + mergeEvents.loadComplete(this); + mergeEvents.execute(NULL); + tx.Commit(); + Logger()->messagebf(LOG_INFO, "%s: Updated events", __PRETTY_FUNCTION__); + + auto ic = ice.adapter->getCommunicator(); + auto sch = P2PVR::SchedulesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("Schedules"))); + sch->DoReschedule(); +} + diff --git a/p2pvr/daemon/maintenance/network.cpp b/p2pvr/daemon/maintenance/network.cpp new file mode 100644 index 0000000..d9ce0ec --- /dev/null +++ b/p2pvr/daemon/maintenance/network.cpp @@ -0,0 +1,107 @@ +#include +#include "../maintenance.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class SiNetworkInformationMerger : public SiNetworkInformationParser { + public: + SiNetworkInformationMerger(DatabaseClient * co) : commonObjects(co) { } + + bool HandleTable(DVBSI::NetworkPtr n) + { + Logger()->messagebf(LOG_DEBUG, "Network Id: %d Name: %s", n->NetworkId, *n->Name); + BOOST_FOREACH(const auto & ts, n->TransportStreams) { + Logger()->messagebf(LOG_DEBUG, "\tTransport Stream Id: %d Original Network Id: %d", ts->TransportStreamId, ts->OriginalNetworkId); + BOOST_FOREACH(const auto & s, ts->Services) { + Logger()->messagebf(LOG_DEBUG, "\t\tService Id: %d Service Type: %d", s.ServiceId, s.ServiceType); + } + if (ts->Terrestrial) { + Logger()->messagebf(LOG_DEBUG, "\t\tDVB-T: Frequency: %d", ts->Terrestrial->Frequency); + } + } + + DatabaseClient::TxHelper tx(commonObjects); + SqlMergeTask mergeNetwork("postgres", "networks"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeNetwork, _1, _2)); + std::vector networks = { n }; + mergeNetwork.sources.insert(new ContainerIterator>(&networks)); + mergeNetwork.loadComplete(commonObjects); + mergeNetwork.execute(NULL); + + SqlMergeTask mergeTransports("postgres", "transportstreams"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeTransports, _1, _2)); + mergeTransports.sources.insert(new ContainerIterator(&n->TransportStreams)); + mergeTransports.loadComplete(commonObjects); + mergeTransports.execute(NULL); + + SqlMergeTask mergeDvbt("postgres", "delivery_dvbt"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeDvbt, _1, _2)); + BOOST_FOREACH(const auto & s, n->TransportStreams) { + if (s->Terrestrial) { + mergeDvbt.sources.insert(new SingleIterator(&s->Terrestrial)); + } + } + mergeDvbt.loadComplete(commonObjects); + mergeDvbt.execute(NULL); + + SqlMergeTask mergeServices("postgres", "services"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeServices, _1, _2)); + BOOST_FOREACH(const auto & s, n->TransportStreams) { + mergeServices.sources.insert(new ContainerIterator(&s->Services)); + } + mergeServices.loadComplete(commonObjects); + mergeServices.execute(NULL); + return false; + } + private: + DatabaseClient * commonObjects; +}; + +void +Maintenance::UpdateNetwork(short type, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); + auto siparser = new SiNetworkInformationMerger(this); + TemporarayIceAdapterObject parser(ice.adapter, siparser); + + if (!devs) { + throw std::runtime_error("bad proxy(s)"); + } + auto transport = si->GetDeliveryForSi(); + if (transport) { + P2PVR::TunerPrx tuner; + try { + tuner = devs->GetTunerAny(type, transport); + tuner->SendNetworkInformation(parser); + devs->ReleaseTuner(tuner); + return; + } + catch (const P2PVR::NoSuitableDeviceAvailable &) { + Logger()->messagebf(LOG_WARNING, "%s: Failed to get a suitable tuner", __PRETTY_FUNCTION__); + throw; + } + catch (const std::exception & ex) { + Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information: %s", __PRETTY_FUNCTION__, ex.what()); + devs->ReleaseTuner(tuner); + throw; + } + catch (...) { + Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information", __PRETTY_FUNCTION__); + devs->ReleaseTuner(tuner); + throw; + } + } + // If we can't do that, do a complete scan + auto tuner = devs->GetPrivateTuner(type); + tuner->ScanAndSendNetworkInformation(parser); + devs->ReleaseTuner(tuner); +} + diff --git a/p2pvr/daemon/maintenance/programAssociations.cpp b/p2pvr/daemon/maintenance/programAssociations.cpp new file mode 100644 index 0000000..ad6438c --- /dev/null +++ b/p2pvr/daemon/maintenance/programAssociations.cpp @@ -0,0 +1,80 @@ +#include +#include "../maintenance.h" +#include +#include +#include +#include +#include +#include +#include + +class SiProgramAssociationHandler : public SiProgramAssociationParser { + public: + bool HandleTable(ProgramAssociationMapPtr pam) + { + Logger()->messagebf(LOG_DEBUG, "Program association table"); + BOOST_FOREACH(const auto & pa, *pam) { + Logger()->messagebf(LOG_DEBUG, " %d -> %d", pa.first, pa.second); + } + BOOST_FOREACH(const auto & pa, *pam) { + map[pa.first] = pa.second; + } + return false; + } + + ProgramAssociationMap map; +}; + +static +void +CreatePATColumns(const ColumnCreator & cc) +{ + cc("serviceId", true); + cc("programId", false); +} + +void +Maintenance::UpdateProgramAssociations(short type, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); + + if (!devs || !si) { + throw std::runtime_error("bad proxy(s)"); + } + + auto siparser = new SiProgramAssociationHandler(); + TemporarayIceAdapterObject parser(ice.adapter, siparser); + + const auto deliveries = si->GetAllDeliveries(type); + if (deliveries.empty()) { + throw std::runtime_error("no delivery methods"); + } + + BOOST_FOREACH(const auto & transport, deliveries) { + try { + Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); + auto tuner = devs->GetTunerSpecific(transport); + Logger()->messagebf(LOG_DEBUG, "%s: Fetching associations", __PRETTY_FUNCTION__); + tuner->SendProgramAssociationTable(parser); + Logger()->messagebf(LOG_INFO, "%s: Updated associations", __PRETTY_FUNCTION__); + devs->ReleaseTuner(tuner); + } + catch (...) { + // Tuning can fail + } + } + + TxHelper tx(this); + SqlMergeTask mergeServices("postgres", "services"); + CreatePATColumns(boost::bind(SqlMergeColumnsInserter, &mergeServices, _1, _2)); + // Don't change the list of services available from the network + mergeServices.doDelete = VariableType(false); + mergeServices.doInsert = VariableType(false); + Columns cols; + mergeServices.sources.insert(new MapIterator(CreatePATColumns, &siparser->map)); + mergeServices.loadComplete(this); + mergeServices.execute(NULL); +} + diff --git a/p2pvr/daemon/maintenance/programMap.cpp b/p2pvr/daemon/maintenance/programMap.cpp new file mode 100644 index 0000000..94d7752 --- /dev/null +++ b/p2pvr/daemon/maintenance/programMap.cpp @@ -0,0 +1,133 @@ +#include +#include "../maintenance.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SiProgramMapHandler : public SiProgramMapParser { + public: + SiProgramMapHandler(const RowProcessorCallback & cb) : + callBack(cb) {} + + bool HandleTable(DVBSI::ProgramMapPtr pmp) + { + Logger()->messagebf(LOG_DEBUG, "Program map: serviceId = %d", pmp->ServiceId); + BOOST_FOREACH(const auto & s, pmp->Streams) { + Logger()->messagef(LOG_DEBUG, "type: %02x id: %d", s->Type, s->Id); + } + BOOST_FOREACH(const auto & s, pmp->Streams) { + BindColumns(rowState, s); + rowState.process(callBack); + } + return false; + } + + private: + ObjectRowState rowState; + const RowProcessorCallback callBack; +}; + +typedef boost::shared_ptr SelectPtr; + +template +void +operator<<(T & val, const DB::Column & col) +{ + HandleAsVariableType havt; + col.apply(havt); + val = havt.variable; +} + +class SiProgramMapMerger : public IHaveSubTasks { + public: + SiProgramMapMerger(short t, CommonObjects * co, const Ice::Current & i) : + SourceObject(__PRETTY_FUNCTION__), + IHaveSubTasks(NULL), + commonObjects(co), + type(t), + ice(i) { } + + void execute(ExecContext * ec) const + { + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); + + if (!devs || !si) { + throw std::runtime_error("bad proxy(s)"); + } + + TemporarayIceAdapterObject parser(ice.adapter, + new SiProgramMapHandler(boost::bind(&SiProgramMapMerger::executeChildren, this, ec))); + + const auto deliveries = si->GetAllDeliveries(type); + if (deliveries.empty()) { + throw std::runtime_error("no delivery methods"); + } + + auto db = commonObjects->dataSource("postgres")->getReadonly(); + SelectPtr sel = SelectPtr(db->newSelectCommand("select d.frequency, s.programid \ + from delivery_dvbt d, services s \ + where d.transportstreamid = s.transportstreamid \ + and s.programid is not null \ + order by s.transportstreamid, s.serviceid")); + int64_t curFreq = 0; + P2PVR::TunerPrx tuner; + while (sel->fetch()) { + int64_t freq, pid; + freq << (*sel)[0]; + pid << (*sel)[1]; + + if (freq != curFreq) { + if (tuner) { + devs->ReleaseTuner(tuner); + } + Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); + const auto transport = *std::find_if(deliveries.begin(), deliveries.end(), + [freq](const DVBSI::DeliveryPtr & del) { return del->Frequency == freq; }); + tuner = devs->GetTunerSpecific(transport); + curFreq = freq; + } + + Logger()->messagebf(LOG_DEBUG, "%s: Fetching associations", __PRETTY_FUNCTION__); + tuner->SendProgramMap(pid, parser); + Logger()->messagebf(LOG_INFO, "%s: Updated associations", __PRETTY_FUNCTION__); + } + if (tuner) { + devs->ReleaseTuner(tuner); + } + } + + private: + CommonObjects * commonObjects; + const short type; + const Ice::Current & ice; + + void executeChildren(ExecContext * ec) const + { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(ec); + } + } +}; + +void +Maintenance::UpdateProgramMaps(short type, const Ice::Current & ice) +{ + TxHelper tx(this); + SqlMergeTask mergeServiceStreams("postgres", "servicestreams"); + CreateColumns(boost::bind(SqlMergeColumnsInserter, &mergeServiceStreams, _1, _2)); + mergeServiceStreams.sources.insert(new SiProgramMapMerger(type, this, ice)); + mergeServiceStreams.loadComplete(this); + mergeServiceStreams.execute(NULL); +} + diff --git a/p2pvr/daemon/maintenance/services.cpp b/p2pvr/daemon/maintenance/services.cpp new file mode 100644 index 0000000..55409c2 --- /dev/null +++ b/p2pvr/daemon/maintenance/services.cpp @@ -0,0 +1,68 @@ +#include +#include "../maintenance.h" +#include +#include +#include +#include +#include +#include +#include +#include + +class SiServicesMerger : public SiServicesParser { + public: + SiServicesMerger(DatabaseClient * co) : commonObjects(co) { } + + bool HandleTable(DVBSI::TransportStreamPtr ts) + { + Logger()->messagebf(LOG_DEBUG, "Transport Stream Id: %d Original Network Id: %s", ts->TransportStreamId, ts->OriginalNetworkId); + BOOST_FOREACH(const auto & s, ts->Services) { + Logger()->messagebf(LOG_DEBUG, "\tService Id: %d Name: %s Type: %d, Provider: %s, DefaultAuthority: %s, RunningStatus %d FreeCaMode %d", + s->ServiceId, (s->Name ? *s->Name : "?"), (s->Type ? *s->Type : -1), + (s->ProviderName ? *s->ProviderName : "?"), (s->DefaultAuthority ? *s->DefaultAuthority : "?"), + s->RunningStatus, s->FreeCaMode); + } + + DatabaseClient::TxHelper tx(commonObjects); + SqlMergeTask mergeServices("postgres", "services"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeServices, _1, _2)); + // Don't change the list of services available from the network + mergeServices.doDelete = VariableType(false); + mergeServices.doInsert = VariableType(false); + mergeServices.sources.insert(new ContainerIterator(&ts->Services)); + mergeServices.loadComplete(commonObjects); + mergeServices.execute(NULL); + return false; + } + + private: + DatabaseClient * commonObjects; +}; + +void +Maintenance::UpdateServices(short type, const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); + + if (!devs || !si) { + throw std::runtime_error("bad proxy(s)"); + } + + auto siparser = new SiServicesMerger(this); + TemporarayIceAdapterObject parser(ice.adapter, siparser); + + auto delivery = si->GetDeliveryForSi(); + if (!delivery) { + throw std::runtime_error("no delivery methods"); + } + + Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); + auto tuner = devs->GetTunerAny(type, delivery); + Logger()->messagebf(LOG_DEBUG, "%s: Fetching service list", __PRETTY_FUNCTION__); + tuner->SendServiceDescriptions(parser); + Logger()->messagebf(LOG_INFO, "%s: Updated service list", __PRETTY_FUNCTION__); + devs->ReleaseTuner(tuner); +} + diff --git a/p2pvr/daemon/pch.hpp b/p2pvr/daemon/pch.hpp new file mode 100644 index 0000000..bf16cef --- /dev/null +++ b/p2pvr/daemon/pch.hpp @@ -0,0 +1,24 @@ +#ifdef BOOST_BUILD_PCH_ENABLED +#ifndef P2PVRLIB_PCH +#define P2PVRLIB_PCH + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#endif +#endif + diff --git a/p2pvr/daemon/recorder.cpp b/p2pvr/daemon/recorder.cpp new file mode 100644 index 0000000..bdd18c6 --- /dev/null +++ b/p2pvr/daemon/recorder.cpp @@ -0,0 +1,100 @@ +#include +#include "recorder.h" +#include "bindTimerTask.h" +#include +#include +#include +#include +#include "serviceStreamer.h" +#include "storage.h" +#include "muxer.h" + +std::string Recorder::extension; +std::string Recorder::muxerCommand; + +DECLARE_OPTIONS(Recorder, "P2PVR Recorder options") +("p2pvr.recorder.extension", Options::value(&extension, "mpg"), + "File extension to save with (default: avi)") +("p2pvr.recorder.muxercommand", Options::value(&muxerCommand, "/usr/bin/ffmpeg -f mpegts -i - -f dvd -codec copy -"), + "File extension to save with (default: '/usr/bin/ffmpeg -f mpegts -i - -f dvd -codec copy -')") +END_OPTIONS(Recorder); + +Recorder::Recorder(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr t) : + adapter(a), + timer(t) +{ + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + RefreshSchedules(Ice::Current()); +} + +void +Recorder::RefreshSchedules(const Ice::Current &) +{ + std::lock_guard g(lock); + BOOST_FOREACH(auto & t, pendingRecordings) { + timer->cancel(t); + } + pendingRecordings.clear(); + auto schedules = P2PVR::SchedulesPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Schedules"))); + auto si = P2PVR::SIPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("SI"))); + BOOST_FOREACH(const auto & s, schedules->GetScheduledToRecord()) { + if (std::find_if(currentRecordings.begin(), currentRecordings.end(), [&s](const CurrentPtr & c) { + return s->ScheduleId == c->schedule->ScheduleId && s->ServiceId == c->event->ServiceId && s->EventId == c->event->EventId;; + }) != currentRecordings.end()) { + continue; + } + auto schedule = schedules->GetSchedule(s->ScheduleId); + auto service = si->GetService(s->ServiceId); + auto event = si->GetEvent(s->ServiceId, s->EventId); + + auto startIn = std::max((*event->StartTime - *schedule->Early - boost::posix_time::second_clock::universal_time()).total_seconds(), 0); + IceUtil::TimerTaskPtr startTimer = new BindTimerTask(boost::bind(&Recorder::StartRecording, this, schedule, service, event)); + timer->schedule(startTimer, IceUtil::Time::seconds(startIn)); + pendingRecordings.push_back(startTimer); + Logger()->messagebf(LOG_DEBUG, "Recording %s scheduled for %s seconds", event->Title, startIn); + } +} + +void +Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event) +{ + std::lock_guard g(lock); + auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); + auto recordings = P2PVR::RecordingsPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Recordings"))); + + auto id = storage->CreateForEventRecording(extension, schedule, service, event); + auto store = storage->OpenForWrite(id); + ScopeObject _store(NULL, NULL, [this,&store,&storage,&id]() { storage->Close(store); storage->Delete(id); }); + auto muxer = P2PVR::RawDataClientPrx::checkedCast(adapter->addWithUUID(new Muxer(store, muxerCommand))); + ScopeObject _muxer(NULL, NULL, [this,&muxer]() { adapter->remove(muxer->ice_getIdentity()); }); + auto ss = ServiceStreamerPtr(new ServiceStreamer(service->ServiceId, muxer, adapter->getCommunicator(), adapter)); + + ss->Start(); + Logger()->messagebf(LOG_INFO, "Started recording %s (%s - %s) on %s (%d)", + event->Title, event->StartTime, event->StopTime, + service->Name ? *service->Name : "", service->ServiceId); + + recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->Title, event->Subtitle, + event->Description, event->StartTime, *(*event->StopTime - *event->StartTime))); + auto newCurrent = CurrentPtr(new Current({muxer, store, ss, schedule, service, event, IceUtil::TimerTaskPtr()})); + currentRecordings.insert(newCurrent); + + auto stopIn = (*event->StopTime + *schedule->Late - boost::posix_time::second_clock::universal_time()).total_seconds(); + newCurrent->stopTimer = new BindTimerTask(boost::bind(&Recorder::StopRecording, this, newCurrent)); + timer->schedule(newCurrent->stopTimer, IceUtil::Time::seconds(stopIn)); + Logger()->messagebf(LOG_DEBUG, "Recording %s scheduled stop in %s seconds", event->Title, stopIn); +} + +void +Recorder::StopRecording(CurrentPtr c) +{ + std::lock_guard g(lock); + Logger()->messagebf(LOG_DEBUG, "Stopping %s", c->event->Title); + c->stream->Stop(); + adapter->remove(c->muxer->ice_getIdentity()); + currentRecordings.erase(c); + auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); + storage->Close(c->store); + Logger()->messagebf(LOG_DEBUG, "Stopped %s", c->event->Title); +} + diff --git a/p2pvr/daemon/recorder.h b/p2pvr/daemon/recorder.h new file mode 100644 index 0000000..78c604b --- /dev/null +++ b/p2pvr/daemon/recorder.h @@ -0,0 +1,51 @@ +#ifndef RECORDER_H +#define RECORDER_H + +#include +#include +#include +#include +#include +#include "serviceStreamer.h" + +class Recorder : public P2PVR::Recorder { + public: + typedef std::vector Pendings; + + class Current { + public: + P2PVR::RawDataClientPrx muxer; + P2PVR::RawDataClientPrx store; + ServiceStreamerPtr stream; + P2PVR::SchedulePtr schedule; + DVBSI::ServicePtr service; + DVBSI::EventPtr event; + IceUtil::TimerTaskPtr stopTimer; + }; + typedef boost::shared_ptr CurrentPtr; + typedef std::set Currents; + + Recorder(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr); + + void RefreshSchedules(const Ice::Current &); + + INITOPTIONS; + + private: + void StartRecordings(); + void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event); + void StopRecording(CurrentPtr); + + Ice::ObjectAdapterPtr adapter; + IceUtil::TimerPtr timer; + + Currents currentRecordings; + Pendings pendingRecordings; + std::mutex lock; + + static std::string extension; + static std::string muxerCommand; +}; + +#endif + diff --git a/p2pvr/daemon/recordings.cpp b/p2pvr/daemon/recordings.cpp new file mode 100644 index 0000000..bad8032 --- /dev/null +++ b/p2pvr/daemon/recordings.cpp @@ -0,0 +1,82 @@ +#include +#include "recordings.h" +#include "resources.h" +#include +#include +#include "sqlContainerCreator.h" + +ResourceString(Recording_Insert, daemon_sql_Recordings_insert_sql); +ResourceString(Recording_InsertNewId, daemon_sql_Recordings_insertNewId_sql); +ResourceString(Recording_Delete, daemon_sql_Recordings_delete_sql); +ResourceString(Recording_GetStorage, daemon_sql_Recordings_getStorage_sql); +ResourceString(Recording_GetAll, daemon_sql_Recordings_getAll_sql); + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("recordingid", true); + cc("storageaddress", false); + cc("guid", false); + cc("scheduleid", false); + cc("title", false); + cc("subtitle", false); + cc("description", false); + cc("starttime", false); + cc("duration", false); +} + +template<> +void +UnbindColumns(RowState & rs, const P2PVR::RecordingPtr & r) +{ + rs.fields[0] >> r->RecordingId; + rs.fields[1] >> r->StorageAddress; + rs.fields[2] >> r->Guid; + rs.fields[3] >> r->ScheduleId; + rs.fields[4] >> r->Title; + rs.fields[5] >> r->Subtitle; + rs.fields[6] >> r->Description; + rs.fields[7] >> r->StartTime; + rs.fields[8] >> r->Duration; +} + +int +Recordings::NewRecording(const P2PVR::RecordingPtr & r, const Ice::Current &) +{ + Logger()->messagebf(LOG_INFO, "%s: Creating new recording %s at %s", __PRETTY_FUNCTION__, r->Guid, r->StorageAddress); + TxHelper tx(this); + auto insert = Modify(Recording_Insert, + r->StorageAddress, r->Guid, r->ScheduleId, r->Title, r->Subtitle, r->Description, r->StartTime, r->Duration); + insert.second->execute(); + r->RecordingId = SelectScalar(Recording_InsertNewId); + Logger()->messagebf(LOG_INFO, "%s: Created recording Id: %d", __PRETTY_FUNCTION__, r->RecordingId); + return r->RecordingId; +} + +void +Recordings::DeleteRecording(int id, const Ice::Current & ice) +{ + Logger()->messagebf(LOG_INFO, "%s: Deleting recording Id: %d", __PRETTY_FUNCTION__, id); + auto ic = ice.adapter->getCommunicator(); + TxHelper tx(this); + auto recordingStorages = Select(Recording_GetStorage, id); + while (recordingStorages.second->fetch()) { + std::string addr = recordingStorages.second / "storageaddress"; + std::string guid = recordingStorages.second / "guid"; + auto storage = P2PVR::StoragePrx::checkedCast(ic->stringToProxy(addr)); + storage->Delete(guid); + Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); + } + Modify(Recording_Delete, id).second->execute(); +} + +P2PVR::RecordingList +Recordings::GetRecordings(const Ice::Current &) +{ + P2PVR::RecordingList rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(Recording_GetAll).second); + return rtn; +} + diff --git a/p2pvr/daemon/recordings.h b/p2pvr/daemon/recordings.h new file mode 100644 index 0000000..0f18a36 --- /dev/null +++ b/p2pvr/daemon/recordings.h @@ -0,0 +1,16 @@ +#ifndef RECORDINGS_H +#define RECORDINGS_H + +#include +#include +#include "dbClient.h" + +class Recordings : public DatabaseClient, public P2PVR::Recordings { + public: + int NewRecording(const P2PVR::RecordingPtr & rec, const Ice::Current &); + void DeleteRecording(int recordingId, const Ice::Current &); + P2PVR::RecordingList GetRecordings(const Ice::Current &); +}; + +#endif + diff --git a/p2pvr/daemon/schedulers/bitDumbScheduler.cpp b/p2pvr/daemon/schedulers/bitDumbScheduler.cpp new file mode 100644 index 0000000..f3cf5fb --- /dev/null +++ b/p2pvr/daemon/schedulers/bitDumbScheduler.cpp @@ -0,0 +1,55 @@ +#include +#include "../schedules.h" + +class TheBitDumbScheduler : public EpisodeGroup { + public: + TheBitDumbScheduler(const Episodes & eps) : + episodes(eps) + { + } + + protected: + void SelectShowings() + { + SelectShowings(episodes.begin(), 1); + } + + private: + void SelectShowings(Episodes::const_iterator e, uint64_t complexityLevel) + { + if (e != episodes.end()) { + complexityLevel *= (*e)->showings.size(); + if (complexityLevel > 2 << 16) { + auto current = showings.size(); + for (EpisodesIter ne = e; ne != episodes.end(); ne++) { + BOOST_FOREACH(const auto & s, (*ne)->showings) { + showings.push_back(s); + if (SuggestWithFeedback(showings) & 0x1) { + break; + } + showings.pop_back(); + } + } + showings.resize(current); + } + else { + EpisodesIter ne = e; + ne++; + BOOST_FOREACH(const auto & s, (*e)->showings) { + showings.push_back(s); + SelectShowings(ne, complexityLevel); + showings.pop_back(); + } + } + } + else { + Suggest(showings); + } + } + + mutable Showings showings; // working set + const Episodes episodes; +}; + +DECLARE_GENERIC_LOADER("BitDumb", EpisodeGroupLoader, TheBitDumbScheduler); + diff --git a/p2pvr/daemon/schedules.cpp b/p2pvr/daemon/schedules.cpp new file mode 100644 index 0000000..90df59c --- /dev/null +++ b/p2pvr/daemon/schedules.cpp @@ -0,0 +1,484 @@ +#include +#include "schedules.h" +#include "sqlContainerCreator.h" +#include +#include +#include +#include +#include +#include "p2Helpers.h" +#include "containerIterator.h" +#include "resources.h" +#include +#include + +ResourceString(Schedules_GetCandidates, daemon_sql_Schedules_GetCandidates_sql); +ResourceString(Schedules_insert, daemon_sql_Schedules_insert_sql); +ResourceString(Schedules_insertNewId, daemon_sql_Schedules_insertNewId_sql); +ResourceString(Schedules_update, daemon_sql_Schedules_update_sql); +ResourceString(Schedules_delete, daemon_sql_Schedules_delete_sql); +ResourceString(Schedules_selectAll, daemon_sql_Schedules_selectAll_sql); +ResourceString(Schedules_selectById, daemon_sql_Schedules_selectById_sql); +ResourceString(Schedules_scheduledToRecord, daemon_sql_Schedules_scheduledToRecord_sql); + +std::string Schedules::SchedulerAlgorithm; + +DECLARE_OPTIONS(Schedules, "P2PVR Scheduler options") +("p2pvr.scheduler.algorithm", Options::value(&SchedulerAlgorithm, "BitDumb"), + "Implementation of episode group scheduler problem solver") +END_OPTIONS() + +class ScheduleCandidate { + public: + std::string What; + int ServiceId; + int EventId; + int TransportStreamId; + datetime StartTime; + datetime StopTime; + int Priority; + int ScheduleId; +}; +typedef boost::shared_ptr ScheduleCandidatePtr; +typedef std::vector ScheduleCandidates; + +enum RecordStatuses { + Record_WillRecordThisShowing = 0, + Record_WillRecordOtherShowing = 1, + Record_CannotRecordAnyShowing = 2 +}; + +class Record { + public: + Record() { }; + Record(int s, int e, RecordStatuses rs, int sc) : + ServiceId(s), + EventId(e), + RecordStatus(rs), + ScheduleId(sc) + { + } + + int ServiceId; + int EventId; + RecordStatuses RecordStatus; + int ScheduleId; +}; +typedef boost::shared_ptr RecordPtr; +typedef std::vector Records; + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceid", true); + cc("eventid", true); + cc("scheduleid", true); +} + +template<> +void +UnbindColumns(RowState & rs, P2PVR::ScheduledToRecordPtr const & s) +{ + rs.fields[0] >> s->ServiceId; + rs.fields[1] >> s->EventId; + rs.fields[2] >> s->ScheduleId; +} + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("what", true); + cc("serviceid", false); + cc("eventid", false); + cc("transportstreamid", false); + cc("starttime", false); + cc("stoptime", false); + cc("priority", false); + cc("scheduleid", false); +} + +template<> +void +UnbindColumns(RowState & rs, ScheduleCandidatePtr const & s) +{ + rs.fields[0] >> s->What; + rs.fields[1] >> s->ServiceId; + rs.fields[2] >> s->EventId; + rs.fields[3] >> s->TransportStreamId; + rs.fields[4] >> s->StartTime; + rs.fields[5] >> s->StopTime; + rs.fields[6] >> s->Priority; + rs.fields[7] >> s->ScheduleId; +} + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("scheduleid", true); + cc("serviceid", false); + cc("eventid", false); + cc("title", false); + cc("search", false); + cc("priority", false); + cc("early", false); + cc("late", false); + cc("repeats", false); +} + +template<> +void +UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) +{ + rs.fields[0] >> s->ScheduleId; + rs.fields[1] >> s->ServiceId; + rs.fields[2] >> s->EventId; + rs.fields[3] >> s->Title; + rs.fields[4] >> s->Search; + rs.fields[5] >> s->Priority; + rs.fields[6] >> s->Early; + rs.fields[7] >> s->Late; + rs.fields[8] >> s->Repeats; +} + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceid", true); + cc("eventid", true); + cc("recordstatus", false); + cc("scheduleid", false); +} + +template<> +void +BindColumns(RowState & rs, RecordPtr const & s) +{ + rs.fields[0] << s->ServiceId; + rs.fields[1] << s->EventId; + rs.fields[2] << (int)s->RecordStatus; + rs.fields[3] << s->ScheduleId; +} + +Showing::Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) : + episode(ep), + serviceId(s), + eventId(e), + priority(p), + scheduleId(sc), + transportStreamId(t), + startTime(start), + stopTime(stop), + period(start, stop) +{ +} + +Episode::Episode(const std::string & w) : + priority(0), + what(w) +{ +} + +EpisodeGroup::EpisodeGroup() : + tuners(1), + sumTimeToStart(0), + score(0) +{ +} + +bool +EpisodeGroup::IsShowingListValid(const Showings & showings) const +{ + struct TransOffset { + unsigned int trans; + char offset; + }; + typedef std::multimap Periods; + typedef std::map Usage; + + Periods periods; + Usage usage; + + BOOST_FOREACH(const auto & s, showings) { + if (s) { + periods.insert(Periods::value_type(s->startTime, {s->transportStreamId, 1})); + periods.insert(Periods::value_type(s->stopTime, {s->transportStreamId, -1})); + } + } + bool result = true; + BOOST_FOREACH(const auto & p, periods) { + auto & u = usage[p.second.trans]; + u += p.second.offset; + if (std::count_if(usage.begin(), usage.end(), [](const Usage::value_type & uv) { return uv.second > 0;}) > tuners) { + result = false; + break; + } + } + periods.clear(); + usage.clear(); + return result; +} + +template +inline +bool NotNull(const T & p) +{ + return p != NULL; +} + +class SumTimeToStart { + public: + SumTimeToStart(time_t & t) : + total(t), + now(boost::posix_time::second_clock::universal_time()) + { + total = 0; + } + inline void operator()(const ShowingPtr & s) const + { + if (s) { + total += std::min((now - s->startTime).seconds(), 0); + } + } + public: + time_t & total; + datetime now; +}; + +const Showings & +EpisodeGroup::Solve() +{ + SelectShowings(); + return selected; +} + +void +EpisodeGroup::Suggest(const Showings & showings) +{ + unsigned int c = 0; + std::for_each(showings.begin(), showings.end(), [&c](const ShowingPtr & s) { if (s) c+= s->episode->priority; }); + if (c >= score) { + time_t stt; + std::for_each(showings.begin(), showings.end(), SumTimeToStart(stt)); + if (stt < sumTimeToStart || (stt == sumTimeToStart && c > score)) { + if (IsShowingListValid(showings)) { + selected = showings; + score = c; + sumTimeToStart = stt; + } + } + } +} + +EpisodeGroup::SuggestionResult +EpisodeGroup::SuggestWithFeedback(const Showings & showings) +{ + if (IsShowingListValid(showings)) { + unsigned int c = 0; + std::for_each(showings.begin(), showings.end(), [&c](const ShowingPtr & s) { if (s) c+= s->episode->priority; }); + if (c >= score) { + time_t stt; + std::for_each(showings.begin(), showings.end(), SumTimeToStart(stt)); + if (stt < sumTimeToStart) { + selected = showings; + score = c; + sumTimeToStart = stt; + return SuggestionValidAndAccepted; + } + } + return SuggestionValid; + } + else { + return SuggestionInvalid; + } +} + +void +Schedules::GetEpisodeIntersects(Episodes & all, Episodes & grouped) +{ + for (Episodes::iterator aei = all.begin(); aei != all.end(); aei++) { + const auto & ae = *aei; + BOOST_FOREACH(const auto & ge, grouped) { + BOOST_FOREACH(const auto & gs, ge->showings) { + BOOST_FOREACH(const auto & as, ae->showings) { + if (gs->period.intersects(as->period)) { + Logger()->messagebf(LOG_DEBUG, " added %s", ae->what); + grouped.push_back(ae); + all.erase(aei); + GetEpisodeIntersects(all, grouped); + return; + } + } + } + } + } +} + +void +Schedules::DoReschedule(const Ice::Current & ice) +{ + auto ic = ice.adapter->getCommunicator(); + auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); + unsigned int tunerCount = devs->TunerCount(); + + // Load list from database + ScheduleCandidates episodes; + SqlContainerCreator cct(episodes); + cct.populate(Select(Schedules_GetCandidates).second); + + Episodes scheduleList; + Showings allShowings; + EpisodePtr cur; + int minPriority = 0; + BOOST_FOREACH(const auto & c, episodes) { + if (!cur || cur->what != c->What) { + cur = new Episode(c->What); + scheduleList.push_back(cur); + } + ShowingPtr s = new Showing(c->ServiceId, c->EventId, c->TransportStreamId, c->ScheduleId, + c->StartTime, c->StopTime, c->Priority, cur.get()); + minPriority = std::min(minPriority, s->priority); + cur->showings.push_back(s); + allShowings.push_back(s); + } + Logger()->messagebf(LOG_DEBUG, "%d episodes created, %s showings", scheduleList.size(), allShowings.size()); + BOOST_FOREACH(const auto & e, scheduleList) { + Logger()->messagebf(LOG_DEBUG, " %s", e->what); + BOOST_FOREACH(const auto & s, e->showings) { + s->priority += 1 - minPriority; + e->priority += s->priority; + } + e->priority /= e->showings.size(); + } + + Records records; + // Solve + while (!scheduleList.empty()) { + auto work = scheduleList.begin(); + Logger()->messagebf(LOG_DEBUG, "start %s", (*work)->what); + Episodes group; + group.push_back(*work); + scheduleList.erase(work); + GetEpisodeIntersects(scheduleList, group); + std::sort(group.begin(), group.end(), [](const EpisodePtr & a, const EpisodePtr & b) { + if (a->priority > b->priority) return true; + if (a->priority < b->priority) return false; + return a->what < b->what; + }); + + Logger()->messagebf(LOG_DEBUG, "group created with %d episodes", group.size()); + double total = 1; + // Measure and add the optional to not record + BOOST_FOREACH(const auto & e, group) { + Logger()->messagebf(LOG_DEBUG, " %d * %d:%s", e->showings.size(), e->priority, e->what); + e->showings.push_back(NULL); + total *= e->showings.size(); + } + Logger()->messagebf(LOG_DEBUG, "group complexity of %d options", total); + + EpisodeGroupPtr sched = EpisodeGroupPtr(EpisodeGroupLoader::createNew(SchedulerAlgorithm, group)); + sched->tuners = tunerCount; + std::set selected; + BOOST_FOREACH(const auto & s, sched->Solve()) { + if (s) selected.insert(s); + } + + BOOST_FOREACH(const auto & c, group) { + Logger()->messagebf(LOG_DEBUG, "Episode %s, %d options", c->what, c->showings.size()); + BOOST_FOREACH(const auto & i, c->showings) { + if (selected.find(i) != selected.end()) { + Logger()->messagebf(LOG_DEBUG, " %s - %s (%d) <-", i->startTime, i->stopTime, i->transportStreamId); + } + else if (i) { + Logger()->messagebf(LOG_DEBUG, " %s - %s (%d)", i->startTime, i->stopTime, i->transportStreamId); + } + } + } + Logger()->message(LOG_DEBUG, "----------"); + BOOST_FOREACH(const auto & c, group) { + bool found = false; + BOOST_FOREACH(const auto & i, c->showings) { + if (i && selected.find(i) != selected.end()) { + found = true; + break; + } + } + BOOST_FOREACH(const auto & i, c->showings) { + if (i) { + records.push_back(RecordPtr(new Record(i->serviceId, i->eventId, + found ? + selected.find(i) != selected.end() ? Record_WillRecordThisShowing : Record_WillRecordOtherShowing : + Record_CannotRecordAnyShowing, i->scheduleId))); + } + } + } + } + + TxHelper tx(this); + SqlMergeTask mergeRecords("postgres", "record"); + CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeRecords, _1, _2)); + mergeRecords.sources.insert(new ContainerIterator(&records)); + mergeRecords.loadComplete(this); + mergeRecords.execute(NULL); + tx.Commit(); + + auto recorder = P2PVR::RecorderPrx::checkedCast(ice.adapter->createProxy(ice.adapter->getCommunicator()->stringToIdentity("Recorder"))); + recorder->RefreshSchedules(); +} + +void +Schedules::DeleteSchedule(int id, const Ice::Current & ice) +{ + TxHelper tx(this); + Modify(Schedules_delete, id).second->execute(); + DoReschedule(ice); +} + +P2PVR::ScheduleList +Schedules::GetSchedules(const Ice::Current &) +{ + P2PVR::ScheduleList schedules; + SqlContainerCreator cct(schedules); + cct.populate(Select(Schedules_selectAll).second); + return schedules; +} + +P2PVR::SchedulePtr +Schedules::GetSchedule(int id, const Ice::Current &) +{ + P2PVR::ScheduleList schedules; + SqlContainerCreator cct(schedules); + cct.populate(Select(Schedules_selectById, id).second); + if (schedules.empty()) throw P2PVR::NotFound(); + return schedules.front(); +} + +P2PVR::ScheduledToRecordList +Schedules::GetScheduledToRecord(const Ice::Current &) +{ + P2PVR::ScheduledToRecordList scheduled; + SqlContainerCreator cct(scheduled); + cct.populate(Select(Schedules_scheduledToRecord).second); + return scheduled; +} + +int +Schedules::UpdateSchedule(const P2PVR::SchedulePtr & s, const Ice::Current & ice) +{ + TxHelper tx(this); + if (s->ScheduleId == 0) { + Modify(Schedules_insert, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute(); + s->ScheduleId = SelectScalar(Schedules_insertNewId); + } + else { + Modify(Schedules_update, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute(); + } + DoReschedule(ice); + return s->ScheduleId; +} + +INSTANTIATESTORE(std::string, EpisodeGroupLoader); + diff --git a/p2pvr/daemon/schedules.h b/p2pvr/daemon/schedules.h new file mode 100644 index 0000000..f7075dd --- /dev/null +++ b/p2pvr/daemon/schedules.h @@ -0,0 +1,85 @@ +#ifndef SCHEDULER_H +#define SCHEDULER_H + +#include +#include +#include "dbClient.h" +#include + +typedef boost::posix_time::ptime datetime; +class Episode; + +class Showing : public IntrusivePtrBase { + public: + Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep); + // Record what? + const Episode * episode; + const unsigned int serviceId; + const unsigned int eventId; + int priority; + const unsigned int scheduleId; + // Requires + const unsigned int transportStreamId; + const datetime startTime; + const datetime stopTime; + const boost::posix_time::time_period period; +}; +typedef boost::intrusive_ptr ShowingPtr; +typedef std::vector Showings; +typedef Showings::const_iterator ShowingsIter; + +class Episode : public IntrusivePtrBase { + public: + Episode(const std::string & w); + int priority; + const std::string what; + Showings showings; +}; +typedef boost::intrusive_ptr EpisodePtr; +typedef std::vector Episodes; +typedef Episodes::const_iterator EpisodesIter; + +class EpisodeGroup { + public: + EpisodeGroup(); + + const Showings & Solve(); + unsigned int tuners; + + protected: + enum SuggestionResult { + SuggestionInvalid = 0, SuggestionValid = 1, SuggestionValidAndAccepted = 3 + }; + SuggestionResult SuggestWithFeedback(const Showings &); + void Suggest(const Showings &); + virtual void SelectShowings() = 0; + + private: + bool IsShowingListValid(const Showings & showings) const; + // chosen set + time_t sumTimeToStart; + unsigned int score; + Showings selected; +}; + +class Schedules : public P2PVR::Schedules, public DatabaseClient { + public: + void DeleteSchedule(int id, const Ice::Current &); + P2PVR::SchedulePtr GetSchedule(int id, const Ice::Current &); + P2PVR::ScheduleList GetSchedules(const Ice::Current &); + P2PVR::ScheduledToRecordList GetScheduledToRecord(const Ice::Current &); + int UpdateSchedule(const P2PVR::SchedulePtr &, const Ice::Current &); + void DoReschedule(const Ice::Current &); + + INITOPTIONS; + protected: + static void GetEpisodeIntersects(Episodes &, Episodes &); + private: + static std::string SchedulerAlgorithm; +}; + +typedef GenLoader EpisodeGroupLoader; +typedef boost::shared_ptr EpisodeGroupPtr; + +#endif + diff --git a/p2pvr/daemon/si.cpp b/p2pvr/daemon/si.cpp new file mode 100644 index 0000000..557003c --- /dev/null +++ b/p2pvr/daemon/si.cpp @@ -0,0 +1,127 @@ +#include +#include "si.h" +#include "resources.h" +#include "dvbsiHelpers.h" +#include "sqlContainerCreator.h" +#include +#include + +ResourceString(SI_serviceNextUsed, daemon_sql_SI_serviceNextUsed_sql); +ResourceString(SI_servicesSelectAll, daemon_sql_SI_servicesSelectAll_sql); +ResourceString(SI_servicesSelectById, daemon_sql_SI_servicesSelectById_sql); +ResourceString(SI_eventById, daemon_sql_SI_eventById_sql); +ResourceString(SI_eventsOnNow, daemon_sql_SI_eventsOnNow_sql); +ResourceString(SI_eventsInRange, daemon_sql_SI_eventsInRange_sql); + +P2PVR::Deliveries +SI::GetAllDeliveries(short type, const Ice::Current &) +{ + Logger()->messagebf(LOG_DEBUG, "%s(type %d)", __PRETTY_FUNCTION__, type); + P2PVR::Deliveries rtn; + SelectPtr sel; + switch (type) { + case FE_OFDM: + { + SqlContainerCreator cc(rtn); + cc.populate(Select("SELECT * FROM delivery_dvbt ORDER BY transportStreamId").second); + break; + } + case FE_QAM: + { + SqlContainerCreator cc(rtn); + cc.populate(Select("SELECT * FROM delivery_dvbc ORDER BY transportStreamId").second); + break; + } + case FE_QPSK: + { + SqlContainerCreator cc(rtn); + cc.populate(Select("SELECT * FROM delivery_dvbs ORDER BY transportStreamId").second); + break; + } + } + Logger()->messagebf(LOG_DEBUG, "%s: Found %d delivery methods", __PRETTY_FUNCTION__, rtn.size()); + return rtn; +} + +DVBSI::DeliveryPtr +SI::GetDeliveryForTransport(int id, const Ice::Current&) +{ + P2PVR::Deliveries rtn; + SqlContainerCreator cct(rtn); + cct.populate(Select("SELECT * FROM delivery_dvbt WHERE transportStreamId = ?", id).second); + SqlContainerCreator ccc(rtn); + ccc.populate(Select("SELECT * FROM delivery_dvbc WHERE transportStreamId = ?", id).second); + SqlContainerCreator ccs(rtn); + ccs.populate(Select("SELECT * FROM delivery_dvbs WHERE transportStreamId = ?", id).second); + return rtn.front(); +} + +DVBSI::DeliveryPtr +SI::GetDeliveryForSi(const Ice::Current&) +{ + P2PVR::Deliveries rtn; + SqlContainerCreator cct(rtn); + cct.populate(Select(SI_serviceNextUsed).second); + return rtn.front(); +} + +DVBSI::DeliveryPtr +SI::GetDeliveryForService(int id, const Ice::Current&) +{ + P2PVR::Deliveries rtn; + SqlContainerCreator cct(rtn); + cct.populate(Select("SELECT d.* FROM services s, delivery_dvbt d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); + SqlContainerCreator ccc(rtn); + ccc.populate(Select("SELECT d.* FROM services s, delivery_dvbc d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); + SqlContainerCreator ccs(rtn); + ccs.populate(Select("SELECT d.* FROM services s, delivery_dvbs d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); + return rtn.front(); +} + +DVBSI::ServiceList +SI::GetServices(const Ice::Current&) +{ + DVBSI::ServiceList rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(SI_servicesSelectAll).second); + return rtn; +} + +DVBSI::ServicePtr +SI::GetService(int id, const Ice::Current&) +{ + DVBSI::ServiceList rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(SI_servicesSelectById, id).second); + if (rtn.empty()) throw P2PVR::NotFound(); + return rtn.front(); +} + +DVBSI::EventPtr +SI::GetEvent(int serviceId, int eventId, const Ice::Current &) +{ + DVBSI::Events rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(SI_eventById, serviceId, eventId).second); + if (rtn.empty()) throw P2PVR::NotFound(); + return rtn.front(); +} + +DVBSI::Events +SI::EventsOnNow(const Ice::Current &) +{ + DVBSI::Events rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(SI_eventsOnNow).second); + return rtn; +} + +DVBSI::Events +SI::EventsInRange(const Common::DateTime & from, const Common::DateTime & to, const Ice::Current &) +{ + DVBSI::Events rtn; + SqlContainerCreator cc(rtn); + cc.populate(Select(SI_eventsInRange, from, to).second); + return rtn; +} + diff --git a/p2pvr/daemon/si.h b/p2pvr/daemon/si.h new file mode 100644 index 0000000..6b720dc --- /dev/null +++ b/p2pvr/daemon/si.h @@ -0,0 +1,23 @@ +#ifndef P2PVR_SI_H +#define P2PVR_SI_H + +#include +#include "dbClient.h" + +class SI : public P2PVR::SI, public DatabaseClient { + public: + P2PVR::Deliveries GetAllDeliveries(short type, const Ice::Current &); + DVBSI::DeliveryPtr GetDeliveryForService(int id, const Ice::Current &); + DVBSI::DeliveryPtr GetDeliveryForTransport(int id, const Ice::Current &); + DVBSI::DeliveryPtr GetDeliveryForSi(const Ice::Current &); + + DVBSI::ServiceList GetServices(const Ice::Current &); + DVBSI::ServicePtr GetService(int id, const Ice::Current &); + + DVBSI::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); + DVBSI::Events EventsOnNow(const Ice::Current &); + DVBSI::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); +}; + +#endif + diff --git a/p2pvr/daemon/sql/Recordings_delete.sql b/p2pvr/daemon/sql/Recordings_delete.sql new file mode 100644 index 0000000..3395376 --- /dev/null +++ b/p2pvr/daemon/sql/Recordings_delete.sql @@ -0,0 +1,2 @@ +DELETE FROM recordings +WHERE recordingId = ? diff --git a/p2pvr/daemon/sql/Recordings_getAll.sql b/p2pvr/daemon/sql/Recordings_getAll.sql new file mode 100644 index 0000000..c0a096c --- /dev/null +++ b/p2pvr/daemon/sql/Recordings_getAll.sql @@ -0,0 +1,3 @@ +SELECT recordingId, storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration +FROM recordings r +ORDER BY startTime, title, subtitle diff --git a/p2pvr/daemon/sql/Recordings_getStorage.sql b/p2pvr/daemon/sql/Recordings_getStorage.sql new file mode 100644 index 0000000..fdaf58d --- /dev/null +++ b/p2pvr/daemon/sql/Recordings_getStorage.sql @@ -0,0 +1,4 @@ +SELECT storageAddress, guid +FROM recordings +WHERE recordingId = ? + diff --git a/p2pvr/daemon/sql/Recordings_insert.sql b/p2pvr/daemon/sql/Recordings_insert.sql new file mode 100644 index 0000000..dfe2ccc --- /dev/null +++ b/p2pvr/daemon/sql/Recordings_insert.sql @@ -0,0 +1,2 @@ +INSERT INTO recordings(storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration) +VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/Recordings_insertNewId.sql b/p2pvr/daemon/sql/Recordings_insertNewId.sql new file mode 100644 index 0000000..0583b49 --- /dev/null +++ b/p2pvr/daemon/sql/Recordings_insertNewId.sql @@ -0,0 +1,2 @@ +SELECT currval('recordings_recordingid_seq'); + diff --git a/p2pvr/daemon/sql/SI_eventById.sql b/p2pvr/daemon/sql/SI_eventById.sql new file mode 100644 index 0000000..f0e028d --- /dev/null +++ b/p2pvr/daemon/sql/SI_eventById.sql @@ -0,0 +1,28 @@ +select e.serviceid, + e.eventid, + e.title, + e.titlelang, + e.subtitle, + e.description, + e.descriptionlang, + e.videoaspect, + e.videoframerate, + e.videohd, + e.audiochannels, + e.audiolanguage, + e.subtitlelanguage, + e.category, + e.subcategory, + e.usercategory, + e.dvbrating, + e.starttime, + e.stoptime, + e.episode, + e.episodes, + e.year, + e.flags, + e.season +from events e +where serviceid = ? +and eventid = ? + diff --git a/p2pvr/daemon/sql/SI_eventsInRange.sql b/p2pvr/daemon/sql/SI_eventsInRange.sql new file mode 100644 index 0000000..0a2d6de --- /dev/null +++ b/p2pvr/daemon/sql/SI_eventsInRange.sql @@ -0,0 +1,28 @@ +select e.serviceid, + e.eventid, + e.title, + e.titlelang, + e.subtitle, + e.description, + e.descriptionlang, + e.videoaspect, + e.videoframerate, + e.videohd, + e.audiochannels, + e.audiolanguage, + e.subtitlelanguage, + e.category, + e.subcategory, + e.usercategory, + e.dvbrating, + e.starttime, + e.stoptime, + e.episode, + e.episodes, + e.year, + e.flags, + e.season +from events e +where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime) +order by e.serviceid, e.starttime + diff --git a/p2pvr/daemon/sql/SI_eventsOnNow.sql b/p2pvr/daemon/sql/SI_eventsOnNow.sql new file mode 100644 index 0000000..36760b4 --- /dev/null +++ b/p2pvr/daemon/sql/SI_eventsOnNow.sql @@ -0,0 +1,27 @@ +select e.serviceid, + e.eventid, + e.title, + e.titlelang, + e.subtitle, + e.description, + e.descriptionlang, + e.videoaspect, + e.videoframerate, + e.videohd, + e.audiochannels, + e.audiolanguage, + e.subtitlelanguage, + e.category, + e.subcategory, + e.usercategory, + e.dvbrating, + e.starttime, + e.stoptime, + e.episode, + e.episodes, + e.year, + e.flags, + e.season +from events e +where now()::timestamp without time zone <@ tsrange(e.starttime, e.stoptime) +order by e.serviceid diff --git a/p2pvr/daemon/sql/SI_serviceNextUsed.sql b/p2pvr/daemon/sql/SI_serviceNextUsed.sql new file mode 100644 index 0000000..8e906ad --- /dev/null +++ b/p2pvr/daemon/sql/SI_serviceNextUsed.sql @@ -0,0 +1,12 @@ +SELECT dd.* +FROM delivery_dvbt dd, services s + LEFT OUTER JOIN record r + ON r.serviceid = s.serviceid + AND r.recordstatus = 0 + LEFT OUTER JOIN events e + ON r.eventid = e.eventid + AND r.serviceid = e.serviceid + AND e.starttime > NOW() +WHERE dd.transportstreamid = s.transportstreamid +ORDER BY e.starttime, s.serviceid +LIMIT 1 diff --git a/p2pvr/daemon/sql/SI_servicesSelectAll.sql b/p2pvr/daemon/sql/SI_servicesSelectAll.sql new file mode 100644 index 0000000..513a076 --- /dev/null +++ b/p2pvr/daemon/sql/SI_servicesSelectAll.sql @@ -0,0 +1,3 @@ +SELECT serviceId, transportStreamId, name, providerName, defaultAuthority, runningStatus, eitSchedule, eitPresentFollowing, freeCaMode +FROM services +ORDER BY serviceId diff --git a/p2pvr/daemon/sql/SI_servicesSelectById.sql b/p2pvr/daemon/sql/SI_servicesSelectById.sql new file mode 100644 index 0000000..f0bda72 --- /dev/null +++ b/p2pvr/daemon/sql/SI_servicesSelectById.sql @@ -0,0 +1,3 @@ +SELECT serviceId, transportStreamId, name, providerName, defaultAuthority, runningStatus, eitSchedule, eitPresentFollowing, freeCaMode +FROM services +WHERE serviceId = ? diff --git a/p2pvr/daemon/sql/Schedules_GetCandidates.sql b/p2pvr/daemon/sql/Schedules_GetCandidates.sql new file mode 100644 index 0000000..8e8b15e --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_GetCandidates.sql @@ -0,0 +1,25 @@ +select what, serviceid, eventid, transportstreamid, + starttime - early starttime, stoptime + late stoptime, + priority, scheduleid +from ( + select (e.title, e.subtitle, e.description)::text what, e.serviceid, e.eventid, sv.transportstreamid, + e.starttime, e.stoptime - interval '1 second' stoptime, + s.early, s.late, s.scheduleid, s.priority, + rank() over(partition by e.serviceid, e.eventid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank + from services sv, events e, schedules s + where (s.serviceid is null or s.serviceid = e.serviceid) + and (s.title is null or lower(s.title) = lower(e.title)) + and (s.eventid is null or s.eventid = e.eventid) + and (s.search is null or event_tsvector(e) @@ plainto_tsquery(s.search)) + and sv.serviceid = e.serviceid + and e.stoptime > now() + and not exists ( + select 1 + from recorded r + where lower(e.title) = lower(r.title) + and coalesce(lower(e.subtitle), '') = coalesce(lower(r.subtitle), '') + and ts_rank(to_tsvector(e.description), plainto_tsquery(r.description)) + + ts_rank(to_tsvector(r.description), plainto_tsquery(e.description)) > 1)) e +where e.schedulerank = 1 +order by e.priority desc, e.what, e.transportstreamid, e.starttime + diff --git a/p2pvr/daemon/sql/Schedules_delete.sql b/p2pvr/daemon/sql/Schedules_delete.sql new file mode 100644 index 0000000..e14edc3 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_delete.sql @@ -0,0 +1 @@ +DELETE FROM schedules WHERE scheduleId = ? diff --git a/p2pvr/daemon/sql/Schedules_insert.sql b/p2pvr/daemon/sql/Schedules_insert.sql new file mode 100644 index 0000000..100e78b --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_insert.sql @@ -0,0 +1,2 @@ +INSERT INTO schedules(serviceId, eventId, title, search, priority, early, late, repeats) +VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/daemon/sql/Schedules_insertNewId.sql b/p2pvr/daemon/sql/Schedules_insertNewId.sql new file mode 100644 index 0000000..f66acd5 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_insertNewId.sql @@ -0,0 +1 @@ +SELECT currval('schedules_scheduleid_seq'); diff --git a/p2pvr/daemon/sql/Schedules_pendingRecord.sql b/p2pvr/daemon/sql/Schedules_pendingRecord.sql new file mode 100644 index 0000000..ba4d7d8 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_pendingRecord.sql @@ -0,0 +1,13 @@ +select * +from record r, events e, schedules s +where r.serviceid = e.serviceid +and r.eventid = e.eventid +and /*r.scheduleid*/ 161 = s.scheduleid +and r.recordstatus = 1 +and r.recordingstatus = 0 +and e.starttime - s.early - interval '3minutes' < now() +order by e.starttime - s.early + +; +select * +from schedules \ No newline at end of file diff --git a/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql new file mode 100644 index 0000000..3874c37 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_scheduledToRecord.sql @@ -0,0 +1,8 @@ +SELECT r.serviceid, r.eventid, r.scheduleid +FROM record r, events e, schedules s +WHERE recordstatus = 0 +AND r.serviceid = e.serviceid +AND r.eventid = e.eventid +AND r.scheduleid = s.scheduleid +AND e.stoptime + s.late > NOW() +ORDER BY e.starttime, e.serviceid diff --git a/p2pvr/daemon/sql/Schedules_selectAll.sql b/p2pvr/daemon/sql/Schedules_selectAll.sql new file mode 100644 index 0000000..e9e500e --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_selectAll.sql @@ -0,0 +1,3 @@ +SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +FROM schedules +ORDER BY scheduleId diff --git a/p2pvr/daemon/sql/Schedules_selectById.sql b/p2pvr/daemon/sql/Schedules_selectById.sql new file mode 100644 index 0000000..4990418 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_selectById.sql @@ -0,0 +1,5 @@ +SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats +FROM schedules +WHERE scheduleid = ? +ORDER BY scheduleId + diff --git a/p2pvr/daemon/sql/Schedules_update.sql b/p2pvr/daemon/sql/Schedules_update.sql new file mode 100644 index 0000000..56c9531 --- /dev/null +++ b/p2pvr/daemon/sql/Schedules_update.sql @@ -0,0 +1,10 @@ +UPDATE schedules SET + serviceId = ?, + eventId = ?, + title = ?, + search = ?, + priority = ?, + early = ?, + late = ?, + repeats = ? +WHERE scheduleId = ? diff --git a/p2pvr/daemon/sqlContainerCreator.h b/p2pvr/daemon/sqlContainerCreator.h new file mode 100644 index 0000000..5c8d8f8 --- /dev/null +++ b/p2pvr/daemon/sqlContainerCreator.h @@ -0,0 +1,28 @@ +#ifndef SQLCONTAINERCREATOR_H +#define SQLCONTAINERCREATOR_H + +#include "containerCreator.h" +#include +#include +#include + +template > +class SqlContainerCreator : public ContainerCreator { + public: + SqlContainerCreator(T & c) : ContainerCreator(c) { } + + void populate(boost::shared_ptr sel) + { + sel->execute(); + ContainerCreator::populate(boost::bind(&DB::SelectCommand::fetch, sel), [sel](unsigned int c) { + HandleAsVariableType h; + const DB::Column & col = (*sel)[c]; + col.apply(h); + return h.variable; + }, sel->columnCount()); + } +}; + + +#endif + diff --git a/p2pvr/daemon/storage.cpp b/p2pvr/daemon/storage.cpp new file mode 100644 index 0000000..9d9345d --- /dev/null +++ b/p2pvr/daemon/storage.cpp @@ -0,0 +1,275 @@ +#include +#include "storage.h" +#include "fileSink.h" +#include +#include +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +fs::path Storage::root; +fs::path Storage::byAll; +fs::path Storage::byTitle; +fs::path Storage::byDate; +fs::path Storage::byService; +fs::path Storage::bySchedule; + +DECLARE_OPTIONS(Storage, "P2PVR Storage options") +("p2pvr.storage.root", Options::value(&root, "recordings"), + "Root folder in which to store recordings") +("p2pvr.storage.all", Options::value(&byAll, "all"), + "Sub folder in which to store all recordings") +("p2pvr.storage.bytitle", Options::value(&byTitle, "title"), + "Sub folder in which to store by title") +("p2pvr.storage.bydate", Options::value(&byDate, "date"), + "Sub folder in which to store by date") +("p2pvr.storage.byservice", Options::value(&byService, "service"), + "Sub folder in which to store by service") +("p2pvr.storage.byschedule", Options::value(&bySchedule, "schedule"), + "Sub folder in which to store by schedule") +END_OPTIONS(Storage); + +inline static +fs::path createPath(const fs::path & start) +{ + return start; +} + +template +inline static +fs::path +operator/(const fs::path & lhs, const IceUtil::Optional & rhs) +{ + if (rhs) { + return lhs / *rhs; + } + return lhs; +} + +template +inline static +fs::path createPath(const fs::path & start, const Arg & arg, const Args & ... args) +{ + auto path = start / arg; + return createPath(path, args...); +} + +template +inline static +std::string firstNotNull(const Arg & arg, const Args & ...) +{ + return boost::lexical_cast(arg); +} + +template +inline static +std::string firstNotNull(const IceUtil::Optional & arg, const Args & ... args) +{ + return arg ? firstNotNull(*arg, args...) : firstNotNull(args...); +} + +template +inline static +std::string firstNotNull(const std::string & arg, const Args & ...) +{ + return arg; +} + +inline static +std::string +formatIf(const boost::format & f) +{ + return f.str(); +} + +template +inline static +IceUtil::Optional +formatIf(boost::format & f, const IceUtil::Optional & arg, const Args & ... args) +{ + if (arg) { + f % *arg; + return formatIf(f, args...); + } + else { + return IceUtil::Optional(); + } +} + +template +inline static +IceUtil::Optional +formatIf(boost::format & f, const Arg & arg, const Args & ... args) +{ + f % arg; + return formatIf(f, args...); +} + +template +inline static +IceUtil::Optional +formatIf(const std::string & msgfmt, const Args & ... args) +{ + boost::format fmt(msgfmt); + return formatIf(fmt, args...); +} + +std::string +Storage::CreateForEventRecording(const std::string & ext, const P2PVR::SchedulePtr & schedule, const DVBSI::ServicePtr & service, const DVBSI::EventPtr & event, const Ice::Current &) +{ + fs::create_directories(root / byAll); + auto id = boost::lexical_cast(boost::uuids::random_generator()()); + fs::path path = root / byAll / id; + path.replace_extension(ext); + auto fd = open(path.string().c_str(), O_WRONLY | O_CREAT | O_EXCL, 0664); + if (fd < 0) { + Logger()->messagebf(LOG_ERR, "%s: Failed to open file for writing at %s (%d:%s)", __PRETTY_FUNCTION__, + path, errno, strerror(errno)); + throw P2PVR::StorageException(path.string(), strerror(errno)); + } + createSymlinks(ext, id, schedule, service, event); + Logger()->messagebf(LOG_INFO, "%s: Created new recording %s", __PRETTY_FUNCTION__, path); + + close(fd); + return id; +} + +void +Storage::createSymlinks(const std::string & ext, const std::string & target, const P2PVR::SchedulePtr & schedule, const DVBSI::ServicePtr & service, const DVBSI::EventPtr & event) +{ + // By title, with optional season and episode information + createSymlink(ext, target, createPath(root, byTitle, + event->Title, + formatIf("Season %02d", event->Season), + firstNotNull( + formatIf("Part %02d of %02d - %s", event->Episode, event->Episodes, event->Subtitle), + formatIf("Episode %02d - %s", event->Episode, event->Subtitle), + formatIf("Part %02d of %02d - %s", event->Episode, event->Episodes, event->Description), + formatIf("Part %02d of %02d", event->Episode, event->Episodes), + formatIf("Episode %02d - %s", event->Episode, event->Description), + event->Subtitle, + event->Description, + formatIf("Episode %02d", event->Episode), + event->StartTime))); + // By date + createSymlink(ext, target, createPath(root, byDate, + formatIf("%04d-%02d-%02d", event->StartTime.Year, event->StartTime.Month, event->StartTime.Day), + firstNotNull( + formatIf("%s - %s", event->Title, event->Subtitle), + formatIf("%s - %s", event->Title, event->Description), + event->Title))); + // By service + createSymlink(ext, target, createPath(root, byService, + service->Name, + firstNotNull( + formatIf("%s - %s", event->Title, event->Subtitle), + formatIf("%s - %s", event->Title, event->Description), + event->Title))); + // By schedule title + createSymlink(ext, target, createPath(root, bySchedule, + formatIf("Title: %s", schedule->Title), + formatIf("%04d-%02d-%02d", event->StartTime.Year, event->StartTime.Month, event->StartTime.Day), + firstNotNull( + formatIf("%s - %s", event->Title, event->Subtitle), + formatIf("%s - %s", event->Title, event->Description), + event->Title))); + // By schedule search + createSymlink(ext, target, createPath(root, bySchedule, + formatIf("Search: %s", schedule->Search), + firstNotNull( + formatIf("%s - %s", event->Title, event->Subtitle), + formatIf("%s - %s", event->Title, event->Description), + event->Title))); +} +void +Storage::createSymlink(const std::string & ext, const std::string & target, const fs::path & link) +{ + fs::path path = link; + path.replace_extension(ext); + Logger()->messagebf(LOG_DEBUG, "%s: link(%s) -> target(%s)", __PRETTY_FUNCTION__, path, target); + if (fs::exists(path)) { + Logger()->messagebf(LOG_WARNING, "%s: symlink already exists %s", __PRETTY_FUNCTION__, path); + return; + } + fs::create_directories(path.parent_path()); + fs::path relativeTarget; + for (fs::path tmp = path.parent_path(); tmp != root; tmp = tmp.parent_path()) { + relativeTarget /= ".."; + } + relativeTarget /= byAll; + relativeTarget /= target; + relativeTarget.replace_extension(ext); + fs::create_symlink(relativeTarget, path); +} + +std::string +Storage::FindExtension(const std::string & id) +{ + fs::directory_iterator end; + for (fs::directory_iterator itr(root / byAll); itr != end; ++itr) { + if (itr->path().stem() == id) { + return itr->path().extension().string(); + } + } + return ""; +} + +P2PVR::RawDataClientPrx +Storage::OpenForWrite(const std::string & id, const Ice::Current & ice) +{ + fs::path path = root / byAll / id; + path.replace_extension(FindExtension(id)); + auto fd = open(path.string().c_str(), O_WRONLY | O_APPEND | O_LARGEFILE); + if (fd < 0) { + Logger()->messagebf(LOG_ERR, "%s: Failed to open file for reading at %s (%d:%s)", __PRETTY_FUNCTION__, + path, errno, strerror(errno)); + throw P2PVR::StorageException(path.string(), strerror(errno)); + } + auto openFile = OpenFilePtr(new OpenFile(ice.adapter, new FileSink(fd))); + openFiles.insert(openFile); + return *openFile; +} + +void +Storage::Close(const P2PVR::RawDataClientPrx & file, const Ice::Current &) +{ + openFiles.erase(std::find_if(openFiles.begin(), openFiles.end(), [&file](const OpenFilePtr & of) { return *of == file; })); +} + +void +Storage::Delete(const std::string & id, const Ice::Current &) +{ + fs::path path = root / byAll / id; + path.replace_extension(FindExtension(id)); + Logger()->messagebf(LOG_INFO, "%s: Deleting links to %s", __PRETTY_FUNCTION__, path); + DeleteFrom(path, fs::canonical(root)); +} + +void +Storage::DeleteFrom(const fs::path & path, const fs::path & from) +{ + Logger()->messagebf(LOG_DEBUG, "%s: Deleting links to %s to %s", __PRETTY_FUNCTION__, path, from); + fs::directory_iterator end; + for (fs::directory_iterator itr(from); itr != end; ++itr) { + if (fs::is_directory(*itr)) { + DeleteFrom(path, *itr); + } + else { + boost::system::error_code err; + auto link = fs::canonical(*itr, err); + if (err || link == path) { + Logger()->messagebf(LOG_DEBUG, "%s: deleting %s", __PRETTY_FUNCTION__, *itr); + fs::remove(*itr); + } + } + } + if (from != root && fs::is_empty(from)) { + Logger()->messagebf(LOG_DEBUG, "%s: deleting directory %s", __PRETTY_FUNCTION__, from); + fs::remove(from); + } +} + diff --git a/p2pvr/daemon/storage.h b/p2pvr/daemon/storage.h new file mode 100644 index 0000000..093e00d --- /dev/null +++ b/p2pvr/daemon/storage.h @@ -0,0 +1,38 @@ +#ifndef STORAGE_H +#define STORAGE_H + +#include +#include +#include +#include +#include "temporaryIceAdapterObject.h" + +class Storage : public P2PVR::Storage { + public: + std::string CreateForEventRecording(const std::string & ext, const P2PVR::SchedulePtr &, const DVBSI::ServicePtr &, const DVBSI::EventPtr &, const Ice::Current &); + P2PVR::RawDataClientPrx OpenForWrite(const std::string &, const Ice::Current &); + void Close(const P2PVR::RawDataClientPrx & file, const Ice::Current &); + void Delete(const std::string &, const Ice::Current &); + + INITOPTIONS; + + protected: + static void createSymlinks(const std::string & ext, const std::string &, const P2PVR::SchedulePtr &, const DVBSI::ServicePtr &, const DVBSI::EventPtr &); + static void createSymlink(const std::string & ext, const std::string & target, const boost::filesystem::path & link); + static void DeleteFrom(const boost::filesystem::path &, const boost::filesystem::path &); + static std::string FindExtension(const std::string & id); + + typedef TemporarayIceAdapterObject OpenFile; + typedef boost::shared_ptr OpenFilePtr; + typedef std::set OpenFiles; + OpenFiles openFiles; + + static boost::filesystem::path root; + static boost::filesystem::path byAll; + static boost::filesystem::path byTitle; + static boost::filesystem::path byDate; + static boost::filesystem::path byService; + static boost::filesystem::path bySchedule; +}; + +#endif diff --git a/p2pvr/daemonbase/Jamfile.jam b/p2pvr/daemonbase/Jamfile.jam new file mode 100644 index 0000000..bae7dca --- /dev/null +++ b/p2pvr/daemonbase/Jamfile.jam @@ -0,0 +1,21 @@ +lib boost_system ; +lib boost_filesystem ; + +cpp-pch pch : pch.hpp : + ..//p2common + ..//p2daemonlib + ../ice//p2pvrice +; + +lib p2pvrdaemonbase : + pch + [ glob-tree *.cpp ] + : + ..//p2common + ../lib//p2pvrlib + ../ice//p2pvrice + : : + ../ice//p2pvrice + ..//p2daemonlib + . + ; diff --git a/p2pvr/daemonbase/daemonBase.cpp b/p2pvr/daemonbase/daemonBase.cpp new file mode 100644 index 0000000..4739498 --- /dev/null +++ b/p2pvr/daemonbase/daemonBase.cpp @@ -0,0 +1,64 @@ +#include +#include "daemonBase.h" +#include "p2LoggerWrapper.h" +#include +#include + +std::string DaemonBase::Adapter; +std::string DaemonBase::Endpoint; + +DECLARE_OPTIONS(DaemonBase, "P2PVR Daemon") +("p2pvr.daemon.iceadapter", Options::value(&Adapter, "DefaultAdapter"), "ICE Adapter name") +("p2pvr.daemon.iceendpoint", Options::value(&Endpoint, "default -p 10000"), "ICE Endpoint address") +END_OPTIONS(DaemonBase); + +DaemonBase::DaemonBase(int argc, char ** argv) : + ic(Ice::initialize(args(argc, argv), initData())) +{ +} + +DaemonBase::~DaemonBase() +{ + ic->destroy(); +} + +void +DaemonBase::run() const +{ + IceUtil::TimerPtr timer = new IceUtil::Timer(); + Logger()->messagebf(LOG_INFO, "Creating adapter (%s, %s)", Adapter, Endpoint); + auto adapter = ic->createObjectAdapterWithEndpoints(Adapter, Endpoint); + addServants(adapter, timer); + adapter->activate(); + + ic->waitForShutdown(); + timer->destroy(); +} + +void +DaemonBase::shutdown() const +{ + ic->shutdown(); + ic->waitForShutdown(); +} + +Ice::InitializationData +DaemonBase::initData() +{ + Ice::InitializationData data; + data.logger = new P2LoggerWrapper(); + return data; +} + +Ice::StringSeq & +DaemonBase::args(int, char **) +{ + _args.clear(); + _args.push_back("--Ice.ThreadPool.Client.Size=5"); + _args.push_back("--Ice.ThreadPool.Server.Size=5"); + _args.push_back("--Ice.ThreadPool.Client.SizeMax=10"); + _args.push_back("--Ice.ThreadPool.Server.SizeMax=20"); + _args.push_back("--Ice.ThreadPool.Client.SizeWarn=8"); + _args.push_back("--Ice.ThreadPool.Server.SizeWarn=16"); + return _args; +} diff --git a/p2pvr/daemonbase/daemonBase.h b/p2pvr/daemonbase/daemonBase.h new file mode 100644 index 0000000..3cf9b19 --- /dev/null +++ b/p2pvr/daemonbase/daemonBase.h @@ -0,0 +1,31 @@ +#ifndef DAEMONBASE_H +#define DAEMONBASE_H + +#include +#include +#include +#include + +class DaemonBase : public Daemon { + public: + DaemonBase(int argc, char ** argv); + ~DaemonBase(); + + void run() const; + void shutdown() const; + INITOPTIONS; + + protected: + virtual void addServants(const Ice::ObjectAdapterPtr &, const IceUtil::TimerPtr &) const = 0; + static Ice::InitializationData initData(); + Ice::StringSeq & args(int, char **); + + Ice::StringSeq _args; + Ice::CommunicatorPtr ic; + + static std::string Adapter; + static std::string Endpoint; +}; + +#endif + diff --git a/p2pvr/daemonbase/p2LoggerWrapper.cpp b/p2pvr/daemonbase/p2LoggerWrapper.cpp new file mode 100644 index 0000000..60ec191 --- /dev/null +++ b/p2pvr/daemonbase/p2LoggerWrapper.cpp @@ -0,0 +1,39 @@ +#include +#include "p2LoggerWrapper.h" +#include "logger.h" + +P2LoggerWrapper::P2LoggerWrapper(const std::string & p) : + prefix(p) +{ +} + +void +P2LoggerWrapper::print(const std::string & message) +{ + ::Logger()->messagebf(LOG_INFO, "%s: %s", prefix, message); +} + +void +P2LoggerWrapper::trace(const std::string & cat, const std::string & message) +{ + ::Logger()->messagebf(LOG_DEBUG, "%s: [%s] %s", prefix, cat, message); +} + +void +P2LoggerWrapper::warning(const std::string & message) +{ + ::Logger()->messagebf(LOG_WARNING, "%s: %s", prefix, message); +} + +void +P2LoggerWrapper::error(const std::string & message) +{ + ::Logger()->messagebf(LOG_ERR, "%s: %s", prefix, message); +} + +Ice::LoggerPtr +P2LoggerWrapper::cloneWithPrefix(const std::string & p) +{ + return new P2LoggerWrapper(prefix + "-" + p); +} + diff --git a/p2pvr/daemonbase/p2LoggerWrapper.h b/p2pvr/daemonbase/p2LoggerWrapper.h new file mode 100644 index 0000000..8febda5 --- /dev/null +++ b/p2pvr/daemonbase/p2LoggerWrapper.h @@ -0,0 +1,23 @@ +#ifndef P2LOGGERWRAPPER +#define P2LOGGERWRAPPER + +#include + +class P2LoggerWrapper : public Ice::Logger { + public: + P2LoggerWrapper(const std::string & prefix = std::string()); + + void print(const std::string & message); + void trace(const std::string & cat, const std::string & message); + void warning(const std::string & message); + void error(const std::string & message); + + Ice::LoggerPtr cloneWithPrefix(const std::string & prefix); + + private: + const std::string prefix; +}; + + +#endif + diff --git a/p2pvr/daemonbase/pch.hpp b/p2pvr/daemonbase/pch.hpp new file mode 100644 index 0000000..28b23b5 --- /dev/null +++ b/p2pvr/daemonbase/pch.hpp @@ -0,0 +1,13 @@ +#ifdef BOOST_BUILD_PCH_ENABLED +#ifndef P2PVRLIB_PCH +#define P2PVRLIB_PCH + +#include +#include +#include +#include +#include + +#endif +#endif + diff --git a/p2pvr/devices/Jamfile.jam b/p2pvr/devices/Jamfile.jam new file mode 100644 index 0000000..a3452a4 --- /dev/null +++ b/p2pvr/devices/Jamfile.jam @@ -0,0 +1,27 @@ +lib boost_system ; +lib boost_filesystem ; + +cpp-pch pch : pch.hpp : + boost_system + boost_filesystem + ..//p2common + ../ice//p2pvrice +; + +lib p2pvrdevices : + pch + [ glob-tree *.cpp ] + : + boost_system + boost_filesystem + ../dvb//p2pvrdvb + ../ice//p2pvrice + ../lib//p2pvrlib + ..//p2common + ../ice//p2pvrice + : : + boost_filesystem + ../ice//p2pvrice + boost_system + . + ; diff --git a/p2pvr/devices/frontend.cpp b/p2pvr/devices/frontend.cpp new file mode 100644 index 0000000..54870a1 --- /dev/null +++ b/p2pvr/devices/frontend.cpp @@ -0,0 +1,39 @@ +#include +#include "frontend.h" +#include "tuner.h" +#include +#include +#include +#include + +Frontend::Frontend(Tuner * t, int fd, const struct dvb_frontend_info & i) : + tuner(t), + frontendFD(fd), + fe_info(i) +{ +} + +Frontend::~Frontend() +{ + close(frontendFD); +} + +const struct dvb_frontend_info & +Frontend::Info() const +{ + return fe_info; +} + +fe_status +Frontend::GetStatus() const +{ + fe_status_t status; + if (ioctl(frontendFD, FE_READ_STATUS, &status) < 0) { + Logger()->messagebf(LOG_ERR, "Reading frontend %s status failed (%s:%d)", tuner->Device(), strerror(errno), errno); + throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); + } + return status; +} + +INSTANTIATESTORE(fe_type, FrontendLoader); + diff --git a/p2pvr/devices/frontend.h b/p2pvr/devices/frontend.h new file mode 100644 index 0000000..d33353d --- /dev/null +++ b/p2pvr/devices/frontend.h @@ -0,0 +1,32 @@ +#ifndef P2PVR_FRONTEND_H +#define P2PVR_FRONTEND_H + +#include +#include +#include + +class Tuner; + +class Frontend { + public: + typedef boost::function OnFrequencyFound; + Frontend(Tuner *, int fd, const struct dvb_frontend_info &); + virtual ~Frontend(); + + fe_status_t GetStatus() const; + virtual void TuneTo(const DVBSI::DeliveryPtr &) const = 0; + virtual void FrequencyScan(const OnFrequencyFound & off) const = 0; + virtual std::string Type() const = 0; + const struct dvb_frontend_info & Info() const; + + protected: + const Tuner * tuner; + const int frontendFD; + const struct dvb_frontend_info fe_info; +}; + +typedef GenLoader FrontendLoader; +typedef boost::shared_ptr FrontendPtr; + +#endif + diff --git a/p2pvr/devices/frontends/ofdm.cpp b/p2pvr/devices/frontends/ofdm.cpp new file mode 100644 index 0000000..93e0d86 --- /dev/null +++ b/p2pvr/devices/frontends/ofdm.cpp @@ -0,0 +1,159 @@ +#include +#include "../frontend.h" +#include "../tuner.h" +#include +#include +#include + +#define FREQ_OFFSET_MIN 0 +#define FREQ_OFFSET_MAX 4 + +class Frontend_OFDM : public Frontend { + public: + Frontend_OFDM(Tuner * t, int fd, const struct dvb_frontend_info & i) : Frontend(t, fd, i) { } + + void TuneTo(const DVBSI::DeliveryPtr & mp) const + { + auto td = DVBSI::TerrestrialDeliveryPtr::dynamicCast(mp); + if (!td) { + throw P2PVR::IncorrectDeliveryType(); + } + dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + feparams.frequency = td->Frequency; + feparams.inversion = INVERSION_OFF; + feparams.u.ofdm.bandwidth = (fe_bandwidth)td->Bandwidth; + feparams.u.ofdm.code_rate_HP = (fe_code_rate_t)td->CodeRateHP; + feparams.u.ofdm.code_rate_LP = (fe_code_rate_t)td->CodeRateLP; + feparams.u.ofdm.constellation = (fe_modulation_t)td->Constellation; + feparams.u.ofdm.transmission_mode = (fe_transmit_mode)td->TransmissionMode; + feparams.u.ofdm.guard_interval = (fe_guard_interval_t)td->GuardInterval; + feparams.u.ofdm.hierarchy_information = (fe_hierarchy_t)td->Hierarchy; + SetParameters(feparams); + WaitForLock(); + } + + dvb_frontend_parameters GetParameters() const + { + dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + if (ioctl(frontendFD, FE_GET_FRONTEND, &feparams) < 0) { + Logger()->messagebf(LOG_ERR, "Reading frontend parameters failed (%s:%d)", tuner->Device(), strerror(errno), errno); + throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); + } + return feparams; + } + + void WaitForLock() const + { + fe_status_t status = (fe_status_t)0; + // Wait for something + for (int x = Tuner::TuningTimeout / 10; x > 0 && (status = GetStatus()) == 0; x -= 1) { + usleep(10000); + } + // Was it useful? + if (!(status & (FE_HAS_SIGNAL | FE_HAS_CARRIER))) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (No signal or carrier: 0x%02x)", tuner->Device(), status); + throw P2PVR::DeviceError(tuner->Device(), "No carrier", 0); + } + // Wait for lock + for (int x = Tuner::LockTimeout / 10; x > 0 && ((status = GetStatus()) & FE_HAS_LOCK) == 0; x -= 1) { + usleep(10000); + } + if (!(status & FE_HAS_LOCK)) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s)", tuner->Device(), "No lock"); + throw P2PVR::DeviceError(tuner->Device(), "No lock", 0); + } + } + + void SetParameters(const dvb_frontend_parameters & feparams) const + { + if (ioctl(frontendFD, FE_SET_FRONTEND, &feparams) < 0) { + Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s:%d)", tuner->Device(), strerror(errno), errno); + throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); + } + } + + std::string Type() const + { + return "OFDM (DVB-T)"; + } + + enum Country { DVBT_AU, DVBT_DE, DVBT_FR, DVBT_GB }; + + static uint32_t FrequencyForCountry(Country country, int channel) + { + switch (country) { + case DVBT_AU: //AUSTRALIA, 7MHz step list + switch (channel) { + case 5 ... 12: return 142500000; + case 21 ... 69: return 333500000; + } + case DVBT_DE: //GERMANY + case DVBT_FR: //FRANCE, +/- offset 166kHz & +offset 332kHz & +offset 498kHz + case DVBT_GB: //UNITED KINGDOM, +/- offset + switch (channel) { + case 5 ... 12: return 142500000; // VHF unused in FRANCE, skip those in offset loop + case 21 ... 69: return 306000000; + } + } + return 0; + } + static uint32_t FrequencyStepForCountry(Country country, int channel) + { + switch (country) { + case DVBT_AU: + return 7000000; // dvb-t australia, 7MHz step + case DVBT_DE: + case DVBT_FR: + case DVBT_GB: + switch (channel) { // dvb-t europe, 7MHz VHF ch5..12, all other 8MHz + case 5 ... 12: return 7000000; + case 21 ... 69: return 8000000; + } + } + return 0; + } + static uint32_t ChannelFrequencyForCountry(Country country, int channel, int) + { + return FrequencyForCountry(country, channel) + (channel * FrequencyStepForCountry(country, channel)); + } + + void FrequencyScan(const OnFrequencyFound & onFrequencyFound) const + { + struct dvb_frontend_parameters feparams; + memset(&feparams, 0, sizeof(dvb_frontend_parameters)); + feparams.inversion = (fe_info.caps & FE_CAN_INVERSION_AUTO ? INVERSION_AUTO : INVERSION_OFF); + feparams.u.ofdm.constellation = (fe_info.caps & FE_CAN_QAM_AUTO ? QAM_AUTO : QAM_64); + feparams.u.ofdm.hierarchy_information = HIERARCHY_NONE; + + for (int channel = 0; channel < 134; channel += 1) { + for (uint32_t offset = FREQ_OFFSET_MIN; offset <= 0/*FREQ_OFFSET_MAX*/; offset += 1) { + feparams.frequency = ChannelFrequencyForCountry(DVBT_GB, channel, offset); + if (feparams.frequency == 0) { + continue; + } + if (fe_info.frequency_min > feparams.frequency || fe_info.frequency_max < feparams.frequency) { + Logger()->messagebf(LOG_WARNING, "Channel %d, freq (%d Hz) outside card range", channel, feparams.frequency); + continue; + } + try { + Logger()->messagebf(LOG_DEBUG, "Channel %d, Frequency %d Hz", channel, feparams.frequency); + SetParameters(feparams); + WaitForLock(); + Logger()->messagebf(LOG_INFO, "Found multiplex at %d Hz", feparams.frequency); + Logger()->messagebf(LOG_DEBUG, "frequency %d", feparams.frequency); + if (onFrequencyFound(feparams.frequency)) { + return; + } + } + catch (const P2PVR::DeviceError &) { + // Moving on... + } + } + } + } +}; + +DECLARE_GENERIC_LOADER(FE_OFDM, FrontendLoader, Frontend_OFDM); + diff --git a/p2pvr/devices/localDevices.cpp b/p2pvr/devices/localDevices.cpp new file mode 100644 index 0000000..7a43a15 --- /dev/null +++ b/p2pvr/devices/localDevices.cpp @@ -0,0 +1,189 @@ +#include +#include "localDevices.h" +#include +#include "tuner.h" +#include "bindTimerTask.h" +#include + +LocalDevices::Devices LocalDevices::devices; +std::mutex LocalDevices::lock; + +DECLARE_OPTIONS(LocalDevices, "P2PVR Devices") +("p2pvr.localdevices.frontend", + Options::functions( + [](const VariableType & df) { devices.insert(Devices::value_type(df.as(), OpenTunerPtr())); }, + []{ devices.clear(); }), + "Frontend of DVB devices to use (/dev/dvb/adapterX/frontendY)") +END_OPTIONS(LocalDevices); + +LocalDevices::LocalDevices(Ice::ObjectAdapterPtr adapter, IceUtil::TimerPtr t) : + timer(t), + clientCheck(new BindTimerTask(boost::bind(&LocalDevices::ClientCheck, this, adapter))) +{ + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + timer->scheduleRepeated(clientCheck, IceUtil::Time::seconds(30)); +} + +LocalDevices::~LocalDevices() +{ + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + timer->cancel(clientCheck); +} + +void +LocalDevices::ClientCheck(Ice::ObjectAdapterPtr adapter) +{ + std::lock_guard g(lock); + BOOST_FOREACH(auto & device, devices) { + if (device.second && device.second->tuner->GetLastUsedTime() < time(NULL) - 30) { + Logger()->messagebf(LOG_DEBUG, "%s: Device %s no longer in use", __PRETTY_FUNCTION__, device.first); + auto id = device.second->tuner->ice_getIdentity(); + if (adapter->find(id)) { + adapter->remove(id); + } + device.second.reset(); + } + } +} + +P2PVR::TunerPrx +LocalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) +{ + std::lock_guard g(lock); + Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner (frequency %d)", __PRETTY_FUNCTION__, delivery->Frequency); + auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) { + return ot.second && !ot.second->openedPrivate && ot.second->delivery && ot.second->delivery->Frequency == delivery->Frequency; + }); + if (openTuner != devices.end()) { + openTuner->second->clients += 1; + return openTuner->second->tuner; + } + + openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); + if (openTuner == devices.end()) { + Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)", + __PRETTY_FUNCTION__, delivery->Frequency); + throw P2PVR::NoSuitableDeviceAvailable(); + } + + Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)", + __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); + P2PVR::PrivateTunerPtr t = new Tuner(openTuner->first); + t->TuneTo(delivery, ice); + auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(t)); + openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, false)); + + Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)", + __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); + return tuner; +} + +P2PVR::TunerPrx +LocalDevices::GetTunerAny(short , const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) +{ + std::lock_guard g(lock); + Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner any frequency", __PRETTY_FUNCTION__); + auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) { + return ot.second && !ot.second->openedPrivate && ot.second->delivery; + }); + if (openTuner != devices.end()) { + openTuner->second->clients += 1; + return openTuner->second->tuner; + } + + openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); + if (openTuner == devices.end()) { + Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)", + __PRETTY_FUNCTION__, delivery->Frequency); + throw P2PVR::NoSuitableDeviceAvailable(); + } + + Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)", + __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); + P2PVR::PrivateTunerPtr t = new Tuner(openTuner->first); + t->TuneTo(delivery, ice); + auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(t)); + openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, false)); + + Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)", + __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); + return tuner; +} + +P2PVR::PrivateTunerPrx +LocalDevices::GetPrivateTuner(short , const Ice::Current & ice) +{ + std::lock_guard g(lock); + Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner", __PRETTY_FUNCTION__); + auto openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); + if (openTuner == devices.end()) { + Logger()->messagebf(LOG_DEBUG, "%s: None free", __PRETTY_FUNCTION__); + throw P2PVR::NoSuitableDeviceAvailable(); + } + + Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner (frontend %s)", + __PRETTY_FUNCTION__, openTuner->first); + auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new Tuner(openTuner->first))); + openTuner->second = OpenTunerPtr(new OpenTuner(NULL, tuner, true)); + + return tuner; +} + +void +LocalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) +{ + std::lock_guard g(lock); + Logger()->messagebf(LOG_DEBUG, "%s", __PRETTY_FUNCTION__); + auto openTuner = std::find_if(devices.begin(), devices.end(), [tuner](const Devices::value_type & ot) { + return ot.second && ot.second->tuner == tuner; + }); + if (openTuner == devices.end()) { + Logger()->messagebf(LOG_DEBUG, "%s: Not one of mine", __PRETTY_FUNCTION__); + return; + } + Logger()->messagebf(LOG_DEBUG, "%s: Locally owned deivce %s", __PRETTY_FUNCTION__, openTuner->first); + openTuner->second->clients -= 1; + if (openTuner->second->clients == 0) { + auto id = tuner->ice_getIdentity(); + if (ice.adapter->find(id)) { + ice.adapter->remove(id); + } + openTuner->second.reset(); + } +} + +int +LocalDevices::TunerCount(const Ice::Current &) +{ + std::lock_guard g(lock); + return devices.size(); +} + +void +LocalDevices::Scan(const Ice::Current &) +{ + std::lock_guard g(lock); +} + +void +LocalDevices::Add(const std::string & frontend, const Ice::Current &) +{ + std::lock_guard g(lock); + devices.insert(Devices::value_type(frontend, OpenTunerPtr())); +} + +void +LocalDevices::Remove(const std::string & frontend, const Ice::Current &) +{ + std::lock_guard g(lock); + devices.erase(frontend); +} + +LocalDevices::OpenTuner::OpenTuner(DVBSI::DeliveryPtr d, P2PVR::PrivateTunerPrx t, bool op) : + openedPrivate(op), + delivery(d), + tuner(t), + clients(1) +{ +} + diff --git a/p2pvr/devices/localDevices.h b/p2pvr/devices/localDevices.h new file mode 100644 index 0000000..5521f8d --- /dev/null +++ b/p2pvr/devices/localDevices.h @@ -0,0 +1,52 @@ +#ifndef LOCALDEVICES_H +#define LOCALDEVICES_H + +// Local devices implements a device collection (P2PVR::Devices) for any devices physically +// attached to the local machine; that is, can be accessed directly through /dev/dvb/adapterX + +#include +#include +#include + +class LocalDevices : public P2PVR::LocalDevices { + public: + LocalDevices(Ice::ObjectAdapterPtr adapter, IceUtil::TimerPtr); + ~LocalDevices(); + + P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, const Ice::Current &); + P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, const Ice::Current &); + P2PVR::PrivateTunerPrx GetPrivateTuner(short type, const Ice::Current &); + void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &); + int TunerCount(const Ice::Current &); + + void Scan(const Ice::Current &); + void Add(const std::string & frontend, const Ice::Current &); + void Remove(const std::string & frontend, const Ice::Current &); + + INITOPTIONS; + private: + // Reference to global timer + IceUtil::TimerPtr timer; + IceUtil::TimerTaskPtr clientCheck; + + // Check that registered clients haven't silently gone away + void ClientCheck(Ice::ObjectAdapterPtr adapter); + + class OpenTuner { + public: + OpenTuner(DVBSI::DeliveryPtr, P2PVR::PrivateTunerPrx, bool); + + const bool openedPrivate; + const DVBSI::DeliveryPtr delivery; + const P2PVR::PrivateTunerPrx tuner; + + unsigned int clients; + }; + typedef boost::shared_ptr OpenTunerPtr; + typedef std::map Devices; + static Devices devices; + static std::mutex lock; +}; + +#endif + diff --git a/p2pvr/devices/pch.hpp b/p2pvr/devices/pch.hpp new file mode 100644 index 0000000..2eeeea5 --- /dev/null +++ b/p2pvr/devices/pch.hpp @@ -0,0 +1,24 @@ +#ifdef BOOST_BUILD_PCH_ENABLED +#ifndef P2PVRLIB_PCH +#define P2PVRLIB_PCH + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#endif +#endif + diff --git a/p2pvr/devices/tuner.cpp b/p2pvr/devices/tuner.cpp new file mode 100644 index 0000000..fe90231 --- /dev/null +++ b/p2pvr/devices/tuner.cpp @@ -0,0 +1,421 @@ +#include +#include "tuner.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fileHandle.h" +#include +#include "tunerSendSi.h" +#include "tunerSendTs.h" + +class FrontendNotSupported : public NotSupported { + public: + FrontendNotSupported(fe_type t) : NotSupported(stringbf("Frontend not supported: %s", t)) + { } +}; + +Tuner::Tuner(const boost::filesystem::path & df) : + deviceFrontend(df), + deviceRoot(df.branch_path()), + backgroundThread(NULL), + lastUsedTime(time(NULL)) +{ + int fd = open(deviceFrontend.string().c_str(), O_RDWR); + if (fd < 0) { + throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno); + } + try { + struct dvb_frontend_info fe_info; + if (ioctl(fd, FE_GET_INFO, &fe_info) < 0) { + throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno); + } + frontend = FrontendPtr(FrontendLoader::createNew(fe_info.type, this, fd, fe_info)); + } + catch (...) { + close(fd); + throw; + } + Logger()->messagebf(LOG_INFO, "%s: Attached to %s (%s, type %s)", __PRETTY_FUNCTION__, + deviceRoot, frontend->Info().name, frontend->Type()); +} + +Tuner::~Tuner() +{ + { + std::lock_guard g(lock); + while (!backgroundClients.empty()) { + close(backgroundClients.begin()->first); + backgroundClients.erase(backgroundClients.begin()); + } + } + if (backgroundThread) { + backgroundThread->join(); + delete backgroundThread; + } +} + +void +Tuner::TuneTo(const DVBSI::DeliveryPtr & mp, const Ice::Current&) +{ + frontend->TuneTo(mp); +} + +int +Tuner::GetStatus(const Ice::Current &) +{ + time(&lastUsedTime); + return frontend->GetStatus(); +} + +std::string +Tuner::Device() const +{ + time(&lastUsedTime); + return deviceRoot.string(); +} + +int +Tuner::OpenDemux() const +{ + int demux = open((deviceRoot / "demux0").string().c_str(), O_RDWR | O_NONBLOCK); + if (demux < 0) { + throw P2PVR::DeviceError(deviceRoot.string(), strerror(errno), errno); + } + return demux; +} + +void +Tuner::ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + time(&lastUsedTime); + frontend->FrequencyScan([this, &client, &ice](long) { + try { + return (SendPID(0x10, client, ice) > 0); + } + catch (const std::exception & ex) { + char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); + Logger()->messagebf(LOG_DEBUG, "%s: frequency scan lock event failed %s:%s", __PRETTY_FUNCTION__, buf, ex.what()); + free(buf); + return false; + } + catch (...) { + Logger()->messagebf(LOG_DEBUG, "%s: frequency scan lock event failed", __PRETTY_FUNCTION__); + return false; + } + }); +} + +void +Tuner::SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(0x10, client, ice); +} + +void +Tuner::SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(0x11, client, ice); +} + +void +Tuner::SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(0x11, client, ice); +} + +void +Tuner::SendProgramMap(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(pid, client, ice); +} + +void +Tuner::SendProgramAssociationTable(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(0x00, client, ice); +} + +void +Tuner::SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + SendPID(0x12, client, ice); +} + +uint64_t +Tuner::SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) const +{ + time(&lastUsedTime); + Logger()->messagebf(LOG_DEBUG, "%s: pid = 0x%x", __PRETTY_FUNCTION__, pid); + + if (ice.con) { + ice.con->createProxy(client->ice_getIdentity()); + } + FileHandle demux(OpenDemux()); + RequestPID(pid, demux); + return ReadDemuxAndSend(demux, client); +} + +void +Tuner::RequestPID(int pid, int demux) +{ + setBufferSize(demux, DemuxTableBufferSize); + struct dmx_sct_filter_params sctFilterParams; + memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params)); + sctFilterParams.pid = pid; + sctFilterParams.flags = DMX_IMMEDIATE_START; + + if (ioctl(demux, DMX_SET_FILTER, &sctFilterParams) < 0) { + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } +} + +uint64_t +Tuner::ReadDemuxAndSend(int demux, const P2PVR::RawDataClientPrx & _client) const +{ + Logger()->messagebf(LOG_DEBUG, "%s: begin", __PRETTY_FUNCTION__); + struct pollfd ufd; + memset(&ufd, 0, sizeof(pollfd)); + ufd.fd = demux; + ufd.events = POLLIN | POLLPRI; + BackgroundClient client = BackgroundClient(new SendSi(_client)); + do { + // Wait for data to appear + switch (poll(&ufd, 1, DemuxReadTimeout)) { + case -1: + Logger()->messagebf(LOG_DEBUG, "%s: poll error reading demux (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + case 0: + auto status = frontend->GetStatus(); + Logger()->messagebf(LOG_DEBUG, "%s: Timed out waiting for data (device status 0x%02x)", __PRETTY_FUNCTION__, status); + throw P2PVR::DeviceError("demux", "timeout", 0); + } + + // Read it + P2PVR::Data buf(1 << 12); + int nr = read(demux, &buf.front(), buf.size()); + if (nr < 0) { + Logger()->messagebf(LOG_DEBUG, "%s: error reading demux (%d:%s) status 0x%02x", + __PRETTY_FUNCTION__, errno, strerror(errno), frontend->GetStatus()); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } + size_t n = nr; + buf.resize(n); + + client->NewData(buf); + time(&lastUsedTime); + + } while (!client->IsFinished()); + auto packetsSent = client->PacketsSent(); + client.reset(); + Logger()->messagebf(LOG_DEBUG, "%s: end (sent %d packets)", __PRETTY_FUNCTION__, packetsSent); + return packetsSent; +} + +int +Tuner::StartSendingSection(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &) +{ + time(&lastUsedTime); + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + + std::lock_guard g(lock); + int demux = backgroundClients.insert(BackgroundClients::value_type(OpenDemux(), + BackgroundClient(new SendSi(client)))).first->first; + RequestPID(pid, demux); + startSenderThread(); + return demux; +} + +int +Tuner::StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) +{ + time(&lastUsedTime); + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + if (pids.empty()) { + throw P2PVR::DeviceError("demux", "Packet Id list cannot be empty", 0); + } + + if (ice.con) { + ice.con->createProxy(client->ice_getIdentity()); + } + std::lock_guard g(lock); + int demux = backgroundClients.insert(BackgroundClients::value_type(OpenDemux(), + BackgroundClient(new SendTs(client)))).first->first; + + struct dmx_pes_filter_params pesFilterParams; + memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params)); + Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER for pid %d", __PRETTY_FUNCTION__, pids[0]); + pesFilterParams.pid = pids[0]; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TSDEMUX_TAP; + pesFilterParams.pes_type = DMX_PES_OTHER; + pesFilterParams.flags = 0; + + if (ioctl(demux, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { + backgroundClients.erase(demux); + Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } + + for (unsigned int x = 1; x < pids.size(); x += 1) { + __u16 p = pids[x]; + Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID for pid %d", __PRETTY_FUNCTION__, p); + if (ioctl(demux, DMX_ADD_PID, &p) < 0) { + backgroundClients.erase(demux); + Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } + } + + setBufferSize(demux, DemuxStreamBufferSize); + if (ioctl(demux, DMX_START) < 0) { + backgroundClients.erase(demux); + Logger()->messagebf(LOG_ERR, "%s: DMX_START failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } + + startSenderThread(); + return demux; +} + +void +Tuner::setBufferSize(int demux, unsigned long size) +{ + if (ioctl(demux, DMX_SET_BUFFER_SIZE, size)) { + Logger()->messagebf(LOG_ERR, "%s: DMX_SET_BUFFER_SIZE to %d failed (%d: %s)", __PRETTY_FUNCTION__, size, errno, strerror(errno)); + throw P2PVR::DeviceError("demux", strerror(errno), errno); + } + Logger()->messagebf(LOG_DEBUG, "%s: DMX_SET_BUFFER_SIZE to %d", __PRETTY_FUNCTION__, size); +} + +void +Tuner::StopSending(int handle, const Ice::Current &) +{ + time(&lastUsedTime); + Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); + std::lock_guard g(lock); + if (backgroundClients.find(handle) != backgroundClients.end()) { + close(handle); + backgroundClients.erase(handle); + } +} + +void +Tuner::startSenderThread() +{ + if (!backgroundThread) { + backgroundThread = new std::thread(&Tuner::senderThread, this); + } +} + +void +Tuner::senderThread() +{ + lock.lock(); + while (!backgroundClients.empty()) { + int n = backgroundClients.rbegin()->first + 1; + fd_set rfds; + FD_ZERO(&rfds); + BOOST_FOREACH(const auto & c, backgroundClients) { + FD_SET(c.first, &rfds); + } + lock.unlock(); + time(&lastUsedTime); + + struct timeval tv { 2, 0 }; + switch (select(n, &rfds, NULL, NULL, &tv)) { + case -1: // error + Logger()->messagebf(LOG_DEBUG, "%s: select failed (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + case 0: // nothing to read, but all is well + break; + default: + { // stuff to do + std::lock_guard g(lock); + for (auto c = backgroundClients.begin(); c != backgroundClients.end(); ) { + if (FD_ISSET(c->first, &rfds)) { + // Read it + P2PVR::Data buf(1 << 16); + int nr = read(c->first, &buf.front(), buf.size()); + if (nr < 0) { + Logger()->messagebf(LOG_DEBUG, "%s: read failed (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); + close(c->first); + c = backgroundClients.erase(c); + } + else { + size_t n = nr; + buf.resize(n); + c->second->NewData(buf); + c++; + } + } + else { + c++; + } + } + } + break; + } + // Clean up finished async requests + lock.lock(); + for (auto client = backgroundClients.begin(); client != backgroundClients.end(); ) { + if (client->second->IsFinished()) { + close(client->first); + client = backgroundClients.erase(client); + } + else { + client++; + } + } + } + backgroundThread = NULL; + Logger()->messagebf(LOG_DEBUG, "%s: Unlocking", __PRETTY_FUNCTION__); + lock.unlock(); +} + +Ice::Long +Tuner::GetLastUsedTime(const Ice::Current &) +{ + return lastUsedTime; +} + +Tuner::IDataSender::IDataSender(const P2PVR::RawDataClientPrx & c) : + _packetsSent(0), + client(c) +{ +} + +Tuner::IDataSender::~IDataSender() +{ +} + +uint64_t +Tuner::IDataSender::PacketsSent() const +{ + return _packetsSent; +} + +int Tuner::TuningTimeout; +int Tuner::LockTimeout; +int Tuner::DemuxReadTimeout; +int Tuner::DemuxTableBufferSize; +int Tuner::DemuxStreamBufferSize; + +DECLARE_OPTIONS(Tuner, "P2PVR Tuner Options") +("p2pvr.tuner.tuningtimeout", Options::value(&TuningTimeout, 500), + "Timeout for a DVB frontend to tune (ms, default 500ms)") +("p2pvr.tuner.locktimeout", Options::value(&LockTimeout, 2000), + "Timeout for a DVB frontend to acquire lock (ms, default 2000ms)") +("p2pvr.tuner.demuxreadtimeout", Options::value(&DemuxReadTimeout, 20000), + "Timeout when reading from a demux device (ms, default 20s)") +("p2pvr.tuner.demuxtablebuffersize", Options::value(&DemuxTableBufferSize, 256*1024), + "Kernel buffer size for demux table data (bytes, default 256KB)") +("p2pvr.tuner.demuxstreambuffersize", Options::value(&DemuxStreamBufferSize, 1024*1024), + "Kernel buffer size for demux stream data (bytes, default 1MB)") +END_OPTIONS(Tuner); + diff --git a/p2pvr/devices/tuner.h b/p2pvr/devices/tuner.h new file mode 100644 index 0000000..670a17d --- /dev/null +++ b/p2pvr/devices/tuner.h @@ -0,0 +1,83 @@ +#ifndef P2PVR_TUNER_H +#define P2PVR_TUNER_H + +#include +#include +#include "frontend.h" +#include +#include +#include +#include +#include +#include +#include + +class Tuner : public P2PVR::PrivateTuner { + public: + class IDataSender { + public: + IDataSender(const P2PVR::RawDataClientPrx &); + virtual ~IDataSender() = 0; + + virtual void NewData(const P2PVR::Data &) = 0; + virtual bool IsFinished() = 0; + uint64_t PacketsSent() const; + + protected: + uint64_t _packetsSent; + const P2PVR::RawDataClientPrx client; + }; + typedef boost::shared_ptr BackgroundClient; + typedef std::map BackgroundClients; + + Tuner(const boost::filesystem::path & deviceFrontend); + ~Tuner(); + + void TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&); + int GetStatus(const Ice::Current&); + std::string Device() const; + + void ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendProgramMap(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendProgramAssociationTable(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + void SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); + + int StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current &); + int StartSendingSection(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &); + void StopSending(int handle, const Ice::Current &); + + Ice::Long GetLastUsedTime(const Ice::Current&); + + INITOPTIONS; + + private: + int OpenDemux() const; + uint64_t SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &) const; + static void RequestPID(int pid, int fd); + uint64_t ReadDemuxAndSend(int fd, const P2PVR::RawDataClientPrx & client) const; + void startSenderThread(); + void senderThread(); + static void setBufferSize(int fd, unsigned long bytes); + + const boost::filesystem::path deviceFrontend; + const boost::filesystem::path deviceRoot; + BackgroundClients backgroundClients; + std::thread * backgroundThread; + std::mutex lock; + + mutable time_t lastUsedTime; + FrontendPtr frontend; + + public: + static int TuningTimeout; + static int LockTimeout; + static int DemuxReadTimeout; + static int DemuxTableBufferSize; + static int DemuxStreamBufferSize; +}; + +#endif + diff --git a/p2pvr/devices/tunerSendSi.cpp b/p2pvr/devices/tunerSendSi.cpp new file mode 100644 index 0000000..e1f4637 --- /dev/null +++ b/p2pvr/devices/tunerSendSi.cpp @@ -0,0 +1,81 @@ +#include +#include "tunerSendSi.h" +#include +#include +#include "siParsers/table.h" + +SendSi::SendSi(const P2PVR::RawDataClientPrx & c) : + Tuner::IDataSender(c->ice_collocationOptimized(false)) +{ +} + +SendSi::~SendSi() +{ +} + +void +SendSi::NewData(const P2PVR::Data & buf) +{ + if (!IsValidSection(buf)) { + return; + } + _packetsSent += 1; + asyncs.insert(client->begin_NewData(buf)); +} + +bool +SendSi::IsFinished() +{ + try { + for (auto c = asyncs.begin(); c != asyncs.end(); ) { + if ((*c)->isCompleted()) { + if (client->end_NewData(*c)) { + return true; + } + c = asyncs.erase(c); + } + else { + c++; + } + } + return false; + } + catch (const std::exception & ex) { + Logger()->messagebf(LOG_DEBUG, "%s: Client transmit error (%s)", __PRETTY_FUNCTION__, ex.what()); + return true; + } +} + +bool +SendSi::IsValidSection(const P2PVR::Data & buf) +{ + auto n = buf.size(); + if (n < sizeof(SiTableHeader)) { + Logger()->messagebf(LOG_WARNING, "Received data too small to be an SI table."); + return false; + } + auto * tab = (const SiTableHeader *)(&buf.front()); + size_t l = sizeof(SiTableHeaderBase) + HILO(tab->section_length); + if (n < l) { + Logger()->messagebf(LOG_WARNING, "Received data shorter than its defined length."); + return false; + } + if (n > l) { + Logger()->messagebf(LOG_WARNING, "Received data longer than its defined length."); + return false; + } + if (!crc32(buf)) { + Logger()->messagebf(LOG_WARNING, "Received data is corrupted (crc32 failed)."); + return false; + } + return true; +} + +bool +SendSi::crc32(const P2PVR::Data & buf) +{ + boost::crc_optimal<32, 0x0, 0xFFFFFFFF, 0x0, true, false> crc; + crc.process_bytes(&buf.front(), buf.size()); + return crc.checksum() == 0; +} + diff --git a/p2pvr/devices/tunerSendSi.h b/p2pvr/devices/tunerSendSi.h new file mode 100644 index 0000000..df48f43 --- /dev/null +++ b/p2pvr/devices/tunerSendSi.h @@ -0,0 +1,24 @@ +#ifndef TUNER_SENDSI_H +#define TUNER_SENDSI_H + +#include "tuner.h" + +class SendSi : public Tuner::IDataSender { + public: + SendSi(const P2PVR::RawDataClientPrx &); + ~SendSi(); + + void NewData(const P2PVR::Data &); + bool IsFinished(); + + private: + static bool crc32(const P2PVR::Data &); + static bool IsValidSection(const P2PVR::Data &); + + std::set asyncs; + bool finish; +}; + +#endif + + diff --git a/p2pvr/devices/tunerSendTs.cpp b/p2pvr/devices/tunerSendTs.cpp new file mode 100644 index 0000000..70b6670 --- /dev/null +++ b/p2pvr/devices/tunerSendTs.cpp @@ -0,0 +1,77 @@ +#include +#include "tunerSendTs.h" +#include + +// ~64kb of TS packets +#define TARGET_BUFFER_SIZE (350 * 188) +// About the ICE message size limit +#define TARGET_BUFFER_LIMIT 512 * 1024 + +SendTs::SendTs(const P2PVR::RawDataClientPrx & c) : + Tuner::IDataSender(c->ice_collocationOptimized(false)) +{ + buffer.reserve(TARGET_BUFFER_SIZE); +} + +SendTs::~SendTs() +{ + try { + if (async) { + if (client->end_NewData(async)) return; + } + while (!buffer.empty()) { + sendBufferChunk(); + if (client->end_NewData(async)) return; + } + } + catch (...) { + } +} + +void +SendTs::NewData(const P2PVR::Data & buf) +{ + buffer.insert(buffer.end(), buf.begin(), buf.end()); + if (!async && buffer.size() >= TARGET_BUFFER_SIZE) { + sendBufferChunk(); + } +} + +void +SendTs::sendBufferChunk() +{ + if (buffer.size() > TARGET_BUFFER_LIMIT) { + auto breakPoint = buffer.begin() + TARGET_BUFFER_LIMIT; + async = client->begin_NewData(P2PVR::Data(buffer.begin(), breakPoint)); + buffer.erase(buffer.begin(), breakPoint); + } + else { + async = client->begin_NewData(buffer); + buffer.clear(); + buffer.reserve(TARGET_BUFFER_SIZE); + } + _packetsSent += 1; +} + +bool +SendTs::IsFinished() +{ + try { + if (async && async->isCompleted()) { + auto finished = client->end_NewData(async); + async = NULL; + if (finished) { + buffer.clear(); + } + return finished; + } + return false; + } + catch (const std::exception & ex) { + async = NULL; + Logger()->messagebf(LOG_DEBUG, "%s: Client transmit error (%s)", __PRETTY_FUNCTION__, ex.what()); + return true; + } +} + + diff --git a/p2pvr/devices/tunerSendTs.h b/p2pvr/devices/tunerSendTs.h new file mode 100644 index 0000000..ecf32fd --- /dev/null +++ b/p2pvr/devices/tunerSendTs.h @@ -0,0 +1,22 @@ +#ifndef TUNER_SENDTS_H +#define TUNER_SENDTS_H + +#include "tuner.h" + +class SendTs : public Tuner::IDataSender { + public: + SendTs(const P2PVR::RawDataClientPrx &); + ~SendTs(); + + void NewData(const P2PVR::Data &); + bool IsFinished(); + + private: + void sendBufferChunk(); + + Ice::AsyncResultPtr async; + P2PVR::Data buffer; +}; + +#endif + diff --git a/p2pvr/dvb/Jamfile.jam b/p2pvr/dvb/Jamfile.jam new file mode 100644 index 0000000..c8f2fe0 --- /dev/null +++ b/p2pvr/dvb/Jamfile.jam @@ -0,0 +1,14 @@ +cpp-pch pch : pch.hpp : + ../ice//p2pvrice +; + +lib p2pvrdvb : + pch + [ glob-tree *.cpp ] + : + ../ice//p2pvrice + ../ice//p2pvrice + : : + ../ice//p2pvrice + . + ; diff --git a/p2pvr/dvb/pch.hpp b/p2pvr/dvb/pch.hpp new file mode 100644 index 0000000..c6319b8 --- /dev/null +++ b/p2pvr/dvb/pch.hpp @@ -0,0 +1,23 @@ +#ifdef BOOST_BUILD_PCH_ENABLED +#ifndef P2PVRLIB_PCH +#define P2PVRLIB_PCH + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#endif +#endif + diff --git a/p2pvr/dvb/siParsers/event.cpp b/p2pvr/dvb/siParsers/event.cpp new file mode 100644 index 0000000..c094331 --- /dev/null +++ b/p2pvr/dvb/siParsers/event.cpp @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event.h" + +struct ShortEvent { + char lang_code[3]; + uint8_t event_name_length; + u_char data[]; +} __attribute__((packed)); + +struct Component { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char :4; + u_char stream_content :4; +#else + u_char stream_content :4; + u_char :4; +#endif + u_char component_type /*:8*/; + u_char component_tag /*:8*/; + char lang_code[3]; +} __attribute__((packed)); + +struct Content { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t content_nibble_level_1 :4; + uint8_t content_nibble_level_2 :4; +#else + uint8_t content_nibble_level_2 :4; + uint8_t content_nibble_level_1 :4; +#endif + uint8_t user_byte; +}; + +struct ParentalRating { + char country_code[3]; + uint8_t rating; +} __attribute__((packed)); + +struct EventDescriptor { + uint16_t EventId; + uint16_t mjd; + uint8_t start_time_h; + uint8_t start_time_m; + uint8_t start_time_s; + uint8_t duration_h; + uint8_t duration_m; + uint8_t duration_s; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char RunningStatus : 3; + u_char FreeCaMode : 1; + u_char descriptors_length_hi : 4; +#else + u_char descriptors_length_hi : 4; + u_char FreeCaMode : 1; + u_char RunningStatus : 3; +#endif + u_char descriptors_length_lo; + u_char data[]; +} __attribute__((packed)); + +static Glib::RefPtr episodeRegex = Glib::Regex::create("(?:[ (]+|^)(?:\\w+ )?([0-9]+)(?: of |/)([0-9]+)(?:[.)]+|$)"); +static Glib::RefPtr seasonEpisodeRegex = Glib::Regex::create("[ ([]*[Ss]\\s*([0-9]+)[ ,]*[Ee][Pp]?\\s*([0-9]+)[).\\]]*"); +static Glib::RefPtr yearRegex = Glib::Regex::create("[[(]([0-9]{4})[ ).\\]]+"); +static Glib::RefPtr flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]"); + +void +SiEpgParser::parseDescriptor_ShortEvent(DVBSI::EventPtr current, const u_char * data) +{ + auto * evtdesc = reinterpret_cast(data); + StrPtr title, subtitle, desc; + + current->TitleLang = std::string(evtdesc->lang_code, 3); + + size_t evtlen = evtdesc->event_name_length; + if (evtlen) { + title = convert((const char *)evtdesc->data, evtlen); + } + + size_t dsclen = evtdesc->data[evtlen]; + if (dsclen) { + subtitle = convert((const char *)evtdesc->data + evtlen + 1, dsclen); + } + + if (subtitle) { + Glib::MatchInfo matches; + if (yearRegex->match(*subtitle, matches)) { + current->Year = boost::lexical_cast(matches.fetch(1)); + *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); + } + if (flagsRegex->match(*subtitle, matches)) { + current->Flags = matches.fetch(1); + *subtitle = flagsRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); + } + if (episodeRegex->match(*subtitle, matches)) { + current->Episode = boost::lexical_cast(matches.fetch(1)); + current->Episodes = boost::lexical_cast(matches.fetch(2)); + if (*current->Episode <= *current->Episodes) { // fudge to catch "24/7" + *subtitle = episodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); + } + } + if (seasonEpisodeRegex->match(*subtitle, matches)) { + current->Season = boost::lexical_cast(matches.fetch(1)); + current->Episode = boost::lexical_cast(matches.fetch(2)); + *subtitle = seasonEpisodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); + } + } + if (title && subtitle) { + if (boost::algorithm::ends_with(*title, "...") && boost::algorithm::starts_with(*subtitle, "...")) { + title->resize(title->length() - 3); + *title += " "; + size_t dot = subtitle->find('.', 4); + if (dot == Glib::ustring::npos) { + title->append(*subtitle, 3, subtitle->length() - 3); + } + else { + title->append(*subtitle, 3, dot - 3); + subtitle->erase(0, dot + 2); + } + } + size_t colon = subtitle->find(':'); + if (colon != Glib::ustring::npos) { + desc = StrPtr(new Glib::ustring(*subtitle, colon + 1, subtitle->length() - colon)); + subtitle->resize(colon); + } + else { + colon = title->find(':'); + desc = subtitle; + if (colon != Glib::ustring::npos) { + subtitle = StrPtr(new Glib::ustring(*title, colon + 1, title->length() - colon)); + title->resize(colon); + } + else { + subtitle.reset(); + } + } + } + if (title) { + boost::algorithm::trim_if(*title, isspace); + current->Title = *title; + } + if (subtitle) { + boost::algorithm::trim_if(*subtitle, isspace); + if (!subtitle->empty()) { + current->Subtitle = *subtitle; + } + } + if (desc) { + boost::algorithm::trim_if(*desc, isspace); + if (!desc->empty()) { + current->Description = *desc; + } + } +} + +void +SiEpgParser::parseDescriptor_Component(DVBSI::EventPtr current, const u_char * data) +{ + auto * dc = reinterpret_cast(data); + + switch (dc->stream_content) { + case 0x01: // Video Info + current->VideoHD = ((dc->component_type - 1) & 0x08) ? 1 : 0; + current->VideoFrameRate = ((dc->component_type - 1) & 0x04) ? 30 : 25; + current->VideoAspect = ((dc->component_type - 1) & 0x03); + break; + case 0x02: // Audio Info + current->AudioChannels = dc->component_type; + current->AudioLanguage = Glib::ustring(dc->lang_code, 3); + break; + case 0x03: // Teletext Info + current->SubtitleLanguage = Glib::ustring(dc->lang_code, 3); + break; + } +} + +void +SiEpgParser::parseDescriptor_Content(DVBSI::EventPtr current, const u_char * data) +{ + auto nc = reinterpret_cast(data); + current->Category = nc->content_nibble_level_1; + current->SubCategory = nc->content_nibble_level_2; + current->UserCategory = nc->user_byte; +} + +void +SiEpgParser::parseDescriptor_ParentalRating(DVBSI::EventPtr current, const u_char * data) +{ + auto * pr = reinterpret_cast(data); + switch (pr->rating) { + case 0x01 ... 0x0F: + current->DvbRating = pr->rating + 3; + break; + case 0x00: /*undefined*/ + case 0x10 ... 0xFF: /*broadcaster defined*/ + current->DvbRating = NULL; + break; + } +} + +bool +SiEpgParser::CheckTableId(u_char tableId) const +{ + return ((tableId >= 0x50 && tableId <= 0x5f) || (tableId >= 0x60 && tableId <= 0x6f)); +} + +bool +SiEpgParser::HandleTable(DVBSI::EitInformationPtr) +{ + return false; +} + +Common::DateTime & +operator<<(Common::DateTime & dt, const boost::posix_time::ptime & pt) +{ + dt.Year = pt.date().year(); + dt.Month = pt.date().month(); + dt.Day = pt.date().day(); + dt.Hour = pt.time_of_day().hours(); + dt.Minute = pt.time_of_day().minutes(); + return dt; +} + +void +SiEpgParser::ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr ei) +{ + ei->ServiceId = ntohs(eit->header.content_id); + ei->TransportStreamId = ntohs(eit->TransportStreamId); + ei->OriginalNetworkId = ntohs(eit->OriginalNetworkId); + LoopOver(eit->data, HILO(eit->header.section_length) - 15, [this,ei](const EventDescriptor * ed) { + DVBSI::EventPtr e = new DVBSI::Event(); + e->EventId = ntohs(ed->EventId); + e->ServiceId = ei->ServiceId; + // + boost::gregorian::date startDate(boost::gregorian::gregorian_calendar::from_modjulian_day_number(ntohs(ed->mjd))); + boost::posix_time::ptime time(startDate); + time += boost::posix_time::time_duration(BcdCharToInt(ed->start_time_h), BcdCharToInt(ed->start_time_m), BcdCharToInt(ed->start_time_s)); + e->StartTime << time; + time += boost::posix_time::time_duration(BcdCharToInt(ed->duration_h), BcdCharToInt(ed->duration_m), BcdCharToInt(ed->duration_s)); + e->StopTime << time; + // + ParseDescriptors(ed->data, HILO(ed->descriptors_length), + 0x4d, boost::bind(&SiEpgParser::parseDescriptor_ShortEvent, e, _1), + 0x50, boost::bind(&SiEpgParser::parseDescriptor_Component, e, _1), + 0x54, boost::bind(&SiEpgParser::parseDescriptor_Content, e, _1), + 0x55, boost::bind(&SiEpgParser::parseDescriptor_ParentalRating, e, _1)); + HandleTable(e); + }); +} + diff --git a/p2pvr/dvb/siParsers/event.h b/p2pvr/dvb/siParsers/event.h new file mode 100644 index 0000000..6b316cc --- /dev/null +++ b/p2pvr/dvb/siParsers/event.h @@ -0,0 +1,35 @@ +#ifndef EPGROWS_H +#define EPGROWS_H + +#include "table.h" +#include + +struct EventInformation { + SiTableHeader header; + uint16_t TransportStreamId; + uint16_t OriginalNetworkId; + uint8_t SegmentLastSectionNumber; + uint8_t LastTableId; + u_char data[]; +} __attribute__((packed)); + +class SiEpgParser : public SiTableParser { + protected: + bool CheckTableId(u_char tableId) const; + int SectionNumberShift() const { return 3; } + uint8_t FirstTableId(const EventInformation * ei) { return (ei->header.tableid >= 0x60 ? 0x60 : 0x50); } + uint8_t LastTableId(const EventInformation * ei) { return ei->LastTableId; } + void ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr); + bool HandleTable(DVBSI::EitInformationPtr); + virtual void HandleTable(DVBSI::EventPtr) = 0; + + private: + static void parseStartTimeAndDuration(DVBSI::EventPtr, const u_char * data); + static void parseDescriptor_ShortEvent(DVBSI::EventPtr, const u_char * data); + static void parseDescriptor_Component(DVBSI::EventPtr, const u_char * data); + static void parseDescriptor_Content(DVBSI::EventPtr, const u_char * data); + static void parseDescriptor_ParentalRating(DVBSI::EventPtr, const u_char * data); +}; + +#endif + diff --git a/p2pvr/dvb/siParsers/network.cpp b/p2pvr/dvb/siParsers/network.cpp new file mode 100644 index 0000000..b91da1a --- /dev/null +++ b/p2pvr/dvb/siParsers/network.cpp @@ -0,0 +1,281 @@ +#include +#include "network.h" +#include +#include +#include +#include + +struct NetworkStreamsHeader { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved1 :4; + u_char transport_stream_loop_length_hi :4; +#else + u_char transport_stream_loop_length_hi :4; + u_char reserved1 :4; +#endif + u_char transport_stream_loop_length_lo; + u_char data[]; +} __attribute__((packed)); + +struct TransportStream { + uint16_t transportStreamId; + uint16_t originalNetworkId; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved1 :4; + u_char descriptors_length_hi :4; +#else + u_char descriptors_length_hi :4; + u_char reserved1 :4; +#endif + u_char descriptors_length_lo; + u_char data[]; +} __attribute__((packed)); + +struct TerrestrialDeliveryDescriptor { + uint32_t Frequency; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t Bandwidth : 3; + uint8_t Priority : 1; + uint8_t TimeSlicing : 1; + uint8_t MpeFec : 1; + uint8_t _reserved1 : 2; +#else + uint8_t _reserved1 : 2; + uint8_t MpeFec : 1; + uint8_t TimeSlicing : 1; + uint8_t Priority : 1; + uint8_t Bandwidth : 3; +#endif +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t Constellation : 2; + uint8_t Hierarchy : 3; + uint8_t CodeRateHP : 3; +#else + uint8_t CodeRateHP : 3; + uint8_t Hierarchy : 3; + uint8_t Constellation : 2; +#endif +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t CodeRateLP : 3; + uint8_t GuardInterval : 2; + uint8_t TransmissionMode : 2; + uint8_t OtherFrequencyFlag : 1; +#else + uint8_t OtherFrequencyFlag : 1; + uint8_t TransmissionMode : 2; + uint8_t GuardInterval : 2; + uint8_t CodeRateLP : 3; +#endif + uint32_t _reserved2; +} __attribute__((packed)); + +struct CableDeliveryDescriptor { + uint32_t Frequency; + uint8_t _reserved2; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t _reserved1 : 4; + uint8_t FecOuter : 4; +#else + uint8_t FecOuter : 4; + uint8_t _reserved1 : 4; +#endif + uint8_t Modulation; + uint8_t SymbolRate1; + uint8_t SymbolRate2; + uint8_t SymbolRate3; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t SymbolRate4 : 4; + uint8_t FecInner : 4; +#else + uint8_t FecInner : 4; + uint8_t SymbolRate4 : 4; +#endif +} __attribute__((packed)); + +struct SatelliteDeliveryDescriptor { + uint32_t Frequency; + uint16_t OrbitalPosition; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t WestEastFlag : 1; + uint8_t Polarization : 2; + uint8_t RollOff : 2; + uint8_t ModulationSystem : 1; + uint8_t ModulationType : 2; +#else + uint8_t ModulationType : 2; + uint8_t ModulationSystem : 1; + uint8_t RollOff : 2; + uint8_t Polarization : 2; + uint8_t WestEastFlag : 1; +#endif + uint8_t SymbolRate1; + uint8_t SymbolRate2; + uint8_t SymbolRate3; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t SymbolRate4 : 4; + uint8_t FecInner : 4; +#else + uint8_t FecInner : 4; + uint8_t SymbolRate4 : 4; +#endif +} __attribute__((packed)); + +struct ServiceListDescriptor { + uint16_t ServiceId; + uint8_t ServiceType; +} __attribute__((packed)); + +bool +SiNetworkInformationParser::CheckTableId(u_char tableId) const +{ + return (tableId == 0x40 || tableId == 0x041); +} + +void +SiNetworkInformationParser::ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr n) +{ + n->NetworkId = ntohs(nit->header.content_id); + auto nsh = ParseDescriptors(nit->data, HILO(nit->network_descriptor_length), + 0x40, boost::bind(&SiNetworkInformationParser::parseDescriptor_NetworkName, n, _1, _2)); + LoopOver(nsh->data, HILO(nsh->transport_stream_loop_length), [this,n](const TransportStream * ts) { + DVBSI::NetworkTransportStreamPtr nts = new DVBSI::NetworkTransportStream(); + nts->TransportStreamId = ntohs(ts->transportStreamId); + nts->NetworkId = n->NetworkId; + nts->OriginalNetworkId = ntohs(ts->originalNetworkId); + ParseDescriptors(ts->data, HILO(ts->descriptors_length), + 0x41, boost::bind(&SiNetworkInformationParser::parseDescriptor_ServiceList, nts, _1, _2), + 0x43, boost::bind(&SiNetworkInformationParser::parseDescriptor_SatelliteDelivery, nts, _1, _2), + 0x44, boost::bind(&SiNetworkInformationParser::parseDescriptor_CableDelivery, nts, _1, _2), + 0x5a, boost::bind(&SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery, nts, _1, _2)); + n->TransportStreams.push_back(nts); + }); +} + +void +SiNetworkInformationParser::parseDescriptor_NetworkName(DVBSI::NetworkPtr n, const u_char * p, size_t len) +{ + n->Name = *convert((const char *)p, len); +} + +#define SINOTSUPPORTED(What) \ +class What##NotSupported : public NotSupported { public: What##NotSupported(short id) : NotSupported(stringbf(#What" 0x%2x", id)) { } }; + +std::map tbandwidths { + {0, BANDWIDTH_8_MHZ}, + {1, BANDWIDTH_7_MHZ}, + {2, BANDWIDTH_6_MHZ}, + {3, BANDWIDTH_5_MHZ} +}; +SINOTSUPPORTED(Bandwidth); + +std::map tconstellations { + {0, QPSK}, + {1, QAM_16}, + {2, QAM_64} +}; +SINOTSUPPORTED(Constellation); + +std::map thierarchies { + {0, HIERARCHY_NONE}, + {1, HIERARCHY_1}, + {2, HIERARCHY_2}, + {3, HIERARCHY_4}, + {4, HIERARCHY_NONE}, + {5, HIERARCHY_1}, + {6, HIERARCHY_2}, + {7, HIERARCHY_4} +}; +SINOTSUPPORTED(Hierarchy); + +std::map tcoderates { + {0, FEC_1_2}, + {1, FEC_2_3}, + {2, FEC_3_4}, + {3, FEC_5_6}, + {4, FEC_7_8} +}; +SINOTSUPPORTED(CodeRate); + +std::map tguardintervals { + {0, GUARD_INTERVAL_1_32}, + {1, GUARD_INTERVAL_1_16}, + {2, GUARD_INTERVAL_1_8}, + {3, GUARD_INTERVAL_1_4} +}; +SINOTSUPPORTED(GuardInterval); + +std::map ttransmitmodes { + {0, TRANSMISSION_MODE_2K}, + {1, TRANSMISSION_MODE_8K}, + {2, TRANSMISSION_MODE_4K} +}; +SINOTSUPPORTED(TransmissionMode); + +void +SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) +{ + assert(len == sizeof(TerrestrialDeliveryDescriptor)); + auto tdd = reinterpret_cast(data); + DVBSI::TerrestrialDeliveryPtr td = new DVBSI::TerrestrialDelivery; + td->Frequency = ((uint64_t)ntohl(tdd->Frequency)) * 10; + td->TransportStreamId = nts->TransportStreamId; + td->Bandwidth = safeMapLookup(tbandwidths, tdd->Bandwidth); + td->Priority = tdd->Priority; + td->TimeSlicing = tdd->TimeSlicing; + td->MpeFec = tdd->MpeFec; + td->Constellation = safeMapLookup(tconstellations, tdd->Constellation); + td->Hierarchy = safeMapLookup(thierarchies, tdd->Hierarchy); + td->CodeRateHP = safeMapLookup(tcoderates, tdd->CodeRateHP); + td->CodeRateLP = safeMapLookup(tcoderates, tdd->CodeRateLP); + td->GuardInterval = safeMapLookup(tguardintervals, tdd->GuardInterval); + td->TransmissionMode = safeMapLookup(ttransmitmodes, tdd->TransmissionMode); + td->OtherFrequencyFlag = tdd->OtherFrequencyFlag; + nts->Terrestrial = td; +} + +void +SiNetworkInformationParser::parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) +{ + assert(len == sizeof(CableDeliveryDescriptor)); + auto cdd = reinterpret_cast(data); + DVBSI::CableDeliveryPtr cd = new DVBSI::CableDelivery; + cd->Frequency = ((uint64_t)ntohl(cdd->Frequency)) * 10; + cd->TransportStreamId = nts->TransportStreamId; + cd->FecOuter = cdd->FecOuter; + cd->Modulation = cdd->Modulation; + cd->SymbolRate = HILO4(cdd->SymbolRate); + cd->FecInner = cdd->FecInner; + nts->Cable = cd; +} + +void +SiNetworkInformationParser::parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) +{ + assert(len == sizeof(SatelliteDeliveryDescriptor)); + auto sdd = reinterpret_cast(data); + DVBSI::SatelliteDeliveryPtr sd = new DVBSI::SatelliteDelivery; + sd->Frequency = ((uint64_t)ntohl(sdd->Frequency)) * 10; + sd->TransportStreamId = nts->TransportStreamId; + sd->OrbitalPosition = ntohs(sdd->OrbitalPosition); + sd->WestEastFlag = sdd->WestEastFlag; + sd->Polarization = sdd->Polarization; + sd->RollOff = sdd->RollOff; + sd->ModulationSystem = sdd->ModulationSystem; + sd->ModulationType = sdd->ModulationType; + sd->SymbolRate = HILO4(sdd->SymbolRate); + sd->FecInner = sdd->FecInner; + nts->Satellite = sd; +} + +void +SiNetworkInformationParser::parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) +{ + auto end = data + len; + while (data < end) { + auto d = reinterpret_cast(data); + nts->Services.push_back({ ntohs(d->ServiceId), nts->TransportStreamId, d->ServiceType }); + data += sizeof(ServiceListDescriptor); + } +} + + diff --git a/p2pvr/dvb/siParsers/network.h b/p2pvr/dvb/siParsers/network.h new file mode 100644 index 0000000..4f8e6e3 --- /dev/null +++ b/p2pvr/dvb/siParsers/network.h @@ -0,0 +1,35 @@ +#ifndef NETWORKINFORMATIONPARSER_H +#define NETWORKINFORMATIONPARSER_H + +#include "table.h" +#include + +struct NetworkInformation { + SiTableHeader header; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved2 :4; + u_char network_descriptor_length_hi :4; +#else + u_char network_descriptor_length_hi :4; + u_char reserved2 :4; +#endif + u_char network_descriptor_length_lo /*:8*/; + u_char data[]; +} __attribute__((packed)); + +class SiNetworkInformationParser : public SiTableParser { + protected: + bool CheckTableId(u_char tableId) const; + void ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr); + + private: + static void parseDescriptor_NetworkName(DVBSI::NetworkPtr, const u_char *data, size_t len); + static void parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); + static void parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); + static void parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); + static void parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); +}; + +#endif + + diff --git a/p2pvr/dvb/siParsers/programAssociation.cpp b/p2pvr/dvb/siParsers/programAssociation.cpp new file mode 100644 index 0000000..7839b9e --- /dev/null +++ b/p2pvr/dvb/siParsers/programAssociation.cpp @@ -0,0 +1,30 @@ +#include +#include "programAssociation.h" + +struct ProgramAssociation { + uint16_t program_number; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t reserved : 3; + uint8_t pid_hi : 5; +#else + uint8_t pid_hi : 5; + uint8_t reserved : 3; +#endif + uint8_t pid_lo; +}; + +bool +SiProgramAssociationParser::CheckTableId(u_char tableId) const +{ + return (tableId == 0x00); +} + +void +SiProgramAssociationParser::ParseSiTable(const ProgramAssociationSection * pas, ProgramAssociationMapPtr pam) +{ + LoopOverSection(pas->data, HILO(pas->header.section_length) - 12, [this,pam](const ProgramAssociation * sd) { + (*pam)[ntohs(sd->program_number)] = HILO(sd->pid); + }); +} + + diff --git a/p2pvr/dvb/siParsers/programAssociation.h b/p2pvr/dvb/siParsers/programAssociation.h new file mode 100644 index 0000000..653be0c --- /dev/null +++ b/p2pvr/dvb/siParsers/programAssociation.h @@ -0,0 +1,23 @@ +#ifndef PROGRAMASSOCIATION_H +#define PROGRAMASSOCIATION_H + +#include "table.h" +#include + +struct ProgramAssociationSection { + SiTableHeader header; + u_char data[]; +} __attribute__((packed)); + +typedef std::map ProgramAssociationMap; +typedef boost::shared_ptr ProgramAssociationMapPtr; + +class SiProgramAssociationParser : public SiTableParser { + protected: + bool CheckTableId(u_char tableId) const; + void ParseSiTable(const struct ProgramAssociationSection * pas, ProgramAssociationMapPtr); +}; + +#endif + + diff --git a/p2pvr/dvb/siParsers/programMap.cpp b/p2pvr/dvb/siParsers/programMap.cpp new file mode 100644 index 0000000..1ba78c4 --- /dev/null +++ b/p2pvr/dvb/siParsers/programMap.cpp @@ -0,0 +1,48 @@ +#include +#include "programMap.h" +#include +#include + +struct ProgramMapStream { + uint8_t stream_type; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved1 :3; + u_char elementary_PID_hi :5; +#else + u_char elementary_PID_hi :5; + u_char reserved1 :3; +#endif + u_char elementary_PID_lo; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved2 :4; + u_char ES_info_length_hi :4; +#else + u_char ES_info_length_hi :4; + u_char reserved2 :4; +#endif + u_char ES_info_length_lo; + u_char data[]; +}; + + +bool +SiProgramMapParser::CheckTableId(u_char tableId) const +{ + return (tableId == 0x02); +} + +void +SiProgramMapParser::ParseSiTable(const struct ProgramMap * pm, DVBSI::ProgramMapPtr pmp) +{ + pmp->ServiceId = ntohs(pm->header.content_id); + auto pms = ParseDescriptors(pm->data, HILO(pm->program_info_len)); + while (reinterpret_cast(pms) < &pm->header.section_length_lo + HILO(pm->header.section_length) - 4) { + DVBSI::StreamPtr s = new DVBSI::Stream(); + s->Type = pms->stream_type; + s->Id = HILO(pms->elementary_PID); + s->ServiceId = pmp->ServiceId; + pmp->Streams.push_back(s); + // Don't care what's in here, just need to move along + pms = ParseDescriptors(pms->data, HILO(pms->ES_info_length)); + } +} diff --git a/p2pvr/dvb/siParsers/programMap.h b/p2pvr/dvb/siParsers/programMap.h new file mode 100644 index 0000000..07821b5 --- /dev/null +++ b/p2pvr/dvb/siParsers/programMap.h @@ -0,0 +1,37 @@ +#ifndef PROGRAMMAP_H +#define PROGRAMMAP_H + +#include "table.h" +#include + +struct ProgramMap { + SiTableHeader header; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved1 :3; + u_char pcr_pid_hi :5; +#else + u_char pcr_pid_hi :5; + u_char reserved1 :3; +#endif + u_char pcr_pid_lo; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved2 :4; + u_char program_info_len_hi :4; +#else + u_char program_info_len_hi :4; + u_char reserved2 :4; +#endif + u_char program_info_len_lo; + u_char data[]; +} __attribute__((packed)); + +class SiProgramMapParser : public SiTableParser { + protected: + bool CheckTableId(u_char tableId) const; + void ParseSiTable(const struct ProgramMap * nit, DVBSI::ProgramMapPtr); +}; + +#endif + + + diff --git a/p2pvr/dvb/siParsers/service.cpp b/p2pvr/dvb/siParsers/service.cpp new file mode 100644 index 0000000..fbcd966 --- /dev/null +++ b/p2pvr/dvb/siParsers/service.cpp @@ -0,0 +1,70 @@ +#include +#include "service.h" +#include + +struct ServiceDescriptor { + uint16_t ServiceId; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char _reserved1 : 6; + u_char EitSchedule : 1; + u_char EitPresentFollowing : 1; +#else + u_char EitPresentFollowing : 1; + u_char EitSchedule : 1; + u_char _reserved1 : 6; +#endif +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char RunningStatus : 3; + u_char FreeCaMode : 1; + u_char descriptors_length_hi : 4; +#else + u_char descriptors_length_hi : 4; + u_char FreeCaMode : 1; + u_char RunningStatus : 3; +#endif + u_char descriptors_length_lo; + u_char data[]; +} __attribute__((packed)); + +bool +SiServicesParser::CheckTableId(u_char tableId) const +{ + return (tableId == 0x42 || tableId == 0x46); +} + +void +SiServicesParser::ParseSiTable(const TransportStreamDescriptor * tsd, DVBSI::TransportStreamPtr ts) +{ + ts->TransportStreamId = ntohs(tsd->header.content_id); + ts->OriginalNetworkId = ntohs(tsd->original_network_id); + LoopOver(tsd->data, HILO(tsd->header.section_length) - 12, [this,ts](const ServiceDescriptor * sd) { + DVBSI::ServicePtr s = new DVBSI::Service(); + s->ServiceId = ntohs(sd->ServiceId); + s->TransportStreamId = ts->TransportStreamId; + s->EitSchedule = sd->EitSchedule; + s->EitPresentFollowing = sd->EitPresentFollowing; + s->RunningStatus = sd->RunningStatus; + s->FreeCaMode = sd->FreeCaMode; + ParseDescriptors(sd->data, HILO(sd->descriptors_length), + 0x48, boost::bind(&SiServicesParser::parseDescriptor_Service, s, _1, _2), + 0x73, boost::bind(&SiServicesParser::parseDescriptor_DefaultAuthority, s, _1, _2)); + ts->Services.push_back(s); + }); +} + +void +SiServicesParser::parseDescriptor_Service(DVBSI::ServicePtr s, const u_char * p, size_t) +{ + s->Type = p[0]; + if (p[1]) { + s->ProviderName = *convert((const char *)(p + 2), p[1]); + } + s->Name = *convert((const char *)(p + 3 + p[1]), p[2 + p[1]]); +} + +void +SiServicesParser::parseDescriptor_DefaultAuthority(DVBSI::ServicePtr s, const u_char * p, size_t len) +{ + s->DefaultAuthority = *convert((const char *)p, len); +} + diff --git a/p2pvr/dvb/siParsers/service.h b/p2pvr/dvb/siParsers/service.h new file mode 100644 index 0000000..611eb90 --- /dev/null +++ b/p2pvr/dvb/siParsers/service.h @@ -0,0 +1,25 @@ +#ifndef SERVICEROWS_H +#define SERVICEROWS_H + +#include "table.h" +#include + +struct TransportStreamDescriptor { + SiTableHeader header; + uint16_t original_network_id; + uint8_t _reserved1; + u_char data[]; +} __attribute__((packed)); + +class SiServicesParser : public SiTableParser { + protected: + bool CheckTableId(u_char tableId) const; + void ParseSiTable(const struct TransportStreamDescriptor * nit, DVBSI::TransportStreamPtr); + + private: + static void parseDescriptor_Service(DVBSI::ServicePtr, const u_char *data, size_t len); + static void parseDescriptor_DefaultAuthority(DVBSI::ServicePtr, const u_char *data, size_t len); +}; + +#endif + diff --git a/p2pvr/dvb/siParsers/table.cpp b/p2pvr/dvb/siParsers/table.cpp new file mode 100644 index 0000000..9844814 --- /dev/null +++ b/p2pvr/dvb/siParsers/table.cpp @@ -0,0 +1,84 @@ +#include +#include "table.h" +#include +#include +#include +#include +#include + +SimpleMessageException(ErrorReadingData); +SimpleMessageException(TimeoutReadingData); +SimpleMessageException(DemuxOpenFailure); + +const std::string SiTableParserBase::ISO10646("ISO-10646"); +const std::string SiTableParserBase::EitEncoding("ISO6937"); +const std::string SiTableParserBase::UTF8("UTF8"); + +SiTableParserBase::SiTableParserBase() : + startTime(time(NULL)), + incomplete(0) +{ +} + +SiTableParserBase::~SiTableParserBase() +{ +} + +bool +SiTableParserBase::NewData(const P2PVR::Data & bytes, const Ice::Current&) +{ + //Logger()->messagebf(LOG_DEBUG, "%s: Got %d bytes", __PRETTY_FUNCTION__, bytes.size()); + currentRawData = &bytes; + return ParseInfoTable(&bytes.front(), bytes.size()); +} + +const P2PVR::Data & +SiTableParserBase::CurrentRawData() const +{ + return *currentRawData; +} + +SiTableParserBase::StrPtr +SiTableParserBase::convert(const char * txt, size_t len) +{ + if (len == 0) { + return boost::shared_ptr(new Glib::ustring()); + } + char enc[20]; + switch (*txt) { + default: + EitEncoding.copy(enc, EitEncoding.length()); + enc[EitEncoding.length()] = '\0'; + break; + case 0x01 ... 0x05: + snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4); + txt += 1; + len -= 1; + break; + case 0x10: + snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]); + txt += 3; + len -= 3; + break; + case 0x11: + ISO10646.copy(enc, ISO10646.length()); + enc[ISO10646.length()] = '\0'; + break; + case 0x1F: + // Values for the first byte of "0x00", "0x06" to "0x0F", and "0x12" to "0x1F" are reserved for future use. + //fprintf(stderr, "Reserved encoding: %02x\n", txt[0]); + //fprintf(stderr, "%d: %.*s\n", txt[1], len - 2, txt + 2); + case 0x06 ... 0x0F: + case 0x12 ... 0x1E: + case 0x00: // empty string + return boost::shared_ptr(new Glib::ustring()); + } + size_t used = 0, newlen = 0; + GError * err = NULL; + boost::shared_ptr utf8 = boost::shared_ptr(g_convert(txt, len, "utf-8", enc, &used, &newlen, &err), g_free); + if (err) { + throw Glib::ConvertError(err); + } + return boost::shared_ptr(new Glib::ustring(utf8.get())); +} + diff --git a/p2pvr/dvb/siParsers/table.h b/p2pvr/dvb/siParsers/table.h new file mode 100644 index 0000000..c470159 --- /dev/null +++ b/p2pvr/dvb/siParsers/table.h @@ -0,0 +1,212 @@ +#ifndef DVBSIREADERHELPER_H +#define DVBSIREADERHELPER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char u_char; + +#define HILO(x) (x##_hi << 8 | x##_lo) +#define HILO2(x) (x##1 << 8 | x##2) +#define HILO3(x) (x##1 << 16 | x##2 << 8 | x##3) +#define HILO4(x) (x##4 << 24 | x##2 << 16 | x##3 << 8 | x##4) +#define BcdCharToInt(x) (10*((x & 0xF0)>>4) + (x & 0xF)) + +class SiTableParserBase : public P2PVR::RawDataClient { + public: + const P2PVR::Data & CurrentRawData() const; + protected: + SiTableParserBase(); + virtual ~SiTableParserBase() = 0; + + typedef boost::shared_ptr StrPtr; + + bool NewData(const P2PVR::Data & bytes, const Ice::Current&); + + static StrPtr convert(const char * txt, size_t len); + + static const std::string ISO10646; + static const std::string EitEncoding; + static const std::string UTF8; + protected: + virtual bool ParseInfoTable(const u_char * data, size_t len) = 0; + time_t startTime; + unsigned int incomplete; + std::mutex lock; + private: + const P2PVR::Data * currentRawData; +}; + +struct SiTableHeaderBase { + uint8_t tableid; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char section_syntax_indicator :1; + u_char reserved2 :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char reserved2 :3; + u_char section_syntax_indicator :1; +#endif + uint8_t section_length_lo; +} __attribute__((packed)); + +struct SiTableHeader : public SiTableHeaderBase { + uint16_t content_id; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + u_char reserved1 :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char reserved1 :2; +#endif + uint8_t section_number; + uint8_t last_section_number; +} __attribute__((packed)); + +struct SiDescriptorHeader { + u_char tag; + u_char length; + u_char data[]; +} __attribute__((packed)); + +template +class SiTableParser : public SiTableParserBase { + protected: + typedef std::set Sections; // Section numbers + typedef boost::tuple TargetSections; // Last section number | Seen section numbers + typedef std::map TableTargetSections; // TableID -> Needed references + typedef boost::tuple ContentType; // TemplateData | Needed references + typedef std::map Contents; // ContentID -> data + + virtual int SectionNumberShift() const { return 0; } + virtual uint8_t LastTableId(const TableType * t) { return t->header.tableid; } + virtual uint8_t FirstTableId(const TableType * t) { return t->header.tableid; } + + bool ParseInfoTable(const u_char * data, size_t len) + { + const u_char * dataEnd = data + len; + while (data < dataEnd) { + auto siTable = reinterpret_cast(data); + if (siTable->header.current_next_indicator == 1 // current only, please. + && CheckTableId(siTable->header.tableid)) { // only tables we're interested in, please. + std::lock_guard g(lock); + uint16_t contentId = ntohs(siTable->header.content_id); + ContentType & content = contents[contentId]; + uint8_t sectionNumber = siTable->header.section_number >> SectionNumberShift(); + TableTargetSections & targetTableSections = boost::get<1>(content); + TargetSections & targetSections = targetTableSections[siTable->header.tableid]; + boost::get<0>(targetSections) = siTable->header.last_section_number >> SectionNumberShift(); + Sections & seen = boost::get<1>(targetSections); + if (seen.find(sectionNumber) == seen.end()) { + auto & obj = boost::get<0>(content); + if (!obj) { + obj = TargetType(new typename TargetType::element_type()); + incomplete += 1; + } + ParseSiTable(siTable, obj); + seen.insert(sectionNumber); + bool complete = true; + for (int tid = FirstTableId(siTable); tid <= LastTableId(siTable); tid += 1) { + TableTargetSections::const_iterator tts = targetTableSections.find(tid); + if (tts == targetTableSections.end()) { + complete = false; + break; + } + if (boost::get<1>(tts->second).size() <= boost::get<0>(tts->second)) { + complete = false; + break; + } + } + if (complete) { + if (HandleTable(obj)) { + targetTableSections.clear(); + } + else { + obj = TargetType(); + } + incomplete -= 1; + } + } + } + data += HILO(siTable->header.section_length) + 4; + } + return IsFinished(); + } + + virtual bool IsFinished() const + { + return ((incomplete == 0) && (startTime < (time(NULL) - 10))); + } + + static void ParseDescriptor(const SiDescriptorHeader * descriptor) + { + (void)descriptor; + // Logger()->messagef(LOG_DEBUG, "Dropped descriptor with tag 0x%02x", descriptor->tag); + return; + } + + template + static void ParseDescriptor(const SiDescriptorHeader * descriptor, u_char tag, boost::function parser, OtherParers ... otherParers) + { + if (tag == descriptor->tag) { + parser(descriptor->data, descriptor->length); + } + else { + ParseDescriptor(descriptor, otherParers...); + } + } + + template + static const NextData * ParseDescriptors(const u_char * data, size_t len, Parsers ... parsers) + { + auto end = data + len; + while (data < end) { + auto descriptor = reinterpret_cast(data); + ParseDescriptor(descriptor, parsers...); + data += descriptor->length + 2; + } + return reinterpret_cast(end); + } + + template + static void LoopOver(const u_char * data, size_t len, boost::function parser) + { + auto end = data + len; + while (data < end) { + auto loopData = reinterpret_cast(data); + parser(loopData); + data += HILO(loopData->descriptors_length) + (loopData->data - data); + } + } + + template + static void LoopOverSection(const u_char * data, size_t len, boost::function parser) + { + auto end = data + len; + while (data < end) { + auto loopData = reinterpret_cast(data); + parser(loopData); + data += sizeof(LoopContent); + } + } + + virtual bool CheckTableId(u_char tableId) const = 0; + virtual void ParseSiTable(const TableType *, TargetType) = 0; + virtual bool HandleTable(TargetType table) = 0; + + private: + mutable Contents contents; +}; + +#endif + diff --git a/p2pvr/ice/Jamfile.jam b/p2pvr/ice/Jamfile.jam index cc97614..8ece4f7 100644 --- a/p2pvr/ice/Jamfile.jam +++ b/p2pvr/ice/Jamfile.jam @@ -3,8 +3,7 @@ lib IceUtil ; lib pthread ; lib p2pvrice : - [ glob *.cpp ] - [ glob *.ice ] : + [ glob *.cpp *.ice ] : Ice IceUtil pthread diff --git a/p2pvr/lib/Jamfile.jam b/p2pvr/lib/Jamfile.jam index 1868a6a..a7ce426 100644 --- a/p2pvr/lib/Jamfile.jam +++ b/p2pvr/lib/Jamfile.jam @@ -5,23 +5,19 @@ cpp-pch pch : pch.hpp : boost_system boost_filesystem ..//p2common - ..//p2sql ..//p2lib - ..//p2daemonlib ../ice//p2pvrice ; lib p2pvrlib : pch [ glob-tree *.cpp ] - [ glob-tree *.sql ] : boost_system boost_filesystem ../ice//p2pvrice - ../util//p2pvrutil + ../dvb//p2pvrdvb ..//p2common - ..//p2sql ..//p2lib ../ice//p2pvrice : : diff --git a/p2pvr/lib/containerCreator.h b/p2pvr/lib/containerCreator.h new file mode 100644 index 0000000..9804d9b --- /dev/null +++ b/p2pvr/lib/containerCreator.h @@ -0,0 +1,33 @@ +#ifndef CONTAINERCREATOR_H +#define CONTAINERCREATOR_H + +#include +#include +#include "objectRowState.h" + +template > +class ContainerCreator { + public: + ContainerCreator(T & c) : container(c) { } + + void populate( + boost::function fetch, + boost::function get, + unsigned int columnCount) + { + while (fetch()) { + auto v = P(new V); + container.push_back(v); + ObjectRowState

rs; + for (unsigned int c = 0; c < columnCount; c++) { + rs.fields[c] = get(c); + } + UnbindColumns

(rs, v); + } + } + private: + T & container; +}; + +#endif + diff --git a/p2pvr/lib/containerIterator.h b/p2pvr/lib/containerIterator.h new file mode 100644 index 0000000..2b61055 --- /dev/null +++ b/p2pvr/lib/containerIterator.h @@ -0,0 +1,41 @@ +#ifndef CONTAINERITERATOR_H +#define CONTAINERITERATOR_H + +#include +#include +#include "objectRowState.h" + +template +class ContainerIterator : public IHaveSubTasks { + public: + ContainerIterator(const T * con) : + SourceObject(__PRETTY_FUNCTION__), + IHaveSubTasks(NULL), + binder(boost::bind(&BindColumns, _1, _2)), + container(con) + { + } + + void execute(ExecContext * ec) const + { + ObjectRowState rs; + BOOST_FOREACH(const auto & i, *container) { + binder(rs, i); + rs.process(boost::bind(&ContainerIterator::executeChildren, this, ec)); + } + } + + private: + boost::function binder; + const T * container; + + void executeChildren(ExecContext * ec) const + { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(ec); + } + } +}; + +#endif + diff --git a/p2pvr/lib/daemonBase.cpp b/p2pvr/lib/daemonBase.cpp deleted file mode 100644 index 4739498..0000000 --- a/p2pvr/lib/daemonBase.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include "daemonBase.h" -#include "p2LoggerWrapper.h" -#include -#include - -std::string DaemonBase::Adapter; -std::string DaemonBase::Endpoint; - -DECLARE_OPTIONS(DaemonBase, "P2PVR Daemon") -("p2pvr.daemon.iceadapter", Options::value(&Adapter, "DefaultAdapter"), "ICE Adapter name") -("p2pvr.daemon.iceendpoint", Options::value(&Endpoint, "default -p 10000"), "ICE Endpoint address") -END_OPTIONS(DaemonBase); - -DaemonBase::DaemonBase(int argc, char ** argv) : - ic(Ice::initialize(args(argc, argv), initData())) -{ -} - -DaemonBase::~DaemonBase() -{ - ic->destroy(); -} - -void -DaemonBase::run() const -{ - IceUtil::TimerPtr timer = new IceUtil::Timer(); - Logger()->messagebf(LOG_INFO, "Creating adapter (%s, %s)", Adapter, Endpoint); - auto adapter = ic->createObjectAdapterWithEndpoints(Adapter, Endpoint); - addServants(adapter, timer); - adapter->activate(); - - ic->waitForShutdown(); - timer->destroy(); -} - -void -DaemonBase::shutdown() const -{ - ic->shutdown(); - ic->waitForShutdown(); -} - -Ice::InitializationData -DaemonBase::initData() -{ - Ice::InitializationData data; - data.logger = new P2LoggerWrapper(); - return data; -} - -Ice::StringSeq & -DaemonBase::args(int, char **) -{ - _args.clear(); - _args.push_back("--Ice.ThreadPool.Client.Size=5"); - _args.push_back("--Ice.ThreadPool.Server.Size=5"); - _args.push_back("--Ice.ThreadPool.Client.SizeMax=10"); - _args.push_back("--Ice.ThreadPool.Server.SizeMax=20"); - _args.push_back("--Ice.ThreadPool.Client.SizeWarn=8"); - _args.push_back("--Ice.ThreadPool.Server.SizeWarn=16"); - return _args; -} diff --git a/p2pvr/lib/daemonBase.h b/p2pvr/lib/daemonBase.h deleted file mode 100644 index 3cf9b19..0000000 --- a/p2pvr/lib/daemonBase.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DAEMONBASE_H -#define DAEMONBASE_H - -#include -#include -#include -#include - -class DaemonBase : public Daemon { - public: - DaemonBase(int argc, char ** argv); - ~DaemonBase(); - - void run() const; - void shutdown() const; - INITOPTIONS; - - protected: - virtual void addServants(const Ice::ObjectAdapterPtr &, const IceUtil::TimerPtr &) const = 0; - static Ice::InitializationData initData(); - Ice::StringSeq & args(int, char **); - - Ice::StringSeq _args; - Ice::CommunicatorPtr ic; - - static std::string Adapter; - static std::string Endpoint; -}; - -#endif - diff --git a/p2pvr/lib/dbClient.cpp b/p2pvr/lib/dbClient.cpp deleted file mode 100644 index 8267584..0000000 --- a/p2pvr/lib/dbClient.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include "dbClient.h" -#include - -void -DatabaseClient::SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key) -{ - merge->cols.insert(new SqlMergeTask::TargetColumn(name, key)); - if (key) { - merge->keys.insert(name); - } -} - -void -DatabaseClient::onAllDatasources(const DataSourceCall & call) const -{ - BOOST_FOREACH(const CommonObjects::DataSources::value_type & ds, CommonObjects::datasources) { - call(ds.second); - } -} - -DatabaseClient::TxHelper::TxHelper(const DatabaseClient * dbc) : - client(dbc), - so(NULL, - boost::bind(&DatabaseClient::onAllDatasources, dbc, DataSourceCall(boost::bind(&DataSource::commit, _1))), - boost::bind(&DatabaseClient::onAllDatasources, dbc, DataSourceCall(boost::bind(&DataSource::rollback, _1)))) -{ -} - -void -DatabaseClient::TxHelper::Commit() const -{ - client->onAllDatasources(boost::bind(&DataSource::commit, _1)); -} - -DatabaseClient::NoRowsFoundException::NoRowsFoundException() : - std::runtime_error("No rows found") -{ -} - -VariableType -operator/(const DatabaseClient::SelectPtr & cmd, unsigned int col) -{ - HandleAsVariableType vt; - (*cmd)[col].apply(vt); - return vt.variable; -} - -VariableType -operator/(const DatabaseClient::SelectPtr & cmd, const std::string & col) -{ - HandleAsVariableType vt; - (*cmd)[col].apply(vt); - return vt.variable; -} - diff --git a/p2pvr/lib/dbClient.h b/p2pvr/lib/dbClient.h deleted file mode 100644 index 84cf5e7..0000000 --- a/p2pvr/lib/dbClient.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef DBCLIENT_H -#define DBCLIENT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "p2Helpers.h" - -class SqlMergeTask; - -class DatabaseClient : public virtual CommonObjects { - public: - typedef boost::shared_ptr SelectPtr; - typedef boost::shared_ptr ModifyPtr; - - static void SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key); - - class TxHelper { - public: - TxHelper(const DatabaseClient *); - void Commit() const; - - private: - const DatabaseClient * client; - ScopeObject so; - }; - - template - std::pair Modify(const std::string & sql, const Args & ... args) const - { - auto db = dataSource("postgres")->getWritable(); - auto cmd = ModifyPtr(db->newModifyCommand(sql)); - Bind(cmd.get(), 0, args...); - return {db, cmd}; - } - - template - std::pair Select(const std::string & sql, const Args & ... args) const - { - auto db = dataSource("postgres")->getReadonly(); - auto cmd = SelectPtr(db->newSelectCommand(sql)); - Bind(cmd.get(), 0, args...); - return {db, cmd}; - } - - class NoRowsFoundException : public std::runtime_error { - public: - NoRowsFoundException(); - }; - - template - Rtn SelectScalar(const std::string & sql, const Args & ... args) const - { - auto db = dataSource("postgres"); - auto cmd = SelectPtr(db->getReadonly()->newSelectCommand(sql)); - Bind(cmd.get(), 0, args...); - while (cmd->fetch()) { - HandleAsVariableType h; - (*cmd)[0].apply(h); - Rtn r; - h.variable >> r; - return r; - } - throw NoRowsFoundException(); - } - - private: - static void Bind(DB::Command *, unsigned int) { } - - template - static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg) - { - VariableType v; - v << arg; - boost::apply_visitor(SqlVariableBinder(cmd, offset), v); - } - - template - static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg, const Args & ... args) - { - Bind(cmd, offset, arg); - Bind(cmd, offset + 1, args...); - } - - friend class TxHelper; - typedef boost::function DataSourceCall; - void onAllDatasources(const DataSourceCall &) const; -}; - -VariableType -operator/(const DatabaseClient::SelectPtr & cmd, unsigned int col); - -VariableType -operator/(const DatabaseClient::SelectPtr & cmd, const std::string & col); - -#endif - diff --git a/p2pvr/lib/dvbsiHelpers.h b/p2pvr/lib/dvbsiHelpers.h new file mode 100644 index 0000000..137bf98 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers.h @@ -0,0 +1,23 @@ +#ifndef ICE_DVBSI_HELPERS_H +#define ICE_DVBSI_HELPERS_H + +#include +#include "objectRowState.h" + +#define ColumnHelper(T) \ + template<> void CreateColumns(const ColumnCreator & cc); \ + template<> void BindColumns(RowState & rs, const T & obj); \ + template<> void UnbindColumns(RowState & rs, const T & s) + +ColumnHelper(DVBSI::NetworkPtr); +ColumnHelper(DVBSI::NetworkTransportStreamPtr); +ColumnHelper(DVBSI::NetworkService); +ColumnHelper(DVBSI::TerrestrialDeliveryPtr); +ColumnHelper(DVBSI::CableDeliveryPtr); +ColumnHelper(DVBSI::SatelliteDeliveryPtr); +ColumnHelper(DVBSI::ServicePtr); +ColumnHelper(DVBSI::StreamPtr); +ColumnHelper(DVBSI::EventPtr); + +#endif + diff --git a/p2pvr/lib/dvbsiHelpers/cableDelivery.cpp b/p2pvr/lib/dvbsiHelpers/cableDelivery.cpp new file mode 100644 index 0000000..7bf9f6d --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/cableDelivery.cpp @@ -0,0 +1,39 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("frequency", false); + cc("transportStreamId", true); + cc("fecOuter", false); + cc("modulation", false); + cc("symbolRate", false); + cc("fecInner", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::CableDeliveryPtr & s) +{ + rs.fields[0] << s->Frequency; + rs.fields[1] << s->TransportStreamId; + rs.fields[2] << s->FecOuter; + rs.fields[3] << s->Modulation; + rs.fields[4] << s->SymbolRate; + rs.fields[5] << s->FecInner; +} +template<> +void +UnbindColumns(RowState & rs, DVBSI::CableDeliveryPtr const & s) +{ + rs.fields[0] >> s->Frequency; + rs.fields[1] >> s->TransportStreamId; + rs.fields[2] >> s->FecOuter; + rs.fields[3] >> s->Modulation; + rs.fields[4] >> s->SymbolRate; + rs.fields[5] >> s->FecInner; +} + diff --git a/p2pvr/lib/dvbsiHelpers/event.cpp b/p2pvr/lib/dvbsiHelpers/event.cpp new file mode 100644 index 0000000..ca072df --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/event.cpp @@ -0,0 +1,94 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceId", true); + cc("eventId", true); + cc("title", false); + cc("titleLang", false); + cc("subtitle", false); + cc("description", false); + cc("descriptionLang", false); + cc("videoAspect", false); + cc("videoFrameRate", false); + cc("videoHd", false); + cc("audioChannels", false); + cc("audioLanguage", false); + cc("subtitleLanguage", false); + cc("category", false); + cc("subCategory", false); + cc("userCategory", false); + cc("dvbRating", false); + cc("startTime", false); + cc("stopTime", false); + cc("episode", false); + cc("episodes", false); + cc("year", false); + cc("flags", false); + cc("season", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::EventPtr & e) +{ + rs.fields[0] << e->ServiceId; + rs.fields[1] << e->EventId; + rs.fields[2] << e->Title; + rs.fields[3] << e->TitleLang; + rs.fields[4] << e->Subtitle; + rs.fields[5] << e->Description; + rs.fields[6] << e->DescriptionLang; + rs.fields[7] << e->VideoAspect; + rs.fields[8] << e->VideoFrameRate; + rs.fields[9] << e->VideoHD; + rs.fields[10] << e->AudioChannels; + rs.fields[11] << e->AudioLanguage; + rs.fields[12] << e->SubtitleLanguage; + rs.fields[13] << e->Category; + rs.fields[14] << e->SubCategory; + rs.fields[15] << e->UserCategory; + rs.fields[16] << e->DvbRating; + rs.fields[17] << e->StartTime; + rs.fields[18] << e->StopTime; + rs.fields[19] << e->Episode; + rs.fields[20] << e->Episodes; + rs.fields[21] << e->Year; + rs.fields[22] << e->Flags; + rs.fields[23] << e->Season; +} + +template<> +void +UnbindColumns(RowState & rs, const DVBSI::EventPtr & e) +{ + rs.fields[0] >> e->ServiceId; + rs.fields[1] >> e->EventId; + rs.fields[2] >> e->Title; + rs.fields[3] >> e->TitleLang; + rs.fields[4] >> e->Subtitle; + rs.fields[5] >> e->Description; + rs.fields[6] >> e->DescriptionLang; + rs.fields[7] >> e->VideoAspect; + rs.fields[8] >> e->VideoFrameRate; + rs.fields[9] >> e->VideoHD; + rs.fields[10] >> e->AudioChannels; + rs.fields[11] >> e->AudioLanguage; + rs.fields[12] >> e->SubtitleLanguage; + rs.fields[13] >> e->Category; + rs.fields[14] >> e->SubCategory; + rs.fields[15] >> e->UserCategory; + rs.fields[16] >> e->DvbRating; + rs.fields[17] >> e->StartTime; + rs.fields[18] >> e->StopTime; + rs.fields[19] >> e->Episode; + rs.fields[20] >> e->Episodes; + rs.fields[21] >> e->Year; + rs.fields[22] >> e->Flags; + rs.fields[23] >> e->Season; +} + diff --git a/p2pvr/lib/dvbsiHelpers/network.cpp b/p2pvr/lib/dvbsiHelpers/network.cpp new file mode 100644 index 0000000..3b117f1 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/network.cpp @@ -0,0 +1,21 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("networkId", true); + cc("name", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::NetworkPtr & network) +{ + rs.fields[0] << network->NetworkId; + rs.fields[1] << network->Name; +} + + diff --git a/p2pvr/lib/dvbsiHelpers/networkService.cpp b/p2pvr/lib/dvbsiHelpers/networkService.cpp new file mode 100644 index 0000000..a4a47d5 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/networkService.cpp @@ -0,0 +1,22 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceId", true); + cc("type", false); + cc("transportStreamId", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::NetworkService & s) +{ + rs.fields[0] << s.ServiceId; + rs.fields[1] << s.ServiceType; + rs.fields[2] << s.TransportStreamId; +} + diff --git a/p2pvr/lib/dvbsiHelpers/networkTransportStream.cpp b/p2pvr/lib/dvbsiHelpers/networkTransportStream.cpp new file mode 100644 index 0000000..bdc7c4f --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/networkTransportStream.cpp @@ -0,0 +1,23 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("transportStreamId", true); + cc("networkId", false); + cc("originalNetworkId", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::NetworkTransportStreamPtr & ts) +{ + rs.fields[0] << ts->TransportStreamId; + rs.fields[1] << ts->NetworkId; + rs.fields[2] << ts->OriginalNetworkId; +} + + diff --git a/p2pvr/lib/dvbsiHelpers/programMap.cpp b/p2pvr/lib/dvbsiHelpers/programMap.cpp new file mode 100644 index 0000000..d8cf400 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/programMap.cpp @@ -0,0 +1,24 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceId", true); + cc("id", true); + cc("type", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::StreamPtr & stream) +{ + rs.fields[0] << stream->ServiceId; + rs.fields[1] << stream->Id; + rs.fields[2] << stream->Type; +} + + + diff --git a/p2pvr/lib/dvbsiHelpers/satelliteDelivery.cpp b/p2pvr/lib/dvbsiHelpers/satelliteDelivery.cpp new file mode 100644 index 0000000..8231fc3 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/satelliteDelivery.cpp @@ -0,0 +1,51 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("frequency", false); + cc("transportStreamId", true); + cc("orbitalPosition", false); + cc("westEastFlag", false); + cc("polarization", false); + cc("rollOff", false); + cc("modulationSystem", false); + cc("modulationType", false); + cc("symbolRate", false); + cc("fecInner", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::SatelliteDeliveryPtr & s) +{ + rs.fields[0] << s->Frequency; + rs.fields[1] << s->TransportStreamId; + rs.fields[2] << s->OrbitalPosition; + rs.fields[3] << s->WestEastFlag; + rs.fields[4] << s->Polarization; + rs.fields[5] << s->RollOff; + rs.fields[6] << s->ModulationSystem; + rs.fields[7] << s->ModulationType; + rs.fields[8] << s->SymbolRate; + rs.fields[9] << s->FecInner; +} +template<> +void +UnbindColumns(RowState & rs, DVBSI::SatelliteDeliveryPtr const & s) +{ + rs.fields[0] >> s->Frequency; + rs.fields[1] << s->TransportStreamId; + rs.fields[2] >> s->OrbitalPosition; + rs.fields[3] >> s->WestEastFlag; + rs.fields[4] >> s->Polarization; + rs.fields[5] >> s->RollOff; + rs.fields[6] >> s->ModulationSystem; + rs.fields[7] >> s->ModulationType; + rs.fields[8] >> s->SymbolRate; + rs.fields[9] >> s->FecInner; +} + diff --git a/p2pvr/lib/dvbsiHelpers/service.cpp b/p2pvr/lib/dvbsiHelpers/service.cpp new file mode 100644 index 0000000..9f82d91 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/service.cpp @@ -0,0 +1,49 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("serviceId", true); + cc("transportStreamId", true); + cc("name", false); + cc("providerName", false); + cc("defaultAuthority", false); + cc("runningStatus", false); + cc("eitSchedule", false); + cc("eitPresentFollowing", false); + cc("freeCAMode", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::ServicePtr & s) +{ + rs.fields[0] << s->ServiceId; + rs.fields[1] << s->TransportStreamId; + rs.fields[2] << s->Name; + rs.fields[3] << s->ProviderName; + rs.fields[4] << s->DefaultAuthority; + rs.fields[5] << s->RunningStatus; + rs.fields[6] << s->EitSchedule; + rs.fields[7] << s->EitPresentFollowing; + rs.fields[8] << s->FreeCaMode; +} + +template<> +void +UnbindColumns(RowState & rs, DVBSI::ServicePtr const & s) +{ + rs.fields[0] >> s->ServiceId; + rs.fields[1] >> s->TransportStreamId; + rs.fields[2] >> s->Name; + rs.fields[3] >> s->ProviderName; + rs.fields[4] >> s->DefaultAuthority; + rs.fields[5] >> s->RunningStatus; + rs.fields[6] >> s->EitSchedule; + rs.fields[7] >> s->EitPresentFollowing; + rs.fields[8] >> s->FreeCaMode; +} + diff --git a/p2pvr/lib/dvbsiHelpers/terrestrialDelivery.cpp b/p2pvr/lib/dvbsiHelpers/terrestrialDelivery.cpp new file mode 100644 index 0000000..46e60f9 --- /dev/null +++ b/p2pvr/lib/dvbsiHelpers/terrestrialDelivery.cpp @@ -0,0 +1,59 @@ +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("frequency", false); + cc("transportStreamId", true); + cc("bandwidth", false); + cc("priority", false); + cc("timeSlicing", false); + cc("mpeFec", false); + cc("constellation", false); + cc("hierarchy", false); + cc("codeRateHP", false); + cc("codeRateLP", false); + cc("guardInterval", false); + cc("transmissionMode", false); + cc("otherFrequencyFlag", false); +} + +template<> +void +BindColumns(RowState & rs, const DVBSI::TerrestrialDeliveryPtr & s) +{ + rs.fields[0] << s->Frequency; + rs.fields[1] << s->TransportStreamId; + rs.fields[2] << s->Bandwidth; + rs.fields[3] << s->Priority; + rs.fields[4] << s->TimeSlicing; + rs.fields[5] << s->MpeFec; + rs.fields[6] << s->Constellation; + rs.fields[7] << s->Hierarchy; + rs.fields[8] << s->CodeRateHP; + rs.fields[9] << s->CodeRateLP; + rs.fields[10] << s->GuardInterval; + rs.fields[11] << s->TransmissionMode; + rs.fields[12] << s->OtherFrequencyFlag; +} +template<> +void +UnbindColumns(RowState & rs, DVBSI::TerrestrialDeliveryPtr const & s) +{ + rs.fields[0] >> s->Frequency; + rs.fields[2] >> s->Bandwidth; + rs.fields[3] >> s->Priority; + rs.fields[4] >> s->TimeSlicing; + rs.fields[5] >> s->MpeFec; + rs.fields[6] >> s->Constellation; + rs.fields[7] >> s->Hierarchy; + rs.fields[8] >> s->CodeRateHP; + rs.fields[9] >> s->CodeRateLP; + rs.fields[10] >> s->GuardInterval; + rs.fields[11] >> s->TransmissionMode; + rs.fields[12] >> s->OtherFrequencyFlag; +} + diff --git a/p2pvr/lib/fileHandle.cpp b/p2pvr/lib/fileHandle.cpp new file mode 100644 index 0000000..b85d390 --- /dev/null +++ b/p2pvr/lib/fileHandle.cpp @@ -0,0 +1,28 @@ +#include +#include "fileHandle.h" +#include +#include + +class InvalidFileHandle : public std::runtime_error { + public: + InvalidFileHandle() : std::runtime_error("Invalid file handle") { } +}; + +FileHandle::FileHandle(int f) : + fd(f) +{ + if (fd < 0) { + throw InvalidFileHandle(); + } +} + +FileHandle::~FileHandle() +{ + close(fd); +} + +FileHandle::operator int() const +{ + return fd; +} + diff --git a/p2pvr/lib/fileHandle.h b/p2pvr/lib/fileHandle.h new file mode 100644 index 0000000..3c8d45e --- /dev/null +++ b/p2pvr/lib/fileHandle.h @@ -0,0 +1,19 @@ +#ifndef FILEHANDLE_H +#define FILEHANDLE_H + +class FileHandle { + public: + FileHandle(int fd); + ~FileHandle(); + + FileHandle(const FileHandle &) = delete; + void operator=(const FileHandle &) = delete; + + operator int() const; + + private: + const int fd; +}; + +#endif + diff --git a/p2pvr/lib/frontend.cpp b/p2pvr/lib/frontend.cpp deleted file mode 100644 index 54870a1..0000000 --- a/p2pvr/lib/frontend.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include "frontend.h" -#include "tuner.h" -#include -#include -#include -#include - -Frontend::Frontend(Tuner * t, int fd, const struct dvb_frontend_info & i) : - tuner(t), - frontendFD(fd), - fe_info(i) -{ -} - -Frontend::~Frontend() -{ - close(frontendFD); -} - -const struct dvb_frontend_info & -Frontend::Info() const -{ - return fe_info; -} - -fe_status -Frontend::GetStatus() const -{ - fe_status_t status; - if (ioctl(frontendFD, FE_READ_STATUS, &status) < 0) { - Logger()->messagebf(LOG_ERR, "Reading frontend %s status failed (%s:%d)", tuner->Device(), strerror(errno), errno); - throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); - } - return status; -} - -INSTANTIATESTORE(fe_type, FrontendLoader); - diff --git a/p2pvr/lib/frontend.h b/p2pvr/lib/frontend.h deleted file mode 100644 index d33353d..0000000 --- a/p2pvr/lib/frontend.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef P2PVR_FRONTEND_H -#define P2PVR_FRONTEND_H - -#include -#include -#include - -class Tuner; - -class Frontend { - public: - typedef boost::function OnFrequencyFound; - Frontend(Tuner *, int fd, const struct dvb_frontend_info &); - virtual ~Frontend(); - - fe_status_t GetStatus() const; - virtual void TuneTo(const DVBSI::DeliveryPtr &) const = 0; - virtual void FrequencyScan(const OnFrequencyFound & off) const = 0; - virtual std::string Type() const = 0; - const struct dvb_frontend_info & Info() const; - - protected: - const Tuner * tuner; - const int frontendFD; - const struct dvb_frontend_info fe_info; -}; - -typedef GenLoader FrontendLoader; -typedef boost::shared_ptr FrontendPtr; - -#endif - diff --git a/p2pvr/lib/frontends/ofdm.cpp b/p2pvr/lib/frontends/ofdm.cpp deleted file mode 100644 index 93e0d86..0000000 --- a/p2pvr/lib/frontends/ofdm.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include "../frontend.h" -#include "../tuner.h" -#include -#include -#include - -#define FREQ_OFFSET_MIN 0 -#define FREQ_OFFSET_MAX 4 - -class Frontend_OFDM : public Frontend { - public: - Frontend_OFDM(Tuner * t, int fd, const struct dvb_frontend_info & i) : Frontend(t, fd, i) { } - - void TuneTo(const DVBSI::DeliveryPtr & mp) const - { - auto td = DVBSI::TerrestrialDeliveryPtr::dynamicCast(mp); - if (!td) { - throw P2PVR::IncorrectDeliveryType(); - } - dvb_frontend_parameters feparams; - memset(&feparams, 0, sizeof(dvb_frontend_parameters)); - feparams.frequency = td->Frequency; - feparams.inversion = INVERSION_OFF; - feparams.u.ofdm.bandwidth = (fe_bandwidth)td->Bandwidth; - feparams.u.ofdm.code_rate_HP = (fe_code_rate_t)td->CodeRateHP; - feparams.u.ofdm.code_rate_LP = (fe_code_rate_t)td->CodeRateLP; - feparams.u.ofdm.constellation = (fe_modulation_t)td->Constellation; - feparams.u.ofdm.transmission_mode = (fe_transmit_mode)td->TransmissionMode; - feparams.u.ofdm.guard_interval = (fe_guard_interval_t)td->GuardInterval; - feparams.u.ofdm.hierarchy_information = (fe_hierarchy_t)td->Hierarchy; - SetParameters(feparams); - WaitForLock(); - } - - dvb_frontend_parameters GetParameters() const - { - dvb_frontend_parameters feparams; - memset(&feparams, 0, sizeof(dvb_frontend_parameters)); - if (ioctl(frontendFD, FE_GET_FRONTEND, &feparams) < 0) { - Logger()->messagebf(LOG_ERR, "Reading frontend parameters failed (%s:%d)", tuner->Device(), strerror(errno), errno); - throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); - } - return feparams; - } - - void WaitForLock() const - { - fe_status_t status = (fe_status_t)0; - // Wait for something - for (int x = Tuner::TuningTimeout / 10; x > 0 && (status = GetStatus()) == 0; x -= 1) { - usleep(10000); - } - // Was it useful? - if (!(status & (FE_HAS_SIGNAL | FE_HAS_CARRIER))) { - Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (No signal or carrier: 0x%02x)", tuner->Device(), status); - throw P2PVR::DeviceError(tuner->Device(), "No carrier", 0); - } - // Wait for lock - for (int x = Tuner::LockTimeout / 10; x > 0 && ((status = GetStatus()) & FE_HAS_LOCK) == 0; x -= 1) { - usleep(10000); - } - if (!(status & FE_HAS_LOCK)) { - Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s)", tuner->Device(), "No lock"); - throw P2PVR::DeviceError(tuner->Device(), "No lock", 0); - } - } - - void SetParameters(const dvb_frontend_parameters & feparams) const - { - if (ioctl(frontendFD, FE_SET_FRONTEND, &feparams) < 0) { - Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s:%d)", tuner->Device(), strerror(errno), errno); - throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno); - } - } - - std::string Type() const - { - return "OFDM (DVB-T)"; - } - - enum Country { DVBT_AU, DVBT_DE, DVBT_FR, DVBT_GB }; - - static uint32_t FrequencyForCountry(Country country, int channel) - { - switch (country) { - case DVBT_AU: //AUSTRALIA, 7MHz step list - switch (channel) { - case 5 ... 12: return 142500000; - case 21 ... 69: return 333500000; - } - case DVBT_DE: //GERMANY - case DVBT_FR: //FRANCE, +/- offset 166kHz & +offset 332kHz & +offset 498kHz - case DVBT_GB: //UNITED KINGDOM, +/- offset - switch (channel) { - case 5 ... 12: return 142500000; // VHF unused in FRANCE, skip those in offset loop - case 21 ... 69: return 306000000; - } - } - return 0; - } - static uint32_t FrequencyStepForCountry(Country country, int channel) - { - switch (country) { - case DVBT_AU: - return 7000000; // dvb-t australia, 7MHz step - case DVBT_DE: - case DVBT_FR: - case DVBT_GB: - switch (channel) { // dvb-t europe, 7MHz VHF ch5..12, all other 8MHz - case 5 ... 12: return 7000000; - case 21 ... 69: return 8000000; - } - } - return 0; - } - static uint32_t ChannelFrequencyForCountry(Country country, int channel, int) - { - return FrequencyForCountry(country, channel) + (channel * FrequencyStepForCountry(country, channel)); - } - - void FrequencyScan(const OnFrequencyFound & onFrequencyFound) const - { - struct dvb_frontend_parameters feparams; - memset(&feparams, 0, sizeof(dvb_frontend_parameters)); - feparams.inversion = (fe_info.caps & FE_CAN_INVERSION_AUTO ? INVERSION_AUTO : INVERSION_OFF); - feparams.u.ofdm.constellation = (fe_info.caps & FE_CAN_QAM_AUTO ? QAM_AUTO : QAM_64); - feparams.u.ofdm.hierarchy_information = HIERARCHY_NONE; - - for (int channel = 0; channel < 134; channel += 1) { - for (uint32_t offset = FREQ_OFFSET_MIN; offset <= 0/*FREQ_OFFSET_MAX*/; offset += 1) { - feparams.frequency = ChannelFrequencyForCountry(DVBT_GB, channel, offset); - if (feparams.frequency == 0) { - continue; - } - if (fe_info.frequency_min > feparams.frequency || fe_info.frequency_max < feparams.frequency) { - Logger()->messagebf(LOG_WARNING, "Channel %d, freq (%d Hz) outside card range", channel, feparams.frequency); - continue; - } - try { - Logger()->messagebf(LOG_DEBUG, "Channel %d, Frequency %d Hz", channel, feparams.frequency); - SetParameters(feparams); - WaitForLock(); - Logger()->messagebf(LOG_INFO, "Found multiplex at %d Hz", feparams.frequency); - Logger()->messagebf(LOG_DEBUG, "frequency %d", feparams.frequency); - if (onFrequencyFound(feparams.frequency)) { - return; - } - } - catch (const P2PVR::DeviceError &) { - // Moving on... - } - } - } - } -}; - -DECLARE_GENERIC_LOADER(FE_OFDM, FrontendLoader, Frontend_OFDM); - diff --git a/p2pvr/lib/globalDevices.cpp b/p2pvr/lib/globalDevices.cpp deleted file mode 100644 index 4368cea..0000000 --- a/p2pvr/lib/globalDevices.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include "globalDevices.h" -#include - -std::vector GlobalDevices::Devices; - -DECLARE_OPTIONS(GlobalDevices, "P2PVR Devices") -("p2pvr.globaldevices.carddaemon", - Options::functions( - [](const VariableType & df) { Devices.push_back(df); }, - []{ Devices.clear(); }), - "ICE address of remote device pools (:)") -END_OPTIONS(GlobalDevices); - -P2PVR::TunerPrx -GlobalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - BOOST_FOREACH(const auto & pool, Devices) { - try { - auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); - return poolprx->GetTunerSpecific(delivery); - } - catch (...) { - } - } - throw P2PVR::NoSuitableDeviceAvailable(); -} - -P2PVR::TunerPrx -GlobalDevices::GetTunerAny(short type, const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - BOOST_FOREACH(const auto & pool, Devices) { - try { - auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); - return poolprx->GetTunerAny(type, delivery); - } - catch (...) { - } - } - throw P2PVR::NoSuitableDeviceAvailable(); -} - -P2PVR::PrivateTunerPrx -GlobalDevices::GetPrivateTuner(short type, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - BOOST_FOREACH(const auto & pool, Devices) { - try { - auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); - return poolprx->GetPrivateTuner(type); - } - catch (...) { - } - } - throw P2PVR::NoSuitableDeviceAvailable(); -} - -void -GlobalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - BOOST_FOREACH(const auto & pool, Devices) { - auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); - poolprx->ReleaseTuner(tuner); - } -} - -int -GlobalDevices::TunerCount(const Ice::Current & ice) -{ - int total = 0; - auto ic = ice.adapter->getCommunicator(); - BOOST_FOREACH(const auto & pool, Devices) { - try { - auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool)); - total += poolprx->TunerCount(); - } - catch (...) { - // Not available, don't count 'em - } - } - return total; -} - diff --git a/p2pvr/lib/globalDevices.h b/p2pvr/lib/globalDevices.h deleted file mode 100644 index da27c95..0000000 --- a/p2pvr/lib/globalDevices.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef GLOBALDEVICES_H -#define GLOBALDEVICES_H - -// Global devices implements a device collection (P2PVR::Devices) for any devices known -// throughout the system through other Devices interfaces - -#include -#include - -class GlobalDevices : public P2PVR::Devices { - public: - P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, const Ice::Current &); - P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, const Ice::Current &); - P2PVR::PrivateTunerPrx GetPrivateTuner(short type, const Ice::Current &); - void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &); - int TunerCount(const Ice::Current &); - - INITOPTIONS; - private: - static std::vector Devices; -}; - -#endif - - diff --git a/p2pvr/lib/localDevices.cpp b/p2pvr/lib/localDevices.cpp deleted file mode 100644 index 7a43a15..0000000 --- a/p2pvr/lib/localDevices.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include "localDevices.h" -#include -#include "tuner.h" -#include "bindTimerTask.h" -#include - -LocalDevices::Devices LocalDevices::devices; -std::mutex LocalDevices::lock; - -DECLARE_OPTIONS(LocalDevices, "P2PVR Devices") -("p2pvr.localdevices.frontend", - Options::functions( - [](const VariableType & df) { devices.insert(Devices::value_type(df.as(), OpenTunerPtr())); }, - []{ devices.clear(); }), - "Frontend of DVB devices to use (/dev/dvb/adapterX/frontendY)") -END_OPTIONS(LocalDevices); - -LocalDevices::LocalDevices(Ice::ObjectAdapterPtr adapter, IceUtil::TimerPtr t) : - timer(t), - clientCheck(new BindTimerTask(boost::bind(&LocalDevices::ClientCheck, this, adapter))) -{ - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - timer->scheduleRepeated(clientCheck, IceUtil::Time::seconds(30)); -} - -LocalDevices::~LocalDevices() -{ - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - timer->cancel(clientCheck); -} - -void -LocalDevices::ClientCheck(Ice::ObjectAdapterPtr adapter) -{ - std::lock_guard g(lock); - BOOST_FOREACH(auto & device, devices) { - if (device.second && device.second->tuner->GetLastUsedTime() < time(NULL) - 30) { - Logger()->messagebf(LOG_DEBUG, "%s: Device %s no longer in use", __PRETTY_FUNCTION__, device.first); - auto id = device.second->tuner->ice_getIdentity(); - if (adapter->find(id)) { - adapter->remove(id); - } - device.second.reset(); - } - } -} - -P2PVR::TunerPrx -LocalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) -{ - std::lock_guard g(lock); - Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner (frequency %d)", __PRETTY_FUNCTION__, delivery->Frequency); - auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) { - return ot.second && !ot.second->openedPrivate && ot.second->delivery && ot.second->delivery->Frequency == delivery->Frequency; - }); - if (openTuner != devices.end()) { - openTuner->second->clients += 1; - return openTuner->second->tuner; - } - - openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); - if (openTuner == devices.end()) { - Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)", - __PRETTY_FUNCTION__, delivery->Frequency); - throw P2PVR::NoSuitableDeviceAvailable(); - } - - Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)", - __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); - P2PVR::PrivateTunerPtr t = new Tuner(openTuner->first); - t->TuneTo(delivery, ice); - auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(t)); - openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, false)); - - Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)", - __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); - return tuner; -} - -P2PVR::TunerPrx -LocalDevices::GetTunerAny(short , const DVBSI::DeliveryPtr & delivery, const Ice::Current & ice) -{ - std::lock_guard g(lock); - Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner any frequency", __PRETTY_FUNCTION__); - auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) { - return ot.second && !ot.second->openedPrivate && ot.second->delivery; - }); - if (openTuner != devices.end()) { - openTuner->second->clients += 1; - return openTuner->second->tuner; - } - - openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); - if (openTuner == devices.end()) { - Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)", - __PRETTY_FUNCTION__, delivery->Frequency); - throw P2PVR::NoSuitableDeviceAvailable(); - } - - Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)", - __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); - P2PVR::PrivateTunerPtr t = new Tuner(openTuner->first); - t->TuneTo(delivery, ice); - auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(t)); - openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, false)); - - Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)", - __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first); - return tuner; -} - -P2PVR::PrivateTunerPrx -LocalDevices::GetPrivateTuner(short , const Ice::Current & ice) -{ - std::lock_guard g(lock); - Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner", __PRETTY_FUNCTION__); - auto openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; }); - if (openTuner == devices.end()) { - Logger()->messagebf(LOG_DEBUG, "%s: None free", __PRETTY_FUNCTION__); - throw P2PVR::NoSuitableDeviceAvailable(); - } - - Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner (frontend %s)", - __PRETTY_FUNCTION__, openTuner->first); - auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new Tuner(openTuner->first))); - openTuner->second = OpenTunerPtr(new OpenTuner(NULL, tuner, true)); - - return tuner; -} - -void -LocalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice) -{ - std::lock_guard g(lock); - Logger()->messagebf(LOG_DEBUG, "%s", __PRETTY_FUNCTION__); - auto openTuner = std::find_if(devices.begin(), devices.end(), [tuner](const Devices::value_type & ot) { - return ot.second && ot.second->tuner == tuner; - }); - if (openTuner == devices.end()) { - Logger()->messagebf(LOG_DEBUG, "%s: Not one of mine", __PRETTY_FUNCTION__); - return; - } - Logger()->messagebf(LOG_DEBUG, "%s: Locally owned deivce %s", __PRETTY_FUNCTION__, openTuner->first); - openTuner->second->clients -= 1; - if (openTuner->second->clients == 0) { - auto id = tuner->ice_getIdentity(); - if (ice.adapter->find(id)) { - ice.adapter->remove(id); - } - openTuner->second.reset(); - } -} - -int -LocalDevices::TunerCount(const Ice::Current &) -{ - std::lock_guard g(lock); - return devices.size(); -} - -void -LocalDevices::Scan(const Ice::Current &) -{ - std::lock_guard g(lock); -} - -void -LocalDevices::Add(const std::string & frontend, const Ice::Current &) -{ - std::lock_guard g(lock); - devices.insert(Devices::value_type(frontend, OpenTunerPtr())); -} - -void -LocalDevices::Remove(const std::string & frontend, const Ice::Current &) -{ - std::lock_guard g(lock); - devices.erase(frontend); -} - -LocalDevices::OpenTuner::OpenTuner(DVBSI::DeliveryPtr d, P2PVR::PrivateTunerPrx t, bool op) : - openedPrivate(op), - delivery(d), - tuner(t), - clients(1) -{ -} - diff --git a/p2pvr/lib/localDevices.h b/p2pvr/lib/localDevices.h deleted file mode 100644 index 5521f8d..0000000 --- a/p2pvr/lib/localDevices.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef LOCALDEVICES_H -#define LOCALDEVICES_H - -// Local devices implements a device collection (P2PVR::Devices) for any devices physically -// attached to the local machine; that is, can be accessed directly through /dev/dvb/adapterX - -#include -#include -#include - -class LocalDevices : public P2PVR::LocalDevices { - public: - LocalDevices(Ice::ObjectAdapterPtr adapter, IceUtil::TimerPtr); - ~LocalDevices(); - - P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, const Ice::Current &); - P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, const Ice::Current &); - P2PVR::PrivateTunerPrx GetPrivateTuner(short type, const Ice::Current &); - void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &); - int TunerCount(const Ice::Current &); - - void Scan(const Ice::Current &); - void Add(const std::string & frontend, const Ice::Current &); - void Remove(const std::string & frontend, const Ice::Current &); - - INITOPTIONS; - private: - // Reference to global timer - IceUtil::TimerPtr timer; - IceUtil::TimerTaskPtr clientCheck; - - // Check that registered clients haven't silently gone away - void ClientCheck(Ice::ObjectAdapterPtr adapter); - - class OpenTuner { - public: - OpenTuner(DVBSI::DeliveryPtr, P2PVR::PrivateTunerPrx, bool); - - const bool openedPrivate; - const DVBSI::DeliveryPtr delivery; - const P2PVR::PrivateTunerPrx tuner; - - unsigned int clients; - }; - typedef boost::shared_ptr OpenTunerPtr; - typedef std::map Devices; - static Devices devices; - static std::mutex lock; -}; - -#endif - diff --git a/p2pvr/lib/maintenance.cpp b/p2pvr/lib/maintenance.cpp deleted file mode 100644 index 3475544..0000000 --- a/p2pvr/lib/maintenance.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include "maintenance.h" -#include -#include "bindTimerTask.h" -#include -#include - -time_t Maintenance::periodUpdateNetwork; -time_t Maintenance::periodUpdateServices; -time_t Maintenance::periodUpdateEvents; - -DECLARE_OPTIONS(Maintenance, "P2PVR Maintenance options") -("p2pvr.maintenance.periodUpdateNetwork", Options::value(&periodUpdateNetwork, 86400 * 7), - "Period between automated updates of DVB network (1 week)") -("p2pvr.maintenance.periodUpdateServices", Options::value(&periodUpdateServices, 86400 * 7), - "Period between automated updates of DVB services (1 week)") -("p2pvr.maintenance.periodUpdateEvents", Options::value(&periodUpdateEvents, 3600 * 12), - "Period between automated updates of DVB events (12 hours)") -END_OPTIONS(Maintenance); - -Maintenance::Maintenance(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr t) : - adapter(a), - timer(t), - clientCheck(new BindTimerTask(boost::bind(&Maintenance::ScheduledUpdate, this))), - lastUpdateNetwork(0), - lastUpdateServices(0), - lastUpdateEvents(0), - updateRunning(false) -{ - timer->scheduleRepeated(clientCheck, IceUtil::Time::seconds(5 * 60)); -#ifdef NDEBUG - ScheduledUpdate(); -#endif -} - -void -Maintenance::UpdateAll(const Ice::Current & ice) -{ - UpdateAll(FE_OFDM, ice); - UpdateAll(FE_QPSK, ice); - UpdateAll(FE_ATSC, ice); - UpdateAll(FE_QAM, ice); -} - -void -Maintenance::UpdateAll(short type, const Ice::Current & ice) -{ - UpdateNetwork(type, ice); - UpdateServices(type, ice); - UpdateProgramAssociations(type, ice); - UpdateProgramMaps(type, ice); - UpdateEvents(type, ice); -} - -void -Maintenance::ScheduledUpdate() -{ - Logger()->messagebf(LOG_DEBUG, "%s: triggered", __PRETTY_FUNCTION__); - if (!updateRunning) { - std::thread update([this] { - try { - ScopeObject notRunning([this]{ updateRunning = false; }); - updateRunning = true; - auto si = P2PVR::MaintenancePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Maintenance"))); - time_t now = time(NULL); - if (lastUpdateNetwork < now - periodUpdateNetwork) { - Logger()->messagebf(LOG_INFO, "%s: updating network", __PRETTY_FUNCTION__); - si->UpdateNetwork(FE_OFDM); - time(&lastUpdateNetwork); - } - if (lastUpdateServices < now - periodUpdateServices) { - Logger()->messagebf(LOG_INFO, "%s: updating services", __PRETTY_FUNCTION__); - si->UpdateServices(FE_OFDM); - time(&lastUpdateServices); - } - if (lastUpdateEvents < now - periodUpdateEvents) { - Logger()->messagebf(LOG_INFO, "%s: updating events", __PRETTY_FUNCTION__); - si->UpdateEvents(FE_OFDM); - time(&lastUpdateEvents); - } - Logger()->messagebf(LOG_DEBUG, "%s: completed", __PRETTY_FUNCTION__); - } - catch (const std::exception & ex) { - char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); - Logger()->messagebf(LOG_ERR, "%s: failed %s: %s", __PRETTY_FUNCTION__, buf, ex.what()); - free(buf); - } - catch (...) { - Logger()->messagebf(LOG_ERR, "%s: failed (unknown exception)", __PRETTY_FUNCTION__); - } - }); - update.detach(); - } -} - diff --git a/p2pvr/lib/maintenance.h b/p2pvr/lib/maintenance.h deleted file mode 100644 index 563455a..0000000 --- a/p2pvr/lib/maintenance.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef P2PVR_MAINTENANCE_H -#define P2PVR_MAINTENANCE_H - -#include -#include "dbClient.h" - -class Maintenance : public P2PVR::Maintenance, public DatabaseClient { - public: - Maintenance(Ice::ObjectAdapterPtr, IceUtil::TimerPtr); - - void UpdateAll(const Ice::Current &); - void UpdateAll(short type, const Ice::Current &); - void UpdateNetwork(short type, const Ice::Current &); - void UpdateServices(short type, const Ice::Current &); - void UpdateProgramAssociations(short type, const Ice::Current &); - void UpdateProgramMaps(short type, const Ice::Current &); - void UpdateEvents(short type, const Ice::Current &); - - INITOPTIONS; - - private: - void ScheduledUpdate(); - - Ice::ObjectAdapterPtr adapter; - IceUtil::TimerPtr timer; - IceUtil::TimerTaskPtr clientCheck; - - time_t lastUpdateNetwork; - time_t lastUpdateServices; - time_t lastUpdateEvents; - bool updateRunning; - - static time_t periodUpdateNetwork; - static time_t periodUpdateServices; - static time_t periodUpdateEvents; -}; - -#endif - diff --git a/p2pvr/lib/maintenance/events.cpp b/p2pvr/lib/maintenance/events.cpp deleted file mode 100644 index baa2bbf..0000000 --- a/p2pvr/lib/maintenance/events.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "../maintenance.h" -#include "../siParsers/event.h" -#include -#include -#include -#include -#include -#include -#include "../temporaryIceAdapterObject.h" -#include - -class SiEventsHandler : public SiEpgParser { - public: - SiEventsHandler(const RowProcessorCallback & cb) : - callBack(cb) {} - - void HandleTable(DVBSI::EventPtr e) - { - Logger()->messagebf(LOG_DEBUG, "Service Id: %d Program Id: %d Title: %s Time: %s - %s", - e->ServiceId, e->EventId, e->Title, e->StartTime, e->StopTime); - BindColumns(rowState, e); - rowState.process(callBack); - } - - private: - ObjectRowState rowState; - const RowProcessorCallback callBack; -}; - -class SiEventsMerger : public IHaveSubTasks { - public: - SiEventsMerger(short t, const Ice::Current & i) : - SourceObject(__PRETTY_FUNCTION__), - IHaveSubTasks(NULL), - type(t), - ice(i) { } - - void execute(ExecContext * ec) const - { - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); - - if (!devs || !si) { - throw std::runtime_error("bad proxy(s)"); - } - - TemporarayIceAdapterObject parser(ice.adapter, - new SiEventsHandler(boost::bind(&SiEventsMerger::executeChildren, this, ec))); - - auto delivery = si->GetDeliveryForSi(); - if (!delivery) { - throw std::runtime_error("no delivery methods"); - } - - Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); - auto tuner = devs->GetTunerAny(type, delivery); - Logger()->messagebf(LOG_DEBUG, "%s: Fetching events", __PRETTY_FUNCTION__); - tuner->SendEventInformation(parser); - devs->ReleaseTuner(tuner); - } - - private: - const short type; - const Ice::Current & ice; - - void executeChildren(ExecContext * ec) const - { - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(ec); - } - } -}; - -void -Maintenance::UpdateEvents(short type, const Ice::Current & ice) -{ - TxHelper tx(this); - SqlMergeTask mergeEvents("postgres", "events"); - CreateColumns(boost::bind(SqlMergeColumnsInserter, &mergeEvents, _1, _2)); - mergeEvents.sources.insert(new SiEventsMerger(type, ice)); - mergeEvents.loadComplete(this); - mergeEvents.execute(NULL); - tx.Commit(); - Logger()->messagebf(LOG_INFO, "%s: Updated events", __PRETTY_FUNCTION__); - - auto ic = ice.adapter->getCommunicator(); - auto sch = P2PVR::SchedulesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("Schedules"))); - sch->DoReschedule(); -} - diff --git a/p2pvr/lib/maintenance/network.cpp b/p2pvr/lib/maintenance/network.cpp deleted file mode 100644 index c66a2dd..0000000 --- a/p2pvr/lib/maintenance/network.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include "../maintenance.h" -#include "../siParsers/network.h" -#include -#include -#include -#include -#include -#include -#include "../temporaryIceAdapterObject.h" - -class SiNetworkInformationMerger : public SiNetworkInformationParser { - public: - SiNetworkInformationMerger(DatabaseClient * co) : commonObjects(co) { } - - bool HandleTable(DVBSI::NetworkPtr n) - { - Logger()->messagebf(LOG_DEBUG, "Network Id: %d Name: %s", n->NetworkId, *n->Name); - BOOST_FOREACH(const auto & ts, n->TransportStreams) { - Logger()->messagebf(LOG_DEBUG, "\tTransport Stream Id: %d Original Network Id: %d", ts->TransportStreamId, ts->OriginalNetworkId); - BOOST_FOREACH(const auto & s, ts->Services) { - Logger()->messagebf(LOG_DEBUG, "\t\tService Id: %d Service Type: %d", s.ServiceId, s.ServiceType); - } - if (ts->Terrestrial) { - Logger()->messagebf(LOG_DEBUG, "\t\tDVB-T: Frequency: %d", ts->Terrestrial->Frequency); - } - } - - DatabaseClient::TxHelper tx(commonObjects); - SqlMergeTask mergeNetwork("postgres", "networks"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeNetwork, _1, _2)); - std::vector networks = { n }; - mergeNetwork.sources.insert(new ContainerIterator>(&networks)); - mergeNetwork.loadComplete(commonObjects); - mergeNetwork.execute(NULL); - - SqlMergeTask mergeTransports("postgres", "transportstreams"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeTransports, _1, _2)); - mergeTransports.sources.insert(new ContainerIterator(&n->TransportStreams)); - mergeTransports.loadComplete(commonObjects); - mergeTransports.execute(NULL); - - SqlMergeTask mergeDvbt("postgres", "delivery_dvbt"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeDvbt, _1, _2)); - BOOST_FOREACH(const auto & s, n->TransportStreams) { - if (s->Terrestrial) { - mergeDvbt.sources.insert(new SingleIterator(&s->Terrestrial)); - } - } - mergeDvbt.loadComplete(commonObjects); - mergeDvbt.execute(NULL); - - SqlMergeTask mergeServices("postgres", "services"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeServices, _1, _2)); - BOOST_FOREACH(const auto & s, n->TransportStreams) { - mergeServices.sources.insert(new ContainerIterator(&s->Services)); - } - mergeServices.loadComplete(commonObjects); - mergeServices.execute(NULL); - return false; - } - private: - DatabaseClient * commonObjects; -}; - -void -Maintenance::UpdateNetwork(short type, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); - auto siparser = new SiNetworkInformationMerger(this); - TemporarayIceAdapterObject parser(ice.adapter, siparser); - - if (!devs) { - throw std::runtime_error("bad proxy(s)"); - } - auto transport = si->GetDeliveryForSi(); - if (transport) { - P2PVR::TunerPrx tuner; - try { - tuner = devs->GetTunerAny(type, transport); - tuner->SendNetworkInformation(parser); - devs->ReleaseTuner(tuner); - return; - } - catch (const P2PVR::NoSuitableDeviceAvailable &) { - Logger()->messagebf(LOG_WARNING, "%s: Failed to get a suitable tuner", __PRETTY_FUNCTION__); - throw; - } - catch (const std::exception & ex) { - Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information: %s", __PRETTY_FUNCTION__, ex.what()); - devs->ReleaseTuner(tuner); - throw; - } - catch (...) { - Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information", __PRETTY_FUNCTION__); - devs->ReleaseTuner(tuner); - throw; - } - } - // If we can't do that, do a complete scan - auto tuner = devs->GetPrivateTuner(type); - tuner->ScanAndSendNetworkInformation(parser); - devs->ReleaseTuner(tuner); -} - diff --git a/p2pvr/lib/maintenance/programAssociations.cpp b/p2pvr/lib/maintenance/programAssociations.cpp deleted file mode 100644 index 94a39be..0000000 --- a/p2pvr/lib/maintenance/programAssociations.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include "../maintenance.h" -#include "../siParsers/programAssociation.h" -#include -#include -#include -#include -#include -#include "../temporaryIceAdapterObject.h" - -class SiProgramAssociationHandler : public SiProgramAssociationParser { - public: - bool HandleTable(ProgramAssociationMapPtr pam) - { - Logger()->messagebf(LOG_DEBUG, "Program association table"); - BOOST_FOREACH(const auto & pa, *pam) { - Logger()->messagebf(LOG_DEBUG, " %d -> %d", pa.first, pa.second); - } - BOOST_FOREACH(const auto & pa, *pam) { - map[pa.first] = pa.second; - } - return false; - } - - ProgramAssociationMap map; -}; - -static -void -CreatePATColumns(const ColumnCreator & cc) -{ - cc("serviceId", true); - cc("programId", false); -} - -void -Maintenance::UpdateProgramAssociations(short type, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); - - if (!devs || !si) { - throw std::runtime_error("bad proxy(s)"); - } - - auto siparser = new SiProgramAssociationHandler(); - TemporarayIceAdapterObject parser(ice.adapter, siparser); - - const auto deliveries = si->GetAllDeliveries(type); - if (deliveries.empty()) { - throw std::runtime_error("no delivery methods"); - } - - BOOST_FOREACH(const auto & transport, deliveries) { - try { - Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); - auto tuner = devs->GetTunerSpecific(transport); - Logger()->messagebf(LOG_DEBUG, "%s: Fetching associations", __PRETTY_FUNCTION__); - tuner->SendProgramAssociationTable(parser); - Logger()->messagebf(LOG_INFO, "%s: Updated associations", __PRETTY_FUNCTION__); - devs->ReleaseTuner(tuner); - } - catch (...) { - // Tuning can fail - } - } - - TxHelper tx(this); - SqlMergeTask mergeServices("postgres", "services"); - CreatePATColumns(boost::bind(SqlMergeColumnsInserter, &mergeServices, _1, _2)); - // Don't change the list of services available from the network - mergeServices.doDelete = VariableType(false); - mergeServices.doInsert = VariableType(false); - Columns cols; - mergeServices.sources.insert(new MapIterator(CreatePATColumns, &siparser->map)); - mergeServices.loadComplete(this); - mergeServices.execute(NULL); -} - diff --git a/p2pvr/lib/maintenance/programMap.cpp b/p2pvr/lib/maintenance/programMap.cpp deleted file mode 100644 index 2a2793d..0000000 --- a/p2pvr/lib/maintenance/programMap.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include "../maintenance.h" -#include "../siParsers/programMap.h" -#include -#include -#include -#include -#include -#include -#include "../temporaryIceAdapterObject.h" -#include -#include -#include -#include - -class SiProgramMapHandler : public SiProgramMapParser { - public: - SiProgramMapHandler(const RowProcessorCallback & cb) : - callBack(cb) {} - - bool HandleTable(DVBSI::ProgramMapPtr pmp) - { - Logger()->messagebf(LOG_DEBUG, "Program map: serviceId = %d", pmp->ServiceId); - BOOST_FOREACH(const auto & s, pmp->Streams) { - Logger()->messagef(LOG_DEBUG, "type: %02x id: %d", s->Type, s->Id); - } - BOOST_FOREACH(const auto & s, pmp->Streams) { - BindColumns(rowState, s); - rowState.process(callBack); - } - return false; - } - - private: - ObjectRowState rowState; - const RowProcessorCallback callBack; -}; - -typedef boost::shared_ptr SelectPtr; - -template -void -operator<<(T & val, const DB::Column & col) -{ - HandleAsVariableType havt; - col.apply(havt); - val = havt.variable; -} - -class SiProgramMapMerger : public IHaveSubTasks { - public: - SiProgramMapMerger(short t, CommonObjects * co, const Ice::Current & i) : - SourceObject(__PRETTY_FUNCTION__), - IHaveSubTasks(NULL), - commonObjects(co), - type(t), - ice(i) { } - - void execute(ExecContext * ec) const - { - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); - - if (!devs || !si) { - throw std::runtime_error("bad proxy(s)"); - } - - TemporarayIceAdapterObject parser(ice.adapter, - new SiProgramMapHandler(boost::bind(&SiProgramMapMerger::executeChildren, this, ec))); - - const auto deliveries = si->GetAllDeliveries(type); - if (deliveries.empty()) { - throw std::runtime_error("no delivery methods"); - } - - auto db = commonObjects->dataSource("postgres")->getReadonly(); - SelectPtr sel = SelectPtr(db->newSelectCommand("select d.frequency, s.programid \ - from delivery_dvbt d, services s \ - where d.transportstreamid = s.transportstreamid \ - and s.programid is not null \ - order by s.transportstreamid, s.serviceid")); - int64_t curFreq = 0; - P2PVR::TunerPrx tuner; - while (sel->fetch()) { - int64_t freq, pid; - freq << (*sel)[0]; - pid << (*sel)[1]; - - if (freq != curFreq) { - if (tuner) { - devs->ReleaseTuner(tuner); - } - Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); - const auto transport = *std::find_if(deliveries.begin(), deliveries.end(), - [freq](const DVBSI::DeliveryPtr & del) { return del->Frequency == freq; }); - tuner = devs->GetTunerSpecific(transport); - curFreq = freq; - } - - Logger()->messagebf(LOG_DEBUG, "%s: Fetching associations", __PRETTY_FUNCTION__); - tuner->SendProgramMap(pid, parser); - Logger()->messagebf(LOG_INFO, "%s: Updated associations", __PRETTY_FUNCTION__); - } - if (tuner) { - devs->ReleaseTuner(tuner); - } - } - - private: - CommonObjects * commonObjects; - const short type; - const Ice::Current & ice; - - void executeChildren(ExecContext * ec) const - { - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(ec); - } - } -}; - -void -Maintenance::UpdateProgramMaps(short type, const Ice::Current & ice) -{ - TxHelper tx(this); - SqlMergeTask mergeServiceStreams("postgres", "servicestreams"); - CreateColumns(boost::bind(SqlMergeColumnsInserter, &mergeServiceStreams, _1, _2)); - mergeServiceStreams.sources.insert(new SiProgramMapMerger(type, this, ice)); - mergeServiceStreams.loadComplete(this); - mergeServiceStreams.execute(NULL); -} - diff --git a/p2pvr/lib/maintenance/services.cpp b/p2pvr/lib/maintenance/services.cpp deleted file mode 100644 index 2f97161..0000000 --- a/p2pvr/lib/maintenance/services.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "../maintenance.h" -#include "../siParsers/service.h" -#include -#include -#include -#include -#include -#include -#include "../temporaryIceAdapterObject.h" - -class SiServicesMerger : public SiServicesParser { - public: - SiServicesMerger(DatabaseClient * co) : commonObjects(co) { } - - bool HandleTable(DVBSI::TransportStreamPtr ts) - { - Logger()->messagebf(LOG_DEBUG, "Transport Stream Id: %d Original Network Id: %s", ts->TransportStreamId, ts->OriginalNetworkId); - BOOST_FOREACH(const auto & s, ts->Services) { - Logger()->messagebf(LOG_DEBUG, "\tService Id: %d Name: %s Type: %d, Provider: %s, DefaultAuthority: %s, RunningStatus %d FreeCaMode %d", - s->ServiceId, (s->Name ? *s->Name : "?"), (s->Type ? *s->Type : -1), - (s->ProviderName ? *s->ProviderName : "?"), (s->DefaultAuthority ? *s->DefaultAuthority : "?"), - s->RunningStatus, s->FreeCaMode); - } - - DatabaseClient::TxHelper tx(commonObjects); - SqlMergeTask mergeServices("postgres", "services"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeServices, _1, _2)); - // Don't change the list of services available from the network - mergeServices.doDelete = VariableType(false); - mergeServices.doInsert = VariableType(false); - mergeServices.sources.insert(new ContainerIterator(&ts->Services)); - mergeServices.loadComplete(commonObjects); - mergeServices.execute(NULL); - return false; - } - - private: - DatabaseClient * commonObjects; -}; - -void -Maintenance::UpdateServices(short type, const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI"))); - - if (!devs || !si) { - throw std::runtime_error("bad proxy(s)"); - } - - auto siparser = new SiServicesMerger(this); - TemporarayIceAdapterObject parser(ice.adapter, siparser); - - auto delivery = si->GetDeliveryForSi(); - if (!delivery) { - throw std::runtime_error("no delivery methods"); - } - - Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); - auto tuner = devs->GetTunerAny(type, delivery); - Logger()->messagebf(LOG_DEBUG, "%s: Fetching service list", __PRETTY_FUNCTION__); - tuner->SendServiceDescriptions(parser); - Logger()->messagebf(LOG_INFO, "%s: Updated service list", __PRETTY_FUNCTION__); - devs->ReleaseTuner(tuner); -} - diff --git a/p2pvr/lib/mapIterator.cpp b/p2pvr/lib/mapIterator.cpp new file mode 100644 index 0000000..157669a --- /dev/null +++ b/p2pvr/lib/mapIterator.cpp @@ -0,0 +1,11 @@ +#include +#include "mapIterator.h" +#include "p2Helpers.h" + +template<> +void BindColumns>(RowState & rs, std::pair const & p) +{ + rs.fields[0] << p.first; + rs.fields[1] << p.second; +} + diff --git a/p2pvr/lib/mapIterator.h b/p2pvr/lib/mapIterator.h new file mode 100644 index 0000000..8a06fe6 --- /dev/null +++ b/p2pvr/lib/mapIterator.h @@ -0,0 +1,45 @@ +#ifndef MAPITERATOR_H +#define MAPITERATOR_H + +#include +#include +#include "objectRowState.h" + +template +class MapIterator : public IHaveSubTasks { + public: + template + MapIterator(const ColumnSpecifier & cs, const T * m, const Parents & ... p) : + SourceObject(__PRETTY_FUNCTION__), + IHaveSubTasks(NULL), + binder(boost::bind(&BindColumns, _1, _2, p...)), + columnSpecifier(cs), + map(m) + { + } + + void execute(ExecContext * ec) const + { + ObjectRowState rs(columnSpecifier); + BOOST_FOREACH(const auto & i, *map) { + binder(rs, i); + rs.process(boost::bind(&MapIterator::executeChildren, this, ec)); + } + } + + private: + boost::function binder; + const ColumnSpecifier columnSpecifier; + const T * map; + + void executeChildren(ExecContext * ec) const + { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(ec); + } + } +}; + +#endif + + diff --git a/p2pvr/lib/objectRowState.h b/p2pvr/lib/objectRowState.h new file mode 100644 index 0000000..9ba69f0 --- /dev/null +++ b/p2pvr/lib/objectRowState.h @@ -0,0 +1,45 @@ +#ifndef OBJECT_ROW_STATE_H +#define OBJECT_ROW_STATE_H + +#include +#include +#include + +typedef boost::function ColumnCreator; +typedef boost::function ColumnSpecifier; + +template +void BindColumns(RowState &, const V &); + +template +void UnbindColumns(RowState &, const V &); + +template +void CreateColumns(const ColumnCreator &); + +template +class ObjectRowState : public RowState { + public: + ObjectRowState(const ColumnSpecifier & cs = CreateColumns) : + columns(ColumnCreatorHelper(cs)) + { + fields.resize(columns.size()); + } + const Columns & getColumns() const { return columns; } + + private: + static Columns ColumnCreatorHelper(const ColumnSpecifier & cs) + { + int index = 0; + Columns columns; + cs([&columns, &index](const std::string & name, bool) { + columns.insert(new Column(index++, name)); + }); + return columns; + } + + Columns columns; +}; + +#endif + diff --git a/p2pvr/lib/p2Helpers.cpp b/p2pvr/lib/p2Helpers.cpp new file mode 100644 index 0000000..c58ff1a --- /dev/null +++ b/p2pvr/lib/p2Helpers.cpp @@ -0,0 +1,43 @@ +#include +#include "p2Helpers.h" +#include + +template <> +VariableType & +operator<<(VariableType & vt, const Common::Duration & d) +{ + return (vt = *d); +} + +template <> +VariableType & +operator<<(VariableType & vt, const Common::DateTime & dt) +{ + return (vt = *dt); +} + +template <> +const VariableType & +operator>>(const VariableType & vt, Common::Duration & d) +{ + const boost::posix_time::time_duration & dur = vt; + d = *dur; + return vt; +} + +template <> +const VariableType & +operator>>(const VariableType & vt, Common::DateTime & dt) +{ + const boost::posix_time::ptime & date = vt; + dt = *date; + return vt; +} + +template <> +const VariableType & +operator>>(const VariableType & vt, short int & v) +{ + v = (int)vt; + return vt; +} diff --git a/p2pvr/lib/p2Helpers.h b/p2pvr/lib/p2Helpers.h new file mode 100644 index 0000000..3b73f1b --- /dev/null +++ b/p2pvr/lib/p2Helpers.h @@ -0,0 +1,71 @@ +#ifndef ICE_P2_HELPERS_H +#define ICE_P2_HELPERS_H + +#include +#include + +template +const VariableType & +operator>>(const VariableType & vt, T & v) +{ + v = vt.as(); + return vt; +} + +template <> +const VariableType & +operator>>(const VariableType & vt, Common::Duration & d); + +template <> +const VariableType & +operator>>(const VariableType & vt, Common::DateTime & dt); + +template +const VariableType & +operator>>(const VariableType & vt, IceUtil::Optional & v) +{ + if (vt.isNull()) { + v = IceUtil::Optional(); + } + else { + v = T(); + vt >> *v; + } + return vt; +} + +template <> +const VariableType & +operator>>(const VariableType & vt, short int & v); + +template +VariableType & +operator<<(VariableType & vt, const T & v) +{ + vt = v; + return vt; +} + +template <> +VariableType & +operator<<(VariableType & vt, const Common::Duration & d); + +template <> +VariableType & +operator<<(VariableType & vt, const Common::DateTime & dt); + +template +VariableType & +operator<<(VariableType & vt, const IceUtil::Optional & v) +{ + if (v) { + vt << *v; + } + else { + vt = Null(); + } + return vt; +} + +#endif + diff --git a/p2pvr/lib/p2LoggerWrapper.cpp b/p2pvr/lib/p2LoggerWrapper.cpp deleted file mode 100644 index 60ec191..0000000 --- a/p2pvr/lib/p2LoggerWrapper.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include "p2LoggerWrapper.h" -#include "logger.h" - -P2LoggerWrapper::P2LoggerWrapper(const std::string & p) : - prefix(p) -{ -} - -void -P2LoggerWrapper::print(const std::string & message) -{ - ::Logger()->messagebf(LOG_INFO, "%s: %s", prefix, message); -} - -void -P2LoggerWrapper::trace(const std::string & cat, const std::string & message) -{ - ::Logger()->messagebf(LOG_DEBUG, "%s: [%s] %s", prefix, cat, message); -} - -void -P2LoggerWrapper::warning(const std::string & message) -{ - ::Logger()->messagebf(LOG_WARNING, "%s: %s", prefix, message); -} - -void -P2LoggerWrapper::error(const std::string & message) -{ - ::Logger()->messagebf(LOG_ERR, "%s: %s", prefix, message); -} - -Ice::LoggerPtr -P2LoggerWrapper::cloneWithPrefix(const std::string & p) -{ - return new P2LoggerWrapper(prefix + "-" + p); -} - diff --git a/p2pvr/lib/p2LoggerWrapper.h b/p2pvr/lib/p2LoggerWrapper.h deleted file mode 100644 index 8febda5..0000000 --- a/p2pvr/lib/p2LoggerWrapper.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef P2LOGGERWRAPPER -#define P2LOGGERWRAPPER - -#include - -class P2LoggerWrapper : public Ice::Logger { - public: - P2LoggerWrapper(const std::string & prefix = std::string()); - - void print(const std::string & message); - void trace(const std::string & cat, const std::string & message); - void warning(const std::string & message); - void error(const std::string & message); - - Ice::LoggerPtr cloneWithPrefix(const std::string & prefix); - - private: - const std::string prefix; -}; - - -#endif - diff --git a/p2pvr/lib/p2pvrHelpers/schedule.cpp b/p2pvr/lib/p2pvrHelpers/schedule.cpp new file mode 100644 index 0000000..f8abc1e --- /dev/null +++ b/p2pvr/lib/p2pvrHelpers/schedule.cpp @@ -0,0 +1,51 @@ +#include +#include +#include "../dvbsiHelpers.h" +#include "../p2Helpers.h" + +template<> +void +CreateColumns(const ColumnCreator & cc) +{ + cc("scheduleid", true); + cc("serviceid", true); + cc("eventid", false); + cc("title", false); + cc("search", false); + cc("priority", false); + cc("early", false); + cc("late", false); + cc("repeats", false); +} + +template<> +void +BindColumns(RowState & rs, const P2PVR::SchedulePtr & s) +{ + rs.fields[0] << s->ScheduleId; + rs.fields[1] << s->ServiceId; + rs.fields[2] << s->EventId; + rs.fields[3] << s->Title; + rs.fields[4] << s->Search; + rs.fields[5] << s->Priority; + rs.fields[6] << s->Early; + rs.fields[7] << s->Late; + rs.fields[8] << s->Repeats; +} + +template<> +void +UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) +{ + rs.fields[0] >> s->ScheduleId; + rs.fields[1] >> s->ServiceId; + rs.fields[2] >> s->EventId; + rs.fields[3] >> s->Title; + rs.fields[4] >> s->Search; + rs.fields[5] >> s->Priority; + rs.fields[6] >> s->Early; + rs.fields[7] >> s->Late; + rs.fields[8] >> s->Repeats; +} + + diff --git a/p2pvr/lib/recorder.cpp b/p2pvr/lib/recorder.cpp deleted file mode 100644 index bdd18c6..0000000 --- a/p2pvr/lib/recorder.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include "recorder.h" -#include "bindTimerTask.h" -#include -#include -#include -#include -#include "serviceStreamer.h" -#include "storage.h" -#include "muxer.h" - -std::string Recorder::extension; -std::string Recorder::muxerCommand; - -DECLARE_OPTIONS(Recorder, "P2PVR Recorder options") -("p2pvr.recorder.extension", Options::value(&extension, "mpg"), - "File extension to save with (default: avi)") -("p2pvr.recorder.muxercommand", Options::value(&muxerCommand, "/usr/bin/ffmpeg -f mpegts -i - -f dvd -codec copy -"), - "File extension to save with (default: '/usr/bin/ffmpeg -f mpegts -i - -f dvd -codec copy -')") -END_OPTIONS(Recorder); - -Recorder::Recorder(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr t) : - adapter(a), - timer(t) -{ - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - RefreshSchedules(Ice::Current()); -} - -void -Recorder::RefreshSchedules(const Ice::Current &) -{ - std::lock_guard g(lock); - BOOST_FOREACH(auto & t, pendingRecordings) { - timer->cancel(t); - } - pendingRecordings.clear(); - auto schedules = P2PVR::SchedulesPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Schedules"))); - auto si = P2PVR::SIPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("SI"))); - BOOST_FOREACH(const auto & s, schedules->GetScheduledToRecord()) { - if (std::find_if(currentRecordings.begin(), currentRecordings.end(), [&s](const CurrentPtr & c) { - return s->ScheduleId == c->schedule->ScheduleId && s->ServiceId == c->event->ServiceId && s->EventId == c->event->EventId;; - }) != currentRecordings.end()) { - continue; - } - auto schedule = schedules->GetSchedule(s->ScheduleId); - auto service = si->GetService(s->ServiceId); - auto event = si->GetEvent(s->ServiceId, s->EventId); - - auto startIn = std::max((*event->StartTime - *schedule->Early - boost::posix_time::second_clock::universal_time()).total_seconds(), 0); - IceUtil::TimerTaskPtr startTimer = new BindTimerTask(boost::bind(&Recorder::StartRecording, this, schedule, service, event)); - timer->schedule(startTimer, IceUtil::Time::seconds(startIn)); - pendingRecordings.push_back(startTimer); - Logger()->messagebf(LOG_DEBUG, "Recording %s scheduled for %s seconds", event->Title, startIn); - } -} - -void -Recorder::StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event) -{ - std::lock_guard g(lock); - auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); - auto recordings = P2PVR::RecordingsPrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Recordings"))); - - auto id = storage->CreateForEventRecording(extension, schedule, service, event); - auto store = storage->OpenForWrite(id); - ScopeObject _store(NULL, NULL, [this,&store,&storage,&id]() { storage->Close(store); storage->Delete(id); }); - auto muxer = P2PVR::RawDataClientPrx::checkedCast(adapter->addWithUUID(new Muxer(store, muxerCommand))); - ScopeObject _muxer(NULL, NULL, [this,&muxer]() { adapter->remove(muxer->ice_getIdentity()); }); - auto ss = ServiceStreamerPtr(new ServiceStreamer(service->ServiceId, muxer, adapter->getCommunicator(), adapter)); - - ss->Start(); - Logger()->messagebf(LOG_INFO, "Started recording %s (%s - %s) on %s (%d)", - event->Title, event->StartTime, event->StopTime, - service->Name ? *service->Name : "", service->ServiceId); - - recordings->NewRecording(new P2PVR::Recording(0, storage->ice_toString(), id, schedule->ScheduleId, event->Title, event->Subtitle, - event->Description, event->StartTime, *(*event->StopTime - *event->StartTime))); - auto newCurrent = CurrentPtr(new Current({muxer, store, ss, schedule, service, event, IceUtil::TimerTaskPtr()})); - currentRecordings.insert(newCurrent); - - auto stopIn = (*event->StopTime + *schedule->Late - boost::posix_time::second_clock::universal_time()).total_seconds(); - newCurrent->stopTimer = new BindTimerTask(boost::bind(&Recorder::StopRecording, this, newCurrent)); - timer->schedule(newCurrent->stopTimer, IceUtil::Time::seconds(stopIn)); - Logger()->messagebf(LOG_DEBUG, "Recording %s scheduled stop in %s seconds", event->Title, stopIn); -} - -void -Recorder::StopRecording(CurrentPtr c) -{ - std::lock_guard g(lock); - Logger()->messagebf(LOG_DEBUG, "Stopping %s", c->event->Title); - c->stream->Stop(); - adapter->remove(c->muxer->ice_getIdentity()); - currentRecordings.erase(c); - auto storage = P2PVR::StoragePrx::checkedCast(adapter->createProxy(adapter->getCommunicator()->stringToIdentity("Storage"))); - storage->Close(c->store); - Logger()->messagebf(LOG_DEBUG, "Stopped %s", c->event->Title); -} - diff --git a/p2pvr/lib/recorder.h b/p2pvr/lib/recorder.h deleted file mode 100644 index 78c604b..0000000 --- a/p2pvr/lib/recorder.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef RECORDER_H -#define RECORDER_H - -#include -#include -#include -#include -#include -#include "serviceStreamer.h" - -class Recorder : public P2PVR::Recorder { - public: - typedef std::vector Pendings; - - class Current { - public: - P2PVR::RawDataClientPrx muxer; - P2PVR::RawDataClientPrx store; - ServiceStreamerPtr stream; - P2PVR::SchedulePtr schedule; - DVBSI::ServicePtr service; - DVBSI::EventPtr event; - IceUtil::TimerTaskPtr stopTimer; - }; - typedef boost::shared_ptr CurrentPtr; - typedef std::set Currents; - - Recorder(Ice::ObjectAdapterPtr a, IceUtil::TimerPtr); - - void RefreshSchedules(const Ice::Current &); - - INITOPTIONS; - - private: - void StartRecordings(); - void StartRecording(P2PVR::SchedulePtr schedule, DVBSI::ServicePtr service, DVBSI::EventPtr event); - void StopRecording(CurrentPtr); - - Ice::ObjectAdapterPtr adapter; - IceUtil::TimerPtr timer; - - Currents currentRecordings; - Pendings pendingRecordings; - std::mutex lock; - - static std::string extension; - static std::string muxerCommand; -}; - -#endif - diff --git a/p2pvr/lib/recordings.cpp b/p2pvr/lib/recordings.cpp deleted file mode 100644 index d2c9658..0000000 --- a/p2pvr/lib/recordings.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include "recordings.h" -#include "resources.h" -#include -#include -#include "sqlContainerCreator.h" - -ResourceString(Recording_Insert, lib_sql_Recordings_insert_sql); -ResourceString(Recording_InsertNewId, lib_sql_Recordings_insertNewId_sql); -ResourceString(Recording_Delete, lib_sql_Recordings_delete_sql); -ResourceString(Recording_GetStorage, lib_sql_Recordings_getStorage_sql); -ResourceString(Recording_GetAll, lib_sql_Recordings_getAll_sql); - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("recordingid", true); - cc("storageaddress", false); - cc("guid", false); - cc("scheduleid", false); - cc("title", false); - cc("subtitle", false); - cc("description", false); - cc("starttime", false); - cc("duration", false); -} - -template<> -void -UnbindColumns(RowState & rs, const P2PVR::RecordingPtr & r) -{ - rs.fields[0] >> r->RecordingId; - rs.fields[1] >> r->StorageAddress; - rs.fields[2] >> r->Guid; - rs.fields[3] >> r->ScheduleId; - rs.fields[4] >> r->Title; - rs.fields[5] >> r->Subtitle; - rs.fields[6] >> r->Description; - rs.fields[7] >> r->StartTime; - rs.fields[8] >> r->Duration; -} - -int -Recordings::NewRecording(const P2PVR::RecordingPtr & r, const Ice::Current &) -{ - Logger()->messagebf(LOG_INFO, "%s: Creating new recording %s at %s", __PRETTY_FUNCTION__, r->Guid, r->StorageAddress); - TxHelper tx(this); - auto insert = Modify(Recording_Insert, - r->StorageAddress, r->Guid, r->ScheduleId, r->Title, r->Subtitle, r->Description, r->StartTime, r->Duration); - insert.second->execute(); - r->RecordingId = SelectScalar(Recording_InsertNewId); - Logger()->messagebf(LOG_INFO, "%s: Created recording Id: %d", __PRETTY_FUNCTION__, r->RecordingId); - return r->RecordingId; -} - -void -Recordings::DeleteRecording(int id, const Ice::Current & ice) -{ - Logger()->messagebf(LOG_INFO, "%s: Deleting recording Id: %d", __PRETTY_FUNCTION__, id); - auto ic = ice.adapter->getCommunicator(); - TxHelper tx(this); - auto recordingStorages = Select(Recording_GetStorage, id); - while (recordingStorages.second->fetch()) { - std::string addr = recordingStorages.second / "storageaddress"; - std::string guid = recordingStorages.second / "guid"; - auto storage = P2PVR::StoragePrx::checkedCast(ic->stringToProxy(addr)); - storage->Delete(guid); - Logger()->messagebf(LOG_DEBUG, "%s: Delete %s from StorageAddress %s", __PRETTY_FUNCTION__, guid, addr); - } - Modify(Recording_Delete, id).second->execute(); -} - -P2PVR::RecordingList -Recordings::GetRecordings(const Ice::Current &) -{ - P2PVR::RecordingList rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(Recording_GetAll).second); - return rtn; -} - diff --git a/p2pvr/lib/recordings.h b/p2pvr/lib/recordings.h deleted file mode 100644 index 0f18a36..0000000 --- a/p2pvr/lib/recordings.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef RECORDINGS_H -#define RECORDINGS_H - -#include -#include -#include "dbClient.h" - -class Recordings : public DatabaseClient, public P2PVR::Recordings { - public: - int NewRecording(const P2PVR::RecordingPtr & rec, const Ice::Current &); - void DeleteRecording(int recordingId, const Ice::Current &); - P2PVR::RecordingList GetRecordings(const Ice::Current &); -}; - -#endif - diff --git a/p2pvr/lib/schedulers/bitDumbScheduler.cpp b/p2pvr/lib/schedulers/bitDumbScheduler.cpp deleted file mode 100644 index f3cf5fb..0000000 --- a/p2pvr/lib/schedulers/bitDumbScheduler.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include "../schedules.h" - -class TheBitDumbScheduler : public EpisodeGroup { - public: - TheBitDumbScheduler(const Episodes & eps) : - episodes(eps) - { - } - - protected: - void SelectShowings() - { - SelectShowings(episodes.begin(), 1); - } - - private: - void SelectShowings(Episodes::const_iterator e, uint64_t complexityLevel) - { - if (e != episodes.end()) { - complexityLevel *= (*e)->showings.size(); - if (complexityLevel > 2 << 16) { - auto current = showings.size(); - for (EpisodesIter ne = e; ne != episodes.end(); ne++) { - BOOST_FOREACH(const auto & s, (*ne)->showings) { - showings.push_back(s); - if (SuggestWithFeedback(showings) & 0x1) { - break; - } - showings.pop_back(); - } - } - showings.resize(current); - } - else { - EpisodesIter ne = e; - ne++; - BOOST_FOREACH(const auto & s, (*e)->showings) { - showings.push_back(s); - SelectShowings(ne, complexityLevel); - showings.pop_back(); - } - } - } - else { - Suggest(showings); - } - } - - mutable Showings showings; // working set - const Episodes episodes; -}; - -DECLARE_GENERIC_LOADER("BitDumb", EpisodeGroupLoader, TheBitDumbScheduler); - diff --git a/p2pvr/lib/schedules.cpp b/p2pvr/lib/schedules.cpp deleted file mode 100644 index 99d4983..0000000 --- a/p2pvr/lib/schedules.cpp +++ /dev/null @@ -1,484 +0,0 @@ -#include -#include "schedules.h" -#include "sqlContainerCreator.h" -#include -#include -#include -#include -#include -#include "p2Helpers.h" -#include "containerIterator.h" -#include "resources.h" -#include -#include - -ResourceString(Schedules_GetCandidates, lib_sql_Schedules_GetCandidates_sql); -ResourceString(Schedules_insert, lib_sql_Schedules_insert_sql); -ResourceString(Schedules_insertNewId, lib_sql_Schedules_insertNewId_sql); -ResourceString(Schedules_update, lib_sql_Schedules_update_sql); -ResourceString(Schedules_delete, lib_sql_Schedules_delete_sql); -ResourceString(Schedules_selectAll, lib_sql_Schedules_selectAll_sql); -ResourceString(Schedules_selectById, lib_sql_Schedules_selectById_sql); -ResourceString(Schedules_scheduledToRecord, lib_sql_Schedules_scheduledToRecord_sql); - -std::string Schedules::SchedulerAlgorithm; - -DECLARE_OPTIONS(Schedules, "P2PVR Scheduler options") -("p2pvr.scheduler.algorithm", Options::value(&SchedulerAlgorithm, "BitDumb"), - "Implementation of episode group scheduler problem solver") -END_OPTIONS() - -class ScheduleCandidate { - public: - std::string What; - int ServiceId; - int EventId; - int TransportStreamId; - datetime StartTime; - datetime StopTime; - int Priority; - int ScheduleId; -}; -typedef boost::shared_ptr ScheduleCandidatePtr; -typedef std::vector ScheduleCandidates; - -enum RecordStatuses { - Record_WillRecordThisShowing = 0, - Record_WillRecordOtherShowing = 1, - Record_CannotRecordAnyShowing = 2 -}; - -class Record { - public: - Record() { }; - Record(int s, int e, RecordStatuses rs, int sc) : - ServiceId(s), - EventId(e), - RecordStatus(rs), - ScheduleId(sc) - { - } - - int ServiceId; - int EventId; - RecordStatuses RecordStatus; - int ScheduleId; -}; -typedef boost::shared_ptr RecordPtr; -typedef std::vector Records; - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceid", true); - cc("eventid", true); - cc("scheduleid", true); -} - -template<> -void -UnbindColumns(RowState & rs, P2PVR::ScheduledToRecordPtr const & s) -{ - rs.fields[0] >> s->ServiceId; - rs.fields[1] >> s->EventId; - rs.fields[2] >> s->ScheduleId; -} - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("what", true); - cc("serviceid", false); - cc("eventid", false); - cc("transportstreamid", false); - cc("starttime", false); - cc("stoptime", false); - cc("priority", false); - cc("scheduleid", false); -} - -template<> -void -UnbindColumns(RowState & rs, ScheduleCandidatePtr const & s) -{ - rs.fields[0] >> s->What; - rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; - rs.fields[3] >> s->TransportStreamId; - rs.fields[4] >> s->StartTime; - rs.fields[5] >> s->StopTime; - rs.fields[6] >> s->Priority; - rs.fields[7] >> s->ScheduleId; -} - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("scheduleid", true); - cc("serviceid", false); - cc("eventid", false); - cc("title", false); - cc("search", false); - cc("priority", false); - cc("early", false); - cc("late", false); - cc("repeats", false); -} - -template<> -void -UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) -{ - rs.fields[0] >> s->ScheduleId; - rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; - rs.fields[3] >> s->Title; - rs.fields[4] >> s->Search; - rs.fields[5] >> s->Priority; - rs.fields[6] >> s->Early; - rs.fields[7] >> s->Late; - rs.fields[8] >> s->Repeats; -} - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceid", true); - cc("eventid", true); - cc("recordstatus", false); - cc("scheduleid", false); -} - -template<> -void -BindColumns(RowState & rs, RecordPtr const & s) -{ - rs.fields[0] << s->ServiceId; - rs.fields[1] << s->EventId; - rs.fields[2] << (int)s->RecordStatus; - rs.fields[3] << s->ScheduleId; -} - -Showing::Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep) : - episode(ep), - serviceId(s), - eventId(e), - priority(p), - scheduleId(sc), - transportStreamId(t), - startTime(start), - stopTime(stop), - period(start, stop) -{ -} - -Episode::Episode(const std::string & w) : - priority(0), - what(w) -{ -} - -EpisodeGroup::EpisodeGroup() : - tuners(1), - sumTimeToStart(0), - score(0) -{ -} - -bool -EpisodeGroup::IsShowingListValid(const Showings & showings) const -{ - struct TransOffset { - unsigned int trans; - char offset; - }; - typedef std::multimap Periods; - typedef std::map Usage; - - Periods periods; - Usage usage; - - BOOST_FOREACH(const auto & s, showings) { - if (s) { - periods.insert(Periods::value_type(s->startTime, {s->transportStreamId, 1})); - periods.insert(Periods::value_type(s->stopTime, {s->transportStreamId, -1})); - } - } - bool result = true; - BOOST_FOREACH(const auto & p, periods) { - auto & u = usage[p.second.trans]; - u += p.second.offset; - if (std::count_if(usage.begin(), usage.end(), [](const Usage::value_type & uv) { return uv.second > 0;}) > tuners) { - result = false; - break; - } - } - periods.clear(); - usage.clear(); - return result; -} - -template -inline -bool NotNull(const T & p) -{ - return p != NULL; -} - -class SumTimeToStart { - public: - SumTimeToStart(time_t & t) : - total(t), - now(boost::posix_time::second_clock::universal_time()) - { - total = 0; - } - inline void operator()(const ShowingPtr & s) const - { - if (s) { - total += std::min((now - s->startTime).seconds(), 0); - } - } - public: - time_t & total; - datetime now; -}; - -const Showings & -EpisodeGroup::Solve() -{ - SelectShowings(); - return selected; -} - -void -EpisodeGroup::Suggest(const Showings & showings) -{ - unsigned int c = 0; - std::for_each(showings.begin(), showings.end(), [&c](const ShowingPtr & s) { if (s) c+= s->episode->priority; }); - if (c >= score) { - time_t stt; - std::for_each(showings.begin(), showings.end(), SumTimeToStart(stt)); - if (stt < sumTimeToStart || (stt == sumTimeToStart && c > score)) { - if (IsShowingListValid(showings)) { - selected = showings; - score = c; - sumTimeToStart = stt; - } - } - } -} - -EpisodeGroup::SuggestionResult -EpisodeGroup::SuggestWithFeedback(const Showings & showings) -{ - if (IsShowingListValid(showings)) { - unsigned int c = 0; - std::for_each(showings.begin(), showings.end(), [&c](const ShowingPtr & s) { if (s) c+= s->episode->priority; }); - if (c >= score) { - time_t stt; - std::for_each(showings.begin(), showings.end(), SumTimeToStart(stt)); - if (stt < sumTimeToStart) { - selected = showings; - score = c; - sumTimeToStart = stt; - return SuggestionValidAndAccepted; - } - } - return SuggestionValid; - } - else { - return SuggestionInvalid; - } -} - -void -Schedules::GetEpisodeIntersects(Episodes & all, Episodes & grouped) -{ - for (Episodes::iterator aei = all.begin(); aei != all.end(); aei++) { - const auto & ae = *aei; - BOOST_FOREACH(const auto & ge, grouped) { - BOOST_FOREACH(const auto & gs, ge->showings) { - BOOST_FOREACH(const auto & as, ae->showings) { - if (gs->period.intersects(as->period)) { - Logger()->messagebf(LOG_DEBUG, " added %s", ae->what); - grouped.push_back(ae); - all.erase(aei); - GetEpisodeIntersects(all, grouped); - return; - } - } - } - } - } -} - -void -Schedules::DoReschedule(const Ice::Current & ice) -{ - auto ic = ice.adapter->getCommunicator(); - auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices"))); - unsigned int tunerCount = devs->TunerCount(); - - // Load list from database - ScheduleCandidates episodes; - SqlContainerCreator cct(episodes); - cct.populate(Select(Schedules_GetCandidates).second); - - Episodes scheduleList; - Showings allShowings; - EpisodePtr cur; - int minPriority = 0; - BOOST_FOREACH(const auto & c, episodes) { - if (!cur || cur->what != c->What) { - cur = new Episode(c->What); - scheduleList.push_back(cur); - } - ShowingPtr s = new Showing(c->ServiceId, c->EventId, c->TransportStreamId, c->ScheduleId, - c->StartTime, c->StopTime, c->Priority, cur.get()); - minPriority = std::min(minPriority, s->priority); - cur->showings.push_back(s); - allShowings.push_back(s); - } - Logger()->messagebf(LOG_DEBUG, "%d episodes created, %s showings", scheduleList.size(), allShowings.size()); - BOOST_FOREACH(const auto & e, scheduleList) { - Logger()->messagebf(LOG_DEBUG, " %s", e->what); - BOOST_FOREACH(const auto & s, e->showings) { - s->priority += 1 - minPriority; - e->priority += s->priority; - } - e->priority /= e->showings.size(); - } - - Records records; - // Solve - while (!scheduleList.empty()) { - auto work = scheduleList.begin(); - Logger()->messagebf(LOG_DEBUG, "start %s", (*work)->what); - Episodes group; - group.push_back(*work); - scheduleList.erase(work); - GetEpisodeIntersects(scheduleList, group); - std::sort(group.begin(), group.end(), [](const EpisodePtr & a, const EpisodePtr & b) { - if (a->priority > b->priority) return true; - if (a->priority < b->priority) return false; - return a->what < b->what; - }); - - Logger()->messagebf(LOG_DEBUG, "group created with %d episodes", group.size()); - double total = 1; - // Measure and add the optional to not record - BOOST_FOREACH(const auto & e, group) { - Logger()->messagebf(LOG_DEBUG, " %d * %d:%s", e->showings.size(), e->priority, e->what); - e->showings.push_back(NULL); - total *= e->showings.size(); - } - Logger()->messagebf(LOG_DEBUG, "group complexity of %d options", total); - - EpisodeGroupPtr sched = EpisodeGroupPtr(EpisodeGroupLoader::createNew(SchedulerAlgorithm, group)); - sched->tuners = tunerCount; - std::set selected; - BOOST_FOREACH(const auto & s, sched->Solve()) { - if (s) selected.insert(s); - } - - BOOST_FOREACH(const auto & c, group) { - Logger()->messagebf(LOG_DEBUG, "Episode %s, %d options", c->what, c->showings.size()); - BOOST_FOREACH(const auto & i, c->showings) { - if (selected.find(i) != selected.end()) { - Logger()->messagebf(LOG_DEBUG, " %s - %s (%d) <-", i->startTime, i->stopTime, i->transportStreamId); - } - else if (i) { - Logger()->messagebf(LOG_DEBUG, " %s - %s (%d)", i->startTime, i->stopTime, i->transportStreamId); - } - } - } - Logger()->message(LOG_DEBUG, "----------"); - BOOST_FOREACH(const auto & c, group) { - bool found = false; - BOOST_FOREACH(const auto & i, c->showings) { - if (i && selected.find(i) != selected.end()) { - found = true; - break; - } - } - BOOST_FOREACH(const auto & i, c->showings) { - if (i) { - records.push_back(RecordPtr(new Record(i->serviceId, i->eventId, - found ? - selected.find(i) != selected.end() ? Record_WillRecordThisShowing : Record_WillRecordOtherShowing : - Record_CannotRecordAnyShowing, i->scheduleId))); - } - } - } - } - - TxHelper tx(this); - SqlMergeTask mergeRecords("postgres", "record"); - CreateColumns(boost::bind(&DatabaseClient::SqlMergeColumnsInserter, &mergeRecords, _1, _2)); - mergeRecords.sources.insert(new ContainerIterator(&records)); - mergeRecords.loadComplete(this); - mergeRecords.execute(NULL); - tx.Commit(); - - auto recorder = P2PVR::RecorderPrx::checkedCast(ice.adapter->createProxy(ice.adapter->getCommunicator()->stringToIdentity("Recorder"))); - recorder->RefreshSchedules(); -} - -void -Schedules::DeleteSchedule(int id, const Ice::Current & ice) -{ - TxHelper tx(this); - Modify(Schedules_delete, id).second->execute(); - DoReschedule(ice); -} - -P2PVR::ScheduleList -Schedules::GetSchedules(const Ice::Current &) -{ - P2PVR::ScheduleList schedules; - SqlContainerCreator cct(schedules); - cct.populate(Select(Schedules_selectAll).second); - return schedules; -} - -P2PVR::SchedulePtr -Schedules::GetSchedule(int id, const Ice::Current &) -{ - P2PVR::ScheduleList schedules; - SqlContainerCreator cct(schedules); - cct.populate(Select(Schedules_selectById, id).second); - if (schedules.empty()) throw P2PVR::NotFound(); - return schedules.front(); -} - -P2PVR::ScheduledToRecordList -Schedules::GetScheduledToRecord(const Ice::Current &) -{ - P2PVR::ScheduledToRecordList scheduled; - SqlContainerCreator cct(scheduled); - cct.populate(Select(Schedules_scheduledToRecord).second); - return scheduled; -} - -int -Schedules::UpdateSchedule(const P2PVR::SchedulePtr & s, const Ice::Current & ice) -{ - TxHelper tx(this); - if (s->ScheduleId == 0) { - Modify(Schedules_insert, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats).second->execute(); - s->ScheduleId = SelectScalar(Schedules_insertNewId); - } - else { - Modify(Schedules_update, s->ServiceId, s->EventId, s->Title, s->Search, s->Priority, s->Early, s->Late, s->Repeats, s->ScheduleId).second->execute(); - } - DoReschedule(ice); - return s->ScheduleId; -} - -INSTANTIATESTORE(std::string, EpisodeGroupLoader); - diff --git a/p2pvr/lib/schedules.h b/p2pvr/lib/schedules.h deleted file mode 100644 index f7075dd..0000000 --- a/p2pvr/lib/schedules.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef SCHEDULER_H -#define SCHEDULER_H - -#include -#include -#include "dbClient.h" -#include - -typedef boost::posix_time::ptime datetime; -class Episode; - -class Showing : public IntrusivePtrBase { - public: - Showing(unsigned int s, unsigned int e, unsigned int t, unsigned int sc, datetime start, datetime stop, int p, const Episode * ep); - // Record what? - const Episode * episode; - const unsigned int serviceId; - const unsigned int eventId; - int priority; - const unsigned int scheduleId; - // Requires - const unsigned int transportStreamId; - const datetime startTime; - const datetime stopTime; - const boost::posix_time::time_period period; -}; -typedef boost::intrusive_ptr ShowingPtr; -typedef std::vector Showings; -typedef Showings::const_iterator ShowingsIter; - -class Episode : public IntrusivePtrBase { - public: - Episode(const std::string & w); - int priority; - const std::string what; - Showings showings; -}; -typedef boost::intrusive_ptr EpisodePtr; -typedef std::vector Episodes; -typedef Episodes::const_iterator EpisodesIter; - -class EpisodeGroup { - public: - EpisodeGroup(); - - const Showings & Solve(); - unsigned int tuners; - - protected: - enum SuggestionResult { - SuggestionInvalid = 0, SuggestionValid = 1, SuggestionValidAndAccepted = 3 - }; - SuggestionResult SuggestWithFeedback(const Showings &); - void Suggest(const Showings &); - virtual void SelectShowings() = 0; - - private: - bool IsShowingListValid(const Showings & showings) const; - // chosen set - time_t sumTimeToStart; - unsigned int score; - Showings selected; -}; - -class Schedules : public P2PVR::Schedules, public DatabaseClient { - public: - void DeleteSchedule(int id, const Ice::Current &); - P2PVR::SchedulePtr GetSchedule(int id, const Ice::Current &); - P2PVR::ScheduleList GetSchedules(const Ice::Current &); - P2PVR::ScheduledToRecordList GetScheduledToRecord(const Ice::Current &); - int UpdateSchedule(const P2PVR::SchedulePtr &, const Ice::Current &); - void DoReschedule(const Ice::Current &); - - INITOPTIONS; - protected: - static void GetEpisodeIntersects(Episodes &, Episodes &); - private: - static std::string SchedulerAlgorithm; -}; - -typedef GenLoader EpisodeGroupLoader; -typedef boost::shared_ptr EpisodeGroupPtr; - -#endif - diff --git a/p2pvr/lib/si.cpp b/p2pvr/lib/si.cpp deleted file mode 100644 index b358f72..0000000 --- a/p2pvr/lib/si.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include "si.h" -#include "resources.h" -#include "dvbsiHelpers.h" -#include "sqlContainerCreator.h" -#include -#include - -ResourceString(SI_serviceNextUsed, lib_sql_SI_serviceNextUsed_sql); -ResourceString(SI_servicesSelectAll, lib_sql_SI_servicesSelectAll_sql); -ResourceString(SI_servicesSelectById, lib_sql_SI_servicesSelectById_sql); -ResourceString(SI_eventById, lib_sql_SI_eventById_sql); -ResourceString(SI_eventsOnNow, lib_sql_SI_eventsOnNow_sql); -ResourceString(SI_eventsInRange, lib_sql_SI_eventsInRange_sql); - -P2PVR::Deliveries -SI::GetAllDeliveries(short type, const Ice::Current &) -{ - Logger()->messagebf(LOG_DEBUG, "%s(type %d)", __PRETTY_FUNCTION__, type); - P2PVR::Deliveries rtn; - SelectPtr sel; - switch (type) { - case FE_OFDM: - { - SqlContainerCreator cc(rtn); - cc.populate(Select("SELECT * FROM delivery_dvbt ORDER BY transportStreamId").second); - break; - } - case FE_QAM: - { - SqlContainerCreator cc(rtn); - cc.populate(Select("SELECT * FROM delivery_dvbc ORDER BY transportStreamId").second); - break; - } - case FE_QPSK: - { - SqlContainerCreator cc(rtn); - cc.populate(Select("SELECT * FROM delivery_dvbs ORDER BY transportStreamId").second); - break; - } - } - Logger()->messagebf(LOG_DEBUG, "%s: Found %d delivery methods", __PRETTY_FUNCTION__, rtn.size()); - return rtn; -} - -DVBSI::DeliveryPtr -SI::GetDeliveryForTransport(int id, const Ice::Current&) -{ - P2PVR::Deliveries rtn; - SqlContainerCreator cct(rtn); - cct.populate(Select("SELECT * FROM delivery_dvbt WHERE transportStreamId = ?", id).second); - SqlContainerCreator ccc(rtn); - ccc.populate(Select("SELECT * FROM delivery_dvbc WHERE transportStreamId = ?", id).second); - SqlContainerCreator ccs(rtn); - ccs.populate(Select("SELECT * FROM delivery_dvbs WHERE transportStreamId = ?", id).second); - return rtn.front(); -} - -DVBSI::DeliveryPtr -SI::GetDeliveryForSi(const Ice::Current&) -{ - P2PVR::Deliveries rtn; - SqlContainerCreator cct(rtn); - cct.populate(Select(SI_serviceNextUsed).second); - return rtn.front(); -} - -DVBSI::DeliveryPtr -SI::GetDeliveryForService(int id, const Ice::Current&) -{ - P2PVR::Deliveries rtn; - SqlContainerCreator cct(rtn); - cct.populate(Select("SELECT d.* FROM services s, delivery_dvbt d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); - SqlContainerCreator ccc(rtn); - ccc.populate(Select("SELECT d.* FROM services s, delivery_dvbc d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); - SqlContainerCreator ccs(rtn); - ccs.populate(Select("SELECT d.* FROM services s, delivery_dvbs d WHERE serviceid = ? AND s.transportstreamid = d.transportstreamid", id).second); - return rtn.front(); -} - -DVBSI::ServiceList -SI::GetServices(const Ice::Current&) -{ - DVBSI::ServiceList rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(SI_servicesSelectAll).second); - return rtn; -} - -DVBSI::ServicePtr -SI::GetService(int id, const Ice::Current&) -{ - DVBSI::ServiceList rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(SI_servicesSelectById, id).second); - if (rtn.empty()) throw P2PVR::NotFound(); - return rtn.front(); -} - -DVBSI::EventPtr -SI::GetEvent(int serviceId, int eventId, const Ice::Current &) -{ - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(SI_eventById, serviceId, eventId).second); - if (rtn.empty()) throw P2PVR::NotFound(); - return rtn.front(); -} - -DVBSI::Events -SI::EventsOnNow(const Ice::Current &) -{ - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(SI_eventsOnNow).second); - return rtn; -} - -DVBSI::Events -SI::EventsInRange(const Common::DateTime & from, const Common::DateTime & to, const Ice::Current &) -{ - DVBSI::Events rtn; - SqlContainerCreator cc(rtn); - cc.populate(Select(SI_eventsInRange, from, to).second); - return rtn; -} - diff --git a/p2pvr/lib/si.h b/p2pvr/lib/si.h deleted file mode 100644 index 6b720dc..0000000 --- a/p2pvr/lib/si.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef P2PVR_SI_H -#define P2PVR_SI_H - -#include -#include "dbClient.h" - -class SI : public P2PVR::SI, public DatabaseClient { - public: - P2PVR::Deliveries GetAllDeliveries(short type, const Ice::Current &); - DVBSI::DeliveryPtr GetDeliveryForService(int id, const Ice::Current &); - DVBSI::DeliveryPtr GetDeliveryForTransport(int id, const Ice::Current &); - DVBSI::DeliveryPtr GetDeliveryForSi(const Ice::Current &); - - DVBSI::ServiceList GetServices(const Ice::Current &); - DVBSI::ServicePtr GetService(int id, const Ice::Current &); - - DVBSI::EventPtr GetEvent(int serviceId, int eventId, const Ice::Current &); - DVBSI::Events EventsOnNow(const Ice::Current &); - DVBSI::Events EventsInRange(const Common::DateTime &, const Common::DateTime &, const Ice::Current &); -}; - -#endif - diff --git a/p2pvr/lib/siParsers/event.cpp b/p2pvr/lib/siParsers/event.cpp deleted file mode 100644 index c094331..0000000 --- a/p2pvr/lib/siParsers/event.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "event.h" - -struct ShortEvent { - char lang_code[3]; - uint8_t event_name_length; - u_char data[]; -} __attribute__((packed)); - -struct Component { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char :4; - u_char stream_content :4; -#else - u_char stream_content :4; - u_char :4; -#endif - u_char component_type /*:8*/; - u_char component_tag /*:8*/; - char lang_code[3]; -} __attribute__((packed)); - -struct Content { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t content_nibble_level_1 :4; - uint8_t content_nibble_level_2 :4; -#else - uint8_t content_nibble_level_2 :4; - uint8_t content_nibble_level_1 :4; -#endif - uint8_t user_byte; -}; - -struct ParentalRating { - char country_code[3]; - uint8_t rating; -} __attribute__((packed)); - -struct EventDescriptor { - uint16_t EventId; - uint16_t mjd; - uint8_t start_time_h; - uint8_t start_time_m; - uint8_t start_time_s; - uint8_t duration_h; - uint8_t duration_m; - uint8_t duration_s; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char RunningStatus : 3; - u_char FreeCaMode : 1; - u_char descriptors_length_hi : 4; -#else - u_char descriptors_length_hi : 4; - u_char FreeCaMode : 1; - u_char RunningStatus : 3; -#endif - u_char descriptors_length_lo; - u_char data[]; -} __attribute__((packed)); - -static Glib::RefPtr episodeRegex = Glib::Regex::create("(?:[ (]+|^)(?:\\w+ )?([0-9]+)(?: of |/)([0-9]+)(?:[.)]+|$)"); -static Glib::RefPtr seasonEpisodeRegex = Glib::Regex::create("[ ([]*[Ss]\\s*([0-9]+)[ ,]*[Ee][Pp]?\\s*([0-9]+)[).\\]]*"); -static Glib::RefPtr yearRegex = Glib::Regex::create("[[(]([0-9]{4})[ ).\\]]+"); -static Glib::RefPtr flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]"); - -void -SiEpgParser::parseDescriptor_ShortEvent(DVBSI::EventPtr current, const u_char * data) -{ - auto * evtdesc = reinterpret_cast(data); - StrPtr title, subtitle, desc; - - current->TitleLang = std::string(evtdesc->lang_code, 3); - - size_t evtlen = evtdesc->event_name_length; - if (evtlen) { - title = convert((const char *)evtdesc->data, evtlen); - } - - size_t dsclen = evtdesc->data[evtlen]; - if (dsclen) { - subtitle = convert((const char *)evtdesc->data + evtlen + 1, dsclen); - } - - if (subtitle) { - Glib::MatchInfo matches; - if (yearRegex->match(*subtitle, matches)) { - current->Year = boost::lexical_cast(matches.fetch(1)); - *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); - } - if (flagsRegex->match(*subtitle, matches)) { - current->Flags = matches.fetch(1); - *subtitle = flagsRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); - } - if (episodeRegex->match(*subtitle, matches)) { - current->Episode = boost::lexical_cast(matches.fetch(1)); - current->Episodes = boost::lexical_cast(matches.fetch(2)); - if (*current->Episode <= *current->Episodes) { // fudge to catch "24/7" - *subtitle = episodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); - } - } - if (seasonEpisodeRegex->match(*subtitle, matches)) { - current->Season = boost::lexical_cast(matches.fetch(1)); - current->Episode = boost::lexical_cast(matches.fetch(2)); - *subtitle = seasonEpisodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY); - } - } - if (title && subtitle) { - if (boost::algorithm::ends_with(*title, "...") && boost::algorithm::starts_with(*subtitle, "...")) { - title->resize(title->length() - 3); - *title += " "; - size_t dot = subtitle->find('.', 4); - if (dot == Glib::ustring::npos) { - title->append(*subtitle, 3, subtitle->length() - 3); - } - else { - title->append(*subtitle, 3, dot - 3); - subtitle->erase(0, dot + 2); - } - } - size_t colon = subtitle->find(':'); - if (colon != Glib::ustring::npos) { - desc = StrPtr(new Glib::ustring(*subtitle, colon + 1, subtitle->length() - colon)); - subtitle->resize(colon); - } - else { - colon = title->find(':'); - desc = subtitle; - if (colon != Glib::ustring::npos) { - subtitle = StrPtr(new Glib::ustring(*title, colon + 1, title->length() - colon)); - title->resize(colon); - } - else { - subtitle.reset(); - } - } - } - if (title) { - boost::algorithm::trim_if(*title, isspace); - current->Title = *title; - } - if (subtitle) { - boost::algorithm::trim_if(*subtitle, isspace); - if (!subtitle->empty()) { - current->Subtitle = *subtitle; - } - } - if (desc) { - boost::algorithm::trim_if(*desc, isspace); - if (!desc->empty()) { - current->Description = *desc; - } - } -} - -void -SiEpgParser::parseDescriptor_Component(DVBSI::EventPtr current, const u_char * data) -{ - auto * dc = reinterpret_cast(data); - - switch (dc->stream_content) { - case 0x01: // Video Info - current->VideoHD = ((dc->component_type - 1) & 0x08) ? 1 : 0; - current->VideoFrameRate = ((dc->component_type - 1) & 0x04) ? 30 : 25; - current->VideoAspect = ((dc->component_type - 1) & 0x03); - break; - case 0x02: // Audio Info - current->AudioChannels = dc->component_type; - current->AudioLanguage = Glib::ustring(dc->lang_code, 3); - break; - case 0x03: // Teletext Info - current->SubtitleLanguage = Glib::ustring(dc->lang_code, 3); - break; - } -} - -void -SiEpgParser::parseDescriptor_Content(DVBSI::EventPtr current, const u_char * data) -{ - auto nc = reinterpret_cast(data); - current->Category = nc->content_nibble_level_1; - current->SubCategory = nc->content_nibble_level_2; - current->UserCategory = nc->user_byte; -} - -void -SiEpgParser::parseDescriptor_ParentalRating(DVBSI::EventPtr current, const u_char * data) -{ - auto * pr = reinterpret_cast(data); - switch (pr->rating) { - case 0x01 ... 0x0F: - current->DvbRating = pr->rating + 3; - break; - case 0x00: /*undefined*/ - case 0x10 ... 0xFF: /*broadcaster defined*/ - current->DvbRating = NULL; - break; - } -} - -bool -SiEpgParser::CheckTableId(u_char tableId) const -{ - return ((tableId >= 0x50 && tableId <= 0x5f) || (tableId >= 0x60 && tableId <= 0x6f)); -} - -bool -SiEpgParser::HandleTable(DVBSI::EitInformationPtr) -{ - return false; -} - -Common::DateTime & -operator<<(Common::DateTime & dt, const boost::posix_time::ptime & pt) -{ - dt.Year = pt.date().year(); - dt.Month = pt.date().month(); - dt.Day = pt.date().day(); - dt.Hour = pt.time_of_day().hours(); - dt.Minute = pt.time_of_day().minutes(); - return dt; -} - -void -SiEpgParser::ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr ei) -{ - ei->ServiceId = ntohs(eit->header.content_id); - ei->TransportStreamId = ntohs(eit->TransportStreamId); - ei->OriginalNetworkId = ntohs(eit->OriginalNetworkId); - LoopOver(eit->data, HILO(eit->header.section_length) - 15, [this,ei](const EventDescriptor * ed) { - DVBSI::EventPtr e = new DVBSI::Event(); - e->EventId = ntohs(ed->EventId); - e->ServiceId = ei->ServiceId; - // - boost::gregorian::date startDate(boost::gregorian::gregorian_calendar::from_modjulian_day_number(ntohs(ed->mjd))); - boost::posix_time::ptime time(startDate); - time += boost::posix_time::time_duration(BcdCharToInt(ed->start_time_h), BcdCharToInt(ed->start_time_m), BcdCharToInt(ed->start_time_s)); - e->StartTime << time; - time += boost::posix_time::time_duration(BcdCharToInt(ed->duration_h), BcdCharToInt(ed->duration_m), BcdCharToInt(ed->duration_s)); - e->StopTime << time; - // - ParseDescriptors(ed->data, HILO(ed->descriptors_length), - 0x4d, boost::bind(&SiEpgParser::parseDescriptor_ShortEvent, e, _1), - 0x50, boost::bind(&SiEpgParser::parseDescriptor_Component, e, _1), - 0x54, boost::bind(&SiEpgParser::parseDescriptor_Content, e, _1), - 0x55, boost::bind(&SiEpgParser::parseDescriptor_ParentalRating, e, _1)); - HandleTable(e); - }); -} - diff --git a/p2pvr/lib/siParsers/event.h b/p2pvr/lib/siParsers/event.h deleted file mode 100644 index 6b316cc..0000000 --- a/p2pvr/lib/siParsers/event.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef EPGROWS_H -#define EPGROWS_H - -#include "table.h" -#include - -struct EventInformation { - SiTableHeader header; - uint16_t TransportStreamId; - uint16_t OriginalNetworkId; - uint8_t SegmentLastSectionNumber; - uint8_t LastTableId; - u_char data[]; -} __attribute__((packed)); - -class SiEpgParser : public SiTableParser { - protected: - bool CheckTableId(u_char tableId) const; - int SectionNumberShift() const { return 3; } - uint8_t FirstTableId(const EventInformation * ei) { return (ei->header.tableid >= 0x60 ? 0x60 : 0x50); } - uint8_t LastTableId(const EventInformation * ei) { return ei->LastTableId; } - void ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr); - bool HandleTable(DVBSI::EitInformationPtr); - virtual void HandleTable(DVBSI::EventPtr) = 0; - - private: - static void parseStartTimeAndDuration(DVBSI::EventPtr, const u_char * data); - static void parseDescriptor_ShortEvent(DVBSI::EventPtr, const u_char * data); - static void parseDescriptor_Component(DVBSI::EventPtr, const u_char * data); - static void parseDescriptor_Content(DVBSI::EventPtr, const u_char * data); - static void parseDescriptor_ParentalRating(DVBSI::EventPtr, const u_char * data); -}; - -#endif - diff --git a/p2pvr/lib/siParsers/network.cpp b/p2pvr/lib/siParsers/network.cpp deleted file mode 100644 index b91da1a..0000000 --- a/p2pvr/lib/siParsers/network.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include -#include "network.h" -#include -#include -#include -#include - -struct NetworkStreamsHeader { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved1 :4; - u_char transport_stream_loop_length_hi :4; -#else - u_char transport_stream_loop_length_hi :4; - u_char reserved1 :4; -#endif - u_char transport_stream_loop_length_lo; - u_char data[]; -} __attribute__((packed)); - -struct TransportStream { - uint16_t transportStreamId; - uint16_t originalNetworkId; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved1 :4; - u_char descriptors_length_hi :4; -#else - u_char descriptors_length_hi :4; - u_char reserved1 :4; -#endif - u_char descriptors_length_lo; - u_char data[]; -} __attribute__((packed)); - -struct TerrestrialDeliveryDescriptor { - uint32_t Frequency; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t Bandwidth : 3; - uint8_t Priority : 1; - uint8_t TimeSlicing : 1; - uint8_t MpeFec : 1; - uint8_t _reserved1 : 2; -#else - uint8_t _reserved1 : 2; - uint8_t MpeFec : 1; - uint8_t TimeSlicing : 1; - uint8_t Priority : 1; - uint8_t Bandwidth : 3; -#endif -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t Constellation : 2; - uint8_t Hierarchy : 3; - uint8_t CodeRateHP : 3; -#else - uint8_t CodeRateHP : 3; - uint8_t Hierarchy : 3; - uint8_t Constellation : 2; -#endif -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t CodeRateLP : 3; - uint8_t GuardInterval : 2; - uint8_t TransmissionMode : 2; - uint8_t OtherFrequencyFlag : 1; -#else - uint8_t OtherFrequencyFlag : 1; - uint8_t TransmissionMode : 2; - uint8_t GuardInterval : 2; - uint8_t CodeRateLP : 3; -#endif - uint32_t _reserved2; -} __attribute__((packed)); - -struct CableDeliveryDescriptor { - uint32_t Frequency; - uint8_t _reserved2; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t _reserved1 : 4; - uint8_t FecOuter : 4; -#else - uint8_t FecOuter : 4; - uint8_t _reserved1 : 4; -#endif - uint8_t Modulation; - uint8_t SymbolRate1; - uint8_t SymbolRate2; - uint8_t SymbolRate3; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t SymbolRate4 : 4; - uint8_t FecInner : 4; -#else - uint8_t FecInner : 4; - uint8_t SymbolRate4 : 4; -#endif -} __attribute__((packed)); - -struct SatelliteDeliveryDescriptor { - uint32_t Frequency; - uint16_t OrbitalPosition; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t WestEastFlag : 1; - uint8_t Polarization : 2; - uint8_t RollOff : 2; - uint8_t ModulationSystem : 1; - uint8_t ModulationType : 2; -#else - uint8_t ModulationType : 2; - uint8_t ModulationSystem : 1; - uint8_t RollOff : 2; - uint8_t Polarization : 2; - uint8_t WestEastFlag : 1; -#endif - uint8_t SymbolRate1; - uint8_t SymbolRate2; - uint8_t SymbolRate3; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t SymbolRate4 : 4; - uint8_t FecInner : 4; -#else - uint8_t FecInner : 4; - uint8_t SymbolRate4 : 4; -#endif -} __attribute__((packed)); - -struct ServiceListDescriptor { - uint16_t ServiceId; - uint8_t ServiceType; -} __attribute__((packed)); - -bool -SiNetworkInformationParser::CheckTableId(u_char tableId) const -{ - return (tableId == 0x40 || tableId == 0x041); -} - -void -SiNetworkInformationParser::ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr n) -{ - n->NetworkId = ntohs(nit->header.content_id); - auto nsh = ParseDescriptors(nit->data, HILO(nit->network_descriptor_length), - 0x40, boost::bind(&SiNetworkInformationParser::parseDescriptor_NetworkName, n, _1, _2)); - LoopOver(nsh->data, HILO(nsh->transport_stream_loop_length), [this,n](const TransportStream * ts) { - DVBSI::NetworkTransportStreamPtr nts = new DVBSI::NetworkTransportStream(); - nts->TransportStreamId = ntohs(ts->transportStreamId); - nts->NetworkId = n->NetworkId; - nts->OriginalNetworkId = ntohs(ts->originalNetworkId); - ParseDescriptors(ts->data, HILO(ts->descriptors_length), - 0x41, boost::bind(&SiNetworkInformationParser::parseDescriptor_ServiceList, nts, _1, _2), - 0x43, boost::bind(&SiNetworkInformationParser::parseDescriptor_SatelliteDelivery, nts, _1, _2), - 0x44, boost::bind(&SiNetworkInformationParser::parseDescriptor_CableDelivery, nts, _1, _2), - 0x5a, boost::bind(&SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery, nts, _1, _2)); - n->TransportStreams.push_back(nts); - }); -} - -void -SiNetworkInformationParser::parseDescriptor_NetworkName(DVBSI::NetworkPtr n, const u_char * p, size_t len) -{ - n->Name = *convert((const char *)p, len); -} - -#define SINOTSUPPORTED(What) \ -class What##NotSupported : public NotSupported { public: What##NotSupported(short id) : NotSupported(stringbf(#What" 0x%2x", id)) { } }; - -std::map tbandwidths { - {0, BANDWIDTH_8_MHZ}, - {1, BANDWIDTH_7_MHZ}, - {2, BANDWIDTH_6_MHZ}, - {3, BANDWIDTH_5_MHZ} -}; -SINOTSUPPORTED(Bandwidth); - -std::map tconstellations { - {0, QPSK}, - {1, QAM_16}, - {2, QAM_64} -}; -SINOTSUPPORTED(Constellation); - -std::map thierarchies { - {0, HIERARCHY_NONE}, - {1, HIERARCHY_1}, - {2, HIERARCHY_2}, - {3, HIERARCHY_4}, - {4, HIERARCHY_NONE}, - {5, HIERARCHY_1}, - {6, HIERARCHY_2}, - {7, HIERARCHY_4} -}; -SINOTSUPPORTED(Hierarchy); - -std::map tcoderates { - {0, FEC_1_2}, - {1, FEC_2_3}, - {2, FEC_3_4}, - {3, FEC_5_6}, - {4, FEC_7_8} -}; -SINOTSUPPORTED(CodeRate); - -std::map tguardintervals { - {0, GUARD_INTERVAL_1_32}, - {1, GUARD_INTERVAL_1_16}, - {2, GUARD_INTERVAL_1_8}, - {3, GUARD_INTERVAL_1_4} -}; -SINOTSUPPORTED(GuardInterval); - -std::map ttransmitmodes { - {0, TRANSMISSION_MODE_2K}, - {1, TRANSMISSION_MODE_8K}, - {2, TRANSMISSION_MODE_4K} -}; -SINOTSUPPORTED(TransmissionMode); - -void -SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) -{ - assert(len == sizeof(TerrestrialDeliveryDescriptor)); - auto tdd = reinterpret_cast(data); - DVBSI::TerrestrialDeliveryPtr td = new DVBSI::TerrestrialDelivery; - td->Frequency = ((uint64_t)ntohl(tdd->Frequency)) * 10; - td->TransportStreamId = nts->TransportStreamId; - td->Bandwidth = safeMapLookup(tbandwidths, tdd->Bandwidth); - td->Priority = tdd->Priority; - td->TimeSlicing = tdd->TimeSlicing; - td->MpeFec = tdd->MpeFec; - td->Constellation = safeMapLookup(tconstellations, tdd->Constellation); - td->Hierarchy = safeMapLookup(thierarchies, tdd->Hierarchy); - td->CodeRateHP = safeMapLookup(tcoderates, tdd->CodeRateHP); - td->CodeRateLP = safeMapLookup(tcoderates, tdd->CodeRateLP); - td->GuardInterval = safeMapLookup(tguardintervals, tdd->GuardInterval); - td->TransmissionMode = safeMapLookup(ttransmitmodes, tdd->TransmissionMode); - td->OtherFrequencyFlag = tdd->OtherFrequencyFlag; - nts->Terrestrial = td; -} - -void -SiNetworkInformationParser::parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) -{ - assert(len == sizeof(CableDeliveryDescriptor)); - auto cdd = reinterpret_cast(data); - DVBSI::CableDeliveryPtr cd = new DVBSI::CableDelivery; - cd->Frequency = ((uint64_t)ntohl(cdd->Frequency)) * 10; - cd->TransportStreamId = nts->TransportStreamId; - cd->FecOuter = cdd->FecOuter; - cd->Modulation = cdd->Modulation; - cd->SymbolRate = HILO4(cdd->SymbolRate); - cd->FecInner = cdd->FecInner; - nts->Cable = cd; -} - -void -SiNetworkInformationParser::parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) -{ - assert(len == sizeof(SatelliteDeliveryDescriptor)); - auto sdd = reinterpret_cast(data); - DVBSI::SatelliteDeliveryPtr sd = new DVBSI::SatelliteDelivery; - sd->Frequency = ((uint64_t)ntohl(sdd->Frequency)) * 10; - sd->TransportStreamId = nts->TransportStreamId; - sd->OrbitalPosition = ntohs(sdd->OrbitalPosition); - sd->WestEastFlag = sdd->WestEastFlag; - sd->Polarization = sdd->Polarization; - sd->RollOff = sdd->RollOff; - sd->ModulationSystem = sdd->ModulationSystem; - sd->ModulationType = sdd->ModulationType; - sd->SymbolRate = HILO4(sdd->SymbolRate); - sd->FecInner = sdd->FecInner; - nts->Satellite = sd; -} - -void -SiNetworkInformationParser::parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len) -{ - auto end = data + len; - while (data < end) { - auto d = reinterpret_cast(data); - nts->Services.push_back({ ntohs(d->ServiceId), nts->TransportStreamId, d->ServiceType }); - data += sizeof(ServiceListDescriptor); - } -} - - diff --git a/p2pvr/lib/siParsers/network.h b/p2pvr/lib/siParsers/network.h deleted file mode 100644 index 4f8e6e3..0000000 --- a/p2pvr/lib/siParsers/network.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef NETWORKINFORMATIONPARSER_H -#define NETWORKINFORMATIONPARSER_H - -#include "table.h" -#include - -struct NetworkInformation { - SiTableHeader header; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved2 :4; - u_char network_descriptor_length_hi :4; -#else - u_char network_descriptor_length_hi :4; - u_char reserved2 :4; -#endif - u_char network_descriptor_length_lo /*:8*/; - u_char data[]; -} __attribute__((packed)); - -class SiNetworkInformationParser : public SiTableParser { - protected: - bool CheckTableId(u_char tableId) const; - void ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr); - - private: - static void parseDescriptor_NetworkName(DVBSI::NetworkPtr, const u_char *data, size_t len); - static void parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); - static void parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); - static void parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); - static void parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len); -}; - -#endif - - diff --git a/p2pvr/lib/siParsers/programAssociation.cpp b/p2pvr/lib/siParsers/programAssociation.cpp deleted file mode 100644 index 7839b9e..0000000 --- a/p2pvr/lib/siParsers/programAssociation.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include "programAssociation.h" - -struct ProgramAssociation { - uint16_t program_number; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint8_t reserved : 3; - uint8_t pid_hi : 5; -#else - uint8_t pid_hi : 5; - uint8_t reserved : 3; -#endif - uint8_t pid_lo; -}; - -bool -SiProgramAssociationParser::CheckTableId(u_char tableId) const -{ - return (tableId == 0x00); -} - -void -SiProgramAssociationParser::ParseSiTable(const ProgramAssociationSection * pas, ProgramAssociationMapPtr pam) -{ - LoopOverSection(pas->data, HILO(pas->header.section_length) - 12, [this,pam](const ProgramAssociation * sd) { - (*pam)[ntohs(sd->program_number)] = HILO(sd->pid); - }); -} - - diff --git a/p2pvr/lib/siParsers/programAssociation.h b/p2pvr/lib/siParsers/programAssociation.h deleted file mode 100644 index 653be0c..0000000 --- a/p2pvr/lib/siParsers/programAssociation.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef PROGRAMASSOCIATION_H -#define PROGRAMASSOCIATION_H - -#include "table.h" -#include - -struct ProgramAssociationSection { - SiTableHeader header; - u_char data[]; -} __attribute__((packed)); - -typedef std::map ProgramAssociationMap; -typedef boost::shared_ptr ProgramAssociationMapPtr; - -class SiProgramAssociationParser : public SiTableParser { - protected: - bool CheckTableId(u_char tableId) const; - void ParseSiTable(const struct ProgramAssociationSection * pas, ProgramAssociationMapPtr); -}; - -#endif - - diff --git a/p2pvr/lib/siParsers/programMap.cpp b/p2pvr/lib/siParsers/programMap.cpp deleted file mode 100644 index 1ba78c4..0000000 --- a/p2pvr/lib/siParsers/programMap.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "programMap.h" -#include -#include - -struct ProgramMapStream { - uint8_t stream_type; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved1 :3; - u_char elementary_PID_hi :5; -#else - u_char elementary_PID_hi :5; - u_char reserved1 :3; -#endif - u_char elementary_PID_lo; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved2 :4; - u_char ES_info_length_hi :4; -#else - u_char ES_info_length_hi :4; - u_char reserved2 :4; -#endif - u_char ES_info_length_lo; - u_char data[]; -}; - - -bool -SiProgramMapParser::CheckTableId(u_char tableId) const -{ - return (tableId == 0x02); -} - -void -SiProgramMapParser::ParseSiTable(const struct ProgramMap * pm, DVBSI::ProgramMapPtr pmp) -{ - pmp->ServiceId = ntohs(pm->header.content_id); - auto pms = ParseDescriptors(pm->data, HILO(pm->program_info_len)); - while (reinterpret_cast(pms) < &pm->header.section_length_lo + HILO(pm->header.section_length) - 4) { - DVBSI::StreamPtr s = new DVBSI::Stream(); - s->Type = pms->stream_type; - s->Id = HILO(pms->elementary_PID); - s->ServiceId = pmp->ServiceId; - pmp->Streams.push_back(s); - // Don't care what's in here, just need to move along - pms = ParseDescriptors(pms->data, HILO(pms->ES_info_length)); - } -} diff --git a/p2pvr/lib/siParsers/programMap.h b/p2pvr/lib/siParsers/programMap.h deleted file mode 100644 index 07821b5..0000000 --- a/p2pvr/lib/siParsers/programMap.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef PROGRAMMAP_H -#define PROGRAMMAP_H - -#include "table.h" -#include - -struct ProgramMap { - SiTableHeader header; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved1 :3; - u_char pcr_pid_hi :5; -#else - u_char pcr_pid_hi :5; - u_char reserved1 :3; -#endif - u_char pcr_pid_lo; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved2 :4; - u_char program_info_len_hi :4; -#else - u_char program_info_len_hi :4; - u_char reserved2 :4; -#endif - u_char program_info_len_lo; - u_char data[]; -} __attribute__((packed)); - -class SiProgramMapParser : public SiTableParser { - protected: - bool CheckTableId(u_char tableId) const; - void ParseSiTable(const struct ProgramMap * nit, DVBSI::ProgramMapPtr); -}; - -#endif - - - diff --git a/p2pvr/lib/siParsers/service.cpp b/p2pvr/lib/siParsers/service.cpp deleted file mode 100644 index fbcd966..0000000 --- a/p2pvr/lib/siParsers/service.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include "service.h" -#include - -struct ServiceDescriptor { - uint16_t ServiceId; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char _reserved1 : 6; - u_char EitSchedule : 1; - u_char EitPresentFollowing : 1; -#else - u_char EitPresentFollowing : 1; - u_char EitSchedule : 1; - u_char _reserved1 : 6; -#endif -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char RunningStatus : 3; - u_char FreeCaMode : 1; - u_char descriptors_length_hi : 4; -#else - u_char descriptors_length_hi : 4; - u_char FreeCaMode : 1; - u_char RunningStatus : 3; -#endif - u_char descriptors_length_lo; - u_char data[]; -} __attribute__((packed)); - -bool -SiServicesParser::CheckTableId(u_char tableId) const -{ - return (tableId == 0x42 || tableId == 0x46); -} - -void -SiServicesParser::ParseSiTable(const TransportStreamDescriptor * tsd, DVBSI::TransportStreamPtr ts) -{ - ts->TransportStreamId = ntohs(tsd->header.content_id); - ts->OriginalNetworkId = ntohs(tsd->original_network_id); - LoopOver(tsd->data, HILO(tsd->header.section_length) - 12, [this,ts](const ServiceDescriptor * sd) { - DVBSI::ServicePtr s = new DVBSI::Service(); - s->ServiceId = ntohs(sd->ServiceId); - s->TransportStreamId = ts->TransportStreamId; - s->EitSchedule = sd->EitSchedule; - s->EitPresentFollowing = sd->EitPresentFollowing; - s->RunningStatus = sd->RunningStatus; - s->FreeCaMode = sd->FreeCaMode; - ParseDescriptors(sd->data, HILO(sd->descriptors_length), - 0x48, boost::bind(&SiServicesParser::parseDescriptor_Service, s, _1, _2), - 0x73, boost::bind(&SiServicesParser::parseDescriptor_DefaultAuthority, s, _1, _2)); - ts->Services.push_back(s); - }); -} - -void -SiServicesParser::parseDescriptor_Service(DVBSI::ServicePtr s, const u_char * p, size_t) -{ - s->Type = p[0]; - if (p[1]) { - s->ProviderName = *convert((const char *)(p + 2), p[1]); - } - s->Name = *convert((const char *)(p + 3 + p[1]), p[2 + p[1]]); -} - -void -SiServicesParser::parseDescriptor_DefaultAuthority(DVBSI::ServicePtr s, const u_char * p, size_t len) -{ - s->DefaultAuthority = *convert((const char *)p, len); -} - diff --git a/p2pvr/lib/siParsers/service.h b/p2pvr/lib/siParsers/service.h deleted file mode 100644 index 611eb90..0000000 --- a/p2pvr/lib/siParsers/service.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SERVICEROWS_H -#define SERVICEROWS_H - -#include "table.h" -#include - -struct TransportStreamDescriptor { - SiTableHeader header; - uint16_t original_network_id; - uint8_t _reserved1; - u_char data[]; -} __attribute__((packed)); - -class SiServicesParser : public SiTableParser { - protected: - bool CheckTableId(u_char tableId) const; - void ParseSiTable(const struct TransportStreamDescriptor * nit, DVBSI::TransportStreamPtr); - - private: - static void parseDescriptor_Service(DVBSI::ServicePtr, const u_char *data, size_t len); - static void parseDescriptor_DefaultAuthority(DVBSI::ServicePtr, const u_char *data, size_t len); -}; - -#endif - diff --git a/p2pvr/lib/siParsers/table.cpp b/p2pvr/lib/siParsers/table.cpp deleted file mode 100644 index 9844814..0000000 --- a/p2pvr/lib/siParsers/table.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include "table.h" -#include -#include -#include -#include -#include - -SimpleMessageException(ErrorReadingData); -SimpleMessageException(TimeoutReadingData); -SimpleMessageException(DemuxOpenFailure); - -const std::string SiTableParserBase::ISO10646("ISO-10646"); -const std::string SiTableParserBase::EitEncoding("ISO6937"); -const std::string SiTableParserBase::UTF8("UTF8"); - -SiTableParserBase::SiTableParserBase() : - startTime(time(NULL)), - incomplete(0) -{ -} - -SiTableParserBase::~SiTableParserBase() -{ -} - -bool -SiTableParserBase::NewData(const P2PVR::Data & bytes, const Ice::Current&) -{ - //Logger()->messagebf(LOG_DEBUG, "%s: Got %d bytes", __PRETTY_FUNCTION__, bytes.size()); - currentRawData = &bytes; - return ParseInfoTable(&bytes.front(), bytes.size()); -} - -const P2PVR::Data & -SiTableParserBase::CurrentRawData() const -{ - return *currentRawData; -} - -SiTableParserBase::StrPtr -SiTableParserBase::convert(const char * txt, size_t len) -{ - if (len == 0) { - return boost::shared_ptr(new Glib::ustring()); - } - char enc[20]; - switch (*txt) { - default: - EitEncoding.copy(enc, EitEncoding.length()); - enc[EitEncoding.length()] = '\0'; - break; - case 0x01 ... 0x05: - snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4); - txt += 1; - len -= 1; - break; - case 0x10: - snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]); - txt += 3; - len -= 3; - break; - case 0x11: - ISO10646.copy(enc, ISO10646.length()); - enc[ISO10646.length()] = '\0'; - break; - case 0x1F: - // Values for the first byte of "0x00", "0x06" to "0x0F", and "0x12" to "0x1F" are reserved for future use. - //fprintf(stderr, "Reserved encoding: %02x\n", txt[0]); - //fprintf(stderr, "%d: %.*s\n", txt[1], len - 2, txt + 2); - case 0x06 ... 0x0F: - case 0x12 ... 0x1E: - case 0x00: // empty string - return boost::shared_ptr(new Glib::ustring()); - } - size_t used = 0, newlen = 0; - GError * err = NULL; - boost::shared_ptr utf8 = boost::shared_ptr(g_convert(txt, len, "utf-8", enc, &used, &newlen, &err), g_free); - if (err) { - throw Glib::ConvertError(err); - } - return boost::shared_ptr(new Glib::ustring(utf8.get())); -} - diff --git a/p2pvr/lib/siParsers/table.h b/p2pvr/lib/siParsers/table.h deleted file mode 100644 index c470159..0000000 --- a/p2pvr/lib/siParsers/table.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef DVBSIREADERHELPER_H -#define DVBSIREADERHELPER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned char u_char; - -#define HILO(x) (x##_hi << 8 | x##_lo) -#define HILO2(x) (x##1 << 8 | x##2) -#define HILO3(x) (x##1 << 16 | x##2 << 8 | x##3) -#define HILO4(x) (x##4 << 24 | x##2 << 16 | x##3 << 8 | x##4) -#define BcdCharToInt(x) (10*((x & 0xF0)>>4) + (x & 0xF)) - -class SiTableParserBase : public P2PVR::RawDataClient { - public: - const P2PVR::Data & CurrentRawData() const; - protected: - SiTableParserBase(); - virtual ~SiTableParserBase() = 0; - - typedef boost::shared_ptr StrPtr; - - bool NewData(const P2PVR::Data & bytes, const Ice::Current&); - - static StrPtr convert(const char * txt, size_t len); - - static const std::string ISO10646; - static const std::string EitEncoding; - static const std::string UTF8; - protected: - virtual bool ParseInfoTable(const u_char * data, size_t len) = 0; - time_t startTime; - unsigned int incomplete; - std::mutex lock; - private: - const P2PVR::Data * currentRawData; -}; - -struct SiTableHeaderBase { - uint8_t tableid; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char section_syntax_indicator :1; - u_char reserved2 :3; - u_char section_length_hi :4; -#else - u_char section_length_hi :4; - u_char reserved2 :3; - u_char section_syntax_indicator :1; -#endif - uint8_t section_length_lo; -} __attribute__((packed)); - -struct SiTableHeader : public SiTableHeaderBase { - uint16_t content_id; -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - u_char reserved1 :2; - u_char version_number :5; - u_char current_next_indicator :1; -#else - u_char current_next_indicator :1; - u_char version_number :5; - u_char reserved1 :2; -#endif - uint8_t section_number; - uint8_t last_section_number; -} __attribute__((packed)); - -struct SiDescriptorHeader { - u_char tag; - u_char length; - u_char data[]; -} __attribute__((packed)); - -template -class SiTableParser : public SiTableParserBase { - protected: - typedef std::set Sections; // Section numbers - typedef boost::tuple TargetSections; // Last section number | Seen section numbers - typedef std::map TableTargetSections; // TableID -> Needed references - typedef boost::tuple ContentType; // TemplateData | Needed references - typedef std::map Contents; // ContentID -> data - - virtual int SectionNumberShift() const { return 0; } - virtual uint8_t LastTableId(const TableType * t) { return t->header.tableid; } - virtual uint8_t FirstTableId(const TableType * t) { return t->header.tableid; } - - bool ParseInfoTable(const u_char * data, size_t len) - { - const u_char * dataEnd = data + len; - while (data < dataEnd) { - auto siTable = reinterpret_cast(data); - if (siTable->header.current_next_indicator == 1 // current only, please. - && CheckTableId(siTable->header.tableid)) { // only tables we're interested in, please. - std::lock_guard g(lock); - uint16_t contentId = ntohs(siTable->header.content_id); - ContentType & content = contents[contentId]; - uint8_t sectionNumber = siTable->header.section_number >> SectionNumberShift(); - TableTargetSections & targetTableSections = boost::get<1>(content); - TargetSections & targetSections = targetTableSections[siTable->header.tableid]; - boost::get<0>(targetSections) = siTable->header.last_section_number >> SectionNumberShift(); - Sections & seen = boost::get<1>(targetSections); - if (seen.find(sectionNumber) == seen.end()) { - auto & obj = boost::get<0>(content); - if (!obj) { - obj = TargetType(new typename TargetType::element_type()); - incomplete += 1; - } - ParseSiTable(siTable, obj); - seen.insert(sectionNumber); - bool complete = true; - for (int tid = FirstTableId(siTable); tid <= LastTableId(siTable); tid += 1) { - TableTargetSections::const_iterator tts = targetTableSections.find(tid); - if (tts == targetTableSections.end()) { - complete = false; - break; - } - if (boost::get<1>(tts->second).size() <= boost::get<0>(tts->second)) { - complete = false; - break; - } - } - if (complete) { - if (HandleTable(obj)) { - targetTableSections.clear(); - } - else { - obj = TargetType(); - } - incomplete -= 1; - } - } - } - data += HILO(siTable->header.section_length) + 4; - } - return IsFinished(); - } - - virtual bool IsFinished() const - { - return ((incomplete == 0) && (startTime < (time(NULL) - 10))); - } - - static void ParseDescriptor(const SiDescriptorHeader * descriptor) - { - (void)descriptor; - // Logger()->messagef(LOG_DEBUG, "Dropped descriptor with tag 0x%02x", descriptor->tag); - return; - } - - template - static void ParseDescriptor(const SiDescriptorHeader * descriptor, u_char tag, boost::function parser, OtherParers ... otherParers) - { - if (tag == descriptor->tag) { - parser(descriptor->data, descriptor->length); - } - else { - ParseDescriptor(descriptor, otherParers...); - } - } - - template - static const NextData * ParseDescriptors(const u_char * data, size_t len, Parsers ... parsers) - { - auto end = data + len; - while (data < end) { - auto descriptor = reinterpret_cast(data); - ParseDescriptor(descriptor, parsers...); - data += descriptor->length + 2; - } - return reinterpret_cast(end); - } - - template - static void LoopOver(const u_char * data, size_t len, boost::function parser) - { - auto end = data + len; - while (data < end) { - auto loopData = reinterpret_cast(data); - parser(loopData); - data += HILO(loopData->descriptors_length) + (loopData->data - data); - } - } - - template - static void LoopOverSection(const u_char * data, size_t len, boost::function parser) - { - auto end = data + len; - while (data < end) { - auto loopData = reinterpret_cast(data); - parser(loopData); - data += sizeof(LoopContent); - } - } - - virtual bool CheckTableId(u_char tableId) const = 0; - virtual void ParseSiTable(const TableType *, TargetType) = 0; - virtual bool HandleTable(TargetType table) = 0; - - private: - mutable Contents contents; -}; - -#endif - diff --git a/p2pvr/lib/singleIterator.h b/p2pvr/lib/singleIterator.h new file mode 100644 index 0000000..1aac418 --- /dev/null +++ b/p2pvr/lib/singleIterator.h @@ -0,0 +1,39 @@ +#ifndef SINGLEITERATOR_H +#define SINGLEITERATOR_H + +#include +#include +#include "objectRowState.h" + +template +class SingleIterator : public IHaveSubTasks { + public: + SingleIterator(const T * i) : + SourceObject(__PRETTY_FUNCTION__), + IHaveSubTasks(NULL), + binder(boost::bind(&BindColumns, _1, _2)), + item(i) + { + } + + void execute(ExecContext * ec) const + { + ObjectRowState rs; + binder(rs, *item); + rs.process(boost::bind(&SingleIterator::executeChildren, this, ec)); + } + + private: + boost::function binder; + const T * item; + + void executeChildren(ExecContext * ec) const + { + BOOST_FOREACH(const Tasks::value_type & sq, normal) { + sq->execute(ec); + } + } +}; + +#endif + diff --git a/p2pvr/lib/sql/Recordings_delete.sql b/p2pvr/lib/sql/Recordings_delete.sql deleted file mode 100644 index 3395376..0000000 --- a/p2pvr/lib/sql/Recordings_delete.sql +++ /dev/null @@ -1,2 +0,0 @@ -DELETE FROM recordings -WHERE recordingId = ? diff --git a/p2pvr/lib/sql/Recordings_getAll.sql b/p2pvr/lib/sql/Recordings_getAll.sql deleted file mode 100644 index c0a096c..0000000 --- a/p2pvr/lib/sql/Recordings_getAll.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT recordingId, storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration -FROM recordings r -ORDER BY startTime, title, subtitle diff --git a/p2pvr/lib/sql/Recordings_getStorage.sql b/p2pvr/lib/sql/Recordings_getStorage.sql deleted file mode 100644 index fdaf58d..0000000 --- a/p2pvr/lib/sql/Recordings_getStorage.sql +++ /dev/null @@ -1,4 +0,0 @@ -SELECT storageAddress, guid -FROM recordings -WHERE recordingId = ? - diff --git a/p2pvr/lib/sql/Recordings_insert.sql b/p2pvr/lib/sql/Recordings_insert.sql deleted file mode 100644 index dfe2ccc..0000000 --- a/p2pvr/lib/sql/Recordings_insert.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO recordings(storageAddress, guid, scheduleId, title, subtitle, description, startTime, duration) -VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/lib/sql/Recordings_insertNewId.sql b/p2pvr/lib/sql/Recordings_insertNewId.sql deleted file mode 100644 index 0583b49..0000000 --- a/p2pvr/lib/sql/Recordings_insertNewId.sql +++ /dev/null @@ -1,2 +0,0 @@ -SELECT currval('recordings_recordingid_seq'); - diff --git a/p2pvr/lib/sql/SI_eventById.sql b/p2pvr/lib/sql/SI_eventById.sql deleted file mode 100644 index f0e028d..0000000 --- a/p2pvr/lib/sql/SI_eventById.sql +++ /dev/null @@ -1,28 +0,0 @@ -select e.serviceid, - e.eventid, - e.title, - e.titlelang, - e.subtitle, - e.description, - e.descriptionlang, - e.videoaspect, - e.videoframerate, - e.videohd, - e.audiochannels, - e.audiolanguage, - e.subtitlelanguage, - e.category, - e.subcategory, - e.usercategory, - e.dvbrating, - e.starttime, - e.stoptime, - e.episode, - e.episodes, - e.year, - e.flags, - e.season -from events e -where serviceid = ? -and eventid = ? - diff --git a/p2pvr/lib/sql/SI_eventsInRange.sql b/p2pvr/lib/sql/SI_eventsInRange.sql deleted file mode 100644 index 0a2d6de..0000000 --- a/p2pvr/lib/sql/SI_eventsInRange.sql +++ /dev/null @@ -1,28 +0,0 @@ -select e.serviceid, - e.eventid, - e.title, - e.titlelang, - e.subtitle, - e.description, - e.descriptionlang, - e.videoaspect, - e.videoframerate, - e.videohd, - e.audiochannels, - e.audiolanguage, - e.subtitlelanguage, - e.category, - e.subcategory, - e.usercategory, - e.dvbrating, - e.starttime, - e.stoptime, - e.episode, - e.episodes, - e.year, - e.flags, - e.season -from events e -where tsrange(?, ?, '[)') && tsrange(e.starttime, e.stoptime) -order by e.serviceid, e.starttime - diff --git a/p2pvr/lib/sql/SI_eventsOnNow.sql b/p2pvr/lib/sql/SI_eventsOnNow.sql deleted file mode 100644 index 36760b4..0000000 --- a/p2pvr/lib/sql/SI_eventsOnNow.sql +++ /dev/null @@ -1,27 +0,0 @@ -select e.serviceid, - e.eventid, - e.title, - e.titlelang, - e.subtitle, - e.description, - e.descriptionlang, - e.videoaspect, - e.videoframerate, - e.videohd, - e.audiochannels, - e.audiolanguage, - e.subtitlelanguage, - e.category, - e.subcategory, - e.usercategory, - e.dvbrating, - e.starttime, - e.stoptime, - e.episode, - e.episodes, - e.year, - e.flags, - e.season -from events e -where now()::timestamp without time zone <@ tsrange(e.starttime, e.stoptime) -order by e.serviceid diff --git a/p2pvr/lib/sql/SI_serviceNextUsed.sql b/p2pvr/lib/sql/SI_serviceNextUsed.sql deleted file mode 100644 index 8e906ad..0000000 --- a/p2pvr/lib/sql/SI_serviceNextUsed.sql +++ /dev/null @@ -1,12 +0,0 @@ -SELECT dd.* -FROM delivery_dvbt dd, services s - LEFT OUTER JOIN record r - ON r.serviceid = s.serviceid - AND r.recordstatus = 0 - LEFT OUTER JOIN events e - ON r.eventid = e.eventid - AND r.serviceid = e.serviceid - AND e.starttime > NOW() -WHERE dd.transportstreamid = s.transportstreamid -ORDER BY e.starttime, s.serviceid -LIMIT 1 diff --git a/p2pvr/lib/sql/SI_servicesSelectAll.sql b/p2pvr/lib/sql/SI_servicesSelectAll.sql deleted file mode 100644 index 513a076..0000000 --- a/p2pvr/lib/sql/SI_servicesSelectAll.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT serviceId, transportStreamId, name, providerName, defaultAuthority, runningStatus, eitSchedule, eitPresentFollowing, freeCaMode -FROM services -ORDER BY serviceId diff --git a/p2pvr/lib/sql/SI_servicesSelectById.sql b/p2pvr/lib/sql/SI_servicesSelectById.sql deleted file mode 100644 index f0bda72..0000000 --- a/p2pvr/lib/sql/SI_servicesSelectById.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT serviceId, transportStreamId, name, providerName, defaultAuthority, runningStatus, eitSchedule, eitPresentFollowing, freeCaMode -FROM services -WHERE serviceId = ? diff --git a/p2pvr/lib/sql/Schedules_GetCandidates.sql b/p2pvr/lib/sql/Schedules_GetCandidates.sql deleted file mode 100644 index 8e8b15e..0000000 --- a/p2pvr/lib/sql/Schedules_GetCandidates.sql +++ /dev/null @@ -1,25 +0,0 @@ -select what, serviceid, eventid, transportstreamid, - starttime - early starttime, stoptime + late stoptime, - priority, scheduleid -from ( - select (e.title, e.subtitle, e.description)::text what, e.serviceid, e.eventid, sv.transportstreamid, - e.starttime, e.stoptime - interval '1 second' stoptime, - s.early, s.late, s.scheduleid, s.priority, - rank() over(partition by e.serviceid, e.eventid, sv.serviceid order by s.priority desc, s.scheduleid) schedulerank - from services sv, events e, schedules s - where (s.serviceid is null or s.serviceid = e.serviceid) - and (s.title is null or lower(s.title) = lower(e.title)) - and (s.eventid is null or s.eventid = e.eventid) - and (s.search is null or event_tsvector(e) @@ plainto_tsquery(s.search)) - and sv.serviceid = e.serviceid - and e.stoptime > now() - and not exists ( - select 1 - from recorded r - where lower(e.title) = lower(r.title) - and coalesce(lower(e.subtitle), '') = coalesce(lower(r.subtitle), '') - and ts_rank(to_tsvector(e.description), plainto_tsquery(r.description)) + - ts_rank(to_tsvector(r.description), plainto_tsquery(e.description)) > 1)) e -where e.schedulerank = 1 -order by e.priority desc, e.what, e.transportstreamid, e.starttime - diff --git a/p2pvr/lib/sql/Schedules_delete.sql b/p2pvr/lib/sql/Schedules_delete.sql deleted file mode 100644 index e14edc3..0000000 --- a/p2pvr/lib/sql/Schedules_delete.sql +++ /dev/null @@ -1 +0,0 @@ -DELETE FROM schedules WHERE scheduleId = ? diff --git a/p2pvr/lib/sql/Schedules_insert.sql b/p2pvr/lib/sql/Schedules_insert.sql deleted file mode 100644 index 100e78b..0000000 --- a/p2pvr/lib/sql/Schedules_insert.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO schedules(serviceId, eventId, title, search, priority, early, late, repeats) -VALUES(?, ?, ?, ?, ?, ?, ?, ?) diff --git a/p2pvr/lib/sql/Schedules_insertNewId.sql b/p2pvr/lib/sql/Schedules_insertNewId.sql deleted file mode 100644 index f66acd5..0000000 --- a/p2pvr/lib/sql/Schedules_insertNewId.sql +++ /dev/null @@ -1 +0,0 @@ -SELECT currval('schedules_scheduleid_seq'); diff --git a/p2pvr/lib/sql/Schedules_pendingRecord.sql b/p2pvr/lib/sql/Schedules_pendingRecord.sql deleted file mode 100644 index ba4d7d8..0000000 --- a/p2pvr/lib/sql/Schedules_pendingRecord.sql +++ /dev/null @@ -1,13 +0,0 @@ -select * -from record r, events e, schedules s -where r.serviceid = e.serviceid -and r.eventid = e.eventid -and /*r.scheduleid*/ 161 = s.scheduleid -and r.recordstatus = 1 -and r.recordingstatus = 0 -and e.starttime - s.early - interval '3minutes' < now() -order by e.starttime - s.early - -; -select * -from schedules \ No newline at end of file diff --git a/p2pvr/lib/sql/Schedules_scheduledToRecord.sql b/p2pvr/lib/sql/Schedules_scheduledToRecord.sql deleted file mode 100644 index 3874c37..0000000 --- a/p2pvr/lib/sql/Schedules_scheduledToRecord.sql +++ /dev/null @@ -1,8 +0,0 @@ -SELECT r.serviceid, r.eventid, r.scheduleid -FROM record r, events e, schedules s -WHERE recordstatus = 0 -AND r.serviceid = e.serviceid -AND r.eventid = e.eventid -AND r.scheduleid = s.scheduleid -AND e.stoptime + s.late > NOW() -ORDER BY e.starttime, e.serviceid diff --git a/p2pvr/lib/sql/Schedules_selectAll.sql b/p2pvr/lib/sql/Schedules_selectAll.sql deleted file mode 100644 index e9e500e..0000000 --- a/p2pvr/lib/sql/Schedules_selectAll.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats -FROM schedules -ORDER BY scheduleId diff --git a/p2pvr/lib/sql/Schedules_selectById.sql b/p2pvr/lib/sql/Schedules_selectById.sql deleted file mode 100644 index 4990418..0000000 --- a/p2pvr/lib/sql/Schedules_selectById.sql +++ /dev/null @@ -1,5 +0,0 @@ -SELECT scheduleid, serviceid, eventid, title, search, priority, early, late, repeats -FROM schedules -WHERE scheduleid = ? -ORDER BY scheduleId - diff --git a/p2pvr/lib/sql/Schedules_update.sql b/p2pvr/lib/sql/Schedules_update.sql deleted file mode 100644 index 56c9531..0000000 --- a/p2pvr/lib/sql/Schedules_update.sql +++ /dev/null @@ -1,10 +0,0 @@ -UPDATE schedules SET - serviceId = ?, - eventId = ?, - title = ?, - search = ?, - priority = ?, - early = ?, - late = ?, - repeats = ? -WHERE scheduleId = ? diff --git a/p2pvr/lib/sqlContainerCreator.h b/p2pvr/lib/sqlContainerCreator.h deleted file mode 100644 index 5c8d8f8..0000000 --- a/p2pvr/lib/sqlContainerCreator.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SQLCONTAINERCREATOR_H -#define SQLCONTAINERCREATOR_H - -#include "containerCreator.h" -#include -#include -#include - -template > -class SqlContainerCreator : public ContainerCreator { - public: - SqlContainerCreator(T & c) : ContainerCreator(c) { } - - void populate(boost::shared_ptr sel) - { - sel->execute(); - ContainerCreator::populate(boost::bind(&DB::SelectCommand::fetch, sel), [sel](unsigned int c) { - HandleAsVariableType h; - const DB::Column & col = (*sel)[c]; - col.apply(h); - return h.variable; - }, sel->columnCount()); - } -}; - - -#endif - diff --git a/p2pvr/lib/storage.cpp b/p2pvr/lib/storage.cpp deleted file mode 100644 index 9d9345d..0000000 --- a/p2pvr/lib/storage.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include -#include "storage.h" -#include "fileSink.h" -#include -#include -#include -#include -#include -#include -#include - -namespace fs = boost::filesystem; - -fs::path Storage::root; -fs::path Storage::byAll; -fs::path Storage::byTitle; -fs::path Storage::byDate; -fs::path Storage::byService; -fs::path Storage::bySchedule; - -DECLARE_OPTIONS(Storage, "P2PVR Storage options") -("p2pvr.storage.root", Options::value(&root, "recordings"), - "Root folder in which to store recordings") -("p2pvr.storage.all", Options::value(&byAll, "all"), - "Sub folder in which to store all recordings") -("p2pvr.storage.bytitle", Options::value(&byTitle, "title"), - "Sub folder in which to store by title") -("p2pvr.storage.bydate", Options::value(&byDate, "date"), - "Sub folder in which to store by date") -("p2pvr.storage.byservice", Options::value(&byService, "service"), - "Sub folder in which to store by service") -("p2pvr.storage.byschedule", Options::value(&bySchedule, "schedule"), - "Sub folder in which to store by schedule") -END_OPTIONS(Storage); - -inline static -fs::path createPath(const fs::path & start) -{ - return start; -} - -template -inline static -fs::path -operator/(const fs::path & lhs, const IceUtil::Optional & rhs) -{ - if (rhs) { - return lhs / *rhs; - } - return lhs; -} - -template -inline static -fs::path createPath(const fs::path & start, const Arg & arg, const Args & ... args) -{ - auto path = start / arg; - return createPath(path, args...); -} - -template -inline static -std::string firstNotNull(const Arg & arg, const Args & ...) -{ - return boost::lexical_cast(arg); -} - -template -inline static -std::string firstNotNull(const IceUtil::Optional & arg, const Args & ... args) -{ - return arg ? firstNotNull(*arg, args...) : firstNotNull(args...); -} - -template -inline static -std::string firstNotNull(const std::string & arg, const Args & ...) -{ - return arg; -} - -inline static -std::string -formatIf(const boost::format & f) -{ - return f.str(); -} - -template -inline static -IceUtil::Optional -formatIf(boost::format & f, const IceUtil::Optional & arg, const Args & ... args) -{ - if (arg) { - f % *arg; - return formatIf(f, args...); - } - else { - return IceUtil::Optional(); - } -} - -template -inline static -IceUtil::Optional -formatIf(boost::format & f, const Arg & arg, const Args & ... args) -{ - f % arg; - return formatIf(f, args...); -} - -template -inline static -IceUtil::Optional -formatIf(const std::string & msgfmt, const Args & ... args) -{ - boost::format fmt(msgfmt); - return formatIf(fmt, args...); -} - -std::string -Storage::CreateForEventRecording(const std::string & ext, const P2PVR::SchedulePtr & schedule, const DVBSI::ServicePtr & service, const DVBSI::EventPtr & event, const Ice::Current &) -{ - fs::create_directories(root / byAll); - auto id = boost::lexical_cast(boost::uuids::random_generator()()); - fs::path path = root / byAll / id; - path.replace_extension(ext); - auto fd = open(path.string().c_str(), O_WRONLY | O_CREAT | O_EXCL, 0664); - if (fd < 0) { - Logger()->messagebf(LOG_ERR, "%s: Failed to open file for writing at %s (%d:%s)", __PRETTY_FUNCTION__, - path, errno, strerror(errno)); - throw P2PVR::StorageException(path.string(), strerror(errno)); - } - createSymlinks(ext, id, schedule, service, event); - Logger()->messagebf(LOG_INFO, "%s: Created new recording %s", __PRETTY_FUNCTION__, path); - - close(fd); - return id; -} - -void -Storage::createSymlinks(const std::string & ext, const std::string & target, const P2PVR::SchedulePtr & schedule, const DVBSI::ServicePtr & service, const DVBSI::EventPtr & event) -{ - // By title, with optional season and episode information - createSymlink(ext, target, createPath(root, byTitle, - event->Title, - formatIf("Season %02d", event->Season), - firstNotNull( - formatIf("Part %02d of %02d - %s", event->Episode, event->Episodes, event->Subtitle), - formatIf("Episode %02d - %s", event->Episode, event->Subtitle), - formatIf("Part %02d of %02d - %s", event->Episode, event->Episodes, event->Description), - formatIf("Part %02d of %02d", event->Episode, event->Episodes), - formatIf("Episode %02d - %s", event->Episode, event->Description), - event->Subtitle, - event->Description, - formatIf("Episode %02d", event->Episode), - event->StartTime))); - // By date - createSymlink(ext, target, createPath(root, byDate, - formatIf("%04d-%02d-%02d", event->StartTime.Year, event->StartTime.Month, event->StartTime.Day), - firstNotNull( - formatIf("%s - %s", event->Title, event->Subtitle), - formatIf("%s - %s", event->Title, event->Description), - event->Title))); - // By service - createSymlink(ext, target, createPath(root, byService, - service->Name, - firstNotNull( - formatIf("%s - %s", event->Title, event->Subtitle), - formatIf("%s - %s", event->Title, event->Description), - event->Title))); - // By schedule title - createSymlink(ext, target, createPath(root, bySchedule, - formatIf("Title: %s", schedule->Title), - formatIf("%04d-%02d-%02d", event->StartTime.Year, event->StartTime.Month, event->StartTime.Day), - firstNotNull( - formatIf("%s - %s", event->Title, event->Subtitle), - formatIf("%s - %s", event->Title, event->Description), - event->Title))); - // By schedule search - createSymlink(ext, target, createPath(root, bySchedule, - formatIf("Search: %s", schedule->Search), - firstNotNull( - formatIf("%s - %s", event->Title, event->Subtitle), - formatIf("%s - %s", event->Title, event->Description), - event->Title))); -} -void -Storage::createSymlink(const std::string & ext, const std::string & target, const fs::path & link) -{ - fs::path path = link; - path.replace_extension(ext); - Logger()->messagebf(LOG_DEBUG, "%s: link(%s) -> target(%s)", __PRETTY_FUNCTION__, path, target); - if (fs::exists(path)) { - Logger()->messagebf(LOG_WARNING, "%s: symlink already exists %s", __PRETTY_FUNCTION__, path); - return; - } - fs::create_directories(path.parent_path()); - fs::path relativeTarget; - for (fs::path tmp = path.parent_path(); tmp != root; tmp = tmp.parent_path()) { - relativeTarget /= ".."; - } - relativeTarget /= byAll; - relativeTarget /= target; - relativeTarget.replace_extension(ext); - fs::create_symlink(relativeTarget, path); -} - -std::string -Storage::FindExtension(const std::string & id) -{ - fs::directory_iterator end; - for (fs::directory_iterator itr(root / byAll); itr != end; ++itr) { - if (itr->path().stem() == id) { - return itr->path().extension().string(); - } - } - return ""; -} - -P2PVR::RawDataClientPrx -Storage::OpenForWrite(const std::string & id, const Ice::Current & ice) -{ - fs::path path = root / byAll / id; - path.replace_extension(FindExtension(id)); - auto fd = open(path.string().c_str(), O_WRONLY | O_APPEND | O_LARGEFILE); - if (fd < 0) { - Logger()->messagebf(LOG_ERR, "%s: Failed to open file for reading at %s (%d:%s)", __PRETTY_FUNCTION__, - path, errno, strerror(errno)); - throw P2PVR::StorageException(path.string(), strerror(errno)); - } - auto openFile = OpenFilePtr(new OpenFile(ice.adapter, new FileSink(fd))); - openFiles.insert(openFile); - return *openFile; -} - -void -Storage::Close(const P2PVR::RawDataClientPrx & file, const Ice::Current &) -{ - openFiles.erase(std::find_if(openFiles.begin(), openFiles.end(), [&file](const OpenFilePtr & of) { return *of == file; })); -} - -void -Storage::Delete(const std::string & id, const Ice::Current &) -{ - fs::path path = root / byAll / id; - path.replace_extension(FindExtension(id)); - Logger()->messagebf(LOG_INFO, "%s: Deleting links to %s", __PRETTY_FUNCTION__, path); - DeleteFrom(path, fs::canonical(root)); -} - -void -Storage::DeleteFrom(const fs::path & path, const fs::path & from) -{ - Logger()->messagebf(LOG_DEBUG, "%s: Deleting links to %s to %s", __PRETTY_FUNCTION__, path, from); - fs::directory_iterator end; - for (fs::directory_iterator itr(from); itr != end; ++itr) { - if (fs::is_directory(*itr)) { - DeleteFrom(path, *itr); - } - else { - boost::system::error_code err; - auto link = fs::canonical(*itr, err); - if (err || link == path) { - Logger()->messagebf(LOG_DEBUG, "%s: deleting %s", __PRETTY_FUNCTION__, *itr); - fs::remove(*itr); - } - } - } - if (from != root && fs::is_empty(from)) { - Logger()->messagebf(LOG_DEBUG, "%s: deleting directory %s", __PRETTY_FUNCTION__, from); - fs::remove(from); - } -} - diff --git a/p2pvr/lib/storage.h b/p2pvr/lib/storage.h deleted file mode 100644 index 093e00d..0000000 --- a/p2pvr/lib/storage.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef STORAGE_H -#define STORAGE_H - -#include -#include -#include -#include -#include "temporaryIceAdapterObject.h" - -class Storage : public P2PVR::Storage { - public: - std::string CreateForEventRecording(const std::string & ext, const P2PVR::SchedulePtr &, const DVBSI::ServicePtr &, const DVBSI::EventPtr &, const Ice::Current &); - P2PVR::RawDataClientPrx OpenForWrite(const std::string &, const Ice::Current &); - void Close(const P2PVR::RawDataClientPrx & file, const Ice::Current &); - void Delete(const std::string &, const Ice::Current &); - - INITOPTIONS; - - protected: - static void createSymlinks(const std::string & ext, const std::string &, const P2PVR::SchedulePtr &, const DVBSI::ServicePtr &, const DVBSI::EventPtr &); - static void createSymlink(const std::string & ext, const std::string & target, const boost::filesystem::path & link); - static void DeleteFrom(const boost::filesystem::path &, const boost::filesystem::path &); - static std::string FindExtension(const std::string & id); - - typedef TemporarayIceAdapterObject OpenFile; - typedef boost::shared_ptr OpenFilePtr; - typedef std::set OpenFiles; - OpenFiles openFiles; - - static boost::filesystem::path root; - static boost::filesystem::path byAll; - static boost::filesystem::path byTitle; - static boost::filesystem::path byDate; - static boost::filesystem::path byService; - static boost::filesystem::path bySchedule; -}; - -#endif diff --git a/p2pvr/lib/tuner.cpp b/p2pvr/lib/tuner.cpp deleted file mode 100644 index fe90231..0000000 --- a/p2pvr/lib/tuner.cpp +++ /dev/null @@ -1,421 +0,0 @@ -#include -#include "tuner.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fileHandle.h" -#include -#include "tunerSendSi.h" -#include "tunerSendTs.h" - -class FrontendNotSupported : public NotSupported { - public: - FrontendNotSupported(fe_type t) : NotSupported(stringbf("Frontend not supported: %s", t)) - { } -}; - -Tuner::Tuner(const boost::filesystem::path & df) : - deviceFrontend(df), - deviceRoot(df.branch_path()), - backgroundThread(NULL), - lastUsedTime(time(NULL)) -{ - int fd = open(deviceFrontend.string().c_str(), O_RDWR); - if (fd < 0) { - throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno); - } - try { - struct dvb_frontend_info fe_info; - if (ioctl(fd, FE_GET_INFO, &fe_info) < 0) { - throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno); - } - frontend = FrontendPtr(FrontendLoader::createNew(fe_info.type, this, fd, fe_info)); - } - catch (...) { - close(fd); - throw; - } - Logger()->messagebf(LOG_INFO, "%s: Attached to %s (%s, type %s)", __PRETTY_FUNCTION__, - deviceRoot, frontend->Info().name, frontend->Type()); -} - -Tuner::~Tuner() -{ - { - std::lock_guard g(lock); - while (!backgroundClients.empty()) { - close(backgroundClients.begin()->first); - backgroundClients.erase(backgroundClients.begin()); - } - } - if (backgroundThread) { - backgroundThread->join(); - delete backgroundThread; - } -} - -void -Tuner::TuneTo(const DVBSI::DeliveryPtr & mp, const Ice::Current&) -{ - frontend->TuneTo(mp); -} - -int -Tuner::GetStatus(const Ice::Current &) -{ - time(&lastUsedTime); - return frontend->GetStatus(); -} - -std::string -Tuner::Device() const -{ - time(&lastUsedTime); - return deviceRoot.string(); -} - -int -Tuner::OpenDemux() const -{ - int demux = open((deviceRoot / "demux0").string().c_str(), O_RDWR | O_NONBLOCK); - if (demux < 0) { - throw P2PVR::DeviceError(deviceRoot.string(), strerror(errno), errno); - } - return demux; -} - -void -Tuner::ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - time(&lastUsedTime); - frontend->FrequencyScan([this, &client, &ice](long) { - try { - return (SendPID(0x10, client, ice) > 0); - } - catch (const std::exception & ex) { - char * buf = __cxxabiv1::__cxa_demangle(typeid(ex).name(), NULL, NULL, NULL); - Logger()->messagebf(LOG_DEBUG, "%s: frequency scan lock event failed %s:%s", __PRETTY_FUNCTION__, buf, ex.what()); - free(buf); - return false; - } - catch (...) { - Logger()->messagebf(LOG_DEBUG, "%s: frequency scan lock event failed", __PRETTY_FUNCTION__); - return false; - } - }); -} - -void -Tuner::SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(0x10, client, ice); -} - -void -Tuner::SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(0x11, client, ice); -} - -void -Tuner::SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(0x11, client, ice); -} - -void -Tuner::SendProgramMap(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(pid, client, ice); -} - -void -Tuner::SendProgramAssociationTable(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(0x00, client, ice); -} - -void -Tuner::SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - SendPID(0x12, client, ice); -} - -uint64_t -Tuner::SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) const -{ - time(&lastUsedTime); - Logger()->messagebf(LOG_DEBUG, "%s: pid = 0x%x", __PRETTY_FUNCTION__, pid); - - if (ice.con) { - ice.con->createProxy(client->ice_getIdentity()); - } - FileHandle demux(OpenDemux()); - RequestPID(pid, demux); - return ReadDemuxAndSend(demux, client); -} - -void -Tuner::RequestPID(int pid, int demux) -{ - setBufferSize(demux, DemuxTableBufferSize); - struct dmx_sct_filter_params sctFilterParams; - memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params)); - sctFilterParams.pid = pid; - sctFilterParams.flags = DMX_IMMEDIATE_START; - - if (ioctl(demux, DMX_SET_FILTER, &sctFilterParams) < 0) { - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } -} - -uint64_t -Tuner::ReadDemuxAndSend(int demux, const P2PVR::RawDataClientPrx & _client) const -{ - Logger()->messagebf(LOG_DEBUG, "%s: begin", __PRETTY_FUNCTION__); - struct pollfd ufd; - memset(&ufd, 0, sizeof(pollfd)); - ufd.fd = demux; - ufd.events = POLLIN | POLLPRI; - BackgroundClient client = BackgroundClient(new SendSi(_client)); - do { - // Wait for data to appear - switch (poll(&ufd, 1, DemuxReadTimeout)) { - case -1: - Logger()->messagebf(LOG_DEBUG, "%s: poll error reading demux (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - case 0: - auto status = frontend->GetStatus(); - Logger()->messagebf(LOG_DEBUG, "%s: Timed out waiting for data (device status 0x%02x)", __PRETTY_FUNCTION__, status); - throw P2PVR::DeviceError("demux", "timeout", 0); - } - - // Read it - P2PVR::Data buf(1 << 12); - int nr = read(demux, &buf.front(), buf.size()); - if (nr < 0) { - Logger()->messagebf(LOG_DEBUG, "%s: error reading demux (%d:%s) status 0x%02x", - __PRETTY_FUNCTION__, errno, strerror(errno), frontend->GetStatus()); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } - size_t n = nr; - buf.resize(n); - - client->NewData(buf); - time(&lastUsedTime); - - } while (!client->IsFinished()); - auto packetsSent = client->PacketsSent(); - client.reset(); - Logger()->messagebf(LOG_DEBUG, "%s: end (sent %d packets)", __PRETTY_FUNCTION__, packetsSent); - return packetsSent; -} - -int -Tuner::StartSendingSection(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &) -{ - time(&lastUsedTime); - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - - std::lock_guard g(lock); - int demux = backgroundClients.insert(BackgroundClients::value_type(OpenDemux(), - BackgroundClient(new SendSi(client)))).first->first; - RequestPID(pid, demux); - startSenderThread(); - return demux; -} - -int -Tuner::StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) -{ - time(&lastUsedTime); - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - if (pids.empty()) { - throw P2PVR::DeviceError("demux", "Packet Id list cannot be empty", 0); - } - - if (ice.con) { - ice.con->createProxy(client->ice_getIdentity()); - } - std::lock_guard g(lock); - int demux = backgroundClients.insert(BackgroundClients::value_type(OpenDemux(), - BackgroundClient(new SendTs(client)))).first->first; - - struct dmx_pes_filter_params pesFilterParams; - memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params)); - Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER for pid %d", __PRETTY_FUNCTION__, pids[0]); - pesFilterParams.pid = pids[0]; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_TSDEMUX_TAP; - pesFilterParams.pes_type = DMX_PES_OTHER; - pesFilterParams.flags = 0; - - if (ioctl(demux, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { - backgroundClients.erase(demux); - Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } - - for (unsigned int x = 1; x < pids.size(); x += 1) { - __u16 p = pids[x]; - Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID for pid %d", __PRETTY_FUNCTION__, p); - if (ioctl(demux, DMX_ADD_PID, &p) < 0) { - backgroundClients.erase(demux); - Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } - } - - setBufferSize(demux, DemuxStreamBufferSize); - if (ioctl(demux, DMX_START) < 0) { - backgroundClients.erase(demux); - Logger()->messagebf(LOG_ERR, "%s: DMX_START failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } - - startSenderThread(); - return demux; -} - -void -Tuner::setBufferSize(int demux, unsigned long size) -{ - if (ioctl(demux, DMX_SET_BUFFER_SIZE, size)) { - Logger()->messagebf(LOG_ERR, "%s: DMX_SET_BUFFER_SIZE to %d failed (%d: %s)", __PRETTY_FUNCTION__, size, errno, strerror(errno)); - throw P2PVR::DeviceError("demux", strerror(errno), errno); - } - Logger()->messagebf(LOG_DEBUG, "%s: DMX_SET_BUFFER_SIZE to %d", __PRETTY_FUNCTION__, size); -} - -void -Tuner::StopSending(int handle, const Ice::Current &) -{ - time(&lastUsedTime); - Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__); - std::lock_guard g(lock); - if (backgroundClients.find(handle) != backgroundClients.end()) { - close(handle); - backgroundClients.erase(handle); - } -} - -void -Tuner::startSenderThread() -{ - if (!backgroundThread) { - backgroundThread = new std::thread(&Tuner::senderThread, this); - } -} - -void -Tuner::senderThread() -{ - lock.lock(); - while (!backgroundClients.empty()) { - int n = backgroundClients.rbegin()->first + 1; - fd_set rfds; - FD_ZERO(&rfds); - BOOST_FOREACH(const auto & c, backgroundClients) { - FD_SET(c.first, &rfds); - } - lock.unlock(); - time(&lastUsedTime); - - struct timeval tv { 2, 0 }; - switch (select(n, &rfds, NULL, NULL, &tv)) { - case -1: // error - Logger()->messagebf(LOG_DEBUG, "%s: select failed (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - case 0: // nothing to read, but all is well - break; - default: - { // stuff to do - std::lock_guard g(lock); - for (auto c = backgroundClients.begin(); c != backgroundClients.end(); ) { - if (FD_ISSET(c->first, &rfds)) { - // Read it - P2PVR::Data buf(1 << 16); - int nr = read(c->first, &buf.front(), buf.size()); - if (nr < 0) { - Logger()->messagebf(LOG_DEBUG, "%s: read failed (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); - close(c->first); - c = backgroundClients.erase(c); - } - else { - size_t n = nr; - buf.resize(n); - c->second->NewData(buf); - c++; - } - } - else { - c++; - } - } - } - break; - } - // Clean up finished async requests - lock.lock(); - for (auto client = backgroundClients.begin(); client != backgroundClients.end(); ) { - if (client->second->IsFinished()) { - close(client->first); - client = backgroundClients.erase(client); - } - else { - client++; - } - } - } - backgroundThread = NULL; - Logger()->messagebf(LOG_DEBUG, "%s: Unlocking", __PRETTY_FUNCTION__); - lock.unlock(); -} - -Ice::Long -Tuner::GetLastUsedTime(const Ice::Current &) -{ - return lastUsedTime; -} - -Tuner::IDataSender::IDataSender(const P2PVR::RawDataClientPrx & c) : - _packetsSent(0), - client(c) -{ -} - -Tuner::IDataSender::~IDataSender() -{ -} - -uint64_t -Tuner::IDataSender::PacketsSent() const -{ - return _packetsSent; -} - -int Tuner::TuningTimeout; -int Tuner::LockTimeout; -int Tuner::DemuxReadTimeout; -int Tuner::DemuxTableBufferSize; -int Tuner::DemuxStreamBufferSize; - -DECLARE_OPTIONS(Tuner, "P2PVR Tuner Options") -("p2pvr.tuner.tuningtimeout", Options::value(&TuningTimeout, 500), - "Timeout for a DVB frontend to tune (ms, default 500ms)") -("p2pvr.tuner.locktimeout", Options::value(&LockTimeout, 2000), - "Timeout for a DVB frontend to acquire lock (ms, default 2000ms)") -("p2pvr.tuner.demuxreadtimeout", Options::value(&DemuxReadTimeout, 20000), - "Timeout when reading from a demux device (ms, default 20s)") -("p2pvr.tuner.demuxtablebuffersize", Options::value(&DemuxTableBufferSize, 256*1024), - "Kernel buffer size for demux table data (bytes, default 256KB)") -("p2pvr.tuner.demuxstreambuffersize", Options::value(&DemuxStreamBufferSize, 1024*1024), - "Kernel buffer size for demux stream data (bytes, default 1MB)") -END_OPTIONS(Tuner); - diff --git a/p2pvr/lib/tuner.h b/p2pvr/lib/tuner.h deleted file mode 100644 index 670a17d..0000000 --- a/p2pvr/lib/tuner.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef P2PVR_TUNER_H -#define P2PVR_TUNER_H - -#include -#include -#include "frontend.h" -#include -#include -#include -#include -#include -#include -#include - -class Tuner : public P2PVR::PrivateTuner { - public: - class IDataSender { - public: - IDataSender(const P2PVR::RawDataClientPrx &); - virtual ~IDataSender() = 0; - - virtual void NewData(const P2PVR::Data &) = 0; - virtual bool IsFinished() = 0; - uint64_t PacketsSent() const; - - protected: - uint64_t _packetsSent; - const P2PVR::RawDataClientPrx client; - }; - typedef boost::shared_ptr BackgroundClient; - typedef std::map BackgroundClients; - - Tuner(const boost::filesystem::path & deviceFrontend); - ~Tuner(); - - void TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&); - int GetStatus(const Ice::Current&); - std::string Device() const; - - void ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendProgramMap(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendProgramAssociationTable(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - void SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&); - - int StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current &); - int StartSendingSection(Ice::Int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &); - void StopSending(int handle, const Ice::Current &); - - Ice::Long GetLastUsedTime(const Ice::Current&); - - INITOPTIONS; - - private: - int OpenDemux() const; - uint64_t SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &) const; - static void RequestPID(int pid, int fd); - uint64_t ReadDemuxAndSend(int fd, const P2PVR::RawDataClientPrx & client) const; - void startSenderThread(); - void senderThread(); - static void setBufferSize(int fd, unsigned long bytes); - - const boost::filesystem::path deviceFrontend; - const boost::filesystem::path deviceRoot; - BackgroundClients backgroundClients; - std::thread * backgroundThread; - std::mutex lock; - - mutable time_t lastUsedTime; - FrontendPtr frontend; - - public: - static int TuningTimeout; - static int LockTimeout; - static int DemuxReadTimeout; - static int DemuxTableBufferSize; - static int DemuxStreamBufferSize; -}; - -#endif - diff --git a/p2pvr/lib/tunerSendSi.cpp b/p2pvr/lib/tunerSendSi.cpp deleted file mode 100644 index e1f4637..0000000 --- a/p2pvr/lib/tunerSendSi.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include "tunerSendSi.h" -#include -#include -#include "siParsers/table.h" - -SendSi::SendSi(const P2PVR::RawDataClientPrx & c) : - Tuner::IDataSender(c->ice_collocationOptimized(false)) -{ -} - -SendSi::~SendSi() -{ -} - -void -SendSi::NewData(const P2PVR::Data & buf) -{ - if (!IsValidSection(buf)) { - return; - } - _packetsSent += 1; - asyncs.insert(client->begin_NewData(buf)); -} - -bool -SendSi::IsFinished() -{ - try { - for (auto c = asyncs.begin(); c != asyncs.end(); ) { - if ((*c)->isCompleted()) { - if (client->end_NewData(*c)) { - return true; - } - c = asyncs.erase(c); - } - else { - c++; - } - } - return false; - } - catch (const std::exception & ex) { - Logger()->messagebf(LOG_DEBUG, "%s: Client transmit error (%s)", __PRETTY_FUNCTION__, ex.what()); - return true; - } -} - -bool -SendSi::IsValidSection(const P2PVR::Data & buf) -{ - auto n = buf.size(); - if (n < sizeof(SiTableHeader)) { - Logger()->messagebf(LOG_WARNING, "Received data too small to be an SI table."); - return false; - } - auto * tab = (const SiTableHeader *)(&buf.front()); - size_t l = sizeof(SiTableHeaderBase) + HILO(tab->section_length); - if (n < l) { - Logger()->messagebf(LOG_WARNING, "Received data shorter than its defined length."); - return false; - } - if (n > l) { - Logger()->messagebf(LOG_WARNING, "Received data longer than its defined length."); - return false; - } - if (!crc32(buf)) { - Logger()->messagebf(LOG_WARNING, "Received data is corrupted (crc32 failed)."); - return false; - } - return true; -} - -bool -SendSi::crc32(const P2PVR::Data & buf) -{ - boost::crc_optimal<32, 0x0, 0xFFFFFFFF, 0x0, true, false> crc; - crc.process_bytes(&buf.front(), buf.size()); - return crc.checksum() == 0; -} - diff --git a/p2pvr/lib/tunerSendSi.h b/p2pvr/lib/tunerSendSi.h deleted file mode 100644 index df48f43..0000000 --- a/p2pvr/lib/tunerSendSi.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TUNER_SENDSI_H -#define TUNER_SENDSI_H - -#include "tuner.h" - -class SendSi : public Tuner::IDataSender { - public: - SendSi(const P2PVR::RawDataClientPrx &); - ~SendSi(); - - void NewData(const P2PVR::Data &); - bool IsFinished(); - - private: - static bool crc32(const P2PVR::Data &); - static bool IsValidSection(const P2PVR::Data &); - - std::set asyncs; - bool finish; -}; - -#endif - - diff --git a/p2pvr/lib/tunerSendTs.cpp b/p2pvr/lib/tunerSendTs.cpp deleted file mode 100644 index 70b6670..0000000 --- a/p2pvr/lib/tunerSendTs.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include "tunerSendTs.h" -#include - -// ~64kb of TS packets -#define TARGET_BUFFER_SIZE (350 * 188) -// About the ICE message size limit -#define TARGET_BUFFER_LIMIT 512 * 1024 - -SendTs::SendTs(const P2PVR::RawDataClientPrx & c) : - Tuner::IDataSender(c->ice_collocationOptimized(false)) -{ - buffer.reserve(TARGET_BUFFER_SIZE); -} - -SendTs::~SendTs() -{ - try { - if (async) { - if (client->end_NewData(async)) return; - } - while (!buffer.empty()) { - sendBufferChunk(); - if (client->end_NewData(async)) return; - } - } - catch (...) { - } -} - -void -SendTs::NewData(const P2PVR::Data & buf) -{ - buffer.insert(buffer.end(), buf.begin(), buf.end()); - if (!async && buffer.size() >= TARGET_BUFFER_SIZE) { - sendBufferChunk(); - } -} - -void -SendTs::sendBufferChunk() -{ - if (buffer.size() > TARGET_BUFFER_LIMIT) { - auto breakPoint = buffer.begin() + TARGET_BUFFER_LIMIT; - async = client->begin_NewData(P2PVR::Data(buffer.begin(), breakPoint)); - buffer.erase(buffer.begin(), breakPoint); - } - else { - async = client->begin_NewData(buffer); - buffer.clear(); - buffer.reserve(TARGET_BUFFER_SIZE); - } - _packetsSent += 1; -} - -bool -SendTs::IsFinished() -{ - try { - if (async && async->isCompleted()) { - auto finished = client->end_NewData(async); - async = NULL; - if (finished) { - buffer.clear(); - } - return finished; - } - return false; - } - catch (const std::exception & ex) { - async = NULL; - Logger()->messagebf(LOG_DEBUG, "%s: Client transmit error (%s)", __PRETTY_FUNCTION__, ex.what()); - return true; - } -} - - diff --git a/p2pvr/lib/tunerSendTs.h b/p2pvr/lib/tunerSendTs.h deleted file mode 100644 index ecf32fd..0000000 --- a/p2pvr/lib/tunerSendTs.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TUNER_SENDTS_H -#define TUNER_SENDTS_H - -#include "tuner.h" - -class SendTs : public Tuner::IDataSender { - public: - SendTs(const P2PVR::RawDataClientPrx &); - ~SendTs(); - - void NewData(const P2PVR::Data &); - bool IsFinished(); - - private: - void sendBufferChunk(); - - Ice::AsyncResultPtr async; - P2PVR::Data buffer; -}; - -#endif - diff --git a/p2pvr/streamer/Jamfile.jam b/p2pvr/streamer/Jamfile.jam index 7f4d2b4..d17e9b2 100644 --- a/p2pvr/streamer/Jamfile.jam +++ b/p2pvr/streamer/Jamfile.jam @@ -1,10 +1,7 @@ - - lib streamer : [ glob-tree *.cpp ] : : ../ice//p2pvrice ../lib//p2pvrlib - ../util//p2pvrutil ../ice//p2pvrice ; diff --git a/p2pvr/util/Jamfile.jam b/p2pvr/util/Jamfile.jam deleted file mode 100644 index 84b2654..0000000 --- a/p2pvr/util/Jamfile.jam +++ /dev/null @@ -1,19 +0,0 @@ -cpp-pch pch : pch.hpp : - ..//p2common - ..//p2lib - ../ice//p2pvrice -; - -lib p2pvrutil : - pch - [ glob-tree *.cpp ] - ../../libmisc/misc.cpp - : - ..//p2common - ..//p2lib - ../ice//p2pvrice - ../ice//p2pvrice - : : - . - ; - diff --git a/p2pvr/util/containerCreator.h b/p2pvr/util/containerCreator.h deleted file mode 100644 index 9804d9b..0000000 --- a/p2pvr/util/containerCreator.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CONTAINERCREATOR_H -#define CONTAINERCREATOR_H - -#include -#include -#include "objectRowState.h" - -template > -class ContainerCreator { - public: - ContainerCreator(T & c) : container(c) { } - - void populate( - boost::function fetch, - boost::function get, - unsigned int columnCount) - { - while (fetch()) { - auto v = P(new V); - container.push_back(v); - ObjectRowState

rs; - for (unsigned int c = 0; c < columnCount; c++) { - rs.fields[c] = get(c); - } - UnbindColumns

(rs, v); - } - } - private: - T & container; -}; - -#endif - diff --git a/p2pvr/util/containerIterator.h b/p2pvr/util/containerIterator.h deleted file mode 100644 index 2b61055..0000000 --- a/p2pvr/util/containerIterator.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef CONTAINERITERATOR_H -#define CONTAINERITERATOR_H - -#include -#include -#include "objectRowState.h" - -template -class ContainerIterator : public IHaveSubTasks { - public: - ContainerIterator(const T * con) : - SourceObject(__PRETTY_FUNCTION__), - IHaveSubTasks(NULL), - binder(boost::bind(&BindColumns, _1, _2)), - container(con) - { - } - - void execute(ExecContext * ec) const - { - ObjectRowState rs; - BOOST_FOREACH(const auto & i, *container) { - binder(rs, i); - rs.process(boost::bind(&ContainerIterator::executeChildren, this, ec)); - } - } - - private: - boost::function binder; - const T * container; - - void executeChildren(ExecContext * ec) const - { - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(ec); - } - } -}; - -#endif - diff --git a/p2pvr/util/dvbsiHelpers.h b/p2pvr/util/dvbsiHelpers.h deleted file mode 100644 index 137bf98..0000000 --- a/p2pvr/util/dvbsiHelpers.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ICE_DVBSI_HELPERS_H -#define ICE_DVBSI_HELPERS_H - -#include -#include "objectRowState.h" - -#define ColumnHelper(T) \ - template<> void CreateColumns(const ColumnCreator & cc); \ - template<> void BindColumns(RowState & rs, const T & obj); \ - template<> void UnbindColumns(RowState & rs, const T & s) - -ColumnHelper(DVBSI::NetworkPtr); -ColumnHelper(DVBSI::NetworkTransportStreamPtr); -ColumnHelper(DVBSI::NetworkService); -ColumnHelper(DVBSI::TerrestrialDeliveryPtr); -ColumnHelper(DVBSI::CableDeliveryPtr); -ColumnHelper(DVBSI::SatelliteDeliveryPtr); -ColumnHelper(DVBSI::ServicePtr); -ColumnHelper(DVBSI::StreamPtr); -ColumnHelper(DVBSI::EventPtr); - -#endif - diff --git a/p2pvr/util/dvbsiHelpers/cableDelivery.cpp b/p2pvr/util/dvbsiHelpers/cableDelivery.cpp deleted file mode 100644 index 7bf9f6d..0000000 --- a/p2pvr/util/dvbsiHelpers/cableDelivery.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("frequency", false); - cc("transportStreamId", true); - cc("fecOuter", false); - cc("modulation", false); - cc("symbolRate", false); - cc("fecInner", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::CableDeliveryPtr & s) -{ - rs.fields[0] << s->Frequency; - rs.fields[1] << s->TransportStreamId; - rs.fields[2] << s->FecOuter; - rs.fields[3] << s->Modulation; - rs.fields[4] << s->SymbolRate; - rs.fields[5] << s->FecInner; -} -template<> -void -UnbindColumns(RowState & rs, DVBSI::CableDeliveryPtr const & s) -{ - rs.fields[0] >> s->Frequency; - rs.fields[1] >> s->TransportStreamId; - rs.fields[2] >> s->FecOuter; - rs.fields[3] >> s->Modulation; - rs.fields[4] >> s->SymbolRate; - rs.fields[5] >> s->FecInner; -} - diff --git a/p2pvr/util/dvbsiHelpers/event.cpp b/p2pvr/util/dvbsiHelpers/event.cpp deleted file mode 100644 index ca072df..0000000 --- a/p2pvr/util/dvbsiHelpers/event.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceId", true); - cc("eventId", true); - cc("title", false); - cc("titleLang", false); - cc("subtitle", false); - cc("description", false); - cc("descriptionLang", false); - cc("videoAspect", false); - cc("videoFrameRate", false); - cc("videoHd", false); - cc("audioChannels", false); - cc("audioLanguage", false); - cc("subtitleLanguage", false); - cc("category", false); - cc("subCategory", false); - cc("userCategory", false); - cc("dvbRating", false); - cc("startTime", false); - cc("stopTime", false); - cc("episode", false); - cc("episodes", false); - cc("year", false); - cc("flags", false); - cc("season", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::EventPtr & e) -{ - rs.fields[0] << e->ServiceId; - rs.fields[1] << e->EventId; - rs.fields[2] << e->Title; - rs.fields[3] << e->TitleLang; - rs.fields[4] << e->Subtitle; - rs.fields[5] << e->Description; - rs.fields[6] << e->DescriptionLang; - rs.fields[7] << e->VideoAspect; - rs.fields[8] << e->VideoFrameRate; - rs.fields[9] << e->VideoHD; - rs.fields[10] << e->AudioChannels; - rs.fields[11] << e->AudioLanguage; - rs.fields[12] << e->SubtitleLanguage; - rs.fields[13] << e->Category; - rs.fields[14] << e->SubCategory; - rs.fields[15] << e->UserCategory; - rs.fields[16] << e->DvbRating; - rs.fields[17] << e->StartTime; - rs.fields[18] << e->StopTime; - rs.fields[19] << e->Episode; - rs.fields[20] << e->Episodes; - rs.fields[21] << e->Year; - rs.fields[22] << e->Flags; - rs.fields[23] << e->Season; -} - -template<> -void -UnbindColumns(RowState & rs, const DVBSI::EventPtr & e) -{ - rs.fields[0] >> e->ServiceId; - rs.fields[1] >> e->EventId; - rs.fields[2] >> e->Title; - rs.fields[3] >> e->TitleLang; - rs.fields[4] >> e->Subtitle; - rs.fields[5] >> e->Description; - rs.fields[6] >> e->DescriptionLang; - rs.fields[7] >> e->VideoAspect; - rs.fields[8] >> e->VideoFrameRate; - rs.fields[9] >> e->VideoHD; - rs.fields[10] >> e->AudioChannels; - rs.fields[11] >> e->AudioLanguage; - rs.fields[12] >> e->SubtitleLanguage; - rs.fields[13] >> e->Category; - rs.fields[14] >> e->SubCategory; - rs.fields[15] >> e->UserCategory; - rs.fields[16] >> e->DvbRating; - rs.fields[17] >> e->StartTime; - rs.fields[18] >> e->StopTime; - rs.fields[19] >> e->Episode; - rs.fields[20] >> e->Episodes; - rs.fields[21] >> e->Year; - rs.fields[22] >> e->Flags; - rs.fields[23] >> e->Season; -} - diff --git a/p2pvr/util/dvbsiHelpers/network.cpp b/p2pvr/util/dvbsiHelpers/network.cpp deleted file mode 100644 index 3b117f1..0000000 --- a/p2pvr/util/dvbsiHelpers/network.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("networkId", true); - cc("name", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::NetworkPtr & network) -{ - rs.fields[0] << network->NetworkId; - rs.fields[1] << network->Name; -} - - diff --git a/p2pvr/util/dvbsiHelpers/networkService.cpp b/p2pvr/util/dvbsiHelpers/networkService.cpp deleted file mode 100644 index a4a47d5..0000000 --- a/p2pvr/util/dvbsiHelpers/networkService.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceId", true); - cc("type", false); - cc("transportStreamId", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::NetworkService & s) -{ - rs.fields[0] << s.ServiceId; - rs.fields[1] << s.ServiceType; - rs.fields[2] << s.TransportStreamId; -} - diff --git a/p2pvr/util/dvbsiHelpers/networkTransportStream.cpp b/p2pvr/util/dvbsiHelpers/networkTransportStream.cpp deleted file mode 100644 index bdc7c4f..0000000 --- a/p2pvr/util/dvbsiHelpers/networkTransportStream.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("transportStreamId", true); - cc("networkId", false); - cc("originalNetworkId", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::NetworkTransportStreamPtr & ts) -{ - rs.fields[0] << ts->TransportStreamId; - rs.fields[1] << ts->NetworkId; - rs.fields[2] << ts->OriginalNetworkId; -} - - diff --git a/p2pvr/util/dvbsiHelpers/programMap.cpp b/p2pvr/util/dvbsiHelpers/programMap.cpp deleted file mode 100644 index d8cf400..0000000 --- a/p2pvr/util/dvbsiHelpers/programMap.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceId", true); - cc("id", true); - cc("type", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::StreamPtr & stream) -{ - rs.fields[0] << stream->ServiceId; - rs.fields[1] << stream->Id; - rs.fields[2] << stream->Type; -} - - - diff --git a/p2pvr/util/dvbsiHelpers/satelliteDelivery.cpp b/p2pvr/util/dvbsiHelpers/satelliteDelivery.cpp deleted file mode 100644 index 8231fc3..0000000 --- a/p2pvr/util/dvbsiHelpers/satelliteDelivery.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("frequency", false); - cc("transportStreamId", true); - cc("orbitalPosition", false); - cc("westEastFlag", false); - cc("polarization", false); - cc("rollOff", false); - cc("modulationSystem", false); - cc("modulationType", false); - cc("symbolRate", false); - cc("fecInner", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::SatelliteDeliveryPtr & s) -{ - rs.fields[0] << s->Frequency; - rs.fields[1] << s->TransportStreamId; - rs.fields[2] << s->OrbitalPosition; - rs.fields[3] << s->WestEastFlag; - rs.fields[4] << s->Polarization; - rs.fields[5] << s->RollOff; - rs.fields[6] << s->ModulationSystem; - rs.fields[7] << s->ModulationType; - rs.fields[8] << s->SymbolRate; - rs.fields[9] << s->FecInner; -} -template<> -void -UnbindColumns(RowState & rs, DVBSI::SatelliteDeliveryPtr const & s) -{ - rs.fields[0] >> s->Frequency; - rs.fields[1] << s->TransportStreamId; - rs.fields[2] >> s->OrbitalPosition; - rs.fields[3] >> s->WestEastFlag; - rs.fields[4] >> s->Polarization; - rs.fields[5] >> s->RollOff; - rs.fields[6] >> s->ModulationSystem; - rs.fields[7] >> s->ModulationType; - rs.fields[8] >> s->SymbolRate; - rs.fields[9] >> s->FecInner; -} - diff --git a/p2pvr/util/dvbsiHelpers/service.cpp b/p2pvr/util/dvbsiHelpers/service.cpp deleted file mode 100644 index 9f82d91..0000000 --- a/p2pvr/util/dvbsiHelpers/service.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("serviceId", true); - cc("transportStreamId", true); - cc("name", false); - cc("providerName", false); - cc("defaultAuthority", false); - cc("runningStatus", false); - cc("eitSchedule", false); - cc("eitPresentFollowing", false); - cc("freeCAMode", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::ServicePtr & s) -{ - rs.fields[0] << s->ServiceId; - rs.fields[1] << s->TransportStreamId; - rs.fields[2] << s->Name; - rs.fields[3] << s->ProviderName; - rs.fields[4] << s->DefaultAuthority; - rs.fields[5] << s->RunningStatus; - rs.fields[6] << s->EitSchedule; - rs.fields[7] << s->EitPresentFollowing; - rs.fields[8] << s->FreeCaMode; -} - -template<> -void -UnbindColumns(RowState & rs, DVBSI::ServicePtr const & s) -{ - rs.fields[0] >> s->ServiceId; - rs.fields[1] >> s->TransportStreamId; - rs.fields[2] >> s->Name; - rs.fields[3] >> s->ProviderName; - rs.fields[4] >> s->DefaultAuthority; - rs.fields[5] >> s->RunningStatus; - rs.fields[6] >> s->EitSchedule; - rs.fields[7] >> s->EitPresentFollowing; - rs.fields[8] >> s->FreeCaMode; -} - diff --git a/p2pvr/util/dvbsiHelpers/terrestrialDelivery.cpp b/p2pvr/util/dvbsiHelpers/terrestrialDelivery.cpp deleted file mode 100644 index 46e60f9..0000000 --- a/p2pvr/util/dvbsiHelpers/terrestrialDelivery.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("frequency", false); - cc("transportStreamId", true); - cc("bandwidth", false); - cc("priority", false); - cc("timeSlicing", false); - cc("mpeFec", false); - cc("constellation", false); - cc("hierarchy", false); - cc("codeRateHP", false); - cc("codeRateLP", false); - cc("guardInterval", false); - cc("transmissionMode", false); - cc("otherFrequencyFlag", false); -} - -template<> -void -BindColumns(RowState & rs, const DVBSI::TerrestrialDeliveryPtr & s) -{ - rs.fields[0] << s->Frequency; - rs.fields[1] << s->TransportStreamId; - rs.fields[2] << s->Bandwidth; - rs.fields[3] << s->Priority; - rs.fields[4] << s->TimeSlicing; - rs.fields[5] << s->MpeFec; - rs.fields[6] << s->Constellation; - rs.fields[7] << s->Hierarchy; - rs.fields[8] << s->CodeRateHP; - rs.fields[9] << s->CodeRateLP; - rs.fields[10] << s->GuardInterval; - rs.fields[11] << s->TransmissionMode; - rs.fields[12] << s->OtherFrequencyFlag; -} -template<> -void -UnbindColumns(RowState & rs, DVBSI::TerrestrialDeliveryPtr const & s) -{ - rs.fields[0] >> s->Frequency; - rs.fields[2] >> s->Bandwidth; - rs.fields[3] >> s->Priority; - rs.fields[4] >> s->TimeSlicing; - rs.fields[5] >> s->MpeFec; - rs.fields[6] >> s->Constellation; - rs.fields[7] >> s->Hierarchy; - rs.fields[8] >> s->CodeRateHP; - rs.fields[9] >> s->CodeRateLP; - rs.fields[10] >> s->GuardInterval; - rs.fields[11] >> s->TransmissionMode; - rs.fields[12] >> s->OtherFrequencyFlag; -} - diff --git a/p2pvr/util/fileHandle.cpp b/p2pvr/util/fileHandle.cpp deleted file mode 100644 index b85d390..0000000 --- a/p2pvr/util/fileHandle.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include "fileHandle.h" -#include -#include - -class InvalidFileHandle : public std::runtime_error { - public: - InvalidFileHandle() : std::runtime_error("Invalid file handle") { } -}; - -FileHandle::FileHandle(int f) : - fd(f) -{ - if (fd < 0) { - throw InvalidFileHandle(); - } -} - -FileHandle::~FileHandle() -{ - close(fd); -} - -FileHandle::operator int() const -{ - return fd; -} - diff --git a/p2pvr/util/fileHandle.h b/p2pvr/util/fileHandle.h deleted file mode 100644 index 3c8d45e..0000000 --- a/p2pvr/util/fileHandle.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FILEHANDLE_H -#define FILEHANDLE_H - -class FileHandle { - public: - FileHandle(int fd); - ~FileHandle(); - - FileHandle(const FileHandle &) = delete; - void operator=(const FileHandle &) = delete; - - operator int() const; - - private: - const int fd; -}; - -#endif - diff --git a/p2pvr/util/mapIterator.cpp b/p2pvr/util/mapIterator.cpp deleted file mode 100644 index 157669a..0000000 --- a/p2pvr/util/mapIterator.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "mapIterator.h" -#include "p2Helpers.h" - -template<> -void BindColumns>(RowState & rs, std::pair const & p) -{ - rs.fields[0] << p.first; - rs.fields[1] << p.second; -} - diff --git a/p2pvr/util/mapIterator.h b/p2pvr/util/mapIterator.h deleted file mode 100644 index 8a06fe6..0000000 --- a/p2pvr/util/mapIterator.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MAPITERATOR_H -#define MAPITERATOR_H - -#include -#include -#include "objectRowState.h" - -template -class MapIterator : public IHaveSubTasks { - public: - template - MapIterator(const ColumnSpecifier & cs, const T * m, const Parents & ... p) : - SourceObject(__PRETTY_FUNCTION__), - IHaveSubTasks(NULL), - binder(boost::bind(&BindColumns, _1, _2, p...)), - columnSpecifier(cs), - map(m) - { - } - - void execute(ExecContext * ec) const - { - ObjectRowState rs(columnSpecifier); - BOOST_FOREACH(const auto & i, *map) { - binder(rs, i); - rs.process(boost::bind(&MapIterator::executeChildren, this, ec)); - } - } - - private: - boost::function binder; - const ColumnSpecifier columnSpecifier; - const T * map; - - void executeChildren(ExecContext * ec) const - { - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(ec); - } - } -}; - -#endif - - diff --git a/p2pvr/util/objectRowState.h b/p2pvr/util/objectRowState.h deleted file mode 100644 index 9ba69f0..0000000 --- a/p2pvr/util/objectRowState.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef OBJECT_ROW_STATE_H -#define OBJECT_ROW_STATE_H - -#include -#include -#include - -typedef boost::function ColumnCreator; -typedef boost::function ColumnSpecifier; - -template -void BindColumns(RowState &, const V &); - -template -void UnbindColumns(RowState &, const V &); - -template -void CreateColumns(const ColumnCreator &); - -template -class ObjectRowState : public RowState { - public: - ObjectRowState(const ColumnSpecifier & cs = CreateColumns) : - columns(ColumnCreatorHelper(cs)) - { - fields.resize(columns.size()); - } - const Columns & getColumns() const { return columns; } - - private: - static Columns ColumnCreatorHelper(const ColumnSpecifier & cs) - { - int index = 0; - Columns columns; - cs([&columns, &index](const std::string & name, bool) { - columns.insert(new Column(index++, name)); - }); - return columns; - } - - Columns columns; -}; - -#endif - diff --git a/p2pvr/util/p2Helpers.cpp b/p2pvr/util/p2Helpers.cpp deleted file mode 100644 index c58ff1a..0000000 --- a/p2pvr/util/p2Helpers.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include "p2Helpers.h" -#include - -template <> -VariableType & -operator<<(VariableType & vt, const Common::Duration & d) -{ - return (vt = *d); -} - -template <> -VariableType & -operator<<(VariableType & vt, const Common::DateTime & dt) -{ - return (vt = *dt); -} - -template <> -const VariableType & -operator>>(const VariableType & vt, Common::Duration & d) -{ - const boost::posix_time::time_duration & dur = vt; - d = *dur; - return vt; -} - -template <> -const VariableType & -operator>>(const VariableType & vt, Common::DateTime & dt) -{ - const boost::posix_time::ptime & date = vt; - dt = *date; - return vt; -} - -template <> -const VariableType & -operator>>(const VariableType & vt, short int & v) -{ - v = (int)vt; - return vt; -} diff --git a/p2pvr/util/p2Helpers.h b/p2pvr/util/p2Helpers.h deleted file mode 100644 index 3b73f1b..0000000 --- a/p2pvr/util/p2Helpers.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef ICE_P2_HELPERS_H -#define ICE_P2_HELPERS_H - -#include -#include - -template -const VariableType & -operator>>(const VariableType & vt, T & v) -{ - v = vt.as(); - return vt; -} - -template <> -const VariableType & -operator>>(const VariableType & vt, Common::Duration & d); - -template <> -const VariableType & -operator>>(const VariableType & vt, Common::DateTime & dt); - -template -const VariableType & -operator>>(const VariableType & vt, IceUtil::Optional & v) -{ - if (vt.isNull()) { - v = IceUtil::Optional(); - } - else { - v = T(); - vt >> *v; - } - return vt; -} - -template <> -const VariableType & -operator>>(const VariableType & vt, short int & v); - -template -VariableType & -operator<<(VariableType & vt, const T & v) -{ - vt = v; - return vt; -} - -template <> -VariableType & -operator<<(VariableType & vt, const Common::Duration & d); - -template <> -VariableType & -operator<<(VariableType & vt, const Common::DateTime & dt); - -template -VariableType & -operator<<(VariableType & vt, const IceUtil::Optional & v) -{ - if (v) { - vt << *v; - } - else { - vt = Null(); - } - return vt; -} - -#endif - diff --git a/p2pvr/util/p2pvrHelpers/schedule.cpp b/p2pvr/util/p2pvrHelpers/schedule.cpp deleted file mode 100644 index f8abc1e..0000000 --- a/p2pvr/util/p2pvrHelpers/schedule.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include "../dvbsiHelpers.h" -#include "../p2Helpers.h" - -template<> -void -CreateColumns(const ColumnCreator & cc) -{ - cc("scheduleid", true); - cc("serviceid", true); - cc("eventid", false); - cc("title", false); - cc("search", false); - cc("priority", false); - cc("early", false); - cc("late", false); - cc("repeats", false); -} - -template<> -void -BindColumns(RowState & rs, const P2PVR::SchedulePtr & s) -{ - rs.fields[0] << s->ScheduleId; - rs.fields[1] << s->ServiceId; - rs.fields[2] << s->EventId; - rs.fields[3] << s->Title; - rs.fields[4] << s->Search; - rs.fields[5] << s->Priority; - rs.fields[6] << s->Early; - rs.fields[7] << s->Late; - rs.fields[8] << s->Repeats; -} - -template<> -void -UnbindColumns(RowState & rs, P2PVR::SchedulePtr const & s) -{ - rs.fields[0] >> s->ScheduleId; - rs.fields[1] >> s->ServiceId; - rs.fields[2] >> s->EventId; - rs.fields[3] >> s->Title; - rs.fields[4] >> s->Search; - rs.fields[5] >> s->Priority; - rs.fields[6] >> s->Early; - rs.fields[7] >> s->Late; - rs.fields[8] >> s->Repeats; -} - - diff --git a/p2pvr/util/pch.hpp b/p2pvr/util/pch.hpp deleted file mode 100644 index dafc462..0000000 --- a/p2pvr/util/pch.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifdef BOOST_BUILD_PCH_ENABLED -#ifndef P2PVRUTIL_PCH -#define P2PVRUTIL_PCH - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#endif -#endif - - diff --git a/p2pvr/util/singleIterator.h b/p2pvr/util/singleIterator.h deleted file mode 100644 index 1aac418..0000000 --- a/p2pvr/util/singleIterator.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SINGLEITERATOR_H -#define SINGLEITERATOR_H - -#include -#include -#include "objectRowState.h" - -template -class SingleIterator : public IHaveSubTasks { - public: - SingleIterator(const T * i) : - SourceObject(__PRETTY_FUNCTION__), - IHaveSubTasks(NULL), - binder(boost::bind(&BindColumns, _1, _2)), - item(i) - { - } - - void execute(ExecContext * ec) const - { - ObjectRowState rs; - binder(rs, *item); - rs.process(boost::bind(&SingleIterator::executeChildren, this, ec)); - } - - private: - boost::function binder; - const T * item; - - void executeChildren(ExecContext * ec) const - { - BOOST_FOREACH(const Tasks::value_type & sq, normal) { - sq->execute(ec); - } - } -}; - -#endif - -- cgit v1.2.3