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