fix for canAllocateChannel
[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|O_LARGEFILE, 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                 return doPrepare();
69         else
70                 return -1;
71 }
72
73 RESULT eDVBServiceRecord::start()
74 {
75         m_want_record = 1;
76                 /* when tune wasn't yet successfully, doRecord stays in "prepared"-state which is fine. */
77         return doRecord();
78 }
79
80
81 RESULT eDVBServiceRecord::stop()
82 {
83         eDebug("stop recording!!");
84         if (m_state == stateRecording)
85         {
86                 m_record->stop();
87                 m_state = statePrepared;
88         }
89         
90         if (m_state == statePrepared)
91         {
92                 m_record = 0;
93                 m_state = stateIdle;
94         }
95         return 0;
96 }
97
98
99 int eDVBServiceRecord::doPrepare()
100 {
101                 /* allocate a ts recorder if we don't already have one. */
102         if (m_state == stateIdle)
103         {
104                 m_pids_active.clear();
105                 m_state = statePrepared;
106                 return m_service_handler.tune(m_ref);
107         }
108         return 0;
109 }
110
111 int eDVBServiceRecord::doRecord()
112 {
113         int err = doPrepare();
114         if (err)
115                 return err;
116         
117         if (!m_record)
118         {
119                 eDebug("demux not available (tune failed?). cannot record.");
120                 return -1;
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                 eDebug(", and the pcr pid is %04x", program.pcrPid);
167                 if (program.pcrPid != 0x1fff)
168                         pids_to_record.insert(program.pcrPid);
169                 
170                         /* find out which pids are NEW and which pids are obsolete.. */
171                 std::set<int> new_pids, obsolete_pids;
172                 
173                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
174                                 m_pids_active.begin(), m_pids_active.end(),
175                                 std::inserter(new_pids, new_pids.begin()));
176                 
177                 std::set_difference(
178                                 m_pids_active.begin(), m_pids_active.end(),
179                                 pids_to_record.begin(), pids_to_record.end(), 
180                                 std::inserter(new_pids, new_pids.begin())
181                                 );
182                 
183                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
184                 {
185                         eDebug("ADD PID: %04x", *i);
186                         m_record->addPID(*i);
187                 }
188                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
189                 {
190                         eDebug("REMOVED PID: %04x", *i);
191                         m_record->removePID(*i);
192                 }
193                 
194                 if (m_state != stateRecording)
195                 {
196                         m_record->start();
197                         m_state = stateRecording;
198                 }
199         }
200         return 0;
201 }