input.c 23.4 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3 4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5 6
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
7
 * $Id: input.c,v 1.91 2001/03/07 10:31:10 stef Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29 30
#include "defs.h"

31 32 33 34 35 36 37
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
38

Henri Fallon's avatar
 
Henri Fallon committed
39 40
/* Network functions */

Sam Hocevar's avatar
 
Sam Hocevar committed
41
#ifndef SYS_BEOS
Henri Fallon's avatar
 
Henri Fallon committed
42 43 44 45 46 47
#include <netdb.h>                                             /* hostent ... */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
48
#endif
Henri Fallon's avatar
 
Henri Fallon committed
49

50 51 52 53
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
54
#include "config.h"
55 56
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
57
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
58
#include "modules.h"
59

60
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
61
#include "intf_plst.h"
62

63 64 65
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
66

67
#include "input.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
68 69 70
#include "interface.h"

#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
71

72
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
73
 * Local prototypes
74
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
75 76 77 78 79
static void RunThread       ( input_thread_t *p_input );
static  int InitThread      ( input_thread_t *p_input );
static void ErrorThread     ( input_thread_t *p_input );
static void DestroyThread   ( input_thread_t *p_input );
static void EndThread       ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
80

81
/*****************************************************************************
82
 * input_CreateThread: creates a new input thread
83
 *****************************************************************************
84 85 86 87
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, it will be updated using one of the THREAD_* constants.
88
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
89
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
90
{
91 92 93
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

94 95 96
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
97
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
98 99
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
100 101
        return( NULL );
    }
102

103 104 105
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

106 107 108
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
109 110 111 112 113
    p_input->b_eof              = 0;

    /* Set target */
    p_input->p_source           = p_item->psz_name;

114
    /* I have never understood that stuff --Meuuh */
115 116
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
117

118
    /* Initialize stream description */
119 120
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
121
    p_input->stream.i_pgrm_number = 0;
122
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
123
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
124

Stéphane Borel's avatar
 
Stéphane Borel committed
125 126 127 128
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
129 130
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
    p_input->stream.p_selected_area->i_seek = NO_SEEK;
Stéphane Borel's avatar
 
Stéphane Borel committed
131

132 133 134 135 136
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
137

Sam Hocevar's avatar
 
Sam Hocevar committed
138 139
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout = p_main->p_aout;
Sam Hocevar's avatar
 
Sam Hocevar committed
140
    p_input->p_default_vout = p_main->p_vout;
Sam Hocevar's avatar
 
Sam Hocevar committed
141

Michel Kaempf's avatar
Michel Kaempf committed
142
    /* Create thread and set locks. */
143
    vlc_mutex_init( &p_input->stream.stream_lock );
144
    vlc_cond_init( &p_input->stream.stream_wait );
145 146 147
    vlc_mutex_init( &p_input->stream.control.control_lock );
    if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
                           (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
148
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
149 150
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
151 152 153
        free( p_input );
        return( NULL );
    }
154

155 156 157 158
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
159
        {
160
            msleep( THREAD_SLEEP );
161
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Sam Hocevar's avatar
 
Sam Hocevar committed
162
                && (i_status != THREAD_FATAL) );
163 164
        if( i_status != THREAD_READY )
        {
165 166
            return( NULL );
        }
167
    }
Michel Kaempf's avatar
Michel Kaempf committed
168 169 170
    return( p_input );
}

171
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
172
 * input_DestroyThread: mark an input thread as zombie
173
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
174
 * This function should not return until the thread is effectively cancelled.
175
 *****************************************************************************/
