Coverage Report

Created: 2025-07-11 07:16

/src/vlc/src/input/vlm.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * vlm.c: VLM interface plugin
3
 *****************************************************************************
4
 * Copyright (C) 2000-2005 VLC authors and VideoLAN
5
 *
6
 * Authors: Simon Latapie <garf@videolan.org>
7
 *          Laurent Aimar <fenrir@videolan.org>
8
 *          Gildas Bazin <gbazin@videolan.org>
9
 *
10
 * This program is free software; you can redistribute it and/or modify it
11
 * under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation; either version 2.1 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this program; if not, write to the Free Software Foundation,
22
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
24
25
/*****************************************************************************
26
 * Preamble
27
 *****************************************************************************/
28
#ifdef HAVE_CONFIG_H
29
# include "config.h"
30
#endif
31
32
#include <vlc_common.h>
33
#include <vlc_arrays.h>
34
35
#include <stdio.h>
36
#include <ctype.h>                                              /* tolower() */
37
#include <time.h>                                                 /* ctime() */
38
#include <limits.h>
39
#include <assert.h>
40
41
#include <vlc_vlm.h>
42
#include <vlc_modules.h>
43
44
#include <vlc_player.h>
45
#include <vlc_stream.h>
46
#include "vlm_internal.h"
47
#include "vlm_event.h"
48
#include <vlc_sout.h>
49
#include <vlc_url.h>
50
#include "../misc/threads.h"
51
#include "../libvlc.h"
52
53
/*****************************************************************************
54
 * Local prototypes.
55
 *****************************************************************************/
56
57
static void* Manage( void * );
58
59
static void player_on_state_changed(vlc_player_t *player,
60
                                    enum vlc_player_state new_state, void *data)
61
0
{
62
0
    vlm_media_sys_t *p_media = data;
63
0
    vlm_t *p_vlm = p_media->vlm;
64
0
    assert( p_vlm );
65
0
    vlm_media_instance_sys_t *instance = NULL;
66
0
    const char *psz_instance_name = NULL;
67
68
0
    for( int i = 0; i < p_media->i_instance; i++ )
69
0
    {
70
0
        if( p_media->instance[i]->player == player )
71
0
        {
72
0
            instance = p_media->instance[i];
73
0
            psz_instance_name = instance->psz_name;
74
0
            break;
75
0
        }
76
0
    }
77
0
    enum vlm_state_e vlm_state;
78
0
    switch (new_state)
79
0
    {
80
0
        case VLC_PLAYER_STATE_STOPPED:
81
0
            vlm_state = vlc_player_GetError(player) ? VLM_ERROR_S : VLM_INIT_S;
82
0
            break;
83
0
        case VLC_PLAYER_STATE_STARTED:
84
0
            vlm_state = VLM_OPENING_S;
85
0
            break;
86
0
        case VLC_PLAYER_STATE_PLAYING:
87
0
            vlm_state = VLM_PLAYING_S;
88
0
            break;
89
0
        case VLC_PLAYER_STATE_PAUSED:
90
0
            vlm_state = VLM_PAUSE_S;
91
0
            break;
92
0
        case VLC_PLAYER_STATE_STOPPING:
93
0
            vlm_state = vlc_player_GetError(player) ? VLM_ERROR_S : VLM_END_S;
94
0
            if (instance != NULL)
95
0
            {
96
0
                vlc_mutex_lock(&p_vlm->lock);
97
0
                instance->finished = true;
98
0
                vlc_mutex_unlock(&p_vlm->lock);
99
0
            }
100
101
0
            break;
102
0
        default:
103
0
            vlc_assert_unreachable();
104
0
    }
105
0
    vlm_SendEventMediaInstanceState( p_vlm, p_media->cfg.id, p_media->cfg.psz_name, psz_instance_name, vlm_state );
106
107
0
    vlc_mutex_lock( &p_vlm->lock_manage );
108
0
    p_vlm->input_state_changed = true;
109
0
    vlc_cond_signal( &p_vlm->wait_manage );
110
0
    vlc_mutex_unlock( &p_vlm->lock_manage );
111
0
}
112
113
static vlc_mutex_t vlm_mutex = VLC_STATIC_MUTEX;
114
115
/*****************************************************************************
116
 * vlm_New:
117
 *****************************************************************************/
