input_manager.cpp 17.9 KB
Newer Older
zorglub's avatar
zorglub committed
1
2
3
/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
4
 * Copyright (C) 2006-2008 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Ilkka Ollakka  <ileoo@videolan.org>
9
 *          Jean-Baptiste <jb@videolan.org>
zorglub's avatar
zorglub committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
25
26
27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
zorglub's avatar
zorglub committed
28

zorglub's avatar
zorglub committed
29
#include "qt4.hpp"
zorglub's avatar
zorglub committed
30
31
32
#include "input_manager.hpp"
#include "dialogs_provider.hpp"

33
34
35
36
static int ChangeVideo( vlc_object_t *p_this, const char *var, vlc_value_t o,
                        vlc_value_t n, void *param );
static int ChangeAudio( vlc_object_t *p_this, const char *var, vlc_value_t o,
                        vlc_value_t n, void *param );
37
38
static int ItemChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
39
static int PLItemChanged( vlc_object_t *, const char *,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
40
                        vlc_value_t, vlc_value_t, void * );
41
42
43
44
45
46
47
48
static int InterfaceChanged( vlc_object_t *, const char *,
                            vlc_value_t, vlc_value_t, void * );
static int ItemStateChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
static int ItemRateChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
static int ItemTitleChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
49
50
static int VolumeChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
51

52
53
/**********************************************************************
 * InputManager implementation
54
55
56
 **********************************************************************
 * The Input Manager can be the main one around the playlist
 * But can also be used for VLM dialog or similar
57
58
 **********************************************************************/

zorglub's avatar
zorglub committed
59
60
61
InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) :
                           QObject( parent ), p_intf( _p_intf )
{
62
    i_old_playing_status = END_S;
63
    old_name = "";
zorglub's avatar
zorglub committed
64
    p_input = NULL;
65
    i_rate = 0;
zorglub's avatar
zorglub committed
66
67
68
69
}

InputManager::~InputManager()
{
70
    delInput();
zorglub's avatar
zorglub committed
71
72
}

73
74
75
/* Define the Input used.
   Add the callbacks on input
   p_input is yield once here */
zorglub's avatar
zorglub committed
76
77
void InputManager::setInput( input_thread_t *_p_input )
{
78
    delInput();
zorglub's avatar
zorglub committed
79
    p_input = _p_input;
80
81
82
    b_had_audio = b_had_video = b_has_audio = b_has_video = false;
    if( p_input )
    {
83
        vlc_object_yield( p_input );
84
85
        emit statusChanged( PLAYING_S );
        addCallbacks();
86
87
    }
}
88

89
90
91
/* delete Input if it ever existed.
   Delete the callbacls on input
   p_input is released once here */
92
93
94
95
void InputManager::delInput()
{
    if( p_input )
    {
96
        delCallbacks();
97
        vlc_object_release( p_input );
98
99
100
101
102
103
104
105
        i_old_playing_status = END_S;

        old_name=qfu("");
        artUrl = qfu("");
        emit positionUpdated( 0.0, 0 ,0 );
        emit statusChanged( END_S );
        emit nameChanged( "" );
        emit artChanged( "" );
106
        p_input = NULL;
107
    }
zorglub's avatar
zorglub committed
108
109
}

110
/* Add the callbacks on Input. Self explanatory */
111
void InputManager::addCallbacks()
112
{
113
114
115
116
117
118
119
120
121
    /* We don't care about:
       - spu-es
       - chapter
       - programs
       - audio-delay
       - spu-delay
       - bookmark
       - position, time, length, because they are included in intf-change
     */
122
123
    /* src/input/input.c:1629 */
    var_AddCallback( p_input, "state", ItemStateChanged, this );
124
    /* src/input/es-out.c:550 */
125
    var_AddCallback( p_input, "audio-es", ChangeAudio, this );
126
    /* src/input/es-out.c:551 */
127
128
129
130
131
132
133
134
135
    var_AddCallback( p_input, "video-es", ChangeVideo, this );
    /* src/input/input.c:1765 */
    var_AddCallback( p_input, "rate", ItemRateChanged, this );
    /* src/input/input.c:2003 */
    var_AddCallback( p_input, "title", ItemTitleChanged, this );
    /* src/input/input.c:734 for timers update*/
    var_AddCallback( p_input, "intf-change", InterfaceChanged, this );
}

136
/* Delete the callbacks on Input. Self explanatory */
137
void InputManager::delCallbacks()
138
{
139
140
141
142
143
144
    var_DelCallback( p_input, "audio-es", ChangeAudio, this );
    var_DelCallback( p_input, "video-es", ChangeVideo, this );
    var_DelCallback( p_input, "state", ItemStateChanged, this );
    var_DelCallback( p_input, "rate", ItemRateChanged, this );
    var_DelCallback( p_input, "title", ItemTitleChanged, this );
    var_DelCallback( p_input, "intf-change", InterfaceChanged, this );
145
146
}

