- Files:
-
- 20 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
/trunk/I_DLNAMediaController1.xml
r20 r30 5 5 local socket = require("socket") 6 6 local url = require("socket.url") 7 8 local PLUGIN_VERSION = "pre 0.6" 7 9 8 10 local MSG_CLASS = "DLNA" … … 128 130 129 131 local function warning(stuff) 130 log("warning " .. stuff, 2)132 log("warning: " .. stuff, 2) 131 133 end 132 134 133 135 local function error(stuff) 134 log("error " .. stuff, 1)136 log("error: " .. stuff, 1) 135 137 end 136 138 137 139 local function debug(stuff) 138 140 if (DEBUG_MODE) then 139 log("debug " .. stuff, 35)141 log("debug: " .. stuff) 140 142 end 141 143 end … … 350 352 status, tmp = AVTransport.GetTransportInfo({InstanceID="0"}) 351 353 if (status ~= true) then 354 debug("AVTransport.GetTransportInfo failed: going offline") 352 355 commsFailure(device, tmp) 353 356 return … … 371 374 status, tmp = AVTransport.GetMediaInfo({InstanceID="0"}) 372 375 currentUri = upnp.extractElement("CurrentURI", tmp, "") 373 currentUriMetaData = upnp. extractElement("CurrentURIMetaData", tmp, "")376 currentUriMetaData = upnp.unformatXML(upnp.extractElement("CurrentURIMetaData", tmp, "")) 374 377 changed = setData("NumberOfTracks", upnp.extractElement("NrTracks", tmp, "NOT_IMPLEMENTED"), device, changed) 375 378 changed = setData("CurrentMediaDuration", upnp.extractElement("MediaDuration", tmp, "NOT_IMPLEMENTED"), device, changed) … … 380 383 status, tmp = AVTransport.GetPositionInfo({InstanceID="0"}) 381 384 trackUri = upnp.extractElement("TrackURI", tmp, "") 382 trackUriMetaData = upnp. extractElement("TrackMetaData", tmp, "")385 trackUriMetaData = upnp.unformatXML(upnp.extractElement("TrackMetaData", tmp, "")) 383 386 changed = setData("CurrentTrack", upnp.extractElement("Track", tmp, "NOT_IMPLEMENTED"), device, changed) 384 387 changed = setData("CurrentTrackDuration", upnp.extractElement("TrackDuration", tmp, "NOT_IMPLEMENTED"), device, changed) … … 407 410 status, tmp = Rendering.GetMute({OrderedArgs={"InstanceID=0", "Channel=Master"}}) 408 411 if (status ~= true) then 412 debug("Rendering.GetMute failed: going offline") 409 413 commsFailure(device, tmp) 410 414 return … … 442 446 443 447 if (status ~= true) then 448 debug("Rendering.GetVolume failed: going offline") 444 449 commsFailure(device, tmp) 445 450 return … … 470 475 471 476 if (status ~= true) then 477 debug("Rendering.GetMute failed: going offline") 472 478 commsFailure(device, tmp) 473 479 return … … 507 513 508 514 if (cxt == nil) then 509 log("Please save the context before restoring it !")515 warning("Please save the context before restoring it !") 510 516 return 511 517 end … … 580 586 581 587 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 582 644 end 583 645 … … 599 661 -- TTS case 600 662 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 641 669 return 642 670 end … … 661 689 local Rendering = upnp.getService(uuidDMR, UPNP_RENDERING_CONTROL_SERVICE) 662 690 663 if (AVTransport ~= nil and uri ~= nil and uri ~= "") then691 if (AVTransport ~= nil) then 664 692 if (dataTable.TransportState ~= "NO_MEDIA_PRESENT") then 665 693 AVTransport.Stop({InstanceID=instanceId}) … … 723 751 local newDevice = false 724 752 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) then753 local baseURL, newIP, newPort, baseDirectory = newDescrURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 754 if (baseURL == nil or newIP == nil or newPort == nil or baseDirectory == nil) then 727 755 luup.variable_set(DLNA_DMC_SID, "DescriptionURL", DMRDescriptionURL, device) 728 756 elseif (newDescrURL ~= DMRDescriptionURL) then … … 736 764 changed = setData("ModelName", "", device, changed) 737 765 changed = setData("Online", "0", device, changed) 766 debug("Switching to a new DMR: setting variable Online to 0") 738 767 end 739 768 740 769 local descrXML = upnp.UPnP_getDeviceDescription(DMRDescriptionURL) 741 770 if (descrXML == nil) then 771 debug("upnp.UPnP_getDeviceDescription failed: going offline") 742 772 deviceIsOffline(device) 743 773 return … … 756 786 iconURL = upnp.getIconFromDescription(descrXML) 757 787 if (iconURL ~= nil) then 758 iconURL = u rl.absolute(string.format("http://%s:%s/", ipDMR, portDMR), iconURL)788 iconURL = upnp.buildURL(baseURL, baseDirectory, iconURL) 759 789 else 760 790 iconURL = PLUGIN_ICON:format(VERA_IP, VERA_WEB_PORT) … … 762 792 763 793 if (upnp.aresServicesLoaded(uuidDMR) == false) then 764 upnp.addServices(uuidDMR, ipDMR, portDMR, descrXML,794 upnp.addServices(uuidDMR, DMRDescriptionURL, descrXML, 765 795 "urn:schemas-upnp-org:device:MediaRenderer:1", 766 796 { UPNP_AVTRANSPORT_SERVICE, … … 798 828 local function setupDMS(descrURL) 799 829 if (descrURL ~= nil) then 800 local newIP, newPort = descrURL:match("http://([%d%.]-):(%d+)/.-")801 if (newIP == nil or newPort== nil) then830 local baseURL, newIP, newPort, baseDirectory = descrURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 831 if (baseURL == nil or newIP == nil or newPort == nil or baseDirectory == nil) then 802 832 return false, "Bad server description URL" 803 833 end … … 823 853 824 854 if (upnp.aresServicesLoaded(uuidDMS) == false) then 825 upnp.addServices(uuidDMS, ipDMS, portDMS, descrXML,855 upnp.addServices(uuidDMS, DMSDescriptionURL, descrXML, 826 856 "urn:schemas-upnp-org:device:MediaServer:1", 827 857 { UPNP_MR_CONTENT_DIRECTORY_SERVICE }) … … 867 897 local item, DMRprotocol, protocol, uri 868 898 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")) 908 909 909 910 local selectedProtocol = "" … … 925 926 end 926 927 927 --log("selected protocol " .. (forceProtocol or "nil"))928 debug("selected protocol " .. (forceProtocol or "nil")) 928 929 for protocol, uri in item:gmatch('<res%s?.-%s?protocolInfo="(.-)"%s?[^>]->(.-)</res>') do 929 --log("server protocol " .. protocol)930 debug("server protocol " .. protocol) 930 931 if (forceProtocol == nil or forceProtocol == "" 931 932 or forceProtocol == "AUTO" or forceProtocol == protocol) then 932 --log("server protocol considered")933 debug("server protocol considered") 933 934 for DMRprotocol, v in pairs(DMRprotocols) do 934 935 if (protocol:match(DMRprotocol) ~= nil) then 935 --log("Matchingwith DMR protocol " .. DMRprotocol)936 debug("Matching OK with DMR protocol " .. DMRprotocol) 936 937 selectedProtocol = protocol 937 938 selectedUri = uri 938 939 break 940 else 941 debug("No matching with DMR protocol " .. DMRprotocol) 939 942 end 940 943 end … … 942 945 break 943 946 end 944 --else945 -- log("server protocol bypassed")947 else 948 debug("server protocol bypassed") 946 949 end 947 950 end … … 962 965 else 963 966 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.") 965 968 end 966 969 end … … 1097 1100 if (device ~= nil and uuid ~= nil) then 1098 1101 device = tonumber(device) 1099 log("Renewal of all event subscriptions for device " .. device)1102 debug("Renewal of all event subscriptions for device " .. device) 1100 1103 if (uuid ~= uuidDMR) then 1101 log("Renewal ignored for uuid " .. uuid)1104 debug("Renewal ignored for uuid " .. uuid) 1102 1105 elseif (upnp.subscribeToEvents(device, ipDMR, portDMR, EventSubscriptions, DLNA_DMC_SID, uuidDMR) == false) then 1103 1106 setup(device, true) … … 1158 1161 log("#" .. lul_device .. " starting up with id " .. luup.devices[lul_device].id) 1159 1162 1163 luup.variable_set(DLNA_DMC_SID, "PluginVersion", PLUGIN_VERSION, lul_device) 1164 1160 1165 if (luup.variable_get(DLNA_DMC_SID, "DMRDiscoveryResult", lul_device) == nil 1161 1166 or luup.variable_get(DLNA_DMC_SID, "DMRDiscoveryResult", lul_device) == "scanning") then … … 1194 1199 if (lang == nil) then 1195 1200 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 1196 1209 end 1197 1210 -
/trunk/L_DLNAUPnPUtility.lua
r20 r30 441 441 icnoURL = icon:match("<url>(.+)</url>") 442 442 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 445 445 if (height >= width and height > size) then 446 size = tonumber(height)446 size = height 447 447 resultURL = icnoURL 448 448 elseif (height < width and width > size) then 449 size = tonumber(width)449 size = width 450 450 resultURL = icnoURL 451 451 end … … 472 472 473 473 474 function getServicesFromDescription(descriptionXML, deviceType, baseURL, subsetServices) 474 function buildURL(baseURL, baseDirectory, path) 475 if (path:sub(1,1) ~= "/") then 476 path = baseDirectory .. path 477 end 478 return url.absolute(baseURL, path) 479 end 480 481 482 function getServicesFromDescription(descriptionXML, deviceType, baseURL, baseDirectory, subsetServices) 475 483 local services = {} 476 484 local value, devices, device, service, service2, serviceType, serviceId, controlURL, eventSubURL … … 499 507 if (service2 == serviceType) then 500 508 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), 504 512 serviceId = serviceId, 505 actions = getActionsFromSCPD( url.absolute(baseURL, scpdURL)),513 actions = getActionsFromSCPD(buildURL(baseURL, baseDirectory, scpdURL)), 506 514 object = nil } 507 515 break … … 544 552 end 545 553 546 function addServices(uuid, ip, port, descriptionXML, deviceType, subsetServices)554 function addServices(uuid, descriptionURL, descriptionXML, deviceType, subsetServices) 547 555 if (uuid == nil or uuid == "") then 548 556 return 549 557 end 550 558 559 local baseURL, ip, port, baseDirectory = descriptionURL:match("(http://([%d%.]-):(%d+))(/.-)[^/]*$") 560 551 561 if (Services[uuid] == nil) then 552 562 Services[uuid] = {} … … 555 565 local services = getServicesFromDescription( 556 566 descriptionXML, deviceType, 557 string.format("http://%s:%s/", ip, port),567 baseURL, baseDirectory, 558 568 subsetServices) 559 569 for k,v in pairs(services) do … … 728 738 "SortCriteria="}}) 729 739 if (status == true) then 730 result = mergeDIDL(result, extractElement("Result", tmp, ""))740 result = mergeDIDL(result, unformatXML(extractElement("Result", tmp, ""))) 731 741 fetched = fetched + tonumber(extractElement("NumberReturned", tmp, "")) 732 742 total = tonumber(extractElement("TotalMatches", tmp, "")) -
/trunk/J_DLNAMediaController1.js
r20 r30 266 266 function DLNA_showHelp(device) 267 267 { 268 var version = get_device_state(device, DLNA_DMC_SID, "PluginVersion", 1); 269 if (version == undefined) { 270 version = ''; 271 } 272 268 273 var html = '<table cellspacing="10">'; 274 html += '<tr>'; 275 html += '<td>Plugin version:</td>'; 276 html += '<td>' + version + '</td>'; 277 html += '</tr>'; 269 278 html += '<tr>'; 270 279 html += '<td>DMS description URL:</td>';
Note: See TracChangeset
for help on using the changeset viewer.