118
vlm_t *vlm_New( libvlc_int_t *libvlc, const char *psz_vlmconf )
119
0
{
120
0
    vlm_t *p_vlm = NULL, **pp_vlm = &(libvlc_priv(libvlc)->p_vlm);
121
0
    vlc_object_t *p_this = VLC_OBJECT(libvlc);
122
123
    /* Avoid multiple creation */
124
0
    vlc_mutex_lock( &vlm_mutex );
125
126
0
    p_vlm = *pp_vlm;
127
0
    if( p_vlm )
128
0
    {   /* VLM already exists */
129
0
        if( likely( p_vlm->users < UINT_MAX ) )
130
0
            p_vlm->users++;
131
0
        else
132
0
            p_vlm = NULL;
133
0
        vlc_mutex_unlock( &vlm_mutex );
134
0
        return p_vlm;
135
0
    }
136
137
0
    msg_Dbg( p_this, "creating VLM" );
138
139
0
    p_vlm = vlc_custom_create( p_this, sizeof( *p_vlm ), "vlm daemon" );
140
0
    if( !p_vlm )
141
0
    {
142
0
        vlc_mutex_unlock( &vlm_mutex );
143
0
        return NULL;
144
0
    }
145
146
0
    vlc_mutex_init( &p_vlm->lock );
147
0
    vlc_mutex_init( &p_vlm->lock_manage );
148
0
    vlc_cond_init( &p_vlm->wait_manage );
149
0
    p_vlm->users = 1;
150
0
    p_vlm->input_state_changed = false;
151
0
    p_vlm->exiting = false;
152
0
    p_vlm->i_id = 1;
153
0
    TAB_INIT( p_vlm->i_media, p_vlm->media );
154
0
    TAB_INIT( p_vlm->i_schedule, p_vlm->schedule );
155
0
    var_Create( p_vlm, "intf-event", VLC_VAR_ADDRESS );
156
157
0
    if( vlc_clone( &p_vlm->thread, Manage, p_vlm ) )
158
0
    {
159
0
        vlc_object_delete(p_vlm);
160
0
        vlc_mutex_unlock( &vlm_mutex );
161
0
        return NULL;
162
0
    }
163
164
0
    *pp_vlm = p_vlm; /* for future reference */
165
166
0
    vlc_mutex_unlock( &vlm_mutex );
167
168
    /* Load our configuration file */
169
0
    if( psz_vlmconf != NULL )
170
0
    {
171
0
        vlm_message_t *p_message = NULL;
172
0
        char *psz_buffer = NULL;
173
174
0
        msg_Dbg( p_this, "loading VLM configuration" );
175
0
        if( asprintf(&psz_buffer, "load %s", psz_vlmconf ) != -1 )
176
0
        {
177
0
            msg_Dbg( p_this, "%s", psz_buffer );
178
0
            if( vlm_ExecuteCommand( p_vlm, psz_buffer, &p_message ) )
179
0
                msg_Warn( p_this, "error while loading the configuration file" );
180
181
0
            vlm_MessageDelete( p_message );
182
0
            free( psz_buffer );
183
0
        }
184
0
    }
185
186
0
    return p_vlm;
187
0
}
188
189
/*****************************************************************************
190
 * vlm_Delete:
191
 *****************************************************************************/
192
void vlm_Delete( vlm_t *p_vlm )
193
0
{
194
    /* vlm_Delete() is serialized against itself, and against vlm_New().
195
     * This mutex protects libvlc_priv->p_vlm and p_vlm->users. */
196
0
    vlc_mutex_lock( &vlm_mutex );
197
0
    assert( p_vlm->users > 0 );
198
0
    if( --p_vlm->users == 0 )
199
0
        assert( libvlc_priv(vlc_object_instance(p_vlm))->p_vlm == p_vlm );
200
0
    else
201
0
        p_vlm = NULL;
202
203
0
    if( p_vlm == NULL )
204
0
    {
205
0
        vlc_mutex_unlock( &vlm_mutex );
206
0
        return;
207
0
    }
208
209
    /* Destroy and release VLM */
210
0
    vlc_mutex_lock( &p_vlm->lock );
211
0
    vlm_ControlInternal( p_vlm, VLM_CLEAR_MEDIAS );
212
0
    TAB_CLEAN( p_vlm->i_media, p_vlm->media );
213
214
0
    vlm_ControlInternal( p_vlm, VLM_CLEAR_SCHEDULES );
215
0
    TAB_CLEAN( p_vlm->i_schedule, p_vlm->schedule );
216
0
    vlc_mutex_unlock( &p_vlm->lock );
217
218
0
    vlc_mutex_lock( &p_vlm->lock_manage );
219
0
    p_vlm->exiting = true;
220
0
    vlc_cond_signal( &p_vlm->wait_manage );
221
0
    vlc_mutex_unlock( &p_vlm->lock_manage );
222
223
0
    libvlc_priv(vlc_object_instance(p_vlm))->p_vlm = NULL;
224
0
    vlc_mutex_unlock( &vlm_mutex );
225
226
0
    vlc_join( p_vlm->thread, NULL );
227
0
    vlc_object_delete(p_vlm);
228
0
}
229
230
/*****************************************************************************
231
 * vlm_ExecuteCommand:
232
 *****************************************************************************/
233
int vlm_ExecuteCommand( vlm_t *p_vlm, const char *psz_command,
234
                        vlm_message_t **pp_message)
235
0
{
236
0
    int i_result;
237
238
0
    vlc_mutex_lock( &p_vlm->lock );
239
0
    i_result = ExecuteCommand( p_vlm, psz_command, pp_message );
240
0
    vlc_mutex_unlock( &p_vlm->lock );
241
242
0
    return i_result;
243
0
}
244
245
/*****************************************************************************
246
 * Manage:
247
 *****************************************************************************/