147
/* Convert the event from the callbacks in actions */
148
149
150
void InputManager::customEvent( QEvent *event )
{
    int type = event->type();
151
152
153
154
    if ( type != PositionUpdate_Type &&
         type != ItemChanged_Type &&
         type != ItemRateChanged_Type &&
         type != ItemTitleChanged_Type &&
155
156
157
         type != ItemStateChanged_Type )
        return;

158
    /* Delete the input */
159
    if( !p_input || p_input->b_dead || p_input->b_die )
160
    {
161
162
         delInput();
         return;
163
164
    }

165
    /* Actions */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
166
    switch( type )
167
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
168
    case PositionUpdate_Type:
169
        UpdatePosition();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
170
171
        break;
    case ItemChanged_Type:
172
        UpdateMeta();
173
        UpdateTitle();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
174
175
176
177
178
179
180
181
        break;
    case ItemRateChanged_Type:
        UpdateRate();
        break;
    case ItemTitleChanged_Type:
        UpdateTitle();
        break;
    case ItemStateChanged_Type:
182
       UpdateStatus();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
183
       break;
184
    }
185
}
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
void InputManager::UpdatePosition( void )
{
     /* Update position */
     int i_length, i_time; /* Int is enough, since we store seconds */
     float f_pos;
     i_length = var_GetTime(  p_input , "length" ) / 1000000;
     i_time = var_GetTime(  p_input , "time") / 1000000;
     f_pos = var_GetFloat(  p_input , "position" );
     emit positionUpdated( f_pos, i_time, i_length );
}

void InputManager::UpdateTitle( void )
{
     /* Update navigation status */
     vlc_value_t val; val.i_int = 0;
     var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
203
     msg_Dbg( p_intf, "updateTitle called" );
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
     if( val.i_int > 0 )
     {
         val.i_int = 0;
         var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
         emit navigationChanged( (val.i_int > 0) ? 1 : 2 );
     }
     else
     {
         emit navigationChanged( 0 );
     }
}

void InputManager::UpdateStatus( void )
{
     /* Update playing status */
     vlc_value_t val; val.i_int = 0;
     var_Get( p_input, "state", &val );
     if( i_old_playing_status != val.i_int )
     {
         i_old_playing_status = val.i_int;
         emit statusChanged( val.i_int );
     }
}

void InputManager::UpdateRate( void )
{
     /* Update Rate */
     int i_new_rate = var_GetInteger( p_input, "rate");
     if( i_new_rate != i_rate )
     {
         i_rate = i_new_rate;
         /* Update rate */
         emit rateChanged( i_rate );
237
     }
238
239
240
241
}

void InputManager::UpdateMeta( void )
{
242
243
    /* Update text, name and nowplaying */
    QString text;
244

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
    char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
    if( EMPTY_STR( psz_name ) )
    {
        free( psz_name );
        psz_name = input_item_GetName( input_GetItem( p_input ) );
    }

    char *psz_nowplaying =
        input_item_GetNowPlaying( input_GetItem( p_input ) );
    if( !EMPTY_STR( psz_nowplaying ) )
    {
        text.sprintf( "%s - %s", psz_nowplaying, psz_name );
    }
    else
    {
        char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
        if( !EMPTY_STR( psz_artist ) )
        {
            text.sprintf( "%s - %s", psz_artist, psz_name );
        }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
265
266
267
        else
        {
            text.sprintf( "%s", psz_name );
268
269
        }
        free( psz_artist );
270
271
272
273
274
275
276
277
278
279
    }
    free( psz_name );
    free( psz_nowplaying );

    if( old_name != text )
    {
        emit nameChanged( text );
        old_name=text;
    }

280
    /* Update Art meta */
281
282
283
284
285
286
287
288
289
290
    QString url;
    char *psz_art = input_item_GetArtURL( input_GetItem( p_input ) );
    url.sprintf("%s", psz_art );
    free( psz_art );
    if( artUrl != url )
    {
        artUrl = url.replace( "file://",QString("" ) );
        emit artChanged( artUrl );
    }

291
292
293
294
295
296
297
    /* Has Audio, has Video Tracks ? */
    vlc_value_t val;
    var_Change( p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
    b_has_audio = val.i_int > 0;
    var_Change( p_input, "video-es", VLC_VAR_CHOICESCOUNT, &val, NULL );
    b_has_video = val.i_int > 0;

298
    /* Update ZVBI status */
299
#ifdef ZVBI_COMPILED
300
301
    /* Update teletext status*/
    emit teletextEnabled( true );/* FIXME */
302
303
304
#endif
}

305
/* User update of the slider */
zorglub's avatar
zorglub committed
306
307
void InputManager::sliderUpdate( float new_pos )
{
308
309
    if( hasInput() )
        var_SetFloat( p_input, "position", new_pos );
zorglub's avatar
zorglub committed
310
}
311

312
/* User togglePlayPause */
313
314
315
316
void InputManager::togglePlayPause()
{
    vlc_value_t state;
    var_Get( p_input, "state", &state );
317
    state.i_int = ( state.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S;
318
319
320
321
    var_Set( p_input, "state", state );
    emit statusChanged( state.i_int );
}

322
323
324
325
void InputManager::sectionPrev()
{
    if( hasInput() )
    {
326
        int i_type = var_Type( p_input, "next-chapter" );
327
328
329
330
331
332
333
334
335
336
        vlc_value_t val; val.b_bool = VLC_TRUE;
        var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
                            "prev-chapter":"prev-title", val );
    }
}

void InputManager::sectionNext()
{
    if( hasInput() )
    {
337
        int i_type = var_Type( p_input, "next-chapter" );
338
339
340
341
342
343
344
345
346
        vlc_value_t val; val.b_bool = VLC_TRUE;
        var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ?
                            "next-chapter":"next-title", val );
    }
}

