diff --git a/configure.ac.in b/configure.ac.in index 597a8194bf..32c644ef02 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -132,6 +132,7 @@ case "x${target_os}" in LDFLAGS_access_output_udp="${LDFLAGS_access_output_udp} -lws2_32" LDFLAGS_sap="${LDFLAGS_sap} -lws2_32" LDFLAGS_slp="${LDFLAGS_slp} -lws2_32" + LDFLAGS_http="${LDFLAGS_http} -lws2_32" LDFLAGS_httpd="${LDFLAGS_httpd} -lws2_32" fi ;; @@ -291,6 +292,7 @@ AC_CHECK_FUNCS(send,,[ LDFLAGS_access_udp="${LDFLAGS_access_udp} -lsocket" LDFLAGS_access_ftp="${LDFLAGS_access_ftp} -lsocket" LDFLAGS_sap="${LDFLAGS_sap} -lsocket" + LDFLAGS_http="${LDFLAGS_http} -lsocket" LDFLAGS_access_output_udp="${LDFLAGS_access_output_udp} -lsocket" )]) @@ -831,7 +833,7 @@ PLUGINS="${PLUGINS} id3 m3u" PLUGINS="${PLUGINS} rawvideo" PLUGINS="${PLUGINS} wav araw demuxdump demuxsub adpcm a52sys au" PLUGINS="${PLUGINS} access_file access_udp access_http ipv4 access_mms" -PLUGINS="${PLUGINS} access_ftp access_directory sap httpd" +PLUGINS="${PLUGINS} access_ftp access_directory sap httpd http" dnl dnl Some plugins aren't useful on some platforms diff --git a/modules/control/Modules.am b/modules/control/Modules.am index 0aca56dea5..6fad06e8a8 100644 --- a/modules/control/Modules.am +++ b/modules/control/Modules.am @@ -1 +1,2 @@ SOURCES_gestures = modules/control/gestures.c +SOURCES_http = modules/control/http.c diff --git a/modules/control/http.c b/modules/control/http.c new file mode 100644 index 0000000000..be7df33940 --- /dev/null +++ b/modules/control/http.c @@ -0,0 +1,431 @@ +/***************************************************************************** + * http.c : http remote control plugin for vlc + ***************************************************************************** + * Copyright (C) 2001 VideoLAN + * $Id: http.c,v 1.1 2003/04/26 21:36:23 gbazin Exp $ + * + * Authors: Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ +#include + +#include /* ENOMEM */ +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#include "httpd.h" + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Activate ( vlc_object_t * ); +static void Close ( vlc_object_t * ); +static void Run ( intf_thread_t *p_intf ); + +static int httpd_page_interface_get( httpd_file_callback_args_t *p_args, + uint8_t *p_request, int i_request, + uint8_t **pp_data, int *pi_data ); + +/***************************************************************************** + * intf_sys_t: description and status of interface + *****************************************************************************/ +struct intf_sys_t +{ + httpd_t *p_httpd; + httpd_host_t *p_httpd_host; + + input_thread_t * p_input; +}; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define PORT_TEXT N_( "http interface bind port" ) +#define PORT_LONGTEXT N_( \ + "You can set the port on which the http interface will accept connections" ) +#define ADDR_TEXT N_( "http interface bind address" ) +#define ADDR_LONGTEXT N_( \ + "You can set the address on which the http interface will bind" ) + +vlc_module_begin(); + add_category_hint( N_("HTTP remote control"), NULL, VLC_TRUE ); + add_string( "http-addr", NULL, NULL, PORT_TEXT, PORT_LONGTEXT, VLC_TRUE ); + add_integer( "http-port", 8080, NULL, ADDR_TEXT, ADDR_LONGTEXT, VLC_TRUE ); + set_description( _("HTTP remote control interface") ); + set_capability( "interface", 10 ); + set_callbacks( Activate, Close ); +vlc_module_end(); + +/***************************************************************************** + * Activate: initialize and create stuff + *****************************************************************************/ +static int Activate( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t*)p_this; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + return VLC_EGENERIC; + }; + + p_intf->p_sys->p_httpd = NULL; + p_intf->p_sys->p_httpd_host = NULL; + + p_intf->pf_run = Run; + + CONSOLE_INTRO_MSG; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * CloseIntf: destroy interface + *****************************************************************************/ +void Close ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + if( p_intf->p_sys->p_httpd_host ) + p_intf->p_sys->p_httpd->pf_unregister_host( p_intf->p_sys->p_httpd, + p_intf->p_sys->p_httpd_host ); + + if( p_intf->p_sys->p_httpd ) + httpd_Release( p_intf->p_sys->p_httpd ); + + /* Destroy structure */ + free( p_intf->p_sys ); +} + +/***************************************************************************** + * Run: http interface thread + *****************************************************************************/ +static void Run( intf_thread_t *p_intf ) +{ + input_thread_t *p_input = NULL; + playlist_t *p_playlist = NULL; + httpd_file_t *p_page_intf; + +#if 0 + input_info_category_t * p_category; + input_info_t * p_info; + + off_t i_oldpos = 0; + off_t i_newpos; + double f_ratio = 1.0; +#endif + + /* Get bind address and port */ + char *psz_bind_addr = config_GetPsz( p_intf, "http-addr" ); + int i_bind_port = config_GetInt( p_intf, "http-port" ); + if( !psz_bind_addr ) psz_bind_addr = strdup( "" ); + + p_intf->p_sys->p_httpd = httpd_Find( VLC_OBJECT(p_intf), VLC_TRUE ); + if( !p_intf->p_sys->p_httpd ) + { + msg_Err( p_intf, "cannot start httpd daemon" ); + free( p_intf->p_sys ); + return; + } + + p_intf->p_sys->p_httpd_host = + p_intf->p_sys->p_httpd->pf_register_host( p_intf->p_sys->p_httpd, + psz_bind_addr, i_bind_port ); + + if( !p_intf->p_sys->p_httpd_host ) + { + msg_Err( p_intf, "cannot listen on %s:%d", psz_bind_addr, i_bind_port); + httpd_Release( p_intf->p_sys->p_httpd ); + free( p_intf->p_sys ); + return; + } + + msg_Info( p_intf, "http interface started" ); + + /* + * Register our interface page with the httpd daemon + */ + p_page_intf = p_intf->p_sys->p_httpd->pf_register_file( + p_intf->p_sys->p_httpd, "/", "text/html", + NULL, NULL, httpd_page_interface_get, + NULL, (httpd_file_callback_args_t*)p_intf ); + + while( !p_intf->b_die ) + { + + /* Manage the input part */ + if( p_input == NULL ) + { + if( p_playlist ) + { + p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT, + FIND_CHILD ); + } + else + { + p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, + FIND_ANYWHERE ); + if( p_input ) + { + p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, + FIND_PARENT ); + } + } + } + else if( p_input->b_dead ) + { + vlc_object_release( p_input ); + p_input = NULL; + } + + if( p_input ) + { + /* Get position */ + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( !p_input->b_die && p_input->stream.i_mux_rate ) + { +#if 0 +#define A p_input->stream.p_selected_area + f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate ); + i_newpos = A->i_tell * f_ratio; + + if( i_oldpos != i_newpos ) + { + i_oldpos = i_newpos; + printf( "pos: %li s / %li s\n", (long int)i_newpos, + (long int)(f_ratio * A->i_size) ); + } +#undef S +#endif + } + vlc_mutex_unlock( &p_input->stream.stream_lock ); + } + + /* Wait a bit */ + msleep( INTF_IDLE_SLEEP ); + } + + p_intf->p_sys->p_httpd->pf_unregister_file( p_intf->p_sys->p_httpd, + p_page_intf ); + + if( p_input ) + { + vlc_object_release( p_input ); + p_input = NULL; + } + + if( p_playlist ) + { + vlc_object_release( p_playlist ); + p_playlist = NULL; + } +} + +/***************************************************************************** + * Local functions + *****************************************************************************/ +static int httpd_page_interface_update( intf_thread_t *p_intf, + playlist_t *p_playlist, + uint8_t **pp_data, int *pi_data ); + +static void uri_extract_value( char *psz_uri, char *psz_name, + char *psz_value, int i_value_max ) +{ + char *p; + + p = strstr( psz_uri, psz_name ); + if( p ) + { + int i_len; + + p += strlen( psz_name ); + if( *p == '=' ) p++; + + if( strchr( p, '&' ) ) + { + i_len = strchr( p, '&' ) - p; + } + else + { + i_len = strlen( p ); + } + i_len = __MIN( i_value_max - 1, i_len ); + if( i_len > 0 ) + { + strncpy( psz_value, p, i_len ); + psz_value[i_len] = '\0'; + } + else + { + strncpy( psz_value, "", i_value_max ); + } + } + else + { + strncpy( psz_value, "", i_value_max ); + } +} + +static int httpd_page_interface_get( httpd_file_callback_args_t *p_args, + uint8_t *p_request, int i_request, + uint8_t **pp_data, int *pi_data ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_args; + playlist_t *p_playlist; + int i_ret; + + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + if( !p_playlist ) + { + return VLC_EGENERIC; + } + + if( i_request > 0) + { + char action[512]; + + uri_extract_value( p_request, "action", action, 512 ); + + if( !strcmp( action, "play" ) ) + { + int i_item; + uri_extract_value( p_request, "item", action, 512 ); + i_item = atol( action ); + playlist_Command( p_playlist, PLAYLIST_GOTO, i_item ); + msg_Dbg( p_intf, "requested playlist item: %i", i_item ); + } + else if( !strcmp( action, "stop" ) ) + { + playlist_Command( p_playlist, PLAYLIST_STOP, 0 ); + msg_Dbg( p_intf, "requested playlist stop" ); + } + else if( !strcmp( action, "pause" ) ) + { + playlist_Command( p_playlist, PLAYLIST_PAUSE, 0 ); + msg_Dbg( p_intf, "requested playlist pause" ); + } + else if( !strcmp( action, "next" ) ) + { + playlist_Command( p_playlist, PLAYLIST_GOTO, + p_playlist->i_index + 1 ); + msg_Dbg( p_intf, "requested playlist next" ); + } + else if( !strcmp( action, "previous" ) ) + { + playlist_Command( p_playlist, PLAYLIST_GOTO, + p_playlist->i_index - 1 ); + msg_Dbg( p_intf, "requested playlist previous" ); + } + else if( !strcmp( action, "add" ) ) + { + uri_extract_value( p_request, "mrl", action, 512 ); + playlist_Add( p_playlist, action, + PLAYLIST_APPEND, PLAYLIST_END ); + msg_Dbg( p_intf, "requested playlist add: %s", action ); + } + } + + i_ret = httpd_page_interface_update( p_intf, p_playlist, pp_data, pi_data); + + vlc_object_release( p_playlist ); + + return i_ret; +} + +static int httpd_page_interface_update( intf_thread_t *p_intf, + playlist_t *p_playlist, + uint8_t **pp_data, int *pi_data ) +{ + int i; + char *p; + + p = *pp_data = malloc( 10240 ); + + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "VLC Media Player\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "

" + "VLC Media Player (http interface)

\n" ); + + /* + * Display the controls + */ + p += sprintf( p, "
\n" ); + + p += sprintf( p, "
" + "" + "" + "" + "" + "

\n" ); + + p += sprintf( p, "
" + "Media Resource Locator: " + "" + "" + "
\n" ); + + p += sprintf( p, "
\n" ); + + /* + * Display the playlist items + */ + for ( i = 0; i < p_playlist->i_size; i++ ) + { + if( i == p_playlist->i_index ) p += sprintf( p, "" ); + + p += sprintf( p, "", i ); + p += sprintf( p, "%i - %s", i, + p_playlist->pp_items[i]->psz_name ); + p += sprintf( p, "" ); + + if( i == p_playlist->i_index ) p += sprintf( p, "" ); + p += sprintf( p, "
\n" ); + } + if ( i == 0 ) + { + p += sprintf( p, "no entries\n" ); + } + + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + + *pi_data = strlen( *pp_data ) + 1; + + return VLC_SUCCESS; +}