aboutsummaryrefslogtreecommitdiff
path: root/lib/dvb/dvb.h
blob: 7b3200066d2b9f4508adf932b34f1d2f382c2e9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#ifndef __dvb_dvb_h
#define __dvb_dvb_h

#ifndef SWIG

#include <lib/base/ebase.h>
#include <lib/base/filepush.h>
#include <lib/base/elock.h>
#include <lib/dvb/idvb.h>
#include <lib/dvb/demux.h>
#include <lib/dvb/frontend.h>
#include <lib/dvb/tstools.h>
#include <lib/dvb/esection.h>
#include <connection.h>

#include <dvbsi++/service_description_section.h>

class eDVBChannel;

	/* we do NOT handle resource conflicts here. instead, the allocateChannel
	   fails, and the application has to see why the channel is allocated
	   (and how to deallocate it). */
class iDVBAdapter;

class eDVBRegisteredFrontend: public iObject, public Object
{
	DECLARE_REF(eDVBRegisteredFrontend);
	ePtr<eTimer> disable;
	void closeFrontend()
	{
		if (!m_inuse && m_frontend->closeFrontend()) // frontend busy
			disable->start(60000, true);  // retry close in 60secs
	}
public:
	Signal0<void> stateChanged;
	eDVBRegisteredFrontend(eDVBFrontend *fe, iDVBAdapter *adap)
		:disable(eTimer::create(eApp)), m_adapter(adap), m_frontend(fe), m_inuse(0)
	{
		CONNECT(disable->timeout, eDVBRegisteredFrontend::closeFrontend);
	}
	void dec_use()
	{
		if (!--m_inuse)
		{
			/* emit */ stateChanged();
			disable->start(3000, true);
		}
	}
	void inc_use()
	{
		if (++m_inuse == 1)
		{
			m_frontend->openFrontend();
			/* emit */ stateChanged();
		}
	}
	iDVBAdapter *m_adapter;
	ePtr<eDVBFrontend> m_frontend;
	int m_inuse;
};

struct eDVBRegisteredDemux
{
	DECLARE_REF(eDVBRegisteredDemux);
public:
	iDVBAdapter *m_adapter;
	ePtr<eDVBDemux> m_demux;
	int m_inuse;
	eDVBRegisteredDemux(eDVBDemux *demux, iDVBAdapter *adap): m_adapter(adap), m_demux(demux), m_inuse(0) { }
};

class eDVBAllocatedFrontend
{
	DECLARE_REF(eDVBAllocatedFrontend);
public:
	
	eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe);
	~eDVBAllocatedFrontend();
	eDVBFrontend &get() { return *m_fe->m_frontend; }
	operator eDVBRegisteredFrontend*() { return m_fe; }
	operator eDVBFrontend*() { return m_fe->m_frontend; }

private:
	eDVBRegisteredFrontend *m_fe;
};

class eDVBAllocatedDemux
{
	DECLARE_REF(eDVBAllocatedDemux);
public:
	
	eDVBAllocatedDemux(eDVBRegisteredDemux *demux);
	~eDVBAllocatedDemux();
	eDVBDemux &get() { return *m_demux->m_demux; }
	operator eDVBRegisteredDemux*() { return m_demux; }
	operator eDVBDemux*() { return m_demux->m_demux; }
	
private:
	eDVBRegisteredDemux *m_demux;
};

class iDVBAdapter: public iObject
{
public:
	virtual int getNumDemux() = 0;
	virtual RESULT getDemux(ePtr<eDVBDemux> &demux, int nr) = 0;
	
	virtual int getNumFrontends() = 0;
	virtual RESULT getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate=false) = 0;
};

class eDVBAdapterLinux: public iDVBAdapter
{
	DECLARE_REF(eDVBAdapterLinux);
public:
	eDVBAdapterLinux(int nr);

	int getNumDemux();
	RESULT getDemux(ePtr<eDVBDemux> &demux, int nr);
	
	int getNumFrontends();
	RESULT getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate=false);
	
	static int exist(int nr);
private:
	int m_nr;
	eSmartPtrList<eDVBFrontend> m_frontend, m_simulate_frontend;
	eSmartPtrList<eDVBDemux>    m_demux;
};
#endif // SWIG

SWIG_IGNORE(eDVBResourceManager);
class eDVBResourceManager: public iObject, public Object
{
	DECLARE_REF(eDVBResourceManager);
	int avail, busy;

	enum { DM7025, DM800, DM500HD, DM8000 };

	int m_boxtype;

	eSmartPtrList<iDVBAdapter> m_adapter;
	eSmartPtrList<eDVBRegisteredDemux> m_demux;
	eSmartPtrList<eDVBRegisteredFrontend> m_frontend, m_simulate_frontend;
	void addAdapter(iDVBAdapter *adapter);

	struct active_channel
	{
		eDVBChannelID m_channel_id;
			/* we don't hold a reference here. */
		eDVBChannel *m_channel;
		
		active_channel(const eDVBChannelID &chid, eDVBChannel *ch) : m_channel_id(chid), m_channel(ch) { }
	};
	
	std::list<active_channel> m_active_channels, m_active_simulate_channels;
	
	ePtr<iDVBChannelList> m_list;
	ePtr<iDVBSatelliteEquipmentControl> m_sec;
	static eDVBResourceManager *instance;
	