248
static void* Manage( void* p_object )
249
0
{
250
0
    vlc_thread_set_name("vlc-vlm");
251
252
0
    vlm_t *vlm = (vlm_t*)p_object;
253
0
    time_t lastcheck;
254
0
    bool exiting;
255
256
0
    time(&lastcheck);
257
258
0
    do
259
0
    {
260
0
        char **ppsz_scheduled_commands = NULL;
261
0
        int    i_scheduled_commands = 0;
262
263
        /* destroy the inputs that wants to die, and launch the next input */
264
0
        vlc_mutex_lock( &vlm->lock );
265
0
        for( int i = 0; i < vlm->i_media; i++ )
266
0
        {
267
0
            vlm_media_sys_t *p_media = vlm->media[i];
268
269
0
            for( int j = 0; j < p_media->i_instance; )
270
0
            {
271
0
                vlm_media_instance_sys_t *p_instance = p_media->instance[j];
272
273
0
                if (p_instance->finished)
274
0
                {
275
0
                    int i_new_input_index;
276
277
                    /* */
278
0
                    i_new_input_index = p_instance->i_index + 1;
279
0
                    if( p_media->cfg.broadcast.b_loop && i_new_input_index >= p_media->cfg.i_input )
280
0
                        i_new_input_index = 0;
281
282
0
                    if( i_new_input_index >= p_media->cfg.i_input )
283
0
                        vlm_ControlInternal( vlm, VLM_STOP_MEDIA_INSTANCE, p_media->cfg.id, p_instance->psz_name );
284
0
                    else
285
0
                        vlm_ControlInternal( vlm, VLM_START_MEDIA_BROADCAST_INSTANCE, p_media->cfg.id, p_instance->psz_name, i_new_input_index );
286
287
0
                    j = 0;
288
0
                }
289
0
                else
290
0
                {
291
0
                    j++;
292
0
                }
293
0
            }
294
0
        }
295
296
        /* scheduling */
297
0
        time_t now, nextschedule = 0;
298
299
0
        time(&now);
300
301
0
        for( int i = 0; i < vlm->i_schedule; i++ )
302
0
        {
303
0
            time_t real_date = vlm->schedule[i]->date;
304
305
0
            if( vlm->schedule[i]->b_enabled )
306
0
            {
307
0
                bool b_now = false;
308
0
                if( vlm->schedule[i]->date == 0 ) // now !
309
0
                {
310
0
                    vlm->schedule[i]->date = now;
311
0
                    real_date = now;
312
0
                    b_now = true;
313
0
                }
314
0
                else if( vlm->schedule[i]->period != 0 )
315
0
                {
316
0
                    int j = 0;
317
0
                    while( ((vlm->schedule[i]->date + j *
318
0
                             vlm->schedule[i]->period) <= lastcheck) &&
319
0
                           ( vlm->schedule[i]->i_repeat > j ||
320
0
                             vlm->schedule[i]->i_repeat < 0 ) )
321
0
                    {
322
0
                        j++;
323
0
                    }
324
325
0
                    real_date = vlm->schedule[i]->date + j *
326
0
                        vlm->schedule[i]->period;
327
0
                }
328
329
0
                if( real_date <= now )
330
0
                {
331
0
                    if( real_date > lastcheck || b_now )
332
0
                    {
333
0
                        for( int j = 0; j < vlm->schedule[i]->i_command; j++ )
334
0
                        {
335
0
                            TAB_APPEND( i_scheduled_commands,
336
0
                                        ppsz_scheduled_commands,
337
0
                                        strdup(vlm->schedule[i]->command[j] ) );
338
0
                        }
339
0
                    }
340
0
                }
341
0
                else if( nextschedule == 0 || real_date < nextschedule )
342
0
                {
343
0
                    nextschedule = real_date;
344
0
                }
345
0
            }
346
0
        }
347
348
0
        while( i_scheduled_commands )
349
0
        {
350
0
            vlm_message_t *message = NULL;
351
0
            char *psz_command = ppsz_scheduled_commands[0];
352
0
            ExecuteCommand( vlm, psz_command,&message );
353
354
            /* for now, drop the message */
355
0
            vlm_MessageDelete( message );
356
0
            TAB_REMOVE( i_scheduled_commands,
357
0
                        ppsz_scheduled_commands,
358
0
                        psz_command );
359
0
            free( psz_command );
360
0
        }
361
362
0
        lastcheck = now;
363
0
        vlc_mutex_unlock( &vlm->lock );
364
365
0
        vlc_mutex_lock( &vlm->lock_manage );
366
367
0
        while( !vlm->input_state_changed && !(exiting = vlm->exiting) )
368
0
        {
369
0
            if( nextschedule )
370
0
            {
371
0
                if( vlc_cond_timedwait_daytime( &vlm->wait_manage,
372
0
                                                &vlm->lock_manage,
373
0
                                                nextschedule ) )
374
0
                    break;
375
0
            }
376
0
            else
377
0
                vlc_cond_wait( &vlm->wait_manage, &vlm->lock_manage );
378
0
        }
379
0
        vlm->input_state_changed = false;
380
0
        vlc_mutex_unlock( &vlm->lock_manage );
381
0
    }
382
0
    while( !exiting );
383
384
0
    return NULL;
385
0
}
386
387
/* New API
388
 */
