gnutv_dvb.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. gnutv utility
  3. Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
  4. Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <limits.h>
  20. #include <string.h>
  21. #include <signal.h>
  22. #include <pthread.h>
  23. #include <errno.h>
  24. #include <sys/poll.h>
  25. #include <libdvbapi/dvbdemux.h>
  26. #include <libucsi/section.h>
  27. #include <libucsi/mpeg/section.h>
  28. #include <libucsi/dvb/section.h>
  29. #include "gnutv.h"
  30. #include "gnutv_dvb.h"
  31. #include "gnutv_data.h"
  32. #include "gnutv_ca.h"
  33. #define FE_STATUS_PARAMS (DVBFE_INFO_LOCKSTATUS|DVBFE_INFO_SIGNAL_STRENGTH|DVBFE_INFO_BER|DVBFE_INFO_SNR|DVBFE_INFO_UNCORRECTED_BLOCKS)
  34. static int dvbthread_shutdown = 0;
  35. static pthread_t dvbthread;
  36. static int tune_state = 0;
  37. static int pat_version = -1;
  38. static int ca_pmt_version = -1;
  39. static int data_pmt_version = -1;
  40. static void *dvbthread_func(void* arg);
  41. static void process_pat(int pat_fd, struct gnutv_dvb_params *params, int *pmt_fd, struct pollfd *pollfd);
  42. static void process_tdt(int tdt_fd);
  43. static void process_pmt(int pmt_fd, struct gnutv_dvb_params *params);
  44. static int create_section_filter(int adapter, int demux, uint16_t pid, uint8_t table_id);
  45. int gnutv_dvb_start(struct gnutv_dvb_params *params)
  46. {
  47. pthread_create(&dvbthread, NULL, dvbthread_func, (void*) params);
  48. return 0;
  49. }
  50. void gnutv_dvb_stop(void)
  51. {
  52. dvbthread_shutdown = 1;
  53. pthread_join(dvbthread, NULL);
  54. }
  55. int gnutv_dvb_locked(void)
  56. {
  57. return tune_state == 2;
  58. }
  59. static void *dvbthread_func(void* arg)
  60. {
  61. int pat_fd = -1;
  62. int pmt_fd = -1;
  63. int tdt_fd = -1;
  64. struct pollfd pollfds[3];
  65. struct gnutv_dvb_params *params = (struct gnutv_dvb_params *) arg;
  66. tune_state = 0;
  67. // create PAT filter
  68. if ((pat_fd = create_section_filter(params->adapter_id, params->demux_id,
  69. TRANSPORT_PAT_PID, stag_mpeg_program_association)) < 0) {
  70. fprintf(stderr, "Failed to create PAT section filter\n");
  71. exit(1);
  72. }
  73. pollfds[0].fd = pat_fd;
  74. pollfds[0].events = POLLIN|POLLPRI|POLLERR;
  75. // create TDT filter
  76. if ((tdt_fd = create_section_filter(params->adapter_id, params->demux_id, TRANSPORT_TDT_PID, stag_dvb_time_date)) < 0) {
  77. fprintf(stderr, "Failed to create TDT section filter\n");
  78. exit(1);
  79. }
  80. pollfds[1].fd = tdt_fd;
  81. pollfds[1].events = POLLIN|POLLPRI|POLLERR;
  82. // zero PMT filter
  83. pollfds[2].fd = 0;
  84. pollfds[2].events = 0;
  85. // the DVB loop
  86. while(!dvbthread_shutdown) {
  87. // tune frontend + monitor lock status
  88. if (tune_state == 0) {
  89. // get the type of frontend
  90. struct dvbfe_info result;
  91. char *types;
  92. memset(&result, 0, sizeof(result));
  93. dvbfe_get_info(params->fe, 0, &result, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
  94. switch(result.type) {
  95. case DVBFE_TYPE_DVBS:
  96. types = "DVB-S";
  97. break;
  98. case DVBFE_TYPE_DVBC:
  99. types = "DVB-C";
  100. break;
  101. case DVBFE_TYPE_DVBT:
  102. types = "DVB-T";
  103. break;
  104. case DVBFE_TYPE_ATSC:
  105. types = "ATSC";
  106. break;
  107. default:
  108. types = "Unknown";
  109. }
  110. fprintf(stderr, "Using frontend \"%s\", type %s\n", result.name, types);
  111. // do we have a valid SEC configuration?
  112. struct dvbsec_config *sec = NULL;
  113. if (params->valid_sec)
  114. sec = &params->sec;
  115. // tune!
  116. if (dvbsec_set(params->fe,
  117. sec,
  118. params->channel.polarization,
  119. (params->channel.diseqc_switch & 0x01) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A,
  120. (params->channel.diseqc_switch & 0x02) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A,
  121. &params->channel.fe_params,
  122. 0)) {
  123. fprintf(stderr, "Failed to set frontend\n");
  124. exit(1);
  125. }
  126. tune_state++;
  127. } else if (tune_state == 1) {
  128. struct dvbfe_info result;
  129. memset(&result, 0, sizeof(result));
  130. dvbfe_get_info(params->fe,
  131. FE_STATUS_PARAMS,
  132. &result,
  133. DVBFE_INFO_QUERYTYPE_IMMEDIATE,
  134. 0);
  135. fprintf(stderr, "status %c%c%c%c%c | signal %04x | snr %04x | ber %08x | unc %08x | %s\r",
  136. result.signal ? 'S' : ' ',
  137. result.carrier ? 'C' : ' ',
  138. result.viterbi ? 'V' : ' ',
  139. result.sync ? 'Y' : ' ',
  140. result.lock ? 'L' : ' ',
  141. result.signal_strength,
  142. result.snr,
  143. result.ber,
  144. result.ucblocks,
  145. result.lock ? "FE_HAS_LOCK" : "");
  146. fflush(stderr);
  147. if (result.lock) {
  148. tune_state++;
  149. fprintf(stderr, "\n");
  150. fflush(stderr);
  151. } else {
  152. usleep(500000);
  153. }
  154. }
  155. // is there SI data?
  156. int count = poll(pollfds, 3, 100);
  157. if (count < 0) {
  158. if (errno != EINTR)
  159. fprintf(stderr, "Poll error: %m\n");
  160. break;
  161. }
  162. if (count == 0) {
  163. continue;
  164. }
  165. // PAT
  166. if (pollfds[0].revents & (POLLIN|POLLPRI)) {
  167. process_pat(pat_fd, params, &pmt_fd, &pollfds[2]);
  168. }
  169. // TDT
  170. if (pollfds[1].revents & (POLLIN|POLLPRI)) {
  171. process_tdt(tdt_fd);
  172. }
  173. // PMT
  174. if (pollfds[2].revents & (POLLIN|POLLPRI)) {
  175. process_pmt(pmt_fd, params);
  176. }
  177. }
  178. // close demuxers
  179. if (pat_fd != -1)
  180. close(pat_fd);
  181. if (pmt_fd != -1)
  182. close(pmt_fd);
  183. if (tdt_fd != -1)
  184. close(tdt_fd);
  185. return 0;
  186. }
  187. static void process_pat(int pat_fd, struct gnutv_dvb_params *params, int *pmt_fd, struct pollfd *pollfd)
  188. {
  189. int size;
  190. uint8_t sibuf[4096];
  191. // read the section
  192. if ((size = read(pat_fd, sibuf, sizeof(sibuf))) < 0) {
  193. return;
  194. }
  195. // parse section
  196. struct section *section = section_codec(sibuf, size);
  197. if (section == NULL) {
  198. return;
  199. }
  200. // parse section_ext
  201. struct section_ext *section_ext = section_ext_decode(section, 0);
  202. if (section_ext == NULL) {
  203. return;
  204. }
  205. if (pat_version == section_ext->version_number) {
  206. return;
  207. }
  208. // parse PAT
  209. struct mpeg_pat_section *pat = mpeg_pat_section_codec(section_ext);
  210. if (pat == NULL) {
  211. return;
  212. }
  213. // try and find the requested program
  214. struct mpeg_pat_program *cur_program;
  215. mpeg_pat_section_programs_for_each(pat, cur_program) {
  216. if (cur_program->program_number == params->channel.service_id) {
  217. // close old PMT fd
  218. if (*pmt_fd != -1)
  219. close(*pmt_fd);
  220. // create PMT filter
  221. if ((*pmt_fd = create_section_filter(params->adapter_id, params->demux_id,
  222. cur_program->pid, stag_mpeg_program_map)) < 0) {
  223. return;
  224. }
  225. pollfd->fd = *pmt_fd;
  226. pollfd->events = POLLIN|POLLPRI|POLLERR;
  227. gnutv_data_new_pat(cur_program->pid);
  228. // we have a new PMT pid
  229. data_pmt_version = -1;
  230. ca_pmt_version = -1;
  231. break;
  232. }
  233. }
  234. // remember the PAT version
  235. pat_version = section_ext->version_number;
  236. }
  237. static void process_tdt(int tdt_fd)
  238. {
  239. int size;
  240. uint8_t sibuf[4096];
  241. // read the section
  242. if ((size = read(tdt_fd, sibuf, sizeof(sibuf))) < 0) {
  243. return;
  244. }
  245. // parse section
  246. struct section *section = section_codec(sibuf, size);
  247. if (section == NULL) {
  248. return;
  249. }
  250. // parse TDT
  251. struct dvb_tdt_section *tdt = dvb_tdt_section_codec(section);
  252. if (tdt == NULL) {
  253. return;
  254. }
  255. // done
  256. gnutv_ca_new_dvbtime(dvbdate_to_unixtime(tdt->utc_time));
  257. }
  258. static void process_pmt(int pmt_fd, struct gnutv_dvb_params *params)
  259. {
  260. int size;
  261. uint8_t sibuf[4096];
  262. // read the section
  263. if ((size = read(pmt_fd, sibuf, sizeof(sibuf))) < 0) {
  264. return;
  265. }
  266. // parse section
  267. struct section *section = section_codec(sibuf, size);
  268. if (section == NULL) {
  269. return;
  270. }
  271. // parse section_ext
  272. struct section_ext *section_ext = section_ext_decode(section, 0);
  273. if (section_ext == NULL) {
  274. return;
  275. }
  276. if ((section_ext->table_id_ext != params->channel.service_id) ||
  277. ((section_ext->version_number == data_pmt_version) &&
  278. (section_ext->version_number == ca_pmt_version))) {
  279. return;
  280. }
  281. // parse PMT
  282. struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec(section_ext);
  283. if (pmt == NULL) {
  284. return;
  285. }
  286. // do data handling
  287. if (section_ext->version_number != data_pmt_version) {
  288. if (gnutv_data_new_pmt(pmt) == 1)
  289. data_pmt_version = pmt->head.version_number;
  290. }
  291. // do ca handling
  292. if (section_ext->version_number != ca_pmt_version) {
  293. if (gnutv_ca_new_pmt(pmt) == 1)
  294. ca_pmt_version = pmt->head.version_number;
  295. }
  296. }
  297. static int create_section_filter(int adapter, int demux, uint16_t pid, uint8_t table_id)
  298. {
  299. int demux_fd = -1;
  300. uint8_t filter[18];
  301. uint8_t mask[18];
  302. // open the demuxer
  303. if ((demux_fd = dvbdemux_open_demux(adapter, demux, 0)) < 0) {
  304. return -1;
  305. }
  306. // create a section filter
  307. memset(filter, 0, sizeof(filter));
  308. memset(mask, 0, sizeof(mask));
  309. filter[0] = table_id;
  310. mask[0] = 0xFF;
  311. if (dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) {
  312. close(demux_fd);
  313. return -1;
  314. }
  315. // done
  316. return demux_fd;
  317. }