	friend class eDVBChannel;
	RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch);
	RESULT removeChannel(eDVBChannel *ch);

	Signal1<void,eDVBChannel*> m_channelAdded;

	eUsePtr<iDVBChannel> m_cached_channel;
	Connection m_cached_channel_state_changed_conn;
	ePtr<eTimer> m_releaseCachedChannelTimer;
	void DVBChannelStateChanged(iDVBChannel*);
	void feStateChanged();
#ifndef SWIG
public:
#endif
	void releaseCachedChannel();
	eDVBResourceManager();
	virtual ~eDVBResourceManager();

	RESULT setChannelList(iDVBChannelList *list);
	RESULT getChannelList(ePtr<iDVBChannelList> &list);
	
	enum {
			/* errNoFrontend = -1 replaced by more spcific messages */
		errNoDemux    = -2,
		errChidNotFound = -3,
		errNoChannelList = -4,
		errChannelNotInList = -5,
		errAllSourcesBusy = -6,
		errNoSourceFound = -7,
	};
	
	RESULT connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection);
	int canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID &ignore, bool simulate=false);

		/* allocate channel... */
	RESULT allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate=false);
	RESULT allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel);
	static RESULT getInstance(ePtr<eDVBResourceManager> &);

			/* allocates a frontend able to tune to frontend paramters 'feperm'.
			   the frontend must be tuned lateron. there is no guarante
			   that tuning will succeed - it just means that if this frontend
			   can't tune, no other frontend could do it.

			   there might be a priority given to certain frontend/chid
			   combinations. this will be evaluated here. */
	RESULT allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate=false);

	RESULT allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index);
			/* allocate a demux able to filter on the selected frontend. */
	RESULT allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap);
#ifdef SWIG
public:
#endif
	int canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate=false);
	bool canMeasureFrontendInputPower();
	PSignal1<void,int> frontendUseMaskChanged;
	SWIG_VOID(RESULT) allocateRawChannel(eUsePtr<iDVBChannel> &SWIG_OUTPUT, int slot_index);
	PyObject *setFrontendSlotInformations(SWIG_PYOBJECT(ePyObject) list);
};
SWIG_TEMPLATE_TYPEDEF(ePtr<eDVBResourceManager>, eDVBResourceManager);
SWIG_EXTEND(ePtr<eDVBResourceManager>,
	static ePtr<eDVBResourceManager> getInstance()
	{
		extern ePtr<eDVBResourceManager> NewResourceManagerPtr(void);
		return NewResourceManagerPtr();
	}
);

#ifndef SWIG

class eDVBChannelFilePush;

	/* iDVBPVRChannel includes iDVBChannel. don't panic. */
class eDVBChannel: public iDVBPVRChannel, public iFilePushScatterGather, public Object
{
	DECLARE_REF(eDVBChannel);
	friend class eDVBResourceManager;
public:
	eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend);
	virtual ~eDVBChannel();

		/* only for managed channels - effectively tunes to the channelid. should not be used... */
		/* cannot be used for PVR channels. */
	RESULT setChannel(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &feparam);
	eDVBChannelID getChannelID() { return m_channel_id; }

	RESULT connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection);
	RESULT connectEvent(const Slot2<void,iDVBChannel*,int> &eventChange, ePtr<eConnection> &connection);
	
	RESULT getState(int &state);

	RESULT setCIRouting(const eDVBCIRouting &routing);
	RESULT getDemux(ePtr<iDVBDemux> &demux, int cap);
	RESULT getFrontend(ePtr<iDVBFrontend> &frontend);
	RESULT getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &param);

		/* iDVBPVRChannel */
	RESULT playFile(const char *file);
	void stopFile();
	
	void setCueSheet(eCueSheet *cuesheet);
	
	RESULT getLength(pts_t &len);
	RESULT getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode);

	int getUseCount() { return m_use_count; }

	RESULT requestTsidOnid(ePyObject callback);
private:
	ePtr<eDVBAllocatedFrontend> m_frontend;
	ePtr<eDVBAllocatedDemux> m_demux, m_decoder_demux;
	
	ePtr<iDVBFrontendParameters> m_current_frontend_parameters;
	eDVBChannelID m_channel_id;
	Signal1<void,iDVBChannel*> m_stateChanged;
	Signal2<void,iDVBChannel*,int> m_event;
	int m_state;

			/* for channel list */
	ePtr<eDVBResourceManager> m_mgr;
	
	void frontendStateChanged(iDVBFrontend*fe);
	ePtr<eConnection> m_conn_frontendStateChanged;
	
		/* for PVR playback */
	eDVBChannelFilePush *m_pvr_thread;
	void pvrEvent(int event);
	
	int m_pvr_fd_dst;
	eDVBTSTools m_tstools;
	
	ePtr<eCueSheet> m_cue;
	
	void cueSheetEvent(int event);
	ePtr<eConnection> m_conn_cueSheetEvent;
	int m_skipmode_m, m_skipmode_n, m_skipmode_frames, m_skipmode_frames_remainder;
	
	std::list<std::pair<off_t, off_t> > m_source_span;
	void getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size);
	void flushPVR(iDVBDemux *decoding_demux=0);
	
	eSingleLock m_cuesheet_lock;

	friend class eUsePtr<eDVBChannel>;
		/* use count */
	oRefCount m_use_count;
	void AddUse();
	void ReleaseUse();

		/* for tsid/onid read */
	ePyObject m_tsid_onid_callback;
	ePtr<iDVBDemux> m_tsid_onid_demux;
	ePtr<eTable<ServiceDescriptionSection> > m_SDT;
	void SDTready(int err);
};
#endif // SWIG

#endif