[vlc-devel] [PATCH] UPnP discovery: add support for SAT>IP servers
Hugo Beauzée-Luyssen
hugo at beauzee.fr
Fri Oct 16 18:35:43 CEST 2015
On 10/16/2015 02:45 PM, Felix Paul Kühne wrote:
> Some servers don't provide a playlist of their channels, so we need to download the list for the chosen satellite from the web and process it accordingly
> ---
> modules/services_discovery/upnp.cpp | 111 ++++++++++++++++++++++++++++++++----
> modules/services_discovery/upnp.hpp | 1 +
> share/Makefile.am | 2 +
> share/lua/playlist/satip.lua | 66 +++++++++++++++++++++
> 4 files changed, 170 insertions(+), 10 deletions(-)
> create mode 100644 share/lua/playlist/satip.lua
>
> diff --git a/modules/services_discovery/upnp.cpp b/modules/services_discovery/upnp.cpp
> index 86f2590..fd01eea 100644
> --- a/modules/services_discovery/upnp.cpp
> +++ b/modules/services_discovery/upnp.cpp
> @@ -42,6 +42,19 @@
> */
> const char* MEDIA_SERVER_DEVICE_TYPE = "urn:schemas-upnp-org:device:MediaServer:1";
> const char* CONTENT_DIRECTORY_SERVICE_TYPE = "urn:schemas-upnp-org:service:ContentDirectory:1";
> +const char* SATIP_SERVER_DEVICE_TYPE = "urn:ses-com:device:SatIPServer:1";
> +
> +#define SATIP_SATELLITE N_("SAT>IP satellite")
> +#define SATIP_SATELLITE_LONG N_( "VLC will download the channel list for SAT>IP " \
> +"playback based on the chosen satellite.")
> +static const char *const ppsz_satip_satellites[] = {
> + "ASTRA_19_2E", "ASTRA_28_2E", "ASTRA_23_5E", "eutelsat_13_0E", "eutelsat_09_0E",
> + "eutelsat_05_0W", "hispasat_30_0W"
> +};
> +static const char *const ppsz_readible_satip_satellites[] = {
> + "Astra 19.2°E", "Astra 28.2°E", "Astra 23.5°E", "Eutelsat 13.0°E", "Eutelsat 09.0°E",
> + "Eutelsat 05.0°W", "Hispasat 30.0°W"
> +};
>
> /*
> * VLC handle
> @@ -89,6 +102,12 @@ vlc_module_begin()
> set_capability( "services_discovery", 0 );
> set_callbacks( SD::Open, SD::Close );
>
> + set_description( N_("SAT>IP") )
> + add_string( "satip-satellite", "ASTRA_19_2E", SATIP_SATELLITE,
> + SATIP_SATELLITE_LONG, false )
> + change_string_list( ppsz_satip_satellites, ppsz_readible_satip_satellites )
> + change_safe ()
> +
> add_submodule()
> set_category( CAT_INPUT )
> set_subcategory( SUBCAT_INPUT_ACCESS )
> @@ -213,6 +232,16 @@ static int Open( vlc_object_t *p_this )
> return VLC_EGENERIC;
> }
>
> + /* Search for Sat Ip servers*/
> + i_res = UpnpSearchAsync( p_sys->p_upnp->handle(), 5,
> + SATIP_SERVER_DEVICE_TYPE, p_sys->p_upnp );
> + if( i_res != UPNP_E_SUCCESS )
> + {
> + msg_Err( p_sd, "Error sending search request: %s", UpnpGetErrorMessage( i_res ) );
> + Close( p_this );
> + return VLC_EGENERIC;
> + }
> +
> return VLC_SUCCESS;
> }
>
> @@ -235,6 +264,7 @@ MediaServerDesc::MediaServerDesc(const std::string& udn, const std::string& fNam
> , friendlyName( fName )
> , location( loc )
> , inputItem( NULL )
> + , isSatIp( false )
> {
> }
>
> @@ -268,15 +298,21 @@ bool MediaServerList::addServer( MediaServerDesc* desc )
>
> msg_Dbg( p_sd_, "Adding server '%s' with uuid '%s'", desc->friendlyName.c_str(), desc->UDN.c_str() );
>
> - char* psz_mrl;
> - if( asprintf(&psz_mrl, "upnp://%s?ObjectID=0", desc->location.c_str() ) < 0 )
> - return false;
> -
> - p_input_item = input_item_NewWithTypeExt( psz_mrl, desc->friendlyName.c_str(), 0,
> - NULL, 0, -1, ITEM_TYPE_NODE, 1);
> - free( psz_mrl );
> - if ( !p_input_item )
> - return false;
> + if ( desc->isSatIp )
> + {
> + p_input_item = input_item_NewWithTypeExt( desc->location.c_str(), desc->friendlyName.c_str(), 0,
> + NULL, 0, -1, ITEM_TYPE_NODE, 1);
> + } else {
> + char* psz_mrl;
> + if( asprintf(&psz_mrl, "upnp://%s?ObjectID=0", desc->location.c_str() ) < 0 )
> + return false;
> +
> + p_input_item = input_item_NewWithTypeExt( psz_mrl, desc->friendlyName.c_str(), 0,
> + NULL, 0, -1, ITEM_TYPE_NODE, 1);
> + free( psz_mrl );
> + if ( !p_input_item )
> + return false;
The p_input_item check should be moved below, to also account for the
item created in the if branch.
> + }
> desc->inputItem = p_input_item;
> input_item_SetDescription( p_input_item, desc->UDN.c_str() );
> services_discovery_AddItem( p_sd_, p_input_item, NULL );
> @@ -349,7 +385,9 @@ void MediaServerList::parseNewServer( IXML_Document *doc, const std::string &loc
> }
>
> if ( strncmp( MEDIA_SERVER_DEVICE_TYPE, psz_device_type,
> - strlen( MEDIA_SERVER_DEVICE_TYPE ) - 1 ) )
> + strlen( MEDIA_SERVER_DEVICE_TYPE ) - 1 )
> + && strncmp( SATIP_SERVER_DEVICE_TYPE, psz_device_type,
> + strlen( SATIP_SERVER_DEVICE_TYPE ) - 1 ) )
> continue;
>
> const char* psz_udn = xml_getChildElementValue( p_device_element,
> @@ -380,6 +418,59 @@ void MediaServerList::parseNewServer( IXML_Document *doc, const std::string &loc
> // We now have basic info, we need to get the content browsing url
> // so the access module can browse without fetching the manifest again
>
> + if ( !strncmp( SATIP_SERVER_DEVICE_TYPE, psz_device_type,
> + strlen( SATIP_SERVER_DEVICE_TYPE ) - 1 ) )
> + {
> + /* Check for SAT>IP m3u list, which is provided by some off-standard devices */
> + const char* psz_m3u_url = xml_getChildElementValue( p_device_element, "satip:X_SATIPM3U" );
> + SD::MediaServerDesc* p_server = NULL;
> + if ( psz_m3u_url ) {
> +
> + if ( strncmp( "http://", psz_m3u_url, 7) && strncmp( "https://", psz_m3u_url, 8) )
> + {
> + char* psz_url = NULL;
> + if ( UpnpResolveURL2( psz_base_url, psz_m3u_url, &psz_url ) == UPNP_E_SUCCESS )
> + {
> + p_server = new(std::nothrow) SD::MediaServerDesc( psz_udn, psz_friendly_name, psz_url );
> + free(psz_url);
> + }
> + } else
> + p_server = new(std::nothrow) SD::MediaServerDesc( psz_udn, psz_friendly_name, psz_m3u_url );
> +
> + if ( unlikely( !p_server ) )
> + break;
> +
> + p_server->isSatIp = true;
> + if ( !addServer( p_server ) )
> + delete p_server;
> + } else {
> + /* if no playlist is found, add a playlist from the web based on the chosen
> + * satellite, which will be processed by a lua script a bit later */
> + vlc_url_t url;
> + vlc_UrlParse( &url, psz_base_url );
> + char* psz_url;
> +
> + if (asprintf( &psz_url, "http/lua://www.satip.info/Playlists/%s.m3u?device=%s",
> + config_GetPsz(p_sd_, "satip-satellite"),
You're leaking config_GetPsz result
> + url.psz_host ) < 0 ) {
> + vlc_UrlClean( &url );
> + continue;
> + }
> + vlc_UrlClean( &url );
> +
> + p_server = new(std::nothrow) SD::MediaServerDesc( psz_udn,
> + psz_friendly_name, psz_url );
> +
> + p_server->isSatIp = true;
> + if(!addServer(p_server)) {
> + delete p_server;
> + }
> + free( psz_url );
> + }
> +
> + continue;
> + }
> +
> /* Check for ContentDirectory service. */
> IXML_NodeList* p_service_list = ixmlElement_getElementsByTagName( p_device_element, "service" );
> if ( !p_service_list )
> diff --git a/modules/services_discovery/upnp.hpp b/modules/services_discovery/upnp.hpp
> index db37f3d..986cf9e 100644
> --- a/modules/services_discovery/upnp.hpp
> +++ b/modules/services_discovery/upnp.hpp
> @@ -87,6 +87,7 @@ struct MediaServerDesc
> std::string friendlyName;
> std::string location;
> input_item_t* inputItem;
> + bool isSatIp;
> };
>
>
> diff --git a/share/Makefile.am b/share/Makefile.am
> index 8c7c36c..1b0c57d 100644
> --- a/share/Makefile.am
> +++ b/share/Makefile.am
> @@ -143,6 +143,7 @@ nobase_vlclib_DATA = \
> lua/playlist/pinkbike.luac \
> lua/playlist/pluzz.luac \
> lua/playlist/rockbox_fm_presets.luac \
> + lua/playlist/satip.luac \
> lua/playlist/soundcloud.luac \
> lua/playlist/vimeo.luac \
> lua/playlist/youtube.luac \
> @@ -237,6 +238,7 @@ EXTRA_DIST += \
> lua/playlist/pinkbike.lua \
> lua/playlist/pluzz.lua \
> lua/playlist/rockbox_fm_presets.lua \
> + lua/playlist/satip.lua \
> lua/playlist/soundcloud.lua \
> lua/playlist/vimeo.lua \
> lua/playlist/youtube.lua \
> diff --git a/share/lua/playlist/satip.lua b/share/lua/playlist/satip.lua
> new file mode 100644
> index 0000000..950d680
> --- /dev/null
> +++ b/share/lua/playlist/satip.lua
> @@ -0,0 +1,66 @@
> +--[[
> + $Id$
> +
> + Copyright © 2015 Videolabs SAS
> +
> + Authors: Felix Paul Kühne (fkuehne at videolan.org)
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms of the GNU Lesser General Public License as published by
> + the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public License
> + along with this program; if not, write to the Free Software Foundation,
> + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> +--]]
> +
> +function get_url_param( url, name )
> + local _, _, res = string.find( url, "[&?]"..name.."=([^&]*)" )
> + return res
> +end
> +
> +-- Probe function.
> +function probe()
> + if vlc.access ~= "http" then
> + return false
> + end
> +
> + return ( string.match( vlc.path, "www.satip.info" ) )
> +end
> +
> +-- Parse function.
> +function parse()
> + local satiphost = get_url_param( vlc.path, "device")
> +
> + vlc.msg.dbg("Parsing SAT>IP playlist for host "..satiphost)
> +
> + -- Skip the prefix line
> + line = vlc.readline()
> +
> + p = {}
> + i = 0
> +
> + while true do
> + name = vlc.readline()
> + if not name then break end
> +
> + name = vlc.strings.from_charset( "ISO_8859-1", name )
> + name = string.gsub(name,"#EXTINF:0,","")
> +
> + url = vlc.readline()
> + if not url then break end
> +
> + finalurl = string.gsub(url,"sat.ip",satiphost)
> + finalurl = string.gsub(finalurl,"rtsp","satip")
> +
> + table.insert( p, { path = finalurl, url = finalurl, name = name } )
> + end
> +
> + return p
> +end
>
More information about the vlc-devel
mailing list