- fixed bogus channel sharing
[vuplus_dvbapp] / lib / dvb / dvb.cpp
1 #include <lib/dvb/idvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/dvb/dvb.h>
4 #include <lib/dvb/sec.h>
5 #include <errno.h>
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10
11 DEFINE_REF(eDVBRegisteredFrontend);
12 DEFINE_REF(eDVBRegisteredDemux);
13
14 DEFINE_REF(eDVBAllocatedFrontend);
15
16 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
17 {
18         m_fe->m_inuse++;
19 }
20
21 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
22 {
23         --m_fe->m_inuse;
24 }
25
26 DEFINE_REF(eDVBAllocatedDemux);
27
28 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
29 {
30         m_demux->m_inuse++;
31 }
32
33 eDVBAllocatedDemux::~eDVBAllocatedDemux()
34 {
35         --m_demux->m_inuse;
36 }
37
38 DEFINE_REF(eDVBResourceManager);
39
40 eDVBResourceManager *eDVBResourceManager::instance;
41
42 eDVBResourceManager::eDVBResourceManager()
43 {
44         avail = 1;
45         busy = 0;
46         m_sec = new eDVBSatelliteEquipmentControl;
47         if (!instance)
48                 instance = this;
49                 
50                 /* search available adapters... */
51
52                 // add linux devices
53         
54         int num_adapter = 0;
55         while (eDVBAdapterLinux::exist(num_adapter))
56         {
57                 addAdapter(new eDVBAdapterLinux(num_adapter));
58                 num_adapter++;
59         }
60         
61         eDebug("found %d adapter, %d frontends and %d demux", 
62                 m_adapter.size(), m_frontend.size(), m_demux.size());
63 }
64
65
66 DEFINE_REF(eDVBAdapterLinux);
67 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
68 {
69                 // scan frontends
70         int num_fe = 0;
71         
72         eDebug("scanning for frontends..");
73         while (1)
74         {
75                 struct stat s;
76                 char filename[128];
77                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
78                 if (stat(filename, &s))
79                         break;
80                 ePtr<eDVBFrontend> fe;
81
82                 int ok = 0;
83                 fe = new eDVBFrontend(m_nr, num_fe, ok);
84                 if (ok)
85                         m_frontend.push_back(fe);
86                 ++num_fe;
87         }
88         
89                 // scan demux
90         int num_demux = 0;
91         while (1)
92         {
93                 struct stat s;
94                 char filename[128];
95                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
96                 if (stat(filename, &s))
97                         break;
98                 ePtr<eDVBDemux> demux;
99                 
100                 demux = new eDVBDemux(m_nr, num_demux);
101                 m_demux.push_back(demux);
102                         
103                 ++num_demux;
104         }
105 }
106
107 int eDVBAdapterLinux::getNumDemux()
108 {
109         return m_demux.size();
110 }
111
112 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
113 {
114         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
115         while (nr && (i != m_demux.end()))
116         {
117                 --nr;
118                 ++i;
119         }
120         
121         if (i != m_demux.end())
122                 demux = *i;
123         else
124                 return -1;
125                 
126         return 0;
127 }
128
129 int eDVBAdapterLinux::getNumFrontends()
130 {
131         return m_frontend.size();
132 }
133
134 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
135 {
136         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
137         while (nr && (i != m_frontend.end()))
138         {
139                 --nr;
140                 ++i;
141         }
142         
143         if (i != m_frontend.end())
144                 fe = *i;
145         else
146                 return -1;
147                 
148         return 0;
149 }
150
151 int eDVBAdapterLinux::exist(int nr)
152 {
153         struct stat s;
154         char filename[128];
155         sprintf(filename, "/dev/dvb/adapter%d", nr);
156         if (!stat(filename, &s))
157                 return 1;
158         return 0;
159 }
160
161 eDVBResourceManager::~eDVBResourceManager()
162 {
163         if (instance == this)
164                 instance = 0;
165
166 }
167
168 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
169 {
170         int num_fe = adapter->getNumFrontends();
171         int num_demux = adapter->getNumDemux();
172         
173         m_adapter.push_back(adapter);
174         
175         int i;
176         for (i=0; i<num_demux; ++i)
177         {
178                 ePtr<eDVBDemux> demux;
179                 if (!adapter->getDemux(demux, i))
180                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
181         }
182
183         for (i=0; i<num_fe; ++i)
184         {
185                 ePtr<eDVBFrontend> frontend;
186                 if (!adapter->getFrontend(frontend, i))
187                         m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
188         }
189 }
190
191 RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr<eDVBAllocatedFrontend> &fe)
192 {
193                 /* find first unused frontend. we ignore compatibility for now. */
194         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
195                 if (!i->m_inuse)
196                 {
197                         fe = new eDVBAllocatedFrontend(i);
198                         return 0;
199                 }
200         return -1;
201 }
202
203 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux)
204 {
205                 /* find first unused demux which is on same adapter as frontend */
206         for (eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin()); i != m_demux.end(); ++i)
207                 if ((!i->m_inuse) && (i->m_adapter == fe->m_adapter))
208                 {
209                         demux = new eDVBAllocatedDemux(i);
210                         return 0;
211                 }
212         return -1;
213 }
214
215 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
216 {
217         m_list = list;
218         return 0;
219 }
220
221 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
222 {
223         list = m_list;
224         if (list)
225                 return 0;
226         else
227                 return -ENOENT;
228 }
229
230
231 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, ePtr<iDVBChannel> &channel)
232 {
233                 /* first, check if a channel is already existing. */
234         
235 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
236         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
237         {
238 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
239                 if (i->m_channel_id == channelid)
240                 {
241 //                      eDebug("found shared channel..");
242                         channel = i->m_channel;
243                         return 0;
244                 }
245         }
246         
247                 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
248                 
249                 /* allocate a frontend. */
250         
251         ePtr<eDVBAllocatedFrontend> fe;
252         
253         if (allocateFrontend(channelid, fe))
254                 return errNoFrontend;
255         
256         ePtr<eDVBAllocatedDemux> demux;
257         
258         if (allocateDemux(*fe, demux))
259                 return errNoDemux;
260         
261         RESULT res;
262         eDVBChannel *ch;
263         ch = new eDVBChannel(this, fe, demux);
264
265         ePtr<iDVBFrontend> myfe;
266         if (!ch->getFrontend(myfe))
267                 myfe->setSEC(m_sec);
268
269         res = ch->setChannel(channelid);
270         if (res)
271         {
272                 channel = 0;
273                 return errChidNotFound;
274         }
275         
276         channel = ch;
277         return 0;
278 }
279
280 RESULT eDVBResourceManager::allocateRawChannel(ePtr<iDVBChannel> &channel)
281 {
282         ePtr<eDVBAllocatedFrontend> fe;
283         
284         if (allocateFrontend(eDVBChannelID(), fe))
285                 return errNoFrontend;
286         
287         ePtr<eDVBAllocatedDemux> demux;
288         
289         if (allocateDemux(*fe, demux))
290                 return errNoDemux;
291         
292         eDVBChannel *ch;
293         ch = new eDVBChannel(this, fe, demux);
294
295         ePtr<iDVBFrontend> myfe;
296         if (!ch->getFrontend(myfe))
297                 myfe->setSEC(m_sec);
298
299         channel = ch;
300         return 0;
301 }
302
303 RESULT eDVBResourceManager::allocatePVRChannel(int caps)
304 {
305         return -1; // will nicht, mag nicht, und das interface ist auch kaputt
306 }
307
308 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
309 {
310         eDebug("add channel %p", ch);
311         m_active_channels.push_back(active_channel(chid, ch));
312         return 0;
313 }
314
315 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
316 {
317         int cnt = 0;
318         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
319         {
320                 if (i->m_channel == ch)
321                 {
322                         i = m_active_channels.erase(i);
323                         ++cnt;
324                 } else
325                         ++i;
326         }
327         ASSERT(cnt == 1);
328         if (cnt == 1)
329                 return 0;
330         return -ENOENT;
331 }
332
333 DEFINE_REF(eDVBChannel);
334
335 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend, eDVBAllocatedDemux *demux): m_state(state_idle), m_mgr(mgr)
336 {
337         m_frontend = frontend;
338         m_demux = demux;
339         
340         if (m_frontend)
341                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
342 }
343
344 eDVBChannel::~eDVBChannel()
345 {
346         if (m_channel_id)
347                 m_mgr->removeChannel(this);
348 }
349
350 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
351 {
352         eDebug("fe state changed!");
353         int state, ourstate = 0;
354         if (fe->getState(state))
355                 return;
356         
357         if (state == iDVBFrontend::stateLock)
358         {
359                 eDebug("OURSTATE: ok");
360                 ourstate = state_ok;
361         } else if (state == iDVBFrontend::stateTuning)
362         {
363                 eDebug("OURSTATE: tuning");
364                 ourstate = state_tuning;
365         } else if (state == iDVBFrontend::stateFailed)
366         {
367                 eDebug("OURSTATE: failed/unavailable");
368                 ourstate = state_unavailable;
369         } else
370                 eFatal("state unknown");
371         
372         if (ourstate != m_state)
373         {
374                 m_state = ourstate;
375                 m_stateChanged(this);
376         }
377 }
378
379 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
380 {
381         if (m_channel_id)
382                 m_mgr->removeChannel(this);
383                 
384         if (!channelid)
385                 return 0;
386
387         ePtr<iDVBChannelList> list;
388         
389         if (m_mgr->getChannelList(list))
390         {
391                 eDebug("no channel list set!");
392                 return -ENOENT;
393         }
394         
395         eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
396                 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
397
398         ePtr<iDVBFrontendParameters> feparm;
399         if (list->getChannelFrontendData(channelid, feparm))
400         {
401                 eDebug("channel not found!");
402                 return -ENOENT;
403         }
404         eDebug("allocateChannel: channel found..");
405         
406         if (!m_frontend)
407         {
408                 eDebug("no frontend to tune!");
409                 return -ENODEV;
410         }
411         
412         m_channel_id = channelid;
413         m_mgr->addChannel(channelid, this);
414         m_state = state_tuning;
415         return m_frontend->get().tune(*feparm);
416 }
417
418 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
419 {
420         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
421         return 0;
422 }
423
424 RESULT eDVBChannel::getState(int &state)
425 {
426         state = m_state;
427         return 0;
428 }
429
430 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
431 {
432         return -1;
433 }
434
435 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux)
436 {
437         demux = &m_demux->get();
438         return 0;
439 }
440
441 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
442 {
443         frontend = &m_frontend->get();
444         if (frontend)
445                 return 0;
446         else
447                 return -ENODEV;
448 }