389
/*
390
typedef struct
391
{
392
    struct
393
    {
394
        int        i_count;
395
        bool b_playing;
396
        int        i_playing_index;
397
    } broadcast;
398
399
} vlm_media_status_t;
400
*/
401
402
/* */
403
static vlm_media_sys_t *vlm_ControlMediaGetById( vlm_t *p_vlm, int64_t id )
404
0
{
405
0
    for( int i = 0; i < p_vlm->i_media; i++ )
406
0
    {
407
0
        if( p_vlm->media[i]->cfg.id == id )
408
0
            return p_vlm->media[i];
409
0
    }
410
0
    return NULL;
411
0
}
412
static vlm_media_sys_t *vlm_ControlMediaGetByName( vlm_t *p_vlm, const char *psz_name )
413
0
{
414
0
    for( int i = 0; i < p_vlm->i_media; i++ )
415
0
    {
416
0
        if( !strcmp( p_vlm->media[i]->cfg.psz_name, psz_name ) )
417
0
            return p_vlm->media[i];
418
0
    }
419
0
    return NULL;
420
0
}
421
static int vlm_MediaDescriptionCheck( vlm_t *p_vlm, vlm_media_t *p_cfg )
422
0
{
423
0
    if( !p_cfg || !p_cfg->psz_name ||
424
0
        !strcmp( p_cfg->psz_name, "all" ) || !strcmp( p_cfg->psz_name, "media" ) || !strcmp( p_cfg->psz_name, "schedule" ) )
425
0
        return VLC_EGENERIC;
426
427
0
    for( int i = 0; i < p_vlm->i_media; i++ )
428
0
    {
429
0
        if( p_vlm->media[i]->cfg.id == p_cfg->id )
430
0
            continue;
431
0
        if( !strcmp( p_vlm->media[i]->cfg.psz_name, p_cfg->psz_name ) )
432
0
            return VLC_EGENERIC;
433
0
    }
434
0
    return VLC_SUCCESS;
435
0
}
436
437
438
/* Called after a media description is changed/added */
439
static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
440
0
{
441
0
    vlm_media_t *p_cfg = &p_media->cfg;
442
443
    /* TODO start media if needed */
444
445
    /* TODO add support of var vlm_media_broadcast */
446
447
0
    vlm_SendEventMediaChanged( p_vlm, p_cfg->id, p_cfg->psz_name );
448
0
    return VLC_SUCCESS;
449
0
}
450
static int vlm_ControlMediaChange( vlm_t *p_vlm, vlm_media_t *p_cfg )
451
0
{
452
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, p_cfg->id );
453
454
    /* */
455
0
    if( !p_media || vlm_MediaDescriptionCheck( p_vlm, p_cfg ) )
456
0
        return VLC_EGENERIC;
457
458
0
    if( 0 )
459
0
    {
460
        /* TODO check what are the changes being done (stop instance if needed) */
461
0
    }
462
463
0
    vlm_media_Clean( &p_media->cfg );
464
0
    vlm_media_Copy( &p_media->cfg, p_cfg );
465
466
0
    return vlm_OnMediaUpdate( p_vlm, p_media );
