~nik90/ubuntu/precise/vlc/keywords

« back to all changes in this revision

Viewing changes to modules/control/dbus.c

  • Committer: Package Import Robot
  • Author(s): Benjamin Drung
  • Date: 2012-02-13 01:34:02 UTC
  • mfrom: (1.1.44)
  • Revision ID: package-import@ubuntu.com-20120213013402-7utx6r7s9dg3r0pf
Tags: 2.0.0~unix-0ubuntu1
* New upstream release (Closes: #499381, #573064, #624027, LP: #455825,
  #573775, #695882, #705151, #708448, #738381, #743581, #747757, #817924,
  #931083).
* Remove dropped mozilla-plugin-vlc, vlc-plugin-ggi, and vlc-plugin-svgalib.
  The Mozilla browser plug-in is now provided by a separate source tarball.
* Add new plugins to and remove dropped plugins from vlc-nox.
* Add new and remove dropped build dependencies:
  + libbluray-dev (for Blu-ray support)
  + libresid-builder-dev
  + libsamplerate0-dev
  + libsidplay2-dev
  + lbspeexdsp-dev
  + libxcb-composite0-dev
  - libgtk2.0-dev
  - xulrunner-dev
* vlc-plugin-fluidsynth depends on fluid-soundfont-gm or
  musescore-soundfont-gm for having a sound font for playing MIDI files.
* Drop all patches (they were either backported or accepted by upstream).
* Update symbols for libvlc5.
* Install plugins.dat instead of running vlc-cache-gen in postinst.
* Update minimum version of build dependencies.
* Change Build-Dependency from libupnp3-dev to unversioned libupnp-dev.
  (Closes: #656831)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 * dbus.c : D-Bus control interface
3
 
 *****************************************************************************
4
 
 * Copyright © 2006-2008 Rafaël Carré
5
 
 * Copyright © 2007-2008 Mirsal Ennaime
6
 
 * Copyright © 2009 The VideoLAN team
7
 
 * $Id: bd59f824745b517c94fe658c375192191f20cf69 $
8
 
 *
9
 
 * Authors:    Rafaël Carré <funman at videolanorg>
10
 
 *             Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
11
 
 *
12
 
 * This program is free software; you can redistribute it and/or modify
13
 
 * it under the terms of the GNU General Public License as published by
14
 
 * the Free Software Foundation; either version 2 of the License, or
15
 
 * (at your option) any later version.
16
 
 *
17
 
 * This program is distributed in the hope that it will be useful,
18
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 
 * GNU General Public License for more details.
21
 
 *
22
 
 * You should have received a copy of the GNU General Public License
23
 
 * along with this program; if not, write to the Free Software
24
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25
 
 *****************************************************************************/
26
 
 
27
 
/*
28
 
 * D-Bus Specification:
29
 
 *      http://dbus.freedesktop.org/doc/dbus-specification.html
30
 
 * D-Bus low-level C API (libdbus)
31
 
 *      http://dbus.freedesktop.org/doc/dbus/api/html/index.html
32
 
 *  extract:
33
 
 *   "If you use this low-level API directly, you're signing up for some pain."
34
 
 *
35
 
 * MPRIS Specification version 1.0
36
 
 *      http://wiki.xmms2.xmms.se/index.php/MPRIS
37
 
 */
38
 
 
39
 
/*****************************************************************************
40
 
 * Preamble
41
 
 *****************************************************************************/
42
 
 
43
 
#ifdef HAVE_CONFIG_H
44
 
# include "config.h"
45
 
#endif
46
 
 
47
 
#include <dbus/dbus.h>
48
 
#include "dbus.h"
49
 
 
50
 
#include <vlc_common.h>
51
 
#include <vlc_plugin.h>
52
 
#include <vlc_aout.h>
53
 
#include <vlc_interface.h>
54
 
#include <vlc_playlist.h>
55
 
#include <vlc_meta.h>
56
 
 
57
 
#include <math.h>
58
 
 
59
 
#include <assert.h>
60
 
 
61
 
/*****************************************************************************
62
 
 * Local prototypes.
63
 
 *****************************************************************************/
64
 
 
65
 
static int  Open    ( vlc_object_t * );
66
 
static void Close   ( vlc_object_t * );
67
 
static void Run     ( intf_thread_t * );
68
 
 
69
 
static int StateChange( intf_thread_t *, int );
70
 
static int TrackChange( intf_thread_t * );
71
 
static int StatusChangeEmit( intf_thread_t *);
72
 
static int TrackListChangeEmit( intf_thread_t *, int, int );
73
 
 
74
 
static int AllCallback( vlc_object_t*, const char*, vlc_value_t, vlc_value_t, void* );
75
 
 
76
 
static int GetInputMeta ( input_item_t *, DBusMessageIter * );
77
 
static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
78
 
static int UpdateCaps( intf_thread_t* );
79
 
 
80
 
/* GetCaps() capabilities */
81
 
enum
82
 
{
83
 
     CAPS_NONE                  = 0,
84
 
     CAPS_CAN_GO_NEXT           = 1 << 0,
85
 
     CAPS_CAN_GO_PREV           = 1 << 1,
86
 
     CAPS_CAN_PAUSE             = 1 << 2,
87
 
     CAPS_CAN_PLAY              = 1 << 3,
88
 
     CAPS_CAN_SEEK              = 1 << 4,
89
 
     CAPS_CAN_PROVIDE_METADATA  = 1 << 5,
90
 
     CAPS_CAN_HAS_TRACKLIST     = 1 << 6
91
 
};
92
 
 
93
 
// The signal that can be get from the callbacks
94
 
enum
95
 
{
96
 
    SIGNAL_ITEM_CURRENT,
97
 
    SIGNAL_INTF_CHANGE,
98
 
    SIGNAL_PLAYLIST_ITEM_APPEND,
99
 
    SIGNAL_PLAYLIST_ITEM_DELETED,
100
 
    SIGNAL_RANDOM,
101
 
    SIGNAL_REPEAT,
102
 
    SIGNAL_LOOP,
103
 
    SIGNAL_STATE
104
 
};
105
 
 
106
 
struct intf_sys_t
107
 
{
108
 
    DBusConnection *p_conn;
109
 
    playlist_t     *p_playlist;
110
 
    bool            b_meta_read;
111
 
    dbus_int32_t    i_caps;
112
 
    bool            b_dead;
113
 
    vlc_array_t    *p_events;
114
 
    vlc_mutex_t     lock;
115
 
    input_thread_t *p_input;
116
 
};
117
 
 
118
 
typedef struct
119
 
{
120
 
    int signal;
121
 
    int i_node;
122
 
    int i_input_state;
123
 
} callback_info_t;
124
 
 
125
 
#define INTF ((intf_thread_t *)p_this)
126
 
#define PL   (INTF->p_sys->p_playlist)
127
 
 
128
 
 
129
 
/*****************************************************************************
130
 
 * Module descriptor
131
 
 *****************************************************************************/
132
 
 
133
 
vlc_module_begin ()
134
 
    set_shortname( N_("dbus"))
135
 
    set_category( CAT_INTERFACE )
136
 
    set_subcategory( SUBCAT_INTERFACE_CONTROL )
137
 
    set_description( N_("D-Bus control interface") )
138
 
    set_capability( "interface", 0 )
139
 
    set_callbacks( Open, Close )
140
 
vlc_module_end ()
141
 
 
142
 
/*****************************************************************************
143
 
 * Methods
144
 
 *****************************************************************************/
145
 
 
146
 
/* Player */
147
 
 
148
 
DBUS_METHOD( Quit )
149
 
{ /* exits vlc */
150
 
    REPLY_INIT;
151
 
    libvlc_Quit(INTF->p_libvlc);
152
 
    REPLY_SEND;
153
 
}
154
 
 
155
 
DBUS_METHOD( MprisVersion )
156
 
{ /*implemented version of the mpris spec */
157
 
    REPLY_INIT;
158
 
    OUT_ARGUMENTS;
159
 
    VLC_UNUSED( p_this );
160
 
    dbus_uint16_t i_major = VLC_MPRIS_VERSION_MAJOR;
161
 
    dbus_uint16_t i_minor = VLC_MPRIS_VERSION_MINOR;
162
 
    DBusMessageIter version;
163
 
 
164
 
    if( !dbus_message_iter_open_container( &args, DBUS_TYPE_STRUCT, NULL,
165
 
            &version ) )
166
 
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
167
 
 
168
 
    if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
169
 
            &i_major ) )
170
 
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
171
 
 
172
 
    if( !dbus_message_iter_append_basic( &version, DBUS_TYPE_UINT16,
173
 
            &i_minor ) )
174
 
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
175
 
 
176
 
    if( !dbus_message_iter_close_container( &args, &version ) )
177
 
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
178
 
    REPLY_SEND;
179
 
}
180
 
 
181
 
