[FCC] Timeshift must be stopped before fast channel change.
[vuplus_dvbapp] / lib / service / servicedvbfcc.cpp
1 #include <lib/service/servicedvbfcc.h>
2 #include <lib/components/file_eraser.h>
3 #include <lib/dvb/decoder.h>
4 #include <lib/base/nconfig.h>
5
6 eDVBServiceFCCPlay::eDVBServiceFCCPlay(const eServiceReference &ref, eDVBService *service)
7         :eDVBServicePlay(ref, service, false), m_fcc_flag(0), m_fcc_mode(fcc_mode_preparing), m_fcc_mustplay(false),
8                 m_pmtVersion(-1)
9 {
10         CONNECT(m_service_handler.serviceEvent, eDVBServiceFCCPlay::serviceEvent);
11 }
12
13 eDVBServiceFCCPlay::~eDVBServiceFCCPlay()
14 {
15 }
16
17 void eDVBServiceFCCPlay::serviceEvent(int event)
18 {
19         if (!m_is_primary) // PIP mode
20         {
21                 eDVBServicePlay::serviceEvent(event);
22                 return;
23         }
24
25         m_tune_state = event;
26
27         switch (event)
28         {
29                 case eDVBServicePMTHandler::eventTuned:
30                 {
31                         eDVBServicePlay::serviceEvent(event);
32                         pushbackFCCEvents(evTunedIn);
33                         break;
34                 }
35                 case eDVBServicePMTHandler::eventNoResources:
36                 case eDVBServicePMTHandler::eventNoPAT:
37                 case eDVBServicePMTHandler::eventNoPATEntry:
38                 case eDVBServicePMTHandler::eventNoPMT:
39                 case eDVBServicePMTHandler::eventTuneFailed:
40                 case eDVBServicePMTHandler::eventMisconfiguration:
41                 {
42                         eDVBServicePlay::serviceEvent(event);
43                         pushbackFCCEvents(evTuneFailed);
44                         break;
45                 }
46                 case eDVBServicePMTHandler::eventNewProgramInfo:
47                 {
48                         eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
49                         if (m_timeshift_enabled)
50                                 updateTimeshiftPids();
51
52                         if (!m_timeshift_active)
53                                 processNewProgramInfo();
54
55                         if (!m_timeshift_active)
56                         {
57                                 m_event((iPlayableService*)this, evUpdatedInfo);
58                                 pushbackFCCEvents(evUpdatedInfo);
59                         }
60                         break;
61                 }
62                 case eDVBServicePMTHandler::eventPreStart:
63                 case eDVBServicePMTHandler::eventEOF:
64                 case eDVBServicePMTHandler::eventSOF:
65                 {
66                         eDVBServicePlay::serviceEvent(event);
67                         break;
68                 }
69                 case eDVBServicePMTHandler::eventHBBTVInfo:
70                 {
71                         eDVBServicePlay::serviceEvent(event);
72                         pushbackFCCEvents(evHBBTVInfo);
73                         break;
74                 }
75         }
76 }
77
78 RESULT eDVBServiceFCCPlay::start()
79 {
80         if (!m_is_primary) // PIP mode
81         {
82                 eDVBServicePlay::start();
83                 return 0;
84         }
85
86         if (m_fcc_flag & fcc_start) // already started
87         {
88                 changeFCCMode();
89         }
90         else
91         {
92                 m_fcc_flag |= fcc_start;
93                 pushbackFCCEvents(evStart);
94
95                 /* disable CA Interfaces on fcc_mode_preparing */
96                 m_service_handler.setCaDisable(true);
97                 eDVBServicePlay::start();
98         }
99         return 0;
100 }
101
102 void eDVBServiceFCCPlay::pushbackFCCEvents(int event)
103 {
104         if (event == evTuneFailed)
105                 m_fcc_flag |= fcc_tune_failed;
106         m_fcc_events.push_back(event);
107 }
108
109 void eDVBServiceFCCPlay::popFCCEvents()
110 {
111         m_fcc_events.unique(); // remove duplicate evUpdatedInfo
112         for (std::list<int>::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it)
113         {
114                 if (*it == evUpdatedInfo)
115                 {
116                         updateFCCDecoder();
117                         break;
118                 }
119         }
120
121         /* add CaHandler */
122         m_service_handler.addCaHandler();
123
124         /* send events */
125         for (std::list<int>::iterator it = m_fcc_events.begin(); it != m_fcc_events.end(); ++it)
126         {
127                 int event = *it;
128 //              eDebug("[eDVBServiceFCCPlay::popFCCEvents][%s] send event : %s", m_reference.toString().c_str(), eventDesc[event]);
129                 m_event((iPlayableService*)this, event);
130         }
131 }
132
133 void eDVBServiceFCCPlay::changeFCCMode()
134 {
135         if (m_fcc_mode == fcc_mode_decoding)
136         {
137                 eDebug("[eDVBServiceFCCPlay::changeFCCMode][%s] disable FCC decoding.", m_reference.toString().c_str());
138                 m_fcc_mode = fcc_mode_preparing;
139
140                 /* stop timeshift */
141                 eDVBServicePlay::stopTimeshift();
142
143                 /* remove CaHandler */
144                 m_service_handler.removeCaHandler();
145
146                 if (m_fcc_flag & fcc_tune_failed)
147                         m_event((iPlayableService*)this, evTuneFailed);
148
149                 else if (m_fcc_flag & fcc_failed)
150                         m_event((iPlayableService*)this, evFccFailed);
151
152                 FCCDecoderStop();
153         }
154         else
155         {
156                 eDebug("[eDVBServiceFCCPlay::changeFCCMode][%s] enable FCC decoding.", m_reference.toString().c_str());
157                 m_fcc_mode = fcc_mode_decoding;
158                 popFCCEvents();
159         }
160 }
161
162 void eDVBServiceFCCPlay::processNewProgramInfo(bool toLive)
163 {
164         updateFCCDecoder(toLive);
165
166         if (m_fcc_flag & fcc_failed)
167         {
168                 m_event((iPlayableService*)this, evFccFailed);
169         }
170 }
171
172 void eDVBServiceFCCPlay::updateFCCDecoder(bool sendSeekableStateChanged)
173 {
174         eDebug("[eDVBServiceFCCPlay::updateFCCDecoder][%s]", m_reference.toString().c_str());
175         int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
176         bool isProgramInfoCached = false;
177         bool pmtVersionChanged = false;
178
179         eDVBServicePMTHandler &h = m_service_handler;
180
181         eDVBServicePMTHandler::program program;
182         if (h.getProgramInfo(program))
183                 eDebug("getting program info failed.");
184         else
185         {
186                 eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
187                 if (!program.videoStreams.empty())
188                 {
189                         eDebugNoNewLine(" (");
190                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
191                                 i(program.videoStreams.begin());
192                                 i != program.videoStreams.end(); ++i)
193                         {
194                                 if (vpid == -1)
195                                 {
196                                         vpid = i->pid;
197                                         vpidtype = i->type;
198                                 }
199                                 if (i != program.videoStreams.begin())
200                                         eDebugNoNewLine(", ");
201                                 eDebugNoNewLine("%04x", i->pid);
202                         }
203                         eDebugNoNewLine(")");
204                 }
205                 eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
206                 if (!program.audioStreams.empty())
207                 {
208                         eDebugNoNewLine(" (");
209                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
210                                 i(program.audioStreams.begin());
211                                 i != program.audioStreams.end(); ++i)
212                         {
213                                 if (i != program.audioStreams.begin())
214                                         eDebugNoNewLine(", ");
215                                 eDebugNoNewLine("%04x", i->pid);
216                         }
217                         eDebugNoNewLine(")");
218                 }
219                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
220                 pcrpid = program.pcrPid;
221                 eDebugNoNewLine(", and the text pid is %04x", program.textPid);
222                 tpid = program.textPid;
223                 eDebug(" %s", program.isCached ? "(Cached)":"");
224                 isProgramInfoCached = program.isCached;
225                 if (m_pmtVersion != program.pmtVersion)
226                 {
227                         if (m_pmtVersion != -1)
228                                 pmtVersionChanged = true;
229                         m_pmtVersion = program.pmtVersion;
230                         //eDebug("[eDVBServiceFCCPlay::updateFCCDecoder] pmt version : %d", m_pmtVersion);
231                 }
232         }
233
234         if (!m_decoder)
235         {
236                 h.getDecodeDemux(m_decode_demux);
237                 if (m_decode_demux)
238                 {
239                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
240                         if (m_decoder)
241                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServiceFCCPlay::video_event), m_video_event_connection);
242                 }
243                 m_fcc_mustplay = true;
244         }
245
246         if (m_decoder)
247         {
248                 if (!((m_fcc_flag & fcc_ready)||(m_fcc_flag & fcc_novideo)))
249                 {
250                         if (vpid == -1)
251                         {
252                                 if (!isProgramInfoCached)
253                                         m_fcc_flag |= fcc_novideo;
254                         }
255                         else if ((vpidtype == -1) || (pcrpid== -1))
256                         {
257                                 if (!isProgramInfoCached)
258                                         m_fcc_flag |= fcc_failed;
259                         }
260                         else if (!m_decoder->prepareFCC(m_decode_demux->getSource(), vpid, vpidtype, pcrpid))
261                                 m_fcc_flag |= fcc_ready;
262                         else
263                                 m_fcc_flag |= fcc_failed;
264                 }
265                 else if (pmtVersionChanged)
266                 {
267                         m_decoder->fccUpdatePids(m_decode_demux->getSource(), vpid, vpidtype, pcrpid);
268                         m_fcc_flag &=~fcc_decoding;
269                 }
270         }
271
272         if (m_fcc_mode != fcc_mode_decoding)
273                 return;
274
275         /* fcc_mode_decoding */
276         if (!(m_fcc_flag & fcc_ready) && !(m_fcc_flag & fcc_novideo))
277         {
278                 eDebug("[eDVBServiceFCCPlay::updateFCCDecoder] fcc is not ready.");
279                 return;
280         }
281
282         if (m_decode_demux)
283         {
284                 if (m_is_primary)
285                 {
286                         m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
287                         m_teletext_parser->connectNewPage(slot(*this, &eDVBServiceFCCPlay::newSubtitlePage), m_new_subtitle_page_connection);
288                         m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
289                         m_subtitle_parser->connectNewPage(slot(*this, &eDVBServiceFCCPlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
290                         if (m_timeshift_changed)
291                         {
292                                 ePyObject subs = getCachedSubtitle();
293                                 if (subs != Py_None)
294                                 {
295                                         int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
296                                             pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
297                                             comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
298                                             anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
299                                         if (type == 0) // dvb
300                                                 m_subtitle_parser->start(pid, comp_page, anc_page);
301                                         else if (type == 1) // ttx
302                                                 m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
303                                 }
304                                 Py_DECREF(subs);
305                         }
306                 }
307         }
308
309         m_timeshift_changed = 0;
310
311         if (m_decoder)
312         {
313                 bool wasSeekable = m_decoder->getVideoProgressive() != -1;
314
315                 if (m_dvb_service)
316                 {
317                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
318                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
319                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
320                 }
321                 else // subservice
322                 {
323                         eServiceReferenceDVB ref;
324                         m_service_handler.getServiceReference(ref);
325                         eServiceReferenceDVB parent = ref.getParentServiceReference();
326                         if (!parent)
327                                 parent = ref;
328                         if (parent)
329                         {
330                                 ePtr<eDVBResourceManager> res_mgr;
331                                 if (!eDVBResourceManager::getInstance(res_mgr))
332                                 {
333                                         ePtr<iDVBChannelList> db;
334                                         if (!res_mgr->getChannelList(db))
335                                         {
336                                                 ePtr<eDVBService> origService;
337                                                 if (!db->getService(parent, origService))
338                                                 {
339                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
340                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
341                                                 }
342                                         }
343                                 }
344                         }
345                 }
346
347                 setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
348                 setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
349
350                 m_decoder->setVideoPID(vpid, vpidtype);
351                 selectAudioStream();
352
353                 if (!(m_is_pvr || m_is_stream || m_timeshift_active))
354                         m_decoder->setSyncPCR(pcrpid);
355                 else
356                         m_decoder->setSyncPCR(-1);
357
358                 if (m_is_primary)
359                 {
360                         m_decoder->setTextPID(tpid);
361                         m_teletext_parser->start(program.textPid);
362                 }
363
364                 if (vpid > 0 && vpid < 0x2000)
365                         ;
366                 else
367                 {
368                         std::string radio_pic;
369                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
370                                 m_decoder->setRadioPic(radio_pic);
371                 }
372
373                 /* fcc stop and decoder start */
374                 if (!(m_fcc_flag & fcc_novideo))
375                 {
376                         if (m_fcc_flag & fcc_decoding)
377                                 ;
378                         else if(!m_decoder->fccDecoderStart())
379                                 m_fcc_flag |= fcc_decoding;
380                 }
381
382                 if (m_fcc_mustplay)
383                 {
384                         m_fcc_mustplay = false;
385                         m_decoder->play();
386                 }
387                 else
388                 {
389                         m_decoder->set();
390                 }
391
392                 m_decoder->setAudioChannel(achannel);
393
394                 /* don't worry about non-existing services, nor pvr services */
395                 if (m_dvb_service)
396                 {
397                                 /* (audio pid will be set in selectAudioTrack */
398                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
399                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
400                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
401                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
402                 }
403                 if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
404                         sendSeekableStateChanged = true;
405         }
406         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
407
408         if (sendSeekableStateChanged)
409                 m_event((iPlayableService*)this, evSeekableStatusChanged);
410 }
411
412 void eDVBServiceFCCPlay::FCCDecoderStop()
413 {
414         eDebug("[eDVBServiceFCCPlay::FCCDecoderStop][%s]", m_reference.toString().c_str());
415
416         if (m_decoder)
417         {
418                 m_teletext_parser = 0;
419                 m_new_subtitle_page_connection = 0;
420                 m_subtitle_parser = 0;
421                 m_new_dvb_subtitle_page_connection = 0;
422
423                 if (m_fcc_flag & fcc_ready)
424                 {
425                         m_decoder->fccDecoderStop();
426                         m_fcc_flag &=~fcc_decoding;
427                 }
428                 else if (m_fcc_flag & fcc_novideo)
429                 {
430                         m_video_event_connection = 0;
431                         m_decoder = 0;
432                 }
433         }
434 }
435
436 void eDVBServiceFCCPlay::switchToLive()
437 {
438         if (!m_timeshift_active)
439                 return;
440
441         eDebug("eDVBServiceFCCPlay::SwitchToLive");
442
443         resetTimeshift(0);
444
445         m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
446
447         /* free the timeshift service handler, we need the resources */
448         m_service_handler_timeshift.free();
449
450         //updateDecoder(true);
451         m_fcc_flag &=~fcc_ready;
452         m_fcc_flag &=~fcc_decoding;
453         processNewProgramInfo(true);
454 }
455
456 DEFINE_REF(eDVBServiceFCCPlay)
457