Changes in / [20:30]


Ignore:
Files:
20 added
3 edited

Legend:

Unmodified
Added
Removed
  • /trunk/I_DLNAMediaController1.xml

    r20 r30  
    55  local socket = require("socket") 
    66  local url = require("socket.url") 
     7 
     8  local PLUGIN_VERSION = "pre 0.6" 
    79 
    810  local MSG_CLASS = "DLNA" 
     
    128130 
    129131  local function warning(stuff) 
    130     log("warning " .. stuff, 2) 
     132    log("warning: " .. stuff, 2) 
    131133  end 
    132134 
    133135  local function error(stuff) 
    134     log("error " .. stuff, 1) 
     136    log("error: " .. stuff, 1) 
    135137  end 
    136138 
    137139  local function debug(stuff) 
    138140    if (DEBUG_MODE) then 
    139       log("debug " .. stuff, 35) 
     141      log("debug: " .. stuff) 
    140142    end 
    141143  end 
     
    350352        status, tmp = AVTransport.GetTransportInfo({InstanceID="0"}) 
    351353        if (status ~= true) then 
     354            debug("AVTransport.GetTransportInfo failed: going offline") 
    352355            commsFailure(device, tmp) 
    353356            return 
     
    371374        status, tmp = AVTransport.GetMediaInfo({InstanceID="0"}) 
    372375        currentUri = upnp.extractElement("CurrentURI", tmp, "") 
    373         currentUriMetaData = upnp.extractElement("CurrentURIMetaData", tmp, "") 
     376        currentUriMetaData = upnp.unformatXML(upnp.extractElement("CurrentURIMetaData", tmp, "")) 
    374377        changed = setData("NumberOfTracks", upnp.extractElement("NrTracks", tmp, "NOT_IMPLEMENTED"), device, changed) 
    375378        changed = setData("CurrentMediaDuration", upnp.extractElement("MediaDuration", tmp, "NOT_IMPLEMENTED"), device, changed) 
     
    380383        status, tmp = AVTransport.GetPositionInfo({InstanceID="0"}) 
    381384        trackUri = upnp.extractElement("TrackURI", tmp, "") 
    382         trackUriMetaData = upnp.extractElement("TrackMetaData", tmp, "") 
     385        trackUriMetaData = upnp.unformatXML(upnp.extractElement("TrackMetaData", tmp, "")) 
    383386        changed = setData("CurrentTrack", upnp.extractElement("Track", tmp, "NOT_IMPLEMENTED"), device, changed) 
    384387        changed = setData("CurrentTrackDuration", upnp.extractElement("TrackDuration", tmp, "NOT_IMPLEMENTED"), device, changed) 
     
    407410        status, tmp = Rendering.GetMute({OrderedArgs={"InstanceID=0", "Channel=Master"}}) 
    408411        if (status ~= true) then 
     412            debug("Rendering.GetMute failed: going offline") 
    409413            commsFailure(device, tmp) 
    410414            return 
     
    442446 
    443447    if (status ~= true) then 
     448        debug("Rendering.GetVolume failed: going offline") 
    444449        commsFailure(device, tmp) 
    445450        return 
     
    470475 
    471476    if (status ~= true) then 
     477        debug("Rendering.GetMute failed: going offline") 
    472478        commsFailure(device, tmp) 
    473479        return 
     
    507513 
    508514    if (cxt == nil) then 
    509         log("Please save the context before restoring it !") 
     515        warning("Please save the context before restoring it !") 
    510516        return 
    511517    end 
     
    580586 
    581587    refreshNow(device, false) 
     588  end 
     589 
     590  -- Output parameters: 
     591  --   + duration: duration of the produced audio file in seconds 
     592  --   + uri: Sonos URI for playing the audio file 
     593  --   + title: title information 
     594  --   + protocol: protocol information to be exchanged with the DMR 
     595  local function runTTSengine(engine, text, language, device) 
     596    local duration = 0 
     597    local uri = nil 
     598    local title = "" 
     599    local protocol = nil 
     600 
     601    if (engine == "Google") then 
     602        -- Cut the text in fragments of max 100 characters 
     603        local tableTextFragments = {} 
     604        local cutSize = 100  
     605        local remaining = text 
     606        while (#remaining > cutSize) do 
     607            local pos = string.find(string.reverse(string.sub(remaining, 1, cutSize+1)), " ") 
     608            if (pos ~= nil) then 
     609                table.insert(tableTextFragments, string.sub(remaining, 1, cutSize+1-pos)) 
     610                remaining = string.sub(remaining, cutSize+3-pos) 
     611            else 
     612                remaining = "" 
     613            end 
     614        end 
     615        if (#remaining > 0) then 
     616            table.insert(tableTextFragments, remaining) 
     617        end 
     618 
     619        -- Get the MP3 files from Google 
     620        local strFiles = "" 
     621        for i, v in ipairs(tableTextFragments) 
     622        do 
     623            strFiles = strFiles .. " " .. SAY_TMP_FILE:format(device, i) 
     624            os.execute(SAY_EXECUTE:format(device, i, device, i, language, url.escape(v))) 
     625        end 
     626        -- Concat the multiple MP3 files 
     627        os.execute(CONCAT_EXECUTE:format(strFiles, device, strFiles)) 
     628 
     629        -- Get the file size to deduce its playback duration 
     630        local fh = io.open(SAY_OUTPUT_FILE:format(device), "a+") 
     631        local size = fh:seek("end") 
     632        fh:close() 
     633 
     634        -- Compute the play duration from the file size (32 kbps) 
     635        duration = math.ceil(size/4000) 
     636 
     637        uri = SAY_OUTPUT_URI:format(VERA_IP, VERA_WEB_PORT, device) 
     638 
     639        title = "Google TTS" 
     640        protocol = "http-get:*:audio/mpeg:*" 
     641    end 
     642 
     643    return duration, uri, title, protocol 
    582644  end 
    583645 
     
    599661        -- TTS case 
    600662 
    601         -- Cut the text in fragments of max 100 characters 
    602         local tableTextFragments = {} 
    603         local cutSize = 100  
    604         local remaining = text 
    605         while (#remaining > cutSize) do 
    606             local pos = string.find(string.reverse(string.sub(remaining, 1, cutSize+1)), " ") 
    607             if (pos ~= nil) then 
    608                 table.insert(tableTextFragments, string.sub(remaining, 1, cutSize+1-pos)) 
    609                 remaining = string.sub(remaining, cutSize+3-pos) 
    610             else 
    611                 remaining = "" 
    612             end 
    613         end 
    614         if (#remaining > 0) then 
    615             table.insert(tableTextFragments, remaining) 
    616         end 
    617  
    618         -- Get the MP3 files from Google 
    619         local strFiles = "" 
    620         for i, v in ipairs(tableTextFragments) 
    621         do 
    622             strFiles = strFiles .. " " .. SAY_TMP_FILE:format(device, i) 
    623             os.execute(SAY_EXECUTE:format(device, i, device, i, language, url.escape(v))) 
    624         end 
    625         -- Concat the multiple MP3 files 
    626         os.execute(CONCAT_EXECUTE:format(strFiles, device, strFiles)) 
    627  
    628         -- Get the file size to deduce its playback duration 
    629         local fh = io.open(SAY_OUTPUT_FILE:format(device), "a+") 
    630         local size = fh:seek("end") 
    631         fh:close() 
    632  
    633         -- Compute the play duration from the file size (32 kbps) 
    634         -- and add 1 second to be sure to not cut the end of the text 
    635         duration = math.ceil(size/4000) + 1 
    636  
    637         uri = SAY_OUTPUT_URI:format(VERA_IP, VERA_WEB_PORT, device) 
    638         title = "Google TTS" 
    639         protocol = "http-get:*:audio/mpeg:*" 
    640     elseif (uri == "") then 
     663        duration, uri, title, protocol = runTTSengine("Google", text, language, device) 
     664        -- add 1 second to be sure to not cut the end of the text 
     665        duration = duration + 1 
     666    end 
     667 
     668    if (uri == nil or uri == "") then 
    641669        return 
    642670    end 
     
    661689    local Rendering = upnp.getService(uuidDMR, UPNP_RENDERING_CONTROL_SERVICE) 
    662690 
    663     if (AVTransport ~= nil and uri ~= nil and uri ~= "") then 
     691    if (AVTransport ~= nil) then 
    664692        if (dataTable.TransportState ~= "NO_MEDIA_PRESENT") then 
    665693            AVTransport.Stop({InstanceID=instanceId}) 
     
    723751    local newDevice = false 
    724752    local newDescrURL = luup.variable_get(DLNA_DMC_SID, "DescriptionURL", device) or "" 
    725     local newIP, newPort = newDescrURL:match("http://([%d%.]-):(%d+)/.-") 
    726     if (newIP == nil or newPort == nil) then 
     753    local baseURL, newIP, newPort, baseDirectory = newDescrURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 
     754    if (baseURL == nil or newIP == nil or newPort == nil or baseDirectory == nil) then 
    727755        luup.variable_set(DLNA_DMC_SID, "DescriptionURL", DMRDescriptionURL, device) 
    728756    elseif (newDescrURL ~= DMRDescriptionURL) then 
     
    736764        changed = setData("ModelName", "", device, changed) 
    737765        changed = setData("Online", "0", device, changed) 
     766        debug("Switching to a new DMR: setting variable Online to 0") 
    738767    end 
    739768 
    740769    local descrXML = upnp.UPnP_getDeviceDescription(DMRDescriptionURL) 
    741770    if (descrXML == nil) then 
     771        debug("upnp.UPnP_getDeviceDescription failed: going offline") 
    742772        deviceIsOffline(device) 
    743773        return 
     
    756786    iconURL = upnp.getIconFromDescription(descrXML) 
    757787    if (iconURL ~= nil) then 
    758         iconURL = url.absolute(string.format("http://%s:%s/", ipDMR, portDMR), iconURL) 
     788        iconURL = upnp.buildURL(baseURL, baseDirectory, iconURL) 
    759789    else 
    760790        iconURL = PLUGIN_ICON:format(VERA_IP, VERA_WEB_PORT) 
     
    762792 
    763793    if (upnp.aresServicesLoaded(uuidDMR) == false) then 
    764         upnp.addServices(uuidDMR, ipDMR, portDMR, descrXML, 
     794        upnp.addServices(uuidDMR, DMRDescriptionURL, descrXML, 
    765795                         "urn:schemas-upnp-org:device:MediaRenderer:1", 
    766796                         { UPNP_AVTRANSPORT_SERVICE, 
     
    798828  local function setupDMS(descrURL) 
    799829    if (descrURL ~= nil) then 
    800         local newIP, newPort = descrURL:match("http://([%d%.]-):(%d+)/.-") 
    801         if (newIP == nil or newPort == nil) then 
     830        local baseURL, newIP, newPort, baseDirectory = descrURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 
     831        if (baseURL == nil or newIP == nil or newPort == nil or baseDirectory == nil) then 
    802832            return false, "Bad server description URL" 
    803833        end 
     
    823853 
    824854            if (upnp.aresServicesLoaded(uuidDMS) == false) then 
    825                 upnp.addServices(uuidDMS, ipDMS, portDMS, descrXML, 
     855                upnp.addServices(uuidDMS, DMSDescriptionURL, descrXML, 
    826856                                 "urn:schemas-upnp-org:device:MediaServer:1", 
    827857                                 { UPNP_MR_CONTENT_DIRECTORY_SERVICE }) 
     
    867897    local item, DMRprotocol, protocol, uri 
    868898 
    869     -- local item = nil 
    870     -- local elt, id, startItem, endItem, startDIDL, endDIDL 
    871     -- local directory = luup.variable_get(DLNA_DMC_SID, "BrowseResult", device) or "" 
    872     -- for elt, id in directory:gmatch('(<item.-%sid="([^"]-)"[^>]->.-</item>)') do 
    873         -- if (upnp.decode(id) == object) then 
    874             -- startItem, item, endItem = elt:match("(<item%s?[^>]->.-)(<res%s?[^>]->.*</res>)(.-</item>)") 
    875             -- if (startItem ~= nil and endItem ~= nil) then 
    876                 -- startDIDL = directory:match("(<DIDL%-Lite%s?[^>]->)") .. startItem 
    877                 -- endDIDL = endItem .. '</DIDL-Lite>' 
    878 -- log("compare") 
    879 -- local xml = upnp.browseContent(uuidDMS, UPNP_MR_CONTENT_DIRECTORY_SERVICE, object, true) 
    880 -- local startDIDL2, item2, endDIDL2 = xml:match("(<DIDL%-Lite%s?[^>]-><item%s?[^>]->.-)(<res%s?[^>]->.*</res>)(.-</item></DIDL%-Lite>)") 
    881 -- if (startDIDL ~= startDIDL2) then 
    882 -- log("diff startDIDL") 
    883 -- log("startDIDL " .. startDIDL) 
    884 -- log("startDIDL2 " .. startDIDL2) 
    885 -- end 
    886 -- if (endDIDL ~= endDIDL2) then 
    887 -- log("diff endDIDL") 
    888 -- log("endDIDL " .. endDIDL) 
    889 -- log("endDIDL2 " .. endDIDL2) 
    890 -- end 
    891 -- if (item ~= item2) then 
    892 -- log("diff item") 
    893 -- log("item " .. item) 
    894 -- log("item2 " .. item2) 
    895 -- end 
    896             -- end 
    897             -- break 
    898         -- end 
    899     -- end 
    900     -- if (item == nil) then 
    901         local xml = upnp.browseContent(uuidDMS, UPNP_MR_CONTENT_DIRECTORY_SERVICE, object, true) 
    902         if (xml == "") then 
    903             luup.variable_set(DLNA_DMC_SID, "PlaybackResult", "Media not available", device) 
    904             return 
    905         end 
    906         local startDIDL, item, endDIDL = xml:match("(<DIDL%-Lite%s?[^>]-><item%s?[^>]->.-)(<res%s?[^>]->.*</res>)(.-</item></DIDL%-Lite>)") 
    907     -- end 
     899    local xml = upnp.browseContent(uuidDMS, UPNP_MR_CONTENT_DIRECTORY_SERVICE, object, true) 
     900    debug("data from server: " .. (xml or "nil")) 
     901    if (xml == "") then 
     902        luup.variable_set(DLNA_DMC_SID, "PlaybackResult", "Media not available", device) 
     903        return 
     904    end 
     905    local startDIDL, item, endDIDL = xml:match("(<DIDL%-Lite%s?[^>]-><item%s?[^>]->.-)(<res%s?[^>]->.*</res>)(.-</item></DIDL%-Lite>)") 
     906    debug("startDIDL: " .. (startDIDL or "nil")) 
     907    debug("endDIDL: " .. (endDIDL or "nil")) 
     908    debug("res: " .. (item or "nil")) 
    908909 
    909910    local selectedProtocol = "" 
     
    925926        end 
    926927 
    927 --log("selected protocol " .. (forceProtocol or "nil")) 
     928        debug("selected protocol " .. (forceProtocol or "nil")) 
    928929        for protocol, uri in item:gmatch('<res%s?.-%s?protocolInfo="(.-)"%s?[^>]->(.-)</res>') do 
    929 --log("server protocol " .. protocol) 
     930            debug("server protocol " .. protocol) 
    930931            if (forceProtocol == nil or forceProtocol == "" 
    931932                    or forceProtocol == "AUTO" or forceProtocol == protocol) then 
    932 --log("server protocol considered") 
     933                debug("server protocol considered") 
    933934                for DMRprotocol, v in pairs(DMRprotocols) do 
    934935                    if (protocol:match(DMRprotocol) ~= nil) then 
    935 --log("Matching with DMR protocol " .. DMRprotocol) 
     936                        debug("Matching OK with DMR protocol " .. DMRprotocol) 
    936937                        selectedProtocol = protocol 
    937938                        selectedUri = uri 
    938939                        break 
     940                    else 
     941                        debug("No matching with DMR protocol " .. DMRprotocol) 
    939942                    end 
    940943                end 
     
    942945                    break 
    943946                end 
    944             -- else 
    945 -- log("server protocol bypassed") 
     947            else 
     948                debug("server protocol bypassed") 
    946949            end 
    947950        end 
     
    962965    else 
    963966        luup.variable_set(DLNA_DMC_SID, "PlaybackResult", "Media not compatible with renderer", device) 
    964         log("Media cannot be rendered by the selected renderer.", 2) 
     967        warning("Media cannot be rendered by the selected renderer.") 
    965968    end 
    966969  end 
     
    10971100    if (device ~= nil and uuid ~= nil) then 
    10981101        device = tonumber(device) 
    1099         log("Renewal of all event subscriptions for device " .. device) 
     1102        debug("Renewal of all event subscriptions for device " .. device) 
    11001103        if (uuid ~= uuidDMR) then 
    1101             log("Renewal ignored for uuid " .. uuid) 
     1104            debug("Renewal ignored for uuid " .. uuid) 
    11021105        elseif (upnp.subscribeToEvents(device, ipDMR, portDMR, EventSubscriptions, DLNA_DMC_SID, uuidDMR) == false) then 
    11031106            setup(device, true) 
     
    11581161    log("#" .. lul_device .. " starting up with id " .. luup.devices[lul_device].id) 
    11591162 
     1163    luup.variable_set(DLNA_DMC_SID, "PluginVersion", PLUGIN_VERSION, lul_device) 
     1164 
    11601165    if (luup.variable_get(DLNA_DMC_SID, "DMRDiscoveryResult", lul_device) == nil 
    11611166            or luup.variable_get(DLNA_DMC_SID, "DMRDiscoveryResult", lul_device) == "scanning") then 
     
    11941199    if (lang == nil) then 
    11951200        luup.variable_set(DLNA_DMC_SID, "DefaultLanguageTTS", "en", lul_device) 
     1201    end 
     1202 
     1203    local debugLogs = luup.variable_get(DLNA_DMC_SID, "DebugLogs", lul_device) 
     1204    if (debugLogs == nil or tonumber(debugLogs) == nil) then 
     1205        luup.variable_set(DLNA_DMC_SID, "DebugLogs", "0", lul_device) 
     1206    end 
     1207    if (luup.variable_get(DLNA_DMC_SID, "DebugLogs", lul_device) == "1") then 
     1208        DEBUG_MODE = true 
    11961209    end 
    11971210 
  • /trunk/L_DLNAUPnPUtility.lua

    r20 r30  
    441441        icnoURL = icon:match("<url>(.+)</url>") 
    442442        if (icnoURL ~= nil and height ~= nil and width ~= nil) then 
    443             height = tonumber(height) 
    444             width = tonumber(width) 
     443            height = tonumber(height) or 0 
     444            width = tonumber(width) or 0 
    445445            if (height >= width and height > size) then 
    446                 size = tonumber(height) 
     446                size = height 
    447447                resultURL = icnoURL 
    448448            elseif (height < width and width > size) then 
    449                 size = tonumber(width) 
     449                size = width 
    450450                resultURL = icnoURL 
    451451            end 
     
    472472 
    473473 
    474 function getServicesFromDescription(descriptionXML, deviceType, baseURL, subsetServices) 
     474function buildURL(baseURL, baseDirectory, path) 
     475    if (path:sub(1,1) ~= "/") then 
     476        path = baseDirectory .. path 
     477    end 
     478    return url.absolute(baseURL, path) 
     479end 
     480 
     481 
     482function getServicesFromDescription(descriptionXML, deviceType, baseURL, baseDirectory, subsetServices) 
    475483    local services = {} 
    476484    local value, devices, device, service, service2, serviceType, serviceId, controlURL, eventSubURL 
     
    499507                            if (service2 == serviceType) then 
    500508                               services[serviceType] = { 
    501                                        controlURL = url.absolute(baseURL, controlURL), 
    502                                        eventSubURL = url.absolute(baseURL, eventSubURL), 
    503                                        scpdURL = url.absolute(baseURL, scpdURL), 
     509                                       controlURL = buildURL(baseURL, baseDirectory, controlURL), 
     510                                       eventSubURL = buildURL(baseURL, baseDirectory, eventSubURL), 
     511                                       scpdURL = buildURL(baseURL, baseDirectory, scpdURL), 
    504512                                       serviceId = serviceId, 
    505                                        actions = getActionsFromSCPD(url.absolute(baseURL, scpdURL)), 
     513                                       actions = getActionsFromSCPD(buildURL(baseURL, baseDirectory, scpdURL)), 
    506514                                       object = nil } 
    507515                                break 
     
    544552  end 
    545553 
    546   function addServices(uuid, ip, port, descriptionXML, deviceType, subsetServices) 
     554  function addServices(uuid, descriptionURL, descriptionXML, deviceType, subsetServices) 
    547555    if (uuid == nil or uuid == "") then 
    548556        return 
    549557    end 
    550558 
     559    local baseURL, ip, port, baseDirectory = descriptionURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 
     560 
    551561    if (Services[uuid] == nil) then 
    552562        Services[uuid] = {} 
     
    555565    local services = getServicesFromDescription( 
    556566                              descriptionXML, deviceType, 
    557                               string.format("http://%s:%s/", ip, port), 
     567                              baseURL, baseDirectory, 
    558568                              subsetServices) 
    559569    for k,v in pairs(services) do 
     
    728738                                 "SortCriteria="}}) 
    729739          if (status == true) then 
    730               result = mergeDIDL(result, extractElement("Result", tmp, "")) 
     740              result = mergeDIDL(result, unformatXML(extractElement("Result", tmp, ""))) 
    731741              fetched = fetched + tonumber(extractElement("NumberReturned", tmp, "")) 
    732742              total = tonumber(extractElement("TotalMatches", tmp, "")) 
  • /trunk/J_DLNAMediaController1.js

    r20 r30  
    266266function DLNA_showHelp(device) 
    267267{ 
     268    var version = get_device_state(device, DLNA_DMC_SID, "PluginVersion", 1); 
     269    if (version == undefined) { 
     270        version = ''; 
     271    } 
     272 
    268273    var html = '<table cellspacing="10">'; 
     274    html += '<tr>'; 
     275    html += '<td>Plugin version:</td>'; 
     276    html += '<td>' + version + '</td>'; 
     277    html += '</tr>'; 
    269278    html += '<tr>'; 
    270279    html += '<td>DMS description URL:</td>'; 
Note: See TracChangeset for help on using the changeset viewer.