DBUS_METHOD( PositionGet )
182
 
{ /* returns position in milliseconds */
183
 
    REPLY_INIT;
184
 
    OUT_ARGUMENTS;
185
 
    dbus_int32_t i_pos;
186
 
 
187
 
    input_thread_t *p_input = playlist_CurrentInput( PL );
188
 
 
189
 
    if( !p_input )
190
 
        i_pos = 0;
191
 
    else
192
 
    {
193
 
        i_pos = var_GetTime( p_input, "time" ) / 1000;
194
 
        vlc_object_release( p_input );
195
 
    }
196
 
    ADD_INT32( &i_pos );
197
 
    REPLY_SEND;
198
 
}
199
 
 
200
 
DBUS_METHOD( PositionSet )
201
 
{ /* set position in milliseconds */
202
 
 
203
 
    REPLY_INIT;
204
 
    vlc_value_t position;
205
 
    dbus_int32_t i_pos;
206
 
 
207
 
    DBusError error;
208
 
    dbus_error_init( &error );
209
 
 
210
 
    dbus_message_get_args( p_from, &error,
211
 
            DBUS_TYPE_INT32, &i_pos,
212
 
            DBUS_TYPE_INVALID );
213
 
 
214
 
    if( dbus_error_is_set( &error ) )
215
 
    {
216
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
217
 
                error.message );
218
 
        dbus_error_free( &error );
219
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
220
 
    }
221
 
    input_thread_t *p_input = playlist_CurrentInput( PL );
222
 
 
223
 
    if( p_input )
224
 
    {
225
 
        position.i_time = ((mtime_t)i_pos) * 1000;
226
 
        var_Set( p_input, "time", position );
227
 
        vlc_object_release( p_input );
228
 
    }
229
 
    REPLY_SEND;
230
 
}
231
 
 
232
 
DBUS_METHOD( VolumeGet )
233
 
{ /* returns volume in percentage */
234
 
    REPLY_INIT;
235
 
    OUT_ARGUMENTS;
236
 
    dbus_int32_t i_dbus_vol;
237
 
    audio_volume_t i_vol;
238
 
 
239
 
    /* 2nd argument of aout_VolumeGet is int32 */
240
 
    aout_VolumeGet( PL, &i_vol );
241
 
 
242
 
    double f_vol = 100. * i_vol / AOUT_VOLUME_MAX;
243
 
    i_dbus_vol = round( f_vol );
244
 
    ADD_INT32( &i_dbus_vol );
245
 
    REPLY_SEND;
246
 
}
247
 
 
248
 
DBUS_METHOD( VolumeSet )
249
 
{ /* set volume in percentage */
250
 
    REPLY_INIT;
251
 
 
252
 
    DBusError error;
253
 
    dbus_error_init( &error );
254
 
 
255
 
    dbus_int32_t i_dbus_vol;
256
 
    audio_volume_t i_vol;
257
 
 
258
 
    dbus_message_get_args( p_from, &error,
259
 
            DBUS_TYPE_INT32, &i_dbus_vol,
260
 
            DBUS_TYPE_INVALID );
261
 
 
262
 
    if( dbus_error_is_set( &error ) )
263
 
    {
264
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
265
 
                error.message );
266
 
        dbus_error_free( &error );
267
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
268
 
    }
269
 
 
270
 
    double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
271
 
    i_vol = round( f_vol );
272
 
    aout_VolumeSet( PL, i_vol );
273
 
    REPLY_SEND;
274
 
}
275
 
 
276
 
DBUS_METHOD( Next )
277
 
{ /* next playlist item */
278
 
    REPLY_INIT;
279
 
    playlist_Next( PL );
280
 
    REPLY_SEND;
281
 
}
282
 
 
283
 
DBUS_METHOD( Prev )
284
 
{ /* previous playlist item */
285
 
    REPLY_INIT;
286
 
    playlist_Prev( PL );
287
 
    REPLY_SEND;
288
 
}
289
 
 
290
 
DBUS_METHOD( Stop )
291
 
{ /* stop playing */
292
 
    REPLY_INIT;
293
 
    playlist_Stop( PL );
294
 
    REPLY_SEND;
295
 
}
296
 
 
297
 
DBUS_METHOD( GetStatus )
298
 
{ /* returns the current status as a struct of 4 ints */
299
 
/*
300
 
    First   0 = Playing, 1 = Paused, 2 = Stopped.
301
 
    Second  0 = Playing linearly , 1 = Playing randomly.
302
 
    Third   0 = Go to the next element once the current has finished playing , 1 = Repeat the current element
303
 
    Fourth  0 = Stop playing once the last element has been played, 1 = Never give up playing *
304
 
 */
305
 
    REPLY_INIT;
306
 
    OUT_ARGUMENTS;
307
 
 
308
 
    MarshalStatus( p_this, &args );
309
 
 
310
 
    REPLY_SEND;
311
 
}
312
 
 
313
 