void InputManager::sectionMenu()
{
    if( hasInput() )
347
        var_SetInteger( p_input, "title 0", 2 );
348
349
}

350
#ifdef ZVBI_COMPILED
351
352
void InputManager::telexGotoPage( int page )
{
353
    if( hasInput() )
354
355
356
357
358
359
360
361
362
363
    {
        vlc_object_t *p_vbi;
        p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
                    "zvbi", FIND_ANYWHERE );
        if( p_vbi )
        {
            var_SetInteger( p_vbi, "vbi-page", page );
            vlc_object_release( p_vbi );
        }
    }
364
365
366
367
}

void InputManager::telexToggle( bool b_enabled )
{
Jean-Paul Saman's avatar
Jean-Paul Saman committed
368
369
370
371
372
    int i_page = 0;

    if( b_enabled )
        i_page = 100;
    telexGotoPage( i_page );
373
374
375
376
}

void InputManager::telexSetTransparency( bool b_transp )
{
377
    if( hasInput() )
378
379
380
381
382
383
384
385
386
387
    {
        vlc_object_t *p_vbi;
        p_vbi = (vlc_object_t *) vlc_object_find_name( p_input,
                    "zvbi", FIND_ANYWHERE );
        if( p_vbi )
        {
            var_SetBool( p_input->p_libvlc, "vbi-opaque", b_transp );
            vlc_object_release( p_vbi );
        }
    }
388
}
389
#endif
390

zorglub's avatar
zorglub committed
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
void InputManager::slower()
{
    if( hasInput() )
        var_SetVoid( p_input, "rate-slower" );
}

void InputManager::faster()
{
    if( hasInput() )
        var_SetVoid( p_input, "rate-faster" );
}

void InputManager::normalRate()
{
    if( hasInput() )
        var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT );
}

409
410
411
412
413
414
void InputManager::setRate( int new_rate )
{
    if( hasInput() )
        var_SetInteger( p_input, "rate", new_rate );
}

415
416
/**********************************************************************
 * MainInputManager implementation. Wrap an input manager and
417
418
 * take care of updating the main playlist input.
 * Used in the main playlist Dialog
419
420
421
 **********************************************************************/
MainInputManager * MainInputManager::instance = NULL;

422
423
MainInputManager::MainInputManager( intf_thread_t *_p_intf )
                 : QObject(NULL), p_intf( _p_intf )
424
425
426
{
    p_input = NULL;
    im = new InputManager( this, p_intf );
427

428
429
430
    var_AddCallback( THEPL, "item-change", PLItemChanged, this );
    var_AddCallback( THEPL, "playlist-current", PLItemChanged, this );
    var_AddCallback( THEPL, "activity", PLItemChanged, this );
431

432
433
    var_AddCallback( THEPL, "playlist-current", ItemChanged, im );

434
    var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
435

436
437
438
    // No necessary, I think TODO REMOVE ME at the end
    //var_AddCallback( THEPL, "intf-change", ItemChanged, im );

439
    /* Warn our embedded IM about input changes */
zorglub's avatar
zorglub committed
440
    CONNECT( this, inputChanged( input_thread_t * ),
441
             im, setInput( input_thread_t * ) );
442
443
}

zorglub's avatar
zorglub committed
444
445
MainInputManager::~MainInputManager()
{
446
447
    if( p_input )
    {
448
449
       emit inputChanged( NULL );
    }
450

451
    var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this );
452
453
454
455
456

    var_DelCallback( THEPL, "playlist-current", PLItemChanged, this );
    var_DelCallback( THEPL, "activity", PLItemChanged, this );
    var_DelCallback( THEPL, "item-change", PLItemChanged, this );

