Reference count libvlc. API break.
[vlc.git] / src / control / mediacontrol_core.c
1 /*****************************************************************************
2  * core.c: Core functions : init, playlist, stream management
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Olivier Aubert <olivier.aubert@liris.univ-lyon1.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25 #include <vlc/mediacontrol.h>
26
27 #include <vlc/libvlc.h>
28 #include <vlc_interface.h>
29 #include <vlc_playlist.h>
30
31 #include <vlc_vout.h>
32 #include <vlc_aout.h>
33 #include <vlc_input.h>
34 #include <vlc_osd.h>
35 #include "mediacontrol_internal.h"
36
37 #include <stdlib.h>                                      /* malloc(), free() */
38 #include <string.h>
39
40 #include <errno.h>                                                 /* ENOMEM */
41 #include <stdio.h>
42 #include <ctype.h>
43
44 #ifdef HAVE_UNISTD_H
45 #    include <unistd.h>
46 #endif
47 #ifdef HAVE_SYS_TIME_H
48 #    include <sys/time.h>
49 #endif
50 #ifdef HAVE_SYS_TYPES_H
51 #    include <sys/types.h>
52 #endif
53
54 mediacontrol_Instance* mediacontrol_new( int argc, char** argv, mediacontrol_Exception *exception )
55 {
56     mediacontrol_Instance* retval;
57     libvlc_exception_t ex;
58     char** ppsz_argv = NULL;
59     int i_index;
60
61     libvlc_exception_init( &ex );
62     mediacontrol_exception_init( exception );
63
64     retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) );
65     if( !retval )
66         RAISE_NULL( mediacontrol_InternalException, "Out of memory" );
67
68     /* Prepend a dummy argv[0] so that users of the API do not have to
69        do it themselves, and can simply provide the args list. */
70     ppsz_argv = malloc( ( argc + 2 ) * sizeof( char * ) ) ;
71     if( ! ppsz_argv )
72         RAISE_NULL( mediacontrol_InternalException, "Out of memory" );
73
74     ppsz_argv[0] = strdup("vlc");
75     for ( i_index = 0; i_index < argc; i_index++ )
76         ppsz_argv[i_index + 1] = argv[i_index];
77     ppsz_argv[argc + 1] = NULL;
78
79     retval->p_instance = libvlc_new( argc + 1, ppsz_argv, &ex );
80     retval->p_playlist = retval->p_instance->p_libvlc_int->p_playlist;
81     HANDLE_LIBVLC_EXCEPTION_NULL( &ex );
82     return retval;
83 };
84
85 void
86 mediacontrol_exit( mediacontrol_Instance *self )
87 {
88     libvlc_exception_t ex;
89     libvlc_exception_init( &ex );
90
91     libvlc_release( self->p_instance, &ex );
92 }
93
94 libvlc_instance_t*
95 mediacontrol_get_libvlc_instance( mediacontrol_Instance *self )
96 {
97   return self->p_instance;
98 }
99
100 mediacontrol_Instance *
101 mediacontrol_new_from_instance( libvlc_instance_t* p_instance,
102                 mediacontrol_Exception *exception )
103 {
104   mediacontrol_Instance* retval;
105
106   retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) );
107   if( ! retval )
108   {
109       RAISE_NULL( mediacontrol_InternalException, "Out of memory" );
110   }
111   retval->p_instance = p_instance;
112   retval->p_playlist = retval->p_instance->p_libvlc_int->p_playlist;
113   return retval;
114 }
115
116 /**************************************************************************
117  * Playback management
118  **************************************************************************/
119 mediacontrol_Position*
120 mediacontrol_get_media_position( mediacontrol_Instance *self,
121                                  const mediacontrol_PositionOrigin an_origin,
122                                  const mediacontrol_PositionKey a_key,
123                                  mediacontrol_Exception *exception )
124 {
125     mediacontrol_Position* retval = NULL;
126     libvlc_exception_t ex;
127     vlc_int64_t pos;
128     libvlc_media_instance_t * p_mi;
129
130     mediacontrol_exception_init( exception );
131     libvlc_exception_init( &ex );
132
133     retval = ( mediacontrol_Position* )malloc( sizeof( mediacontrol_Position ) );
134     retval->origin = an_origin;
135     retval->key = a_key;
136
137     p_mi = libvlc_playlist_get_media_instance( self->p_instance, &ex);
138     HANDLE_LIBVLC_EXCEPTION_NULL( &ex );
139
140     if(  an_origin != mediacontrol_AbsolutePosition )
141     {
142         libvlc_media_instance_release( p_mi );
143         /* Relative or ModuloPosition make no sense */
144         RAISE_NULL( mediacontrol_PositionOriginNotSupported,
145                     "Only absolute position is valid." );
146     }
147
148     /* We are asked for an AbsolutePosition. */
149     pos = libvlc_media_instance_get_time( p_mi, &ex );
150
151     if( a_key == mediacontrol_MediaTime )
152     {
153         retval->value = pos;
154     }
155     else
156     {
157         if( ! self->p_playlist->p_input )
158         {
159             libvlc_media_instance_release( p_mi );
160             RAISE_NULL( mediacontrol_InternalException,
161                         "No input" );
162         }
163         retval->value = private_mediacontrol_unit_convert( self->p_playlist->p_input,
164                                                    mediacontrol_MediaTime,
165                                                    a_key,
166                                                    pos );
167     }
168     libvlc_media_instance_release( p_mi );
169     return retval;
170 }
171
172 /* Sets the media position */
173 void
174 mediacontrol_set_media_position( mediacontrol_Instance *self,
175                                  const mediacontrol_Position * a_position,
176                                  mediacontrol_Exception *exception )
177 {
178     libvlc_media_instance_t * p_mi;
179     libvlc_exception_t ex;
180     vlc_int64_t i_pos;
181
182     libvlc_exception_init( &ex );
183     mediacontrol_exception_init( exception );
184
185     p_mi = libvlc_playlist_get_media_instance( self->p_instance, &ex);
186     HANDLE_LIBVLC_EXCEPTION_VOID( &ex );
187
188     i_pos = private_mediacontrol_position2microsecond( self->p_playlist->p_input, a_position );
189     libvlc_media_instance_set_time( p_mi, i_pos / 1000, &ex );
190     libvlc_media_instance_release( p_mi );
191     HANDLE_LIBVLC_EXCEPTION_VOID( &ex );
192 }
193
194 /* Starts playing a stream */
195 /*
196  * Known issues: since moving in the playlist using playlist_Next
197  * or playlist_Prev implies starting to play items, the a_position
198  * argument will be only honored for the 1st item in the list.
199  *
200  * XXX:FIXME split moving in the playlist and playing items two
201  * different actions or make playlist_<Next|Prev> accept a time
202  * value to start to play from.
203  */
204 void
205 mediacontrol_start( mediacontrol_Instance *self,
206                     const mediacontrol_Position * a_position,
207                     mediacontrol_Exception *exception )
208 {
209     playlist_t * p_playlist = self->p_playlist;
210
211     mediacontrol_exception_init( exception );
212     if( ! p_playlist )
213     {
214         RAISE( mediacontrol_PlaylistException, "No available playlist" );
215         return;
216     }
217
218     vlc_mutex_lock( &p_playlist->object_lock );
219     if( p_playlist->items.i_size )
220     {
221         int i_from;
222         char *psz_from = NULL;
223
224         psz_from = ( char * )malloc( 20 * sizeof( char ) );
225         if( psz_from && p_playlist->status.p_item )
226         {
227             i_from = private_mediacontrol_position2microsecond( p_playlist->p_input, a_position ) / 1000000;
228
229             /* Set start time */
230             snprintf( psz_from, 20, "start-time=%i", i_from );
231             input_ItemAddOption( p_playlist->status.p_item->p_input, psz_from );
232             free( psz_from );
233         }
234
235         vlc_mutex_unlock( &p_playlist->object_lock );
236         playlist_Play( p_playlist );
237     }
238     else
239     {
240         RAISE( mediacontrol_PlaylistException, "Empty playlist." );
241         vlc_mutex_unlock( &p_playlist->object_lock );
242     }
243 }
244
245 void
246 mediacontrol_pause( mediacontrol_Instance *self,
247                     const mediacontrol_Position * a_position,
248                     mediacontrol_Exception *exception )
249 {
250     input_thread_t *p_input = self->p_playlist->p_input;
251
252     /* FIXME: use the a_position parameter */
253     mediacontrol_exception_init( exception );
254     if( p_input != NULL )
255     {
256         var_SetInteger( p_input, "state", PAUSE_S );
257     }
258     else
259     {
260         RAISE( mediacontrol_InternalException, "No input" );
261     }
262 }
263
264 void
265 mediacontrol_resume( mediacontrol_Instance *self,
266                      const mediacontrol_Position * a_position,
267                      mediacontrol_Exception *exception )
268 {
269     input_thread_t *p_input = self->p_playlist->p_input;
270
271     /* FIXME: use the a_position parameter */
272     mediacontrol_exception_init( exception );
273     if( p_input != NULL )
274     {
275         var_SetInteger( p_input, "state", PAUSE_S );
276     }
277     else
278     {
279         RAISE( mediacontrol_InternalException, "No input" );
280     }
281 }
282
283 void
284 mediacontrol_stop( mediacontrol_Instance *self,
285                    const mediacontrol_Position * a_position,
286                    mediacontrol_Exception *exception )
287 {
288     /* FIXME: use the a_position parameter */
289     mediacontrol_exception_init( exception );
290     if( !self->p_playlist )
291     {
292         RAISE( mediacontrol_PlaylistException, "No playlist" );
293     }
294     else
295         playlist_Stop( self->p_playlist );
296 }
297
298 /**************************************************************************
299  * Playlist management
300  **************************************************************************/
301
302 void
303 mediacontrol_playlist_add_item( mediacontrol_Instance *self,
304                                 const char * psz_file,
305                                 mediacontrol_Exception *exception )
306 {
307     libvlc_exception_t ex;
308
309     mediacontrol_exception_init( exception );
310     libvlc_exception_init( &ex );
311
312     libvlc_playlist_add( self->p_instance, psz_file, psz_file, &ex );
313     HANDLE_LIBVLC_EXCEPTION_VOID( &ex );
314 }
315
316 void
317 mediacontrol_playlist_next_item( mediacontrol_Instance *self,
318                                  mediacontrol_Exception *exception )
319 {
320     libvlc_exception_t ex;
321
322     mediacontrol_exception_init( exception );
323     libvlc_exception_init( &ex );
324
325     libvlc_playlist_next( self->p_instance, &ex );
326     HANDLE_LIBVLC_EXCEPTION_VOID( &ex );
327 }
328
329 void
330 mediacontrol_playlist_clear( mediacontrol_Instance *self,
331                              mediacontrol_Exception *exception )
332 {
333     libvlc_exception_t ex;
334
335     mediacontrol_exception_init( exception );
336     libvlc_exception_init( &ex );
337
338     libvlc_playlist_clear( self->p_instance, &ex );
339     HANDLE_LIBVLC_EXCEPTION_VOID( &ex );
340 }
341
342 mediacontrol_PlaylistSeq *
343 mediacontrol_playlist_get_list( mediacontrol_Instance *self,
344                                 mediacontrol_Exception *exception )
345 {
346     mediacontrol_PlaylistSeq *retval = NULL;
347     int i_index;
348     playlist_t * p_playlist = self->p_playlist;
349     int i_playlist_size;
350
351     mediacontrol_exception_init( exception );
352     if( !p_playlist )
353     {
354         RAISE( mediacontrol_PlaylistException, "No playlist" );
355         return NULL;
356     }
357
358     vlc_mutex_lock( &p_playlist->object_lock );
359     i_playlist_size = p_playlist->current.i_size;
360
361     retval = private_mediacontrol_PlaylistSeq__alloc( i_playlist_size );
362
363     for( i_index = 0 ; i_index < i_playlist_size ; i_index++ )
364     {
365         retval->data[i_index] = input_item_GetURI( ARRAY_VAL(p_playlist->current, i_index)->p_input );
366     }
367     vlc_mutex_unlock( &p_playlist->object_lock );
368
369     return retval;
370 }
371
372 /***************************************************************************
373  * Status feedback
374  ***************************************************************************/
375
376 mediacontrol_StreamInformation *
377 mediacontrol_get_stream_information( mediacontrol_Instance *self,
378                                      mediacontrol_PositionKey a_key,
379                                      mediacontrol_Exception *exception )
380 {
381     mediacontrol_StreamInformation *retval = NULL;
382     input_thread_t *p_input = self->p_playlist->p_input;
383     vlc_value_t val;
384
385     retval = ( mediacontrol_StreamInformation* )
386                             malloc( sizeof( mediacontrol_StreamInformation ) );
387     if( ! retval )
388     {
389         RAISE( mediacontrol_InternalException, "Out of memory" );
390         return NULL;
391     }
392
393     if( ! p_input )
394     {
395         /* No p_input defined */
396         retval->streamstatus = mediacontrol_UndefinedStatus;
397         retval->url          = strdup( "None" );
398         retval->position     = 0;
399         retval->length       = 0;
400     }
401     else
402     {
403         switch( var_GetInteger( p_input, "state" ) )
404         {
405         case PLAYING_S     :
406             retval->streamstatus = mediacontrol_PlayingStatus;
407             break;
408         case PAUSE_S       :
409             retval->streamstatus = mediacontrol_PauseStatus;
410             break;
411         case INIT_S        :
412             retval->streamstatus = mediacontrol_InitStatus;
413             break;
414         case END_S         :
415             retval->streamstatus = mediacontrol_EndStatus;
416             break;
417         default :
418             retval->streamstatus = mediacontrol_UndefinedStatus;
419             break;
420         }
421
422         retval->url = input_item_GetURI( input_GetItem( p_input ) );
423
424         /* TIME and LENGTH are in microseconds. We want them in ms */
425         var_Get( p_input, "time", &val);
426         retval->position = val.i_time / 1000;
427
428         var_Get( p_input, "length", &val);
429         retval->length = val.i_time / 1000;
430
431         retval->position = private_mediacontrol_unit_convert( p_input,
432                                          mediacontrol_MediaTime, a_key,
433                                          retval->position );
434         retval->length   = private_mediacontrol_unit_convert( p_input,
435                                          mediacontrol_MediaTime, a_key,
436                                          retval->length );
437     }
438     return retval;
439 }