event.c 11.9 KB
Newer Older
Filippo Carone's avatar
Filippo Carone committed
1
/*****************************************************************************
2
 * event.c: New libvlc event control API
Filippo Carone's avatar
Filippo Carone committed
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2007-2010 VLC authors and VideoLAN
Filippo Carone's avatar
Filippo Carone committed
5 6 7
 * $Id $
 *
 * Authors: Filippo Carone <filippo@carone.org>
8
 *          Pierre d'Herbemont <pdherbemont # videolan.org>
Filippo Carone's avatar
Filippo Carone committed
9
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Filippo Carone's avatar
Filippo Carone committed
13 14 15 16
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Filippo Carone's avatar
Filippo Carone committed
19
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser 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.
Filippo Carone's avatar
Filippo Carone committed
23 24
 *****************************************************************************/

25 26 27 28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <assert.h>
30
#include <errno.h>
31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
#include <vlc/libvlc.h>
#include "libvlc_internal.h"

#include <vlc_common.h>

/*
 * Event Handling
 */

/* Example usage
 *
 * struct libvlc_cool_object_t
 * {
 *        ...
 *        libvlc_event_manager_t * p_event_manager;
 *        ...
 * }
 *
 * libvlc_my_cool_object_new()
 * {
 *        ...
 *        p_self->p_event_manager = libvlc_event_manager_new( p_self )
 *        libvlc_event_manager_register_event_type(p_self->p_event_manager,
 *                libvlc_MyCoolObjectDidSomething, p_e)
 *        ...
 * }
 *
 * libvlc_my_cool_object_release()
 * {
 *         ...
 *         libvlc_event_manager_release( p_self->p_event_manager );
 *         ...
 * }
 *
 * libvlc_my_cool_object_do_something()
 * {
 *        ...
 *        libvlc_event_t event;
 *        event.type = libvlc_MyCoolObjectDidSomething;
 *        event.u.my_cool_object_did_something.what_it_did = kSomething;
 *        libvlc_event_send( p_self->p_event_manager, &event );
 * }
 * */

typedef struct libvlc_event_listener_t
{
    libvlc_event_type_t event_type;
    void *              p_user_data;
    libvlc_callback_t   pf_callback;
} libvlc_event_listener_t;

typedef struct libvlc_event_manager_t
{
    void * p_obj;
    vlc_array_t listeners_groups;
87
    vlc_mutex_t lock;
88 89
} libvlc_event_sender_t;

90 91 92 93 94
typedef struct libvlc_event_listeners_group_t
{
    libvlc_event_type_t event_type;
    vlc_array_t listeners;
} libvlc_event_listeners_group_t;
Filippo Carone's avatar
Filippo Carone committed
95

96 97 98
/*
 * Internal libvlc functions
 */
Filippo Carone's avatar
Filippo Carone committed
99

100
/**************************************************************************
101
 *       libvlc_event_manager_new (internal) :
102
 *
103
 * Init an object's event manager.
104
 **************************************************************************/
105
libvlc_event_manager_t *
106
libvlc_event_manager_new( void * p_obj )
107
{
108
    libvlc_event_manager_t * p_em;
109

110 111 112
    p_em = malloc(sizeof( libvlc_event_manager_t ));
    if( !p_em )
    {
113
        libvlc_printerr( "Not enough memory" );
114 115
        return NULL;
    }
116

117 118
    p_em->p_obj = p_obj;

119
    vlc_array_init( &p_em->listeners_groups );
120
    vlc_mutex_init_recursive(&p_em->lock);
121
    return p_em;
122 123
}

124
/**************************************************************************
125
 *       libvlc_event_manager_release (internal) :
126
 *
127
 * Release an object's event manager.
128
 **************************************************************************/
129
void libvlc_event_manager_release( libvlc_event_manager_t * p_em )
130
{
131 132
    libvlc_event_listeners_group_t * p_lg;
    int i,j ;
133

134
    vlc_mutex_destroy(&p_em->lock);
135

136 137 138 139 140
    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
    {
        p_lg = vlc_array_item_at_index( &p_em->listeners_groups, i );

        for( j = 0; j < vlc_array_count(&p_lg->listeners); j++)
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
141
            free( vlc_array_item_at_index( &p_lg->listeners, j ) );
142

143 144 145 146
        vlc_array_clear( &p_lg->listeners );
        free( p_lg );
    }
    vlc_array_clear( &p_em->listeners_groups );
147
    free( p_em );
148 149
}

150
/**************************************************************************
151
 *       libvlc_event_manager_register_event_type (internal) :
152
 *
153
 * Init an object's event manager.
154
 **************************************************************************/