467
0
}
468
469
static int vlm_ControlMediaAdd( vlm_t *p_vlm, vlm_media_t *p_cfg, int64_t *p_id )
470
0
{
471
0
    vlm_media_sys_t *p_media;
472
473
0
    if( vlm_MediaDescriptionCheck( p_vlm, p_cfg ) || vlm_ControlMediaGetByName( p_vlm, p_cfg->psz_name ) )
474
0
    {
475
0
        msg_Err( p_vlm, "invalid media description" );
476
0
        return VLC_EGENERIC;
477
0
    }
478
479
0
    p_media = malloc(sizeof(*p_media));
480
0
    if( !p_media )
481
0
        return VLC_ENOMEM;
482
483
0
    p_media->vlm = p_vlm;
484
485
0
    vlm_media_Copy( &p_media->cfg, p_cfg );
486
0
    p_media->cfg.id = p_vlm->i_id++;
487
    /* FIXME do we do something here if enabled is true ? */
488
489
0
    TAB_INIT( p_media->i_instance, p_media->instance );
490
491
    /* */
492
0
    TAB_APPEND( p_vlm->i_media, p_vlm->media, p_media );
493
494
0
    if( p_id )
495
0
        *p_id = p_media->cfg.id;
496
497
    /* */
498
0
    vlm_SendEventMediaAdded( p_vlm, p_media->cfg.id, p_media->cfg.psz_name );
499
0
    return vlm_OnMediaUpdate( p_vlm, p_media );
500
0
}
501
502
static int vlm_ControlMediaDel( vlm_t *p_vlm, int64_t id )
503
0
{
504
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
505
506
0
    if( !p_media )
507
0
        return VLC_EGENERIC;
508
509
0
    while( p_media->i_instance > 0 )
510
0
        vlm_ControlInternal( p_vlm, VLM_STOP_MEDIA_INSTANCE, id, p_media->instance[0]->psz_name );
511
512
    /* */
513
0
    vlm_SendEventMediaRemoved( p_vlm, id, p_media->cfg.psz_name );
514
515
0
    vlm_media_Clean( &p_media->cfg );
516
517
0
    TAB_REMOVE( p_vlm->i_media, p_vlm->media, p_media );
518
0
    free(p_media);
519
520
0
    return VLC_SUCCESS;
521
0
}
522
523
static int vlm_ControlMediaGets( vlm_t *p_vlm, vlm_media_t ***ppp_dsc, int *pi_dsc )
524
0
{
525
0
    vlm_media_t **pp_dsc;
526
0
    int                     i_dsc;
527
528
0
    TAB_INIT( i_dsc, pp_dsc );
529
0
    for( int i = 0; i < p_vlm->i_media; i++ )
530
0
    {
531
0
        vlm_media_t *p_dsc = vlm_media_Duplicate( &p_vlm->media[i]->cfg );
532
0
        TAB_APPEND( i_dsc, pp_dsc, p_dsc );
533
0
    }
534
535
0
    *ppp_dsc = pp_dsc;
536
0
    *pi_dsc = i_dsc;
537
538
0
    return VLC_SUCCESS;
539
0
}
540
static int vlm_ControlMediaClear( vlm_t *p_vlm )
541
0
{
542
0
    while( p_vlm->i_media > 0 )
543
0
        vlm_ControlMediaDel( p_vlm, p_vlm->media[0]->cfg.id );
544
545
0
    return VLC_SUCCESS;
546
0
}
547
static int vlm_ControlMediaGet( vlm_t *p_vlm, int64_t id, vlm_media_t **pp_dsc )
548
0
{
549
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
550
0
    if( !p_media )
551
0
        return VLC_EGENERIC;
552
553
0
    *pp_dsc = vlm_media_Duplicate( &p_media->cfg );
554
0
    return VLC_SUCCESS;
555
0
}
556
static int vlm_ControlMediaGetId( vlm_t *p_vlm, const char *psz_name, int64_t *p_id )
557
0
{
558
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetByName( p_vlm, psz_name );
559
0
    if( !p_media )
560
0
        return VLC_EGENERIC;
561
562
0
    *p_id = p_media->cfg.id;
563
0
    return VLC_SUCCESS;
564
0
}
565
566
static vlm_media_instance_sys_t *vlm_ControlMediaInstanceGetByName( vlm_media_sys_t *p_media, const char *psz_id )
567
0
{
568
0
    for( int i = 0; i < p_media->i_instance; i++ )
569
0
    {
570
0
        const char *psz = p_media->instance[i]->psz_name;
571
0
        if( ( psz == NULL && psz_id == NULL ) ||
572
0
            ( psz && psz_id && !strcmp( psz, psz_id ) ) )
573
0
            return p_media->instance[i];
574
0
    }
575
0
    return NULL;
576
0
}
577
578
static vlm_media_instance_sys_t *vlm_MediaInstanceNew( vlm_media_sys_t *p_media, const char *psz_name )
579
0
{
580
0
    vlm_media_instance_sys_t *p_instance = calloc( 1, sizeof(vlm_media_instance_sys_t) );
581
0
    if( !p_instance )
582
0
        return NULL;
583
584
0
    p_instance->psz_name = NULL;
585
0
    if( psz_name )
586
0
        p_instance->psz_name = strdup( psz_name );
587
588
0
    p_instance->p_item = input_item_New( NULL, NULL );
589
0
    if (!p_instance->p_item)
590
0
        goto error;
591
592
0
    p_instance->i_index = 0;
593
594
0
    p_instance->player = vlc_player_New(VLC_OBJECT(p_media->vlm),
595
0
                                        VLC_PLAYER_LOCK_NORMAL);
596
0
    if (!p_instance->player)
597
0
        goto error;
598
599
0
    static struct vlc_player_cbs cbs = {
600
0
        .on_state_changed = player_on_state_changed,
601
0
    };
602
0
    vlc_player_Lock(p_instance->player);
603
0
    p_instance->listener =
604
0
        vlc_player_AddListener(p_instance->player, &cbs, p_media);
605
0
    vlc_player_Unlock(p_instance->player);
606
607
0
    if (!p_instance->listener)
608
0
        goto error;
609
0
    return p_instance;
610
611
0
error:
612
0
    if (p_instance->player)
613
0
        vlc_player_Delete(p_instance->player);
614
0
    if (p_instance->p_item)
615
0
        input_item_Release(p_instance->p_item);
616
0
    free(p_instance->psz_name);
617
0
    free(p_instance);
618
0
    return NULL;
619
0
}
620
static void vlm_MediaInstanceDelete( vlm_t *p_vlm, int64_t id, vlm_media_instance_sys_t *p_instance, vlm_media_sys_t *p_media )
621
0
{
622
0
    vlc_player_t *player = p_instance->player;
623
624
0
    vlc_player_Lock(player);
625
0
    vlc_player_RemoveListener(player, p_instance->listener);
626
0
    vlc_player_Stop(player);
627
0
    bool had_media = vlc_player_GetCurrentMedia(player);
628
0
    vlc_player_Unlock(player);
629
0
    vlc_player_Delete(player);
630
631
0
    if (had_media)
632
0
        vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
633
634
0
    TAB_REMOVE( p_media->i_instance, p_media->instance, p_instance );
635
0
    input_item_Release( p_instance->p_item );
636
0
    free( p_instance->psz_name );
637
0
    free( p_instance );
638
0
}
639
640
641
static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *psz_id, int i_input_index )
642
0
{
643
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
644
0
    vlm_media_instance_sys_t *p_instance;
645
646
0
    if( !p_media || !p_media->cfg.b_enabled || p_media->cfg.i_input <= 0 )
647
0
        return VLC_EGENERIC;
648
649
0
    if( i_input_index < 0 || i_input_index >= p_media->cfg.i_input )
650
0
        return VLC_EGENERIC;
651
652
0
    p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
653
0
    if( !p_instance )
654
0
    {
655
0
        vlm_media_t *p_cfg = &p_media->cfg;
656
657
0
        p_instance = vlm_MediaInstanceNew( p_media, psz_id );
658
0
        if( !p_instance )
659
0
            return VLC_ENOMEM;
660
661
0
        if( p_cfg->psz_output != NULL )
662
0
        {
663
0
            char *psz_buffer;
664
0
            if( asprintf( &psz_buffer, "sout=%s", p_cfg->psz_output ) != -1 )
665
0
            {
666
0
                input_item_AddOption( p_instance->p_item, psz_buffer, VLC_INPUT_OPTION_TRUSTED );
667
0
                free( psz_buffer );
668
0
            }
669
0
        }
670
671
0
        for( int i = 0; i < p_cfg->i_option; i++ )
672
0
            input_item_AddOption( p_instance->p_item, p_cfg->ppsz_option[i], VLC_INPUT_OPTION_TRUSTED );
673
0
        TAB_APPEND( p_media->i_instance, p_media->instance, p_instance );
674
0
    }
675
676
    /* Stop old instance */
677
0
    vlc_player_t *player = p_instance->player;
678
0
    vlc_player_Lock(player);
679
0
    if (vlc_player_GetCurrentMedia(player))
680
0
    {
681
0
        if( p_instance->i_index == i_input_index )
682
0
        {
683
0
            if (vlc_player_IsPaused(player))
684
0
                vlc_player_Resume(player);
685
0
            return VLC_SUCCESS;
686
0
        }
687
688
0
        vlc_player_Stop(player);
689
0
        vlc_player_Unlock(player);
690
0
        vlm_SendEventMediaInstanceStopped( p_vlm, id, p_media->cfg.psz_name );
691
0
        vlc_player_Lock(player);
692
0
    }
693
694
    /* Start new one */
695
0
    p_instance->i_index = i_input_index;
696
0
    if( strstr( p_media->cfg.ppsz_input[p_instance->i_index], "://" ) == NULL )
697
0
    {
698
0
        char *psz_uri = vlc_path2uri(
699
0
                          p_media->cfg.ppsz_input[p_instance->i_index], NULL );
700
0
        input_item_SetURI( p_instance->p_item, psz_uri ) ;
701
0
        free( psz_uri );
702
0
    }
703
0
    else
704
0
        input_item_SetURI( p_instance->p_item, p_media->cfg.ppsz_input[p_instance->i_index] ) ;
705
706
0
    vlc_player_SetCurrentMedia(player, p_instance->p_item);
707
0
    vlc_player_Start(player);
708
0
    vlc_player_Unlock(player);
709
0
    p_instance->finished = false;
710
711
0
    vlm_SendEventMediaInstanceStarted( p_vlm, id, p_media->cfg.psz_name );
712
713
0
    return VLC_SUCCESS;
714
0
}
715
716
static int vlm_ControlMediaInstanceStop( vlm_t *p_vlm, int64_t id, const char *psz_id )
717
0
{
718
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
719
0
    vlm_media_instance_sys_t *p_instance;
720
721
0
    if( !p_media )
722
0
        return VLC_EGENERIC;
723
724
0
    p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
725
0
    if( !p_instance )
726
0
        return VLC_EGENERIC;
727
728
0
    vlm_MediaInstanceDelete( p_vlm, id, p_instance, p_media );
729
730
0
    return VLC_SUCCESS;
731
0
}
732
static int vlm_ControlMediaInstancePause( vlm_t *p_vlm, int64_t id, const char *psz_id )
733
0
{
734
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
735
0
    vlm_media_instance_sys_t *p_instance;
736
0
    if( !p_media )
737
0
        return VLC_EGENERIC;
738
739
0
    p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
740
0
    if( !p_instance )
741
0
        return VLC_EGENERIC;
742
743
0
    vlc_player_Lock(p_instance->player);
744
0
    vlc_player_TogglePause(p_instance->player);
745
0
    vlc_player_Unlock(p_instance->player);
746
747
0
    return VLC_SUCCESS;
748
0
}
749
static int vlm_ControlMediaInstanceGetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t *pi_time, double *pd_position )
750
0
{
751
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
752
0
    vlm_media_instance_sys_t *p_instance;
753
754
0
    if( !p_media )
755
0
        return VLC_EGENERIC;
756
757
0
    p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
758
0
    if( !p_instance )
759
0
        return VLC_EGENERIC;
760
761
0
    vlc_player_Lock(p_instance->player);
762
0
    if( pi_time )
763
0
        *pi_time = US_FROM_VLC_TICK(vlc_player_GetTime(p_instance->player));
764
0
    if( pd_position )
765
0
        *pd_position = vlc_player_GetPosition(p_instance->player);
766
0
    vlc_player_Unlock(p_instance->player);
767
0
    return VLC_SUCCESS;
768
0
}
769
static int vlm_ControlMediaInstanceSetTimePosition( vlm_t *p_vlm, int64_t id, const char *psz_id, int64_t i_time, double d_position )
770
0
{
771
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
772
0
    vlm_media_instance_sys_t *p_instance;
773
774
0
    if( !p_media )
775
0
        return VLC_EGENERIC;
776
777
0
    p_instance = vlm_ControlMediaInstanceGetByName( p_media, psz_id );
778
0
    if( !p_instance )
779
0
        return VLC_EGENERIC;
780
781
0
    vlc_player_Lock(p_instance->player);
782
0
    if( i_time >= 0 )
783
0
        vlc_player_SetTime(p_instance->player, VLC_TICK_FROM_US(i_time));
784
0
    else if( d_position >= 0 && d_position <= 100 )
785
0
        vlc_player_SetPosition(p_instance->player, d_position);
786
0
    vlc_player_Unlock(p_instance->player);
787
0
    return VLC_SUCCESS;
788
0
}
789
790
static int vlm_ControlMediaInstanceGets( vlm_t *p_vlm, int64_t id, vlm_media_instance_t ***ppp_idsc, int *pi_instance )
791
0
{
792
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
793
0
    vlm_media_instance_t **pp_idsc;
794
0
    int                              i_idsc;
795
796
0
    if( !p_media )
797
0
        return VLC_EGENERIC;
798
799
0
    TAB_INIT( i_idsc, pp_idsc );
800
0
    for( int i = 0; i < p_media->i_instance; i++ )
801
0
    {
802
0
        vlm_media_instance_sys_t *p_instance = p_media->instance[i];
803
0
        vlm_media_instance_t *p_idsc = vlm_media_instance_New();
804
0
        if( p_instance->psz_name )
805
0
            p_idsc->psz_name = strdup( p_instance->psz_name );
806
0
        vlc_player_Lock(p_instance->player);
807
0
        p_idsc->i_time = US_FROM_VLC_TICK(vlc_player_GetTime(p_instance->player));
808
0
        p_idsc->i_length = US_FROM_VLC_TICK(vlc_player_GetLength(p_instance->player));
809
0
        p_idsc->d_position = vlc_player_GetPosition(p_instance->player);
810
0
        p_idsc->b_paused = vlc_player_IsPaused(p_instance->player);
811
0
        p_idsc->f_rate = vlc_player_GetRate(p_instance->player);
812
0
        vlc_player_Unlock(p_instance->player);
813
814
0
        TAB_APPEND( i_idsc, pp_idsc, p_idsc );
815
0
    }
816
0
    *ppp_idsc = pp_idsc;
817
0
    *pi_instance = i_idsc;
818
0
    return VLC_SUCCESS;
819
0
}
820
821
static int vlm_ControlMediaInstanceClear( vlm_t *p_vlm, int64_t id )
822
0
{
823
0
    vlm_media_sys_t *p_media = vlm_ControlMediaGetById( p_vlm, id );
824
825
0
    if( !p_media )
826
0
        return VLC_EGENERIC;
827
828
0
    while( p_media->i_instance > 0 )
829
0
        vlm_ControlMediaInstanceStop( p_vlm, id, p_media->instance[0]->psz_name );
830
831
0
    return VLC_SUCCESS;
832
0
}
833
834
static int vlm_ControlScheduleClear( vlm_t *p_vlm )
835
0
{
836
0
    while( p_vlm->i_schedule > 0 )
837
0
        vlm_ScheduleDelete( p_vlm, p_vlm->schedule[0] );
838
839
0
    return VLC_SUCCESS;
840
0
}
841
842
static int vlm_vaControlInternal( vlm_t *p_vlm, int i_query, va_list args )
843
0
{
844
0
    vlm_media_t *p_dsc;
845
0
    vlm_media_t **pp_dsc;
846
0
    vlm_media_t ***ppp_dsc;
847
0
    vlm_media_instance_t ***ppp_idsc;
848
0
    const char *psz_id;
849
0
    int64_t *p_id;
850
0
    int64_t id;
851
0
    int i_int;
852
0
    int *pi_int;
853
854
0
    int64_t *pi_i64;
855
0
    int64_t i_i64;
856
0
    double *pd_double;
857
0
    double d_double;
858
859
0
    switch( i_query )
860
0
    {
861
    /* Media control */
862
0
    case VLM_GET_MEDIAS:
863
0
        ppp_dsc = (vlm_media_t ***)va_arg( args, vlm_media_t *** );
864
0
        pi_int = (int *)va_arg( args, int * );
865
0
        return vlm_ControlMediaGets( p_vlm, ppp_dsc, pi_int );
866
867
0
    case VLM_CLEAR_MEDIAS:
868
0
        return vlm_ControlMediaClear( p_vlm );
869
870
0
    case VLM_CHANGE_MEDIA:
871
0
        p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
872
0
        return vlm_ControlMediaChange( p_vlm, p_dsc );
873
874
0
    case VLM_ADD_MEDIA:
875
0
        p_dsc = (vlm_media_t*)va_arg( args, vlm_media_t * );
876
0
        p_id = (int64_t*)va_arg( args, int64_t * );
877
0
        return vlm_ControlMediaAdd( p_vlm, p_dsc, p_id );
878
879
0
    case VLM_DEL_MEDIA:
880
0
        id = (int64_t)va_arg( args, int64_t );
881
0
        return vlm_ControlMediaDel( p_vlm, id );
882
883
0
    case VLM_GET_MEDIA:
884
0
        id = (int64_t)va_arg( args, int64_t );
885
0
        pp_dsc = (vlm_media_t **)va_arg( args, vlm_media_t ** );
886
0
        return vlm_ControlMediaGet( p_vlm, id, pp_dsc );
887
888
0
    case VLM_GET_MEDIA_ID:
889
0
        psz_id = (const char*)va_arg( args, const char * );
890
0
        p_id = (int64_t*)va_arg( args, int64_t * );
891
0
        return vlm_ControlMediaGetId( p_vlm, psz_id, p_id );
892
893
894
    /* Media instance control */
895
0
    case VLM_GET_MEDIA_INSTANCES:
896
0
        id = (int64_t)va_arg( args, int64_t );
897
0
        ppp_idsc = (vlm_media_instance_t ***)va_arg( args, vlm_media_instance_t *** );
898
0
        pi_int = (int *)va_arg( args, int *);
899
0
        return vlm_ControlMediaInstanceGets( p_vlm, id, ppp_idsc, pi_int );
900
901
0
    case VLM_CLEAR_MEDIA_INSTANCES:
902
0
        id = (int64_t)va_arg( args, int64_t );
903
0
        return vlm_ControlMediaInstanceClear( p_vlm, id );
904
905
906
0
    case VLM_START_MEDIA_BROADCAST_INSTANCE:
907
0
        id = (int64_t)va_arg( args, int64_t );
908
0
        psz_id = (const char*)va_arg( args, const char* );
909
0
        i_int = (int)va_arg( args, int );
910
0
        return vlm_ControlMediaInstanceStart( p_vlm, id, psz_id, i_int );
911
912
0
    case VLM_STOP_MEDIA_INSTANCE:
913
0
        id = (int64_t)va_arg( args, int64_t );
914
0
        psz_id = (const char*)va_arg( args, const char* );
915
0
        return vlm_ControlMediaInstanceStop( p_vlm, id, psz_id );
916
917
0
    case VLM_PAUSE_MEDIA_INSTANCE:
918
0
        id = (int64_t)va_arg( args, int64_t );
919
0
        psz_id = (const char*)va_arg( args, const char* );
920
0
        return vlm_ControlMediaInstancePause( p_vlm, id, psz_id );
921
922
0
    case VLM_GET_MEDIA_INSTANCE_TIME:
923
0
        id = (int64_t)va_arg( args, int64_t );
924
0
        psz_id = (const char*)va_arg( args, const char* );
925
0
        pi_i64 = (int64_t*)va_arg( args, int64_t * );
926
0
        return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, pi_i64, NULL );
927
0
    case VLM_GET_MEDIA_INSTANCE_POSITION:
928
0
        id = (int64_t)va_arg( args, int64_t );
929
0
        psz_id = (const char*)va_arg( args, const char* );
930
0
        pd_double = (double*)va_arg( args, double* );
931
0
        return vlm_ControlMediaInstanceGetTimePosition( p_vlm, id, psz_id, NULL, pd_double );
932
933
0
    case VLM_SET_MEDIA_INSTANCE_TIME:
934
0
        id = (int64_t)va_arg( args, int64_t );
935
0
        psz_id = (const char*)va_arg( args, const char* );
936
0
        i_i64 = (int64_t)va_arg( args, int64_t);
937
0
        return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, i_i64, -1 );
