Statistics
| Branch: | Tag: | Revision:

dvbd / src / tuner.cpp @ 34667f4a

History | View | Annotate | Download (6.01 KB)

1
/*
2
  Copyright 2003 John Knottenbelt
3
  
4
  This program is free software; you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation; either version 2 of the License, or
7
  (at your option) any later version.
8
 
9
  This program is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
 
14
  You should have received a copy of the GNU General Public License
15
  along with this program; if not, write to the Free Software
16
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17
*/
18

    
19
#include "config.h"
20
#include "tuner.h"
21
#include "demuxer.h"
22
#include "tuneparams.h"
23
#include "psfilter.h"
24
#include "debug.h"
25

    
26
#include <iostream>
27
#include <cstdlib>
28
#include <cerrno>
29
#include <cstring>
30
#include <cassert>
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <fcntl.h>
34

    
35
// Size of a TS packet
36
#define TS_SIZE 188
37

    
38
Tuner::Tuner( const std::string &frontendDevice )
39
    : numReaders(0),
40
      frontendFD(-1),
41
      dvrFD(-1),
42
      tuneParams(NULL), oldTuneParams(NULL),
43
      frontendDevice(frontendDevice),
44
      state(Closed),
45
      closeRequestedTime(0)
46
{
47
  // Derive the demuxDevice from the frontend string
48
  unsigned fPos = frontendDevice.find("frontend");
49
  if (fPos == std::string::npos) {
50
    std::cerr << "Fatal error: frontendDevice not in expected form\n";
51
    exit(1);
52
  }
53

    
54
  demuxDevice = frontendDevice;
55
  demuxDevice.replace(fPos, 8, "demux" );
56

    
57
  dvrDevice = frontendDevice;
58
  dvrDevice.replace(fPos, 8, "dvr" );
59
  
60
  if (debugging) {
61
    // Debugging information
62
    std::cerr << "frontend: " << frontendDevice << "\n"
63
              << "demux: " << demuxDevice << "\n"
64
              << "dvr: " << dvrDevice << std::endl;
65
  }
66
}
67

    
68
Tuner::~Tuner()
69
{
70
  SinkList copy = subscribers;
71

    
72
  unsubscribeAll();
73

    
74
  // Destroy all the Demuxes
75
  for (DemuxerMap::iterator i = demuxerMap.begin(); i != demuxerMap.end(); i++) {
76
    PIDMap &pidmap = i->second;
77
    for (PIDMap::iterator j = pidmap.begin(); j != pidmap.end(); j++)
78
      delete j->second;
79
  }
80

    
81
  // Destroy all the PSFilters
82
  for (PSFilterMap::iterator i = psfilterMap.begin(); i != psfilterMap.end(); i++) 
83
    delete i->second;
84
}
85

    
86
void Tuner::setTuneParams(const TuneParams *tuneParams)
87
{
88
  if (numReaders > 0) {
89
    std::cerr << "Fatal error: can't change tuning parameters while readers > 0\n";
90
    exit(1);
91
  }
92
  this->tuneParams = tuneParams;
93
}
94

    
95
void Tuner::addSelectFDs(Select &s) const
96
{
97
  if (dvrFD != -1)
98
    s.addReadFD(dvrFD);
99

    
100
  if (state == Closing) {
101
    s.addAlarm(closeSecondsRemaining(), 0);
102
  }
103
}
104

    
105
bool Tuner::isReady(const Select &s) const 
106
{
107
  if (state == Closing && closeSecondsRemaining() == 0)
108
    return true;
109

    
110
  if (dvrFD == -1)
111
    return false;
112

    
113
  return s.readyToRead(dvrFD);
114
}
115

    
116
Demuxer *Tuner::makeNewDemuxer(int pid, Demuxer::PESType pesType) const
117
{
118
  return new Demuxer(const_cast<Tuner *>(this), pid, pesType);
119
}
120

    
121
// Keep a list of all the demuxers ever created
122
Source *Tuner::getDemuxer(int pid, bool convertToPS, Demuxer::PESType pesType) const
123
{
124
  // Strictly speaking getDemuxer() is not a const
125
  // method, however, it does have minimal side
126
  // effects since creating a Demuxer is not
127
  // the same thing as subscribing to one.
128

    
129
  if (pid == 0)
130
    return NULL;
131

    
132
  assert(tuneParams != NULL);
133

    
134
  DemuxerMap &dm = demuxerMap;
135
  PIDMap &pidMap = dm[tuneParams];
136
  Demuxer *&demuxer = pidMap[pid];
137

    
138
  if (demuxer == NULL) 
139
    demuxer = makeNewDemuxer(pid, pesType);
140

    
141
  if (!convertToPS) 
142
    return demuxer;
143

    
144
  PSFilter *&psfilter = psfilterMap[demuxer];
145
  if (psfilter == NULL) 
146
    psfilter = new PSFilter(demuxer);
147
  return psfilter;
148
}
149

    
150
bool Tuner::openFrontend()
151
{
152
  // Front end is already open, no need to close it.
153
  if (frontendFD != -1) {
154
    state = Open;
155
    return true;
156
  }
157
  
158
  if((frontendFD = open(frontendDevice.c_str(),O_RDWR)) < 0){
159
    std::cerr << "Error opening frontend device " << frontendDevice << ":" 
160
              << strerror(errno) << std::endl;
161
    return false;
162
  }
163
  else {
164
    state = Open;
165
    return true;
166
  }
167
}
168

    
169
unsigned Tuner::closeSecondsRemaining() const
170
{
171
  int timeRemaining = 5 + closeRequestedTime - time(NULL);
172
  return (timeRemaining < 0 ? 0 : timeRemaining);
173
}
174

    
175
void Tuner::requestCloseFrontend()
176
{
177
  if (state == Open) {
178
    state = Closing;
179
    closeRequestedTime = time(NULL);
180
  }
181
}
182

    
183
void Tuner::closeFrontend()
184
{
185
  if (frontendFD >= 0) {
186
    close(frontendFD);
187
    frontendFD = -1;
188
  }
189
  oldTuneParams = 0;
190
  state = Closed;
191
}
192

    
193
bool Tuner::openDvr()
194
{
195
  if((dvrFD = open(dvrDevice.c_str(),O_RDONLY|O_NONBLOCK)) < 0){
196
    std::cerr << "Error opening DVR device " << dvrDevice << ":" 
197
              << strerror(errno) << std::endl;
198
    return false;
199
  }
200
  return true;
201
}
202

    
203
void Tuner::closeDvr()
204
{
205
  if (dvrFD >= 0) {
206
    close(dvrFD);
207
    dvrFD = -1;
208
  }
209
}
210

    
211
bool Tuner::tune()
212
{
213
  if (tuneParams && oldTuneParams && 
214
      tuneParams->sameAsExceptPIDs(*oldTuneParams))
215
    return true;
216
  
217
  if (!tuneParams->tune(frontendFD))
218
    return false;
219
  
220
  oldTuneParams = tuneParams;
221
  return true;
222
}
223

    
224
bool Tuner::subscribe(Sink *s)
225
{
226
  // If we're waiting for the 
227
  if (state == Closing)
228
    state = Open;
229

    
230
  // On the first subscriber make sure to tune the channel
231
  // and open the dvr device 
232

    
233
  if (getNumSubscribers() == 0) {
234
    assert(tuneParams);
235
    
236
    if (!openFrontend())
237
      return false;
238

    
239
    if (!tune()) {
240
      closeFrontend();
241
      return false;
242
    }
243

    
244
    if (!openDvr()) {
245
      closeFrontend();
246
      return false;
247
    }
248

    
249
  }
250
  return Source::subscribe(s);
251
}
252

    
253
void Tuner::unsubscribe(Sink *s)
254
{
255
  Source::unsubscribe(s);
256

    
257
  // On the last subscriber close down the dvr channel
258
  if (getNumSubscribers() == 0) 
259
    requestCloseFrontend();
260
}
261

    
262
void Tuner::process() {
263
  if (state == Closing && closeSecondsRemaining() == 0) {
264
    closeDvr();
265
    closeFrontend();
266
  }
267

    
268
  if (dvrFD == -1) 
269
    return;
270

    
271
  unsigned char data[TS_SIZE];
272
  int  bytesread;
273

    
274
  if ((bytesread = read(dvrFD, (char *) data, TS_SIZE)) > 0) 
275
    sendData(data, (unsigned) bytesread);
276
}