Merge branch 'nto-signal-stats'
[dvblast.git] / dvblast.c
blob4b47890e130829e1f8c8133f20a1f7229e573862
1 /*****************************************************************************
2 * dvblast.c
3 *****************************************************************************
4 * Copyright (C) 2004, 2008-2011, 2015, 2020 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Andy Gatward <a.j.gatward@reading.ac.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <pthread.h>
33 #include <netdb.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <signal.h>
38 #include <getopt.h>
39 #include <errno.h>
41 #include <ev.h>
43 #include "dvblast.h"
45 #ifdef HAVE_ICONV
46 #include <iconv.h>
47 #endif
49 #include <bitstream/dvb/si.h>
50 #include <bitstream/ietf/rtp.h>
52 #include "mrtg-cnt.h"
54 /*****************************************************************************
55 * Local declarations
56 *****************************************************************************/
57 struct ev_loop *event_loop;
58 output_t **pp_outputs = NULL;
59 int i_nb_outputs = 0;
60 output_t output_dup;
61 bool b_passthrough = false;
62 static const char *psz_conf_file = NULL;
63 char *psz_srv_socket = NULL;
64 static int i_priority = -1;
65 int i_adapter = 0;
66 int i_fenum = 0;
67 int i_canum = 0;
68 char *psz_delsys = NULL;
69 int i_frequency = 0;
70 char *psz_lnb_type = "universal";
71 int dvb_plp_id = 0;
72 int i_inversion = -1;
73 int i_srate = 27500000;
74 int i_fec = 999;
75 int i_rolloff = 35;
76 int i_satnum = 0;
77 int i_uncommitted = 0;
78 int i_voltage = 13;
79 int b_tone = 0;
80 int i_bandwidth = 8;
81 char *psz_modulation = NULL;
82 int i_pilot = -1;
83 int i_mis = 0;
84 char *psz_mis_pls_mode = "ROOT";
85 int i_mis_pls_mode = 0;
86 int i_mis_pls_code = 0;
87 int i_mis_is_id = 0;
88 int i_fec_lp = 999;
89 int i_guard = -1;
90 int i_transmission = -1;
91 int i_hierarchy = -1;
92 mtime_t i_frontend_timeout_duration = DEFAULT_FRONTEND_TIMEOUT;
93 mtime_t i_quit_timeout_duration = 0;
94 int b_budget_mode = 0;
95 int b_any_type = 0;
96 int b_select_pmts = 0;
97 int b_random_tsid = 0;
98 char *psz_udp_src = NULL;
99 int i_asi_adapter = 0;
100 const char *psz_native_charset = "UTF-8//IGNORE";
101 print_type_t i_print_type = PRINT_TEXT;
102 bool b_print_enabled = false;
103 FILE *print_fh;
104 mtime_t i_print_period = 0;
105 mtime_t i_es_timeout = 0;
106 mtime_t i_udp_lock_timeout = DEFAULT_UDP_LOCK_TIMEOUT;
108 int i_verbose = DEFAULT_VERBOSITY;
109 int i_syslog = 0;
110 char *psz_syslog_ident = NULL;
112 bool b_enable_emm = false;
113 bool b_enable_ecm = false;
115 uint8_t pi_ssrc_global[4] = { 0, 0, 0, 0 };
116 static bool b_udp_global = false;
117 static bool b_dvb_global = false;
118 static bool b_epg_global = false;
119 static mtime_t i_latency_global = DEFAULT_OUTPUT_LATENCY;
120 static mtime_t i_retention_global = DEFAULT_MAX_RETENTION;
121 static int i_ttl_global = 64;
123 static const char *psz_dvb_charset = "UTF-8//IGNORE";
124 static iconv_t conf_iconv = (iconv_t)-1;
125 static uint16_t i_network_id = 0xffff;
126 static dvb_string_t network_name;
127 static dvb_string_t provider_name;
129 /* TPS Input log filename */
130 char * psz_mrtg_file = NULL;
132 /* PID mapping */
133 bool b_do_remap = false;
134 uint16_t pi_newpids[ N_MAP_PIDS ]; /* pmt, audio, video, spu */
136 void (*pf_Open)( void ) = NULL;
137 void (*pf_Reset)( void ) = NULL;
138 int (*pf_SetFilter)( uint16_t i_pid ) = NULL;
139 void (*pf_UnsetFilter)( int i_fd, uint16_t i_pid ) = NULL;
141 /*****************************************************************************
142 * Configuration files
143 *****************************************************************************/
144 void config_Init( output_config_t *p_config )
146 memset( p_config, 0, sizeof(output_config_t) );
148 p_config->psz_displayname = NULL;
149 p_config->i_network_id = i_network_id;
150 dvb_string_init(&p_config->network_name);
151 dvb_string_init(&p_config->service_name);
152 dvb_string_init(&p_config->provider_name);
153 p_config->psz_srcaddr = NULL;
155 p_config->i_family = AF_UNSPEC;
156 p_config->connect_addr.ss_family = AF_UNSPEC;
157 p_config->bind_addr.ss_family = AF_UNSPEC;
158 p_config->i_if_index_v6 = -1;
159 p_config->i_srcport = 0;
161 p_config->pi_pids = NULL;
162 p_config->b_passthrough = false;
163 p_config->b_do_remap = false;
164 unsigned int i;
165 for ( i = 0; i < N_MAP_PIDS; i++ ) {
166 p_config->pi_confpids[i] = UNUSED_PID;
170 void config_Free( output_config_t *p_config )
172 free( p_config->psz_displayname );
173 dvb_string_clean( &p_config->network_name );
174 dvb_string_clean( &p_config->service_name );
175 dvb_string_clean( &p_config->provider_name );
176 free( p_config->pi_pids );
177 free( p_config->psz_srcaddr );
180 static void config_Defaults( output_config_t *p_config )
182 config_Init( p_config );
184 p_config->i_config = (b_udp_global ? OUTPUT_UDP : 0) |
185 (b_dvb_global ? OUTPUT_DVB : 0) |
186 (b_epg_global ? OUTPUT_EPG : 0);
187 p_config->i_max_retention = i_retention_global;
188 p_config->i_output_latency = i_latency_global;
189 p_config->i_tsid = -1;
190 p_config->i_ttl = i_ttl_global;
191 memcpy( p_config->pi_ssrc, pi_ssrc_global, 4 * sizeof(uint8_t) );
192 dvb_string_copy(&p_config->network_name, &network_name);
193 dvb_string_copy(&p_config->provider_name, &provider_name);
196 char *config_stropt( const char *psz_string )
198 char *ret, *tmp;
199 if ( !psz_string || strlen( psz_string ) == 0 )
200 return NULL;
201 ret = tmp = strdup( psz_string );
202 while (*tmp) {
203 if (*tmp == '_')
204 *tmp = ' ';
205 if (*tmp == '/') {
206 *tmp = '\0';
207 break;
209 tmp++;
211 return ret;
214 static uint8_t *config_striconv( const char *psz_string,
215 const char *psz_charset, size_t *pi_length )
217 char *psz_input = config_stropt(psz_string);
218 *pi_length = strlen(psz_input);
220 /* do not convert ASCII strings */
221 const char *c = psz_string;
222 while (*c)
223 if (!isascii(*c++))
224 break;
225 if (!*c)
226 return (uint8_t *)psz_input;
228 if ( !strcasecmp( psz_native_charset, psz_charset ) )
229 return (uint8_t *)psz_input;
231 #ifdef HAVE_ICONV
232 if ( conf_iconv == (iconv_t)-1 )
234 conf_iconv = iconv_open( psz_charset, psz_native_charset );
235 if ( conf_iconv == (iconv_t)-1 )
236 return (uint8_t *)psz_input;
239 char *psz_tmp = psz_input;
240 size_t i_input = *pi_length;
241 size_t i_output = i_input * 6;
242 size_t i_available = i_output;
243 char *p_output = malloc( i_output );
244 char *p = p_output;
245 if ( iconv( conf_iconv, &psz_tmp, &i_input, &p, &i_available ) == (size_t)-1 )
247 free( p_output );
249 return (uint8_t *)psz_input;
252 free(psz_input);
253 *pi_length = i_output - i_available;
254 return (uint8_t *)p_output;
255 #else
256 msg_Warn( NULL,
257 "unable to convert from %s to %s (iconv is not available)",
258 psz_native_charset, psz_charset );
259 return (uint8_t *)psz_input;
260 #endif
263 static void config_strdvb( dvb_string_t *p_dvb_string, const char *psz_string,
264 const char *psz_charset )
266 if (psz_string == NULL)
268 dvb_string_init(p_dvb_string);
269 return;
271 dvb_string_clean(p_dvb_string);
273 size_t i_iconv;
274 uint8_t *p_iconv = config_striconv(psz_string, psz_charset, &i_iconv);
275 p_dvb_string->p = dvb_string_set(p_iconv, i_iconv, psz_charset,
276 &p_dvb_string->i);
277 free(p_iconv);
280 static bool config_ParseHost( output_config_t *p_config, char *psz_string )
282 struct addrinfo *p_ai;
283 int i_mtu;
285 p_config->psz_displayname = strdup( psz_string );
287 p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT );
288 if ( p_ai == NULL ) return false;
289 memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen );
290 freeaddrinfo( p_ai );
292 p_config->i_family = p_config->connect_addr.ss_family;
293 if ( p_config->i_family == AF_UNSPEC ) return false;
295 if ( psz_string == NULL || !*psz_string ) goto end;
297 if ( *psz_string == '@' )
299 psz_string++;
300 p_ai = ParseNodeService( psz_string, &psz_string, 0 );
301 if ( p_ai == NULL || p_ai->ai_family != p_config->i_family )
302 msg_Warn( NULL, "invalid bind address" );
303 else
304 memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen );
305 freeaddrinfo( p_ai );
308 const char *psz_charset = psz_dvb_charset;
309 const char *psz_network_name = NULL;
310 const char *psz_service_name = NULL;
311 const char *psz_provider_name = NULL;
313 while ( (psz_string = strchr( psz_string, '/' )) != NULL )
315 *psz_string++ = '\0';
317 #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) ))
318 #define ARG_OPTION( option ) (psz_string + strlen(option))
320 if ( IS_OPTION("udp") )
321 p_config->i_config |= OUTPUT_UDP;
322 else if ( IS_OPTION("dvb") )
323 p_config->i_config |= OUTPUT_DVB;
324 else if ( IS_OPTION("epg") )
325 p_config->i_config |= OUTPUT_EPG;
326 else if ( IS_OPTION("tsid=") )
327 p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 );
328 else if ( IS_OPTION("retention=") )
329 p_config->i_max_retention = strtoll( ARG_OPTION("retention="),
330 NULL, 0 ) * 1000;
331 else if ( IS_OPTION("latency=") )
332 p_config->i_output_latency = strtoll( ARG_OPTION("latency="),
333 NULL, 0 ) * 1000;
334 else if ( IS_OPTION("ttl=") )
335 p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 );
336 else if ( IS_OPTION("tos=") )
337 p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 );
338 else if ( IS_OPTION("mtu=") )
339 p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 );
340 else if ( IS_OPTION("ifindex=") )
341 p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 );
342 else if ( IS_OPTION("networkid=") )
343 p_config->i_network_id = strtol( ARG_OPTION("networkid="), NULL, 0 );
344 else if ( IS_OPTION("onid=") )
345 p_config->i_onid = strtol( ARG_OPTION("onid="), NULL, 0 );
346 else if ( IS_OPTION("charset=") )
347 psz_charset = ARG_OPTION("charset=");
348 else if ( IS_OPTION("networkname=") )
349 psz_network_name = ARG_OPTION("networkname=");
350 else if ( IS_OPTION("srvname=") )
351 psz_service_name = ARG_OPTION("srvname=");
352 else if ( IS_OPTION("srvprovider=") )
353 psz_provider_name = ARG_OPTION("srvprovider=");
354 else if ( IS_OPTION("srcaddr=") )
356 if ( p_config->i_family != AF_INET ) {
357 msg_Err( NULL, "RAW sockets currently implemented for ipv4 only");
358 return false;
360 free( p_config->psz_srcaddr );
361 p_config->psz_srcaddr = config_stropt( ARG_OPTION("srcaddr=") );
362 p_config->i_config |= OUTPUT_RAW;
364 else if ( IS_OPTION("srcport=") )
365 p_config->i_srcport = strtol( ARG_OPTION("srcport="), NULL, 0 );
366 else if ( IS_OPTION("ssrc=") )
368 in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") );
369 memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) );
371 else if ( IS_OPTION("pidmap=") )
373 char *str1;
374 char *saveptr = NULL;
375 char *tok = NULL;
376 int i, i_newpid;
377 for (i = 0, str1 = config_stropt( (ARG_OPTION("pidmap="))); i < N_MAP_PIDS; i++, str1 = NULL)
379 tok = strtok_r(str1, ",", &saveptr);
380 if ( !tok )
381 break;
382 i_newpid = strtoul(tok, NULL, 0);
383 p_config->pi_confpids[i] = i_newpid;
385 p_config->b_do_remap = true;
387 else if ( IS_OPTION("newsid=") )
388 p_config->i_new_sid = strtol( ARG_OPTION("newsid="), NULL, 0 );
389 else
390 msg_Warn( NULL, "unrecognized option %s", psz_string );
392 #undef IS_OPTION
393 #undef ARG_OPTION
396 if (psz_network_name != NULL)
397 config_strdvb( &p_config->network_name, psz_network_name, psz_charset );
398 if (psz_service_name != NULL)
399 config_strdvb( &p_config->service_name, psz_service_name, psz_charset );
400 if (psz_provider_name != NULL)
401 config_strdvb( &p_config->provider_name, psz_provider_name,
402 psz_charset );
404 end:
405 i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU :
406 DEFAULT_IPV4_MTU;
408 if ( !p_config->i_mtu )
409 p_config->i_mtu = i_mtu;
410 else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE )
412 msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu );
413 p_config->i_mtu = i_mtu;
416 return true;
419 static void config_Print( output_config_t *p_config )
421 if ( p_config->b_passthrough )
423 msg_Dbg( NULL, "conf: %s config=0x%"PRIx64" sid=*",
424 p_config->psz_displayname, p_config->i_config);
425 return;
428 const char *psz_base = "conf: %s config=0x%"PRIx64" sid=%hu pids[%d]=";
429 size_t i_len = strlen(psz_base) + 6 * p_config->i_nb_pids + 1;
430 char psz_format[i_len];
431 int i, j = strlen(psz_base);
433 strcpy( psz_format, psz_base );
434 for ( i = 0; i < p_config->i_nb_pids; i++ )
435 j += sprintf( psz_format + j, "%u,", p_config->pi_pids[i] );
436 psz_format[j - 1] = '\0';
438 msg_Dbg( NULL, psz_format, p_config->psz_displayname, p_config->i_config,
439 p_config->i_sid, p_config->i_nb_pids );
442 void config_ReadFile(void)
444 FILE *p_file;
445 char psz_line[2048];
446 int i;
448 if ( psz_conf_file == NULL )
450 msg_Err( NULL, "no config file" );
451 return;
454 if ( (p_file = fopen( psz_conf_file, "r" )) == NULL )
456 msg_Err( NULL, "can't fopen config file %s", psz_conf_file );
457 return;
460 while ( fgets( psz_line, sizeof(psz_line), p_file ) != NULL )
462 output_config_t config;
463 output_t *p_output;
464 char *psz_token, *psz_parser;
466 psz_parser = strchr( psz_line, '#' );
467 if ( psz_parser != NULL )
468 *psz_parser-- = '\0';
469 while ( psz_parser >= psz_line && isblank( *psz_parser ) )
470 *psz_parser-- = '\0';
471 if ( psz_line[0] == '\0' )
472 continue;
474 config_Defaults( &config );
476 psz_token = strtok_r( psz_line, "\t\n ", &psz_parser );
477 if ( psz_token == NULL || !config_ParseHost( &config, psz_token ))
479 config_Free( &config );
480 continue;
483 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
484 if ( psz_token == NULL )
486 config_Free( &config );
487 continue;
489 if( atoi( psz_token ) == 1 )
490 config.i_config |= OUTPUT_WATCH;
491 else
492 config.i_config &= ~OUTPUT_WATCH;
494 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
495 if ( psz_token == NULL )
497 config_Free( &config );
498 continue;
501 if ( psz_token[0] == '*' )
503 config.b_passthrough = true;
505 else
507 config.i_sid = strtol(psz_token, NULL, 0);
509 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
510 if ( psz_token != NULL )
512 psz_parser = NULL;
513 for ( ; ; )
515 psz_token = strtok_r( psz_token, ",", &psz_parser );
516 if ( psz_token == NULL )
517 break;
518 config.pi_pids = realloc( config.pi_pids,
519 (config.i_nb_pids + 1) * sizeof(uint16_t) );
520 config.pi_pids[config.i_nb_pids++] = strtol(psz_token, NULL, 0);
521 psz_token = NULL;
526 config_Print( &config );
528 p_output = output_Find( &config );
530 if ( p_output == NULL )
531 p_output = output_Create( &config );
533 if ( p_output != NULL )
535 free( p_output->config.psz_displayname );
536 p_output->config.psz_displayname = strdup( config.psz_displayname );
538 config.i_config |= OUTPUT_VALID | OUTPUT_STILL_PRESENT;
539 output_Change( p_output, &config );
540 demux_Change( p_output, &config );
543 config_Free( &config );
546 fclose( p_file );
548 for ( i = 0; i < i_nb_outputs; i++ )
550 output_t *p_output = pp_outputs[i];
551 output_config_t config;
553 config_Init( &config );
555 if ( (p_output->config.i_config & OUTPUT_VALID) &&
556 !(p_output->config.i_config & OUTPUT_STILL_PRESENT) )
558 msg_Dbg( NULL, "closing %s", p_output->config.psz_displayname );
559 demux_Change( p_output, &config );
560 output_Close( p_output );
563 p_output->config.i_config &= ~OUTPUT_STILL_PRESENT;
564 config_Free( &config );
568 /*****************************************************************************
569 * Signal Handler
570 *****************************************************************************/
571 static void signal_watcher_init(struct ev_signal *w, struct ev_loop *loop,
572 void (*cb)(struct ev_loop*, struct ev_signal*, int),
573 int signum)
575 ev_signal_init(w, cb, signum);
576 ev_signal_start(loop, w);
577 ev_unref(loop);
580 static void sighandler(struct ev_loop *loop, struct ev_signal *w, int revents)
582 switch (w->signum)
584 case SIGINT:
585 case SIGTERM:
586 default:
587 msg_Info( NULL, "Shutdown was requested." );
588 ev_break(loop, EVBREAK_ALL);
589 break;
591 case SIGHUP:
592 msg_Info( NULL, "Configuration reload was requested." );
593 config_ReadFile();
594 break;
598 /*****************************************************************************
599 * Quit timeout
600 *****************************************************************************/
601 static void quit_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
603 ev_break(loop, EVBREAK_ALL);
606 /*****************************************************************************
607 * Version
608 *****************************************************************************/
609 static void DisplayVersion()
611 msg_Raw( NULL, "DVBlast %s (%s)", VERSION, VERSION_EXTRA );
614 /*****************************************************************************
615 * Entry point
616 *****************************************************************************/
617 void usage()
619 DisplayVersion();
620 msg_Raw( NULL, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] "
621 "[-i <RT priority>] "
622 #ifdef HAVE_ASI_SUPPORT
623 "[-A <ASI adapter>]"
624 #endif
625 #ifdef HAVE_DVB_SUPPORT
626 "[-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-k <uncommitted port>]"
627 "[-f <frequency>]"
628 "[-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-I <inversion>] "
629 "[-F <fec inner>] [-m <modulation] [-R <rolloff>] [-P <pilot>] [-K <fec lp>] "
630 "[-G <guard interval>] [-H <hierarchy>] [-X <transmission>] [-O <lock timeout>] "
631 #endif
632 "[-D [<src host>[:<src port>]@]<src mcast>[:<port>][/<opts>]*] "
633 "[-u] [-w] [-U] [-L <latency>] [-E <retention>] [-d <dest IP>[<:port>][/<opts>]*] [-3] "
634 "[-z] [-C [-e] [-M <network name>] [-N <network ID>]] [-T] [-j <system charset>] "
635 "[-W] [-Y] [-l] [-g <logger ident>] [-Z <mrtg file>] [-V] [-h] [-B <provider_name>] "
636 "[-1 <mis_id>] [-2 <size>] [-5 <DVBS|DVBS2|DVBC_ANNEX_A|DVBC_ANNEX_B|DVBT|DVBT2|ATSC|ISDBT>] -y <ca_dev_number> "
637 "[-J <DVB charset>] [-Q <quit timeout>] [-0 pid_mapping] [-x <text|xml>]"
638 "[-6 <print period>] [-7 <ES timeout>] [-4 <UDP lock timeout>]" );
640 msg_Raw( NULL, "Input:" );
641 #ifdef HAVE_ASI_SUPPORT
642 msg_Raw( NULL, " -A --asi-adapter read packets from an ASI adapter (0-n)" );
643 #endif
644 #ifdef HAVE_DVB_SUPPORT
645 msg_Raw( NULL, " -a --adapter read packets from a Linux-DVB adapter (typically 0-n)" );
646 msg_Raw( NULL, " -b --bandwidth frontend bandwidth" );
647 #endif
648 msg_Raw( NULL, " -D --rtp-input read packets from a multicast address instead of a DVB card" );
649 #ifdef HAVE_DVB_SUPPORT
650 msg_Raw( NULL, " -5 --delsys delivery system" );
651 msg_Raw( NULL, " DVBS|DVBS2|DVBC_ANNEX_A|DVBT|DVBT2|ATSC|ISDBT|DVBC_ANNEX_B(ATSC-C/QAMB) (default guessed)");
652 msg_Raw( NULL, " -f --frequency frontend frequency" );
653 msg_Raw( NULL, " -8 --lnb-type <type> Set LNB type')" );
654 msg_Raw( NULL, " universal old-sky (default: universal)");
655 msg_Raw( NULL, " -9 --dvb-plp-id <number> Switch PLP of the DVB-T2 transmission (default: 0)" );
656 msg_Raw( NULL, " -F --fec-inner Forward Error Correction (FEC Inner)");
657 msg_Raw( NULL, " DVB-S2 0|12|23|34|35|56|78|89|910|999 (default auto: 999)");
658 msg_Raw( NULL, " -I --inversion Inversion (-1 auto, 0 off, 1 on)" );
659 msg_Raw( NULL, " -m --modulation Modulation type" );
660 msg_Raw( NULL, " DVB-C qpsk|qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
661 msg_Raw( NULL, " DVB-T qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
662 msg_Raw( NULL, " DVB-S2 qpsk|psk_8|apsk_16|apsk_32 (default legacy DVB-S)" );
663 msg_Raw( NULL, " -n --frontend-number <frontend number>" );
664 msg_Raw( NULL, " -p --force-pulse force 22kHz pulses for high-band selection (DVB-S)" );
665 msg_Raw( NULL, " -P --pilot DVB-S2 Pilot (-1 auto, 0 off, 1 on)" );
666 msg_Raw( NULL, " -R --rolloff DVB-S2 Rolloff value" );
667 msg_Raw( NULL, " DVB-S2 35=0.35|25=0.25|20=0.20|0=AUTO (default: 35)" );
668 msg_Raw( NULL, " -1 --multistream-id Set stream ID (0-2147483648, default: 0)." );
669 msg_Raw( NULL, " --multistream-id-pls-mode Set multistream PLS mode (ROOT, GOLD, COMBO, default: ROOT)" );
670 msg_Raw( NULL, " --multistream-id-pls-code Set multistream PLS code (0-262143, default: 0)" );
671 msg_Raw( NULL, " --multistream-id-is-id Set multistream IS id (0-255, default: 0)" );
672 msg_Raw( NULL, " -K --fec-lp DVB-T low priority FEC (default auto)" );
673 msg_Raw( NULL, " -G --guard DVB-T guard interval" );
674 msg_Raw( NULL, " DVB-T 32 (1/32)|16 (1/16)|8 (1/8)|4 (1/4)|-1 (auto, default)" );
675 msg_Raw( NULL, " -H --hierarchy DVB-T hierarchy (0, 1, 2, 4 or -1 auto, default)" );
676 msg_Raw( NULL, " -X --transmission DVB-T transmission (2, 4, 8 or -1 auto, default)" );
677 msg_Raw( NULL, " -s --symbol-rate" );
678 msg_Raw( NULL, " -S --diseqc satellite number for diseqc (0: no diseqc, 1-4, A or B)" );
679 msg_Raw( NULL, " -k --uncommitted port number for uncommitted DiSEqC switch (0: no uncommitted DiSEqC switch, 1-16)" );
680 msg_Raw( NULL, " -u --budget-mode turn on budget mode (no hardware PID filtering)" );
681 msg_Raw( NULL, " -v --voltage voltage to apply to the LNB (QPSK)" );
682 msg_Raw( NULL, " -w --select-pmts set a PID filter on all PMTs (auto on, when config file is used)" );
683 msg_Raw( NULL, " -O --lock-timeout timeout for the lock operation (in ms)" );
684 msg_Raw( NULL, " -y --ca-number <ca_device_number>" );
685 msg_Raw( NULL, " -2 --dvr-buf-size <size> set the size of the DVR TS buffer in bytes (default: %d)", i_dvr_buffer_size);
686 #endif
688 msg_Raw( NULL, "Output:" );
689 msg_Raw( NULL, " -c --config-file <config file>" );
690 msg_Raw( NULL, " -C --dvb-compliance pass through or build the mandatory DVB tables" );
691 msg_Raw( NULL, " -d --duplicate duplicate all received packets to a given destination" );
692 msg_Raw( NULL, " -3 --passthrough duplicate all received packets to stdout" );
693 msg_Raw( NULL, " -W --emm-passthrough pass through EMM data (CA system data)" );
694 msg_Raw( NULL, " -Y --ecm-passthrough pass through ECM data (CA program data)" );
695 msg_Raw( NULL, " -e --epg-passthrough pass through DVB EIT schedule tables" );
696 msg_Raw( NULL, " -E --retention maximum retention allowed between input and output (default: 40 ms)" );
697 msg_Raw( NULL, " -L --latency maximum latency allowed between input and output (default: 100 ms)" );
698 msg_Raw( NULL, " -M --network-name DVB network name to declare in the NIT" );
699 msg_Raw( NULL, " -N --network-id DVB network ID to declare in the NIT" );
700 msg_Raw( NULL, " -B --provider-name Service provider name to declare in the SDT" );
701 msg_Raw( NULL, " -o --rtp-output <SSRC IP>" );
702 msg_Raw( NULL, " -t --ttl <ttl> TTL of the output stream" );
703 msg_Raw( NULL, " -T --unique-ts-id generate random unique TS ID for each output" );
704 msg_Raw( NULL, " -U --udp use raw UDP rather than RTP (required by some IPTV set top boxes)" );
705 msg_Raw( NULL, " -z --any-type pass through all ESs from the PMT, of any type" );
706 msg_Raw( NULL, " -0 --pidmap <pmt_pid,audio_pid,video_pid,spu_pid>");
708 msg_Raw( NULL, "Misc:" );
709 msg_Raw( NULL, " -h --help display this full help" );
710 msg_Raw( NULL, " -i --priority <RT priority>" );
711 msg_Raw( NULL, " -j --system-charset character set used for printing messages (default UTF-8//IGNORE)" );
712 msg_Raw( NULL, " -J --dvb-charset character set used in output DVB tables (default UTF-8//IGNORE)" );
713 msg_Raw( NULL, " -l --logger use syslog for logging messages instead of stderr" );
714 msg_Raw( NULL, " -g --logger-ident program name that will be used in syslog messages" );
715 msg_Raw( NULL, " -x --print print interesting events on stdout in a given format" );
716 msg_Raw( NULL, " -q --quiet be quiet (less verbosity, repeat or use number for even quieter)" );
717 msg_Raw( NULL, " -Q --quit-timeout when locked, quit after this delay (in ms), or after the first lock timeout" );
718 msg_Raw( NULL, " -6 --print-period periodicity at which we print bitrate and errors (in ms)" );
719 msg_Raw( NULL, " -7 --es-timeout time of inactivy before which a PID is reported down (in ms)" );
720 msg_Raw( NULL, " -4 --udp lock-timeout time of inactivy before which a UDP stream is reported down (in ms)" );
721 msg_Raw( NULL, " -r --remote-socket <remote socket>" );
722 msg_Raw( NULL, " -Z --mrtg-file <file> Log input packets and errors into mrtg-file" );
723 msg_Raw( NULL, " -V --version only display the version" );
724 exit(1);
727 int main( int i_argc, char **pp_argv )
729 const char *psz_network_name = "DVBlast - videolan.org";
730 const char *psz_provider_name = NULL;
731 char *psz_dup_config = NULL;
732 struct sched_param param;
733 int i_error;
734 int c;
735 int b_enable_syslog = 0;
736 struct ev_signal sigint_watcher, sigterm_watcher, sighup_watcher;
737 struct ev_timer quit_watcher;
739 print_fh = stdout;
741 if ( i_argc == 1 )
742 usage();
745 * No short options are left.
747 static const struct option long_options[] =
749 { "config-file", required_argument, NULL, 'c' },
750 { "remote-socket", required_argument, NULL, 'r' },
751 { "ttl", required_argument, NULL, 't' },
752 { "rtp-output", required_argument, NULL, 'o' },
753 { "priority", required_argument, NULL, 'i' },
754 { "adapter", required_argument, NULL, 'a' },
755 { "frontend-number", required_argument, NULL, 'n' },
756 { "delsys", required_argument, NULL, '5' },
757 { "dvb-plp-id", required_argument, NULL, '9' },
758 { "frequency", required_argument, NULL, 'f' },
759 { "lnb-type", required_argument, NULL, '8' },
760 { "fec-inner", required_argument, NULL, 'F' },
761 { "rolloff", required_argument, NULL, 'R' },
762 { "symbol-rate", required_argument, NULL, 's' },
763 { "diseqc", required_argument, NULL, 'S' },
764 { "uncommitted", required_argument, NULL, 'k' },
765 { "voltage", required_argument, NULL, 'v' },
766 { "force-pulse", no_argument, NULL, 'p' },
767 { "bandwidth", required_argument, NULL, 'b' },
768 { "inversion", required_argument, NULL, 'I' },
769 { "modulation", required_argument, NULL, 'm' },
770 { "pilot", required_argument, NULL, 'P' },
771 { "multistream-id", required_argument, NULL, '1' },
772 { "multistream-id-pls-mode", required_argument, NULL, 0x100001 },
773 { "multistream-id-pls-code", required_argument, NULL, 0x100002 },
774 { "multistream-id-is-id" , required_argument, NULL, 0x100003 },
775 { "fec-lp", required_argument, NULL, 'K' },
776 { "guard", required_argument, NULL, 'G' },
777 { "hierarchy", required_argument, NULL, 'H' },
778 { "transmission", required_argument, NULL, 'X' },
779 { "lock-timeout", required_argument, NULL, 'O' },
780 { "budget-mode", no_argument, NULL, 'u' },
781 { "select-pmts", no_argument, NULL, 'w' },
782 { "udp", no_argument, NULL, 'U' },
783 { "unique-ts-id", no_argument, NULL, 'T' },
784 { "latency", required_argument, NULL, 'L' },
785 { "retention", required_argument, NULL, 'E' },
786 { "duplicate", required_argument, NULL, 'd' },
787 { "passthrough", no_argument, NULL, '3' },
788 { "rtp-input", required_argument, NULL, 'D' },
789 { "asi-adapter", required_argument, NULL, 'A' },
790 { "any-type", no_argument, NULL, 'z' },
791 { "dvb-compliance", no_argument, NULL, 'C' },
792 { "emm-passthrough", no_argument, NULL, 'W' },
793 { "ecm-passthrough", no_argument, NULL, 'Y' },
794 { "epg-passthrough", no_argument, NULL, 'e' },
795 { "network-name", no_argument, NULL, 'M' },
796 { "network-id", no_argument, NULL, 'N' },
797 { "system-charset", required_argument, NULL, 'j' },
798 { "dvb-charset", required_argument, NULL, 'J' },
799 { "provider-name", required_argument, NULL, 'B' },
800 { "logger", no_argument, NULL, 'l' },
801 { "logger-ident", required_argument, NULL, 'g' },
802 { "print", required_argument, NULL, 'x' },
803 { "quit-timeout", required_argument, NULL, 'Q' },
804 { "print-period", required_argument, NULL, '6' },
805 { "es-timeout", required_argument, NULL, '7' },
806 { "udp-lock-timeout", required_argument, NULL, '4' },
807 { "quiet", no_argument, NULL, 'q' },
808 { "help", no_argument, NULL, 'h' },
809 { "version", no_argument, NULL, 'V' },
810 { "mrtg-file", required_argument, NULL, 'Z' },
811 { "ca-number", required_argument, NULL, 'y' },
812 { "pidmap", required_argument, NULL, '0' },
813 { "dvr-buf-size", required_argument, NULL, '2' },
814 { 0, 0, 0, 0 }
817 while ( (c = getopt_long(i_argc, pp_argv, "q::c:r:t:o:i:a:n:5:f:F:R:s:S:k:v:pb:I:m:P:K:G:H:X:O:uwUTL:E:d:3D:A:lg:zCWYeM:N:j:J:B:x:Q:6:7:4:hVZ:y:0:1:2:9:", long_options, NULL)) != -1 )
819 switch ( c )
821 case 'q':
822 if ( optarg )
824 if ( *optarg == 'q' ) /* e.g. -qqq */
826 i_verbose--;
827 while ( *optarg == 'q' )
829 i_verbose--;
830 optarg++;
833 else
835 i_verbose -= atoi( optarg ); /* e.g. -q2 */
838 else
840 i_verbose--; /* -q */
842 break;
844 case 'c':
845 psz_conf_file = optarg;
847 * When configuration file is used it is reasonable to assume that
848 * services may be added/removed. If b_select_pmts is not set dvblast
849 * is unable to start streaming newly added services in the config.
851 b_select_pmts = 1;
852 break;
854 case 'r':
855 psz_srv_socket = optarg;
856 break;
858 case 't':
859 i_ttl_global = strtol( optarg, NULL, 0 );
860 break;
862 case 'o':
864 struct in_addr maddr;
865 if ( !inet_aton( optarg, &maddr ) )
866 usage();
867 memcpy( pi_ssrc_global, &maddr.s_addr, 4 * sizeof(uint8_t) );
868 break;
871 case 'i':
872 i_priority = strtol( optarg, NULL, 0 );
873 break;
875 case 'a':
876 i_adapter = strtol( optarg, NULL, 0 );
877 break;
879 case 'n':
880 i_fenum = strtol( optarg, NULL, 0 );
881 break;
883 case 'y':
884 i_canum = strtol( optarg, NULL, 0 );
885 break;
887 case '5':
888 psz_delsys = optarg;
889 break;
890 case '9':
891 dvb_plp_id = strtol( optarg, NULL, 0 );
892 break;
893 case 'f':
894 if (optarg && optarg[0] != '-')
895 i_frequency = strtol( optarg, NULL, 0 );
896 if ( pf_Open != NULL )
897 usage();
898 #ifdef HAVE_DVB_SUPPORT
899 pf_Open = dvb_Open;
900 pf_Reset = dvb_Reset;
901 pf_SetFilter = dvb_SetFilter;
902 pf_UnsetFilter = dvb_UnsetFilter;
903 #else
904 msg_Err( NULL, "DVBlast is compiled without DVB support.");
905 exit(1);
906 #endif
907 break;
909 case '8':
910 psz_lnb_type = optarg;
911 break;
913 case 'F':
914 i_fec = strtol( optarg, NULL, 0 );
915 break;
917 case 'R':
918 i_rolloff = strtol( optarg, NULL, 0 );
919 break;
921 case 's':
922 i_srate = strtol( optarg, NULL, 0 );
923 break;
925 case 'S':
926 i_satnum = strtol( optarg, NULL, 16 );
927 break;
929 case 'k':
930 i_uncommitted = strtol( optarg, NULL, 10 );
931 break;
933 case 'v':
934 i_voltage = strtol( optarg, NULL, 0 );
935 break;
937 case 'p':
938 b_tone = 1;
939 break;
941 case 'b':
942 i_bandwidth = strtol( optarg, NULL, 0 );
943 break;
945 case 'I':
946 i_inversion = strtol( optarg, NULL, 0 );
947 break;
949 case 'm':
950 psz_modulation = optarg;
951 break;
953 case 'P':
954 i_pilot = strtol( optarg, NULL, 0 );
955 break;
957 case '1':
958 i_mis = strtol( optarg, NULL, 0 );
959 break;
961 case 0x100001: // --multistream-id-pls-mode
962 psz_mis_pls_mode = optarg;
963 if ( streq( psz_mis_pls_mode, "ROOT" ) ) {
964 i_mis_pls_mode = 0;
965 } else if ( streq( psz_mis_pls_mode, "GOLD" ) ) {
966 i_mis_pls_mode = 1;
967 } else if ( streq( psz_mis_pls_mode, "COMBO" ) ) {
968 i_mis_pls_mode = 2;
969 } else {
970 msg_Err(NULL, "Invalid --multistream-id-pls-mode '%s', valid options are: ROOT GOLD COMBO", optarg);
971 exit(1);
973 break;
975 case 0x100002: // --multistream-id-pls-code
976 i_mis_pls_code = strtol( optarg, NULL, 0 );
977 if ( i_mis_pls_code < 0 || i_mis_pls_code > 262143 ) {
978 msg_Err(NULL, "ERROR: Invalid --multistream-id-pls-code '%s', valid options are: 0-262143", optarg);
979 exit(1);
981 break;
983 case 0x100003: // --multistream-id-is-id
984 i_mis_is_id = strtol( optarg, NULL, 0 );
985 if ( i_mis_is_id < 0 || i_mis_is_id > 255 ) {
986 msg_Err(NULL, "ERROR: Invalid --multistream-id-is-id '%s', valid options are: 0-255", optarg);
987 exit(1);
989 break;
991 case 'K':
992 i_fec_lp = strtol( optarg, NULL, 0 );
993 break;
995 case 'G':
996 i_guard = strtol( optarg, NULL, 0 );
997 break;
999 case 'X':
1000 i_transmission = strtol( optarg, NULL, 0 );
1001 break;
1003 case 'O':
1004 i_frontend_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
1005 break;
1007 case 'H':
1008 i_hierarchy = strtol( optarg, NULL, 0 );
1009 break;
1011 case 'u':
1012 b_budget_mode = 1;
1013 break;
1015 case 'w':
1016 b_select_pmts = !b_select_pmts;
1017 break;
1019 case 'U':
1020 b_udp_global = true;
1021 break;
1023 case 'L':
1024 i_latency_global = strtoll( optarg, NULL, 0 ) * 1000;
1025 break;
1027 case 'E':
1028 i_retention_global = strtoll( optarg, NULL, 0 ) * 1000;
1029 break;
1031 case 'd':
1032 psz_dup_config = optarg;
1033 break;
1035 case '3':
1036 b_passthrough = true;
1037 print_fh = stderr;
1038 break;
1040 case 'D':
1041 psz_udp_src = optarg;
1042 if ( pf_Open != NULL )
1043 usage();
1044 pf_Open = udp_Open;
1045 pf_Reset = udp_Reset;
1046 pf_SetFilter = udp_SetFilter;
1047 pf_UnsetFilter = udp_UnsetFilter;
1048 break;
1050 case 'A':
1051 #ifdef HAVE_ASI_SUPPORT
1052 if ( pf_Open != NULL )
1053 usage();
1054 if ( strncmp(optarg, "deltacast:", 10) == 0)
1056 #ifdef HAVE_ASI_DELTACAST_SUPPORT
1057 i_asi_adapter = strtol( optarg+10, NULL, 0 );
1058 pf_Open = asi_deltacast_Open;
1059 pf_Reset = asi_deltacast_Reset;
1060 pf_SetFilter = asi_deltacast_SetFilter;
1061 pf_UnsetFilter = asi_deltacast_UnsetFilter;
1062 #else
1063 msg_Err( NULL, "DVBlast is compiled without Deltacast ASI support.");
1064 exit(1);
1065 #endif
1067 else
1069 i_asi_adapter = strtol( optarg, NULL, 0 );
1070 pf_Open = asi_Open;
1071 pf_Reset = asi_Reset;
1072 pf_SetFilter = asi_SetFilter;
1073 pf_UnsetFilter = asi_UnsetFilter;
1075 #else
1076 msg_Err( NULL, "DVBlast is compiled without ASI support.");
1077 exit(1);
1078 #endif
1079 break;
1081 case 'z':
1082 b_any_type = 1;
1083 break;
1085 case 'C':
1086 b_dvb_global = true;
1087 break;
1089 case 'W':
1090 b_enable_emm = true;
1091 break;
1093 case 'Y':
1094 b_enable_ecm = true;
1095 break;
1097 case 'e':
1098 b_epg_global = true;
1099 break;
1101 case 'M':
1102 psz_network_name = optarg;
1103 break;
1105 case 'N':
1106 i_network_id = strtoul( optarg, NULL, 0 );
1107 break;
1109 case 'T':
1110 b_random_tsid = 1;
1111 break;
1113 case 'j':
1114 psz_native_charset = optarg;
1115 break;
1117 case 'J':
1118 psz_dvb_charset = optarg;
1119 break;
1121 case 'B':
1122 psz_provider_name = optarg;
1123 break;
1125 case 'l':
1126 b_enable_syslog = 1;
1127 break;
1129 case 'g':
1130 psz_syslog_ident = optarg;
1131 break;
1133 case 'x':
1134 b_print_enabled = true;
1135 if ( !strcmp(optarg, "text") )
1136 i_print_type = PRINT_TEXT;
1137 else if ( !strcmp(optarg, "xml") )
1138 i_print_type = PRINT_XML;
1139 else
1141 b_print_enabled = false;
1142 msg_Warn( NULL, "unrecognized print type %s", optarg );
1144 break;
1146 case 'Q':
1147 i_quit_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
1148 break;
1150 case '6':
1151 i_print_period = strtoll( optarg, NULL, 0 ) * 1000;
1152 break;
1154 case '7':
1155 i_es_timeout = strtoll( optarg, NULL, 0 ) * 1000;
1156 break;
1158 case '4':
1159 i_udp_lock_timeout = strtoll( optarg, NULL, 0 ) * 1000;
1160 break;
1162 case 'V':
1163 DisplayVersion();
1164 exit(0);
1165 break;
1167 case 'Z':
1168 psz_mrtg_file = optarg;
1169 break;
1171 case '0': {
1172 /* We expect a comma separated list of numbers.
1173 Put them into the pi_newpids array as they appear */
1174 char *str1;
1175 char *saveptr = NULL;
1176 char *tok = NULL;
1177 int i, i_newpid;
1178 for (i = 0, str1 = optarg; i < N_MAP_PIDS; i++, str1 = NULL)
1180 tok = strtok_r(str1, ",", &saveptr);
1181 if ( !tok )
1182 break;
1183 i_newpid = strtoul(tok, NULL, 0);
1184 if ( !i_newpid ) {
1185 msg_Err( NULL, "Invalid pidmap string" );
1186 usage();
1188 pi_newpids[i] = i_newpid;
1190 b_do_remap = true;
1191 break;
1193 #ifdef HAVE_DVB_SUPPORT
1194 case '2':
1195 i_dvr_buffer_size = strtol( optarg, NULL, 0 );
1196 if (!i_dvr_buffer_size)
1197 usage(); // it exits
1198 /* roundup to packet size */
1199 i_dvr_buffer_size += TS_SIZE - 1;
1200 i_dvr_buffer_size /= TS_SIZE;
1201 i_dvr_buffer_size *= TS_SIZE;
1202 break;
1203 #endif
1204 case 'h':
1205 default:
1206 usage();
1209 if ( optind < i_argc || pf_Open == NULL )
1210 usage();
1212 if ( b_enable_syslog )
1213 msg_Connect( psz_syslog_ident ? psz_syslog_ident : pp_argv[0] );
1215 if ( b_print_enabled )
1217 /* Make std* line-buffered */
1218 setvbuf(print_fh, NULL, _IOLBF, 0);
1221 if ( i_verbose )
1222 DisplayVersion();
1224 msg_Warn( NULL, "restarting" );
1226 switch (i_print_type)
1228 case PRINT_XML:
1229 fprintf(print_fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1230 fprintf(print_fh, "<TS>\n");
1231 break;
1232 default:
1233 break;
1236 if ( b_udp_global )
1238 msg_Warn( NULL, "raw UDP output is deprecated. Please consider using RTP." );
1239 msg_Warn( NULL, "for DVB-IP compliance you should use RTP." );
1242 if ( b_epg_global && !b_dvb_global )
1244 msg_Dbg( NULL, "turning on DVB compliance, required by EPG information" );
1245 b_dvb_global = true;
1248 if ((event_loop = ev_default_loop(0)) == NULL)
1250 msg_Err( NULL, "unable to initialize libev" );
1251 exit(EXIT_FAILURE);
1254 memset( &output_dup, 0, sizeof(output_dup) );
1255 if ( psz_dup_config != NULL )
1257 output_config_t config;
1259 config_Defaults( &config );
1260 if ( !config_ParseHost( &config, psz_dup_config ) )
1261 msg_Err( NULL, "Invalid target address for -d switch" );
1262 else
1264 output_Init( &output_dup, &config );
1265 output_Change( &output_dup, &config );
1268 config_Free( &config );
1271 config_strdvb( &network_name, psz_network_name, psz_dvb_charset );
1272 config_strdvb( &provider_name, psz_provider_name, psz_dvb_charset );
1274 /* Set signal handlers */
1275 signal_watcher_init(&sigint_watcher, event_loop, sighandler, SIGINT);
1276 signal_watcher_init(&sigterm_watcher, event_loop, sighandler, SIGTERM);
1277 signal_watcher_init(&sighup_watcher, event_loop, sighandler, SIGHUP);
1279 srand( time(NULL) * getpid() );
1281 if ( i_mis_pls_mode || i_mis_pls_code || i_mis_is_id )
1283 i_mis = calc_multistream_id( i_mis_pls_mode, i_mis_pls_code, i_mis_is_id );
1284 msg_Info( NULL, "Calculating multistream-id using pls-mode: %s (%d) pls-code: %d is-id: %d. Resulting multistream-id: %d (0x%x)",
1285 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1287 else if ( i_mis )
1289 i_mis_pls_mode = (i_mis >> 26) & 0x03;
1290 i_mis_pls_code = (i_mis >> 8) & 0x3ffff;
1291 i_mis_is_id = i_mis & 0xff;
1292 psz_mis_pls_mode =
1293 i_mis_pls_mode == 0 ? "ROOT" :
1294 i_mis_pls_mode == 1 ? "GOLD" :
1295 i_mis_pls_mode == 2 ? "COMBO" : "UNKNOWN";
1297 msg_Info( NULL, "Calculated multistream pls-mode: %s (%d) pls-code: %d is-id: %d from multistream-id: %d (0x%x)",
1298 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1301 demux_Open();
1303 // init the mrtg logfile
1304 mrtgInit(psz_mrtg_file);
1306 if ( i_priority > 0 )
1308 memset( &param, 0, sizeof(struct sched_param) );
1309 param.sched_priority = i_priority;
1310 if ( (i_error = pthread_setschedparam( pthread_self(), SCHED_RR,
1311 &param )) )
1313 msg_Warn( NULL, "couldn't set thread priority: %s",
1314 strerror(i_error) );
1318 config_ReadFile();
1320 if ( psz_srv_socket != NULL )
1321 comm_Open();
1323 if ( i_quit_timeout_duration )
1325 ev_timer_init(&quit_watcher, quit_cb,
1326 i_quit_timeout_duration / 1000000., 0);
1327 ev_timer_start(event_loop, &quit_watcher);
1330 outputs_Init();
1332 ev_run(event_loop, 0);
1334 mrtgClose();
1335 outputs_Close( i_nb_outputs );
1336 demux_Close();
1337 dvb_string_clean( &network_name );
1338 dvb_string_clean( &provider_name );
1339 if ( conf_iconv != (iconv_t)-1 )
1340 iconv_close( conf_iconv );
1342 switch (i_print_type)
1344 case PRINT_XML:
1345 fprintf(print_fh, "</TS>\n");
1346 break;
1347 default:
1348 break;
1351 if ( b_enable_syslog )
1352 msg_Disconnect();
1354 comm_Close();
1355 block_Vacuum();
1356 ev_loop_destroy(event_loop);
1358 return EXIT_SUCCESS;