6beeacda009bcbcdaf9af78699242ce42324fbe1
[vlc.git] / lib / event.c
1 /*****************************************************************************
2  * event.c: New libvlc event control API
3  *****************************************************************************
4  * Copyright (C) 2007-2010 VLC authors and VideoLAN
5  * $Id $
6  *
7  * Authors: Filippo Carone <filippo@carone.org>
8  *          Pierre d'Herbemont <pdherbemont # 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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <assert.h>
30 #include <errno.h>
31
32 #include <vlc/libvlc.h>
33 #include "libvlc_internal.h"
34
35 #include <vlc_common.h>
36
37 /*
38  * Event Handling
39  */
40
41 /* Example usage
42  *
43  * struct libvlc_cool_object_t
44  * {
45  *        ...
46  *        libvlc_event_manager_t * p_event_manager;
47  *        ...
48  * }
49  *
50  * libvlc_my_cool_object_new()
51  * {
52  *        ...
53  *        p_self->p_event_manager = libvlc_event_manager_new( p_self )
54  *        ...
55  * }
56  *
57  * libvlc_my_cool_object_release()
58  * {
59  *         ...
60  *         libvlc_event_manager_release( p_self->p_event_manager );
61  *         ...
62  * }
63  *
64  * libvlc_my_cool_object_do_something()
65  * {
66  *        ...
67  *        libvlc_event_t event;
68  *        event.type = libvlc_MyCoolObjectDidSomething;
69  *        event.u.my_cool_object_did_something.what_it_did = kSomething;
70  *        libvlc_event_send( p_self->p_event_manager, &event );
71  * }
72  * */
73
74 typedef struct libvlc_event_listener_t
75 {
76     libvlc_event_type_t event_type;
77     void *              p_user_data;
78     libvlc_callback_t   pf_callback;
79 } libvlc_event_listener_t;
80
81 typedef struct libvlc_event_manager_t
82 {
83     void * p_obj;
84     vlc_array_t listeners;
85     vlc_mutex_t lock;
86 } libvlc_event_sender_t;
87
88 /*
89  * Internal libvlc functions
90  */
91
92 /**************************************************************************
93  *       libvlc_event_manager_new (internal) :
94  *
95  * Init an object's event manager.
96  **************************************************************************/
97 libvlc_event_manager_t *
98 libvlc_event_manager_new( void * p_obj )
99 {
100     libvlc_event_manager_t * p_em;
101
102     p_em = malloc(sizeof( libvlc_event_manager_t ));
103     if( !p_em )
104     {
105         libvlc_printerr( "Not enough memory" );
106         return NULL;
107     }
108
109     p_em->p_obj = p_obj;
110     vlc_array_init(&p_em->listeners);
111     vlc_mutex_init_recursive(&p_em->lock);
112     return p_em;
113 }
114
115 /**************************************************************************
116  *       libvlc_event_manager_release (internal) :
117  *
118  * Release an object's event manager.
119  **************************************************************************/
120 void libvlc_event_manager_release( libvlc_event_manager_t * p_em )
121 {
122     vlc_mutex_destroy(&p_em->lock);
123
124     for (int i = 0; i < vlc_array_count(&p_em->listeners); i++)
125         free(vlc_array_item_at_index(&p_em->listeners, i));
126
127     vlc_array_clear(&p_em->listeners);
128     free( p_em );
129 }
130
131 /**************************************************************************
132  *       libvlc_event_send (internal) :
133  *
134  * Send a callback.
135  **************************************************************************/
136 void libvlc_event_send( libvlc_event_manager_t * p_em,
137                         libvlc_event_t * p_event )
138 {
139     /* Fill event with the sending object now */
140     p_event->p_obj = p_em->p_obj;
141
142     vlc_mutex_lock(&p_em->lock);
143     for (int i = 0; i < vlc_array_count(&p_em->listeners); i++)
144     {
145         libvlc_event_listener_t *listener;
146
147         listener = vlc_array_item_at_index(&p_em->listeners, i);
148         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  * Public libvlc functions
156  */
157
158 #define DEF( a ) { libvlc_##a, #a, },
159
160 typedef struct
161 {
162     int type;
163     const char name[40];
164 } event_name_t;
165
166 static const event_name_t event_list[] = {
167     DEF(MediaMetaChanged)
168     DEF(MediaSubItemAdded)
169     DEF(MediaDurationChanged)
170     DEF(MediaParsedChanged)
171     DEF(MediaFreed)
172     DEF(MediaStateChanged)
173     DEF(MediaSubItemTreeAdded)
174
175     DEF(MediaPlayerMediaChanged)
176     DEF(MediaPlayerNothingSpecial)
177     DEF(MediaPlayerOpening)
178     DEF(MediaPlayerBuffering)
179     DEF(MediaPlayerPlaying)
180     DEF(MediaPlayerPaused)
181     DEF(MediaPlayerStopped)
182     DEF(MediaPlayerForward)
183     DEF(MediaPlayerBackward)
184     DEF(MediaPlayerEndReached)
185     DEF(MediaPlayerEncounteredError)
186     DEF(MediaPlayerTimeChanged)
187     DEF(MediaPlayerPositionChanged)
188     DEF(MediaPlayerSeekableChanged)
189     DEF(MediaPlayerPausableChanged)
190     DEF(MediaPlayerTitleChanged)
191     DEF(MediaPlayerSnapshotTaken)
192     DEF(MediaPlayerLengthChanged)
193     DEF(MediaPlayerVout)
194     DEF(MediaPlayerScrambledChanged)
195     DEF(MediaPlayerESAdded)
196     DEF(MediaPlayerESDeleted)
197     DEF(MediaPlayerESSelected)
198     DEF(MediaPlayerCorked)
199     DEF(MediaPlayerUncorked)
200     DEF(MediaPlayerMuted)
201     DEF(MediaPlayerUnmuted)
202     DEF(MediaPlayerAudioVolume)
203     DEF(MediaPlayerAudioDevice)
204     DEF(MediaPlayerChapterChanged)
205
206     DEF(MediaListItemAdded)
207     DEF(MediaListWillAddItem)
208     DEF(MediaListItemDeleted)
209     DEF(MediaListWillDeleteItem)
210     DEF(MediaListEndReached)
211
212     DEF(MediaListViewItemAdded)
213     DEF(MediaListViewWillAddItem)
214     DEF(MediaListViewItemDeleted)
215     DEF(MediaListViewWillDeleteItem)
216
217     DEF(MediaListPlayerPlayed)
218     DEF(MediaListPlayerNextItemSet)
219     DEF(MediaListPlayerStopped)
220
221     DEF(MediaDiscovererStarted)
222     DEF(MediaDiscovererEnded)
223
224     DEF(VlmMediaAdded)
225     DEF(VlmMediaRemoved)
226     DEF(VlmMediaChanged)
227     DEF(VlmMediaInstanceStarted)
228     DEF(VlmMediaInstanceStopped)
229     DEF(VlmMediaInstanceStatusInit)
230     DEF(VlmMediaInstanceStatusOpening)
231     DEF(VlmMediaInstanceStatusPlaying)
232     DEF(VlmMediaInstanceStatusPause)
233     DEF(VlmMediaInstanceStatusEnd)
234     DEF(VlmMediaInstanceStatusError)
235 };
236 #undef DEF
237
238 static const char unknown_event_name[] = "Unknown Event";
239
240 static int evcmp( const void *a, const void *b )
241 {
242     return (*(const int *)a) - ((event_name_t *)b)->type;
243 }
244
245 const char * libvlc_event_type_name( int event_type )
246 {
247     const event_name_t *p;
248
249     p = bsearch( &event_type, event_list,
250                  sizeof(event_list)/sizeof(event_list[0]), sizeof(*p),
251                  evcmp );
252     return p ? p->name : unknown_event_name;
253 }
254
255 /**************************************************************************
256  *       libvlc_event_attach (public) :
257  *
258  * Add a callback for an event.
259  **************************************************************************/
260 int libvlc_event_attach(libvlc_event_manager_t *em, libvlc_event_type_t type,
261                         libvlc_callback_t callback, void *opaque)
262 {
263     libvlc_event_listener_t *listener = malloc(sizeof (*listener));
264     if (unlikely(listener == NULL))
265         return ENOMEM;
266
267     listener->event_type = type;
268     listener->p_user_data = opaque;
269     listener->pf_callback = callback;
270
271     vlc_mutex_lock(&em->lock);
272     vlc_array_append(&em->listeners, listener);
273     vlc_mutex_unlock(&em->lock);
274     return 0;
275 }
276
277 /**************************************************************************
278  *       libvlc_event_detach (public) :
279  *
280  * Remove a callback for an event.
281  **************************************************************************/
282 void libvlc_event_detach(libvlc_event_manager_t *em, libvlc_event_type_t type,
283                          libvlc_callback_t callback, void *opaque)
284 {
285     vlc_mutex_lock(&em->lock);
286     for (int i = 0; i < vlc_array_count(&em->listeners); i++)
287     {
288          libvlc_event_listener_t *listener;
289
290          listener = vlc_array_item_at_index(&em->listeners, i);
291
292          if (listener->event_type == type
293           && listener->pf_callback == callback
294           && listener->p_user_data == opaque)
295          {   /* that's our listener */
296              vlc_array_remove(&em->listeners, i);
297              vlc_mutex_unlock(&em->lock);
298              free(listener);
299              return;
300          }
301     }
302     abort();
303 }