Statistics
| Branch: | Tag: | Revision:

dvbd / src / tuner.cpp @ e386e4be

History | View | Annotate | Download (5.96 KB)

1 bfdb7446 jak
/*
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 59be6a47 jak
#include "psfilter.h"
24 bfdb7446 jak
#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 a24dbbce jak
      tuneParams(NULL), oldTuneParams(NULL),
43
      frontendDevice(frontendDevice),
44
      closeTimer(1000, &Tuner::reallyCloseFrontendCallback, this)
45 bfdb7446 jak
{
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 59be6a47 jak
  SinkList copy = subscribers;
70 bfdb7446 jak
71
  unsubscribeAll();
72
73
  // Destroy all the Demuxes
74 59be6a47 jak
  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 bfdb7446 jak
  }
79 59be6a47 jak
80
  // Destroy all the PSFilters
81
  for (PSFilterMap::iterator i = psfilterMap.begin(); i != psfilterMap.end(); i++) 
82
    delete i->second;
83 bfdb7446 jak
}
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 59be6a47 jak
Demuxer *Tuner::makeNewDemuxer(int pid, Demuxer::PESType pesType) const
108 bfdb7446 jak
{
109 59be6a47 jak
  return new Demuxer(const_cast<Tuner *>(this), pid, pesType);
110 bfdb7446 jak
}
111
112
// Keep a list of all the demuxers ever created
113 59be6a47 jak
Source *Tuner::getDemuxer(int pid, bool convertToPS, Demuxer::PESType pesType) const
114 bfdb7446 jak
{
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 59be6a47 jak
  DemuxerMap &dm = demuxerMap;
126 2cecea08 jak
  PIDMap &pidMap = dm[tuneParams];
127 bfdb7446 jak
  Demuxer *&demuxer = pidMap[pid];
128
129 59be6a47 jak
  if (demuxer == NULL) 
130
    demuxer = makeNewDemuxer(pid, pesType);
131
132
  if (!convertToPS) 
133
    return demuxer;
134 bfdb7446 jak
135 59be6a47 jak
  PSFilter *&psfilter = psfilterMap[demuxer];
136
  if (psfilter == NULL) 
137
    psfilter = new PSFilter(demuxer);
138
  return psfilter;
139 bfdb7446 jak
}
140
141
bool Tuner::openFrontend()
142
{
143 a24dbbce jak
  closeTimer.stop();
144
  
145
  // Front end is already open, no need to close it.
146
  if (frontendFD != -1) 
147
    return true;
148
  
149 bfdb7446 jak
  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 a24dbbce jak
    // 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 e386e4be jak
    std::cout << "Starting timer to close front end" << std::endl;
165 a24dbbce jak
    closeTimer.start();
166
    oldTuneParams = tuneParams;
167 bfdb7446 jak
  }
168
}
169
170 a24dbbce jak
void Tuner::reallyCloseFrontendCallback( void *arg )
171
{
172 e386e4be jak
  std::cout << "Really closing frontend" << std::endl;
173 a24dbbce jak
  Tuner *self = (Tuner *) arg;
174
  close(self->frontendFD);
175
  self->frontendFD = -1;
176
  self->oldTuneParams = 0;
177
}
178
179 bfdb7446 jak
bool Tuner::openDvr()
180
{
181
  if((dvrFD = open(dvrDevice.c_str(),O_RDONLY|O_NONBLOCK)) < 0){
182
    std::cerr << "Error opening DVR device " << dvrDevice << ":" 
183
              << strerror(errno) << std::endl;
184
    return false;
185
  }
186
  return true;
187
}
188
189
void Tuner::closeDvr()
190
{
191
  if (dvrFD >= 0) {
192
    close(dvrFD);
193
    dvrFD = -1;
194
  }
195
}
196
197
bool Tuner::tune()
198
{
199 e386e4be jak
  if (tuneParams && oldTuneParams && 
200
      tuneParams->sameAsExceptPIDs(*oldTuneParams))
201 a24dbbce jak
    return true;
202
  
203
  if (!tuneParams->tune(frontendFD))
204
    return false;
205
  
206
  oldTuneParams = tuneParams;
207
  return true;
208 bfdb7446 jak
}
209
210
bool Tuner::subscribe(Sink *s)
211
{
212
  // On the first subscriber make sure to tune the channel
213
  // and open the dvr device 
214
215
  if (getNumSubscribers() == 0) {
216
    assert(tuneParams);
217
    
218
    if (!openFrontend())
219
      return false;
220
221
    if (!tune()) {
222
      closeFrontend();
223
      return false;
224
    }
225
226
    if (!openDvr()) {
227
      closeFrontend();
228
      return false;
229
    }
230
231
  }
232
  return Source::subscribe(s);
233
}
234
235
void Tuner::unsubscribe(Sink *s)
236
{
237 e386e4be jak
  std::cout << "Unsubscribing" << std::endl;
238 bfdb7446 jak
  Source::unsubscribe(s);
239
240
  // On the last subscriber close down the dvr channel
241
  if (getNumSubscribers() == 0) {
242 e386e4be jak
    std::cout << "Closing dvr, and frontend" << std::endl;
243 bfdb7446 jak
    closeDvr();
244
    closeFrontend();
245
  }
246
}
247
248
void Tuner::process() {
249
  if (dvrFD == -1) 
250
    return;
251
252
  unsigned char data[TS_SIZE];
253
  int  bytesread;
254
255
  if ((bytesread = read(dvrFD, (char *) data, TS_SIZE)) > 0) 
256
    sendData(data, (unsigned) bytesread);
257
}