save timing information after record
[vuplus_dvbapp] / lib / service / servicedvbrecord.cpp
1 #include <lib/service/servicedvbrecord.h>
2 #include <lib/base/eerror.h>
3
4 #include <fcntl.h>
5
6 DEFINE_REF(eDVBServiceRecord);
7
8 eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref): m_ref(ref)
9 {
10         CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
11         m_state = stateIdle;
12         m_want_record = 0;
13         m_tuned = 0;
14 }
15
16 void eDVBServiceRecord::serviceEvent(int event)
17 {
18         eDebug("RECORD service event %d", event);
19         switch (event)
20         {
21         case eDVBServicePMTHandler::eventTuned:
22         {
23                 eDebug("tuned..");
24                 m_tuned = 1;
25                 if (m_state == stateRecording && m_want_record)
26                         doRecord();
27                 break;
28         }
29         case eDVBServicePMTHandler::eventNewProgramInfo:
30         {
31                 if (m_state == stateIdle)
32                         doPrepare();
33                 else if (m_want_record) /* doRecord can be called from Prepared and Recording state */
34                         doRecord();
35                 break;
36         }
37         }
38 }
39
40 RESULT eDVBServiceRecord::prepare(const char *filename)
41 {
42         m_filename = filename;
43         if (m_state == stateIdle)
44                 return doPrepare();
45         else
46                 return -1;
47 }
48
49 RESULT eDVBServiceRecord::start()
50 {
51         m_want_record = 1;
52                 /* when tune wasn't yet successfully, doRecord stays in "prepared"-state which is fine. */
53         return doRecord();
54 }
55
56
57 RESULT eDVBServiceRecord::stop()
58 {
59         eDebug("stop recording!!");
60         if (m_state == stateRecording)
61         {
62                 if (m_record)
63                         m_record->stop();
64                 m_state = statePrepared;
65         }
66         
67         if (m_state == statePrepared)
68         {
69                 m_record = 0;
70                 m_state = stateIdle;
71         }
72         return 0;
73 }
74
75
76 int eDVBServiceRecord::doPrepare()
77 {
78                 /* allocate a ts recorder if we don't already have one. */
79         if (m_state == stateIdle)
80         {
81                 m_pids_active.clear();
82                 m_state = statePrepared;
83                 return m_service_handler.tune(m_ref, 0);
84         }
85         return 0;
86 }
87
88 int eDVBServiceRecord::doRecord()
89 {
90         int err = doPrepare();
91         if (err)
92                 return err;
93         
94         if (!m_tuned)
95                 return 0; /* try it again when we are tuned in */
96         
97         if (!m_record && m_tuned)
98         {
99
100                 eDebug("Recording to %s...", m_filename.c_str());
101                 ::remove(m_filename.c_str());
102                 int fd = ::open(m_filename.c_str(), O_WRONLY|O_CREAT|O_LARGEFILE, 0644);
103                 if (fd == -1)
104                 {
105                         eDebug("eDVBServiceRecord - can't open recording file!");
106                         return -1;
107                 }
108                 
109                         /* turn off kernel caching strategies */
110                 posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
111                 
112                 ePtr<iDVBDemux> demux;
113                 if (m_service_handler.getDataDemux(demux))
114                 {
115                         eDebug("eDVBServiceRecord - NO DEMUX available!");
116                         return -2;
117                 }
118                 demux->createTSRecorder(m_record);
119                 if (!m_record)
120                 {
121                         eDebug("eDVBServiceRecord - no ts recorder available.");
122                         return -3;
123                 }
124                 m_record->setTargetFD(fd);
125                 m_record->setTargetFilename(m_filename.c_str());
126         }
127         eDebug("starting recording..");
128         
129         eDVBServicePMTHandler::program program;
130         if (m_service_handler.getProgramInfo(program))
131                 eDebug("getting program info failed.");
132         else
133         {
134                 std::set<int> pids_to_record;
135                 
136                 pids_to_record.insert(0); // PAT
137                 
138                 if (program.pmtPid != -1)
139                         pids_to_record.insert(program.pmtPid); // PMT
140                 
141                 int timing_pid = -1;
142                 
143                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
144                 if (!program.videoStreams.empty())
145                 {
146                         eDebugNoNewLine(" (");
147                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
148                                 i(program.videoStreams.begin()); 
149                                 i != program.videoStreams.end(); ++i)
150                         {
151                                 pids_to_record.insert(i->pid);
152                                 
153                                 if (timing_pid == -1)
154                                         timing_pid = i->pid;
155                                 
156                                 if (i != program.videoStreams.begin())
157                                         eDebugNoNewLine(", ");
158                                 eDebugNoNewLine("%04x", i->pid);
159                         }
160                         eDebugNoNewLine(")");
161                 }
162                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
163                 if (!program.audioStreams.empty())
164                 {
165                         eDebugNoNewLine(" (");
166                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
167                                 i(program.audioStreams.begin()); 
168                                 i != program.audioStreams.end(); ++i)
169                         {
170                                 pids_to_record.insert(i->pid);
171
172                                 if (timing_pid == -1)
173                                         timing_pid = i->pid;
174                                 
175                                 if (i != program.audioStreams.begin())
176                                         eDebugNoNewLine(", ");
177                                 eDebugNoNewLine("%04x", i->pid);
178                         }
179                         eDebugNoNewLine(")");
180                 }
181                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
182                 if (program.pcrPid != 0x1fff)
183                         pids_to_record.insert(program.pcrPid);
184                 eDebug(", and the text pid is %04x", program.textPid);
185                 if (program.textPid != -1)
186                         pids_to_record.insert(program.textPid); // Videotext
187
188                         /* find out which pids are NEW and which pids are obsolete.. */
189                 std::set<int> new_pids, obsolete_pids;
190                 
191                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
192                                 m_pids_active.begin(), m_pids_active.end(),
193                                 std::inserter(new_pids, new_pids.begin()));
194                 
195                 std::set_difference(
196                                 m_pids_active.begin(), m_pids_active.end(),
197                                 pids_to_record.begin(), pids_to_record.end(), 
198                                 std::inserter(new_pids, new_pids.begin())
199                                 );
200                 
201                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
202                 {
203                         eDebug("ADD PID: %04x", *i);
204                         m_record->addPID(*i);
205                 }
206                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
207                 {
208                         eDebug("REMOVED PID: %04x", *i);
209                         m_record->removePID(*i);
210                 }
211                 
212                 if (timing_pid != -1)
213                         m_record->setTimingPID(timing_pid);
214                 
215                 m_pids_active = pids_to_record;
216                 
217                 if (m_state != stateRecording)
218                 {
219                         m_record->start();
220                         m_state = stateRecording;
221                 }
222         }
223         return 0;
224 }