1 /*****************************************************************************
2 * http.c : http remote control plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: http.c,v 1.7 2003/05/22 15:34:02 hartman Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
30 #include <errno.h> /* ENOMEM */
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
45 #include <sys/types.h>
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Activate ( vlc_object_t * );
53 static void Close ( vlc_object_t * );
54 static void Run ( intf_thread_t *p_intf );
56 static int httpd_page_interface_get( httpd_file_callback_args_t *p_args,
57 uint8_t *p_request, int i_request,
58 uint8_t **pp_data, int *pi_data );
60 /*****************************************************************************
61 * intf_sys_t: description and status of interface
62 *****************************************************************************/
66 httpd_host_t *p_httpd_host;
68 input_thread_t * p_input;
71 /*****************************************************************************
73 *****************************************************************************/
74 #define PORT_TEXT N_( "HTTP interface bind port" )
75 #define PORT_LONGTEXT N_( \
76 "You can set the port on which the http interface will accept connections" )
77 #define ADDR_TEXT N_( "HTTP interface bind address" )
78 #define ADDR_LONGTEXT N_( \
79 "You can set the address on which the http interface will bind" )
82 add_category_hint( N_("HTTP remote control"), NULL, VLC_TRUE );
83 add_string( "http-addr", NULL, NULL, ADDR_TEXT, ADDR_LONGTEXT, VLC_TRUE );
84 add_integer( "http-port", 8080, NULL, PORT_TEXT, PORT_LONGTEXT, VLC_TRUE );
85 set_description( _("HTTP remote control interface") );
86 set_capability( "interface", 10 );
87 set_callbacks( Activate, Close );
90 /*****************************************************************************
91 * Activate: initialize and create stuff
92 *****************************************************************************/
93 static int Activate( vlc_object_t *p_this )
95 intf_thread_t *p_intf = (intf_thread_t*)p_this;
97 /* Allocate instance and initialize some members */
98 p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
99 if( p_intf->p_sys == NULL )
104 p_intf->p_sys->p_httpd = NULL;
105 p_intf->p_sys->p_httpd_host = NULL;
107 p_intf->pf_run = Run;
114 /*****************************************************************************
115 * CloseIntf: destroy interface
116 *****************************************************************************/
117 void Close ( vlc_object_t *p_this )
119 intf_thread_t *p_intf = (intf_thread_t *)p_this;
121 if( p_intf->p_sys->p_httpd_host )
122 p_intf->p_sys->p_httpd->pf_unregister_host( p_intf->p_sys->p_httpd,
123 p_intf->p_sys->p_httpd_host );
125 if( p_intf->p_sys->p_httpd )
126 httpd_Release( p_intf->p_sys->p_httpd );
128 /* Destroy structure */
129 free( p_intf->p_sys );
132 /*****************************************************************************
133 * Run: http interface thread
134 *****************************************************************************/
135 static void Run( intf_thread_t *p_intf )
137 input_thread_t *p_input = NULL;
138 playlist_t *p_playlist = NULL;
139 httpd_file_t *p_page_intf;
142 input_info_category_t * p_category;
143 input_info_t * p_info;
147 double f_ratio = 1.0;
150 /* Get bind address and port */
151 char *psz_bind_addr = config_GetPsz( p_intf, "http-addr" );
152 int i_bind_port = config_GetInt( p_intf, "http-port" );
153 if( !psz_bind_addr ) psz_bind_addr = strdup( "" );
155 p_intf->p_sys->p_httpd = httpd_Find( VLC_OBJECT(p_intf), VLC_TRUE );
156 if( !p_intf->p_sys->p_httpd )
158 msg_Err( p_intf, "cannot start httpd daemon" );
159 free( p_intf->p_sys );
163 p_intf->p_sys->p_httpd_host =
164 p_intf->p_sys->p_httpd->pf_register_host( p_intf->p_sys->p_httpd,
165 psz_bind_addr, i_bind_port );
167 if( !p_intf->p_sys->p_httpd_host )
169 msg_Err( p_intf, "cannot listen on %s:%d", psz_bind_addr, i_bind_port);
170 httpd_Release( p_intf->p_sys->p_httpd );
171 free( p_intf->p_sys );
175 msg_Info( p_intf, "http interface started" );
178 * Register our interface page with the httpd daemon
180 p_page_intf = p_intf->p_sys->p_httpd->pf_register_file(
181 p_intf->p_sys->p_httpd, "/", "text/html",
182 NULL, NULL, httpd_page_interface_get,
183 httpd_page_interface_get,
184 (httpd_file_callback_args_t*)p_intf );
186 while( !p_intf->b_die )
189 /* Manage the input part */
190 if( p_input == NULL )
194 p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
199 p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
203 p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
208 else if( p_input->b_dead )
210 vlc_object_release( p_input );
217 vlc_mutex_lock( &p_input->stream.stream_lock );
218 if( !p_input->b_die && p_input->stream.i_mux_rate )
221 #define A p_input->stream.p_selected_area
222 f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate );
223 i_newpos = A->i_tell * f_ratio;
225 if( i_oldpos != i_newpos )
228 printf( "pos: %li s / %li s\n", (long int)i_newpos,
229 (long int)(f_ratio * A->i_size) );
234 vlc_mutex_unlock( &p_input->stream.stream_lock );
238 msleep( INTF_IDLE_SLEEP );
241 p_intf->p_sys->p_httpd->pf_unregister_file( p_intf->p_sys->p_httpd,
246 vlc_object_release( p_input );
252 vlc_object_release( p_playlist );
257 /*****************************************************************************
259 *****************************************************************************/
260 static int httpd_page_interface_update( intf_thread_t *p_intf,
261 playlist_t *p_playlist,
262 uint8_t **pp_data, int *pi_data, vlc_bool_t b_redirect );
264 static void uri_extract_value( char *psz_uri, char *psz_name,
265 char *psz_value, int i_value_max )
269 p = strstr( psz_uri, psz_name );
274 p += strlen( psz_name );
277 if( strchr( p, '&' ) )
279 i_len = strchr( p, '&' ) - p;
283 /* for POST method */
284 if( strchr( p, '\n' ) )
286 i_len = strchr( p, '\n' ) - p;
287 if( i_len && *(p+i_len-1) == '\r' ) i_len--;
294 i_len = __MIN( i_value_max - 1, i_len );
297 strncpy( psz_value, p, i_len );
298 psz_value[i_len] = '\0';
302 strncpy( psz_value, "", i_value_max );
307 strncpy( psz_value, "", i_value_max );
311 static void uri_decode_url_encoded( char *psz )
313 char *dup = strdup( psz );
331 *psz++ = strtol( val, NULL, 16 );
347 static int httpd_page_interface_get( httpd_file_callback_args_t *p_args,
348 uint8_t *p_request, int i_request,
349 uint8_t **pp_data, int *pi_data )
351 intf_thread_t *p_intf = (intf_thread_t *)p_args;
352 playlist_t *p_playlist;
355 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
365 uri_extract_value( p_request, "action", action, 512 );
367 if( !strcmp( action, "play" ) )
370 uri_extract_value( p_request, "item", action, 512 );
371 i_item = atol( action );
372 playlist_Command( p_playlist, PLAYLIST_GOTO, i_item );
373 msg_Dbg( p_intf, "requested playlist item: %i", i_item );
375 else if( !strcmp( action, "stop" ) )
377 playlist_Command( p_playlist, PLAYLIST_STOP, 0 );
378 msg_Dbg( p_intf, "requested playlist stop" );
380 else if( !strcmp( action, "pause" ) )
382 playlist_Command( p_playlist, PLAYLIST_PAUSE, 0 );
383 msg_Dbg( p_intf, "requested playlist pause" );
385 else if( !strcmp( action, "next" ) )
387 playlist_Command( p_playlist, PLAYLIST_GOTO,
388 p_playlist->i_index + 1 );
389 msg_Dbg( p_intf, "requested playlist next" );
391 else if( !strcmp( action, "previous" ) )
393 playlist_Command( p_playlist, PLAYLIST_GOTO,
394 p_playlist->i_index - 1 );
395 msg_Dbg( p_intf, "requested playlist previous" );
397 else if( !strcmp( action, "add" ) )
399 uri_extract_value( p_request, "mrl", action, 512 );
400 uri_decode_url_encoded( action );
401 playlist_Add( p_playlist, action,
402 PLAYLIST_APPEND, PLAYLIST_END );
403 msg_Dbg( p_intf, "requested playlist add: %s", action );
407 i_ret = httpd_page_interface_update( p_intf, p_playlist, pp_data, pi_data, i_request ? VLC_TRUE : VLC_FALSE );
409 vlc_object_release( p_playlist );
414 static int httpd_page_interface_update( intf_thread_t *p_intf,
415 playlist_t *p_playlist,
416 uint8_t **pp_data, int *pi_data, vlc_bool_t b_redirect )
421 vlc_mutex_lock( &p_playlist->object_lock );
424 * Count playlist items for memory allocation
426 for ( i = 0; i < p_playlist->i_size; i++ )
428 i_size += sizeof("<a href=?action=play&item=?>? - </a><br />\n" );
429 i_size += strlen( p_playlist->pp_items[i]->psz_name );
431 /* add something for all the static strings below */
434 p = *pp_data = malloc( i_size );
436 p += sprintf( p, "<html>\n" );
437 p += sprintf( p, "<head>\n" );
438 p += sprintf( p, "<title>VLC Media Player</title>\n" );
441 p += sprintf( p, "<meta http-equiv=\"refresh\" content=\"0;URL=/\"\n" );
443 /* p += sprintf( p, "<link rel=\"shortcut icon\" href=\"http://www.videolan.org/favicon.ico\">\n" ); */
444 p += sprintf( p, "</head>\n" );
445 p += sprintf( p, "<body>\n" );
446 p += sprintf( p, "<h2><center><a href=\"http://www.videolan.org\">"
447 "VLC Media Player</a> (http interface)</center></h2>\n" );
450 * Display the controls
452 p += sprintf( p, "<hr />\n" );
454 p += sprintf( p, "<td><form method=\"get\" action=\"\">"
455 "<input type=\"submit\" name=\"action\" value=\"stop\" />"
456 "<input type=\"submit\" name=\"action\" value=\"pause\" />"
457 "<input type=\"submit\" name=\"action\" value=\"previous\" />"
458 "<input type=\"submit\" name=\"action\" value=\"next\" />"
459 "</form></td><br />\n" );
461 p += sprintf( p, "<td><form method=\"get\" action=\"\" "
462 "enctype=\"text/plain\" >"
463 "Media Resource Locator: "
464 "<input type=\"text\" name=\"mrl\" size=\"40\" />"
465 "<input type=\"submit\" name=\"action\" value=\"add\" />"
468 p += sprintf( p, "<hr />\n" );
471 * Display the playlist items
473 for ( i = 0; i < p_playlist->i_size; i++ )
475 if( i == p_playlist->i_index ) p += sprintf( p, "<b>" );
477 p += sprintf( p, "<a href=?action=play&item=%i>", i );
478 p += sprintf( p, "%i - %s", i,
479 p_playlist->pp_items[i]->psz_name );
480 p += sprintf( p, "</a>" );
482 if( i == p_playlist->i_index ) p += sprintf( p, "</b>" );
483 p += sprintf( p, "<br />\n" );
487 p += sprintf( p, "no entries\n" );
490 p += sprintf( p, "</body>\n" );
491 p += sprintf( p, "</html>\n" );
493 *pi_data = strlen( *pp_data ) + 1;
495 vlc_mutex_unlock( &p_playlist->object_lock );