176
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
177
{
178
    int         i_status;                                   /* thread status */
179 180 181

    /* Set status */
    p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
182 183
    *p_input->pi_status = THREAD_DESTROY;

184 185
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
186

187 188 189 190 191
    /* Make the thread exit of an eventual vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

192 193 194 195 196 197
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
198 199
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
200
    }
Michel Kaempf's avatar
Michel Kaempf committed
201 202
}

203
/*****************************************************************************
204
 * RunThread: main thread loop
205
 *****************************************************************************
206
 * Thread in charge of processing the network packets and demultiplexing.
207
 *****************************************************************************/
208
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
209
{
210
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
211

Sam Hocevar's avatar
 
Sam Hocevar committed
212 213 214 215 216 217 218 219 220 221
    if( InitThread( p_input ) )
    {

        /* If we failed, wait before we are killed, and exit */
        *p_input->pi_status = THREAD_ERROR;
        p_input->b_error = 1;
        ErrorThread( p_input );
        DestroyThread( p_input );
        return;
    }
Michel Kaempf's avatar
Michel Kaempf committed
222

Sam Hocevar's avatar
 
Sam Hocevar committed
223
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
224
    {
225
        data_packet_t *         pp_packets[p_input->i_read_once];
226

Sam Hocevar's avatar
 
Sam Hocevar committed
227
#ifdef STATS
Sam Hocevar's avatar
 
Sam Hocevar committed
228
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
229 230
#endif

231
        vlc_mutex_lock( &p_input->stream.stream_lock );
232
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
233
        {
234 235
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
236 237
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
238 239 240 241 242 243 244 245 246 247 248 249 250

                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];
                    /* Escape all decoders for the stream discontinuity they
                     * will encounter. */
                    input_EscapeDiscontinuity( p_input, p_pgrm );

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
251
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
252
        }
253
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
254 255

        i_error = p_input->pf_read( p_input, pp_packets );
Sam Hocevar's avatar
 
Sam Hocevar committed
256

Sam Hocevar's avatar
 
Sam Hocevar committed
257
        /* Demultiplex read packets. */
258
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
259 260 261
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
262

Sam Hocevar's avatar
 
Sam Hocevar committed
263 264 265
        if( i_error )
        {
            if( i_error == 1 )
266
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
267 268 269 270
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
                intf_WarnMsg( 1, "End of file reached" );
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
271
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
272
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
273
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
274
                p_input->b_error = 1;
275
            }
276 277 278
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
279
    if( p_input->b_error || p_input->b_eof )
280 281 282
    {
        ErrorThread( p_input );
    }
283

284
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
285 286 287

    DestroyThread( p_input );

288
    intf_DbgMsg("Thread end");
289 290
}

291
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
292
 * InitThread: init the input Thread
293
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
294
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
295 296 297
{

#ifdef STATS
298 299 300 301 302 303
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->c_bytes                    = 0;
    p_input->c_payload_bytes            = 0;
    p_input->c_packets_read             = 0;
    p_input->c_packets_trashed          = 0;
Michel Kaempf's avatar
Michel Kaempf committed
304
#endif
305

Sam Hocevar's avatar
 
Sam Hocevar committed
306
    p_input->p_input_module = module_Need( p_main->p_bank,
Sam Hocevar's avatar
 
Sam Hocevar committed
307 308
                                           MODULE_CAPABILITY_INPUT,
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
309 310

    if( p_input->p_input_module == NULL )
311
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
312
        intf_ErrMsg( "input error: no suitable input module" );
Sam Hocevar's avatar
 
Sam Hocevar committed
313
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
314
    }
315

Sam Hocevar's avatar
 
Sam Hocevar committed
316 317 318 319 320 321
#define f p_input->p_input_module->p_functions->input.functions.input
    p_input->pf_init          = f.pf_init;
    p_input->pf_open          = f.pf_open;
    p_input->pf_close         = f.pf_close;
    p_input->pf_end           = f.pf_end;
    p_input->pf_read          = f.pf_read;
322
    p_input->pf_set_area      = f.pf_set_area;
Sam Hocevar's avatar
 
Sam Hocevar committed
323 324 325 326 327 328 329 330 331
    p_input->pf_demux         = f.pf_demux;
    p_input->pf_new_packet    = f.pf_new_packet;
    p_input->pf_new_pes       = f.pf_new_pes;
    p_input->pf_delete_packet = f.pf_delete_packet;
    p_input->pf_delete_pes    = f.pf_delete_pes;
    p_input->pf_rewind        = f.pf_rewind;
    p_input->pf_seek          = f.pf_seek;
#undef f
    p_input->pf_open( p_input );
332

Sam Hocevar's avatar
 
Sam Hocevar committed
333
    if( p_input->b_error )
334
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
335 336
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
337
        module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
338
        return( -1 );
339
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
340 341

    p_input->pf_init( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
342

Sam Hocevar's avatar
 
Sam Hocevar committed
343
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
344 345

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
346 347
}

348
/*****************************************************************************
349
 * ErrorThread: RunThread() error loop
350
 *****************************************************************************
351
 * This function is called when an error occured during thread main's loop.
352
 *****************************************************************************/
353
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
354
{
355
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
356
    {
357 358
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
359 360 361
    }
}

362
/*****************************************************************************
363
 * EndThread: end the input thread
364
 *****************************************************************************/
365
static void EndThread( input_thread_t * p_input )
366
{
367
    int *       pi_status;                                  /* thread status */
368

369 370 371
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
372

Sam Hocevar's avatar
 
Sam Hocevar committed
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("input stats: cpu usage (user: %d, system: %d)",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }
#endif

    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

    /* Free demultiplexer's data */
    p_input->pf_end( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
389 390 391
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
392
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
393
    module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
394

Sam Hocevar's avatar
 
Sam Hocevar committed
395 396 397 398 399 400 401 402 403 404 405
}

/*****************************************************************************
 * DestroyThread: destroy the input thread
 *****************************************************************************/
static void DestroyThread( input_thread_t * p_input )
{
    int *       pi_status;                                  /* thread status */

    /* Store status */
    pi_status = p_input->pi_status;
Sam Hocevar's avatar
 
Sam Hocevar committed
406

Henri Fallon's avatar
 
Henri Fallon committed
407 408
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
409
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
410
    
411
    /* Free input structure */
412
    free( p_input );
413

414 415
    /* Update status */
    *pi_status = THREAD_OVER;
416
}
417

418
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
419
 * input_FileOpen : open a file descriptor
420
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
421
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
422
{
423
    struct stat         stat_info;
Sam Hocevar's avatar
 
Sam Hocevar committed
424 425 426
    int                 i_stat;

    char *psz_name = p_input->p_source;
Michel Kaempf's avatar
Michel Kaempf committed
427

Sam Hocevar's avatar
 
Sam Hocevar committed
428 429 430
    /* FIXME: this code ought to be in the plugin so that code can
     * be shared with the *_Probe function */
    if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
431
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
432 433 434 435 436 437 438 439
        int i_size = strlen( psz_name );

        if( ( i_size > 4 )
            && !strncasecmp( psz_name, "dvd:", 4 ) )
        {
            /* get rid of the 'dvd:' stuff and try again */
            psz_name += 4;
            i_stat = stat( psz_name, &stat_info );
Henri Fallon's avatar
 
Henri Fallon committed
440
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
441
        else if( ( i_size > 5 )
Sam Hocevar's avatar
 
Sam Hocevar committed
442 443 444 445 446
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
Henri Fallon's avatar
 
Henri Fallon committed
447
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
448

Sam Hocevar's avatar
 
Sam Hocevar committed
449
        if( i_stat == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
450 451 452 453 454 455
        {
            intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
                         psz_name, strerror(errno));
            p_input->b_error = 1;
            return;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
456 457 458 459 460 461 462 463 464 465 466
    }

    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* If we are here we can control the pace... */
    p_input->stream.b_pace_control = 1;

    if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
         || S_ISBLK(stat_info.st_mode) )
    {
        p_input->stream.b_seekable = 1;
467
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
Sam Hocevar's avatar
 
Sam Hocevar committed
468
    }
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
469 470 471 472 473
    else if( S_ISFIFO(stat_info.st_mode)
#ifndef SYS_BEOS
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
474
    {
475
        p_input->stream.b_seekable = 0;
476
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
 
Benoit Steiner committed
477 478 479
    }
    else
    {
480
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
481
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
 
Sam Hocevar committed
482
                     psz_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
483 484 485
        p_input->b_error = 1;
        return;
    }
486

487
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
488 489
    vlc_mutex_unlock( &p_input->stream.stream_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
490 491
    intf_Msg( "input: opening %s", p_input->p_source );
    if( (p_input->i_handle = open( psz_name,
Sam Hocevar's avatar
 
Sam Hocevar committed
492 493
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
494
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
 
Sam Hocevar committed
495 496
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
497 498 499
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
500 501

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
502
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
503
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
504
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
505
{
Sam Hocevar's avatar
 
Sam Hocevar committed
506
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
507

Sam Hocevar's avatar
 
Sam Hocevar committed
508
    return;
Stéphane Borel's avatar
Stéphane Borel committed
509
}
Sam Hocevar's avatar
 
Sam Hocevar committed
510

Sam Hocevar's avatar
 
Sam Hocevar committed
511
#ifndef SYS_BEOS
Henri Fallon's avatar
 
Henri Fallon committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
/*****************************************************************************
 * input_BuildLocalAddr : fill a sockaddr_in structure for local binding
 *****************************************************************************/
int input_BuildLocalAddr( struct sockaddr_in * p_socket, int i_port, 
                      boolean_t b_broadcast )
{
    char                psz_hostname[INPUT_MAX_SOURCE_LENGTH];
    struct hostent    * p_hostent;
    
    /* Reset struct */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
    p_socket->sin_family = AF_INET;                                 /* family */
    p_socket->sin_port = htons( i_port );
    
    if( !b_broadcast )
    {
        /* Try to get our own IP */
        if( gethostname( psz_hostname, sizeof(psz_hostname) ) )
        {
            intf_ErrMsg( "BuildLocalAddr : unable to resolve local name : %s",
                         strerror( errno ) );
            return( -1 );
        }

    }
    else
    {
        /* Using broadcast address. There are many ways of doing it, one of
         * the simpliest being a #define ...
         * FIXME : this is ugly */ 
        strncpy( psz_hostname, INPUT_BCAST_ADDR,INPUT_MAX_SOURCE_LENGTH );
    }

    /* Try to convert address directly from in_addr - this will work if
     * psz_in_addr is dotted decimal. */

#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( psz_hostname, &p_socket->sin_addr) )
#else
    if( (p_socket->sin_addr.s_addr = inet_addr( psz_hostname )) == -1 )
#endif
    {
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname( psz_hostname )) == NULL )
        {
            intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_hostname );
            return( -1 );
        }
        
        /* Copy the first address of the host in the socket address */
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0], 
                 p_hostent->h_length );
    }

    return( 0 );
}

/*****************************************************************************
 * input_BuildRemoteAddr : fill a sockaddr_in structure for remote host
 *****************************************************************************/
int input_BuildRemoteAddr( input_thread_t * p_input, 
                           struct sockaddr_in * p_socket )
{
    struct hostent            * p_hostent;

    /* Reset structure */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
    p_socket->sin_family = AF_INET;                                 /* family */
    p_socket->sin_port = htons( 0 );                /* This is for remote end */
    
    /* Get the remote server */
    if( p_input->p_source == NULL )
    {
        p_input->p_source = main_GetPszVariable( INPUT_SERVER_VAR, 
                                                 INPUT_SERVER_DEFAULT );
    }

     /* Try to convert address directly from in_addr - this will work if
      * psz_in_addr is dotted decimal. */
#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( p_input->p_source, &p_socket->sin_addr) )
#else
    if( (p_socket->sin_addr.s_addr = inet_addr( p_input->p_source )) == -1 )
#endif
    {
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname(p_input->p_source)) == NULL )
        {
            intf_ErrMsg( "BuildRemoteAddr: unknown host %s", 
                         p_input->p_source );
            return( -1 );
        }
        
        /* Copy the first address of the host in the socket address */
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0], 
                 p_hostent->h_length );
    }

    return( 0 );
}

/*****************************************************************************
 * input_NetworkOpen : open a network socket 
 *****************************************************************************/
void input_NetworkOpen( input_thread_t * p_input )
{
 
    int                 i_option_value, i_port;
    struct sockaddr_in  s_socket;
    boolean_t           b_broadcast;
    
    /* FIXME : we don't handle channels for the moment */

    /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
     * protocol */
    p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
    if( p_input->i_handle == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't create socket : %s", strerror(errno));
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
    i_option_value = 1;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
                    &i_option_value,sizeof( i_option_value ) ) == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't configure socket (SO_REUSEADDR: %s)",
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

#ifndef SYS_BEOS
    /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
     * packet loss caused by scheduling problems */
    i_option_value = 524288;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF, &i_option_value,
                    sizeof( i_option_value ) ) == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't configure socket (SO_RCVBUF: %s)", 
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
#endif /* SYS_BEOS */

    /* Get details about what we are supposed to do */
    b_broadcast = (boolean_t)main_GetIntVariable( INPUT_BROADCAST_VAR, 0 );
    i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );

    /* TODO : here deal with channel stufs */

    /* Build the local socket */
    if ( input_BuildLocalAddr( &s_socket, i_port, b_broadcast ) 
         == -1 )
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
    if( bind( p_input->i_handle, (struct sockaddr *)&s_socket, 
              sizeof( s_socket ) ) < 0 )
    {
        intf_ErrMsg("NetworkOpen: can't bind socket (%s)", strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
    if ( input_BuildRemoteAddr( p_input, &s_socket ) 
         == -1 )
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* And connect it ... should we really connect ? */
    if( connect( p_input->i_handle, (struct sockaddr *) &s_socket,
                 sizeof( s_socket ) ) == (-1) )
    {
        intf_ErrMsg("NetworkOpen: can't connect socket" );
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR
     * with the server. */
    p_input->stream.b_pace_control = 1;
    
    return;
}

/*****************************************************************************
 * input_NetworkClose : close a network socket
 *****************************************************************************/
void input_NetworkClose( input_thread_t * p_input )
{
    close( p_input->i_handle );
    /* FIXME: deal with channels */
}
Sam Hocevar's avatar
 
Sam Hocevar committed
721
#endif