856b8c96e97dcb1c855dc72d5e31cae77437c852
[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                 eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
124                 if (!program.videoStreams.empty())
125                 {
126                         eDebugNoNewLine(" (");
127                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
128                                 i(program.videoStreams.begin()); 
129                                 i != program.videoStreams.end(); ++i)
130                         {
131                                 pids_to_record.insert(i->pid);
132                                 if (i != program.videoStreams.begin())
133                                         eDebugNoNewLine(", ");
134                                 eDebugNoNewLine("%04x", i->pid);
135                         }
136                         eDebugNoNewLine(")");
137                 }
138                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
139                 if (!program.audioStreams.empty())
140                 {
141                         eDebugNoNewLine(" (");
142                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
143                                 i(program.audioStreams.begin()); 
144                                 i != program.audioStreams.end(); ++i)
145                         {
146                                 pids_to_record.insert(i->pid);
147                                 if (i != program.audioStreams.begin())
148                                         eDebugNoNewLine(", ");
149                                 eDebugNoNewLine("%04x", i->pid);
150                         }
151                         eDebugNoNewLine(")");
152                 }
153                 eDebug(", and the pcr pid is %04x", program.pcrPid);
154                 if (program.pcrPid != 0x1fff)
155                         pids_to_record.insert(program.pcrPid);
156                 
157                         /* find out which pids are NEW and which pids are obsolete.. */
158                 std::set<int> new_pids, obsolete_pids;
159                 
160                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
161                                 m_pids_active.begin(), m_pids_active.end(),
162                                 std::inserter(new_pids, new_pids.begin()));
163                 
164                 std::set_difference(
165                                 m_pids_active.begin(), m_pids_active.end(),
166                                 pids_to_record.begin(), pids_to_record.end(), 
167                                 std::inserter(new_pids, new_pids.begin())
168                                 );
169                 
170                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
171                 {
172                         eDebug("ADD PID: %04x", *i);
173                         m_record->addPID(*i);
174                 }
175                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
176                 {
177                         eDebug("REMOVED PID: %04x", *i);
178                         m_record->removePID(*i);
179                 }
180                 
181                 if (m_state != stateRecording)
182                 {
183                         m_record->start();
184                         m_state = stateRecording;
185                 }
186         }
187         return 0;
188 }