Statistics
| Branch: | Tag: | Revision:

dvbd / src / tuner.cpp @ a24dbbce

History | View | Annotate | Download (5.69 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
      closeTimer(1000, &Tuner::reallyCloseFrontendCallback, this)
45
{
46
  // Derive the demuxDevice from the frontend string
47
  unsigned fPos = frontendDevice.find("frontend");
48
  if (fPos == std::string::npos) {
49
    std::cerr << "Fatal error: frontendDevice not in expected form\n";
50
    exit(1);
51
  }
52

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

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

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

    
71
  unsubscribeAll();
72

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

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

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

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

    
100
bool Tuner::isReady(const Select &s) const {
101
  if (dvrFD == -1)
102
    return false;
103

    
104
  return s.readyToRead(dvrFD);
105
}
106

    
107
Demuxer *Tuner::makeNewDemuxer(int pid, Demuxer::PESType pesType) const
108
{
109
  return new Demuxer(const_cast<Tuner *>(this), pid, pesType);
110
}
111

    
112
// Keep a list of all the demuxers ever created
113
Source *Tuner::getDemuxer(int pid, bool convertToPS, Demuxer::PESType pesType) const
114
{
115
  // Strictly speaking getDemuxer() is not a const
116
  // method, however, it does have minimal side
117
  // effects since creating a Demuxer is not
118
  // the same thing as subscribing to one.
119

    
120
  if (pid == 0)
121
    return NULL;
122

    
123
  assert(tuneParams != NULL);
124

    
125
  DemuxerMap &dm = demuxerMap;
126
  PIDMap &pidMap = dm[tuneParams];
127
  Demuxer *&demuxer = pidMap[pid];
128

    
129
  if (demuxer == NULL) 
130
    demuxer = makeNewDemuxer(pid, pesType);
131

    
132
  if (!convertToPS) 
133
    return demuxer;
134

    
135
  PSFilter *&psfilter = psfilterMap[demuxer];
136
  if (psfilter == NULL) 
137
    psfilter = new PSFilter(demuxer);
138
  return psfilter;
139
}
140

    
141
bool Tuner::openFrontend()
142
{
143
  closeTimer.stop();
144
  
145
  // Front end is already open, no need to close it.
146
  if (frontendFD != -1) 
147
    return true;
148
  
149
  if((frontendFD = open(frontendDevice.c_str(),O_RDWR)) < 0){
150
    std::cerr << "Error opening frontend device " << frontendDevice << ":" 
151
              << strerror(errno) << std::endl;
152
    return false;
153
  }
154
  else 
155
    return true;
156
}
157

    
158
void Tuner::closeFrontend()
159
{
160
  if (frontendFD >= 0) {
161
    // Take a second to actually close the front end
162
    // So that if another channel of the same frequency
163
    // is requested in that time we don't have to waste time re-tuning.
164
    closeTimer.start();
165
    oldTuneParams = tuneParams;
166
  }
167
}
168

    
169
void Tuner::reallyCloseFrontendCallback( void *arg )
170
{
171
  Tuner *self = (Tuner *) arg;
172
  close(self->frontendFD);
173
  self->frontendFD = -1;
174
  self->oldTuneParams = 0;
175
}
176

    
177
bool Tuner::openDvr()
178
{
179
  if((dvrFD = open(dvrDevice.c_str(),O_RDONLY|O_NONBLOCK)) < 0){
180
    std::cerr << "Error opening DVR device " << dvrDevice << ":" 
181
              << strerror(errno) << std::endl;
182
    return false;
183
  }
184
  return true;
185
}
186

    
187
void Tuner::closeDvr()
188
{
189
  if (dvrFD >= 0) {
190
    close(dvrFD);
191
    dvrFD = -1;
192
  }
193
}
194

    
195
bool Tuner::tune()
196
{
197
  if (tuneParams == oldTuneParams)
198
    return true;
199
  
200
  if (!tuneParams->tune(frontendFD))
201
    return false;
202
  
203
  oldTuneParams = tuneParams;
204
  return true;
205
}
206

    
207
bool Tuner::subscribe(Sink *s)
208
{
209
  // On the first subscriber make sure to tune the channel
210
  // and open the dvr device 
211

    
212
  if (getNumSubscribers() == 0) {
213
    assert(tuneParams);
214
    
215
    if (!openFrontend())
216
      return false;
217

    
218
    if (!tune()) {
219
      closeFrontend();
220
      return false;
221
    }
222

    
223
    if (!openDvr()) {
224
      closeFrontend();
225
      return false;
226
    }
227

    
228
  }
229
  return Source::subscribe(s);
230
}
231

    
232
void Tuner::unsubscribe(Sink *s)
233
{
234
  Source::unsubscribe(s);
235

    
236
  // On the last subscriber close down the dvr channel
237
  if (getNumSubscribers() == 0) {
238
    closeDvr();
239
    closeFrontend();
240
  }
241
}
242

    
243
void Tuner::process() {
244
  if (dvrFD == -1) 
245
    return;
246

    
247
  unsigned char data[TS_SIZE];
248
  int  bytesread;
249

    
250
  if ((bytesread = read(dvrFD, (char *) data, TS_SIZE)) > 0) 
251
    sendData(data, (unsigned) bytesread);
252
}