DBUS_METHOD( Pause )
314
 
{
315
 
    REPLY_INIT;
316
 
    playlist_Pause( PL );
317
 
    REPLY_SEND;
318
 
}
319
 
 
320
 
DBUS_METHOD( Play )
321
 
{
322
 
    REPLY_INIT;
323
 
 
324
 
    input_thread_t *p_input =  playlist_CurrentInput( PL );
325
 
 
326
 
    if( p_input )
327
 
    {
328
 
        double i_pos = 0;
329
 
        input_Control( p_input, INPUT_SET_POSITION, i_pos );
330
 
        vlc_object_release( p_input );
331
 
    }
332
 
    else
333
 
        playlist_Play( PL );
334
 
 
335
 
    REPLY_SEND;
336
 
}
337
 
 
338
 
DBUS_METHOD( GetCurrentMetadata )
339
 
{
340
 
    REPLY_INIT;
341
 
    OUT_ARGUMENTS;
342
 
    playlist_t *p_playlist = PL;
343
 
 
344
 
    PL_LOCK;
345
 
    playlist_item_t* p_item =  playlist_CurrentPlayingItem( p_playlist );
346
 
    if( p_item )
347
 
        GetInputMeta( p_item->p_input, &args );
348
 
    PL_UNLOCK;
349
 
    REPLY_SEND;
350
 
}
351
 
 
352
 
DBUS_METHOD( GetCaps )
353
 
{
354
 
    REPLY_INIT;
355
 
    OUT_ARGUMENTS;
356
 
 
357
 
    ADD_INT32( &INTF->p_sys->i_caps );
358
 
 
359
 
    REPLY_SEND;
360
 
}
361
 
 
362
 
/* Media Player information */
363
 
 
364
 
DBUS_METHOD( Identity )
365
 
{
366
 
    VLC_UNUSED(p_this);
367
 
    REPLY_INIT;
368
 
    OUT_ARGUMENTS;
369
 
    char *psz_identity;
370
 
 
371
 
    if( asprintf( &psz_identity, "%s %s", PACKAGE, VERSION ) != -1 )
372
 
    {
373
 
        ADD_STRING( &psz_identity );
374
 
        free( psz_identity );
375
 
    }
376
 
    else
377
 
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
378
 
 
379
 
    REPLY_SEND;
380
 
}
381
 
 
382
 
/* TrackList */
383
 
 
384
 
DBUS_METHOD( AddTrack )
385
 
{ /* add the string to the playlist, and play it if the boolean is true */
386
 
    REPLY_INIT;
387
 
    OUT_ARGUMENTS;
388
 
 
389
 
    DBusError error;
390
 
    dbus_error_init( &error );
391
 
 
392
 
    char *psz_mrl;
393
 
    dbus_bool_t b_play;
394
 
 
395
 
    dbus_message_get_args( p_from, &error,
396
 
            DBUS_TYPE_STRING, &psz_mrl,
397
 
            DBUS_TYPE_BOOLEAN, &b_play,
398
 
            DBUS_TYPE_INVALID );
399
 
 
400
 
    if( dbus_error_is_set( &error ) )
401
 
    {
402
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
403
 
                error.message );
404
 
        dbus_error_free( &error );
405
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
406
 
    }
407
 
 
408
 
    playlist_Add( PL, psz_mrl, NULL, PLAYLIST_APPEND |
409
 
            ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
410
 
            PLAYLIST_END, true, false );
411
 
 
412
 
    dbus_int32_t i_success = 0;
413
 
    ADD_INT32( &i_success );
414
 
 
415
 
    REPLY_SEND;
416
 
}
417
 
 
418
 
DBUS_METHOD( GetCurrentTrack )
419
 
{
420
 
    REPLY_INIT;
421
 
    OUT_ARGUMENTS;
422
 
 
423
 
    playlist_t *p_playlist = PL;
424
 
 
425
 
    PL_LOCK;
426
 
    dbus_int32_t i_position = PL->i_current_index;
427
 
    PL_UNLOCK;
428
 
 
429
 
    ADD_INT32( &i_position );
430
 
    REPLY_SEND;
431
 
}
432
 
 
433
 
DBUS_METHOD( GetMetadata )
434
 
{
435
 
    REPLY_INIT;
436
 
    OUT_ARGUMENTS;
437
 
    DBusError error;
438
 
    dbus_error_init( &error );
439
 
 
440
 
    dbus_int32_t i_position;
441
 
    playlist_t *p_playlist = PL;
442
 
 
443
 
    dbus_message_get_args( p_from, &error,
444
 
           DBUS_TYPE_INT32, &i_position,
445
 
           DBUS_TYPE_INVALID );
446
 
 
447
 
    if( dbus_error_is_set( &error ) )
448
 
    {
449
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
450
 
                error.message );
451
 
        dbus_error_free( &error );
452
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
453
 
    }
454
 
 
455
 
    PL_LOCK;
456
 
    if( i_position < p_playlist->current.i_size )
457
 
    {
458
 
        GetInputMeta( p_playlist->current.p_elems[i_position]->p_input, &args );
459
 
    }
460
 
 
461
 
    PL_UNLOCK;
462
 
    REPLY_SEND;
463
 
}
464
 
 
465
 
DBUS_METHOD( GetLength )
466
 
{
467
 
    REPLY_INIT;
468
 
    OUT_ARGUMENTS;
469
 
    playlist_t *p_playlist = PL;
470
 
 
471
 
    PL_LOCK;
472
 
    dbus_int32_t i_elements = PL->current.i_size;
473
 
    PL_UNLOCK;
474
 
 
475
 
    ADD_INT32( &i_elements );
476
 
    REPLY_SEND;
477
 
}
478
 
 
479
 
DBUS_METHOD( DelTrack )
480
 
{
481
 
    REPLY_INIT;
482
 
 
483
 
    DBusError error;
484
 
    dbus_error_init( &error );
485
 
 
486
 
    dbus_int32_t i_position;
487
 
    playlist_t *p_playlist = PL;
488
 
 
489
 
    dbus_message_get_args( p_from, &error,
490
 
            DBUS_TYPE_INT32, &i_position,
491
 
            DBUS_TYPE_INVALID );
492
 
 
493
 
    if( dbus_error_is_set( &error ) )
494
 
    {
495
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
496
 
                error.message );
497
 
        dbus_error_free( &error );
498
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499
 
    }
500
 
 
501
 
    PL_LOCK;
502
 
    if( i_position < p_playlist->current.i_size )
503
 
    {
504
 
        playlist_DeleteFromInput( p_playlist,
505
 
            p_playlist->current.p_elems[i_position]->p_input,
506
 
            pl_Locked );
507
 
    }
508
 
    PL_UNLOCK;
509
 
 
510
 
    REPLY_SEND;
511
 
}
512
 
 
513
 
DBUS_METHOD( SetLoop )
514
 
