add bouquet support
[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                 break;
24         }
25         case eDVBServicePMTHandler::eventNewProgramInfo:
26         {
27                 if (m_state == stateIdle)
28                         doPrepare();
29                 else if (m_want_record) /* doRecord can be called from Prepared and Recording state */
30                         doRecord();
31                 break;
32         }
33         }
34 }
35
36
37 RESULT eDVBServiceRecord::prepare(const char *filename)
38 {
39         m_filename = filename;
40         if (m_state == stateIdle)
41                 return m_service_handler.tune(m_ref);
42         else
43                 return -1;
44 }
45
46 RESULT eDVBServiceRecord::start()
47 {
48         m_want_record = 1;
49                 /* when tune wasn't yet successfully, doRecord stays in "prepared"-state which is fine. */
50         return doRecord();
51 }
52
53
54 RESULT eDVBServiceRecord::stop()
55 {
56         eDebug("stop recording!!");
57         if (m_state == stateRecording)
58         {
59                 m_record->stop();
60                 m_state = statePrepared;
61         }
62         
63         if (m_state == statePrepared)
64         {
65                 m_record = 0;
66                 m_state = stateIdle;
67         }
68         return 0;
69 }
70
71
72 int eDVBServiceRecord::doPrepare()
73 {
74                 /* allocate a ts recorder if we don't already have one. */
75         if (m_state == stateIdle)
76         {
77                 eDebug("Recording to %s...", m_filename.c_str());
78                 ::remove(m_filename.c_str());
79                 int fd = ::open(m_filename.c_str(), O_WRONLY|O_CREAT, 0644);
80                 if (fd == -1)
81                 {
82                         eDebug("eDVBServiceRecord - can't open hardcoded recording file!");
83                         return -1;
84                 }
85                 ePtr<iDVBDemux> demux;
86                 if (m_service_handler.getDemux(demux))
87                 {
88                         eDebug("eDVBServiceRecord - NO DEMUX available!");
89                         return -2;
90                 }
91                 demux->createTSRecorder(m_record);
92                 if (!m_record)
93                 {
94                         eDebug("eDVBServiceRecord - no ts recorder available.");
95                         return -3;
96                 }
97                 m_record->setTargetFD(fd);
98                 m_pids_active.clear();
99                 m_state = statePrepared;
100         } else if ((m_state == statePrepared) || (m_state == stateRecording))
101         {
102                         /* when we're already recording, we already have a recorder allocated. */
103                 assert(m_record);
104         }
105         return 0;
106 }
107
108 int eDVBServiceRecord::doRecord()
109 {
110         int err = doPrepare();
111         if (err)
112                 return err;
113         
114         eDebug("starting recording..");
115         
116         eDVBServicePMTHandler::program program;
117         if (m_service_handler.getProgramInfo(program))
118                 eDebug("getting program info failed.");
119         else
120         {
121                 std::set<int> pids_to_record;
122                 
123                 pids_to_record.insert(0); // PAT
124                 
125                 if (program.pmtPid != -1)
126                         pids_to_record.insert(program.pmtPid); // PMT
127                 
128                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
129                 if (!program.videoStreams.empty())
130                 {
131                         eDebugNoNewLine(" (");
132                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
133                                 i(program.videoStreams.begin()); 
134                                 i != program.videoStreams.end(); ++i)
135                         {
136                                 pids_to_record.insert(i->pid);
137                                 if (i != program.videoStreams.begin())
138                                         eDebugNoNewLine(", ");
139                                 eDebugNoNewLine("%04x", i->pid);
140                         }
141                         eDebugNoNewLine(")");
142                 }
143                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
144                 if (!program.audioStreams.empty())
145                 {
146                         eDebugNoNewLine(" (");
147                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
148                                 i(program.audioStreams.begin()); 
149                                 i != program.audioStreams.end(); ++i)
150                         {
151                                 pids_to_record.insert(i->pid);
152                                 if (i != program.audioStreams.begin())
153                                         eDebugNoNewLine(", ");
154                                 eDebugNoNewLine("%04x", i->pid);
155                         }
156                         eDebugNoNewLine(")");
157                 }
158                 eDebug(", and the pcr pid is %04x", program.pcrPid);
159                 if (program.pcrPid != 0x1fff)
160                         pids_to_record.insert(program.pcrPid);
161                 
162                         /* find out which pids are NEW and which pids are obsolete.. */
163                 std::set<int> new_pids, obsolete_pids;
164                 
165                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
166                                 m_pids_active.begin(), m_pids_active.end(),
167                                 std::inserter(new_pids, new_pids.begin()));
168                 
169                 std::set_difference(
170                                 m_pids_active.begin(), m_pids_active.end(),
171                                 pids_to_record.begin(), pids_to_record.end(), 
172                                 std::inserter(new_pids, new_pids.begin())
173                                 );
174                 
175                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
176                 {
177                         eDebug("ADD PID: %04x", *i);
178                         m_record->addPID(*i);
179                 }
180                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
181                 {
182                         eDebug("REMOVED PID: %04x", *i);
183                         m_record->removePID(*i);
184                 }
185                 
186                 if (m_state != stateRecording)
187                 {
188                         m_record->start();
189                         m_state = stateRecording;
190                 }
191         }
192         return 0;
193 }