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