938
0
    case VLM_SET_MEDIA_INSTANCE_POSITION:
939
0
        id = (int64_t)va_arg( args, int64_t );
940
0
        psz_id = (const char*)va_arg( args, const char* );
941
0
        d_double = (double)va_arg( args, double );
942
0
        return vlm_ControlMediaInstanceSetTimePosition( p_vlm, id, psz_id, -1, d_double );
943
944
0
    case VLM_CLEAR_SCHEDULES:
945
0
        return vlm_ControlScheduleClear( p_vlm );
946
947
0
    default:
948
0
        msg_Err( p_vlm, "unknown VLM query" );
949
0
        return VLC_EGENERIC;
950
0
    }
951
0
}
952
953
int vlm_ControlInternal( vlm_t *p_vlm, int i_query, ... )
954
0
{
955
0
    va_list args;
956
0
    int     i_result;
957
958
0
    va_start( args, i_query );
959
0
    i_result = vlm_vaControlInternal( p_vlm, i_query, args );
960
0
    va_end( args );
961
962
0
    return i_result;
963
0
}
964
965
int vlm_Control( vlm_t *p_vlm, int i_query, ... )
966
0
{
967
0
    va_list args;
968
0
    int     i_result;
969
970
0
    va_start( args, i_query );
971
972
0
    vlc_mutex_lock( &p_vlm->lock );
973
0
    i_result = vlm_vaControlInternal( p_vlm, i_query, args );
974
0
    vlc_mutex_unlock( &p_vlm->lock );
975
976
0
    va_end( args );
977
978
0
    return i_result;
979
0
}