fix recording (thx to tmb)
[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), m_service_handler(1)
9 {
10         CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
11         m_state = stateIdle;
12         m_want_record = 0;
13 }
14
15 void eDVBServiceRecord::serviceEvent(int event)
16 {
17         eDebug("RECORD service event %d", event);
18         switch (event)
19         {
20         case eDVBServicePMTHandler::eventTuned:
21         {
22                 eDebug("tuned..");
23                 if (!m_record)
24                 {
25                         eDebug("Recording to %s...", m_filename.c_str());
26                         ::remove(m_filename.c_str());
27                         int fd = ::open(m_filename.c_str(), O_WRONLY|O_CREAT, 0644);
28                         if (fd == -1)
29                         {
30                                 eDebug("eDVBServiceRecord - can't open hardcoded recording file!");
31                                 return;
32 //                              return -1;
33                         }
34                         ePtr<iDVBDemux> demux;
35                         if (m_service_handler.getDemux(demux))
36                         {
37                                 eDebug("eDVBServiceRecord - NO DEMUX available!");
38                                 return;
39 //                              return -2;
40                         }
41                         demux->createTSRecorder(m_record);
42                         if (!m_record)
43                         {
44                                 eDebug("eDVBServiceRecord - no ts recorder available.");
45                                 return;
46 //                              return -3;
47                         }
48                         m_record->setTargetFD(fd);
49                 }
50                 break;
51         }
52         case eDVBServicePMTHandler::eventNewProgramInfo:
53         {
54                 if (m_state == stateIdle)
55                         doPrepare();
56                 else if (m_want_record) /* doRecord can be called from Prepared and Recording state */
57                         doRecord();
58                 break;
59         }
60         }
61 }
62
63
64 RESULT eDVBServiceRecord::prepare(const char *filename)
65 {
66         m_filename = filename;
67         if (m_state == stateIdle)
68         {
69                 doPrepare();
70                 return 0;
71         }
72         else
73                 return -1;
74 }
75
76 RESULT eDVBServiceRecord::start()
77 {
78         m_want_record = 1;
79                 /* when tune wasn't yet successfully, doRecord stays in "prepared"-state which is fine. */
80         return doRecord();
81 }
82
83
84 RESULT eDVBServiceRecord::stop()
85 {
86         eDebug("stop recording!!");
87         if (m_state == stateRecording)
88         {
89                 m_record->stop();
90                 m_state = statePrepared;
91         }
92         
93         if (m_state == statePrepared)
94         {
95                 m_record = 0;
96                 m_state = stateIdle;
97         }
98         return 0;
99 }
100
101
102 int eDVBServiceRecord::doPrepare()
103 {
104                 /* allocate a ts recorder if we don't already have one. */
105         if (m_state == stateIdle)
106         {
107                 m_pids_active.clear();
108                 m_state = statePrepared;
109                 m_service_handler.tune(m_ref);
110         }
111         return 0;
112 }
113
114 int eDVBServiceRecord::doRecord()
115 {
116         int err = doPrepare();
117         if (err)
118                 return err;
119         
120         if (!m_record)
121         {
122                 eDebug("demux not available (tune failed?). cannot record.");
123                 return -1;
124         }
125         eDebug("starting recording..");
126         
127         eDVBServicePMTHandler::program program;
128         if (m_service_handler.getProgramInfo(program))
129                 eDebug("getting program info failed.");
130         else
131         {
132                 std::set<int> pids_to_record;
133                 
134                 pids_to_record.insert(0); // PAT
135                 
136                 if (program.pmtPid != -1)
137                         pids_to_record.insert(program.pmtPid); // PMT
138                 
139                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
140                 if (!program.videoStreams.empty())
141                 {
142                         eDebugNoNewLine(" (");
143                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
144                                 i(program.videoStreams.begin()); 
145                                 i != program.videoStreams.end(); ++i)
146                         {
147                                 pids_to_record.insert(i->pid);
148                                 if (i != program.videoStreams.begin())
149                                         eDebugNoNewLine(", ");
150                                 eDebugNoNewLine("%04x", i->pid);
151                         }
152                         eDebugNoNewLine(")");
153                 }
154                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
155                 if (!program.audioStreams.empty())
156                 {
157                         eDebugNoNewLine(" (");
158                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
159                                 i(program.audioStreams.begin()); 
160                                 i != program.audioStreams.end(); ++i)
161                         {
162                                 pids_to_record.insert(i->pid);
163                                 if (i != program.audioStreams.begin())
164                                         eDebugNoNewLine(", ");
165                                 eDebugNoNewLine("%04x", i->pid);
166                         }
167                         eDebugNoNewLine(")");
168                 }
169                 eDebug(", and the pcr pid is %04x", program.pcrPid);
170                 if (program.pcrPid != 0x1fff)
171                         pids_to_record.insert(program.pcrPid);
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                 if (m_state != stateRecording)
198                 {
199                         m_record->start();
200                         m_state = stateRecording;
201                 }
202         }
203         return 0;
204 }