diff options
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  | 
