Statistics
| Branch: | Tag: | Revision:

dvbd / src / tuner.cpp @ 59be6a47

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

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

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

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

    
70
  unsubscribeAll();
71

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

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

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

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

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

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

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

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

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

    
122
  assert(tuneParams != NULL);
123

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

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

    
131
  if (!convertToPS) 
132
    return demuxer;
133

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

    
140
bool Tuner::openFrontend()
141
{
142
  if((frontendFD = open(frontendDevice.c_str(),O_RDWR)) < 0){
143
    std::cerr << "Error opening frontend device " << frontendDevice << ":" 
144
              << strerror(errno) << std::endl;
145
    return false;
146
  }
147
  else 
148
    return true;
149
}
150

    
151
void Tuner::closeFrontend()
152
{
153
  if (frontendFD >= 0) {
154
    close(frontendFD);
155
    frontendFD = -1;
156
  }
157
}
158

    
159
bool Tuner::openDvr()
160
{
161
  if((dvrFD = open(dvrDevice.c_str(),O_RDONLY|O_NONBLOCK)) < 0){
162
    std::cerr << "Error opening DVR device " << dvrDevice << ":" 
163
              << strerror(errno) << std::endl;
164
    return false;
165
  }
166
  return true;
167
}
168

    
169
void Tuner::closeDvr()
170
{
171
  if (dvrFD >= 0) {
172
    close(dvrFD);
173
    dvrFD = -1;
174
  }
175
}
176

    
177
bool Tuner::tune()
178
{
179
  return tuneParams->tune(frontendFD);
180
}
181

    
182
bool Tuner::subscribe(Sink *s)
183
{
184
  // On the first subscriber make sure to tune the channel
185
  // and open the dvr device 
186

    
187
  if (getNumSubscribers() == 0) {
188
    assert(tuneParams);
189
    
190
    if (!openFrontend())
191
      return false;
192

    
193
    if (!tune()) {
194
      closeFrontend();
195
      return false;
196
    }
197

    
198
    if (!openDvr()) {
199
      closeFrontend();
200
      return false;
201
    }
202

    
203
  }
204
  return Source::subscribe(s);
205
}
206

    
207
void Tuner::unsubscribe(Sink *s)
208
{
209
  Source::unsubscribe(s);
210

    
211
  // On the last subscriber close down the dvr channel
212
  if (getNumSubscribers() == 0) {
213
    closeDvr();
214
    closeFrontend();
215
  }
216
}
217

    
218
void Tuner::process() {
219
  if (dvrFD == -1) 
220
    return;
221

    
222
  unsigned char data[TS_SIZE];
223
  int  bytesread;
224

    
225
  if ((bytesread = read(dvrFD, (char *) data, TS_SIZE)) > 0) 
226
    sendData(data, (unsigned) bytesread);
227
}