Statistics
| Branch: | Tag: | Revision:

dvbd / src / dvbcat.cpp @ 59be6a47

History | View | Annotate | Download (5.83 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 "dvbd.h"
21
#include "utils.h"
22
#include "stringutil.h"
23
#include "select.h"
24
#include "clientconnection.h"
25
#include "unixclientsocket.h"
26

    
27
#include <string>
28
#include <iostream>
29
#include <time.h>
30
#include <getopt.h>
31
#include <cerrno>
32
#include <fstream>
33

    
34
// Unfortunately, large file support (LFS) in gcc 3.2, 3.3 is broken
35
// on Debian sarge/sid. Work around with LFS_WORKAROUND
36

    
37
#define LFS_WORKAROUND
38

    
39
#ifdef LFS_WORKAROUND
40
#include <fcntl.h>
41
#include <ext/stdio_filebuf.h>
42
#endif
43

    
44
void usage(const char *progname);
45
time_t convertTime(const char *theTime);
46
std::ostream *openOutputFile(std::string &outputfile);
47
void closeOutputFile(std::ostream *o);
48

    
49
int main(int argc, char *argv[])
50
{
51
  // improve iostream performance
52
  std::ios::sync_with_stdio(false);
53

    
54
  std::string outputFile = "-";
55
  std::string socketFile = DEFAULT_SOCKET_FILE;
56
  bool durationSpecified = false;
57
  unsigned duration = 0;
58
  int priority = 10;
59
  bool convertToPS = false;
60

    
61
  while (true) {
62
    static struct option long_options[] = {
63
      {"duration", 1, 0, 'd'},
64
      {"priority", 1, 0, 'p'},
65
      {"output", 1, 0, 'o'},
66
      {"socket", 1, 0, 's'},
67
      {"ps", 0, 0, 'P'},
68
      {0, 0, 0, 0}
69
    };
70
 
71
    int option_index = 0;
72
    int c = getopt_long(argc, argv, "Pd:p:o:s:", long_options, &option_index);
73
    if (c == -1)
74
      break;
75
    switch (c) {
76
    case 'd':
77
      durationSpecified = true;
78
      duration = toInt(optarg);
79
      break;
80
    case 'p':
81
      priority = toInt(optarg);
82
      break;
83
    case 'o':
84
      outputFile = optarg;
85
      break;
86
    case 's':
87
      socketFile = optarg;
88
      break;
89
    case 'P':
90
      convertToPS = true;
91
      break;
92
    default:
93
      usage(argv[0]);
94
      return 1;
95
    }
96
  }
97

    
98
  if (argc - optind != 2) {
99
    if (argc - optind != 0)
100
      std::cerr << "Incorrect number of arguments passed (expected 2, got " 
101
                << argc - optind << ")\n\n";
102

    
103
    usage(argv[0]);
104
    return 1;
105
  }
106

    
107
  // Parse the command line arguments
108
  std::string type(argv[optind++]);
109
  std::string channel(argv[optind++]);
110

    
111
  ClientConnection client(socketFile);
112
  if (!client) {
113
    std::cerr << "Fatal error: failed to connect to server on socket " << socketFile << std::endl;
114
    return 1;
115
  }
116

    
117
  // Open the output file
118
  std::ostream *output = openOutputFile(outputFile);
119
  if (output == NULL || !*output) {
120
    std::cerr << "Fatal error: failed to open " << outputFile << " for output"
121
              << std::endl;
122
    return 1;
123
  }
124

    
125
  // Tune the channel
126
  if (!client.tune(type, channel, convertToPS, priority)) {
127
    std::cerr << "Failed to tune channel. Response from server was:\n"
128
              << client.getError() << "\n";
129
    return 1;
130
  }
131

    
132
  UnixClientSocket &control = client.control();
133
  UnixClientSocket &data = client.data();
134

    
135
  control.setBlocking(false);
136
  data.setBlocking(false);
137

    
138
  time_t start = time(NULL);
139
  Select s;
140
  do {
141
    s.clearFDs();
142
    control.addSelectFDs(s);
143
    data.addSelectFDs(s);
144

    
145
    if (durationSpecified) {
146
      unsigned elapsed = time(NULL) - start;
147
      if (elapsed >= duration*60) {
148
        std::cerr << "Duration elapsed" << std::endl;
149
        break;
150
      }
151
      s.addAlarm(duration * 60 - elapsed, 0);
152
    }
153

    
154
    s.wait();
155

    
156
    if (data.isReady(s)) {
157
      if (!data.processReady(s)) {
158
        std::cerr << "Server closed data connection" << std::endl;
159
        break;
160
      }
161

    
162
      char buffer[1024];
163
      int bytesRead = data.read(buffer, 1024);
164

    
165
      if (bytesRead > 0) 
166
        output->write(buffer, bytesRead);
167
    }
168
    else if (control.isReady(s)) {
169
      if (!control.processReady(s)) {
170
        std::cerr << "Server closed control connection" << std::endl;
171
        break;
172
      }
173

    
174
      std::string line;
175
      if (control.readLine(line)) 
176
        std::cerr << line;
177
    }
178
  } while (true);
179

    
180
  closeOutputFile(output);
181
  return 0;
182
}
183

    
184
std::ostream *openOutputFile(std::string &outputFile)
185
{
186
  if (outputFile == "-") 
187
    return &std::cout;
188

    
189
#ifndef LFS_WORKAROUND
190
  return = new std::ofstream(outputFile.c_str());
191
#else
192
  int openMode = O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE;
193

    
194
  // Don't bother caching if possible
195
#ifdef O_STREAMING
196
  openMode |= O_STREAMING;
197
#endif
198
  
199
  int fd = open(outputFile.c_str(), openMode, 0644);
200
  if (fd < 0) 
201
    return NULL;
202
  return new std::ostream(new __gnu_cxx::stdio_filebuf<char>(fd, std::ios_base::out, true, BUFSIZ));
203
#endif // LFS_WORKAROUND
204
}
205

    
206
void closeOutputFile(std::ostream *o)
207
{
208
  if (o != &std::cout)
209
    delete o;
210
}
211

    
212
void usage(const char *progname) {
213
  std::cerr << "Usage: " << progname << " [OPTION] TYPE CHANNEL\n"
214
            << "Receive DVB broadcast for channel CHANNEL, using DVB-card\n"
215
            << "\n"
216
            << "TYPE can be dvb-t, dvb-s or dvb-c.\n"
217
            << "\n"
218
            << "  -d, --duration         Time to stream for in minutes.\n"
219
            << "  -p, --priority         Priority of stream (default is 10\n"
220
            << "                         higher priorities may dislodge lower\n"
221
            << "                         ones).\n"
222
            << "  -o, --output           Record to output file\n"
223
            << "                         (default is standard output).\n"
224
            << "  -s, --socket           Specify socket to connect to\n"
225
            << "                         (default is " << DEFAULT_SOCKET_FILE << ")\n"
226
            << "  -P, --ps               Convert stream to program stream\n";
227
}