4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "../../guicast/bcwindowbase.inc"
23 #include "../../guicast/clip.h"
24 #include "condition.h"
25 #include "devicedvbinput.inc"
32 #include <linux/dvb/dmx.h>
33 #include <linux/dvb/frontend.h>
37 #include <sys/ioctl.h>
44 /* Frequency tables ripped straight off of pchdtv source code. */
45 /* DVB frequencies for US broadcast */
46 /* First two entries are to make the entries
47 line up with the channel number as index */
48 static unsigned long ntsc_dvb[ ] = {
49 0, 0, 57, 63, 69, 79, 85, 177, 183, 189 ,
50 195, 201, 207, 213, 473, 479, 485, 491, 497, 503 ,
51 509, 515, 521, 527, 533, 539, 545, 551, 557, 563 ,
52 569, 575, 581, 587, 593, 599, 605, 611, 617, 623 ,
53 629, 635, 641, 647, 653, 659, 665, 671, 677, 683 ,
54 689, 695, 701, 707, 713, 719, 725, 731, 737, 743 ,
55 749, 755, 761, 767, 773, 779, 785, 791, 797, 803 ,
56 809, 815, 821, 827, 833, 839, 845, 851, 857, 863 ,
57 869, 875, 881, 887, 893, 899, 905, 911, 917, 923 ,
58 929, 935, 941, 947, 953, 959, 965, 971, 977, 983 ,
59 989, 995, 1001, 1007, 1013, 1019, 1025, 1031, 1037, 1043
62 static unsigned long catv_dvb[] = {
63 0, 0, 57, 63, 69, 79, 85, 177, 183, 189,
64 195, 201, 207, 213, 123, 129, 135, 141, 147, 153,
65 159, 165, 171, 219, 225, 231, 237, 243, 249, 255,
66 261, 267, 273, 279, 285, 291, 297, 303, 309, 315,
67 321, 327, 333, 339, 345, 351, 357, 363, 369, 375,
68 381, 387, 393, 399, 405, 411, 417, 423, 429, 435,
69 441, 447, 453, 459, 465, 471, 477, 483, 489, 495,
70 501, 507, 513, 519, 525, 531, 537, 543, 549, 555,
71 561, 567, 573, 579, 585, 591, 597, 603, 609, 615,
72 621, 627, 633, 639, 645, 93, 99, 105, 111, 117,
73 651, 657, 663, 669, 675, 681, 687, 693, 699, 705,
74 711, 717, 723, 729, 735, 741, 747, 753, 759, 765,
75 771, 777, 783, 789, 795, 781, 807, 813, 819, 825,
76 831, 837, 843, 849, 855, 861, 867, 873, 879, 885,
77 891, 897, 903, 909, 915, 921, 927, 933, 939, 945,
78 951, 957, 963, 969, 975, 981, 987, 993, 999
84 DVBTune::DVBTune(RenderFarmClientThread *client)
88 buffer_lock = new Mutex("DVBTune::buffer_lock");
107 buffer_allocated = 0;
113 int DVBTune::open_tuner()
116 char frontend_path[BCTEXTLEN];
117 char demux_path[BCTEXTLEN];
118 char dvr_path[BCTEXTLEN];
120 sprintf(frontend_path, "/dev/dvb/adapter%d/frontend%d",
123 sprintf(demux_path, "/dev/dvb/adapter%d/demux%d",
126 sprintf(dvr_path, "/dev/dvb/adapter%d/dvr%d",
137 if((frontend_fd = ::open(frontend_path, O_RDWR)) < 0)
140 "DVBTune::open_tuner %s: %s\n",
147 // Open transport stream for reading
148 if((dvr_fd = ::open(dvr_path, O_RDONLY)) < 0)
151 "DVBTune::open_tuner %s: %s\n",
157 struct dvb_frontend_parameters frontend_param;
158 bzero(&frontend_param, sizeof(frontend_param));
161 int index = CLIP(TunerServer::get_channel(), 2, 69);
162 int table = TunerServer::get_table();
166 frontend_param.frequency = ntsc_dvb[index] * 1000000;
167 frontend_param.u.vsb.modulation = VSB_8;
170 frontend_param.frequency = catv_dvb[index] * 1000000;
171 frontend_param.u.vsb.modulation = QAM_AUTO;
176 if(ioctl(frontend_fd, FE_SET_FRONTEND, &frontend_param) < 0)
179 "DVBTune::open_tuner FE_SET_FRONTEND frequency=%d: %s",
180 frontend_param.frequency,
185 if((video_fd = ::open(demux_path, O_RDWR)) < 0)
188 "DVBTune::open_tuner %s for video: %s\n",
194 //printf("DVBTune::open_tuner 0x%x 0x%x\n", get_audio_pid(), get_video_pid());
195 // Setting exactly one PES filter to 0x2000 dumps the entire
197 struct dmx_pes_filter_params pesfilter;
198 if(!get_video_pid() && !get_audio_pid())
200 pesfilter.pid = 0x2000;
201 pesfilter.input = DMX_IN_FRONTEND;
202 pesfilter.output = DMX_OUT_TS_TAP;
203 pesfilter.pes_type = DMX_PES_OTHER;
204 pesfilter.flags = DMX_IMMEDIATE_START;
205 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
208 "DVBTune::open_tuner DMX_SET_PES_FILTER for raw: %s\n",
219 pesfilter.pid = get_video_pid();
220 pesfilter.input = DMX_IN_FRONTEND;
221 pesfilter.output = DMX_OUT_TS_TAP;
222 pesfilter.pes_type = DMX_PES_VIDEO;
223 pesfilter.flags = DMX_IMMEDIATE_START;
224 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
227 "DVBTune::open_tuner DMX_SET_PES_FILTER for video: %s\n",
235 if((audio_fd = ::open(demux_path, O_RDWR)) < 0)
238 "DVBTune::open_tuner %s for audio: %s\n",
244 pesfilter.pid = get_audio_pid();
245 pesfilter.input = DMX_IN_FRONTEND;
246 pesfilter.output = DMX_OUT_TS_TAP;
247 pesfilter.pes_type = DMX_PES_AUDIO;
248 pesfilter.flags = DMX_IMMEDIATE_START;
249 if(ioctl(audio_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
252 "DVBTune::open_tuner DMX_SET_PES_FILTER for audio: %s\n",
265 thread = new DVBTuneThread(this);
271 status = new DVBTuneStatus(this);
279 int DVBTune::close_tuner()
285 if(frontend_fd >= 0) close(frontend_fd);
286 if(audio_fd >= 0) close(audio_fd);
287 if(video_fd >= 0) close(video_fd);
288 if(dvr_fd >= 0) close(dvr_fd);
296 int DVBTune::get_signal_strength(int *current_power, int *current_lock)
313 int DVBTune::read_data(unsigned char *data, int size)
317 // Poll if not enough data
318 buffer_lock->lock("DVBTune::read_data 2");
319 buffer_size = this->buffer_size;
320 buffer_lock->unlock();
322 if(buffer_size < size)
330 memcpy(data, buffer, size);
332 buffer_lock->lock("DVBTune::read_data 2");
333 int new_size = buffer_size - size;
334 for(int i = 0, j = size; i < new_size; i++, j++)
336 buffer[i] = buffer[j];
338 this->buffer_size -= size;
339 buffer_lock->unlock();
350 #define BUFFER_SIZE 0x100000
351 #define MAX_BUFFER_SIZE 0x10000000
352 DVBTuneThread::DVBTuneThread(DVBTune *server)
355 this->server = server;
356 temp = new unsigned char[BUFFER_SIZE];
359 DVBTuneThread::~DVBTuneThread()
366 void DVBTuneThread::run()
370 Thread::enable_cancel();
372 // Pretend to be blocking if no signal
373 while(!server->has_lock)
379 int result = ::read(server->dvr_fd, temp, BUFFER_SIZE);
380 Thread::disable_cancel();
381 // This happens if buffer overrun.
384 printf("DVBTuneThread::run: %s\n", strerror(errno));
388 // Discard if server full.
389 if(server->buffer_size > MAX_BUFFER_SIZE)
394 // Store in server buffer.
396 server->buffer_lock->lock("DVBTuneThread::run");
397 if(!server->buffer ||
398 server->buffer_allocated < server->buffer_size + result)
400 int new_allocation = server->buffer_size + result;
401 unsigned char *new_buffer = new unsigned char[new_allocation];
402 memcpy(new_buffer, server->buffer, server->buffer_size);
403 delete [] server->buffer;
405 server->buffer = new_buffer;
406 server->buffer_allocated = new_allocation;
409 memcpy(server->buffer + server->buffer_size, temp, result);
410 server->buffer_size += result;
411 server->buffer_lock->unlock();
426 DVBTuneStatus::DVBTuneStatus(DVBTune *server)
429 this->server = server;
432 DVBTuneStatus::~DVBTuneStatus()
438 void DVBTuneStatus::run()
444 uint16_t snr, signal;
445 uint32_t ber, uncorrected_blocks;
448 bzero(&status, sizeof(status));
449 Thread::enable_cancel();
450 ioctl(server->frontend_fd, FE_READ_STATUS, &status);
451 ioctl(server->frontend_fd, FE_READ_SIGNAL_STRENGTH, &signal);
452 ioctl(server->frontend_fd, FE_READ_SNR, &snr);
453 ioctl(server->frontend_fd, FE_READ_BER, &ber);
454 ioctl(server->frontend_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
455 Thread::disable_cancel();
457 // printf ("DVBTuneStatus::run %02x | signal %04x | snr %04x | "
458 // "ber %08x | unc %08x | ",
459 // status, signal, snr, ber, uncorrected_blocks);
460 if (status & FE_HAS_LOCK)
462 printf("DVBTuneStatus::run FE_HAS_LOCK\n");
465 if(status & FE_HAS_LOCK) server->has_lock = 1;