diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2017-08-24 10:28:33 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2017-08-24 10:28:33 +0100 |
commit | 63d970c72fbb12dda8d0641bd3d1b68459649c3f (patch) | |
tree | 545912b4f379a9a19f5fd1adea838ee913774a13 | |
parent | Fix card daemon config file (diff) | |
download | p2pvr-63d970c72fbb12dda8d0641bd3d1b68459649c3f.tar.bz2 p2pvr-63d970c72fbb12dda8d0641bd3d1b68459649c3f.tar.xz p2pvr-63d970c72fbb12dda8d0641bd3d1b68459649c3f.zip |
Fix up behaviour of table based SI parsers to stop only when they have received all on a required set of tables. Required updated sample SI packets which were actually complete and revisions to test cases. Allows for removal of hacky HasPending workaround.
37 files changed, 436 insertions, 141 deletions
diff --git a/p2pvr/daemon/maintenance/events.cpp b/p2pvr/daemon/maintenance/events.cpp index 2dd91af..fbdeb51 100644 --- a/p2pvr/daemon/maintenance/events.cpp +++ b/p2pvr/daemon/maintenance/events.cpp @@ -8,13 +8,15 @@ #include <sqlWriter.h> #include <slicer/modelPartsTypes.impl.h> #include "sql/maintenance/pruneEvents.sql.h" +#include "sql/si/serviceIdsWithEit.sql.h" namespace P2PVR { class SiEventsStream : public Slicer::Stream<::DVBSI::EventPtr> { private: class SiEventsHandler : public DVBSI::SiEpgParser { public: - SiEventsHandler(const Consumer & c, IceTray::Logging::LoggerPtr l) : + SiEventsHandler(const Consumer & c, DB::Connection * d, IceTray::Logging::LoggerPtr l) : + DVBSI::SiEpgParser(getIds(d)), consumer(c), logger(l) { @@ -28,14 +30,22 @@ class SiEventsStream : public Slicer::Stream<::DVBSI::EventPtr> { return false; } + static RequiredContentIds getIds(DB::Connection * db) + { + auto sel = sql::si::serviceIdsWithEit.select(db); + auto ids = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, std::vector<Ice::Int>>(*sel); + return {ids.begin(), ids.end()}; + } + private: const Consumer & consumer; const IceTray::Logging::LoggerPtr logger; }; public: - SiEventsStream(const Ice::Current & i, IceTray::Logging::LoggerPtr l) : + SiEventsStream(const Ice::Current & i, DB::Connection * d, IceTray::Logging::LoggerPtr l) : ice(i), + db(d), logger(l) { } @@ -55,13 +65,14 @@ class SiEventsStream : public Slicer::Stream<::DVBSI::EventPtr> { } logger->messagebf(LOG::DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__); logger->messagebf(LOG::DEBUG, "%s: Fetching events", __PRETTY_FUNCTION__); - TemporaryIceAdapterObject<RawDataClient> parser(ice.adapter, new SiEventsHandler(ch, logger)); + TemporaryIceAdapterObject<RawDataClient> parser(ice.adapter, new SiEventsHandler(ch, db, logger)); devs->SendEventInformation(delivery, parser); } private: const Ice::Current & ice; + DB::Connection * db; const IceTray::Logging::LoggerPtr logger; }; @@ -71,7 +82,7 @@ MaintenanceI::UpdateEvents(const Ice::Current & ice) auto dbc = db->get(); auto ic = ice.adapter->getCommunicator(); - SiEventsStream stream(ice, logger); + SiEventsStream stream(ice, dbc.get(), logger); DB::TransactionScope tx(dbc.get()); DB::TablePatch tp; diff --git a/p2pvr/daemon/maintenance/network.cpp b/p2pvr/daemon/maintenance/network.cpp index c514175..2f74050 100644 --- a/p2pvr/daemon/maintenance/network.cpp +++ b/p2pvr/daemon/maintenance/network.cpp @@ -43,7 +43,9 @@ class SiNetworkInformationMerger : public DVBSI::SiNetworkInformationParser { ::DVBSI::NetworkServiceList services; for (const auto & ts : n->TransportStreams) { for (const auto & s : ts->Services) { - services.push_back(s); + if (std::find_if(services.begin(), services.end(), [&s](const auto & es) { return es.ServiceId == s.ServiceId; }) == services.end()) { + services.push_back(s); + } } } DB::TablePatch mergeServices; @@ -62,7 +64,9 @@ class SiNetworkInformationMerger : public DVBSI::SiNetworkInformationParser { std::vector<Delivery> dels; for (const auto & s : n->TransportStreams) { if (auto d = s.get()->*member) { - dels.push_back(d); + if (std::find_if(dels.begin(), dels.end(), [&d](const auto & ed) { return ed->Frequency == d->Frequency; }) == dels.end()) { + dels.push_back(d); + } } } Slicer::SerializeAny<Slicer::SqlTablePatchSerializer>(dels, dbc, tp); diff --git a/p2pvr/daemon/maintenance/services.cpp b/p2pvr/daemon/maintenance/services.cpp index 12b23ce..288dd99 100644 --- a/p2pvr/daemon/maintenance/services.cpp +++ b/p2pvr/daemon/maintenance/services.cpp @@ -6,11 +6,13 @@ #include <slicer/slicer.h> #include <db/sqlTablePatchSerializer.h> #include <tablepatch.h> +#include <sql/si/allDeliveriesTransportStreamId.sql.h> namespace P2PVR { class SiServicesMerger : public DVBSI::SiServicesParser { public: SiServicesMerger(IceTray::Logging::LoggerPtr l, DB::Connection * d) : + DVBSI::SiServicesParser(getIds(d)), logger(l), dbc(d) { @@ -34,6 +36,13 @@ class SiServicesMerger : public DVBSI::SiServicesParser { return false; } + static RequiredContentIds getIds(DB::Connection * db) + { + auto sel = sql::si::allDeliveriesTransportStreamId.select(db); + auto ids = Slicer::DeserializeAny<Slicer::SqlSelectDeserializer, std::vector<Ice::Int>>(*sel); + return {ids.begin(), ids.end()}; + } + private: IceTray::Logging::LoggerPtr logger; DB::Connection * dbc; diff --git a/p2pvr/daemon/sql/si/allDeliveriesTransportStreamId.sql b/p2pvr/daemon/sql/si/allDeliveriesTransportStreamId.sql new file mode 100644 index 0000000..55ff3c8 --- /dev/null +++ b/p2pvr/daemon/sql/si/allDeliveriesTransportStreamId.sql @@ -0,0 +1,2 @@ +SELECT transportStreamId +FROM allDeliveries diff --git a/p2pvr/daemon/sql/si/serviceIdsWithEit.sql b/p2pvr/daemon/sql/si/serviceIdsWithEit.sql new file mode 100644 index 0000000..ca4883d --- /dev/null +++ b/p2pvr/daemon/sql/si/serviceIdsWithEit.sql @@ -0,0 +1,4 @@ +SELECT s.serviceId +FROM allDeliveries d, services s +WHERE d.transportStreamId = s.transportStreamId +AND s.eitschedule diff --git a/p2pvr/daemon/unittests/mockDevices.cpp b/p2pvr/daemon/unittests/mockDevices.cpp index 5ff2cb9..e5ec6a4 100644 --- a/p2pvr/daemon/unittests/mockDevices.cpp +++ b/p2pvr/daemon/unittests/mockDevices.cpp @@ -13,7 +13,7 @@ namespace P2PVR { TunerPtr MockDevices::openTuner(const boost::filesystem::path & path) const { - return new MockTuner(path, ic); + return new P2PVR::DVB::Testing::MockTuner(path, ic); } } } diff --git a/p2pvr/daemon/unittests/testErrorHandling.cpp b/p2pvr/daemon/unittests/testErrorHandling.cpp index 80af051..5b53999 100644 --- a/p2pvr/daemon/unittests/testErrorHandling.cpp +++ b/p2pvr/daemon/unittests/testErrorHandling.cpp @@ -32,10 +32,15 @@ class Core : public StandardMockDatabase { class TestDataClient : public RawDataClient { public: + TestDataClient() : + packets(3) + { + } virtual bool NewData(const Data &, const Ice::Current &) override { - return false; + return !--packets; } + unsigned int packets; }; class FailingTestClient : public RawDataClient { diff --git a/p2pvr/daemon/unittests/testMaint.cpp b/p2pvr/daemon/unittests/testMaint.cpp index e918d74..a166d04 100644 --- a/p2pvr/daemon/unittests/testMaint.cpp +++ b/p2pvr/daemon/unittests/testMaint.cpp @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE( GetDeliveryForTransport ) BOOST_AUTO_TEST_CASE( GetServices_stubs ) { auto services = si->GetServices(); - BOOST_REQUIRE_EQUAL(services.size(), 145); + BOOST_REQUIRE_EQUAL(services.size(), 180); BOOST_REQUIRE_EQUAL(services[0]->ServiceId, 4170); BOOST_REQUIRE_EQUAL(services[0]->TransportStreamId, 4170); // Definitely a stub @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE( update_services ) BOOST_AUTO_TEST_CASE( GetServices ) { auto services = si->GetServices(); - BOOST_REQUIRE_EQUAL(services.size(), 145); + BOOST_REQUIRE_EQUAL(services.size(), 180); BOOST_REQUIRE_EQUAL(services[0]->ServiceId, 4170); BOOST_REQUIRE_EQUAL(services[0]->TransportStreamId, 4170); BOOST_REQUIRE_EQUAL(services[0]->Name, "BBC ONE Yorks"); @@ -186,17 +186,17 @@ BOOST_AUTO_TEST_CASE( update_events ) auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("postgres")); BOOST_TEST_CHECKPOINT("Write first events"); - MockTuner::SetEventsSet(0); + P2PVR::DVB::Testing::MockTuner::SetEventsSet(0); maint->UpdateEvents(); auto dayOneEvents = si->EventSearch(IceUtil::Optional<std::string>(), IceUtil::Optional<int>(), - Common::DateTime {2014, 12, 18, 3, 0}, Common::DateTime {2014, 12, 19, 3, 0}); - BOOST_REQUIRE_EQUAL(dayOneEvents.size(), 3345); - BOOST_REQUIRE(si->GetEvent(14448, 27052)); + Common::DateTime {2017, 8, 22, 3, 0}, Common::DateTime {2017, 8, 23, 3, 0}); + BOOST_REQUIRE_EQUAL(dayOneEvents.size(), 3023); + BOOST_REQUIRE(si->GetEvent(15048, 29747)); BOOST_REQUIRE_THROW(si->GetEvent(15856, 3591), P2PVR::NotFound); BOOST_TEST_CHECKPOINT("Fake some recorded stuff"); - auto keyEvent1 = si->GetEvent(25664, 55689); - auto keyEvent2 = si->GetEvent(24256, 1014); + auto keyEvent1 = dayOneEvents[1000]; + auto keyEvent2 = dayOneEvents[2000]; db->execute("INSERT INTO schedules(repeats) VALUES(false)"); auto irecorded = boost::shared_ptr<DB::ModifyCommand>( db->newModifyCommand("INSERT INTO recorded(scheduleId, eventUid) VALUES(?, ?)")); @@ -211,21 +211,23 @@ BOOST_AUTO_TEST_CASE( update_events ) BOOST_REQUIRE(keyEvent1); BOOST_REQUIRE(keyEvent2); BOOST_REQUIRE(keyEvent1->Current); - BOOST_REQUIRE_EQUAL(keyEvent1->StartTime, Common::DateTime({2014, 12, 18, 21, 0})); + BOOST_REQUIRE_EQUAL(keyEvent1->StartTime, Common::DateTime({2017, 8, 22, 5, 0})); BOOST_REQUIRE(keyEvent2->Current); - BOOST_REQUIRE_EQUAL(keyEvent2->StartTime, Common::DateTime({2014, 12, 17, 5, 30})); + BOOST_REQUIRE_EQUAL(keyEvent2->StartTime, Common::DateTime({2017, 8, 22, 6, 30})); BOOST_TEST_CHECKPOINT("Write second events"); - MockTuner::SetEventsSet(1); + P2PVR::DVB::Testing::MockTuner::SetEventsSet(1); maint->UpdateEvents(); - BOOST_REQUIRE_THROW(si->GetEvent(14448, 27052), P2PVR::NotFound); - BOOST_REQUIRE(si->GetEvent(15856, 3591)); + auto dayTwoEvents = si->EventSearch(IceUtil::Optional<std::string>(), IceUtil::Optional<int>(), + Common::DateTime {2017, 8, 23, 3, 0}, Common::DateTime {2017, 8, 24, 3, 0}); + BOOST_REQUIRE_THROW(si->GetEvent(15064, 22), P2PVR::NotFound); + BOOST_REQUIRE(si->GetEvent(15048, 29791)); BOOST_TEST_CHECKPOINT("Check our faked stuff is still there and right"); auto dayOneEventsOnDayTwo = si->EventSearch(IceUtil::Optional<std::string>(), IceUtil::Optional<int>(), - Common::DateTime {2014, 12, 18, 3, 0}, Common::DateTime {2014, 12, 19, 3, 0}); + Common::DateTime {2017, 8, 22, 3, 0}, Common::DateTime {2017, 8, 23, 3, 0}); // Some datetime range overlap, but most are gone - BOOST_REQUIRE_EQUAL(dayOneEventsOnDayTwo.size(), 373); + BOOST_REQUIRE_EQUAL(dayOneEventsOnDayTwo.size(), 316); BOOST_REQUIRE_EQUAL(std::count_if(dayOneEventsOnDayTwo.begin(), dayOneEventsOnDayTwo.end(), [](const P2PVR::EventPtr & e) { return (e->ServiceId == 25664 && e->EventId == 55689) diff --git a/p2pvr/devices/Jamfile.jam b/p2pvr/devices/Jamfile.jam index 92573d5..bb9f70e 100644 --- a/p2pvr/devices/Jamfile.jam +++ b/p2pvr/devices/Jamfile.jam @@ -1,5 +1,6 @@ import type ; import generators ; +import testing ; lib boost_system ; lib boost_thread ; @@ -8,7 +9,7 @@ lib boost_program_options ; lib lzma ; lib p2pvrdevices : - [ glob-tree *.cpp : mockTuner.cpp ] + [ glob-tree *.cpp : mock*.cpp ] : <library>boost_system <library>boost_filesystem @@ -40,9 +41,8 @@ IMPORT $(__name__) : datxz.embed.asm : : datxz.embed.asm ; lib p2pvrMockTuner : mockTuner.cpp - [ glob-tree *.datxz ] : - <library>lzma + <library>mockdata <library>boost_system <library>boost_thread <library>boost_filesystem @@ -60,3 +60,25 @@ lib p2pvrMockTuner : <include>. ; +lib mockdata : + mockData.cpp + [ glob-tree *.datxz ] + : + <library>lzma + <library>../ice//p2pvrice + <implicit-dependency>../ice//p2pvrice + ; + +run + mockDataValidate.cpp + : : : + <library>../dvb//p2pvrdvb + <library>../ice//p2pvrice + <library>..//adhocutil + <library>..//icetray + <library>mockdata + <library>boost_filesystem + <library>boost_system + <library>..//boost_utf + <define>BOOST_TEST_DYN_LINK + ; diff --git a/p2pvr/devices/mockData.cpp b/p2pvr/devices/mockData.cpp new file mode 100644 index 0000000..31a7100 --- /dev/null +++ b/p2pvr/devices/mockData.cpp @@ -0,0 +1,75 @@ +#include "mockData.h" +#include <lzma.h> +#include <Ice/Stream.h> +#include <Ice/Initialize.h> +#include <Ice/Communicator.h> + +#define ResourceFile(resource) \ +extern "C" { \ + extern char resource##_start, resource##_end;\ + extern unsigned int resource##_len; \ +} + +namespace P2PVR { + namespace DVB { + namespace Testing { + ResourceFile(network); + ResourceFile(services); + ResourceFile(events1); + ResourceFile(events2); + ResourceFile(pat); + ResourceFile(pmt); + ResourceFile(vid); + + void LZMA_ASSERT(int ret_xz) + { + if (ret_xz != LZMA_OK) { + throw std::runtime_error("LZMA Decompressor error"); + } + } + + MockData::MockData(Ice::CommunicatorPtr c) : ic(c) { } + + ::P2PVR::Data MockData::decompress(const char * front, size_t len) const + { + lzma_stream strm = LZMA_STREAM_INIT; + const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED; + const uint64_t memory_limit = UINT64_MAX; + LZMA_ASSERT(lzma_stream_decoder(&strm, memory_limit, flags)); + strm.next_in = (unsigned char *)front; + strm.avail_in = len; + uint8_t buf[BUFSIZ]; + + ::P2PVR::Data data; + data.reserve(len * 20); + do { + strm.next_out = buf; + strm.avail_out = BUFSIZ; + LZMA_ASSERT(lzma_code(&strm, LZMA_RUN)); + for (auto idx = 0u; idx < BUFSIZ - strm.avail_out; idx += 1) { + data.push_back(buf[idx]); + } + } while (strm.avail_out == 0); + data.shrink_to_fit(); + return data; + } + + MockData::PacketList MockData::decompressAndRead(const char * front, size_t len) const + { + PacketList packets; + auto istrm = Ice::createInputStream(ic, decompress(front, len)); + istrm->read(packets); + return packets; + } + + MockData::PacketList MockData::getNetwork() const { return decompressAndRead(&network_start, network_len); } + MockData::PacketList MockData::getServices() const { return decompressAndRead(&services_start, services_len); } + MockData::PacketList MockData::getEvents1() const { return decompressAndRead(&events1_start, events1_len); } + MockData::PacketList MockData::getEvents2() const { return decompressAndRead(&events2_start, events2_len); } + MockData::PacketList MockData::getPAT() const { return decompressAndRead(&pat_start, pat_len); } + MockData::PacketList MockData::getPMT() const { return decompressAndRead(&pmt_start, pmt_len); } + MockData::PacketList MockData::getVideo() const { return decompressAndRead(&vid_start, vid_len); } + } + } +} + diff --git a/p2pvr/devices/mockData.h b/p2pvr/devices/mockData.h new file mode 100644 index 0000000..b86807d --- /dev/null +++ b/p2pvr/devices/mockData.h @@ -0,0 +1,35 @@ +#ifndef P2PVR_DEVICES_MOCKDATA_H +#define P2PVR_DEVICES_MOCKDATA_H + +#include <dvb.h> +#include <list> +#include <visibility.h> + +namespace P2PVR { + namespace DVB { + namespace Testing { + class DLL_PUBLIC MockData { + public: + typedef std::list<::P2PVR::Data> PacketList; + + MockData(Ice::CommunicatorPtr); + + PacketList getNetwork() const; + PacketList getServices() const; + PacketList getEvents1() const; + PacketList getEvents2() const; + PacketList getPMT() const; + PacketList getPAT() const; + PacketList getVideo() const; + + protected: + DLL_PRIVATE ::P2PVR::Data decompress(const char * front, size_t len) const; + DLL_PRIVATE PacketList decompressAndRead(const char * front, size_t len) const; + + Ice::CommunicatorPtr ic; + }; + } + } +} + +#endif diff --git a/p2pvr/devices/mockDataValidate.cpp b/p2pvr/devices/mockDataValidate.cpp new file mode 100644 index 0000000..6bd6b5b --- /dev/null +++ b/p2pvr/devices/mockDataValidate.cpp @@ -0,0 +1,126 @@ +#define BOOST_TEST_MODULE ValidateTestData +#include <boost/test/unit_test.hpp> +#include <Ice/Communicator.h> +#include <Ice/Initialize.h> +#include <siParsers/event.h> +#include <siParsers/network.h> +#include <siParsers/programAssociation.h> +#include <siParsers/programMap.h> +#include <siParsers/service.h> +#include <boost/algorithm/string/predicate.hpp> +#include <boost/bind.hpp> +#include "mockData.h" + +BOOST_TEST_DONT_PRINT_LOG_VALUE(P2PVR::DVB::Testing::MockData::PacketList::const_iterator); + +template <typename SIObject, typename Base> +class DiscardSI : public Base, public P2PVR::DVB::Testing::MockData { + public: + DiscardSI() : + MockData(Ice::initialize({})) + { + } + DiscardSI(const P2PVR::DVBSI::SiTableParserBase::RequiredContentIds & ids) : + Base(ids), + MockData(Ice::initialize({})) + { + } + virtual ~DiscardSI() { ic->destroy(); } + + bool HandleTable(const SIObject & o) override + { + objects.push_back(o); + return false; + } + + std::list<SIObject> validate(const P2PVR::DVB::Testing::MockData::PacketList & packets, unsigned int count, unsigned int objectCount) + { + BOOST_REQUIRE_EQUAL(count, packets.size()); + auto ends = std::count_if(packets.begin(), packets.end(), [this](const auto & p) { return this->NewData(p, current); }); + for (const auto & x : Base::parents) { + BOOST_TEST_INFO(x); + } + BOOST_REQUIRE_GT(ends, 0); + BOOST_REQUIRE_EQUAL(objectCount, objects.size()); + return objects; + } + + protected: + std::list<SIObject> objects; + Ice::Current current; +}; + +::DVBSI::NetworkPtr network; +std::list<::DVBSI::TransportStreamPtr> streams; +class NetworkTester : public DiscardSI<::DVBSI::NetworkPtr, ::P2PVR::DVBSI::SiNetworkInformationParser> { + public: +}; +class ServiceTester : public DiscardSI<::DVBSI::TransportStreamPtr, ::P2PVR::DVBSI::SiServicesParser> { + public: + ServiceTester() : DiscardSI<::DVBSI::TransportStreamPtr, ::P2PVR::DVBSI::SiServicesParser>(getIds()) + { + } + static P2PVR::DVBSI::SiTableParserBase::RequiredContentIds getIds() + { + P2PVR::DVBSI::SiTableParserBase::RequiredContentIds ids; + for (const auto & t : network->TransportStreams) { + if (t->Satellite || t->Cable || t->Terrestrial) { + ids.insert(t->TransportStreamId); + } + } + return ids; + } +}; +class Events1Tester : public DiscardSI<::DVBSI::EventPtr, ::P2PVR::DVBSI::SiEpgParser> { + public: + Events1Tester() : DiscardSI<::DVBSI::EventPtr, ::P2PVR::DVBSI::SiEpgParser>(getIds()) + { + } + static P2PVR::DVBSI::SiTableParserBase::RequiredContentIds getIds() + { + P2PVR::DVBSI::SiTableParserBase::RequiredContentIds ids; + for (const auto & st : streams) { + for (const auto & s : st->Services) { + if (s->EitSchedule) { + ids.insert(s->ServiceId); + } + } + } + return ids; + } +}; +typedef DiscardSI<::DVBSI::ProgramMapPtr, ::P2PVR::DVBSI::SiProgramMapParser> PMTester; +typedef DiscardSI<::P2PVR::DVBSI::ProgramAssociationMapPtr, ::P2PVR::DVBSI::SiProgramAssociationParser> PATester; + +BOOST_FIXTURE_TEST_SUITE(ValidateTestDataNetwork, NetworkTester); + +BOOST_AUTO_TEST_CASE( networkPackets ) +{ + network = validate(getNetwork(), 3, 1).front(); +} + +BOOST_AUTO_TEST_SUITE_END(); + +BOOST_FIXTURE_TEST_SUITE(ValidateTestDataService, ServiceTester); + +BOOST_AUTO_TEST_CASE( servicePackets ) +{ + streams = validate(getServices(), 25, 8); +} + +BOOST_AUTO_TEST_SUITE_END(); + +BOOST_FIXTURE_TEST_SUITE(ValidateTestDataEvents1, Events1Tester); + +BOOST_AUTO_TEST_CASE( events1Packets ) +{ + validate(getEvents1(), 64266, 23132); +} + +BOOST_AUTO_TEST_CASE( events2Packets ) +{ + validate(getEvents2(), 64847, 23126); +} + +BOOST_AUTO_TEST_SUITE_END(); + diff --git a/p2pvr/devices/mockTuner.cpp b/p2pvr/devices/mockTuner.cpp index 8e772c6..706bbd9 100644 --- a/p2pvr/devices/mockTuner.cpp +++ b/p2pvr/devices/mockTuner.cpp @@ -12,24 +12,8 @@ extern "C" { \ static const Ice::ByteSeq resource(&resource##_start, &resource##_end); namespace P2PVR { +namespace DVB { namespace Testing { -void -MockTuner::LZMA_ASSERT(int ret_xz) -{ - if (ret_xz != LZMA_OK) { - MockTuner::logger->messagebf(LOG::ERR, "%s: LZMA error (%d)", __PRETTY_FUNCTION__, ret_xz); - throw P2PVR::DeviceError("LZMA", "Decompressor error", ret_xz); - } -} - -ResourceFile(network); -ResourceFile(services); -ResourceFile(events1); -ResourceFile(events2); -ResourceFile(pat); -ResourceFile(pmt); -ResourceFile(vid); - int MockTuner::eventSet = 0; IceTray::Logging::LoggerPtr MockTuner::logger = LOGMANAGER()->getLogger<MockTuner>(); @@ -61,45 +45,11 @@ class MockFrontend : public DVB::Frontend { MockTuner::MockTuner(const boost::filesystem::path & deviceFrontend, Ice::CommunicatorPtr c) : TunerI(deviceFrontend, DVB::FrontendPtr(new MockFrontend(this, dvb_frontend_info(), logger))), + MockData(c), ic(c) { } -Ice::ByteSeq MockTuner::Decompress(const Ice::ByteSeq & dataxz) -{ - lzma_stream strm = LZMA_STREAM_INIT; - const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED; - const uint64_t memory_limit = UINT64_MAX; - LZMA_ASSERT(lzma_stream_decoder(&strm, memory_limit, flags)); - strm.next_in = &dataxz.front(); - strm.avail_in = dataxz.size(); - uint8_t buf[BUFSIZ]; - - Ice::ByteSeq data; - data.reserve(dataxz.size() * 20); - do { - strm.next_out = buf; - strm.avail_out = BUFSIZ; - LZMA_ASSERT(lzma_code(&strm, LZMA_RUN)); - for (auto idx = 0u; idx < BUFSIZ - strm.avail_out; idx += 1) { - data.push_back(buf[idx]); - } - } while (strm.avail_out == 0); - data.shrink_to_fit(); - return data; -} - -std::list<Ice::ByteSeq> -MockTuner::DecompressAndRead(const Ice::ByteSeq & dataxz) const -{ - logger->messagef(LOG::DEBUG, "%s: decompress %zu bytes", __PRETTY_FUNCTION__, dataxz.size()); - std::list<Ice::ByteSeq> packets; - auto istrm = Ice::createInputStream(ic, Decompress(dataxz)); - istrm->read(packets); - logger->messagef(LOG::DEBUG, "%s: read %zu packets", __PRETTY_FUNCTION__, packets.size()); - return packets; -} - AdHoc::FileUtils::FileHandle MockTuner::OpenDemux() const { @@ -111,6 +61,7 @@ MockTuner::iopoll(struct pollfd *fds, nfds_t nfds, int) const { auto & packets = selectedPackets[fds[0].fd]; if (packets.empty()) { + sleep(1); return -2; } if (nfds > 0) { @@ -169,19 +120,19 @@ MockTuner::RequestPID(int pid, int fh) const logger->messagef(LOG::DEBUG, "%s: pid %x, fh %d", __PRETTY_FUNCTION__, pid, fh); switch (pid) { case 0: // pat - selectedPackets[fh] = DecompressAndRead(pat); + selectedPackets[fh] = getPAT(); break; case 0x10: - selectedPackets[fh] = DecompressAndRead(network); + selectedPackets[fh] = getNetwork(); break; case 0x11: - selectedPackets[fh] = DecompressAndRead(services); + selectedPackets[fh] = getServices(); break; case 0x12: - selectedPackets[fh] = DecompressAndRead(eventSet == 0 ? events1 : events2); + selectedPackets[fh] = (eventSet == 0 ? getEvents1() : getEvents2()); break; case 100: // sample pmt - selectedPackets[fh] = DecompressAndRead(pmt); + selectedPackets[fh] = getPMT(); break; } } @@ -190,9 +141,10 @@ void MockTuner::RequestTS(const PacketIds & pids, int fh) const { logger->messagef(LOG::DEBUG, "%s: pids %zu, fh %d", __PRETTY_FUNCTION__, pids.size(), fh); - selectedPackets[fh] = DecompressAndRead(vid); + selectedPackets[fh] = getVideo(); } } } +} diff --git a/p2pvr/devices/mockTuner.h b/p2pvr/devices/mockTuner.h index 74578db..2277deb 100644 --- a/p2pvr/devices/mockTuner.h +++ b/p2pvr/devices/mockTuner.h @@ -7,10 +7,12 @@ #include <boost/thread.hpp> #include <logger.h> #include "tuner.h" +#include "mockData.h" namespace P2PVR { +namespace DVB { namespace Testing { -class DLL_PUBLIC MockTuner : public DVB::TunerI { +class DLL_PUBLIC MockTuner : public DVB::TunerI, MockData { public: MockTuner(const boost::filesystem::path & deviceFrontend, Ice::CommunicatorPtr); @@ -25,10 +27,6 @@ class DLL_PUBLIC MockTuner : public DVB::TunerI { ssize_t ioread(int fd, void *buf, size_t count) const override; int ioselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) const override; - static Ice::ByteSeq Decompress(const Ice::ByteSeq &); - static void LZMA_ASSERT(int ret_xz); - std::list<Ice::ByteSeq> DecompressAndRead(const Ice::ByteSeq &) const; - Ice::CommunicatorPtr ic; // The open fh -> list of DVB packets mutable std::map<int, std::list<Ice::ByteSeq>> selectedPackets; @@ -38,6 +36,7 @@ class DLL_PUBLIC MockTuner : public DVB::TunerI { }; } } +} #endif diff --git a/p2pvr/devices/sampleSiData/events1.datxz b/p2pvr/devices/sampleSiData/events1.datxz Binary files differindex 43358a9..dff36dc 100644 --- a/p2pvr/devices/sampleSiData/events1.datxz +++ b/p2pvr/devices/sampleSiData/events1.datxz diff --git a/p2pvr/devices/sampleSiData/events2.datxz b/p2pvr/devices/sampleSiData/events2.datxz Binary files differindex b2fa9c2..035bfaf 100644 --- a/p2pvr/devices/sampleSiData/events2.datxz +++ b/p2pvr/devices/sampleSiData/events2.datxz diff --git a/p2pvr/devices/sampleSiData/network.datxz b/p2pvr/devices/sampleSiData/network.datxz Binary files differindex f2e74cd..b779e5f 100644 --- a/p2pvr/devices/sampleSiData/network.datxz +++ b/p2pvr/devices/sampleSiData/network.datxz diff --git a/p2pvr/devices/sampleSiData/services.datxz b/p2pvr/devices/sampleSiData/services.datxz Binary files differindex 0961e92..89509d7 100644 --- a/p2pvr/devices/sampleSiData/services.datxz +++ b/p2pvr/devices/sampleSiData/services.datxz diff --git a/p2pvr/devices/tuner.cpp b/p2pvr/devices/tuner.cpp index d3d0488..7358428 100644 --- a/p2pvr/devices/tuner.cpp +++ b/p2pvr/devices/tuner.cpp @@ -181,7 +181,6 @@ TunerI::ReadDemuxAndSend(AdHoc::FileUtils::FileHandle demux, const RawDataClient // Wait for data to appear switch (iopoll(&ufd, 1, options->DemuxReadTimeout)) { case -2: - //logger->messagef(LOG::DEBUG, "%s: All test data has been read... waiting...", __PRETTY_FUNCTION__); break; case -1: logger->messagef(LOG::ERR, "%s: poll error reading demux (%d:%s)", __PRETTY_FUNCTION__, errno, strerror(errno)); @@ -203,12 +202,10 @@ TunerI::ReadDemuxAndSend(AdHoc::FileUtils::FileHandle demux, const RawDataClient size_t n = nr; buf.resize(n); - logger->messagef(LOG::DEBUG, "%s: sending", __PRETTY_FUNCTION__); client->NewData(buf); - logger->messagef(LOG::DEBUG, "%s: sent", __PRETTY_FUNCTION__); } } - } while (!client->IsFinished() && client->HasPending()); + } while (!client->IsFinished()); auto packetsSent = client->PacketsSent(); client.reset(); logger->messagebf(LOG::DEBUG, "%s: end (sent %d packets)", __PRETTY_FUNCTION__, packetsSent); diff --git a/p2pvr/devices/tuner.h b/p2pvr/devices/tuner.h index 983d3ff..5a70e94 100644 --- a/p2pvr/devices/tuner.h +++ b/p2pvr/devices/tuner.h @@ -31,7 +31,6 @@ class DLL_PUBLIC TunerI : public Tuner { virtual void NewData(const Data &) = 0; virtual bool IsFinished() = 0; - virtual bool HasPending() = 0; uint64_t PacketsSent() const; int fileHandle() const; diff --git a/p2pvr/devices/tunerSendSi.cpp b/p2pvr/devices/tunerSendSi.cpp index 822ec14..76eb2b7 100644 --- a/p2pvr/devices/tunerSendSi.cpp +++ b/p2pvr/devices/tunerSendSi.cpp @@ -66,12 +66,6 @@ SendSiStream::IsFinished() } bool -SendSi::HasPending() -{ - return !asyncs.empty(); -} - -bool SendSi::IsValidSection(const Data & buf) { auto n = buf.size(); diff --git a/p2pvr/devices/tunerSendSi.h b/p2pvr/devices/tunerSendSi.h index e6517c6..a2b8b4f 100644 --- a/p2pvr/devices/tunerSendSi.h +++ b/p2pvr/devices/tunerSendSi.h @@ -13,7 +13,6 @@ class SendSi : public TunerI::IDataSender { void NewData(const P2PVR::Data &) override; bool IsFinished() override; - bool HasPending() override; protected: static bool crc32(const P2PVR::Data &); diff --git a/p2pvr/devices/tunerSendTs.cpp b/p2pvr/devices/tunerSendTs.cpp index 23bc3b4..0cddb93 100644 --- a/p2pvr/devices/tunerSendTs.cpp +++ b/p2pvr/devices/tunerSendTs.cpp @@ -77,11 +77,6 @@ SendTs::IsFinished() } } -bool -SendTs::HasPending() -{ - return async; -} } } diff --git a/p2pvr/devices/tunerSendTs.h b/p2pvr/devices/tunerSendTs.h index 5390882..a3f584c 100644 --- a/p2pvr/devices/tunerSendTs.h +++ b/p2pvr/devices/tunerSendTs.h @@ -13,7 +13,6 @@ class SendTs : public TunerI::IDataSender { void NewData(const P2PVR::Data &); bool IsFinished(); - bool HasPending(); private: void sendBufferChunk(); diff --git a/p2pvr/dvb/siParsers/event.cpp b/p2pvr/dvb/siParsers/event.cpp index a9ec158..26751a7 100644 --- a/p2pvr/dvb/siParsers/event.cpp +++ b/p2pvr/dvb/siParsers/event.cpp @@ -75,6 +75,11 @@ static Glib::RefPtr<Glib::Regex> seasonEpisodeRegex = Glib::Regex::create("[ ([] static Glib::RefPtr<Glib::Regex> yearRegex = Glib::Regex::create("[[(]([0-9]{4})[ ).\\]]+"); static Glib::RefPtr<Glib::Regex> flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]"); +SiEpgParser::SiEpgParser(const RequiredContentIds & serviceIds) : + SiTableParser<EventInformation, ::DVBSI::EitInformationPtr, int>(serviceIds) +{ +} + void SiEpgParser::parseDescriptor_ShortEvent(::DVBSI::EventPtr current, const u_char * data) { @@ -264,6 +269,7 @@ SiEpgParser::ParseSiTable(const EventInformation * eit, const ::DVBSI::EitInform HandleTable(e); }); } +template DLL_PUBLIC SiTableParser<EventInformation, ::DVBSI::EitInformationPtr, int>::SiTableParser(const RequiredContentIds &); template bool DLL_PUBLIC SiTableParser<EventInformation, ::DVBSI::EitInformationPtr, int>::ParseInfoTable(const u_char * data, size_t len); } } diff --git a/p2pvr/dvb/siParsers/event.h b/p2pvr/dvb/siParsers/event.h index 73da292..8c98f93 100644 --- a/p2pvr/dvb/siParsers/event.h +++ b/p2pvr/dvb/siParsers/event.h @@ -18,6 +18,7 @@ struct EventInformation { class DLL_PUBLIC SiEpgParser : public SiTableParser<EventInformation, ::DVBSI::EitInformationPtr, int> { protected: + SiEpgParser(const RequiredContentIds & serviceIds); bool CheckTableId(u_char tableId) const override; int SectionNumberShift() const override { return 3; } uint8_t FirstTableId(const EventInformation * ei) override { return (ei->header.tableid >= 0x60 ? 0x60 : 0x50); } diff --git a/p2pvr/dvb/siParsers/network.cpp b/p2pvr/dvb/siParsers/network.cpp index 9aa1525..ea39209 100644 --- a/p2pvr/dvb/siParsers/network.cpp +++ b/p2pvr/dvb/siParsers/network.cpp @@ -298,6 +298,7 @@ SiNetworkInformationParser::parseDescriptor_ServiceList(::DVBSI::NetworkTranspor data += sizeof(ServiceListDescriptor); } } +template DLL_PUBLIC SiTableParser<NetworkInformation, ::DVBSI::NetworkPtr, u_char>::SiTableParser(); template bool DLL_PUBLIC SiTableParser<NetworkInformation, ::DVBSI::NetworkPtr, u_char>::ParseInfoTable(const u_char * data, size_t len); } } diff --git a/p2pvr/dvb/siParsers/programAssociation.cpp b/p2pvr/dvb/siParsers/programAssociation.cpp index 43ef79d..64beff2 100644 --- a/p2pvr/dvb/siParsers/programAssociation.cpp +++ b/p2pvr/dvb/siParsers/programAssociation.cpp @@ -28,6 +28,7 @@ SiProgramAssociationParser::ParseSiTable(const ProgramAssociationSection * pas, (*pam)[ntohs(sd->program_number)] = HILO(sd->pid); }); } +template DLL_PUBLIC SiTableParser<ProgramAssociationSection, ProgramAssociationMapPtr, int>::SiTableParser(); template bool DLL_PUBLIC SiTableParser<ProgramAssociationSection, ProgramAssociationMapPtr, int>::ParseInfoTable(const u_char * data, size_t len); } } diff --git a/p2pvr/dvb/siParsers/programMap.cpp b/p2pvr/dvb/siParsers/programMap.cpp index 492c2c2..3491e88 100644 --- a/p2pvr/dvb/siParsers/programMap.cpp +++ b/p2pvr/dvb/siParsers/programMap.cpp @@ -47,6 +47,7 @@ SiProgramMapParser::ParseSiTable(const struct ProgramMap * pm, const ::DVBSI::Pr pms = ParseDescriptors<ProgramMapStream>(pms->data, HILO(pms->ES_info_length)); } } +template DLL_PUBLIC SiTableParser<ProgramMap, ::DVBSI::ProgramMapPtr, u_char>::SiTableParser(); template bool DLL_PUBLIC SiTableParser<ProgramMap, ::DVBSI::ProgramMapPtr, u_char>::ParseInfoTable(const u_char * data, size_t len); } } diff --git a/p2pvr/dvb/siParsers/service.cpp b/p2pvr/dvb/siParsers/service.cpp index a3fa464..9ee9341 100644 --- a/p2pvr/dvb/siParsers/service.cpp +++ b/p2pvr/dvb/siParsers/service.cpp @@ -28,6 +28,11 @@ struct ServiceDescriptor { u_char data[]; } __attribute__((packed)); +SiServicesParser::SiServicesParser(const RequiredContentIds & transportStreamIds) : + SiTableParser<TransportStreamDescriptor, ::DVBSI::TransportStreamPtr, int>(transportStreamIds) +{ +} + bool SiServicesParser::CheckTableId(u_char tableId) const { @@ -69,6 +74,7 @@ SiServicesParser::parseDescriptor_DefaultAuthority(::DVBSI::ServicePtr s, const { s->DefaultAuthority = *convert((const char *)p, len); } +template DLL_PUBLIC SiTableParser<TransportStreamDescriptor, ::DVBSI::TransportStreamPtr, int>::SiTableParser(const RequiredContentIds &); template bool DLL_PUBLIC SiTableParser<TransportStreamDescriptor, ::DVBSI::TransportStreamPtr, int>::ParseInfoTable(const u_char * data, size_t len); } } diff --git a/p2pvr/dvb/siParsers/service.h b/p2pvr/dvb/siParsers/service.h index 6834f52..b8c2b86 100644 --- a/p2pvr/dvb/siParsers/service.h +++ b/p2pvr/dvb/siParsers/service.h @@ -16,6 +16,7 @@ struct TransportStreamDescriptor { class DLL_PUBLIC SiServicesParser : public SiTableParser<TransportStreamDescriptor, ::DVBSI::TransportStreamPtr, int> { protected: + SiServicesParser(const RequiredContentIds & transportStreamIds); bool CheckTableId(u_char tableId) const override; void ParseSiTable(const struct TransportStreamDescriptor * nit, const ::DVBSI::TransportStreamPtr &) override; diff --git a/p2pvr/dvb/siParsers/table.cpp b/p2pvr/dvb/siParsers/table.cpp index b4a052a..e1214bf 100644 --- a/p2pvr/dvb/siParsers/table.cpp +++ b/p2pvr/dvb/siParsers/table.cpp @@ -10,8 +10,13 @@ const std::string SiTableParserBase::EitEncoding("ISO6937"); const std::string SiTableParserBase::UTF8("UTF8"); SiTableParserBase::SiTableParserBase() : - startTime(time(NULL)), - incomplete(0) + parentsOnly(false) +{ +} + +SiTableParserBase::SiTableParserBase(const RequiredContentIds & p) : + parents(p), + parentsOnly(true) { } @@ -32,12 +37,6 @@ SiTableParserBase::CurrentRawData() const return *currentRawData; } -bool -SiTableParserBase::IsFinished() const -{ - return ((incomplete == 0) && (startTime < (time(NULL) - 10))); -} - SiTableParserBase::StrPtr SiTableParserBase::convert(const char * txt, size_t len) { diff --git a/p2pvr/dvb/siParsers/table.h b/p2pvr/dvb/siParsers/table.h index ec74090..30d3614 100644 --- a/p2pvr/dvb/siParsers/table.h +++ b/p2pvr/dvb/siParsers/table.h @@ -23,18 +23,19 @@ namespace P2PVR { namespace DVBSI { class DLL_PUBLIC SiTableParserBase : public P2PVR::RawDataClient { public: + typedef std::set<uint16_t> RequiredContentIds; + const P2PVR::Data & CurrentRawData() const; protected: SiTableParserBase(); + SiTableParserBase(const RequiredContentIds & requiredParents); virtual ~SiTableParserBase() = 0; typedef std::unique_ptr<Glib::ustring> StrPtr; bool NewData(const P2PVR::Data & bytes, const Ice::Current&) override; - virtual bool IsFinished() const; - static StrPtr convert(const char * txt, size_t len); static const std::string ISO10646; @@ -42,9 +43,9 @@ class DLL_PUBLIC SiTableParserBase : public P2PVR::RawDataClient { static const std::string UTF8; virtual bool ParseInfoTable(const u_char * data, size_t len) = 0; - time_t startTime; - unsigned int incomplete; std::mutex lock; + RequiredContentIds parents; + bool parentsOnly; private: const P2PVR::Data * currentRawData; @@ -88,6 +89,9 @@ struct SiDescriptorHeader { template <class TableType, class TargetType, class Key> class SiTableParser : public SiTableParserBase { protected: + SiTableParser(); + SiTableParser(const RequiredContentIds & requiredParents); + typedef std::set<uint8_t> Sections; // Section numbers typedef boost::tuple<uint8_t, Sections> TargetSections; // Last section number | Seen section numbers typedef std::map<uint8_t, TargetSections> TableTargetSections; // TableID -> Needed references diff --git a/p2pvr/dvb/siParsers/table.impl.h b/p2pvr/dvb/siParsers/table.impl.h index c5fed98..aa2fa1e 100644 --- a/p2pvr/dvb/siParsers/table.impl.h +++ b/p2pvr/dvb/siParsers/table.impl.h @@ -3,16 +3,32 @@ namespace P2PVR { namespace DVBSI { template <class TableType, class TargetType, class Key> + SiTableParser<TableType, TargetType, Key>::SiTableParser() + { + } + + template <class TableType, class TargetType, class Key> + SiTableParser<TableType, TargetType, Key>::SiTableParser(const RequiredContentIds & rcIds) : + SiTableParserBase(rcIds) + { + } + + template <class TableType, class TargetType, class Key> bool SiTableParser<TableType, TargetType, Key>::ParseInfoTable(const u_char * data, size_t len) { const u_char * dataEnd = data + len; - while (data < dataEnd) { - auto siTable = reinterpret_cast<const TableType *>(data); + bool completed = false; + for (const TableType * siTable = NULL; + data < dataEnd && (siTable = reinterpret_cast<const TableType *>(data)); + data += HILO(siTable->header.section_length) + 4) { if (siTable->header.current_next_indicator == 1 // current only, please. && CheckTableId(siTable->header.tableid)) { // only tables we're interested in, please. std::lock_guard<std::mutex> g(lock); uint16_t contentId = ntohs(siTable->header.content_id); + if (parentsOnly && parents.find(contentId) == parents.end()) { + continue; + } ContentType & content = contents[contentId]; uint8_t sectionNumber = siTable->header.section_number >> SectionNumberShift(); TableTargetSections & targetTableSections = boost::get<1>(content); @@ -23,7 +39,6 @@ namespace P2PVR { auto & obj = boost::get<0>(content); if (!obj) { obj = TargetType(new typename TargetType::element_type()); - incomplete += 1; } ParseSiTable(siTable, obj); seen.insert(sectionNumber); @@ -46,13 +61,13 @@ namespace P2PVR { else { obj = TargetType(); } - incomplete -= 1; + parents.erase(contentId); + completed = parents.empty(); } } } - data += HILO(siTable->header.section_length) + 4; } - return IsFinished(); + return completed; } template <class TableType, class TargetType, class Key> diff --git a/p2pvr/dvb/unittests/createSamples.cpp b/p2pvr/dvb/unittests/createSamples.cpp index 3c07620..d0d4890 100644 --- a/p2pvr/dvb/unittests/createSamples.cpp +++ b/p2pvr/dvb/unittests/createSamples.cpp @@ -15,10 +15,10 @@ namespace P2PVR { namespace Testing { -template <class Parser> +template <class Parser, class ... P> static -boost::tuple<Ice::CommunicatorPtr, Ice::ObjectAdapterPtr, Parser *> -standardConfig() +boost::tuple<Ice::CommunicatorPtr, Ice::ObjectAdapterPtr, IceUtil::Handle<Parser>> +standardConfig(const P & ... p) { Ice::StringSeq params { "--Ice.ThreadPool.Client.Size=5", @@ -28,7 +28,7 @@ standardConfig() }; Ice::CommunicatorPtr ic = Ice::initialize(params); auto adapter = ic->createObjectAdapterWithEndpoints("Adp", "tcp -p 12000"); - auto parser = new Parser(); + IceUtil::Handle<Parser> parser = new Parser(p...); adapter->add(parser, ic->stringToIdentity("parser")); adapter->activate(); return { ic, adapter, parser }; @@ -37,13 +37,16 @@ standardConfig() template <class Base, class Object> class SiSampleCollector : public Base { public: - SiSampleCollector() : + template<class ... P> + SiSampleCollector(const P & ... p) : + Base(p...), packets(0) { } - bool HandleTable(const Object &) override + bool HandleTable(const Object & o) override { + objects.push_back(o); return false; } @@ -55,17 +58,18 @@ class SiSampleCollector : public Base { } std::list<Data> packets; + std::list<Object> objects; private: std::mutex lock; }; -template <class Base, class Object> +template <class Base, class Object, class ... P> static -void -CaptureAndSave(const boost::filesystem::path & fileName, const boost::function<void(TunersPrx, ::DVBSI::DeliveryPtr, RawDataClientPrx)> & method) +IceUtil::Handle<SiSampleCollector<Base, Object>> +CaptureAndSave(const boost::filesystem::path & fileName, const boost::function<void(TunersPrx, ::DVBSI::DeliveryPtr, RawDataClientPrx)> & method, const P & ... pp) { - auto icp = standardConfig<SiSampleCollector<Base, Object>>(); + auto icp = standardConfig<SiSampleCollector<Base, Object>>(pp...); auto ic = boost::get<0>(icp); auto adap = boost::get<1>(icp); auto p = boost::get<2>(icp); @@ -90,7 +94,10 @@ CaptureAndSave(const boost::filesystem::path & fileName, const boost::function<v method(devs, transport, parser); BOOST_TEST_MESSAGE("Total packets: " << p->packets.size()); - BOOST_REQUIRE(p->packets.size() > 0); + BOOST_REQUIRE_GT(p->packets.size(), 0); + + BOOST_TEST_MESSAGE("Total objects: " << p->objects.size()); + BOOST_REQUIRE_GT(p->objects.size(), 0); auto out = Ice::createOutputStream(ic); out->write(p->packets); @@ -101,6 +108,7 @@ CaptureAndSave(const boost::filesystem::path & fileName, const boost::function<v BOOST_REQUIRE(outFile); BOOST_REQUIRE_EQUAL(1, fwrite(&buf.front(), buf.size(), 1, outFile)); BOOST_REQUIRE_EQUAL(0, fclose(outFile)); + return boost::get<2>(icp); } } } @@ -108,22 +116,45 @@ CaptureAndSave(const boost::filesystem::path & fileName, const boost::function<v using namespace P2PVR; using namespace P2PVR::Testing; using namespace P2PVR::DVBSI; +::DVBSI::NetworkPtr network; +std::list<::DVBSI::TransportStreamPtr> streams; BOOST_AUTO_TEST_CASE( network_sample ) { - CaptureAndSave<SiNetworkInformationParser, ::DVBSI::NetworkPtr>("network.dat", - [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendNetworkInformation(del, rdc); }); + auto parser = CaptureAndSave<SiNetworkInformationParser, ::DVBSI::NetworkPtr>("network.dat", + [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendNetworkInformation(del, rdc); }); + network = parser->objects.front(); } BOOST_AUTO_TEST_CASE( services_sample ) { - CaptureAndSave<SiServicesParser, ::DVBSI::TransportStreamPtr>("services.dat", - [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendServiceDescriptions(del, rdc); }); + SiTableParserBase::RequiredContentIds ids; + for (const auto & t : network->TransportStreams) { + if (t->Satellite || t->Cable || t->Terrestrial) { + ids.insert(t->TransportStreamId); + } + } + auto parser = CaptureAndSave<SiServicesParser, ::DVBSI::TransportStreamPtr>("services.dat", + [ids](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendServiceDescriptions(del, rdc); }, ids); + streams = parser->objects; + streams.erase(std::remove_if(streams.begin(), streams.end(), [ids](const auto & s) { + return ids.find(s->TransportStreamId) == ids.end(); + }), streams.end()); } BOOST_AUTO_TEST_CASE( events_sample ) { + SiTableParserBase::RequiredContentIds ids; + for (const auto & st : streams) { + for (const auto & s : st->Services) { + if (s->EitSchedule) { + std::cerr << "Adding " << s->ServiceId << " " << *s->Name << std::endl; + ids.insert(s->ServiceId); + } + } + } + std::cerr << "Added " << ids.size() << std::endl; CaptureAndSave<SiEpgParser, ::DVBSI::EventPtr>("events.dat", - [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendEventInformation(del, rdc); }); + [ids](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendEventInformation(del, rdc); }, ids); } diff --git a/p2pvr/dvb/unittests/network.dat b/p2pvr/dvb/unittests/network.dat Binary files differnew file mode 100644 index 0000000..b3c97fe --- /dev/null +++ b/p2pvr/dvb/unittests/network.dat diff --git a/p2pvr/dvb/unittests/services.dat b/p2pvr/dvb/unittests/services.dat Binary files differnew file mode 100644 index 0000000..74f0c51 --- /dev/null +++ b/p2pvr/dvb/unittests/services.dat |