[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