{
515
 
    REPLY_INIT;
516
 
    OUT_ARGUMENTS;
517
 
 
518
 
    DBusError error;
519
 
    dbus_bool_t b_loop;
520
 
 
521
 
    dbus_error_init( &error );
522
 
    dbus_message_get_args( p_from, &error,
523
 
            DBUS_TYPE_BOOLEAN, &b_loop,
524
 
            DBUS_TYPE_INVALID );
525
 
 
526
 
    if( dbus_error_is_set( &error ) )
527
 
    {
528
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
529
 
                error.message );
530
 
        dbus_error_free( &error );
531
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
532
 
    }
533
 
 
534
 
    var_SetBool( PL, "loop", ( b_loop == TRUE ) );
535
 
 
536
 
    REPLY_SEND;
537
 
}
538
 
 
539
 
DBUS_METHOD( Repeat )
540
 
{
541
 
    REPLY_INIT;
542
 
    OUT_ARGUMENTS;
543
 
 
544
 
    DBusError error;
545
 
    dbus_bool_t b_repeat;
546
 
 
547
 
    dbus_error_init( &error );
548
 
    dbus_message_get_args( p_from, &error,
549
 
            DBUS_TYPE_BOOLEAN, &b_repeat,
550
 
            DBUS_TYPE_INVALID );
551
 
 
552
 
    if( dbus_error_is_set( &error ) )
553
 
    {
554
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
555
 
                error.message );
556
 
        dbus_error_free( &error );
557
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
558
 
    }
559
 
 
560
 
    var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
561
 
 
562
 
    REPLY_SEND;
563
 
}
564
 
 
565
 
DBUS_METHOD( SetRandom )
566
 
{
567
 
    REPLY_INIT;
568
 
    OUT_ARGUMENTS;
569
 
 
570
 
    DBusError error;
571
 
    dbus_bool_t b_random;
572
 
 
573
 
    dbus_error_init( &error );
574
 
    dbus_message_get_args( p_from, &error,
575
 
            DBUS_TYPE_BOOLEAN, &b_random,
576
 
            DBUS_TYPE_INVALID );
577
 
 
578
 
    if( dbus_error_is_set( &error ) )
579
 
    {
580
 
        msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
581
 
                error.message );
582
 
        dbus_error_free( &error );
583
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
584
 
    }
585
 
 
586
 
    var_SetBool( PL, "random", ( b_random == TRUE ) );
587
 
 
588
 
    REPLY_SEND;
589
 
}
590
 
/*****************************************************************************
591
 
 * Introspection method
592
 
 *****************************************************************************/
593
 
 
594
 
DBUS_METHOD( handle_introspect_root )
595
 
{ /* handles introspection of root object */
596
 
    VLC_UNUSED(p_this);
597
 
    REPLY_INIT;
598
 
    OUT_ARGUMENTS;
599
 
    ADD_STRING( &psz_introspection_xml_data_root );
600
 
    REPLY_SEND;
601
 
}
602
 
 
603
 
DBUS_METHOD( handle_introspect_player )
604
 
{
605
 
    VLC_UNUSED(p_this);
606
 
    REPLY_INIT;
607
 
    OUT_ARGUMENTS;
608
 
    ADD_STRING( &psz_introspection_xml_data_player );
609
 
    REPLY_SEND;
610
 
}
611
 
 
612
 
DBUS_METHOD( handle_introspect_tracklist )
613
 
{
614
 
    VLC_UNUSED(p_this);
615
 
    REPLY_INIT;
616
 
    OUT_ARGUMENTS;
617
 
    ADD_STRING( &psz_introspection_xml_data_tracklist );
618
 
    REPLY_SEND;
619
 
}
620
 
 
621
 
/*****************************************************************************
622
 
 * handle_*: answer to incoming messages
623
 
 *****************************************************************************/
624
 
 
625
 
#define METHOD_FUNC( method, function ) \
626
 
    else if( dbus_message_is_method_call( p_from, MPRIS_DBUS_INTERFACE, method ) )\
627
 
        return function( p_conn, p_from, p_this )
628
 
 
629
 
DBUS_METHOD( handle_root )
630
 