155
void libvlc_event_manager_register_event_type(
156
        libvlc_event_manager_t * p_em,
157
        libvlc_event_type_t event_type )
158
{
159
    libvlc_event_listeners_group_t * listeners_group;
160
    listeners_group = xmalloc(sizeof(libvlc_event_listeners_group_t));
161
    listeners_group->event_type = event_type;
162
    vlc_array_init( &listeners_group->listeners );
163

164
    vlc_mutex_lock(&p_em->lock);
165
    vlc_array_append( &p_em->listeners_groups, listeners_group );
166
    vlc_mutex_unlock(&p_em->lock);
167
}
168

169
/**************************************************************************
170
 *       libvlc_event_send (internal) :
171
 *
172
 * Send a callback.
173
 **************************************************************************/
174 175
void libvlc_event_send( libvlc_event_manager_t * p_em,
                        libvlc_event_t * p_event )
176
{
177
    int i;
178

179 180 181
    /* Fill event with the sending object now */
    p_event->p_obj = p_em->p_obj;

182
    vlc_mutex_lock(&p_em->lock);
183 184
    for( i = 0; i < vlc_array_count(&p_em->listeners_groups); i++)
    {
185
        libvlc_event_listeners_group_t *listeners_group;
186

187 188 189
        listeners_group = vlc_array_item_at_index(&p_em->listeners_groups, i);
        if (listeners_group->event_type != p_event->type)
            continue;
190

191
        for (int j = 0; j < vlc_array_count(&listeners_group->listeners); j++)
192
        {
193 194 195 196
            libvlc_event_listener_t *listener;

            listener = vlc_array_item_at_index(&listeners_group->listeners, j);
            listener->pf_callback(p_event, listener->p_user_data);
197
        }
198
        break;
199
    }
200
    vlc_mutex_unlock(&p_em->lock);
201 202
}

203 204 205 206
/*
 * Public libvlc functions
 */

207 208 209 210 211 212 213 214 215 216 217 218
#define DEF( a ) { libvlc_##a, #a, },

typedef struct
{
    int type;
    const char name[40];
} event_name_t;

static const event_name_t event_list[] = {
    DEF(MediaMetaChanged)
    DEF(MediaSubItemAdded)
    DEF(MediaDurationChanged)
219
    DEF(MediaParsedChanged)
220 221
    DEF(MediaFreed)
    DEF(MediaStateChanged)
222
    DEF(MediaSubItemTreeAdded)
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

    DEF(MediaPlayerMediaChanged)
    DEF(MediaPlayerNothingSpecial)
    DEF(MediaPlayerOpening)
    DEF(MediaPlayerBuffering)
    DEF(MediaPlayerPlaying)
    DEF(MediaPlayerPaused)
    DEF(MediaPlayerStopped)
    DEF(MediaPlayerForward)
    DEF(MediaPlayerBackward)
    DEF(MediaPlayerEndReached)
    DEF(MediaPlayerEncounteredError)
    DEF(MediaPlayerTimeChanged)
    DEF(MediaPlayerPositionChanged)
    DEF(MediaPlayerSeekableChanged)
    DEF(MediaPlayerPausableChanged)
    DEF(MediaPlayerTitleChanged)
    DEF(MediaPlayerSnapshotTaken)
    DEF(MediaPlayerLengthChanged)
242
    DEF(MediaPlayerVout)
243
    DEF(MediaPlayerScrambledChanged)
244 245 246
    DEF(MediaPlayerESAdded)
    DEF(MediaPlayerESDeleted)
    DEF(MediaPlayerESSelected)
247 248
    DEF(MediaPlayerCorked)
    DEF(MediaPlayerUncorked)
249 250
    DEF(MediaPlayerMuted)
    DEF(MediaPlayerUnmuted)
251
    DEF(MediaPlayerAudioVolume)
252
    DEF(MediaPlayerAudioDevice)
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

    DEF(MediaListItemAdded)
    DEF(MediaListWillAddItem)
    DEF(MediaListItemDeleted)
    DEF(MediaListWillDeleteItem)

    DEF(MediaListViewItemAdded)
    DEF(MediaListViewWillAddItem)
    DEF(MediaListViewItemDeleted)
    DEF(MediaListViewWillDeleteItem)

    DEF(MediaListPlayerPlayed)
    DEF(MediaListPlayerNextItemSet)
    DEF(MediaListPlayerStopped)

    DEF(MediaDiscovererStarted)
    DEF(MediaDiscovererEnded)

    DEF(VlmMediaAdded)
    DEF(VlmMediaRemoved)
    DEF(VlmMediaChanged)
    DEF(VlmMediaInstanceStarted)
    DEF(VlmMediaInstanceStopped)
    DEF(VlmMediaInstanceStatusInit)
    DEF(VlmMediaInstanceStatusOpening)
278 279 280 281
    DEF(VlmMediaInstanceStatusPlaying)
    DEF(VlmMediaInstanceStatusPause)
    DEF(VlmMediaInstanceStatusEnd)
    DEF(VlmMediaInstanceStatusError)
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
};
#undef DEF

