]> git.sesse.net Git - vlc/blob - modules/access/dvb/scan.c
dvb: add ability to scann modulation from dvb-c
[vlc] / modules / access / dvb / scan.c
1 /*****************************************************************************
2  * scan.c: DVB scanner helpers
3  *****************************************************************************
4  * Copyright (C) 2008,2010 the VideoLAN team
5  *
6  * Authors: Laurent Aimar <fenrir@videolan.org>
7  *          David Kaplan <david@2of1.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_block.h>
33 #include <vlc_dialog.h>
34 #include <vlc_fs.h>
35 #include <vlc_charset.h>
36
37 #include <sys/types.h>
38
39 /* Include dvbpsi headers */
40 #include <dvbpsi/dvbpsi.h>
41 #include <dvbpsi/descriptor.h>
42 #include <dvbpsi/pat.h>
43 #include <dvbpsi/pmt.h>
44 #include <dvbpsi/dr.h>
45 #include <dvbpsi/psi.h>
46 #include <dvbpsi/demux.h>
47 #include <dvbpsi/sdt.h>
48 #ifdef _DVBPSI_DR_43_H_
49 #   define DVBPSI_USE_NIT 1
50 #   include <dvbpsi/nit.h>
51 #endif
52
53 #include "scan.h"
54 #include "../../demux/dvb-text.h"
55
56 typedef enum
57 {
58     SERVICE_UNKNOWN = 0,
59     SERVICE_DIGITAL_RADIO,
60     SERVICE_DIGITAL_TELEVISION,
61     SERVICE_DIGITAL_TELEVISION_AC_SD,
62     SERVICE_DIGITAL_TELEVISION_AC_HD,
63 } scan_service_type_t;
64
65 typedef struct
66 {
67     int  i_program;     /* program number (service id) */
68     scan_configuration_t cfg;
69     int i_snr;
70
71     scan_service_type_t type;
72     char *psz_name;     /* channel name in utf8 or NULL */
73     int  i_channel;     /* -1 if unknown */
74     bool b_crypted;     /* True if potentially crypted */
75
76     int i_network_id;
77
78     int i_nit_version;
79     int i_sdt_version;
80
81 } scan_service_t;
82
83 struct scan_t
84 {
85     vlc_object_t *p_obj;
86     struct dialog_progress_bar_t *p_dialog;
87     int64_t i_index;
88     scan_parameter_t parameter;
89     int64_t i_time_start;
90
91     int            i_service;
92     scan_service_t **pp_service;
93 };
94
95 struct scan_session_t
96 {
97     vlc_object_t *p_obj;
98
99     scan_configuration_t cfg;
100     int i_snr;
101
102     dvbpsi_handle pat;
103     dvbpsi_pat_t *p_pat;
104     int i_nit_pid;
105
106     dvbpsi_handle sdt;
107     dvbpsi_sdt_t *p_sdt;
108
109 #ifdef DVBPSI_USE_NIT
110     dvbpsi_handle nit;
111     dvbpsi_nit_t *p_nit;
112 #else
113 #   warning NIT is not supported by your libdvbpsi version
114 #endif
115
116 };
117
118 /* */
119 static scan_service_t *scan_service_New( int i_program,
120                                          const scan_configuration_t *p_cfg )
121 {
122     scan_service_t *p_srv = malloc( sizeof(*p_srv) );
123     if( !p_srv )
124         return NULL;
125
126     p_srv->i_program = i_program;
127     p_srv->cfg = *p_cfg;
128     p_srv->i_snr = -1;
129
130     p_srv->type = SERVICE_UNKNOWN;
131     p_srv->psz_name = NULL;
132     p_srv->i_channel = -1;
133     p_srv->b_crypted = false;
134
135     p_srv->i_network_id = -1;
136     p_srv->i_nit_version = -1;
137     p_srv->i_sdt_version = -1;
138
139     return p_srv;
140 }
141
142 static void scan_service_Delete( scan_service_t *p_srv )
143 {
144     free( p_srv->psz_name );
145     free( p_srv );
146 }
147
148 /* */
149 scan_t *scan_New( vlc_object_t *p_obj, const scan_parameter_t *p_parameter )
150 {
151     if( p_parameter->type == SCAN_DVB_T )
152     {
153         msg_Dbg( p_obj, "DVB-T scanning:" );
154         msg_Dbg( p_obj, " - frequency [%d, %d]",
155                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
156         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
157                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
158         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
159     }
160     else if( p_parameter->type == SCAN_DVB_C )
161     {
162         msg_Dbg( p_obj, "DVB-C scanning:" );
163         msg_Dbg( p_obj, " - frequency [%d, %d]",
164                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
165         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
166                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
167         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
168         msg_Dbg( p_obj, " - scannin modulations %s", p_parameter->b_modulation_set ? "off" : "on" );
169     }
170     else if( p_parameter->type == SCAN_DVB_S )
171     {
172         msg_Dbg( p_obj, "DVB-S scanning:" );
173         msg_Dbg( p_obj, " - satellite [%s]", p_parameter->sat_info.psz_name );
174     }
175     else
176     {
177         return NULL;
178     }
179     msg_Dbg( p_obj, " - use NIT %s", p_parameter->b_use_nit ? "on" : "off" );
180     msg_Dbg( p_obj, " - FTA only %s", p_parameter->b_free_only ? "on" : "off" );
181
182     scan_t *p_scan = malloc( sizeof( *p_scan ) );
183     if( unlikely(p_scan == NULL) )
184         return NULL;
185
186     p_scan->p_obj = VLC_OBJECT(p_obj);
187     p_scan->i_index = 0;
188     p_scan->p_dialog = NULL;
189     TAB_INIT( p_scan->i_service, p_scan->pp_service );
190     p_scan->parameter = *p_parameter;
191     p_scan->i_time_start = mdate();
192
193     return p_scan;
194 }
195
196 void scan_Destroy( scan_t *p_scan )
197 {
198     if( p_scan->p_dialog != NULL )
199         dialog_ProgressDestroy( p_scan->p_dialog );
200
201     for( int i = 0; i < p_scan->i_service; i++ )
202         scan_service_Delete( p_scan->pp_service[i] );
203     TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
204     free( p_scan );
205 }
206
207 static int ScanDvbSNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
208 {
209     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
210
211     int *pi_count = &p_scan->parameter.sat_info.i_count;
212
213     if( !p_scan->parameter.sat_info.psz_name )
214     {
215         msg_Err( p_scan->p_obj, "no satellite selected" );
216         return VLC_EGENERIC;
217     }
218
219     /* if there are no transponders in mem, laod from config file */
220     if( !*pi_count )
221     {
222         DIR *p_dir;
223
224         char *psz_dir = NULL;
225         char *data_dir = config_GetDataDir( p_scan->p_obj );
226
227         if( asprintf( &psz_dir, "%s" DIR_SEP "dvb" DIR_SEP "dvb-s", data_dir ) == -1 )
228             psz_dir = NULL;
229         free( data_dir );
230
231         if( !psz_dir )
232         {
233             free( p_scan->parameter.sat_info.psz_name );
234             return VLC_EGENERIC;
235         }
236
237         /* open config directory */
238         if( !( p_dir = vlc_opendir( psz_dir ) ) )
239         {
240             msg_Err( p_scan->p_obj, "could not open satellite info directory (%s)", psz_dir );
241             free( p_scan->parameter.sat_info.psz_name );
242             return VLC_EGENERIC;
243         }
244
245         /* find the requested file in the directory */
246         for( ; ; ) {
247             char *psz_filename;
248
249             if( ! (psz_filename = vlc_readdir( p_dir ) ) )
250                 break;
251
252             if( !strncmp( p_scan->parameter.sat_info.psz_name, psz_filename, 20 ) )
253             {
254                 if( asprintf( &p_scan->parameter.sat_info.psz_path, "%s" DIR_SEP "%s", psz_dir, psz_filename ) == -1 )
255                     p_scan->parameter.sat_info.psz_path = NULL;
256
257                 free( psz_filename );
258                 break;
259             }
260         }
261
262         closedir( p_dir );
263
264         if( !p_scan->parameter.sat_info.psz_path )
265         {
266             msg_Err( p_scan->p_obj, "could not find satellite config (%s)", p_scan->parameter.sat_info.psz_name );
267             free( p_scan->parameter.sat_info.psz_name );
268             return VLC_EGENERIC;
269         }
270
271         msg_Dbg( p_scan->p_obj, "using satellite config file (%s)", p_scan->parameter.sat_info.psz_path );
272
273         FILE *f = vlc_fopen( p_scan->parameter.sat_info.psz_path, "r" );
274
275         /* parse file */
276         if( f )
277         {
278             scan_dvbs_transponder_t *p_transponders = malloc( sizeof( scan_dvbs_transponder_t ) );
279             char type;
280             char psz_fec[3];
281
282             int res;
283             do
284             {
285                 if ( ( res = fscanf( f, "%c %d %c %d %s\n",
286                             &type,
287                             &p_transponders[*pi_count].i_frequency,
288                             &p_transponders[*pi_count].c_polarization,
289                             &p_transponders[*pi_count].i_symbol_rate,
290                             psz_fec ) ) != 5 )
291                 {
292                     msg_Dbg( p_scan->p_obj, "error parsing transponder from file" );
293                     continue;
294                 }
295
296                 /* decode fec */
297                 char psz_fec_list[] = "1/22/33/44/55/66/77/88/9";
298                 char *p_fec = strstr( psz_fec_list, psz_fec );
299                 if ( !p_fec )
300                     p_transponders[*pi_count].i_fec = 9;    /* FEC_AUTO */
301                 else
302                     p_transponders[*pi_count].i_fec = 1 + ( ( p_fec-psz_fec_list ) / 3 );
303
304                 (*pi_count)++;
305
306                 p_transponders = realloc(p_transponders, ( *pi_count + 1 ) * sizeof( scan_dvbs_transponder_t ) );
307             } while (res != EOF);
308
309             msg_Dbg( p_scan->p_obj, "parsed %d transponders from config", *pi_count);
310
311             fclose( f );
312             p_scan->parameter.sat_info.p_transponders = p_transponders;
313         }
314         else
315         {
316             msg_Err( p_scan->p_obj, "failed to open satellite file (%s)", p_scan->parameter.sat_info.psz_path );
317             free( p_scan->parameter.sat_info.psz_name );
318             free( p_scan->parameter.sat_info.psz_path );
319             return VLC_EGENERIC;
320         }
321         free( p_scan->parameter.sat_info.psz_name );
322         free( p_scan->parameter.sat_info.psz_path );
323     }
324
325     if( p_scan->i_index < *pi_count )
326     {
327         /* setup params for scan */
328         p_cfg->i_symbol_rate = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_symbol_rate / 1000;
329         p_cfg->i_frequency = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_frequency;
330         p_cfg->i_fec = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].i_fec;
331         p_cfg->c_polarization = p_scan->parameter.sat_info.p_transponders[p_scan->i_index].c_polarization;
332
333         msg_Dbg( p_scan->p_obj,
334                  "transponder [%"PRId64"/%d]: frequency=%d, symbolrate=%d, fec=%d, polarization=%c",
335                  p_scan->i_index + 1,
336                  *pi_count,
337                  p_cfg->i_frequency,
338                  p_cfg->i_symbol_rate,
339                  p_cfg->i_fec,
340                  p_cfg->c_polarization );
341
342         *pf_pos = (double)p_scan->i_index / *pi_count;
343
344         return VLC_SUCCESS;
345     }
346
347     if( p_scan->parameter.sat_info.p_transponders )
348     {
349         free( p_scan->parameter.sat_info.p_transponders );
350         p_scan->parameter.sat_info.p_transponders = NULL;
351     }
352
353     return VLC_EGENERIC;
354 }
355
356 static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
357 {
358     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
359     /* Values taken from dvb-scan utils frequency-files, sorted by how
360      * often they appear. This hopefully speeds up finding services. */
361     static const unsigned short frequencies[] = {
362      410, 426, 418, 394, 402, 362,
363      370, 354, 346, 442, 434, 386,
364      378, 450, 306, 162, 154, 474,
365      466, 458, 338, 754, 714, 586,
366      562, 546, 514, 490, 314, 170,
367      113, 770, 762, 746, 738, 730,
368      722, 706, 690, 682, 674, 666,
369      650, 642, 634, 554, 538, 530,
370      506, 498, 330, 322, 283, 850,
371      842, 834, 818, 810, 802, 794,
372      786, 778, 748, 732, 728, 724,
373      720, 698, 660, 658, 656, 610,
374      594, 578, 570, 522, 482, 377,
375      372, 347, 339, 323, 315, 299,
376      298, 291, 275, 267, 259, 255,
377      251, 243, 235, 232, 227, 219,
378      211, 203, 195, 187, 179, 171,
379      163, 155, 147, 146, 143, 139,
380      131, 123, 121
381     };
382     enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
383
384     if( p_scan->i_index < num_frequencies )
385     {
386         p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
387         *pf_pos = (double)p_scan->i_index / num_frequencies;
388         return VLC_SUCCESS;
389     }
390     return VLC_EGENERIC;
391 }
392
393 static int ScanDvbNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
394 {
395     if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
396         return VLC_EGENERIC;
397
398     const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
399     const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
400
401     p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
402     p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
403
404     *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
405     return VLC_SUCCESS;
406 }
407
408 static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
409 {
410     static const int i_band_count = 2;
411     static const struct
412     {
413         const char *psz_name;
414         int i_min;
415         int i_max;
416     }
417     band[2] =
418     {
419         { "VHF", 174, 230 },
420         { "UHF", 470, 862 },
421     };
422     const int i_offset_count = 5;
423     const int i_mhz = 1000000;
424
425     /* We will probe the whole band divided in all bandwidth possibility trying 
426      * i_offset_count offset around the position
427      */
428     for( ;; p_scan->i_index++ )
429     {
430
431         const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
432         const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
433         const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
434
435         const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
436         int i;
437
438         for( i = 0; i < i_band_count; i++ )
439         {
440             if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
441                 break;
442         }
443         if( i >=i_band_count )
444         {
445             if( i_fi > band[i_band_count-1].i_max )
446                 return VLC_EGENERIC;
447             continue;
448         }
449
450         const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
451         const int i_frequency_base = i_fi*i_mhz;
452
453         if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
454         {
455             const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
456
457             if( i_frequency < p_scan->parameter.frequency.i_min ||
458                 i_frequency > p_scan->parameter.frequency.i_max )
459                 continue;
460
461             p_cfg->i_frequency = i_frequency;
462             p_cfg->i_bandwidth = i_bandwidth;
463
464             int i_current = 0, i_total = 0;
465             for( int i = 0; i < i_band_count; i++ )
466             {
467                 const int i_frag = band[i].i_max-band[i].i_min;
468
469                 if( i_fi >= band[i].i_min )
470                     i_current += __MIN( i_fi - band[i].i_min, i_frag );
471                 i_total += i_frag;
472             }
473
474             *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
475             return VLC_SUCCESS;
476         }
477     }
478 }
479
480 static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
481 {
482     if( p_scan->parameter.b_exhaustive )
483         return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
484     else
485         return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
486 }
487
488 static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
489 {
490     if( p_scan->parameter.b_exhaustive )
491         return ScanDvbNextExhaustive( p_scan, p_cfg, pf_pos );
492     else
493         return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
494 }
495
496 static int ScanDvbSNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
497 {
498     if( p_scan->parameter.b_exhaustive )
499         msg_Dbg( p_scan->p_obj, "no exhaustive svb-d scan mode" );
500
501     return ScanDvbSNextFast( p_scan, p_cfg, pf_pos );
502 }
503
504 int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
505 {
506     double f_position;
507     int i_ret;
508
509     if( scan_IsCancelled( p_scan ) )
510         return VLC_EGENERIC;
511
512     memset( p_cfg, 0, sizeof(*p_cfg) );
513     switch( p_scan->parameter.type )
514     {
515     case SCAN_DVB_T:
516         i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
517         break;
518     case SCAN_DVB_C:
519         i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
520         break;
521     case SCAN_DVB_S:
522         i_ret = ScanDvbSNext( p_scan, p_cfg, &f_position );
523         break;
524     default:
525         i_ret = VLC_EGENERIC;
526         break;
527     }
528
529     if( i_ret )
530         return i_ret;
531
532     char *psz_text;
533     int i_service = 0;
534
535     for( int i = 0; i < p_scan->i_service; i++ )
536     {
537         if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
538             i_service++;
539     }
540
541     const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
542     char psz_eta[MSTRTIME_MAX_SIZE];
543
544     if( asprintf( &psz_text, _("%.1f MHz (%d services)\n~%s remaining"),
545                   (double)p_cfg->i_frequency / 1000000, i_service, secstotimestr( psz_eta, i_eta/1000000 ) ) >= 0 )
546     {
547         if( i_eta >= 0 )
548             msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
549
550         if( p_scan->p_dialog == NULL )
551             p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB"), psz_text, _("Cancel") );
552         if( p_scan->p_dialog != NULL )
553             dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
554         free( psz_text );
555     }
556
557     if( i_service == 0 &&
558         p_scan->parameter.type == SCAN_DVB_C &&
559         !p_scan->parameter.b_modulation_set )
560     {
561         p_scan->parameter.i_modulation = (p_scan->parameter.i_modulation << 1 ) % 512;
562         /* if we iterated all modulations, move on */
563         if( !p_cfg->i_modulation )
564         {
565             p_scan->parameter.i_modulation = 16;
566             p_scan->i_index++;
567         }
568         msg_Dbg( p_scan->p_obj, "modulation %d ", p_cfg->i_modulation );
569     } else {
570        p_scan->i_index++;
571     }
572     if( p_scan->parameter.type == SCAN_DVB_C )
573        p_cfg->i_modulation = p_scan->parameter.i_modulation;
574     return VLC_SUCCESS;
575 }
576
577 bool scan_IsCancelled( scan_t *p_scan )
578 {
579     return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
580 }
581
582 static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
583 {
584     for( int i = i_service_start; i < p_scan->i_service; i++ )
585     {
586         if( p_scan->pp_service[i]->i_program == i_program )
587             return p_scan->pp_service[i];
588     }
589     return NULL;
590 }
591
592 /* FIXME handle properly string (convert to utf8) */
593 static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
594 {
595     vlc_object_t *p_obj = p_session->p_obj;
596
597     msg_Dbg( p_obj, "PATCallBack" );
598
599     /* */
600     if( p_session->p_pat && p_session->p_pat->b_current_next )
601     {
602         dvbpsi_DeletePAT( p_session->p_pat );
603         p_session->p_pat = NULL;
604     }
605     if( p_session->p_pat )
606     {
607         dvbpsi_DeletePAT( p_pat );
608         return;
609     }
610
611     dvbpsi_pat_program_t *p_program;
612
613     /* */
614     p_session->p_pat = p_pat;
615
616     /* */
617     msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
618              p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
619     for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
620     {
621         msg_Dbg( p_obj, "  * number=%d pid=%d", p_program->i_number, p_program->i_pid );
622         if( p_program->i_number == 0 )
623             p_session->i_nit_pid = p_program->i_pid;
624     }
625 }
626 static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
627 {
628     vlc_object_t *p_obj = p_session->p_obj;
629
630     msg_Dbg( p_obj, "SDTCallBack" );
631
632     if( p_session->p_sdt && p_session->p_sdt->b_current_next )
633     {
634         dvbpsi_DeleteSDT( p_session->p_sdt );
635         p_session->p_sdt = NULL;
636     }
637     if( p_session->p_sdt )
638     {
639         dvbpsi_DeleteSDT( p_sdt );
640         return;
641     }
642
643     /* */
644     p_session->p_sdt = p_sdt;
645
646     /* */
647     msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
648              p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
649              p_sdt->i_network_id );
650
651
652     dvbpsi_sdt_service_t *p_srv;
653     for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
654     {
655         dvbpsi_descriptor_t *p_dr;
656
657         msg_Dbg( p_obj, "  * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
658                  p_srv->i_service_id, p_srv->b_eit_schedule,
659                  p_srv->b_eit_present, p_srv->i_running_status,
660                  p_srv->b_free_ca );
661         for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
662         {
663             if( p_dr->i_tag == 0x48 )
664             {
665                 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
666                 char str2[257];
667
668                 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
669                 str2[pD->i_service_name_length] = '\0';
670
671                 msg_Dbg( p_obj, "    - type=%d name=%s",
672                          pD->i_service_type, str2 );
673             }
674             else
675             {
676                 msg_Dbg( p_obj, "    * dsc 0x%x", p_dr->i_tag );
677             }
678         }
679     }
680 }
681
682 #ifdef DVBPSI_USE_NIT
683 static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
684 {
685     vlc_object_t *p_obj = p_session->p_obj;
686
687     msg_Dbg( p_obj, "NITCallBack" );
688     msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
689              p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
690
691     /* */
692     if( p_session->p_nit && p_session->p_nit->b_current_next )
693     {
694         dvbpsi_DeleteNIT( p_session->p_nit );
695         p_session->p_nit = NULL;
696     }
697     if( p_session->p_nit )
698     {
699         dvbpsi_DeleteNIT( p_nit );
700         return;
701     }
702
703     /* */
704     p_session->p_nit = p_nit;
705
706     dvbpsi_descriptor_t *p_dsc;
707     for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
708     {
709         if( p_dsc->i_tag == 0x40 )
710         {
711             msg_Dbg( p_obj, "   * network name descriptor" );
712             char str1[257];
713
714             memcpy( str1, p_dsc->p_data, p_dsc->i_length );
715             str1[p_dsc->i_length] = '\0';
716             msg_Dbg( p_obj, "       * name %s", str1 );
717         }
718         else if( p_dsc->i_tag == 0x4a )
719         {
720             msg_Dbg( p_obj, "   * linkage descriptor" );
721             uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
722             uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
723             uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
724             int i_linkage_type = p_dsc->p_data[6];
725
726             msg_Dbg( p_obj, "       * ts_id %d", i_ts_id );
727             msg_Dbg( p_obj, "       * on_id %d", i_on_id );
728             msg_Dbg( p_obj, "       * service_id %d", i_service_id );
729             msg_Dbg( p_obj, "       * linkage_type %d", i_linkage_type );
730         }
731         else 
732         {
733             msg_Dbg( p_obj, "   * dsc 0x%x", p_dsc->i_tag );
734         }
735     }
736
737     dvbpsi_nit_ts_t *p_ts;
738     for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
739     {
740         msg_Dbg( p_obj, "   * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
741
742         uint32_t i_private_data_id = 0;
743         dvbpsi_descriptor_t *p_dsc;
744         for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
745         {
746             if( p_dsc->i_tag == 0x41 )
747             {
748                 msg_Dbg( p_obj, "       * service list descriptor" );
749                 for( int i = 0; i < p_dsc->i_length/3; i++ )
750                 {
751                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
752                     uint8_t  i_service_type = p_dsc->p_data[3*i+2];
753                     msg_Dbg( p_obj, "           * service_id=%d type=%d", i_service_id, i_service_type );
754                 }
755             }
756             else if( p_dsc->i_tag == 0x5a )
757             {
758                 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
759                 msg_Dbg( p_obj, "       * terrestrial delivery system" );
760                 msg_Dbg( p_obj, "           * centre_frequency 0x%x", p_t->i_centre_frequency  );
761                 msg_Dbg( p_obj, "           * bandwidth %d", 8 - p_t->i_bandwidth );
762                 msg_Dbg( p_obj, "           * constellation %d", p_t->i_constellation );
763                 msg_Dbg( p_obj, "           * hierarchy %d", p_t->i_hierarchy_information );
764                 msg_Dbg( p_obj, "           * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
765                 msg_Dbg( p_obj, "           * guard_interval %d", p_t->i_guard_interval );
766                 msg_Dbg( p_obj, "           * transmission_mode %d", p_t->i_transmission_mode );
767                 msg_Dbg( p_obj, "           * other_frequency_flag %d", p_t->i_other_frequency_flag );
768             }
769             else if( p_dsc->i_tag == 0x5f )
770             {
771                 msg_Dbg( p_obj, "       * private data specifier descriptor" );
772                 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
773                 msg_Dbg( p_obj, "           * value 0x%8.8x", i_private_data_id );
774             }
775             else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
776             {
777                 msg_Dbg( p_obj, "       * logical channel descriptor (EICTA)" );
778                 for( int i = 0; i < p_dsc->i_length/4; i++ )
779                 {
780                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
781                     int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
782                     msg_Dbg( p_obj, "           * service_id=%d channel_number=%d", i_service_id, i_channel_number );
783                 }
784
785             }
786             else
787             {
788                 msg_Warn( p_obj, "       * dsc 0x%x", p_dsc->i_tag );
789             }
790         }
791     }
792 }
793 #endif
794
795 static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t  i_table_id, uint16_t i_extension )
796 {
797     if( i_table_id == 0x42 )
798         dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
799 #ifdef DVBPSI_USE_NIT
800     else if( i_table_id == 0x40 )
801         dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
802 #endif
803 }
804
805 scan_session_t *scan_session_New( vlc_object_t *p_obj,
806                                   const scan_configuration_t *p_cfg )
807 {
808     scan_session_t *p_session = malloc( sizeof( *p_session ) );
809     if( unlikely(p_session == NULL) )
810         return NULL;
811     p_session->p_obj = p_obj;
812     p_session->cfg = *p_cfg;
813     p_session->i_snr = -1;
814     p_session->pat = NULL;
815     p_session->p_pat = NULL;
816     p_session->i_nit_pid = -1;
817     p_session->sdt = NULL;
818     p_session->p_sdt = NULL;
819 #ifdef DVBPSI_USE_NIT
820     p_session->nit = NULL;
821     p_session->p_nit = NULL;
822 #endif
823     return p_session;;
824 }
825
826 void scan_session_Destroy( scan_t *p_scan, scan_session_t *p_session )
827 {
828     const int i_service_start = p_scan->i_service;
829
830     dvbpsi_pat_t *p_pat = p_session->p_pat;
831     dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
832
833 #ifdef DVBPSI_USE_NIT
834     dvbpsi_nit_t *p_nit = p_session->p_nit;
835 #endif
836
837     if( p_pat )
838     {
839         /* Parse PAT */
840         dvbpsi_pat_program_t *p_program;
841         for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
842         {
843             if( p_program->i_number == 0 )  /* NIT */
844                 continue;
845
846             scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
847             TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
848         }
849     }
850     /* Parse SDT */
851     if( p_pat && p_sdt )
852     {
853         dvbpsi_sdt_service_t *p_srv;
854         for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
855         {
856             scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
857             dvbpsi_descriptor_t *p_dr;
858
859             if( s )
860                 s->b_crypted = p_srv->b_free_ca;
861
862             for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
863             {
864                 if( p_dr->i_tag == 0x48 )
865                 {
866                     dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
867
868                     if( s )
869                     {
870                         if( !s->psz_name )
871                             s->psz_name = vlc_from_EIT( pD->i_service_name,
872                                                    pD->i_service_name_length );
873
874                         if( s->type == SERVICE_UNKNOWN )
875                         {
876                             switch( pD->i_service_type )
877                             {
878                             case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
879                             case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
880                             case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
881                             case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
882                             }
883                         }
884                     }
885                 }
886             }
887         }
888     }
889
890 #ifdef DVBPSI_USE_NIT
891     /* Parse NIT */
892     if( p_pat && p_nit )
893     {
894         dvbpsi_nit_ts_t *p_ts;
895         for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
896         {
897             uint32_t i_private_data_id = 0;
898             dvbpsi_descriptor_t *p_dsc;
899
900             if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
901                 continue;
902
903             for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
904             {
905                 if( p_dsc->i_tag == 0x5f )
906                 {
907                     i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
908                 }
909                 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
910                 {
911                     for( int i = 0; i < p_dsc->i_length/4; i++ )
912                     {
913                         uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
914                         int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
915
916                         scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
917                         if( s && s->i_channel < 0 )
918                             s->i_channel = i_channel_number;
919                     }
920                 }
921             }
922         }
923     }
924 #endif
925
926     /* */
927     for( int i = i_service_start; i < p_scan->i_service; i++ )
928     {
929         scan_service_t *p_srv = p_scan->pp_service[i];
930
931         p_srv->i_snr = p_session->i_snr;
932         if( p_sdt )
933             p_srv->i_sdt_version = p_sdt->i_version;
934 #ifdef DVBPSI_USE_NIT
935         if( p_nit )
936         {
937             p_srv->i_network_id = p_nit->i_network_id;
938             p_srv->i_nit_version = p_nit->i_version;
939         }
940 #endif
941     }
942
943
944     /* */
945     if( p_session->pat )
946         dvbpsi_DetachPAT( p_session->pat );
947     if( p_session->p_pat )
948         dvbpsi_DeletePAT( p_session->p_pat );
949
950     if( p_session->sdt )
951         dvbpsi_DetachDemux( p_session->sdt );
952     if( p_session->p_sdt )
953         dvbpsi_DeleteSDT( p_session->p_sdt );
954 #ifdef DVBPSI_USE_NIT
955     if( p_session->nit )
956         dvbpsi_DetachDemux( p_session->nit );
957     if( p_session->p_nit )
958         dvbpsi_DeleteNIT( p_session->p_nit );
959 #endif
960     free( p_session );
961 }
962
963 static int ScanServiceCmp( const void *a, const void *b )
964 {
965     scan_service_t *sa = *(scan_service_t**)a;
966     scan_service_t *sb = *(scan_service_t**)b;
967
968     if( sa->i_channel == sb->i_channel )
969     {
970         if( sa->psz_name && sb->psz_name )
971             return strcmp( sa->psz_name, sb->psz_name );
972         return 0;
973     }
974     if( sa->i_channel == -1 )
975         return 1;
976     else if( sb->i_channel == -1 )
977         return -1;
978
979     if( sa->i_channel < sb->i_channel )
980         return -1;
981     else if( sa->i_channel > sb->i_channel )
982         return 1;
983     return 0;
984 }
985
986 static block_t *BlockString( const char *psz )
987 {
988     block_t *p = block_Alloc( strlen(psz) );
989     if( p )
990         memcpy( p->p_buffer, psz, p->i_buffer );
991     return p;
992 }
993
994 block_t *scan_GetM3U( scan_t *p_scan )
995 {
996     vlc_object_t *p_obj = p_scan->p_obj;
997     block_t *p_playlist = NULL;
998
999     if( p_scan->i_service <= 0 )
1000         return NULL;
1001
1002     /* */
1003     qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
1004
1005     /* */
1006     p_playlist = BlockString( "#EXTM3U\n\n" );/* */
1007
1008     for( int i = 0; i < p_scan->i_service; i++ )
1009     {
1010         scan_service_t *s = p_scan->pp_service[i];
1011
1012         if( s->type == SERVICE_UNKNOWN )
1013         {
1014             /* We should only select service that have been described by SDT */
1015             msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
1016             continue;
1017         }
1018
1019         const char *psz_type;
1020         switch( s->type )
1021         {
1022         case SERVICE_DIGITAL_TELEVISION:       psz_type = "Digital television"; break;
1023         case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
1024         case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
1025         case SERVICE_DIGITAL_RADIO:            psz_type = "Digital radio"; break;
1026         default:
1027             psz_type = "Unknown";
1028             break;
1029         }
1030         msg_Warn( p_obj, "scan_GetM3U: service number %d type '%s' name '%s' channel %d cypted=%d| network_id %d (nit:%d sdt:%d)| f=%d bw=%d snr=%d modulation=%d",
1031                   s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
1032                   s->i_network_id, s->i_nit_version, s->i_sdt_version,
1033                   s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr, s->cfg.i_modulation );
1034
1035         if( !s->cfg.i_fec )
1036             s->cfg.i_fec = 9;   /* FEC_AUTO */
1037
1038         char *psz;
1039         if( asprintf( &psz, "#EXTINF:,,%s\n"
1040                         "#EXTVLCOPT:program=%d\n"
1041                         "dvb://frequency=%d:bandwidth=%d:voltage=%d:fec=%d:modulation=%d\n"
1042                         "\n",
1043                       s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
1044                       s->i_program,
1045                       s->cfg.i_frequency,
1046                       s->cfg.i_bandwidth,
1047                       s->cfg.c_polarization == 'H' ? 18 : 13,
1048                       s->cfg.i_fec,
1049                       s->cfg.i_modulation ) < 0 )
1050             psz = NULL;
1051         if( psz )
1052         {
1053             block_t *p_block = BlockString( psz );
1054             if( p_block )
1055                 block_ChainAppend( &p_playlist, p_block );
1056         }
1057     }
1058
1059     return p_playlist ? block_ChainGather( p_playlist ) : NULL;
1060 }
1061
1062 bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
1063 {
1064     if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
1065     {
1066         block_Release( p_block );
1067         return false;
1068     }
1069
1070     /* */
1071     const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
1072     if( i_pid == 0x00 )
1073     {
1074         if( !p_scan->pat )
1075             p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
1076
1077         if( p_scan->pat )
1078             dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
1079     }
1080     else if( i_pid == 0x11 )
1081     {
1082         if( !p_scan->sdt )
1083             p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1084
1085         if( p_scan->sdt )
1086             dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
1087     }
1088     else if( i_pid == p_scan->i_nit_pid )
1089     {
1090 #ifdef DVBPSI_USE_NIT
1091         if( !p_scan->nit )
1092             p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
1093
1094         if( p_scan->nit )
1095             dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
1096 #endif
1097     }
1098
1099     block_Release( p_block );
1100
1101     return p_scan->p_pat && p_scan->p_sdt && 
1102 #ifdef DVBPSI_USE_NIT
1103         p_scan->p_nit;
1104 #else
1105         true;
1106 #endif
1107 }
1108
1109 void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
1110 {
1111     p_session->i_snr = i_snr;
1112 }
1113