{
631
 
 
632
 
    if( dbus_message_is_method_call( p_from,
633
 
                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
634
 
        return handle_introspect_root( p_conn, p_from, p_this );
635
 
 
636
 
    /* here D-Bus method's names are associated to an handler */
637
 
 
638
 
    METHOD_FUNC( "Identity",                Identity );
639
 
    METHOD_FUNC( "MprisVersion",            MprisVersion );
640
 
    METHOD_FUNC( "Quit",                    Quit );
641
 
 
642
 
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
643
 
}
644
 
 
645
 
 
646
 
DBUS_METHOD( handle_player )
647
 
{
648
 
    if( dbus_message_is_method_call( p_from,
649
 
                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
650
 
        return handle_introspect_player( p_conn, p_from, p_this );
651
 
 
652
 
    /* here D-Bus method's names are associated to an handler */
653
 
 
654
 
    METHOD_FUNC( "Prev",                    Prev );
655
 
    METHOD_FUNC( "Next",                    Next );
656
 
    METHOD_FUNC( "Stop",                    Stop );
657
 
    METHOD_FUNC( "Play",                    Play );
658
 
    METHOD_FUNC( "Pause",                   Pause );
659
 
    METHOD_FUNC( "Repeat",                  Repeat );
660
 
    METHOD_FUNC( "VolumeSet",               VolumeSet );
661
 
    METHOD_FUNC( "VolumeGet",               VolumeGet );
662
 
    METHOD_FUNC( "PositionSet",             PositionSet );
663
 
    METHOD_FUNC( "PositionGet",             PositionGet );
664
 
    METHOD_FUNC( "GetStatus",               GetStatus );
665
 
    METHOD_FUNC( "GetMetadata",             GetCurrentMetadata );
666
 
    METHOD_FUNC( "GetCaps",                 GetCaps );
667
 
 
668
 
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
669
 
}
670
 
 
671
 
DBUS_METHOD( handle_tracklist )
672
 
{
673
 
    if( dbus_message_is_method_call( p_from,
674
 
                DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
675
 
    return handle_introspect_tracklist( p_conn, p_from, p_this );
676
 
 
677
 
    /* here D-Bus method's names are associated to an handler */
678
 
 
679
 
    METHOD_FUNC( "GetMetadata",             GetMetadata );
680
 
    METHOD_FUNC( "GetCurrentTrack",         GetCurrentTrack );
681
 
    METHOD_FUNC( "GetLength",               GetLength );
682
 
    METHOD_FUNC( "AddTrack",                AddTrack );
683
 
    METHOD_FUNC( "DelTrack",                DelTrack );
684
 
    METHOD_FUNC( "SetLoop",                 SetLoop );
685
 
    METHOD_FUNC( "SetRandom",               SetRandom );
686
 
 
687
 
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
688
 
}
689
 
 
690
 
/*****************************************************************************
691
 
 * Open: initialize interface
692
 
 *****************************************************************************/
693
 
 
694
 
static int Open( vlc_object_t *p_this )
695
 
{ /* initialisation of the connection */
696
 
    intf_thread_t   *p_intf = (intf_thread_t*)p_this;
697
 
    intf_sys_t      *p_sys  = malloc( sizeof( intf_sys_t ) );
698
 
    playlist_t      *p_playlist;
699
 
    DBusConnection  *p_conn;
700
 
    DBusError       error;
701
 
 
702
 
    if( !p_sys )
703
 
        return VLC_ENOMEM;
704
 
 
705
 
    p_sys->b_meta_read = false;
706
 
    p_sys->i_caps = CAPS_NONE;
707
 
    p_sys->b_dead = false;
708
 
    p_sys->p_input = NULL;
709
 
 
710
 
    dbus_error_init( &error );
711
 
 
712
 
    /* connect to the session bus */
713
 
    p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
714
 
    if( !p_conn )
715
 
    {
716
 
        msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
717
 
                error.message );
718
 
        dbus_error_free( &error );
719
 
        free( p_sys );
720
 
        return VLC_EGENERIC;
721
 
    }
722
 
 
723
 
    /* register a well-known name on the bus */
724
 
    dbus_bus_request_name( p_conn, VLC_MPRIS_DBUS_SERVICE, 0, &error );
725
 
    if( dbus_error_is_set( &error ) )
726
 
    {
727
 
        msg_Err( p_this, "Error requesting service " VLC_MPRIS_DBUS_SERVICE
728
 
                 ": %s", error.message );
729
 
        dbus_error_free( &error );
730
 
        free( p_sys );
731
 
        return VLC_EGENERIC;
732
 
    }
733
 
 
734
 
    /* we register the objects */
735
 
    dbus_connection_register_object_path( p_conn, MPRIS_DBUS_ROOT_PATH,
736
 
            &vlc_dbus_root_vtable, p_this );
737
 
    dbus_connection_register_object_path( p_conn, MPRIS_DBUS_PLAYER_PATH,
738
 
            &vlc_dbus_player_vtable, p_this );
739
 
    dbus_connection_register_object_path( p_conn, MPRIS_DBUS_TRACKLIST_PATH,
740
 
            &vlc_dbus_tracklist_vtable, p_this );
741
 
 
742
 
    dbus_connection_flush( p_conn );
743
 
 
744
 
    p_intf->pf_run = Run;
745
 
    p_intf->p_sys = p_sys;
746
 
    p_sys->p_conn = p_conn;
747
 
    p_sys->p_events = vlc_array_new();
748
 
    vlc_mutex_init( &p_sys->lock );
749
 
 
750
 
    p_playlist = pl_Get( p_intf );
751
 
    p_sys->p_playlist = p_playlist;
752
 
 
753
 
    var_AddCallback( p_playlist, "item-current", AllCallback, p_intf );
754
 
    var_AddCallback( p_playlist, "intf-change", AllCallback, p_intf );
755
 
    var_AddCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
756
 
    var_AddCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
757
 
    var_AddCallback( p_playlist, "random", AllCallback, p_intf );
758
 
    var_AddCallback( p_playlist, "repeat", AllCallback, p_intf );
759
 
    var_AddCallback( p_playlist, "loop", AllCallback, p_intf );
760
 
 
761
 
    UpdateCaps( p_intf );
762
 
 
763
 
    return VLC_SUCCESS;
764
 
}
765
 
 
766
 
/*****************************************************************************
767
 
 * Close: destroy interface
768
 
 *****************************************************************************/
769
 
 
770
 
static void Close   ( vlc_object_t *p_this )
771
 
{
772
 
    intf_thread_t   *p_intf     = (intf_thread_t*) p_this;
773
 
    intf_sys_t      *p_sys      = p_intf->p_sys;
774
 
    playlist_t      *p_playlist = p_sys->p_playlist;
775
 
 
776
 
    var_DelCallback( p_playlist, "item-current", AllCallback, p_intf );
777
 
    var_DelCallback( p_playlist, "intf-change", AllCallback, p_intf );
778
 
    var_DelCallback( p_playlist, "playlist-item-append", AllCallback, p_intf );
779
 
    var_DelCallback( p_playlist, "playlist-item-deleted", AllCallback, p_intf );
780
 
    var_DelCallback( p_playlist, "random", AllCallback, p_intf );
781
 
    var_DelCallback( p_playlist, "repeat", AllCallback, p_intf );
782
 
    var_DelCallback( p_playlist, "loop", AllCallback, p_intf );
783
 
 
784
 
    if( p_sys->p_input )
785
 
    {
786
 
        var_DelCallback( p_sys->p_input, "state", AllCallback, p_intf );
787
 
        vlc_object_release( p_sys->p_input );
788
 
    }
789
 
 
790
 
    dbus_connection_unref( p_sys->p_conn );
791
 
 
792
 
    // Free the events array
793
 
    for( int i = 0; i < vlc_array_count( p_sys->p_events ); i++ )
794
 
    {
795
 
        callback_info_t* info = vlc_array_item_at_index( p_sys->p_events, i );
796
 
        free( info );
797
 
    }
798
 
    vlc_mutex_destroy( &p_sys->lock );
799
 
    vlc_array_destroy( p_sys->p_events );
800
 
    free( p_sys );
801
 
}
802
 
 
803
 
/*****************************************************************************
804
 
 * Run: main loop
805
 
 *****************************************************************************/
806
 
 
807
 
static void Run          ( intf_thread_t *p_intf )
808
 
{
809
 
    for( ;; )
810
 
    {
811
 
        if( dbus_connection_get_dispatch_status(p_intf->p_sys->p_conn)
812
 
                                             == DBUS_DISPATCH_COMPLETE )
813
 
            msleep( INTF_IDLE_SLEEP );
814
 
        int canc = vlc_savecancel();
815
 
        dbus_connection_read_write_dispatch( p_intf->p_sys->p_conn, 0 );
816
 
 
817
 
        /* Get the list of events to process
818
 
         *
819
 
         * We can't keep the lock on p_intf->p_sys->p_events, else we risk a
820
 
         * deadlock:
821
 
         * The signal functions could lock mutex X while p_events is locked;
822
 
         * While some other function in vlc (playlist) might lock mutex X
823
 
         * and then set a variable which would call AllCallback(), which itself
824
 
         * needs to lock p_events to add a new event.
825
 
         */
826
 
        vlc_mutex_lock( &p_intf->p_sys->lock );
827
 
        int i_events = vlc_array_count( p_intf->p_sys->p_events );
828
 
        callback_info_t* info[i_events];
829
 
        for( int i = i_events - 1; i >= 0; i-- )
830
 
        {
831
 
            info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i );
832
 
            vlc_array_remove( p_intf->p_sys->p_events, i );
833
 
        }
834
 
        vlc_mutex_unlock( &p_intf->p_sys->lock );
835
 
 
836
 
        for( int i = 0; i < i_events; i++ )
837
 
        {
838
 
            switch( info[i]->signal )
839
 
            {
840
 
            case SIGNAL_ITEM_CURRENT:
841
 
                TrackChange( p_intf );
842
 
                break;
843
 
            case SIGNAL_INTF_CHANGE:
844
 
            case SIGNAL_PLAYLIST_ITEM_APPEND:
845
 
            case SIGNAL_PLAYLIST_ITEM_DELETED:
846
 
                TrackListChangeEmit( p_intf, info[i]->signal, info[i]->i_node );
847
 
                break;
848
 
            case SIGNAL_RANDOM:
849
 
            case SIGNAL_REPEAT:
850
 
            case SIGNAL_LOOP:
851
 
                StatusChangeEmit( p_intf );
852
 
                break;
853
 
            case SIGNAL_STATE:
854
 
                StateChange( p_intf, info[i]->i_input_state );
855
 
                break;
856
 
            default:
857
 
                assert(0);
858
 
            }
859
 
            free( info[i] );
860
 
        }
861
 
        vlc_restorecancel( canc );
862
 
    }
863
 
}
864
 
 
865
 
 
866
 
// Get all the callbacks
867
 
static int AllCallback( vlc_object_t *p_this, const char *psz_var,
868
 
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
869
 
{
870
 
    (void)p_this;
871
 
    (void)oldval;
872
 
    intf_thread_t *p_intf = (intf_thread_t*)p_data;
873
 
 
874
 
    callback_info_t *info = malloc( sizeof( callback_info_t ) );
875
 
    if( !info )
876
 
        return VLC_ENOMEM;
877
 
 
878
 
    // Wich event is it ?
879
 
    if( !strcmp( "item-current", psz_var ) )
880
 
        info->signal = SIGNAL_ITEM_CURRENT;
881
 
    else if( !strcmp( "intf-change", psz_var ) )
882
 
        info->signal = SIGNAL_INTF_CHANGE;
883
 
    else if( !strcmp( "playlist-item-append", psz_var ) )
884
 
    {
885
 
        info->signal = SIGNAL_PLAYLIST_ITEM_APPEND;
886
 
        info->i_node = ((playlist_add_t*)newval.p_address)->i_node;
887
 
    }
888
 
    else if( !strcmp( "playlist-item-deleted", psz_var ) )
889
 
        info->signal = SIGNAL_PLAYLIST_ITEM_DELETED;
890
 
    else if( !strcmp( "random", psz_var ) )
891
 
        info->signal = SIGNAL_RANDOM;
892
 
    else if( !strcmp( "repeat", psz_var ) )
893
 
        info->signal = SIGNAL_REPEAT;
894
 
    else if( !strcmp( "loop", psz_var ) )
895
 
        info->signal = SIGNAL_LOOP;
896
 
    else if( !strcmp( "state", psz_var ) )
897
 
    {
898
 
        info->signal = SIGNAL_STATE;
899
 
        info->i_input_state = newval.i_int;
900
 
    }
901
 
    else
902
 
        assert(0);
903
 
 
904
 
    // Append the event
905
 
    vlc_mutex_lock( &p_intf->p_sys->lock );
906
 
    vlc_array_append( p_intf->p_sys->p_events, info );
907
 
    vlc_mutex_unlock( &p_intf->p_sys->lock );
908
 
    return VLC_SUCCESS;
909
 
}
910
 
 
911
 
/******************************************************************************
912
 
 * CapsChange: player capabilities change signal
913
 
 *****************************************************************************/
914
 
DBUS_SIGNAL( CapsChangeSignal )
915
 
{
916
 
    SIGNAL_INIT( MPRIS_DBUS_PLAYER_PATH, "CapsChange" );
917
 
    OUT_ARGUMENTS;
918
 
 
919
 
    ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
920
 
    SIGNAL_SEND;
921
 
}
922
 
 
923
 
/******************************************************************************
924
 
 * TrackListChange: tracklist order / length change signal
925
 
 *****************************************************************************/
926
 
DBUS_SIGNAL( TrackListChangeSignal )
927
 
{ /* emit the new tracklist lengh */
928
 
    SIGNAL_INIT( MPRIS_DBUS_TRACKLIST_PATH, "TrackListChange");
929
 
    OUT_ARGUMENTS;
930
 
 
931
 
    /* XXX: locking */
932
 
    dbus_int32_t i_elements = ((intf_thread_t*)p_data)->p_sys->p_playlist->current.i_size;
933
 
 
934
 
    ADD_INT32( &i_elements );
935
 
    SIGNAL_SEND;
936
 
}
937
 
 
938
 
/*****************************************************************************
939
 
 * TrackListChangeEmit: Emits the TrackListChange signal
940
 
 *****************************************************************************/
941
 
/* FIXME: It is not called on tracklist reordering */
942
 
static int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
943
 
{
944
 
    // "playlist-item-append"
945
 
    if( signal == SIGNAL_PLAYLIST_ITEM_APPEND )
946
 
    {
947
 
        /* don't signal when items are added/removed in p_category */
948
 
        playlist_t *p_playlist = p_intf->p_sys->p_playlist;
949
 
        PL_LOCK;
950
 
        playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_node );
951
 
        assert( p_item );
952
 
        while( p_item->p_parent )
953
 
            p_item = p_item->p_parent;
954
 
        if( p_item == p_playlist->p_root_category )
955
 
        {
956
 
            PL_UNLOCK;
957
 
            return VLC_SUCCESS;
958
 
        }
959
 
        PL_UNLOCK;
960
 
    }
961
 
 
962
 
    if( p_intf->p_sys->b_dead )
963
 
        return VLC_SUCCESS;
964
 
 
965
 
    UpdateCaps( p_intf );
966
 
    TrackListChangeSignal( p_intf->p_sys->p_conn, p_intf );
967
 
    return VLC_SUCCESS;
968
 
}
969
 
/*****************************************************************************
970
 
 * TrackChange: Playlist item change callback
971
 
 *****************************************************************************/
972
 
 
973
 
DBUS_SIGNAL( TrackChangeSignal )
974
 
{ /* emit the metadata of the new item */
975
 
    SIGNAL_INIT( MPRIS_DBUS_PLAYER_PATH, "TrackChange" );
976
 
    OUT_ARGUMENTS;
977
 
 
978
 
    input_item_t *p_item = (input_item_t*) p_data;
979
 
    GetInputMeta ( p_item, &args );
980
 
 
981
 
    SIGNAL_SEND;
982
 
}
983
 
 
984
 
/*****************************************************************************
985
 
 * StatusChange: Player status change signal
986
 
 *****************************************************************************/
987
 
 
988
 
DBUS_SIGNAL( StatusChangeSignal )
989
 
{ /* send the updated status info on the bus */
990
 
    SIGNAL_INIT( MPRIS_DBUS_PLAYER_PATH, "StatusChange" );
991
 
    OUT_ARGUMENTS;
992
 
 
993
 
    /* we're called from a callback of input_thread_t, so it can not be
994
 
     * destroyed before we return */
995
 
    MarshalStatus( (intf_thread_t*) p_data, &args );
996
 
 
997
 
    SIGNAL_SEND;
998
 
}
999
 
 
1000
 
/*****************************************************************************
1001
 
 * StateChange: callback on input "state"
1002
 
 *****************************************************************************/
1003
 
//static int StateChange( vlc_object_t *p_this, const char* psz_var,
1004
 
//            vlc_value_t oldval, vlc_value_t newval, void *p_data )
1005
 
static int StateChange( intf_thread_t *p_intf, int i_input_state )
1006
 
{
1007
 
    intf_sys_t          *p_sys      = p_intf->p_sys;
1008
 
    playlist_t          *p_playlist = p_sys->p_playlist;
1009
 
    input_thread_t      *p_input;
1010
 
    input_item_t        *p_item;
1011
 
 
1012
 
    if( p_intf->p_sys->b_dead )
1013
 
        return VLC_SUCCESS;
1014
 
 
1015
 
    UpdateCaps( p_intf );
1016
 
 
1017
 
    if( !p_sys->b_meta_read && i_input_state == PLAYING_S )
1018
 
    {
1019
 
        p_input = playlist_CurrentInput( p_playlist );
1020
 
        if( p_input )
1021
 
        {
1022
 
            p_item = input_GetItem( p_input );
1023
 
            if( p_item )
1024
 
            {
1025
 
                p_sys->b_meta_read = true;
1026
 
                TrackChangeSignal( p_sys->p_conn, p_item );
1027
 
            }
1028
 
            vlc_object_release( p_input );
1029
 
        }
1030
 
    }
1031
 
 
1032
 
    if( i_input_state == PLAYING_S || i_input_state == PAUSE_S ||
1033
 
        i_input_state == END_S )
1034
 
    {
1035
 
        StatusChangeSignal( p_sys->p_conn, p_intf );
1036
 
    }
1037
 
 
1038
 
    return VLC_SUCCESS;
1039
 
}
1040
 
 
1041
 
/*****************************************************************************
1042
 
 * StatusChangeEmit: Emits the StatusChange signal
1043
 
 *****************************************************************************/
1044
 
static int StatusChangeEmit( intf_thread_t * p_intf )
1045
 
{
1046
 
    if( p_intf->p_sys->b_dead )
1047
 
        return VLC_SUCCESS;
1048
 
 
1049
 
    UpdateCaps( p_intf );
1050
 
    StatusChangeSignal( p_intf->p_sys->p_conn, p_intf );
1051
 
    return VLC_SUCCESS;
1052
 
}
1053
 
 
1054
 
/*****************************************************************************
1055
 
 * TrackChange: callback on playlist "item-current"
1056
 
 *****************************************************************************/
1057
 
static int TrackChange( intf_thread_t *p_intf )
1058
 
{
1059
 
    intf_sys_t          *p_sys      = p_intf->p_sys;
1060
 
    playlist_t          *p_playlist = p_sys->p_playlist;
1061
 
    input_thread_t      *p_input    = NULL;
1062
 
    input_item_t        *p_item     = NULL;
1063
 
 
1064
 
    if( p_intf->p_sys->b_dead )
1065
 
        return VLC_SUCCESS;
1066
 
 
1067
 
    if( p_sys->p_input )
1068
 
    {
1069
 
        var_DelCallback( p_sys->p_input, "state", AllCallback, p_intf );
1070
 
        vlc_object_release( p_sys->p_input );
1071
 
        p_sys->p_input = NULL;
1072
 
    }
1073
 
 
1074
 
    p_sys->b_meta_read = false;
1075
 
 
1076
 
    p_input = playlist_CurrentInput( p_playlist );
1077
 
    if( !p_input )
1078
 
    {
1079
 
        return VLC_SUCCESS;
1080
 
    }
1081
 
 
1082
 
    p_item = input_GetItem( p_input );
1083
 
    if( !p_item )
1084
 
    {
1085
 
        vlc_object_release( p_input );
1086
 
        return VLC_EGENERIC;
1087
 
    }
1088
 
 
1089
 
    if( input_item_IsPreparsed( p_item ) )
1090
 
    {
1091
 
        p_sys->b_meta_read = true;
1092
 
        TrackChangeSignal( p_sys->p_conn, p_item );
1093
 
    }
1094
 
 
1095
 
    p_sys->p_input = p_input;
1096
 
    var_AddCallback( p_input, "state", AllCallback, p_intf );
1097
 
 
1098
 
    return VLC_SUCCESS;
1099
 
}
1100
 
 
1101
 
/*****************************************************************************
1102
 
 * UpdateCaps: update p_sys->i_caps
1103
 
 * This function have to be called with the playlist unlocked
1104
 
 ****************************************************************************/
1105
 
static int UpdateCaps( intf_thread_t* p_intf )
1106
 
{
1107
 
    intf_sys_t* p_sys = p_intf->p_sys;
1108
 
    dbus_int32_t i_caps = CAPS_CAN_HAS_TRACKLIST;
1109
 
    playlist_t* p_playlist = p_sys->p_playlist;
1110
 
 
1111
 
    PL_LOCK;
1112
 
    if( p_playlist->current.i_size > 0 )
1113
 
        i_caps |= CAPS_CAN_PLAY | CAPS_CAN_GO_PREV | CAPS_CAN_GO_NEXT;
1114
 
    PL_UNLOCK;
1115
 
 
1116
 
    input_thread_t* p_input = playlist_CurrentInput( p_playlist );
1117
 
    if( p_input )
1118
 
    {
1119
 
        /* XXX: if UpdateCaps() is called too early, these are
1120
 
         * unconditionnaly true */
1121
 
        if( var_GetBool( p_input, "can-pause" ) )
1122
 
            i_caps |= CAPS_CAN_PAUSE;
1123
 
        if( var_GetBool( p_input, "can-seek" ) )
1124
 
            i_caps |= CAPS_CAN_SEEK;
1125
 
        vlc_object_release( p_input );
1126
 
    }
1127
 
 
1128
 
    if( p_sys->b_meta_read )
1129
 
        i_caps |= CAPS_CAN_PROVIDE_METADATA;
1130
 
 
1131
 
    if( i_caps != p_intf->p_sys->i_caps )
1132
 
    {
1133
 
        p_sys->i_caps = i_caps;
1134
 
        CapsChangeSignal( p_intf->p_sys->p_conn, (vlc_object_t*)p_intf );
1135
 
    }
1136
 
 
1137
 
    return VLC_SUCCESS;
1138
 
}
1139
 
 
1140
 
/*****************************************************************************
1141
 
 * GetInputMeta: Fill a DBusMessage with the given input item metadata
1142
 
 *****************************************************************************/
1143
 
 
1144
 
#define ADD_META( entry, type, data ) \
1145
 
    if( data ) { \
1146
 
        dbus_message_iter_open_container( &dict, DBUS_TYPE_DICT_ENTRY, \
1147
 
                NULL, &dict_entry ); \
1148
 
        dbus_message_iter_append_basic( &dict_entry, DBUS_TYPE_STRING, \
1149
 
                &ppsz_meta_items[entry] ); \
1150
 
        dbus_message_iter_open_container( &dict_entry, DBUS_TYPE_VARIANT, \
1151
 
                type##_AS_STRING, &variant ); \
1152
 
        dbus_message_iter_append_basic( &variant, \
1153
 
                type, \
1154
 
                & data ); \
1155
 
        dbus_message_iter_close_container( &dict_entry, &variant ); \
1156
 
        dbus_message_iter_close_container( &dict, &dict_entry ); }
1157
 
 
1158
 
#define ADD_VLC_META_STRING( entry, item ) \
1159
 
    { \
1160
 
        char * psz = input_item_Get##item( p_input );\
1161
 
        ADD_META( entry, DBUS_TYPE_STRING, \
1162
 
                  psz ); \
1163
 
        free( psz ); \
1164
 
    }
1165
 
 
1166
 
static int GetInputMeta( input_item_t* p_input,
1167
 
                        DBusMessageIter *args )
1168
 
{
1169
 
    DBusMessageIter dict, dict_entry, variant;
1170
 
    /** The duration of the track can be expressed in second, milli-seconds and
1171
 
        µ-seconds */
1172
 
    dbus_int64_t i_mtime = input_item_GetDuration( p_input );
1173
 
    dbus_uint32_t i_time = i_mtime / 1000000;
1174
 
    dbus_int64_t i_length = i_mtime / 1000;
1175
 
 
1176
 
    const char* ppsz_meta_items[] =
1177
 
    {
1178
 
    /* Official MPRIS metas */
1179
 
    "location", "title", "artist", "album", "tracknumber", "time", "mtime",
1180
 
    "genre", "rating", "date", "arturl",
1181
 
    "audio-bitrate", "audio-samplerate", "video-bitrate",
1182
 
    /* VLC specifics metas */
1183
 
    "audio-codec", "copyright", "description", "encodedby", "language", "length",
1184
 
    "nowplaying", "publisher", "setting", "status", "trackid", "url",
1185
 
    "video-codec"
1186
 
    };
1187
 
 
1188
 
    dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict );
1189
 
 
1190
 
    ADD_VLC_META_STRING( 0,  URI );
1191
 
    ADD_VLC_META_STRING( 1,  Title );
1192
 
    ADD_VLC_META_STRING( 2,  Artist );
1193
 
    ADD_VLC_META_STRING( 3,  Album );
1194
 
    ADD_VLC_META_STRING( 4,  TrackNum );
1195
 
    ADD_META( 5, DBUS_TYPE_UINT32, i_time );
1196
 
    ADD_META( 6, DBUS_TYPE_UINT32, i_mtime );
1197
 
    ADD_VLC_META_STRING( 7,  Genre );
1198
 
    ADD_VLC_META_STRING( 8,  Rating );
1199
 
    ADD_VLC_META_STRING( 9,  Date );
1200
 
    ADD_VLC_META_STRING( 10, ArtURL );
1201
 
 
1202
 
    ADD_VLC_META_STRING( 15, Copyright );
1203
 
    ADD_VLC_META_STRING( 16, Description );
1204
 
    ADD_VLC_META_STRING( 17, EncodedBy );
1205
 
    ADD_VLC_META_STRING( 18, Language );
1206
 
    ADD_META( 19, DBUS_TYPE_INT64, i_length );
1207
 
    ADD_VLC_META_STRING( 20, NowPlaying );
1208
 
    ADD_VLC_META_STRING( 21, Publisher );
1209
 
    ADD_VLC_META_STRING( 22, Setting );
1210
 
    ADD_VLC_META_STRING( 24, TrackID );
1211
 
    ADD_VLC_META_STRING( 25, URL );
1212
 
 
1213
 
    vlc_mutex_lock( &p_input->lock );
1214
 
    if( p_input->p_meta )
1215
 
    {
1216
 
        int i_status = vlc_meta_GetStatus( p_input->p_meta );
1217
 
        ADD_META( 23, DBUS_TYPE_INT32, i_status );
1218
 
    }
1219
 
    vlc_mutex_unlock( &p_input->lock );
1220
 
 
1221
 
    dbus_message_iter_close_container( args, &dict );
1222
 
    return VLC_SUCCESS;
1223
 
}
1224
 
 
1225
 
#undef ADD_META
1226
 
#undef ADD_VLC_META_STRING
1227
 
 
1228
 
/*****************************************************************************
1229
 
 * MarshalStatus: Fill a DBusMessage with the current player status
1230
 
 *****************************************************************************/
1231
 
 
1232
 
static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args )
1233
 
{ /* This is NOT the right way to do that, it would be better to sore
1234
 
     the status information in p_sys and update it on change, thus
1235
 
     avoiding a long lock */
1236
 
 
1237
 
    DBusMessageIter status;
1238
 
    dbus_int32_t i_state, i_random, i_repeat, i_loop;
1239
 
    int i_val;
1240
 
    playlist_t* p_playlist = p_intf->p_sys->p_playlist;
1241
 
    input_thread_t* p_input = NULL;
1242
 
 
1243
 
    i_state = 2;
1244
 
 
1245
 
    p_input = playlist_CurrentInput( p_playlist );
1246
 
    if( p_input )
1247
 
    {
1248
 
        i_val = var_GetInteger( p_input, "state" );
1249
 
        if( i_val >= END_S )
1250
 
            i_state = 2;
1251
 
        else if( i_val == PAUSE_S )
1252
 
            i_state = 1;
1253
 
        else if( i_val <= PLAYING_S )
1254
 
            i_state = 0;
1255
 
        vlc_object_release( p_input );
1256
 
    }
1257
 
 
1258
 
    i_random = var_CreateGetBool( p_playlist, "random" );
1259
 
 
1260
 
    i_repeat = var_CreateGetBool( p_playlist, "repeat" );
1261
 
 
1262
 
    i_loop = var_CreateGetBool( p_playlist, "loop" );
1263
 
 
1264
 
    dbus_message_iter_open_container( args, DBUS_TYPE_STRUCT, NULL, &status );
1265
 
    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_state );
1266
 
    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_random );
1267
 
    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_repeat );
1268
 
    dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_loop );
1269
 
    dbus_message_iter_close_container( args, &status );
1270
 
 
1271
 
    return VLC_SUCCESS;
1272
 
}