enable wrap around in epglist and servicelist
[enigma2.git] / 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         }
126         eDebug("starting recording..");
127         
128         eDVBServicePMTHandler::program program;
129         if (m_service_handler.getProgramInfo(program))
130                 eDebug("getting program info failed.");
131         else
132         {
133                 std::set<int> pids_to_record;
134                 
135                 pids_to_record.insert(0); // PAT
136                 
137                 if (program.pmtPid != -1)
138                         pids_to_record.insert(program.pmtPid); // PMT
139                 
140                 int timing_pid = -1;
141                 
142                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
143                 if (!program.videoStreams.empty())
144                 {
145                         eDebugNoNewLine(" (");
146                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
147                                 i(program.videoStreams.begin()); 
148                                 i != program.videoStreams.end(); ++i)
149                         {
150                                 pids_to_record.insert(i->pid);
151                                 
152                                 if (timing_pid == -1)
153                                         timing_pid = i->pid;
154                                 
155                                 if (i != program.videoStreams.begin())
156                                         eDebugNoNewLine(", ");
157                                 eDebugNoNewLine("%04x", i->pid);
158                         }
159                         eDebugNoNewLine(")");
160                 }
161                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
162                 if (!program.audioStreams.empty())
163                 {
164                         eDebugNoNewLine(" (");
165                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
166                                 i(program.audioStreams.begin()); 
167                                 i != program.audioStreams.end(); ++i)
168                         {
169                                 pids_to_record.insert(i->pid);
170
171                                 if (timing_pid == -1)
172                                         timing_pid = i->pid;
173                                 
174                                 if (i != program.audioStreams.begin())
175                                         eDebugNoNewLine(", ");
176                                 eDebugNoNewLine("%04x", i->pid);
177                         }
178                         eDebugNoNewLine(")");
179                 }
180                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
181                 if (program.pcrPid != 0x1fff)
182                         pids_to_record.insert(program.pcrPid);
183                 eDebug(", and the text pid is %04x", program.textPid);
184                 if (program.textPid != -1)
185                         pids_to_record.insert(program.textPid); // Videotext
186
187                         /* find out which pids are NEW and which pids are obsolete.. */
188                 std::set<int> new_pids, obsolete_pids;
189                 
190                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
191                                 m_pids_active.begin(), m_pids_active.end(),
192                                 std::inserter(new_pids, new_pids.begin()));
193                 
194                 std::set_difference(
195                                 m_pids_active.begin(), m_pids_active.end(),
196                                 pids_to_record.begin(), pids_to_record.end(), 
197                                 std::inserter(new_pids, new_pids.begin())
198                                 );
199                 
200                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
201                 {
202                         eDebug("ADD PID: %04x", *i);
203                         m_record->addPID(*i);
204                 }
205                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
206                 {
207                         eDebug("REMOVED PID: %04x", *i);
208                         m_record->removePID(*i);
209                 }
210                 
211                 if (timing_pid != -1)
212                         m_record->setTimingPID(timing_pid);
213                 
214                 m_pids_active = pids_to_record;
215                 
216                 if (m_state != stateRecording)
217                 {
218                         m_record->start();
219                         m_state = stateRecording;
220                 }
221         }
222         return 0;
223 }