[vlc-devel] [PATCH] UPnP discovery: add support for SAT>IP servers
Felix Paul Kühne
fkuehne at videolan.org
Fri Oct 16 14:45:05 CEST 2015
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;
+ }
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"),
+ 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
--
2.6.0
More information about the vlc-devel
mailing list