]> git.sesse.net Git - vlc/blob - src/control/mediacontrol_core.c
FSF address change.
[vlc] / 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 <mediacontrol_internal.h>
25 #include <vlc/mediacontrol.h>
26
27 #include <vlc/intf.h>
28 #include <vlc/vout.h>
29 #include <vlc/aout.h>
30 #include <vlc_demux.h>
31
32 #include <vlc_osd.h>
33
34 #define HAS_SNAPSHOT 1
35
36 #ifdef HAS_SNAPSHOT
37 #include <snapshot.h>
38 #endif
39
40 #include <stdlib.h>                                      /* malloc(), free() */
41 #include <string.h>
42
43 #include <errno.h>                                                 /* ENOMEM */
44 #include <stdio.h>
45 #include <ctype.h>
46
47 #ifdef HAVE_UNISTD_H
48 #    include <unistd.h>
49 #endif
50 #ifdef HAVE_SYS_TIME_H
51 #    include <sys/time.h>
52 #endif
53 #ifdef HAVE_SYS_TYPES_H
54 #    include <sys/types.h>
55 #endif
56
57 #define RAISE( c, m )  exception->code = c; \
58                        exception->message = strdup(m);
59
60 vlc_t * vlc_current_object( int );
61
62 mediacontrol_Instance* mediacontrol_new_from_object( int vlc_object_id,
63                                                      mediacontrol_Exception *exception )
64 {
65     mediacontrol_Instance* retval;
66     vlc_object_t *p_vlc;
67     vlc_object_t *p_object;
68
69     p_object = ( vlc_object_t* )vlc_current_object( vlc_object_id );
70     if( ! p_object )
71     {
72         RAISE( mediacontrol_InternalException, "Unable to find vlc object" );
73         return NULL;
74     }
75
76     p_vlc = vlc_object_find( p_object, VLC_OBJECT_ROOT, FIND_PARENT );
77     if( ! p_vlc )
78     {
79         RAISE( mediacontrol_InternalException, "Unable to initialize VLC" );
80         return NULL;
81     }
82     retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) );
83     retval->p_vlc = p_vlc;
84     retval->vlc_object_id = p_vlc->i_object_id;
85
86     /* We can keep references on these, which should not change. Is it true ? */
87     retval->p_playlist = vlc_object_find( p_vlc,
88                                         VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
89     retval->p_intf = vlc_object_find( p_vlc, VLC_OBJECT_INTF, FIND_ANYWHERE );
90
91     if( ! retval->p_playlist || ! retval->p_intf )
92     {
93         RAISE( mediacontrol_InternalException, "No available interface" );
94         return NULL;
95     }
96     return retval;
97 };
98
99
100 /**************************************************************************
101  * Playback management
102  **************************************************************************/
103 mediacontrol_Position*
104 mediacontrol_get_media_position( mediacontrol_Instance *self,
105                                  const mediacontrol_PositionOrigin an_origin,
106                                  const mediacontrol_PositionKey a_key,
107                                  mediacontrol_Exception *exception )
108 {
109     mediacontrol_Position* retval;
110     vlc_value_t val;
111     input_thread_t * p_input = self->p_playlist->p_input;
112
113     exception = mediacontrol_exception_init( exception );
114
115     retval = ( mediacontrol_Position* )malloc( sizeof( mediacontrol_Position ) );
116     retval->origin = an_origin;
117     retval->key = a_key;
118
119     if( ! p_input )
120     {
121         RAISE( mediacontrol_InternalException, "No input thread." );
122         return NULL;
123     }
124
125     if(  an_origin != mediacontrol_AbsolutePosition )
126     {
127         /* Relative or ModuloPosition make no sense */
128         RAISE( mediacontrol_PositionOriginNotSupported, "Only absolute position is valid." );
129         return NULL;
130     }
131
132     /* We are asked for an AbsolutePosition. */
133     val.i_time = 0;
134     var_Get( p_input, "time", &val );
135     /* FIXME: check val.i_time > 0 */
136
137     retval->value = mediacontrol_unit_convert( p_input,
138                                                mediacontrol_MediaTime,
139                                                a_key,
140                                                val.i_time / 1000 );
141     return retval;
142 }
143
144 /* Sets the media position */
145 void
146 mediacontrol_set_media_position( mediacontrol_Instance *self,
147                                  const mediacontrol_Position * a_position,
148                                  mediacontrol_Exception *exception )
149 {
150     vlc_value_t val;
151     input_thread_t * p_input = self->p_playlist->p_input;
152
153     exception=mediacontrol_exception_init( exception );
154     if( ! p_input )
155     {
156         RAISE( mediacontrol_InternalException, "No input thread." );
157         return;
158     }
159
160     if( !var_GetBool( p_input, "seekable" ) )
161     {
162         RAISE( mediacontrol_InvalidPosition, "Stream not seekable" );
163         return;
164     }
165
166     val.i_time = mediacontrol_position2microsecond( p_input, a_position );
167     var_Set( p_input, "time", val );
168     return;
169 }
170
171 /* Starts playing a stream */
172 /*
173  * Known issues: since moving in the playlist using playlist_Next
174  * or playlist_Prev implies starting to play items, the a_position
175  * argument will be only honored for the 1st item in the list.
176  * 
177  * XXX:FIXME split moving in the playlist and playing items two
178  * different actions or make playlist_<Next|Prev> accept a time
179  * value to start to play from.
180  */
181 void
182 mediacontrol_start( mediacontrol_Instance *self,
183                     const mediacontrol_Position * a_position,
184                     mediacontrol_Exception *exception )
185 {
186     playlist_t * p_playlist = self->p_playlist;
187
188     exception = mediacontrol_exception_init( exception );
189     if( ! p_playlist )
190     {
191         RAISE( mediacontrol_PlaylistException, "No available playlist" );
192         return;
193     }
194
195     vlc_mutex_lock( &p_playlist->object_lock );
196     if( p_playlist->i_size )
197     {
198         int i_index;
199         int i_from;
200         char * psz_from = ( char * )malloc( 20 * sizeof( char ) );
201
202         i_from = mediacontrol_position2microsecond( p_playlist->p_input, a_position ) / 1000000;
203         
204         i_index = p_playlist->i_index;
205         if( i_index < 0 )
206         { 
207             /* We know that there is at least 1 element, since i_size != 0 */
208             i_index = 0;
209         }
210
211         /* Set start time */
212         snprintf( psz_from, 20, "start-time=%i", i_from );
213         playlist_ItemAddOption( p_playlist->pp_items[i_index], psz_from );
214         free( psz_from );
215
216         vlc_mutex_unlock( &p_playlist->object_lock );
217
218         playlist_Play( p_playlist );
219     }
220     else
221     {
222         RAISE( mediacontrol_PlaylistException, "Empty playlist." );
223         vlc_mutex_unlock( &p_playlist->object_lock );
224     }
225
226     return;
227 }
228
229 void
230 mediacontrol_pause( mediacontrol_Instance *self,
231                     const mediacontrol_Position * a_position,
232                     mediacontrol_Exception *exception )
233 {
234     input_thread_t *p_input = self->p_playlist->p_input;
235
236     /* FIXME: use the a_position parameter */
237     exception=mediacontrol_exception_init( exception );
238     if( p_input != NULL )
239     {
240         var_SetInteger( p_input, "state", PAUSE_S );
241     }
242     else
243     {
244         RAISE( mediacontrol_InternalException, "No input" );
245     }
246
247     return;
248 }
249
250 void
251 mediacontrol_resume( mediacontrol_Instance *self,
252                      const mediacontrol_Position * a_position,
253                      mediacontrol_Exception *exception )
254 {
255     input_thread_t *p_input = self->p_playlist->p_input;
256
257     /* FIXME: use the a_position parameter */
258     exception=mediacontrol_exception_init( exception );
259     if( p_input != NULL )
260     {
261         var_SetInteger( p_input, "state", PAUSE_S );
262     }
263     else
264     {
265         RAISE( mediacontrol_InternalException, "No input" );
266     }
267 }
268
269 void
270 mediacontrol_stop( mediacontrol_Instance *self,
271                    const mediacontrol_Position * a_position,
272                    mediacontrol_Exception *exception )
273 {
274     /* FIXME: use the a_position parameter */
275     exception=mediacontrol_exception_init( exception );
276     if( !self->p_playlist )
277     {
278         RAISE( mediacontrol_PlaylistException, "No playlist" );
279         return;
280     }
281
282     playlist_Stop( self->p_playlist );
283 }
284
285 /**************************************************************************
286  * Playlist management
287  **************************************************************************/
288
289 void
290 mediacontrol_playlist_add_item( mediacontrol_Instance *self,
291                                 const char * psz_file,
292                                 mediacontrol_Exception *exception )
293 {
294     exception=mediacontrol_exception_init( exception );
295     if( !self->p_playlist )
296     {
297         RAISE( mediacontrol_InternalException, "No playlist" );
298         return;
299     }
300
301     playlist_Add( self->p_playlist, psz_file, psz_file , PLAYLIST_INSERT,
302                   PLAYLIST_END );
303 }
304
305 void
306 mediacontrol_playlist_next_item( mediacontrol_Instance *self,
307                                  mediacontrol_Exception *exception )
308 {
309     exception=mediacontrol_exception_init( exception );
310     if ( !self->p_playlist )
311     {
312         RAISE( mediacontrol_InternalException, "No playlist" );
313         return;
314     }
315
316     playlist_Next( self->p_playlist );
317
318     return;
319 }
320
321 void
322 mediacontrol_playlist_clear( mediacontrol_Instance *self,
323                              mediacontrol_Exception *exception )
324 {
325     exception=mediacontrol_exception_init( exception );
326     if( !self->p_playlist )
327     {
328         RAISE( mediacontrol_PlaylistException, "No playlist" );
329         return;
330     }
331
332     playlist_Clear( self->p_playlist );
333
334     return;
335 }
336
337 mediacontrol_PlaylistSeq *
338 mediacontrol_playlist_get_list( mediacontrol_Instance *self,
339                                 mediacontrol_Exception *exception )
340 {
341     mediacontrol_PlaylistSeq *retval;
342     int i_index;
343     playlist_t * p_playlist = self->p_playlist;
344     int i_playlist_size;
345
346     exception=mediacontrol_exception_init( exception );
347     if( !p_playlist )
348     {
349         RAISE( mediacontrol_PlaylistException, "No playlist" );
350         return NULL;
351     }
352
353     vlc_mutex_lock( &p_playlist->object_lock );
354     i_playlist_size = p_playlist->i_size;
355
356     retval = mediacontrol_PlaylistSeq__alloc( i_playlist_size );
357
358     for( i_index = 0 ; i_index < i_playlist_size ; i_index++ )
359     {
360         retval->data[i_index] = strdup( p_playlist->pp_items[i_index]->input.psz_uri );
361     }
362     vlc_mutex_unlock( &p_playlist->object_lock );
363
364     return retval;
365 }
366
367 /***************************************************************************
368  * Status feedback
369  ***************************************************************************/
370
371 mediacontrol_StreamInformation *
372 mediacontrol_get_stream_information( mediacontrol_Instance *self,
373                                      mediacontrol_PositionKey a_key,
374                                      mediacontrol_Exception *exception )
375 {
376     mediacontrol_StreamInformation *retval;
377     input_thread_t *p_input = self->p_playlist->p_input;
378     vlc_value_t val;
379
380     retval = ( mediacontrol_StreamInformation* )malloc( sizeof( mediacontrol_StreamInformation ) );
381     if( ! retval )
382     {
383         RAISE( mediacontrol_InternalException, "Out of memory" );
384         return NULL;
385     }
386
387     if( ! p_input )
388     {
389         /* No p_input defined */
390         retval->streamstatus = mediacontrol_UndefinedStatus;
391         retval->url          = strdup( "None" );
392         retval->position     = 0;
393         retval->length       = 0;
394     }
395     else
396     {
397         switch( var_GetInteger( p_input, "state" ) )
398         {
399         case PLAYING_S     :
400             retval->streamstatus = mediacontrol_PlayingStatus;
401             break;
402         case PAUSE_S       :
403             retval->streamstatus = mediacontrol_PauseStatus;
404             break;
405         case INIT_S        :
406             retval->streamstatus = mediacontrol_InitStatus;
407             break;
408         case END_S         :
409             retval->streamstatus = mediacontrol_EndStatus;
410             break;
411         default :
412             retval->streamstatus = mediacontrol_UndefinedStatus;
413             break;
414         }
415
416         retval->url = strdup( p_input->input.p_item->psz_uri );
417
418         /* TIME and LENGTH are in microseconds. We want them in ms */
419         var_Get( p_input, "time", &val);
420         retval->position = val.i_time / 1000;
421
422         var_Get( p_input, "length", &val);
423         retval->length = val.i_time / 1000;
424
425         retval->position = mediacontrol_unit_convert( p_input,
426                                                       mediacontrol_MediaTime, a_key,
427                                                       retval->position );
428         retval->length   = mediacontrol_unit_convert( p_input,
429                                                       mediacontrol_MediaTime, a_key,
430                                                       retval->length );
431     }
432     return retval;
433 }