From 63d970c72fbb12dda8d0641bd3d1b68459649c3f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 24 Aug 2017 10:28:33 +0100 Subject: 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. --- p2pvr/daemon/maintenance/events.cpp | 19 +++- p2pvr/daemon/maintenance/network.cpp | 8 +- p2pvr/daemon/maintenance/services.cpp | 9 ++ .../sql/si/allDeliveriesTransportStreamId.sql | 2 + p2pvr/daemon/sql/si/serviceIdsWithEit.sql | 4 + p2pvr/daemon/unittests/mockDevices.cpp | 2 +- p2pvr/daemon/unittests/testErrorHandling.cpp | 7 +- p2pvr/daemon/unittests/testMaint.cpp | 32 +++--- p2pvr/devices/Jamfile.jam | 28 ++++- p2pvr/devices/mockData.cpp | 75 ++++++++++++ p2pvr/devices/mockData.h | 35 ++++++ p2pvr/devices/mockDataValidate.cpp | 126 +++++++++++++++++++++ p2pvr/devices/mockTuner.cpp | 68 ++--------- p2pvr/devices/mockTuner.h | 9 +- p2pvr/devices/sampleSiData/events1.datxz | Bin 1112857 -> 1532360 bytes p2pvr/devices/sampleSiData/events2.datxz | Bin 1108428 -> 1542916 bytes p2pvr/devices/sampleSiData/network.datxz | Bin 1244 -> 1532 bytes p2pvr/devices/sampleSiData/services.datxz | Bin 2392 -> 3164 bytes p2pvr/devices/tuner.cpp | 5 +- p2pvr/devices/tuner.h | 1 - p2pvr/devices/tunerSendSi.cpp | 6 - p2pvr/devices/tunerSendSi.h | 1 - p2pvr/devices/tunerSendTs.cpp | 5 - p2pvr/devices/tunerSendTs.h | 1 - p2pvr/dvb/siParsers/event.cpp | 6 + p2pvr/dvb/siParsers/event.h | 1 + p2pvr/dvb/siParsers/network.cpp | 1 + p2pvr/dvb/siParsers/programAssociation.cpp | 1 + p2pvr/dvb/siParsers/programMap.cpp | 1 + p2pvr/dvb/siParsers/service.cpp | 6 + p2pvr/dvb/siParsers/service.h | 1 + p2pvr/dvb/siParsers/table.cpp | 15 ++- p2pvr/dvb/siParsers/table.h | 12 +- p2pvr/dvb/siParsers/table.impl.h | 27 ++++- p2pvr/dvb/unittests/createSamples.cpp | 63 ++++++++--- p2pvr/dvb/unittests/network.dat | Bin 0 -> 2809 bytes p2pvr/dvb/unittests/services.dat | Bin 0 -> 11274 bytes 37 files changed, 436 insertions(+), 141 deletions(-) create mode 100644 p2pvr/daemon/sql/si/allDeliveriesTransportStreamId.sql create mode 100644 p2pvr/daemon/sql/si/serviceIdsWithEit.sql create mode 100644 p2pvr/devices/mockData.cpp create mode 100644 p2pvr/devices/mockData.h create mode 100644 p2pvr/devices/mockDataValidate.cpp create mode 100644 p2pvr/dvb/unittests/network.dat create mode 100644 p2pvr/dvb/unittests/services.dat 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 #include #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>(*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 parser(ice.adapter, new SiEventsHandler(ch, logger)); + TemporaryIceAdapterObject 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 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(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 #include #include +#include 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>(*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(), IceUtil::Optional(), - 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->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(), IceUtil::Optional(), + 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(), IceUtil::Optional(), - 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 ] : boost_system boost_filesystem @@ -40,9 +41,8 @@ IMPORT $(__name__) : datxz.embed.asm : : datxz.embed.asm ; lib p2pvrMockTuner : mockTuner.cpp - [ glob-tree *.datxz ] : - lzma + mockdata boost_system boost_thread boost_filesystem @@ -60,3 +60,25 @@ lib p2pvrMockTuner : . ; +lib mockdata : + mockData.cpp + [ glob-tree *.datxz ] + : + lzma + ../ice//p2pvrice + ../ice//p2pvrice + ; + +run + mockDataValidate.cpp + : : : + ../dvb//p2pvrdvb + ../ice//p2pvrice + ..//adhocutil + ..//icetray + mockdata + boost_filesystem + boost_system + ..//boost_utf + 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 +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mockData.h" + +BOOST_TEST_DONT_PRINT_LOG_VALUE(P2PVR::DVB::Testing::MockData::PacketList::const_iterator); + +template +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 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 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(); @@ -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 -MockTuner::DecompressAndRead(const Ice::ByteSeq & dataxz) const -{ - logger->messagef(LOG::DEBUG, "%s: decompress %zu bytes", __PRETTY_FUNCTION__, dataxz.size()); - std::list 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 #include #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 DecompressAndRead(const Ice::ByteSeq &) const; - Ice::CommunicatorPtr ic; // The open fh -> list of DVB packets mutable std::map> 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 index 43358a9..dff36dc 100644 Binary files a/p2pvr/devices/sampleSiData/events1.datxz and b/p2pvr/devices/sampleSiData/events1.datxz differ diff --git a/p2pvr/devices/sampleSiData/events2.datxz b/p2pvr/devices/sampleSiData/events2.datxz index b2fa9c2..035bfaf 100644 Binary files a/p2pvr/devices/sampleSiData/events2.datxz and b/p2pvr/devices/sampleSiData/events2.datxz differ diff --git a/p2pvr/devices/sampleSiData/network.datxz b/p2pvr/devices/sampleSiData/network.datxz index f2e74cd..b779e5f 100644 Binary files a/p2pvr/devices/sampleSiData/network.datxz and b/p2pvr/devices/sampleSiData/network.datxz differ diff --git a/p2pvr/devices/sampleSiData/services.datxz b/p2pvr/devices/sampleSiData/services.datxz index 0961e92..89509d7 100644 Binary files a/p2pvr/devices/sampleSiData/services.datxz and b/p2pvr/devices/sampleSiData/services.datxz differ 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 @@ -65,12 +65,6 @@ SendSiStream::IsFinished() } } -bool -SendSi::HasPending() -{ - return !asyncs.empty(); -} - bool SendSi::IsValidSection(const Data & buf) { 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 seasonEpisodeRegex = Glib::Regex::create("[ ([] static Glib::RefPtr yearRegex = Glib::Regex::create("[[(]([0-9]{4})[ ).\\]]+"); static Glib::RefPtr flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]"); +SiEpgParser::SiEpgParser(const RequiredContentIds & serviceIds) : + SiTableParser(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::SiTableParser(const RequiredContentIds &); template bool DLL_PUBLIC SiTableParser::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 { 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::SiTableParser(); template bool DLL_PUBLIC SiTableParser::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::SiTableParser(); template bool DLL_PUBLIC SiTableParser::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(pms->data, HILO(pms->ES_info_length)); } } +template DLL_PUBLIC SiTableParser::SiTableParser(); template bool DLL_PUBLIC SiTableParser::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(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::SiTableParser(const RequiredContentIds &); template bool DLL_PUBLIC SiTableParser::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 { 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 RequiredContentIds; + const P2PVR::Data & CurrentRawData() const; protected: SiTableParserBase(); + SiTableParserBase(const RequiredContentIds & requiredParents); virtual ~SiTableParserBase() = 0; typedef std::unique_ptr 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 SiTableParser : public SiTableParserBase { protected: + SiTableParser(); + SiTableParser(const RequiredContentIds & requiredParents); + typedef std::set Sections; // Section numbers typedef boost::tuple TargetSections; // Last section number | Seen section numbers typedef std::map 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 @@ -2,17 +2,33 @@ namespace P2PVR { namespace DVBSI { + template + SiTableParser::SiTableParser() + { + } + + template + SiTableParser::SiTableParser(const RequiredContentIds & rcIds) : + SiTableParserBase(rcIds) + { + } + template bool SiTableParser::ParseInfoTable(const u_char * data, size_t len) { const u_char * dataEnd = data + len; - while (data < dataEnd) { - auto siTable = reinterpret_cast(data); + bool completed = false; + for (const TableType * siTable = NULL; + data < dataEnd && (siTable = reinterpret_cast(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 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 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 +template static -boost::tuple -standardConfig() +boost::tuple> +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 = new Parser(p...); adapter->add(parser, ic->stringToIdentity("parser")); adapter->activate(); return { ic, adapter, parser }; @@ -37,13 +37,16 @@ standardConfig() template class SiSampleCollector : public Base { public: - SiSampleCollector() : + template + 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 packets; + std::list objects; private: std::mutex lock; }; -template +template static -void -CaptureAndSave(const boost::filesystem::path & fileName, const boost::function & method) +IceUtil::Handle> +CaptureAndSave(const boost::filesystem::path & fileName, const boost::function & method, const P & ... pp) { - auto icp = standardConfig>(); + auto icp = standardConfig>(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::functionpackets.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(icp); } } } @@ -108,22 +116,45 @@ CaptureAndSave(const boost::filesystem::path & fileName, const boost::function streams; BOOST_AUTO_TEST_CASE( network_sample ) { - CaptureAndSave("network.dat", - [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendNetworkInformation(del, rdc); }); + auto parser = CaptureAndSave("network.dat", + [](TunersPrx t, ::DVBSI::DeliveryPtr del, RawDataClientPrx rdc) { t->SendNetworkInformation(del, rdc); }); + network = parser->objects.front(); } BOOST_AUTO_TEST_CASE( services_sample ) { - CaptureAndSave("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("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("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 new file mode 100644 index 0000000..b3c97fe Binary files /dev/null and b/p2pvr/dvb/unittests/network.dat differ diff --git a/p2pvr/dvb/unittests/services.dat b/p2pvr/dvb/unittests/services.dat new file mode 100644 index 0000000..74f0c51 Binary files /dev/null and b/p2pvr/dvb/unittests/services.dat differ -- cgit v1.2.3