00001 #include "bcwindowbase.inc"
00002 #include "clip.h"
00003 #include "condition.h"
00004 #include "devicedvbinput.inc"
00005 #include "dvbtune.h"
00006 #include "mutex.h"
00007
00008 #include <errno.h>
00009 #include <fcntl.h>
00010 #ifdef HAVE_DVB
00011 #include <linux/dvb/dmx.h>
00012 #include <linux/dvb/frontend.h>
00013 #endif
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <sys/ioctl.h>
00017 #include <unistd.h>
00018
00019
00020
00021
00022
00023
00024
00025
00026 static unsigned long ntsc_dvb[ ] = {
00027 0, 0, 57, 63, 69, 79, 85, 177, 183, 189 ,
00028 195, 201, 207, 213, 473, 479, 485, 491, 497, 503 ,
00029 509, 515, 521, 527, 533, 539, 545, 551, 557, 563 ,
00030 569, 575, 581, 587, 593, 599, 605, 611, 617, 623 ,
00031 629, 635, 641, 647, 653, 659, 665, 671, 677, 683 ,
00032 689, 695, 701, 707, 713, 719, 725, 731, 737, 743 ,
00033 749, 755, 761, 767, 773, 779, 785, 791, 797, 803 ,
00034 809, 815, 821, 827, 833, 839, 845, 851, 857, 863 ,
00035 869, 875, 881, 887, 893, 899, 905, 911, 917, 923 ,
00036 929, 935, 941, 947, 953, 959, 965, 971, 977, 983 ,
00037 989, 995, 1001, 1007, 1013, 1019, 1025, 1031, 1037, 1043
00038 };
00039
00040 static unsigned long catv_dvb[] = {
00041 0, 0, 57, 63, 69, 79, 85, 177, 183, 189,
00042 195, 201, 207, 213, 123, 129, 135, 141, 147, 153,
00043 159, 165, 171, 219, 225, 231, 237, 243, 249, 255,
00044 261, 267, 273, 279, 285, 291, 297, 303, 309, 315,
00045 321, 327, 333, 339, 345, 351, 357, 363, 369, 375,
00046 381, 387, 393, 399, 405, 411, 417, 423, 429, 435,
00047 441, 447, 453, 459, 465, 471, 477, 483, 489, 495,
00048 501, 507, 513, 519, 525, 531, 537, 543, 549, 555,
00049 561, 567, 573, 579, 585, 591, 597, 603, 609, 615,
00050 621, 627, 633, 639, 645, 93, 99, 105, 111, 117,
00051 651, 657, 663, 669, 675, 681, 687, 693, 699, 705,
00052 711, 717, 723, 729, 735, 741, 747, 753, 759, 765,
00053 771, 777, 783, 789, 795, 781, 807, 813, 819, 825,
00054 831, 837, 843, 849, 855, 861, 867, 873, 879, 885,
00055 891, 897, 903, 909, 915, 921, 927, 933, 939, 945,
00056 951, 957, 963, 969, 975, 981, 987, 993, 999
00057 };
00058
00059
00060
00061 DVBTune::DVBTune(RenderFarmClientThread *client)
00062 : TunerServer(client)
00063 {
00064 reset();
00065 buffer_lock = new Mutex("DVBTune::buffer_lock");
00066 }
00067
00068 DVBTune::~DVBTune()
00069 {
00070 delete [] buffer;
00071 delete buffer_lock;
00072 delete thread;
00073 delete status;
00074 }
00075
00076 void DVBTune::reset()
00077 {
00078 frontend_fd = -1;
00079 audio_fd = -1;
00080 video_fd = -1;
00081 dvr_fd = -1;
00082 buffer = 0;
00083 buffer_size = 0;
00084 buffer_allocated = 0;
00085 thread = 0;
00086 status = 0;
00087 has_lock = 0;
00088 }
00089
00090 int DVBTune::open_tuner()
00091 {
00092 #ifdef HAVE_DVB
00093 char frontend_path[BCTEXTLEN];
00094 char demux_path[BCTEXTLEN];
00095 char dvr_path[BCTEXTLEN];
00096
00097 sprintf(frontend_path, "/dev/dvb/adapter%d/frontend%d",
00098 get_device_number(),
00099 0);
00100 sprintf(demux_path, "/dev/dvb/adapter%d/demux%d",
00101 get_device_number(),
00102 0);
00103 sprintf(dvr_path, "/dev/dvb/adapter%d/dvr%d",
00104 get_device_number(),
00105 0);
00106
00107
00108
00109
00110
00111
00112
00113
00114 if((frontend_fd = ::open(frontend_path, O_RDWR)) < 0)
00115 {
00116 fprintf(stderr,
00117 "DVBTune::open_tuner %s: %s\n",
00118 frontend_path,
00119 strerror(errno));
00120 return 1;
00121 }
00122
00123
00124
00125 if((dvr_fd = ::open(dvr_path, O_RDONLY)) < 0)
00126 {
00127 fprintf(stderr,
00128 "DVBTune::open_tuner %s: %s\n",
00129 dvr_path,
00130 strerror(errno));
00131 return 1;
00132 }
00133
00134 struct dvb_frontend_parameters frontend_param;
00135 bzero(&frontend_param, sizeof(frontend_param));
00136
00137
00138 int index = CLIP(TunerServer::get_channel(), 2, 69);
00139 int table = TunerServer::get_table();
00140 switch(table)
00141 {
00142 case NETTUNE_AIR:
00143 frontend_param.frequency = ntsc_dvb[index] * 1000000;
00144 frontend_param.u.vsb.modulation = VSB_8;
00145 break;
00146 case NETTUNE_CABLE:
00147 frontend_param.frequency = catv_dvb[index] * 1000000;
00148 frontend_param.u.vsb.modulation = QAM_AUTO;
00149 break;
00150 }
00151
00152
00153 if(ioctl(frontend_fd, FE_SET_FRONTEND, &frontend_param) < 0)
00154 {
00155 fprintf(stderr,
00156 "DVBTune::open_tuner FE_SET_FRONTEND frequency=%d: %s",
00157 frontend_param.frequency,
00158 strerror(errno));
00159 return 1;
00160 }
00161
00162 if((video_fd = ::open(demux_path, O_RDWR)) < 0)
00163 {
00164 fprintf(stderr,
00165 "DVBTune::open_tuner %s for video: %s\n",
00166 demux_path,
00167 strerror(errno));
00168 return 1;
00169 }
00170
00171
00172
00173
00174 struct dmx_pes_filter_params pesfilter;
00175 if(!get_video_pid() && !get_audio_pid())
00176 {
00177 pesfilter.pid = 0x2000;
00178 pesfilter.input = DMX_IN_FRONTEND;
00179 pesfilter.output = DMX_OUT_TS_TAP;
00180 pesfilter.pes_type = DMX_PES_OTHER;
00181 pesfilter.flags = DMX_IMMEDIATE_START;
00182 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
00183 {
00184 fprintf(stderr,
00185 "DVBTune::open_tuner DMX_SET_PES_FILTER for raw: %s\n",
00186 strerror(errno));
00187 return 1;
00188 }
00189 }
00190
00191
00192 if(get_video_pid())
00193 {
00194
00195
00196 pesfilter.pid = get_video_pid();
00197 pesfilter.input = DMX_IN_FRONTEND;
00198 pesfilter.output = DMX_OUT_TS_TAP;
00199 pesfilter.pes_type = DMX_PES_VIDEO;
00200 pesfilter.flags = DMX_IMMEDIATE_START;
00201 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
00202 {
00203 fprintf(stderr,
00204 "DVBTune::open_tuner DMX_SET_PES_FILTER for video: %s\n",
00205 strerror(errno));
00206 return 1;
00207 }
00208 }
00209
00210 if(get_audio_pid())
00211 {
00212 if((audio_fd = ::open(demux_path, O_RDWR)) < 0)
00213 {
00214 fprintf(stderr,
00215 "DVBTune::open_tuner %s for audio: %s\n",
00216 demux_path,
00217 strerror(errno));
00218 return 1;
00219 }
00220
00221 pesfilter.pid = get_audio_pid();
00222 pesfilter.input = DMX_IN_FRONTEND;
00223 pesfilter.output = DMX_OUT_TS_TAP;
00224 pesfilter.pes_type = DMX_PES_AUDIO;
00225 pesfilter.flags = DMX_IMMEDIATE_START;
00226 if(ioctl(audio_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
00227 {
00228 fprintf(stderr,
00229 "DVBTune::open_tuner DMX_SET_PES_FILTER for audio: %s\n",
00230 strerror(errno));
00231 return 1;
00232 }
00233 }
00234
00235
00236
00237
00238
00239
00240 if(!thread)
00241 {
00242 thread = new DVBTuneThread(this);
00243 thread->start();
00244 }
00245
00246 if(!status)
00247 {
00248 status = new DVBTuneStatus(this);
00249 status->start();
00250 }
00251 return 0;
00252 #endif
00253 return 1;
00254 }
00255
00256 int DVBTune::close_tuner()
00257 {
00258 delete thread;
00259 delete status;
00260 delete [] buffer;
00261
00262 if(frontend_fd >= 0) close(frontend_fd);
00263 if(audio_fd >= 0) close(audio_fd);
00264 if(video_fd >= 0) close(video_fd);
00265 if(dvr_fd >= 0) close(dvr_fd);
00266 reset();
00267
00268 return 0;
00269 }
00270
00271
00272
00273 int DVBTune::get_signal_strength(int *current_power, int *current_lock)
00274 {
00275 if(has_lock)
00276 {
00277 *current_power = 10;
00278 *current_lock = 1;
00279 }
00280 else
00281 {
00282 *current_power = 0;
00283 *current_lock = 0;
00284 }
00285
00286
00287 return 0;
00288 }
00289
00290 int DVBTune::read_data(unsigned char *data, int size)
00291 {
00292 int buffer_size = 0;
00293
00294
00295 buffer_lock->lock("DVBTune::read_data 2");
00296 buffer_size = this->buffer_size;
00297 buffer_lock->unlock();
00298
00299 if(buffer_size < size)
00300 {
00301 usleep(100000);
00302 return 0;
00303 }
00304
00305
00306
00307 memcpy(data, buffer, size);
00308
00309 buffer_lock->lock("DVBTune::read_data 2");
00310 int new_size = buffer_size - size;
00311 for(int i = 0, j = size; i < new_size; i++, j++)
00312 {
00313 buffer[i] = buffer[j];
00314 }
00315 this->buffer_size -= size;
00316 buffer_lock->unlock();
00317
00318 return size;
00319 }
00320
00321
00322
00323
00324
00325
00326
00327 #define BUFFER_SIZE 0x100000
00328 #define MAX_BUFFER_SIZE 0x10000000
00329 DVBTuneThread::DVBTuneThread(DVBTune *server)
00330 : Thread(1, 0, 0)
00331 {
00332 this->server = server;
00333 temp = new unsigned char[BUFFER_SIZE];
00334 }
00335
00336 DVBTuneThread::~DVBTuneThread()
00337 {
00338 Thread::cancel();
00339 Thread::join();
00340 delete [] temp;
00341 }
00342
00343 void DVBTuneThread::run()
00344 {
00345 while(1)
00346 {
00347 Thread::enable_cancel();
00348
00349
00350 while(!server->has_lock)
00351 {
00352 usleep(1000000);
00353 }
00354
00355
00356 int result = ::read(server->dvr_fd, temp, BUFFER_SIZE);
00357 Thread::disable_cancel();
00358
00359 if(result < 0)
00360 {
00361 printf("DVBTuneThread::run: %s\n", strerror(errno));
00362 result = 0;
00363 }
00364 else
00365
00366 if(server->buffer_size > MAX_BUFFER_SIZE)
00367 {
00368 ;
00369 }
00370 else
00371
00372 {
00373 server->buffer_lock->lock("DVBTuneThread::run");
00374 if(!server->buffer ||
00375 server->buffer_allocated < server->buffer_size + result)
00376 {
00377 int new_allocation = server->buffer_size + result;
00378 unsigned char *new_buffer = new unsigned char[new_allocation];
00379 memcpy(new_buffer, server->buffer, server->buffer_size);
00380 delete [] server->buffer;
00381
00382 server->buffer = new_buffer;
00383 server->buffer_allocated = new_allocation;
00384 }
00385
00386 memcpy(server->buffer + server->buffer_size, temp, result);
00387 server->buffer_size += result;
00388 server->buffer_lock->unlock();
00389 }
00390 }
00391 }
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 DVBTuneStatus::DVBTuneStatus(DVBTune *server)
00404 : Thread(1, 0, 0)
00405 {
00406 this->server = server;
00407 }
00408
00409 DVBTuneStatus::~DVBTuneStatus()
00410 {
00411 Thread::cancel();
00412 Thread::join();
00413 }
00414
00415 void DVBTuneStatus::run()
00416 {
00417 #ifdef HAVE_DVB
00418 while(1)
00419 {
00420 fe_status_t status;
00421 uint16_t snr, signal;
00422 uint32_t ber, uncorrected_blocks;
00423
00424
00425 bzero(&status, sizeof(status));
00426 Thread::enable_cancel();
00427 ioctl(server->frontend_fd, FE_READ_STATUS, &status);
00428 ioctl(server->frontend_fd, FE_READ_SIGNAL_STRENGTH, &signal);
00429 ioctl(server->frontend_fd, FE_READ_SNR, &snr);
00430 ioctl(server->frontend_fd, FE_READ_BER, &ber);
00431 ioctl(server->frontend_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
00432 Thread::disable_cancel();
00433
00434
00435
00436
00437 if (status & FE_HAS_LOCK)
00438 {
00439 printf("DVBTuneStatus::run FE_HAS_LOCK\n");
00440 }
00441
00442 if(status & FE_HAS_LOCK) server->has_lock = 1;
00443 sleep(1);
00444 }
00445 #endif
00446 }
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459