Statistics
| Branch: | Tag: | Revision:

dvbd / src / dvbcat.cpp @ 1eb242d0

History | View | Annotate | Download (5.65 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

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

    
93
  if (argc - optind != 2) {
94
    if (argc - optind != 0)
95
      std::cerr << "Incorrect number of arguments passed (expected 2, got " 
96
                << argc - optind << ")\n\n";
97

    
98
    usage(argv[0]);
99
    return 1;
100
  }
101

    
102
  // Parse the command line arguments
103
  std::string type(argv[optind++]);
104
  std::string channel(argv[optind++]);
105

    
106
  ClientConnection client(socketFile);
107
  if (!client) {
108
    std::cerr << "Fatal error: failed to connect to server on socket " << socketFile << std::endl;
109
    return 1;
110
  }
111

    
112
  // Open the output file
113
  std::ostream *output = openOutputFile(outputFile);
114
  if (output == NULL || !*output) {
115
    std::cerr << "Fatal error: failed to open " << outputFile << " for output"
116
              << std::endl;
117
    return 1;
118
  }
119

    
120
  // Tune the channel
121
  if (!client.tune(type, channel, priority)) {
122
    std::cerr << "Failed to tune channel. Response from server was:\n"
123
              << client.getError() << "\n";
124
    return 1;
125
  }
126

    
127
  UnixClientSocket &control = client.control();
128
  UnixClientSocket &data = client.data();
129

    
130
  control.setBlocking(false);
131
  data.setBlocking(false);
132

    
133
  time_t start = time(NULL);
134
  Select s;
135
  do {
136
    s.clearFDs();
137
    control.addSelectFDs(s);
138
    data.addSelectFDs(s);
139

    
140
    if (durationSpecified) {
141
      unsigned elapsed = time(NULL) - start;
142
      if (elapsed >= duration*60) {
143
        std::cerr << "Duration elapsed" << std::endl;
144
        break;
145
      }
146
      s.addAlarm(duration * 60 - elapsed, 0);
147
    }
148

    
149
    s.wait();
150

    
151
    if (data.isReady(s)) {
152
      if (!data.processReady(s)) {
153
        std::cerr << "Server closed data connection" << std::endl;
154
        break;
155
      }
156

    
157
      char buffer[1024];
158
      int bytesRead = data.read(buffer, 1024);
159

    
160
      if (bytesRead > 0) 
161
        output->write(buffer, bytesRead);
162
    }
163
    else if (control.isReady(s)) {
164
      if (!control.processReady(s)) {
165
        std::cerr << "Server closed control connection" << std::endl;
166
        break;
167
      }
168

    
169
      std::string line;
170
      if (control.readLine(line)) 
171
        std::cerr << line;
172
    }
173
  } while (true);
174

    
175
  closeOutputFile(output);
176
  return 0;
177
}
178

    
179
std::ostream *openOutputFile(std::string &outputFile)
180
{
181
  if (outputFile == "-") 
182
    return &std::cout;
183

    
184
#ifndef LFS_WORKAROUND
185
  return = new std::ofstream(outputFile.c_str());
186
#else
187
  int openMode = O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE;
188

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

    
201
void closeOutputFile(std::ostream *o)
202
{
203
  if (o != &std::cout)
204
    delete o;
205
}
206

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