add support for videotext (VBI)
[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 hardcoded recording file!");
106                         return -1;
107                 }
108                 ePtr<iDVBDemux> demux;
109                 if (m_service_handler.getDataDemux(demux))
110                 {
111                         eDebug("eDVBServiceRecord - NO DEMUX available!");
112                         return -2;
113                 }
114                 demux->createTSRecorder(m_record);
115                 if (!m_record)
116                 {
117                         eDebug("eDVBServiceRecord - no ts recorder available.");
118                         return -3;
119                 }
120                 m_record->setTargetFD(fd);
121         }
122         eDebug("starting recording..");
123         
124         eDVBServicePMTHandler::program program;
125         if (m_service_handler.getProgramInfo(program))
126                 eDebug("getting program info failed.");
127         else
128         {
129                 std::set<int> pids_to_record;
130                 
131                 pids_to_record.insert(0); // PAT
132                 
133                 if (program.pmtPid != -1)
134                         pids_to_record.insert(program.pmtPid); // PMT
135                 
136                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
137                 if (!program.videoStreams.empty())
138                 {
139                         eDebugNoNewLine(" (");
140                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
141                                 i(program.videoStreams.begin()); 
142                                 i != program.videoStreams.end(); ++i)
143                         {
144                                 pids_to_record.insert(i->pid);
145                                 if (i != program.videoStreams.begin())
146                                         eDebugNoNewLine(", ");
147                                 eDebugNoNewLine("%04x", i->pid);
148                         }
149                         eDebugNoNewLine(")");
150                 }
151                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
152                 if (!program.audioStreams.empty())
153                 {
154                         eDebugNoNewLine(" (");
155                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
156                                 i(program.audioStreams.begin()); 
157                                 i != program.audioStreams.end(); ++i)
158                         {
159                                 pids_to_record.insert(i->pid);
160                                 if (i != program.audioStreams.begin())
161                                         eDebugNoNewLine(", ");
162                                 eDebugNoNewLine("%04x", i->pid);
163                         }
164                         eDebugNoNewLine(")");
165                 }
166                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
167                 if (program.pcrPid != 0x1fff)
168                         pids_to_record.insert(program.pcrPid);
169                 eDebug(", and the text pid is %04x", program.textPid);
170                 if (program.textPid != -1)
171                         pids_to_record.insert(program.textPid); // Videotext
172
173                         /* find out which pids are NEW and which pids are obsolete.. */
174                 std::set<int> new_pids, obsolete_pids;
175                 
176                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
177                                 m_pids_active.begin(), m_pids_active.end(),
178                                 std::inserter(new_pids, new_pids.begin()));
179                 
180                 std::set_difference(
181                                 m_pids_active.begin(), m_pids_active.end(),
182                                 pids_to_record.begin(), pids_to_record.end(), 
183                                 std::inserter(new_pids, new_pids.begin())
184                                 );
185                 
186                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
187                 {
188                         eDebug("ADD PID: %04x", *i);
189                         m_record->addPID(*i);
190                 }
191                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
192                 {
193                         eDebug("REMOVED PID: %04x", *i);
194                         m_record->removePID(*i);
195                 }
196                 
197                 m_pids_active = pids_to_record;
198                 
199                 if (m_state != stateRecording)
200                 {
201                         m_record->start();
202                         m_state = stateRecording;
203                 }
204         }
205         return 0;
206 }