[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