457
    var_DelCallback( THEPL, "playlist-current", ItemChanged, im );
zorglub's avatar
zorglub committed
458
459
}

460
void MainInputManager::customEvent( QEvent *event )
461
{
462
    int type = event->type();
463
464
465
466
467
468
    if ( type != ItemChanged_Type && type != VolumeChanged_Type )
        return;

    if( type == VolumeChanged_Type )
    {
        emit volumeChanged();
469
        return;
470
    }
471

472
    /* Should be PLItemChanged Event */
473
    if( VLC_OBJECT_INTF == p_intf->i_object_type )
474
    {
475
        vlc_mutex_lock( &p_intf->change_lock );
476
        if( p_input && ( p_input->b_dead || p_input->b_die ) )
477
        {
478
            im->delInput();
479
            emit inputChanged( NULL );
480
            p_input = NULL;
481
        }
482

483
484
485
486
        if( !p_input )
        {
            QPL_LOCK;
            p_input = THEPL->p_input;
487
            if( p_input && !( p_input->b_die || p_input->b_dead) )
488
489
490
            {
                emit inputChanged( p_input );
            }
491
492
            else
                p_input = NULL;
493
494
495
496
            QPL_UNLOCK;
        }
        vlc_mutex_unlock( &p_intf->change_lock );
    }
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
497
498
    else
    {
499
        /* we are working as a dialogs provider */
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
500
501
        playlist_t *p_playlist = (playlist_t *) vlc_object_find( p_intf,
                                       VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
502
        if( p_playlist )
503
        {
504
            p_input = p_playlist->p_input;
505
506
507
508
            emit inputChanged( p_input );
        }
    }
}
509

510
/* Playlist Control functions */
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
void MainInputManager::stop()
{
   playlist_Stop( THEPL );
}

void MainInputManager::next()
{
   playlist_Next( THEPL );
}

void MainInputManager::prev()
{
   playlist_Prev( THEPL );
}

526
527
528
529
530
531
532
533
534
void MainInputManager::togglePlayPause()
{
    if( p_input == NULL )
    {
        playlist_Play( THEPL );
        return;
    }
    getIM()->togglePlayPause();
}
535

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
536
537
538
/* Static callbacks */

/* IM */
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
static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var,
                           vlc_value_t oldval, vlc_value_t newval, void *param )
{
    static int counter = 0;
    InputManager *im = (InputManager*)param;

    counter = counter++ % 4;
    if(!counter)
        return VLC_SUCCESS;
    IMEvent *event = new IMEvent( PositionUpdate_Type, 0 );
    QApplication::postEvent( im, static_cast<QEvent*>(event) );
    return VLC_SUCCESS;
}

static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var,
                            vlc_value_t oldval, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;

    IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 );
    QApplication::postEvent( im, static_cast<QEvent*>(event) );
    return VLC_SUCCESS;
}

static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var,
                            vlc_value_t oldval, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;
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
    IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 );
    QApplication::postEvent( im, static_cast<QEvent*>(event) );
    return VLC_SUCCESS;
}

static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var,
                            vlc_value_t oldval, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;

    IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 );
    QApplication::postEvent( im, static_cast<QEvent*>(event) );
    return VLC_SUCCESS;
}

static int ItemChanged( vlc_object_t *p_this, const char *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
    InputManager *im = (InputManager*)param;

    IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
    QApplication::postEvent( im, static_cast<QEvent*>(event) );
    return VLC_SUCCESS;
}
592

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
593

594
595
596
597
598
static int ChangeAudio( vlc_object_t *p_this, const char *var, vlc_value_t o,
                        vlc_value_t n, void *param )
{
    InputManager *im = (InputManager*)param;
    im->b_has_audio = true;
599
    return VLC_SUCCESS;
600
}
zorglub's avatar
zorglub committed
601

602
603
604
605
606
static int ChangeVideo( vlc_object_t *p_this, const char *var, vlc_value_t o,
                        vlc_value_t n, void *param )
{
    InputManager *im = (InputManager*)param;
    im->b_has_video = true;
607
    return VLC_SUCCESS;
608
}
609

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
610
/* MIM */
611
static int PLItemChanged( vlc_object_t *p_this, const char *psz_var,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
612
613
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
614
    MainInputManager *mim = (MainInputManager*)param;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
615
616

    IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int );
617
    QApplication::postEvent( mim, static_cast<QEvent*>(event) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
618
619
620
621
622
623
    return VLC_SUCCESS;
}

static int VolumeChanged( vlc_object_t *p_this, const char *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *param )
{
624
    MainInputManager *mim = (MainInputManager*)param;
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
625
626

    IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int );
627
    QApplication::postEvent( mim, static_cast<QEvent*>(event) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
628
629
630
    return VLC_SUCCESS;
}