event.c 8.52 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
#include <vlc/libvlc.h>
#include "libvlc_internal.h"

#include <vlc_common.h>

/*
 * Event Handling
 */

/* Example usage
 *
 * struct libvlc_cool_object_t
 * {
 *        ...
46
 *        libvlc_event_manager_t event_manager;
47 48 49 50 51 52
 *        ...
 * }
 *
 * libvlc_my_cool_object_new()
 * {
 *        ...
53
 *        libvlc_event_manager_init(&p_self->event_manager, p_self)
54 55 56 57 58 59
 *        ...
 * }
 *
 * libvlc_my_cool_object_release()
 * {
 *         ...
60
 *         libvlc_event_manager_release(&p_self->event_manager);
61 62 63 64 65 66 67 68 69
 *         ...
 * }
 *
 * 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;
70
 *        libvlc_event_send(&p_self->event_manager, &event);
71 72 73 74 75 76 77 78 79 80
 * }
 * */

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;

81 82 83
/*
 * Internal libvlc functions
 */
Filippo Carone's avatar
Filippo Carone committed
84

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
void libvlc_event_manager_init(libvlc_event_manager_t *em, void *obj)
{
    em->p_obj = obj;
    vlc_array_init(&em->listeners);
    vlc_mutex_init_recursive(&em->lock);
}

void libvlc_event_manager_destroy(libvlc_event_manager_t *em)
{
    vlc_mutex_destroy(&em->lock);

    for (size_t i = 0; i < vlc_array_count(&em->listeners); i++)
        free(vlc_array_item_at_index(&em->listeners, i));

    vlc_array_clear(&em->listeners);
}

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

112 113
    p_em = malloc(sizeof( libvlc_event_manager_t ));
    if( !p_em )
114
        libvlc_printerr( "Not enough memory" );
115 116
    else
        libvlc_event_manager_init( p_em, p_obj );
117
    return p_em;
118 119
}

120
/**************************************************************************
121
 *       libvlc_event_manager_release (internal) :
122
 *
123
 * Release an object's event manager.
124
 **************************************************************************/
125
void libvlc_event_manager_release( libvlc_event_manager_t * p_em )
126
{
127
    libvlc_event_manager_destroy( p_em );
128
    free( p_em );
129 130
}

131
/**************************************************************************
132
 *       libvlc_event_send (internal) :
133
 *
134
 * Send a callback.
135
 **************************************************************************/
136 137
void libvlc_event_send( libvlc_event_manager_t * p_em,
                        libvlc_event_t * p_event )
138
{
139 140 141
    /* Fill event with the sending object now */
    p_event->p_obj = p_em->p_obj;

142
    vlc_mutex_lock(&p_em->lock);
143
    for (size_t i = 0; i < vlc_array_count(&p_em->listeners); i++)
144
    {
145
        libvlc_event_listener_t *listener;
146

147 148
        listener = vlc_array_item_at_index(&p_em->listeners, i);
        if (listener->event_type == p_event->type)
149
            listener->pf_callback(p_event, listener->p_user_data);
150
    }
151
    vlc_mutex_unlock(&p_em->lock);
152 153
}

154 155 156 157
/*
 * Public libvlc functions
 */

158 159 160 161 162 163 164 165 166 167 168 169
#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)
170
    DEF(MediaParsedChanged)
171 172
    DEF(MediaFreed)
    DEF(MediaStateChanged)
173
    DEF(MediaSubItemTreeAdded)
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

    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)
193
    DEF(MediaPlayerVout)
194
    DEF(MediaPlayerScrambledChanged)
195 196 197
    DEF(MediaPlayerESAdded)
    DEF(MediaPlayerESDeleted)
    DEF(MediaPlayerESSelected)
198 199
    DEF(MediaPlayerCorked)
    DEF(MediaPlayerUncorked)
200 201
    DEF(MediaPlayerMuted)
    DEF(MediaPlayerUnmuted)
202
    DEF(MediaPlayerAudioVolume)
203
    DEF(MediaPlayerAudioDevice)
204
    DEF(MediaPlayerChapterChanged)
205 206 207 208 209

    DEF(MediaListItemAdded)
    DEF(MediaListWillAddItem)
    DEF(MediaListItemDeleted)
    DEF(MediaListWillDeleteItem)
210
    DEF(MediaListEndReached)
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

    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)
231 232 233 234
    DEF(VlmMediaInstanceStatusPlaying)
    DEF(VlmMediaInstanceStatusPause)
    DEF(VlmMediaInstanceStatusEnd)
    DEF(VlmMediaInstanceStatusError)
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
};
#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;
}

255
/**************************************************************************
256
 *       libvlc_event_attach (public) :
257 258 259
 *
 * Add a callback for an event.
 **************************************************************************/
260 261
int libvlc_event_attach(libvlc_event_manager_t *em, libvlc_event_type_t type,
                        libvlc_callback_t callback, void *opaque)
Filippo Carone's avatar
Filippo Carone committed
262
{
263 264
    libvlc_event_listener_t *listener = malloc(sizeof (*listener));
    if (unlikely(listener == NULL))
265
        return ENOMEM;
266

267 268 269
    listener->event_type = type;
    listener->p_user_data = opaque;
    listener->pf_callback = callback;
270

271 272 273 274
    vlc_mutex_lock(&em->lock);
    vlc_array_append(&em->listeners, listener);
    vlc_mutex_unlock(&em->lock);
    return 0;
Filippo Carone's avatar
Filippo Carone committed
275 276
}

277
/**************************************************************************
278
 *       libvlc_event_detach (public) :
279 280 281
 *
 * Remove a callback for an event.
 **************************************************************************/
282 283
void libvlc_event_detach(libvlc_event_manager_t *em, libvlc_event_type_t type,
                         libvlc_callback_t callback, void *opaque)
Filippo Carone's avatar
Filippo Carone committed
284
{
285
    vlc_mutex_lock(&em->lock);
286
    for (size_t i = 0; i < vlc_array_count(&em->listeners); i++)
287
    {
288 289 290 291 292 293 294 295 296 297 298 299 300
         libvlc_event_listener_t *listener;

         listener = vlc_array_item_at_index(&em->listeners, i);

         if (listener->event_type == type
          && listener->pf_callback == callback
          && listener->p_user_data == opaque)
         {   /* that's our listener */
             vlc_array_remove(&em->listeners, i);
             vlc_mutex_unlock(&em->lock);
             free(listener);
             return;
         }
301
    }
302
    abort();
Filippo Carone's avatar
Filippo Carone committed
303
}