static const char unknown_event_name[] = "Unknown Event";

static int evcmp( const void *a, const void *b )
{
    return (*(const int *)a) - ((event_name_t *)b)->type;
}

const char * libvlc_event_type_name( int event_type )
{
    const event_name_t *p;

    p = bsearch( &event_type, event_list,
                 sizeof(event_list)/sizeof(event_list[0]), sizeof(*p),
                 evcmp );
    return p ? p->name : unknown_event_name;
}

302
/**************************************************************************
303
 *       event_attach (internal) :
304 305 306
 *
 * Add a callback for an event.
 **************************************************************************/
307
static
308 309
int event_attach( libvlc_event_manager_t * p_event_manager,
                  libvlc_event_type_t event_type,
310
                  libvlc_callback_t pf_callback, void *p_user_data )
Filippo Carone's avatar
Filippo Carone committed
311
{
312 313
    libvlc_event_listeners_group_t * listeners_group;
    libvlc_event_listener_t * listener;
314
    int i;
315

316
    listener = malloc(sizeof(libvlc_event_listener_t));
317 318
    if( unlikely(listener == NULL) )
        return ENOMEM;
319

320 321 322
    listener->event_type = event_type;
    listener->p_user_data = p_user_data;
    listener->pf_callback = pf_callback;
323

324
    vlc_mutex_lock(&p_event_manager->lock);
325 326 327
    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++ )
    {
        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
328 329
        if( listeners_group->event_type == listener->event_type )
        {
330
            vlc_array_append( &listeners_group->listeners, listener );
331
            vlc_mutex_unlock(&p_event_manager->lock);
332
            return 0;
333
        }
334
    }
335
    vlc_mutex_unlock(&p_event_manager->lock);
336

337
    free(listener);
338 339
    fprintf( stderr, "This object event manager doesn't know about '%s' events",
             libvlc_event_type_name(event_type) );
340
    vlc_assert_unreachable();
341
    return -1;
342 343 344 345 346 347 348
}

/**************************************************************************
 *       libvlc_event_attach (public) :
 *
 * Add a callback for an event.
 **************************************************************************/
349
int libvlc_event_attach( libvlc_event_manager_t * p_event_manager,
350 351
                         libvlc_event_type_t event_type,
                         libvlc_callback_t pf_callback,
352
                         void *p_user_data )
353
{
354
    return event_attach(p_event_manager, event_type, pf_callback, p_user_data);
Filippo Carone's avatar
Filippo Carone committed
355 356
}

357
/**************************************************************************
358
 *       libvlc_event_detach (public) :
359 360 361
 *
 * Remove a callback for an event.
 **************************************************************************/
362
void libvlc_event_detach( libvlc_event_manager_t *p_event_manager,
363 364
                                     libvlc_event_type_t event_type,
                                     libvlc_callback_t pf_callback,
365
                                     void *p_user_data )
Filippo Carone's avatar
Filippo Carone committed
366
{
367 368
    libvlc_event_listeners_group_t * listeners_group;
    libvlc_event_listener_t * listener;
369
    int i, j;
370
    bool found = false;
371

372
    vlc_mutex_lock(&p_event_manager->lock);
373 374 375
    for( i = 0; i < vlc_array_count(&p_event_manager->listeners_groups); i++)
    {
        listeners_group = vlc_array_item_at_index(&p_event_manager->listeners_groups, i);
376 377
        if( listeners_group->event_type == event_type )
        {
378
            for( j = 0; j < vlc_array_count(&listeners_group->listeners); j++)
379
            {
380
                listener = vlc_array_item_at_index(&listeners_group->listeners, j);
381 382 383 384 385 386
                if( listener->event_type == event_type &&
                    listener->pf_callback == pf_callback &&
                    listener->p_user_data == p_user_data )
                {
                    /* that's our listener */
                    free( listener );
387
                    vlc_array_remove( &listeners_group->listeners, j );
388 389
                    found = true;
                    break;
390
                }
391
            }
392
        }
393
    }
394
    vlc_mutex_unlock(&p_event_manager->lock);
395

396
    assert(found);
Filippo Carone's avatar
Filippo Carone committed
397
}