aboutsummaryrefslogtreecommitdiff
path: root/lib/libUPnP/Platinum/Source/Devices/MediaServer
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Platinum/Source/Devices/MediaServer')
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/ConnectionManagerSCPD.cpp10
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorySCPD.cpp3
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorywSearchSCPD.cpp5
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.cpp186
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h50
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.cpp579
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.h131
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.cpp38
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.h34
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.cpp124
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.h172
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp1082
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h168
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.cpp83
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.h85
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.cpp165
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.h106
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp31
-rw-r--r--lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h13
19 files changed, 1268 insertions, 1797 deletions
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ConnectionManagerSCPD.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ConnectionManagerSCPD.cpp
index cf97533dd8..e57e805976 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ConnectionManagerSCPD.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ConnectionManagerSCPD.cpp
@@ -2,7 +2,7 @@
|
| Platinum - ConnectionManager SCPD
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP Service SCPD for urn:schemas-upnp-org:service:ConnectionManager:1
+ */
+
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
@@ -254,3 +259,4 @@ NPT_UInt8 MS_ConnectionManagerSCPD[4216] =
0x62, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x3C, 0x2F, 0x73, 0x63, 0x70, 0x64, 0x3E, 0x0D, 0x0A, 0x00
};
+/** @} */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorySCPD.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorySCPD.cpp
index d8d51c7902..726a021792 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorySCPD.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorySCPD.cpp
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorywSearchSCPD.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorywSearchSCPD.cpp
index faf747db9e..4fb91d8e8c 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorywSearchSCPD.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/ContentDirectorywSearchSCPD.cpp
@@ -2,7 +2,7 @@
|
| Platinum - ContentDirectory SCPD
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.cpp
index ad650f3311..2c20b25c81 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.cpp
@@ -2,7 +2,7 @@
|
| Platinum - DIDL
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -35,7 +36,7 @@
| includes
+---------------------------------------------------------------------*/
#include "PltDidl.h"
-#include "PltXmlHelper.h"
+#include "PltUtilities.h"
#include "PltService.h"
NPT_SET_LOCAL_LOGGER("platinum.media.server.didl")
@@ -56,7 +57,7 @@ const char* didl_namespace_dlna = "urn:schemas-dlna-org:metadata-1-0/";
| PLT_Didl::ConvertFilterToMask
+---------------------------------------------------------------------*/
NPT_UInt32
-PLT_Didl::ConvertFilterToMask(NPT_String filter)
+PLT_Didl::ConvertFilterToMask(const NPT_String& filter)
{
// easy out
if (filter.GetLength() == 0) return PLT_FILTER_MASK_ALL;
@@ -71,64 +72,77 @@ PLT_Didl::ConvertFilterToMask(NPT_String filter)
while (s[i] != '\0') {
int next_comma = filter.Find(',', i);
- int len = ((next_comma < 0)?filter.GetLength():next_comma)-i;
+ int len = ((next_comma < 0)?(int)filter.GetLength():next_comma)-i;
if (NPT_String::CompareN(s+i, "*", 1) == 0) {
// return now, there's no point in parsing the rest
return PLT_FILTER_MASK_ALL;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CREATOR, len) == 0) {
+ }
+
+ // title is required, so we return a non empty mask
+ mask |= PLT_FILTER_MASK_TITLE;
+
+ if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_TITLE, len, true) == 0) {
+ mask |= PLT_FILTER_MASK_TITLE;
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_REFID, len, true) == 0) {
+ mask |= PLT_FILTER_MASK_REFID;
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CREATOR, len, true) == 0) {
mask |= PLT_FILTER_MASK_CREATOR;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ARTIST, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ARTIST, len, true) == 0) {
mask |= PLT_FILTER_MASK_ARTIST;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ACTOR, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ACTOR, len, true) == 0) {
mask |= PLT_FILTER_MASK_ACTOR;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_AUTHOR, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_AUTHOR, len, true) == 0) {
mask |= PLT_FILTER_MASK_AUTHOR;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DATE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DATE, len, true) == 0) {
mask |= PLT_FILTER_MASK_DATE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUM, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUM, len, true) == 0) {
mask |= PLT_FILTER_MASK_ALBUM;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_GENRE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_GENRE, len, true) == 0) {
mask |= PLT_FILTER_MASK_GENRE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUMARTURI, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUMARTURI, len, true) == 0 ||
+ NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ALBUMARTURI_DLNAPROFILEID, len, true) == 0) {
mask |= PLT_FILTER_MASK_ALBUMARTURI;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DESCRIPTION, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_DESCRIPTION, len, true) == 0) {
mask |= PLT_FILTER_MASK_DESCRIPTION;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ORIGINALTRACK, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_ORIGINALTRACK, len, true) == 0) {
mask |= PLT_FILTER_MASK_ORIGINALTRACK;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SEARCHABLE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SEARCHABLE, len, true) == 0) {
mask |= PLT_FILTER_MASK_SEARCHABLE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_SEARCHABLE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SEARCHCLASS, len, true) == 0) {
+ mask |= PLT_FILTER_MASK_SEARCHCLASS;
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_SEARCHABLE, len, true) == 0) {
mask |= PLT_FILTER_MASK_SEARCHABLE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CHILDCOUNT, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CHILDCOUNT, len, true) == 0) {
mask |= PLT_FILTER_MASK_CHILDCOUNT;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_CHILDCOUNT, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_CONTAINER_CHILDCOUNT, len, true) == 0) {
mask |= PLT_FILTER_MASK_CHILDCOUNT;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_PROGRAMTITLE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_PROGRAMTITLE, len, true) == 0) {
mask |= PLT_FILTER_MASK_PROGRAMTITLE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SERIESTITLE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_SERIESTITLE, len, true) == 0) {
mask |= PLT_FILTER_MASK_SERIESTITLE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_EPISODE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_EPISODE, len, true) == 0) {
mask |= PLT_FILTER_MASK_EPISODE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_DURATION, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES, len, true) == 0) {
+ mask |= PLT_FILTER_MASK_RES;
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_DURATION, len, true) == 0 ||
+ NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_DURATION_SHORT, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_DURATION;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_SIZE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_SIZE, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_SIZE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_PROTECTION, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_PROTECTION, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_PROTECTION;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_RESOLUTION, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_RESOLUTION, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_RESOLUTION;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_BITRATE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_BITRATE, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_BITRATE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_BITSPERSAMPLE, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_BITSPERSAMPLE, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_BITSPERSAMPLE;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_NRAUDIOCHANNELS, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_NRAUDIOCHANNELS, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_NRAUDIOCHANNELS;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_SAMPLEFREQUENCY, len) == 0) {
+ } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES_SAMPLEFREQUENCY, len, true) == 0) {
mask |= PLT_FILTER_MASK_RES | PLT_FILTER_MASK_RES_SAMPLEFREQUENCY;
- } else if (NPT_String::CompareN(s+i, PLT_FILTER_FIELD_RES, len) == 0) {
- mask |= PLT_FILTER_MASK_RES;
- }
+ }
if (next_comma < 0) {
return mask;
@@ -198,99 +212,80 @@ PLT_Didl::AppendXmlEscape(NPT_String& out, const char* in)
/*----------------------------------------------------------------------
| PLT_Didl::FormatTimeStamp
+---------------------------------------------------------------------*/
-void
-PLT_Didl::FormatTimeStamp(NPT_String& out, NPT_UInt32 seconds)
+NPT_String
+PLT_Didl::FormatTimeStamp(NPT_UInt32 seconds)
{
+ NPT_String result;
int hours = seconds/3600;
if (hours == 0) {
- out += "0:";
+ result += "0:";
} else {
- out += NPT_String::FromInteger(hours) + ":";
+ result += NPT_String::FromInteger(hours) + ":";
}
int minutes = (seconds/60)%60;
if (minutes == 0) {
- out += "00:";
+ result += "00:";
} else {
if (minutes < 10) {
- out += '0';
+ result += '0';
}
- out += NPT_String::FromInteger(minutes) + ":";
+ result += NPT_String::FromInteger(minutes) + ":";
}
int secs = seconds%60;
if (secs == 0) {
- out += "00";
+ result += "00";
} else {
if (secs < 10) {
- out += '0';
+ result += '0';
}
- out += NPT_String::FromInteger(secs);
+ result += NPT_String::FromInteger(secs);
}
- out += ".000"; // needed for XBOX360 otherwise it won't play the track
+ result += ".000"; // needed for XBOX360 otherwise it won't play the track
+ return result;
}
/*----------------------------------------------------------------------
| PLT_Didl::ParseTimeStamp
+---------------------------------------------------------------------*/
NPT_Result
-PLT_Didl::ParseTimeStamp(NPT_String timestamp, NPT_UInt32& seconds)
+PLT_Didl::ParseTimeStamp(const NPT_String& timestamp, NPT_UInt32& seconds)
{
- // assume a timestamp in the format HH:MM:SS
- int colon;
+ // assume a timestamp in the format HH:MM:SS.FFF
+ int separator;
NPT_String str = timestamp;
- NPT_UInt32 num;
+ NPT_UInt32 value;
- // extract millisecondsfirst
- if ((colon = timestamp.ReverseFind('.')) != -1) {
- str = timestamp.SubString(colon + 1);
- timestamp = timestamp.Left(colon);
+ // reset output params first
+ seconds = 0;
+
+ // remove milliseconds first if any
+ if ((separator = str.ReverseFind('.')) != -1) {
+ str = str.Left(separator);
}
+ // look for next separator
+ if ((separator = str.ReverseFind(':')) == -1) return NPT_FAILURE;
+
// extract seconds
- str = timestamp;
- if ((colon = timestamp.ReverseFind(':')) != -1) {
- str = timestamp.SubString(colon + 1);
- timestamp = timestamp.Left(colon);
- }
-
- if (NPT_FAILED(str.ToInteger(num))) {
- return NPT_FAILURE;
- }
-
- seconds = num;
+ NPT_CHECK_WARNING(str.SubString(separator+1).ToInteger(value));
+ seconds = value;
+ str = str.Left(separator);
+ // look for next separator
+ if ((separator = str.ReverseFind(':')) == -1) return NPT_FAILURE;
+
// extract minutes
- str = timestamp;
- if (timestamp.GetLength()) {
- if ((colon = timestamp.ReverseFind(':')) != -1) {
- str = timestamp.SubString(colon + 1);
- timestamp = timestamp.Left(colon);
- }
-
- if (NPT_FAILED(str.ToInteger(num))) {
- return NPT_FAILURE;
- }
-
- seconds += 60*num;
- }
-
+ NPT_CHECK_WARNING(str.SubString(separator+1).ToInteger(value));
+ seconds += 60*value;
+ str = str.Left(separator);
+
// extract hours
- str = timestamp;
- if (timestamp.GetLength()) {
- if ((colon = timestamp.ReverseFind(':')) != -1) {
- str = timestamp.SubString(colon + 1);
- timestamp = timestamp.Left(colon);
- }
-
- if (NPT_FAILED(str.ToInteger(num))) {
- return NPT_FAILURE;
- }
-
- seconds += 3600*num;
- }
-
+ NPT_CHECK_WARNING(str.ToInteger(value));
+ seconds += 3600*value;
+
return NPT_SUCCESS;
}
@@ -298,7 +293,7 @@ PLT_Didl::ParseTimeStamp(NPT_String timestamp, NPT_UInt32& seconds)
| PLT_Didl::ToDidl
+---------------------------------------------------------------------*/
NPT_Result
-PLT_Didl::ToDidl(PLT_MediaObject& object, NPT_String filter, NPT_String& didl)
+PLT_Didl::ToDidl(PLT_MediaObject& object, const NPT_String& filter, NPT_String& didl)
{
NPT_UInt32 mask = ConvertFilterToMask(filter);
@@ -353,9 +348,10 @@ PLT_Didl::FromDidl(const char* xml, PLT_MediaObjectListReference& objects)
continue;
}
- if(NPT_FAILED(object->FromDidl(child))) {
- NPT_LOG_WARNING("Invalid didl");
- continue;
+ if (NPT_FAILED(object->FromDidl(child))) {
+ NPT_LOG_WARNING_1("Invalid didl for object: %s",
+ (const char*) PLT_XmlHelper::Serialize(*child, false));
+ continue;
}
objects->Add(object);
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h
index 5ccb0adf97..f6eaf1486f 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltDidl.h
@@ -2,7 +2,7 @@
|
| Platinum - DIDL handling
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Didl
+ */
+
#ifndef _PLT_DIDL_H_
#define _PLT_DIDL_H_
@@ -60,6 +65,7 @@
#define PLT_FILTER_MASK_PROGRAMTITLE 0x00001000
#define PLT_FILTER_MASK_SERIESTITLE 0x00002000
#define PLT_FILTER_MASK_EPISODE 0x00004000
+#define PLT_FILTER_MASK_TITLE 0x00008000
#define PLT_FILTER_MASK_RES 0x00010000
#define PLT_FILTER_MASK_RES_DURATION 0x00020000
@@ -71,8 +77,14 @@
#define PLT_FILTER_MASK_RES_NRAUDIOCHANNELS 0x00800000
#define PLT_FILTER_MASK_RES_SAMPLEFREQUENCY 0x01000000
+#define PLT_FILTER_MASK_LONGDESCRIPTION 0x02000000
+#define PLT_FILTER_MASK_ICON 0x04000000
+
#define PLT_FILTER_MASK_TOC 0x02000000
+#define PLT_FILTER_MASK_SEARCHCLASS 0x04000000
+#define PLT_FILTER_MASK_REFID 0x08000000
+#define PLT_FILTER_FIELD_TITLE "dc:title"
#define PLT_FILTER_FIELD_CREATOR "dc:creator"
#define PLT_FILTER_FIELD_DATE "dc:date"
#define PLT_FILTER_FIELD_ARTIST "upnp:artist"
@@ -81,18 +93,24 @@
#define PLT_FILTER_FIELD_ALBUM "upnp:album"
#define PLT_FILTER_FIELD_GENRE "upnp:genre"
#define PLT_FILTER_FIELD_ALBUMARTURI "upnp:albumArtURI"
-#define PLT_FILTER_FIELD_DESCRIPTION "upnp:longDescription"
+#define PLT_FILTER_FIELD_ALBUMARTURI_DLNAPROFILEID "upnp:albumArtURI@dlna:profileID"
+#define PLT_FILTER_FIELD_DESCRIPTION "dc:description"
+#define PLT_FILTER_FIELD_LONGDESCRIPTION "upnp:longDescription"
+#define PLT_FILTER_FIELD_ICON "upnp:icon"
#define PLT_FILTER_FIELD_ORIGINALTRACK "upnp:originalTrackNumber"
#define PLT_FILTER_FIELD_PROGRAMTITLE "upnp:programTitle"
#define PLT_FILTER_FIELD_SERIESTITLE "upnp:seriesTitle"
#define PLT_FILTER_FIELD_EPISODE "upnp:episodeNumber"
+#define PLT_FILTER_FIELD_SEARCHCLASS "upnp:searchClass"
#define PLT_FILTER_FIELD_SEARCHABLE "@searchable"
#define PLT_FILTER_FIELD_CHILDCOUNT "@childcount"
#define PLT_FILTER_FIELD_CONTAINER_CHILDCOUNT "container@childCount"
#define PLT_FILTER_FIELD_CONTAINER_SEARCHABLE "container@searchable"
+#define PLT_FILTER_FIELD_REFID "@refID"
#define PLT_FILTER_FIELD_RES "res"
#define PLT_FILTER_FIELD_RES_DURATION "res@duration"
+#define PLT_FILTER_FIELD_RES_DURATION_SHORT "@duration"
#define PLT_FILTER_FIELD_RES_SIZE "res@size"
#define PLT_FILTER_FIELD_RES_PROTECTION "res@protection"
#define PLT_FILTER_FIELD_RES_RESOLUTION "res@resolution"
@@ -105,32 +123,36 @@ extern const char* didl_header;
extern const char* didl_footer;
extern const char* didl_namespace_dc;
extern const char* didl_namespace_upnp;
+extern const char* didl_namespace_dlna;
/*----------------------------------------------------------------------
-| PLT_Didl class
+| PLT_Didl
+---------------------------------------------------------------------*/
+/**
+ DIDL manipulation.
+ The PLT_Didl class provides a mechanism to (de)serialize a PLT_MediaObject or
+ list of PLT_MediaObject (PLT_MediaObjectList).
+ */
class PLT_Didl
{
public:
- static NPT_Result ToDidl(PLT_MediaObject& object,
- NPT_String filter,
- NPT_String& didl);
+ static NPT_Result ToDidl(PLT_MediaObject& object,
+ const NPT_String& filter,
+ NPT_String& didl);
static NPT_Result FromDidl(const char* didl,
PLT_MediaObjectListReference& objects);
-
static void AppendXmlEscape(NPT_String& out, const char* in);
static void AppendXmlUnEscape(NPT_String& out, const char* in);
- static NPT_Result ParseTimeStamp(NPT_String timestamp, NPT_UInt32& seconds);
- static void FormatTimeStamp(NPT_String& out, NPT_UInt32 seconds);
-
- static NPT_Result ParseTimeStamp(NPT_String in, NPT_TimeStamp& timestamp) {
+ static NPT_Result ParseTimeStamp(const NPT_String& timestamp, NPT_UInt32& seconds);
+ static NPT_String FormatTimeStamp(NPT_UInt32 seconds);
+ static NPT_Result ParseTimeStamp(const NPT_String& in, NPT_TimeStamp& timestamp) {
NPT_UInt32 seconds;
NPT_Result res = ParseTimeStamp(in, seconds);
- timestamp = NPT_TimeStamp(seconds, 0);
+ timestamp = NPT_TimeStamp((double)seconds);
return res;
}
- static NPT_UInt32 ConvertFilterToMask(NPT_String filter);
+ static NPT_UInt32 ConvertFilterToMask(const NPT_String& filter);
};
#endif /* _PLT_DIDL_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.cpp
index 5b41c61d13..d4e6b5f3b3 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.cpp
@@ -1,8 +1,8 @@
/*****************************************************************
|
-| Platinum - File Media Server
+| Platinum - File Media Server Delegate
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -41,230 +42,85 @@
#include "PltTaskManager.h"
#include "PltHttpServer.h"
#include "PltDidl.h"
-#include "PltMetadataHandler.h"
#include "PltVersion.h"
+#include "PltMimeType.h"
-NPT_SET_LOCAL_LOGGER("platinum.media.server.file")
+NPT_SET_LOCAL_LOGGER("platinum.media.server.file.delegate")
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::PLT_FileMediaServer
+| PLT_FileMediaServerDelegate::PLT_FileMediaServerDelegate
+---------------------------------------------------------------------*/
-PLT_FileMediaServer::PLT_FileMediaServer(const char* path,
- const char* friendly_name,
- bool show_ip /* = false */,
- const char* uuid /* = NULL */,
- NPT_UInt16 port /* = 0 */,
- bool port_rebind /* = false */) :
- PLT_MediaServer(friendly_name,
- show_ip,
- uuid,
- port,
- port_rebind),
+PLT_FileMediaServerDelegate::PLT_FileMediaServerDelegate(const char* url_root,
+ const char* file_root) :
+ m_UrlRoot(url_root),
+ m_FileRoot(file_root),
m_FilterUnknownOut(false)
{
- /* set up the server root file path */
- m_Path = path;
- m_Path.TrimRight("/\\");
+ /* Trim excess separators */
+ m_FileRoot.TrimRight("/\\");
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::~PLT_FileMediaServer
+| PLT_FileMediaServerDelegate::~PLT_FileMediaServerDelegate
+---------------------------------------------------------------------*/
-PLT_FileMediaServer::~PLT_FileMediaServer()
+PLT_FileMediaServerDelegate::~PLT_FileMediaServerDelegate()
{
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::AddMetadataHandler
+| PLT_FileMediaServerDelegate::ProcessFileRequest
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::AddMetadataHandler(PLT_MetadataHandler* handler)
-{
- /* TODO: make sure we don't have a metadata handler
- already registered for the same extension */
-
- m_MetadataHandlers.Add(handler);
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer::SetupDevice
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_FileMediaServer::SetupDevice()
-{
- /* set the base paths for content and album art
- we use "0.0.0.0" for the ip as a placeholder
- to be replaced by the local interface ip a
- request is received on
- */
- m_FileBaseUri = NPT_HttpUrl("0.0.0.0", GetPort(), "/");
- m_AlbumArtBaseUri = NPT_HttpUrl("0.0.0.0", GetPort(), "/", ALBUMART_QUERY);
-
- return PLT_MediaServer::SetupDevice();
-}
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer::ProcessHttpGetRequest
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_FileMediaServer::ProcessHttpGetRequest(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response)
-{
- /* Try to handle file request first */
- NPT_Result res = ProcessFileRequest(request, context, response);
-
- /* file not found, delegate to host */
- if (response.GetStatusCode() == 404) {
- response.SetStatus(200, "OK");
- return PLT_MediaServer::ProcessHttpGetRequest(request, context, response);
- }
-
- return res;
-}
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer::ProcessGetDescription
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_FileMediaServer::ProcessGetDescription(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response)
-{
- NPT_String m_OldModelName = m_ModelName;
- NPT_String m_OldModelNumber = m_ModelNumber;
-
- /* change some things based on User-Agent header */
- NPT_HttpHeader* user_agent = request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT);
- if (user_agent && user_agent->GetValue().Find("Sonos", 0, true)>=0) {
- /* Force "Rhapsody" so that Sonos doesn't reject us */
- m_ModelName = "Rhapsody";
- m_ModelNumber = "3.0";
- }
-
- NPT_Result res = PLT_MediaServer::ProcessGetDescription(request, context, response);
-
- /* reset back to old values now */
- m_ModelName = m_OldModelName;
- m_ModelNumber = m_OldModelNumber;
-
- return res;
-}
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer::ProcessFileRequest
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response)
+PLT_FileMediaServerDelegate::ProcessFileRequest(NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& context,
+ NPT_HttpResponse& response)
{
NPT_HttpUrlQuery query(request.GetUrl().GetQuery());
-
- NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:");
- PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request);
-
- response.GetHeaders().SetHeader("Accept-Ranges", "bytes");
-
+
+ PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, "PLT_FileMediaServerDelegate::ProcessFileRequest:", &request);
+
if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) {
response.SetStatus(500, "Internal Server Error");
return NPT_SUCCESS;
}
-
+
/* Extract file path from url */
NPT_String file_path;
- NPT_CHECK_LABEL_WARNING(ExtractResourcePath(request.GetUrl(), file_path),
- failure);
-
- /* Serve album art or file */
- if (query.GetField(ALBUMART_QUERY)) {
- NPT_CHECK_WARNING(OnAlbumArtRequest(response, NPT_FilePath::Create(m_Path, file_path)));
- return NPT_SUCCESS;
- } else {
- NPT_CHECK_WARNING(ServeFile(request, context, response, NPT_FilePath::Create(m_Path, file_path)));
- return NPT_SUCCESS;
- }
-
+ NPT_CHECK_LABEL_WARNING(ExtractResourcePath(request.GetUrl(), file_path), failure);
+
+ /* Serve file */
+ NPT_CHECK_WARNING(ServeFile(request, context, response, NPT_FilePath::Create(m_FileRoot, file_path)));
+ return NPT_SUCCESS;
+
failure:
response.SetStatus(404, "File Not Found");
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::ServeFile
+| PLT_FileMediaServerDelegate::ServeFile
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::ServeFile(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response,
- const NPT_String& file_path)
+PLT_FileMediaServerDelegate::ServeFile(const NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& context,
+ NPT_HttpResponse& response,
+ const NPT_String& file_path)
{
- NPT_COMPILER_UNUSED(context);
-
- NPT_Position start, end;
- PLT_HttpHelper::GetRange(request, start, end);
-
- NPT_CHECK_WARNING(PLT_FileServer::ServeFile(response,
- file_path,
- start,
- end,
- !request.GetMethod().Compare("HEAD")));
-
- /* Update content type header according to file and context */
- NPT_HttpEntity* entity = response.GetEntity();
- PLT_HttpRequestContext tmp_context(request, context);
- if (entity) entity->SetContentType(PLT_MediaItem::GetMimeType(file_path, &tmp_context));
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer::OnAlbumArtRequest
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_FileMediaServer::OnAlbumArtRequest(NPT_HttpResponse& response,
- NPT_String file_path)
-{
- PLT_MetadataHandler* metadataHandler = NULL;
- char* caData;
- int caDataLen;
-
- /* prevent hackers from accessing files outside of our root */
- if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0) ||
- !NPT_File::Exists(file_path)) {
- goto filenotfound;
- }
-
- /* load the metadata handler and read the cover art */
- NPT_ContainerFind(m_MetadataHandlers,
- PLT_MetadataHandlerFinder(NPT_FilePath::FileExtension(file_path)),
- metadataHandler);
- if (metadataHandler &&
- NPT_SUCCEEDED(metadataHandler->Load(file_path)) &&
- NPT_SUCCEEDED(metadataHandler->GetCoverArtData(caData, caDataLen))) {
-
- PLT_HttpHelper::SetContentType(response, "application/octet-stream");
- PLT_HttpHelper::SetBody(response, caData, caDataLen);
- delete caData;
- return NPT_SUCCESS;
- }
-
-filenotfound:
- response.SetStatus(404, "File Not Found");
+ NPT_CHECK_WARNING(PLT_HttpServer::ServeFile(request, context, response, file_path));
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::OnBrowseMetadata
+| PLT_FileMediaServerDelegate::OnBrowseMetadata
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::OnBrowseMetadata(PLT_ActionReference& action,
- const char* object_id,
- const char* filter,
- NPT_UInt32 starting_index,
- NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
- const PLT_HttpRequestContext& context)
+PLT_FileMediaServerDelegate::OnBrowseMetadata(PLT_ActionReference& action,
+ const char* object_id,
+ const char* filter,
+ NPT_UInt32 starting_index,
+ NPT_UInt32 requested_count,
+ const char* sort_criteria,
+ const PLT_HttpRequestContext& context)
{
NPT_COMPILER_UNUSED(sort_criteria);
NPT_COMPILER_UNUSED(requested_count);
@@ -272,143 +128,158 @@ PLT_FileMediaServer::OnBrowseMetadata(PLT_ActionReference& action,
NPT_String didl;
PLT_MediaObjectReference item;
-
+
/* locate the file from the object ID */
NPT_String filepath;
if (NPT_FAILED(GetFilePath(object_id, filepath))) {
/* error */
- NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - ObjectID not found.");
+ NPT_LOG_WARNING("PLT_FileMediaServerDelegate::OnBrowse - ObjectID not found.");
action->SetError(701, "No Such Object.");
return NPT_FAILURE;
}
-
+
/* build the object didl */
- item = BuildFromFilePath(filepath, context, true);
+ item = BuildFromFilePath(filepath, context, true, false, (NPT_String(filter).Find("ALLIP")!=-1));
if (item.IsNull()) return NPT_FAILURE;
NPT_String tmp;
NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp));
-
+
/* add didl header and footer */
didl = didl_header + tmp + didl_footer;
-
+
NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl));
NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", "1"));
NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", "1"));
-
- // update ID may be wrong here, it should be the one of the container?
- // TODO: We need to keep track of the overall updateID of the CDS
+
+ /* update ID may be wrong here, it should be the one of the container?
+ TODO: We need to keep track of the overall updateID of the CDS */
NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1"));
-
+
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::OnBrowseDirectChildren
+| PLT_FileMediaServerDelegate::OnBrowseDirectChildren
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference& action,
- const char* object_id,
- const char* filter,
- NPT_UInt32 starting_index,
- NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
- const PLT_HttpRequestContext& context)
+PLT_FileMediaServerDelegate::OnBrowseDirectChildren(PLT_ActionReference& action,
+ const char* object_id,
+ const char* filter,
+ NPT_UInt32 starting_index,
+ NPT_UInt32 requested_count,
+ const char* sort_criteria,
+ const PLT_HttpRequestContext& context)
{
NPT_COMPILER_UNUSED(sort_criteria);
/* locate the file from the object ID */
NPT_String dir;
- if (NPT_FAILED(GetFilePath(object_id, dir))) {
- /* error */
- NPT_LOG_WARNING("ObjectID not found.");
- action->SetError(710, "No Such Container.");
- return NPT_FAILURE;
- }
-
- /* retrieve the item type */
NPT_FileInfo info;
- NPT_Result res = NPT_File::GetInfo(dir, &info);
- if (NPT_FAILED(res)) {
- /* Object does not exist */
- NPT_LOG_WARNING_1("BROWSEDIRECTCHILDREN failed for item %s", dir.GetChars());
- action->SetError(701, "No such Object");
- return NPT_FAILURE;
- }
-
- if (info.m_Type != NPT_FileInfo::FILE_TYPE_DIRECTORY) {
+ if (NPT_FAILED(GetFilePath(object_id, dir)) ||
+ NPT_FAILED(NPT_File::GetInfo(dir, &info)) ||
+ info.m_Type != NPT_FileInfo::FILE_TYPE_DIRECTORY) {
/* error */
- NPT_LOG_WARNING("BROWSEDIRECTCHILDREN not allowed on an item.");
- action->SetError(710, "No such container");
- return NPT_FAILURE;
+ NPT_LOG_WARNING_1("ObjectID \'%s\' not found or not allowed", object_id);
+ action->SetError(701, "No such Object");
+ NPT_CHECK_WARNING(NPT_FAILURE);
}
-
- NPT_List<NPT_String> entries;
- res = NPT_File::ListDir(dir, entries, 0, 0);
- if (NPT_FAILED(res)) {
- NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowseDirectChildren - failed to open dir %s", (const char*) dir);
- return res;
+
+ /* get uuid from device via action reference */
+ NPT_String uuid = action->GetActionDesc().GetService()->GetDevice()->GetUUID();
+
+ /* Try to get list from cache */
+ NPT_Result res;
+ NPT_Reference<NPT_List<NPT_String> > entries;
+ NPT_TimeStamp cached_entries_time;
+ if (NPT_FAILED(m_DirCache.Get(uuid, dir, entries, &cached_entries_time)) ||
+ cached_entries_time < info.m_ModificationTime) {
+ /* if not found in cache or if current dir has newer modified time
+ fetch fresh new list from source */
+
+ entries = new NPT_List<NPT_String>();
+ res = NPT_File::ListDir(dir, *entries);
+ if (NPT_FAILED(res)) {
+ NPT_LOG_WARNING_1("PLT_FileMediaServerDelegate::OnBrowseDirectChildren - failed to open dir %s", (const char*) dir);
+ NPT_CHECK_WARNING(res);
+ }
+
+ /* sort results according to modification date */
+ res = entries->Sort(NPT_FileDateComparator(dir));
+ if (NPT_FAILED(res)) {
+ NPT_LOG_WARNING_1("PLT_FileMediaServerDelegate::OnBrowseDirectChildren - failed to open sort dir %s", (const char*) dir);
+ NPT_CHECK_WARNING(res);
+ }
+
+ /* add new list to cache */
+ m_DirCache.Put(uuid, dir, entries, &info.m_ModificationTime);
}
-
+
unsigned long cur_index = 0;
unsigned long num_returned = 0;
unsigned long total_matches = 0;
NPT_String didl = didl_header;
-
+ bool allip = (NPT_String(filter).Find("ALLIP") != -1);
+
PLT_MediaObjectReference item;
- for (NPT_List<NPT_String>::Iterator it = entries.GetFirstItem();
+ for (NPT_List<NPT_String>::Iterator it = entries->GetFirstItem();
it;
++it) {
NPT_String filepath = NPT_FilePath::Create(dir, *it);
- // verify we want to process this file first
- if (!ProcessFile(filepath)) continue;
+ /* verify we want to process this file first */
+ if (!ProcessFile(filepath, filter)) continue;
/* build item object from file path */
- item = BuildFromFilePath(
- filepath,
- context,
- true);
-
+ item = BuildFromFilePath(filepath,
+ context,
+ true,
+ false,
+ allip);
+
/* generate didl if within range requested */
if (!item.IsNull()) {
if ((cur_index >= starting_index) &&
((num_returned < requested_count) || (requested_count == 0))) {
NPT_String tmp;
NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp));
-
+
didl += tmp;
- num_returned++;
+ ++num_returned;
}
- cur_index++;
- total_matches++;
+ ++cur_index;
+ ++total_matches;
}
};
-
+
didl += didl_footer;
-
+
+ NPT_LOG_FINE_6("BrowseDirectChildren from %s returning %d-%d/%d objects (%d out of %d requested)",
+ (const char*)context.GetLocalAddress().GetIpAddress().ToString(),
+ starting_index, starting_index+num_returned, total_matches, num_returned, requested_count);
+
NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl));
NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned)));
NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches))); // 0 means we don't know how many we have but most browsers don't like that!!
NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1"));
-
+
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::OnSearchContainer
+| PLT_FileMediaServerDelegate::OnSearchContainer
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::OnSearchContainer(PLT_ActionReference& action,
- const char* object_id,
- const char* search_criteria,
- const char* /* filter */,
- NPT_UInt32 /* starting_index */,
- NPT_UInt32 /* requested_count */,
- const NPT_List<NPT_String>& /* sort_criteria */,
- const PLT_HttpRequestContext& /* context */)
+PLT_FileMediaServerDelegate::OnSearchContainer(PLT_ActionReference& action,
+ const char* object_id,
+ const char* search_criteria,
+ const char* /* filter */,
+ NPT_UInt32 /* starting_index */,
+ NPT_UInt32 /* requested_count */,
+ const char* /* sort_criteria */,
+ const PLT_HttpRequestContext& /* context */)
{
/* parse search criteria */
-
+
/* TODO: HACK TO PASS DLNA */
if (search_criteria && NPT_StringsEqual(search_criteria, "Unknownfieldname")) {
/* error */
@@ -425,7 +296,7 @@ PLT_FileMediaServer::OnSearchContainer(PLT_ActionReference& action,
action->SetError(710, "No Such Container.");
return NPT_FAILURE;
}
-
+
/* retrieve the item type */
NPT_FileInfo info;
NPT_Result res = NPT_File::GetInfo(dir, &info);
@@ -440,183 +311,175 @@ PLT_FileMediaServer::OnSearchContainer(PLT_ActionReference& action,
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::GetFilePath
+| PLT_FileMediaServerDelegate::GetFilePath
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::GetFilePath(const char* object_id,
- NPT_String& filepath)
+PLT_FileMediaServerDelegate::GetFilePath(const char* object_id,
+ NPT_String& filepath)
{
if (!object_id) return NPT_ERROR_INVALID_PARAMETERS;
-
- filepath = m_Path;
-
- if (NPT_StringLength(object_id) > 2 || object_id[0]!='0') {
- filepath += (const char*)object_id + (object_id[0]=='0'?1:0);
+
+ filepath = m_FileRoot;
+
+ /* object id is formatted as 0/<filepath> */
+ if (NPT_StringLength(object_id) >= 1) {
+ filepath += (object_id + (object_id[0]=='0'?1:0));
}
-
+
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::BuildSafeResourceUri
+| PLT_FileMediaServerDelegate::BuildSafeResourceUri
+---------------------------------------------------------------------*/
NPT_String
-PLT_FileMediaServer::BuildSafeResourceUri(const NPT_HttpUrl& base_uri,
- const char* host,
- const char* file_path)
+PLT_FileMediaServerDelegate::BuildSafeResourceUri(const NPT_HttpUrl& base_uri,
+ const char* host,
+ const char* file_path)
{
NPT_String result;
NPT_HttpUrl uri = base_uri;
-
+
if (host) uri.SetHost(host);
-
+
NPT_String uri_path = uri.GetPath();
if (!uri_path.EndsWith("/")) uri_path += "/";
- // WMP hack: just prefix with %25/ so we know if something url decodes again
- uri_path += "%25/" + NPT_Uri::PercentEncode(file_path, " !\"<>\\^`{|}?#[]:/", true);
- uri.SetPath(uri_path);
- // 360 hack: force inclusion of port in case it's 80
+ /* some controllers (like WMP) will call us with an already urldecoded version.
+ We're intentionally prepending a known urlencoded string
+ to detect it when we receive the request urlencoded or already decoded to avoid double decoding*/
+ uri_path += "%/";
+ uri_path += file_path;
+
+ /* set path */
+ uri.SetPath(uri_path);
+
+ /* 360 hack: force inclusion of port in case it's 80 */
return uri.ToStringWithDefaultPort(0);
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::ExtractResourcePath
+| PLT_FileMediaServerDelegate::ExtractResourcePath
+---------------------------------------------------------------------*/
NPT_Result
-PLT_FileMediaServer::ExtractResourcePath(const NPT_HttpUrl& url, NPT_String& file_path)
+PLT_FileMediaServerDelegate::ExtractResourcePath(const NPT_HttpUrl& url,
+ NPT_String& file_path)
{
- // Extract uri path from url
+ /* Extract non decoded path, we need to autodetect urlencoding */
NPT_String uri_path = url.GetPath();
- if (uri_path.StartsWith(m_FileBaseUri.GetPath(), true)) {
- file_path = uri_path.SubString(m_FileBaseUri.GetPath().GetLength());
- } else if (uri_path.StartsWith(m_AlbumArtBaseUri.GetPath(), true)) {
- file_path = uri_path.SubString(m_AlbumArtBaseUri.GetPath().GetLength());
- } else
+ NPT_String url_root_encode = NPT_Uri::PercentEncode(m_UrlRoot, NPT_Uri::PathCharsToEncode);
+
+ NPT_Ordinal skip = 0;
+ if (uri_path.StartsWith(m_UrlRoot)) {
+ skip = m_UrlRoot.GetLength();
+ } else if (uri_path.StartsWith(url_root_encode)) {
+ skip = url_root_encode.GetLength();
+ } else {
return NPT_FAILURE;
+ }
+
+ /* account for extra slash */
+ skip += ((m_UrlRoot=="/")?0:1);
+ file_path = uri_path.SubString(skip);
+
+ /* detect if client such as WMP sent a non urlencoded url */
+ if (file_path.StartsWith("%/")) {
+ NPT_LOG_FINE("Received a urldecoded version of our url!");
+ file_path.Erase(0, 2);
+ } else {
+ /* remove our prepended string we used to detect urldecoded version */
+ if (file_path.StartsWith("%25/")) file_path.Erase(0, 4);
- // Detect if server is url decoding paths invalidly
- if(file_path.Left(4) == "%25/") {
+ /* ok to urldecode */
file_path = NPT_Uri::PercentDecode(file_path);
- file_path.Erase(0, 2);
- } else if(file_path.Left(2) == "%/") {
- file_path.Erase(0, 2);
- NPT_LOG_FINE("Client is urldecoding our resource paths");
}
-
+
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::BuildResourceUri
+| PLT_FileMediaServerDelegate::BuildResourceUri
+---------------------------------------------------------------------*/
NPT_String
-PLT_FileMediaServer::BuildResourceUri(const NPT_HttpUrl& base_uri,
- const char* host,
- const char* file_path)
+PLT_FileMediaServerDelegate::BuildResourceUri(const NPT_HttpUrl& base_uri,
+ const char* host,
+ const char* file_path)
{
return BuildSafeResourceUri(base_uri, host, file_path);
}
/*----------------------------------------------------------------------
-| PLT_FileMediaServer::BuildFromFilePath
+| PLT_FileMediaServerDelegate::BuildFromFilePath
+---------------------------------------------------------------------*/
PLT_MediaObject*
-PLT_FileMediaServer::BuildFromFilePath(const NPT_String& filepath,
- const PLT_HttpRequestContext& context,
- bool with_count /* = true */,
- bool keep_extension_in_title /* = false */)
+PLT_FileMediaServerDelegate::BuildFromFilePath(const NPT_String& filepath,
+ const PLT_HttpRequestContext& context,
+ bool with_count /* = true */,
+ bool keep_extension_in_title /* = false */,
+ bool allip /* = false */)
{
- NPT_String root = m_Path;
+ NPT_String root = m_FileRoot;
PLT_MediaItemResource resource;
PLT_MediaObject* object = NULL;
NPT_LOG_FINEST_1("Building didl for file '%s'", (const char*)filepath);
-
+
/* retrieve the entry type (directory or file) */
NPT_FileInfo info;
NPT_CHECK_LABEL_FATAL(NPT_File::GetInfo(filepath, &info), failure);
-
+
if (info.m_Type == NPT_FileInfo::FILE_TYPE_REGULAR) {
object = new PLT_MediaItem();
-
+
/* Set the title using the filename for now */
object->m_Title = NPT_FilePath::BaseName(filepath, keep_extension_in_title);
if (object->m_Title.GetLength() == 0) goto failure;
-
+
/* make sure we return something with a valid mimetype */
if (m_FilterUnknownOut &&
- NPT_StringsEqual(PLT_MediaItem::GetMimeType(filepath, &context),
+ NPT_StringsEqual(PLT_MimeType::GetMimeType(filepath, &context),
"application/octet-stream")) {
goto failure;
}
/* Set the protocol Info from the extension */
- resource.m_ProtocolInfo = PLT_ProtocolInfo(PLT_MediaItem::GetProtocolInfo(filepath, true, &context));
+ resource.m_ProtocolInfo = PLT_ProtocolInfo::GetProtocolInfo(filepath, true, &context);
if (!resource.m_ProtocolInfo.IsValid()) goto failure;
-
+
/* Set the resource file size */
resource.m_Size = info.m_Size;
-
+
/* format the resource URI */
NPT_String url = filepath.SubString(root.GetLength()+1);
-
+
// get list of ip addresses
NPT_List<NPT_IpAddress> ips;
NPT_CHECK_LABEL_SEVERE(PLT_UPnPMessageHelper::GetIPAddresses(ips), failure);
-
+
/* if we're passed an interface where we received the request from
move the ip to the top so that it is used for the first resource */
if (context.GetLocalAddress().GetIpAddress().ToString() != "0.0.0.0") {
ips.Remove(context.GetLocalAddress().GetIpAddress());
ips.Insert(ips.GetFirstItem(), context.GetLocalAddress().GetIpAddress());
+ } else if (!allip) {
+ NPT_LOG_WARNING("Couldn't determine local interface IP so we might return an unreachable IP");
}
- NPT_List<NPT_IpAddress>::Iterator ip = ips.GetFirstItem();
-
- /* Look to see if a metadata handler exists for this extension */
- PLT_MetadataHandler* handler = NULL;
- NPT_Result res = NPT_ContainerFind(
- m_MetadataHandlers,
- PLT_MetadataHandlerFinder(NPT_FilePath::FileExtension(filepath)),
- handler);
- if (NPT_SUCCEEDED(res) && handler) {
- /* if it failed loading data, reset the metadata handler so we don't use it */
- if (NPT_SUCCEEDED(handler->Load(filepath))) {
- /* replace the title with the one from the Metadata */
- NPT_String newTitle;
- if (handler->GetTitle(newTitle) != NULL) {
- object->m_Title = newTitle;
- }
-
- /* assign description */
- handler->GetDescription(object->m_Description.long_description);
-
- /* assign album art uri if we haven't yet */
- if (object->m_ExtraInfo.album_art_uri.GetLength() == 0) {
- object->m_ExtraInfo.album_art_uri =
- NPT_Uri::PercentEncode(BuildResourceUri(m_AlbumArtBaseUri, ip->ToString(), url),
- NPT_Uri::UnsafeCharsToEncode);
- }
-
- /* duration */
- handler->GetDuration(resource.m_Duration);
-
- /* protection */
- handler->GetProtection(resource.m_Protection);
- }
- }
-
object->m_ObjectClass.type = PLT_MediaItem::GetUPnPClass(filepath, &context);
/* add as many resources as we have interfaces s*/
+ NPT_HttpUrl base_uri("127.0.0.1", context.GetLocalAddress().GetPort(), NPT_HttpUrl::PercentEncode(m_UrlRoot, NPT_Uri::PathCharsToEncode));
+ NPT_List<NPT_IpAddress>::Iterator ip = ips.GetFirstItem();
while (ip) {
- resource.m_Uri = BuildResourceUri(m_FileBaseUri, ip->ToString(), url);
+ resource.m_Uri = BuildResourceUri(base_uri, ip->ToString(), url);
object->m_Resources.Add(resource);
++ip;
+
+ /* if we only want the one resource reachable by client */
+ if (!allip) break;
}
} else {
object = new PLT_MediaContainer;
-
+
/* Assign a title for this container */
if (filepath.Compare(root, true) == 0) {
object->m_Title = "Root";
@@ -624,16 +487,16 @@ PLT_FileMediaServer::BuildFromFilePath(const NPT_String& filepath,
object->m_Title = NPT_FilePath::BaseName(filepath, keep_extension_in_title);
if (object->m_Title.GetLength() == 0) goto failure;
}
-
+
/* Get the number of children for this container */
- NPT_Cardinal count = 0;
- if (with_count && NPT_SUCCEEDED(NPT_File::GetCount(filepath, count))) {
- ((PLT_MediaContainer*)object)->m_ChildrenCount = count;
+ NPT_LargeSize count = 0;
+ if (with_count && NPT_SUCCEEDED(NPT_File::GetSize(filepath, count))) {
+ ((PLT_MediaContainer*)object)->m_ChildrenCount = (NPT_Int32)count;
}
-
+
object->m_ObjectClass.type = "object.container.storageFolder";
}
-
+
/* is it the root? */
if (filepath.Compare(root, true) == 0) {
object->m_ParentID = "-1";
@@ -648,9 +511,9 @@ PLT_FileMediaServer::BuildFromFilePath(const NPT_String& filepath,
}
object->m_ObjectID = "0" + filepath.SubString(root.GetLength());
}
-
+
return object;
-
+
failure:
delete object;
return NULL;
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.h
index 52fb70c95c..bcb9f9704e 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltFileMediaServer.h
@@ -2,7 +2,7 @@
|
| Platinum - File Media Server
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Filesystem based Media Server sample implementation
+ */
+
#ifndef _PLT_FILE_MEDIA_SERVER_H_
#define _PLT_FILE_MEDIA_SERVER_H_
@@ -39,71 +44,42 @@
+---------------------------------------------------------------------*/
#include "Neptune.h"
#include "PltMediaServer.h"
+#include "PltMediaCache.h"
/*----------------------------------------------------------------------
-| constants
-+---------------------------------------------------------------------*/
-#define MAX_PATH_LENGTH 1024
-#define ALBUMART_QUERY "aa"
-
-/*----------------------------------------------------------------------
-| forward declarations
-+---------------------------------------------------------------------*/
-class PLT_MetadataHandler;
-
-/*----------------------------------------------------------------------
-| PLT_FileMediaServer class
+| PLT_FileMediaServerDelegate
+---------------------------------------------------------------------*/
-class PLT_FileMediaServer : public PLT_MediaServer
+/**
+ File Media Server Delegate.
+ The PLT_FileMediaServerDelegate class is an example of a PLT_MediaServerDelegate
+ implementation for a file system backed Media Server.
+ */
+class PLT_FileMediaServerDelegate : public PLT_MediaServerDelegate
{
public:
// class methods
static NPT_String BuildSafeResourceUri(const NPT_HttpUrl& base_uri,
const char* host,
const char* file_path);
-
- // constructor
- PLT_FileMediaServer(const char* path,
- const char* friendly_name,
- bool show_ip = false,
- const char* uuid = NULL,
- NPT_UInt16 port = 0,
- bool port_rebind = false);
-
- // overridable
- virtual NPT_Result AddMetadataHandler(PLT_MetadataHandler* handler);
- virtual NPT_Result ExtractResourcePath(const NPT_HttpUrl& url, NPT_String& file_path);
- virtual NPT_String BuildResourceUri(const NPT_HttpUrl& base_uri, const char* host, const char* file_path);
-
+ // constructor & destructor
+ PLT_FileMediaServerDelegate(const char* url_root, const char* file_root);
+ virtual ~PLT_FileMediaServerDelegate();
+
protected:
- virtual ~PLT_FileMediaServer();
-
- // overridable
- virtual NPT_Result ProcessFileRequest(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response);
- // PLT_DeviceHost methods
- virtual NPT_Result SetupDevice();
- virtual NPT_Result ProcessHttpGetRequest(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response);
- virtual NPT_Result ProcessGetDescription(NPT_HttpRequest& request,
- const NPT_HttpRequestContext& context,
- NPT_HttpResponse& response);
- // PLT_MediaServer methods
+ // PLT_MediaServerDelegate methods
virtual NPT_Result OnBrowseMetadata(PLT_ActionReference& action,
const char* object_id,
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
virtual NPT_Result OnBrowseDirectChildren(PLT_ActionReference& action,
const char* object_id,
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
virtual NPT_Result OnSearchContainer(PLT_ActionReference& action,
const char* object_id,
@@ -111,33 +87,64 @@ protected:
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
-
- virtual NPT_Result ServeFile(NPT_HttpRequest& request,
+ virtual NPT_Result ProcessFileRequest(NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& context,
+ NPT_HttpResponse& response);
+
+ // overridable methods
+ virtual NPT_Result ExtractResourcePath(const NPT_HttpUrl& url, NPT_String& file_path);
+ virtual NPT_String BuildResourceUri(const NPT_HttpUrl& base_uri, const char* host, const char* file_path);
+ virtual NPT_Result ServeFile(const NPT_HttpRequest& request,
const NPT_HttpRequestContext& context,
NPT_HttpResponse& response,
const NPT_String& file_path);
- virtual NPT_Result OnAlbumArtRequest(NPT_HttpResponse& response,
- NPT_String file_path);
virtual NPT_Result GetFilePath(const char* object_id, NPT_String& filepath);
- virtual bool ProcessFile(const NPT_String&) { return true;}
+ virtual bool ProcessFile(const NPT_String&, const char* filter = NULL) { NPT_COMPILER_UNUSED(filter); return true;}
virtual PLT_MediaObject* BuildFromFilePath(const NPT_String& filepath,
const PLT_HttpRequestContext& context,
bool with_count = true,
- bool keep_extension_in_title = false);
-
-public:
- NPT_UInt16 m_FileServerPort;
-
+ bool keep_extension_in_title = false,
+ bool allip = false);
+
protected:
friend class PLT_MediaItem;
+
+ NPT_String m_UrlRoot;
+ NPT_String m_FileRoot;
+ bool m_FilterUnknownOut;
+
+ PLT_MediaCache<NPT_Reference<NPT_List<NPT_String> >, NPT_TimeStamp> m_DirCache;
+};
- NPT_String m_Path;
- NPT_HttpUrl m_FileBaseUri;
- NPT_HttpUrl m_AlbumArtBaseUri;
- NPT_List<PLT_MetadataHandler*> m_MetadataHandlers;
- bool m_FilterUnknownOut;
+/*----------------------------------------------------------------------
+| PLT_FileMediaServer
++---------------------------------------------------------------------*/
+/**
+ File Media Server.
+ The PLT_FileMediaServer class is an example of a PLT_MediaServer implementation
+ for a file system backed Media Server.
+ */
+class PLT_FileMediaServer : public PLT_MediaServer,
+ public PLT_FileMediaServerDelegate
+{
+public: // constructor
+ PLT_FileMediaServer(const char* file_root,
+ const char* friendly_name,
+ bool show_ip = false,
+ const char* uuid = NULL,
+ NPT_UInt16 port = 0,
+ bool port_rebind = false) :
+ PLT_MediaServer(friendly_name,
+ show_ip,
+ uuid,
+ port,
+ port_rebind),
+ PLT_FileMediaServerDelegate("/", file_root) {SetDelegate(this);}
+
+protected:
+ virtual ~PLT_FileMediaServer() {}
};
#endif /* _PLT_FILE_MEDIA_SERVER_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.cpp
index 0eca53c3f2..266397d7da 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.cpp
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Browser (Media Server Control Point)
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -212,12 +213,14 @@ PLT_MediaBrowser::Search(PLT_DeviceDataReference& device,
}
// set the Starting Index
- if (NPT_FAILED(action->SetArgumentValue("StartingIndex", NPT_String::FromInteger(start_index)))) {
+ if (NPT_FAILED(action->SetArgumentValue("StartingIndex",
+ NPT_String::FromInteger(start_index)))) {
return NPT_ERROR_INVALID_PARAMETERS;
}
// set the Requested Count
- if (NPT_FAILED(action->SetArgumentValue("RequestedCount", NPT_String::FromInteger(count)))) {
+ if (NPT_FAILED(action->SetArgumentValue("RequestedCount",
+ NPT_String::FromInteger(count)))) {
return NPT_ERROR_INVALID_PARAMETERS;
}
@@ -266,7 +269,8 @@ PLT_MediaBrowser::Browse(PLT_DeviceDataReference& device,
}
// set the browse_flag
- if (NPT_FAILED(action->SetArgumentValue("BrowseFlag", browse_metadata?"BrowseMetadata":"BrowseDirectChildren"))) {
+ if (NPT_FAILED(action->SetArgumentValue("BrowseFlag",
+ browse_metadata?"BrowseMetadata":"BrowseDirectChildren"))) {
return NPT_ERROR_INVALID_PARAMETERS;
}
@@ -276,12 +280,14 @@ PLT_MediaBrowser::Browse(PLT_DeviceDataReference& device,
}
// set the Starting Index
- if (NPT_FAILED(action->SetArgumentValue("StartingIndex", NPT_String::FromInteger(start_index)))) {
+ if (NPT_FAILED(action->SetArgumentValue("StartingIndex",
+ NPT_String::FromInteger(start_index)))) {
return NPT_ERROR_INVALID_PARAMETERS;
}
// set the Requested Count
- if (NPT_FAILED(action->SetArgumentValue("RequestedCount", NPT_String::FromInteger(count)))) {
+ if (NPT_FAILED(action->SetArgumentValue("RequestedCount",
+ NPT_String::FromInteger(count)))) {
return NPT_ERROR_INVALID_PARAMETERS;
}
@@ -306,14 +312,12 @@ PLT_MediaBrowser::OnActionResponse(NPT_Result res,
PLT_ActionReference& action,
void* userdata)
{
- NPT_String actionName = action->GetActionDesc().GetName();
-
// look for device in our list first
PLT_DeviceDataReference device;
NPT_String uuid = action->GetActionDesc().GetService()->GetDevice()->GetUUID();
if (NPT_FAILED(FindServer(uuid, device))) res = NPT_FAILURE;
- // Browse action response
+ NPT_String actionName = action->GetActionDesc().GetName();
if (actionName.Compare("Browse", true) == 0) {
return OnBrowseResponse(res, device, action, userdata);
} else if (actionName.Compare("Search", true) == 0) {
@@ -336,6 +340,8 @@ PLT_MediaBrowser::OnBrowseResponse(NPT_Result res,
PLT_BrowseInfo info;
NPT_String unescaped;
+ if (!m_Delegate) return NPT_SUCCESS;
+
if (NPT_FAILED(res) || action->GetErrorCode() != 0) {
goto bad_action;
}
@@ -367,11 +373,11 @@ PLT_MediaBrowser::OnBrowseResponse(NPT_Result res,
goto bad_action;
}
- if (m_Delegate) m_Delegate->OnBrowseResult(NPT_SUCCESS, device, &info, userdata);
+ m_Delegate->OnBrowseResult(NPT_SUCCESS, device, &info, userdata);
return NPT_SUCCESS;
bad_action:
- if (m_Delegate) m_Delegate->OnBrowseResult(NPT_FAILURE, device, NULL, userdata);
+ m_Delegate->OnBrowseResult(NPT_FAILURE, device, NULL, userdata);
return NPT_FAILURE;
}
@@ -388,6 +394,8 @@ PLT_MediaBrowser::OnSearchResponse(NPT_Result res,
PLT_BrowseInfo info;
NPT_String unescaped;
+ if (!m_Delegate) return NPT_SUCCESS;
+
if (NPT_FAILED(res) || action->GetErrorCode() != 0) {
goto bad_action;
}
@@ -419,11 +427,11 @@ PLT_MediaBrowser::OnSearchResponse(NPT_Result res,
goto bad_action;
}
- if (m_Delegate) m_Delegate->OnSearchResult(NPT_SUCCESS, device, &info, userdata);
+ m_Delegate->OnSearchResult(NPT_SUCCESS, device, &info, userdata);
return NPT_SUCCESS;
bad_action:
- if (m_Delegate) m_Delegate->OnSearchResult(NPT_FAILURE, device, NULL, userdata);
+ m_Delegate->OnSearchResult(NPT_FAILURE, device, NULL, userdata);
return NPT_FAILURE;
}
@@ -442,6 +450,6 @@ PLT_MediaBrowser::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable
PLT_DeviceDataReference data;
NPT_CHECK_WARNING(FindServer(service->GetDevice()->GetUUID(), data));
- if (m_Delegate) m_Delegate->OnMSStateVariablesChanged(service, vars);
+ m_Delegate->OnMSStateVariablesChanged(service, vars);
return NPT_SUCCESS;
}
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.h
index 6a18c266b6..2ee032b842 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaBrowser.h
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Browser (Media Server Control Point)
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Media Controller implementation.
+ */
+
#ifndef _PLT_MEDIA_BROWSER_H_
#define _PLT_MEDIA_BROWSER_H_
@@ -43,17 +48,26 @@
/*----------------------------------------------------------------------
| PLT_BrowseInfo
+---------------------------------------------------------------------*/
-struct PLT_BrowseInfo {
+/**
+ The PLT_BrowseInfo struct is used to marshall Browse or Search action
+ response results across different threads of execution.
+ */
+typedef struct {
NPT_String object_id;
PLT_MediaObjectListReference items;
+ NPT_UInt32 si;
NPT_UInt32 nr;
NPT_UInt32 tm;
NPT_UInt32 uid;
-};
+} PLT_BrowseInfo;
/*----------------------------------------------------------------------
-| PLT_MediaBrowserDelegate class
+| PLT_MediaBrowserDelegate
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaBrowserDelegate class is an interface for receiving PLT_MediaBrowser
+ events or action responses.
+ */
class PLT_MediaBrowserDelegate
{
public:
@@ -80,8 +94,11 @@ public:
};
/*----------------------------------------------------------------------
-| PLT_MediaBrowser class
+| PLT_MediaBrowser
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaBrowser class implements a UPnP AV Media Server control point.
+ */
class PLT_MediaBrowser : public PLT_CtrlPointListener
{
public:
@@ -95,7 +112,7 @@ public:
NPT_UInt32 start_index,
NPT_UInt32 count = 30, // DLNA recommendations
bool browse_metadata = false,
- const char* filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:album,upnp:artist,upnp:author",
+ const char* filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:originalTrackNumber,upnp:album,upnp:artist,upnp:author", // explicitely specify res otherwise WMP won't return a URL!
const char* sort_criteria = "",
void* userdata = NULL);
@@ -104,9 +121,8 @@ public:
const char* search_criteria,
NPT_UInt32 start_index,
NPT_UInt32 count = 30, // DLNA recommendations
- const char* filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:album,upnp:artist,upnp:author",
+ const char* filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:originalTrackNumber,upnp:album,upnp:artist,upnp:author", // explicitely specify res otherwise WMP won't return a URL!
void* userdata = NULL);
- //BBMOD END
// methods
virtual const NPT_Lock<PLT_DeviceDataReferenceList>& GetMediaServers() { return m_MediaServers; }
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.cpp
index e130de35fb..aae5d01ae4 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.cpp
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Cache
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -34,122 +35,3 @@
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
-#include "PltMediaCache.h"
-
-NPT_SET_LOCAL_LOGGER("platinum.media.server.cache")
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::PLT_MediaCache
-+---------------------------------------------------------------------*/
-PLT_MediaCache::PLT_MediaCache()
-{
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::~PLT_MediaCache
-+---------------------------------------------------------------------*/
-PLT_MediaCache::~PLT_MediaCache()
-{
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::GenerateKey
-+---------------------------------------------------------------------*/
-NPT_String
-PLT_MediaCache::GenerateKey(const char* device_uuid,
- const char* item_id)
-{
- NPT_String key = "upnp://";
- key += device_uuid;
- key += "/";
- key += item_id;
-
- return key;
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::Clear
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaCache::Clear(const char* device_uuid,
- const char* item_id)
-{
- NPT_AutoLock lock(m_Mutex);
-
- NPT_String key = GenerateKey(device_uuid, item_id);
- if (key.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
-
- NPT_List<PLT_MediaCacheEntry*>::Iterator entries = m_Items.GetEntries().GetFirstItem();
- NPT_List<PLT_MediaCacheEntry*>::Iterator entry;
- while (entries) {
- entry = entries++;
- if ((*entry)->GetKey() == (key)) {
- m_Items.Erase(key);
- return NPT_SUCCESS;
- }
- }
-
- return NPT_FAILURE;
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::Clear
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaCache::Clear(const char* device_uuid)
-{
- NPT_AutoLock lock(m_Mutex);
-
- if (!device_uuid) return m_Items.Clear();
-
- NPT_String key = GenerateKey(device_uuid, "");
- NPT_List<PLT_MediaCacheEntry*>::Iterator entries = m_Items.GetEntries().GetFirstItem();
- NPT_List<PLT_MediaCacheEntry*>::Iterator entry;
- while (entries) {
- entry = entries++;
- NPT_String entry_key = (*entry)->GetKey();
- if (entry_key.StartsWith(key)) {
- m_Items.Erase(entry_key);
- }
- }
-
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::Put
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaCache::Put(const char* device_uuid,
- const char* item_id,
- PLT_MediaObjectListReference& list)
-{
- NPT_AutoLock lock(m_Mutex);
-
- NPT_String key = GenerateKey(device_uuid, item_id);
- if (key.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
-
- m_Items.Erase(key);
- return m_Items.Put(key, list);
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaCache::Get
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaCache::Get(const char* device_uuid,
- const char* item_id,
- PLT_MediaObjectListReference& list)
-{
- NPT_AutoLock lock(m_Mutex);
-
- NPT_String key = GenerateKey(device_uuid, item_id);
- if (key.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
-
- PLT_MediaObjectListReference* val = NULL;
- NPT_CHECK_FINE(m_Items.Get(key, val));
-
- list = *val;
- return NPT_SUCCESS;
-}
-
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.h
index 4cb89e8d9c..e5959cc13b 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaCache.h
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Cache
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ Simple Object Caching utility.
+ */
+
#ifndef _PLT_MEDIA_CACHE_H_
#define _PLT_MEDIA_CACHE_H_
@@ -38,38 +43,161 @@
| includes
+---------------------------------------------------------------------*/
#include "Neptune.h"
-#include "PltMediaItem.h"
-#include "PltDeviceData.h"
/*----------------------------------------------------------------------
-| forward declarations
+| PLT_MediaCache
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaCache template provides a way to hold references to object in
+ memory.
+ */
+template <typename T, typename U>
+class PLT_MediaCache
+{
+public:
+ typedef typename NPT_Map<NPT_String,T>::Entry ElementEntry;
+ typedef typename NPT_List<ElementEntry*>::Iterator ElementIterator;
+
+ PLT_MediaCache<T,U>() {}
+ virtual ~PLT_MediaCache<T,U>() {}
+
+ NPT_Result Put(const char* root, const char* key, T& value, U* tag = NULL);
+ NPT_Result Get(const char* root, const char* key, T& value, U* tag = NULL);
+ NPT_Result Clear(const char* root, const char* key);
+ NPT_Result Clear(const char* root = NULL);
+
+private:
+ // methods
+ NPT_String GenerateKey(const char* root, const char* key);
+
+private:
+ // members
+ NPT_Mutex m_Mutex;
+ NPT_Map<NPT_String, T> m_Items;
+ NPT_Map<NPT_String, U> m_Tags;
+};
/*----------------------------------------------------------------------
-| typedefs
+| PLT_MediaCache::GenerateKey
+---------------------------------------------------------------------*/
-typedef NPT_Map<NPT_String, PLT_MediaObjectListReference>::Entry PLT_MediaCacheEntry;
+template <typename T, typename U>
+inline
+NPT_String
+PLT_MediaCache<T,U>::GenerateKey(const char* root, const char* key)
+{
+ // TODO: There could be collision
+ NPT_String result = root;
+ result += "/";
+ result += key;
+ return result;
+}
/*----------------------------------------------------------------------
-| PLT_MediaCache class
+| PLT_MediaCache::Put
+---------------------------------------------------------------------*/
-class PLT_MediaCache
+template <typename T, typename U>
+inline
+NPT_Result
+PLT_MediaCache<T,U>::Put(const char* root,
+ const char* key,
+ T& value,
+ U* tag)
{
-public:
- PLT_MediaCache();
- virtual ~PLT_MediaCache();
+ NPT_AutoLock lock(m_Mutex);
- NPT_Result Put(const char* device_uuid, const char* item_id, PLT_MediaObjectListReference& list);
- NPT_Result Get(const char* device_uuid, const char* item_id, PLT_MediaObjectListReference& list);
- NPT_Result Clear(const char* device_uuid, const char* item_id);
- NPT_Result Clear(const char* device_uuid = NULL);
+ NPT_String fullkey = GenerateKey(root, key);
+ if (fullkey.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
-private:
- NPT_String GenerateKey(const char* device_uuid, const char* item_id);
+ m_Items.Erase(fullkey);
+ NPT_CHECK(m_Items.Put(fullkey, value));
+
+ if (tag) NPT_CHECK(m_Tags.Put(fullkey, *tag));
+
+ return NPT_SUCCESS;
+}
-private:
- NPT_Mutex m_Mutex;
- NPT_Map<NPT_String, PLT_MediaObjectListReference> m_Items;
-};
+/*----------------------------------------------------------------------
+| PLT_MediaCache::Get
++---------------------------------------------------------------------*/
+template <typename T, typename U>
+inline
+NPT_Result
+PLT_MediaCache<T,U>::Get(const char* root,
+ const char* key,
+ T& value,
+ U* tag /* = NULL */)
+{
+ NPT_AutoLock lock(m_Mutex);
+
+ NPT_String fullkey = GenerateKey(root, key);
+ if (fullkey.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
+
+ T* _value = NULL;
+ NPT_CHECK(m_Items.Get(fullkey, _value));
+
+ U* _tag;
+ if (tag) {
+ m_Tags.Get(fullkey, _tag);
+ if (_tag) *tag = *_tag;
+ }
+
+ value = *_value;
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| PLT_MediaCache::Clear
++---------------------------------------------------------------------*/
+template <typename T, typename U>
+inline
+NPT_Result
+PLT_MediaCache<T,U>::Clear(const char* root, const char* key)
+{
+ NPT_AutoLock lock(m_Mutex);
+
+ NPT_String fullkey = GenerateKey(root, key);
+ if (fullkey.GetLength() == 0) return NPT_ERROR_INVALID_PARAMETERS;
+
+ ElementIterator entries = m_Items.GetEntries().GetFirstItem();
+ ElementIterator entry;
+ while (entries) {
+ entry = entries++;
+ if ((*entry)->GetKey() == (fullkey)) {
+ m_Items.Erase(fullkey);
+ m_Tags.Erase(fullkey);
+ return NPT_SUCCESS;
+ }
+ }
+
+ return NPT_ERROR_NO_SUCH_ITEM;
+}
+
+/*----------------------------------------------------------------------
+| PLT_MediaCache::Clear
++---------------------------------------------------------------------*/
+template <typename T, typename U>
+inline
+NPT_Result
+PLT_MediaCache<T,U>::Clear(const char* root)
+{
+ NPT_AutoLock lock(m_Mutex);
+
+ if (!root || root[0]=='\0')
+ return m_Items.Clear();
+
+ NPT_String key = GenerateKey(root, "");
+ ElementIterator entries = m_Items.GetEntries().GetFirstItem();
+ ElementIterator entry;
+ while (entries) {
+ entry = entries++;
+ NPT_String entry_key = (*entry)->GetKey();
+ if (entry_key.StartsWith(key)) {
+ m_Items.Erase(entry_key);
+ m_Tags.Erase(entry_key);
+ }
+ }
+
+ return NPT_SUCCESS;
+}
#endif /* _PLT_MEDIA_CACHE_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp
index 41fe4fceb0..5b974e88a4 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.cpp
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Item
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -36,15 +37,19 @@
+---------------------------------------------------------------------*/
#include "PltMediaItem.h"
#include "PltMediaServer.h"
-#include "PltMetadataHandler.h"
#include "PltDidl.h"
-#include "PltXmlHelper.h"
+#include "PltUtilities.h"
#include "PltService.h"
+#include "PltMimeType.h"
NPT_SET_LOCAL_LOGGER("platinum.media.server.item")
-extern const char* didl_namespace_dc;
-extern const char* didl_namespace_upnp;
+/*----------------------------------------------------------------------
+| globals
++---------------------------------------------------------------------*/
+NPT_DEFINE_DYNAMIC_CAST_ANCHOR(PLT_MediaObject)
+NPT_DEFINE_DYNAMIC_CAST_ANCHOR(PLT_MediaItem)
+NPT_DEFINE_DYNAMIC_CAST_ANCHOR(PLT_MediaContainer)
/*----------------------------------------------------------------------
| PLT_PersonRoles::AddPerson
@@ -96,357 +101,15 @@ PLT_PersonRoles::FromDidl(const NPT_Array<NPT_XmlElementNode*>& nodes)
PLT_PersonRole person;
const NPT_String* name = nodes[i]->GetText();
const NPT_String* role = nodes[i]->GetAttribute("role");
- if (name) person.name = *name;
- if (role) person.role = *role;
+ // DLNA 7.3.17
+ if (name) person.name = name->SubString(0, 1024);
+ if (role) person.role = role->SubString(0, 1024);
NPT_CHECK(NPT_List<PLT_PersonRole>::Add(person));
}
return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::PLT_ProtocolInfo
-+---------------------------------------------------------------------*/
-PLT_ProtocolInfo::PLT_ProtocolInfo() :
- m_Valid(false)
-{
-}
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::PLT_ProtocolInfo
-+---------------------------------------------------------------------*/
-PLT_ProtocolInfo::PLT_ProtocolInfo(const char* protocol_info) :
- m_Valid(false)
-{
- if (!protocol_info || protocol_info[0] == '\0') return;
-
- NPT_List<NPT_String> parts = NPT_String(protocol_info).Split(":");
- if (parts.GetItemCount() != 4) return;
-
- NPT_List<NPT_String>::Iterator part = parts.GetFirstItem();
- m_Protocol = *part++;
- m_Mask = *part++;
- m_ContentType = *part++;
- m_Extra = *part;
-
- ValidateExtra();
-}
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::PLT_ProtocolInfo
-+---------------------------------------------------------------------*/
-PLT_ProtocolInfo::PLT_ProtocolInfo(const char* protocol,
- const char* mask,
- const char* content_type,
- const char* extra) :
- m_Protocol(protocol),
- m_Mask(mask),
- m_ContentType(content_type),
- m_Extra(extra),
- m_Valid(false)
-{
- ValidateExtra();
-}
-
-/*----------------------------------------------------------------------
-| types
-+---------------------------------------------------------------------*/
-typedef enum {
- PLT_PROTINFO_PARSER_STATE_PN,
- PLT_PROTINFO_PARSER_STATE_OP,
- PLT_PROTINFO_PARSER_STATE_PS,
- PLT_PROTINFO_PARSER_STATE_CI,
- PLT_PROTINFO_PARSER_STATE_FLAGS,
- PLT_PROTINFO_PARSER_STATE_MAXSP,
- PLT_PROTINFO_PARSER_STATE_OTHER
-} NPT_ProtocolInfoParserState;
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::ParseExtra
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_ProtocolInfo::ParseExtra(NPT_List<FieldEntry>& entries)
-{
- if (m_Extra == "*") return NPT_SUCCESS;
-
- NPT_List<NPT_String> fields = m_Extra.Split(";");
- NPT_List<NPT_String>::Iterator field = fields.GetFirstItem();
- if (!field) NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- while (field) {
- NPT_List<NPT_String> entry = (*field).Split("=");
- if (entry.GetItemCount() != 2) NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
- entries.Add(FieldEntry(*entry.GetFirstItem(), *entry.GetLastItem()));
- ++field;
- }
-
- return NPT_SUCCESS;
-}
-
-#define PLT_FIELD_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-#define PLT_FIELD_NUM "0123456789"
-
-/*----------------------------------------------------------------------
-| PLT_DLNAPNCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAPNCharsToValidate[] = PLT_FIELD_ALPHA PLT_FIELD_NUM "_";
-
-/*----------------------------------------------------------------------
-| PLT_DLNAPSCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAPSCharsToValidate[] = PLT_FIELD_NUM "-,/";
-
-/*----------------------------------------------------------------------
-| PLT_DLNAFlagCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAFlagCharsToValidate[] = "01";
-
-/*----------------------------------------------------------------------
-| PLT_DLNAHexCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAHexCharsToValidate[] = PLT_FIELD_NUM "ABCDEFabcdef";
-
-/*----------------------------------------------------------------------
-| PLT_DLNAOTherNameCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAOTherNameCharsToValidate[] = PLT_FIELD_ALPHA PLT_FIELD_NUM;
-
-/*----------------------------------------------------------------------
-| PLT_DLNAOTherValueCharsToValidate
-+---------------------------------------------------------------------*/
-static const char PLT_DLNAOTherValueCharsToValidate[] = PLT_FIELD_ALPHA PLT_FIELD_NUM "_-+,";
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::ValidateField
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_ProtocolInfo::ValidateField(const char* val,
- const char* valid_chars,
- NPT_Cardinal num_chars /* = 0 */)
-{
- if (!valid_chars || !val || val[0] == '\0')
- return NPT_ERROR_INVALID_PARAMETERS;
-
- // shortcut
- if (num_chars && NPT_StringLength(val) != num_chars)
- return NPT_ERROR_INVALID_SYNTAX;
-
- while (val) {
- char c = *val++;
- if (c == '\0') return NPT_SUCCESS;
-
- // look for character in valid chars
- const char* p = valid_chars;
- while (*p != c && ++p) {};
-
- // reached end of valid chars means we didn't find it
- if (!p) break;
- }
-
- return NPT_ERROR_INVALID_SYNTAX;
-
-}
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::ValidateExtra
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_ProtocolInfo::ValidateExtra()
-{
- if (m_Extra != "*") {
- NPT_List<FieldEntry> entries;
- NPT_CHECK(ParseExtra(entries));
-
- NPT_List<FieldEntry>::Iterator entry =
- entries.GetFirstItem();
-
- // parse other optional fields
- NPT_ProtocolInfoParserState state = PLT_PROTINFO_PARSER_STATE_PN;
- for (;entry;entry++) {
- if (entry->m_Key == "DLNA.ORG_PN") {
- if (state > PLT_PROTINFO_PARSER_STATE_PN)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_DLNAPNCharsToValidate));
-
- m_DLNA_PN = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_PN;
- continue;
- } else if (entry->m_Key == "DLNA.ORG_OP") {
- // op-param only allowed after pn-param
- if (state > PLT_PROTINFO_PARSER_STATE_PN)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate value
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_DLNAFlagCharsToValidate,
- 2));
-
- m_DLNA_OP = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_OP;
- continue;
- } else if (entry->m_Key == "DLNA.ORG_PS") {
- // ps-param only allowed after op-param
- if (state > PLT_PROTINFO_PARSER_STATE_OP)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate value
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_DLNAPSCharsToValidate));
-
- m_DLNA_PS = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_PS;
- continue;
- } else if (entry->m_Key == "DLNA.ORG_CI") {
- // ci-param only allowed after ps-param
- if (state > PLT_PROTINFO_PARSER_STATE_PS)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate value
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_DLNAFlagCharsToValidate,
- 1));
-
- m_DLNA_CI = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_CI;
- continue;
- } else if (entry->m_Key == "DLNA.ORG_FLAGS") {
- // flags-param only allowed after ci-param
- if (state > PLT_PROTINFO_PARSER_STATE_CI)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate value
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_DLNAHexCharsToValidate,
- 32));
-
- m_DLNA_FLAGS = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_FLAGS;
- continue;
- } else if (entry->m_Key == "DLNA.ORG_MAXSP") {
- // maxsp-param only allowed after flags-param
- if (state > PLT_PROTINFO_PARSER_STATE_FLAGS)
- NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate value
- NPT_CHECK_SEVERE(ValidateField(
- entry->m_Value,
- PLT_FIELD_NUM "."));
-
- m_DLNA_MAXSP = entry->m_Value;
- state = PLT_PROTINFO_PARSER_STATE_MAXSP;
- continue;
- } else {
- state = PLT_PROTINFO_PARSER_STATE_OTHER;
-
- // validate key first which should IANA_*<"a"-"z","A"-"Z","0"-"9">
- int index = entry->m_Key.Find("_");
- if (index == -1) NPT_CHECK_SEVERE(NPT_ERROR_INVALID_SYNTAX);
-
- // validate key
- if (NPT_FAILED(ValidateField(
- entry->m_Key.GetChars()+index,
- PLT_DLNAOTherNameCharsToValidate))) {
- NPT_LOG_WARNING_2("Invalid protocolinfo 4th field other param: %s=%s",
- (const char*)entry->m_Key,
- (const char*)entry->m_Value);
- continue;
- }
-
- // validate value
- if (NPT_FAILED(ValidateField(
- entry->m_Value,
- PLT_DLNAOTherValueCharsToValidate))) {
-
- NPT_LOG_WARNING_2("Invalid protocolinfo 4th field other param: %s=%s",
- (const char*)entry->m_Key,
- (const char*)entry->m_Value);
- continue;
- }
-
- m_DLNA_OTHER.Add(*entry);
- continue;
- }
- }
- }
-
- m_Valid = true;
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::ToString
-+---------------------------------------------------------------------*/
-NPT_String
-PLT_ProtocolInfo::ToString() const
-{
- NPT_String output = m_Protocol + ":";
- output += m_Mask + ":";
- output += m_ContentType + ":";
- if (m_Extra == "*") {
- output += "*";
- } else {
- output += "DLNA.ORG_PN=" + m_DLNA_PN;
- if (!m_DLNA_OP.IsEmpty()) {
- output += ";DLNA.ORG_OP=" + m_DLNA_OP;
- }
- if (!m_DLNA_PS.IsEmpty()) {
- output += ";DLNA.ORG_PS=" + m_DLNA_PS;
- }
- if (!m_DLNA_CI.IsEmpty()) {
- output += ";DLNA.ORG_CI=" + m_DLNA_CI;
- }
- if (!m_DLNA_FLAGS.IsEmpty()) {
- output += ";DLNA.ORG_FLAGS=" + m_DLNA_FLAGS;
- }
- if (!m_DLNA_MAXSP.IsEmpty()) {
- output += ";DLNA.ORG_MAXSP=" + m_DLNA_MAXSP;
- }
- if (m_DLNA_OTHER.GetItemCount()) {
- for (NPT_List<FieldEntry>::Iterator iter;
- iter;
- iter++) {
- output += ";" + iter->m_Key + "=" + iter->m_Value;
- }
- }
- }
-
- return output;
-}
-
-/*----------------------------------------------------------------------
-| PLT_ProtocolInfo::Match
-+---------------------------------------------------------------------*/
-bool
-PLT_ProtocolInfo::Match(const PLT_ProtocolInfo& other) const
-{
- // we need the first 3 params
- if (m_Protocol != '*' &&
- other.GetProtocol() != '*' &&
- m_Protocol != other.GetProtocol()) return false;
-
- if (m_Mask != '*' &&
- other.GetMask() != '*' &&
- m_Mask != other.GetMask()) return false;
-
- if (m_ContentType != '*' &&
- other.GetContentType() != '*' &&
- m_ContentType != other.GetContentType()) return false;
-
- // match DLNAPn of 4th item if not '*'
- if (m_Extra == '*' ||
- other.GetExtra() == '*' ||
- (!m_DLNA_PN.IsEmpty() && m_DLNA_PN == other.GetDLNA_PN())) return true;
-
- return false;
-}
-
-/*----------------------------------------------------------------------
| PLT_MediaItemResource::PLT_MediaItemResource
+---------------------------------------------------------------------*/
PLT_MediaItemResource::PLT_MediaItemResource()
@@ -464,199 +127,17 @@ PLT_MediaItemResource::PLT_MediaItemResource()
m_ColorDepth = (NPT_UInt32)-1;
}
-const NPT_HttpFileRequestHandler_FileTypeMapEntry
-PLT_HttpFileRequestHandler_360FileTypeMap[] = {
- {"avi", "video/avi"},
- {"divx", "video/avi"},
- {"xvid", "video/avi"},
- {"mov", "video/mp4"}
-};
-
-const NPT_HttpFileRequestHandler_FileTypeMapEntry
-PLT_HttpFileRequestHandler_PS3FileTypeMap[] = {
- {"avi", "video/x-msvideo"},
- {"divx", "video/x-msvideo"},
- {"xvid", "video/x-msvideo"}
-};
-
-/*----------------------------------------------------------------------
-| PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry
-+---------------------------------------------------------------------*/
-typedef struct PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry {
- const char* mime_type;
- const char* dlna_ext;
-} PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry ;
-
-static const PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry
-PLT_HttpFileRequestHandler_DefaultDlnaMap[] = {
- {"image/gif", "DLNA.ORG_PN=GIF_LRG"},
- {"image/jpeg", "DLNA.ORG_PN=JPEG_LRG"},
- {"image/jp2", "DLNA.ORG_PN=JPEG_LRG"},
- {"image/png", "DLNA.ORG_PN=PNG_LRG"},
- {"image/bmp", "DLNA.ORG_PN=BMP_LRG"},
- {"image/tiff", "DLNA.ORG_PN=TIFF_LRG"},
- {"audio/mpeg", "DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"audio/mp4", "DLNA.ORG_PN=AAC_ISO_320;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"audio/x-ms-wma", "DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"audio/x-wav", "DLNA.ORG_PN=WAV;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/avi", "DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/mp4", "DLNA.ORG_PN=MPEG4_P2_SP_AAC;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/mpeg", "DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/x-ms-wmv", "DLNA.ORG_PN=WMVMED_FULL;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/x-msvideo","DLNA.ORG_PN=AVI;DLNA.ORG_OP=01;DLNA.ORG_CI=0"},
- {"video/x-ms-asf", "DLNA.ORG_OP=01;DLNA.ORG_CI=0"}
-};
-
-static const PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry
-PLT_HttpFileRequestHandler_360DlnaMap[] = {
- {"video/mp4", "DLNA.ORG_OP=01;DLNA.ORG_CI=0"}
-};
-
-static const PLT_HttpFileRequestHandler_DefaultDlnaExtMapEntry
-PLT_HttpFileRequestHandler_PS3DlnaMap[] = {
- {"image/jpg", "DLNA.ORG_OP=01"},
- {"image/png", "DLNA.ORG_OP=01"}
-};
-
-/*----------------------------------------------------------------------
-| PLT_MediaObject::GetMimeType
-+---------------------------------------------------------------------*/
-const char*
-PLT_MediaObject::GetMimeType(const NPT_String& filename,
- const PLT_HttpRequestContext* context /* = NULL */)
-{
- int last_dot = filename.ReverseFind('.');
- if (last_dot >= 0) { // passing just the extension is ok (ex .mp3)
- NPT_String extension = filename.GetChars()+last_dot+1;
- extension.MakeLowercase();
-
- return GetMimeTypeFromExtension(extension, context);
- }
-
- return "application/octet-stream";
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaObject::GetMimeTypeFromExtension
-+---------------------------------------------------------------------*/
-const char*
-PLT_MediaObject::GetMimeTypeFromExtension(const NPT_String& extension,
- const PLT_HttpRequestContext* context /* = NULL */)
-{
- if (context) {
- NPT_HttpRequest& request = (NPT_HttpRequest&)context->GetRequest();
- const NPT_String* agent = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_USER_AGENT);
- const NPT_String* hdr = request.GetHeaders().GetHeaderValue("X-AV-Client-Info");
-
- // look for special case for 360
- if (agent && (agent->Find("XBox", 0, true) >= 0 || agent->Find("Xenon", 0, true) >= 0)) {
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(PLT_HttpFileRequestHandler_360FileTypeMap); i++) {
- if (extension == PLT_HttpFileRequestHandler_360FileTypeMap[i].extension) {
- return PLT_HttpFileRequestHandler_360FileTypeMap[i].mime_type;
- }
- }
-
- // fallback to default if not found
- } else if (hdr && hdr->Find("PLAYSTATION 3", 0, true) >= 0) {
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(PLT_HttpFileRequestHandler_PS3FileTypeMap); i++) {
- if (extension == PLT_HttpFileRequestHandler_PS3FileTypeMap[i].extension) {
- return PLT_HttpFileRequestHandler_PS3FileTypeMap[i].mime_type;
- }
- }
-
- // fallback to default if not found
- }
- }
-
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(NPT_HttpFileRequestHandler_DefaultFileTypeMap); i++) {
- if (extension == NPT_HttpFileRequestHandler_DefaultFileTypeMap[i].extension) {
- return NPT_HttpFileRequestHandler_DefaultFileTypeMap[i].mime_type;
- }
- }
-
- return "application/octet-stream";
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaObject::GetDlnaExtension
-+---------------------------------------------------------------------*/
-const char*
-PLT_MediaObject::GetDlnaExtension(const char* mime_type,
- const PLT_HttpRequestContext* context /* = NULL */)
-{
- NPT_String _mime_type = mime_type;
- _mime_type.MakeLowercase();
-
- if (context) {
- NPT_HttpRequest& request = (NPT_HttpRequest&)context->GetRequest();
- const NPT_String* agent = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_USER_AGENT);
- const NPT_String* hdr = request.GetHeaders().GetHeaderValue("X-AV-Client-Info");
-
- // look for special case for 360
- if (agent && (agent->Find("XBox", 0, true) >= 0 || agent->Find("Xenon", 0, true) >= 0)) {
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(PLT_HttpFileRequestHandler_360DlnaMap); i++) {
- if (_mime_type == PLT_HttpFileRequestHandler_360DlnaMap[i].mime_type) {
- return PLT_HttpFileRequestHandler_360DlnaMap[i].dlna_ext;
- }
- }
-
- return "*"; // Should we try default dlna instead?
- } else if (hdr && hdr->Find("PLAYSTATION 3", 0, true) >= 0) {
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(PLT_HttpFileRequestHandler_PS3DlnaMap); i++) {
- if (_mime_type == PLT_HttpFileRequestHandler_PS3DlnaMap[i].mime_type) {
- return PLT_HttpFileRequestHandler_PS3DlnaMap[i].dlna_ext;
- }
- }
-
- return "DLNA.ORG_OP=01"; // Should we try default dlna instead?
- }
- }
-
- for (unsigned int i=0; i<NPT_ARRAY_SIZE(PLT_HttpFileRequestHandler_DefaultDlnaMap); i++) {
- if (_mime_type == PLT_HttpFileRequestHandler_DefaultDlnaMap[i].mime_type) {
- return PLT_HttpFileRequestHandler_DefaultDlnaMap[i].dlna_ext;
- }
- }
-
- return "*";
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaObject::GetProtocolInfo
-+---------------------------------------------------------------------*/
-NPT_String
-PLT_MediaObject::GetProtocolInfo(const char* filepath,
- bool with_dlna_extension /* = true */,
- const PLT_HttpRequestContext* context /* = NULL */)
-{
- NPT_String mime_type = GetMimeType(filepath, context);
- return "http-get:*:"+mime_type+":"+ \
- (with_dlna_extension?GetDlnaExtension(mime_type, context):"*");
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaObject::GetMimeTypeFromProtocolInfo
-+---------------------------------------------------------------------*/
-NPT_String
-PLT_MediaObject::GetMimeTypeFromProtocolInfo(const char* protocol_info)
-{
- NPT_String info = protocol_info;
- NPT_List<NPT_String> fragments = info.Split(":");
- if (fragments.GetItemCount() != 4) return "";
- return *fragments.GetItem(2);
-}
-
/*----------------------------------------------------------------------
| PLT_MediaObject::GetUPnPClass
+---------------------------------------------------------------------*/
const char*
-PLT_MediaObject::GetUPnPClass(const char* filepath,
+PLT_MediaObject::GetUPnPClass(const char* filename,
const PLT_HttpRequestContext* context /* = NULL */)
{
NPT_COMPILER_UNUSED(context);
const char* ret = NULL;
- NPT_String mime_type = GetMimeType(filepath, context);
+ NPT_String mime_type = PLT_MimeType::GetMimeType(filename, context);
if (mime_type.StartsWith("audio")) {
ret = "object.item.audioItem.musicTrack";
@@ -679,12 +160,12 @@ PLT_MediaObject::Reset()
{
m_ObjectClass.type = "";
m_ObjectClass.friendly_name = "";
- m_ObjectID = "";
- m_ParentID = "";
+ m_ObjectID = "";
+ m_ParentID = "";
- m_Title = "";
- m_Creator = "";
- m_Date = "";
+ m_Title = "";
+ m_Creator = "";
+ m_Date = "";
m_Restricted = true;
m_People.actors.Clear();
@@ -692,21 +173,22 @@ PLT_MediaObject::Reset()
m_People.authors.Clear();
m_Affiliation.album = "";
- m_Affiliation.genre.Clear();
+ m_Affiliation.genres.Clear();
m_Affiliation.playlist = "";
- m_Description.description = "";
- m_Description.long_description = "";
- m_ExtraInfo.album_art_uri = "";
+ m_Description.description = "";
+ m_Description.long_description = "";
+ m_Description.icon_uri = "";
+ m_ExtraInfo.album_arts.Clear();
m_ExtraInfo.artist_discography_uri = "";
m_MiscInfo.original_track_number = 0;
- m_MiscInfo.dvdregioncode = 0;
- m_MiscInfo.toc = "";
- m_MiscInfo.user_annotation = "";
+ m_MiscInfo.dvdregioncode = 0;
+ m_MiscInfo.toc = "";
+ m_MiscInfo.user_annotation = "";
- m_Recorded.program_title = "";
- m_Recorded.series_title = "";
+ m_Recorded.program_title = "";
+ m_Recorded.series_title = "";
m_Recorded.episode_number = 0;
m_Resources.Clear();
@@ -720,6 +202,15 @@ PLT_MediaObject::Reset()
| PLT_MediaObject::ToDidl
+---------------------------------------------------------------------*/
NPT_Result
+PLT_MediaObject::ToDidl(const NPT_String& filter, NPT_String& didl)
+{
+ return ToDidl(PLT_Didl::ConvertFilterToMask(filter), didl);
+}
+
+/*----------------------------------------------------------------------
+| PLT_MediaObject::ToDidl
++---------------------------------------------------------------------*/
+NPT_Result
PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
{
// title is required
@@ -736,7 +227,7 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
}
// date
- if (mask & PLT_FILTER_MASK_DATE && !m_Date.IsEmpty()) {
+ if ((mask & PLT_FILTER_MASK_DATE) && !m_Date.IsEmpty()) {
didl += "<dc:date>";
PLT_Didl::AppendXmlEscape(didl, m_Date);
didl += "</dc:date>";
@@ -760,7 +251,7 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
}
// album
- if (mask & PLT_FILTER_MASK_ALBUM && !m_Affiliation.album.IsEmpty()) {
+ if ((mask & PLT_FILTER_MASK_ALBUM) && !m_Affiliation.album.IsEmpty()) {
didl += "<upnp:album>";
PLT_Didl::AppendXmlEscape(didl, m_Affiliation.album);
didl += "</upnp:album>";
@@ -769,11 +260,11 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
// genre
if (mask & PLT_FILTER_MASK_GENRE) {
// Add unknown genre
- if (m_Affiliation.genre.GetItemCount() == 0)
- m_Affiliation.genre.Add("Unknown");
+ if (m_Affiliation.genres.GetItemCount() == 0)
+ m_Affiliation.genres.Add("Unknown");
for (NPT_List<NPT_String>::Iterator it =
- m_Affiliation.genre.GetFirstItem(); it; ++it) {
+ m_Affiliation.genres.GetFirstItem(); it; ++it) {
didl += "<upnp:genre>";
PLT_Didl::AppendXmlEscape(didl, (*it));
didl += "</upnp:genre>";
@@ -781,27 +272,46 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
}
// album art URI
- if (mask & PLT_FILTER_MASK_ALBUMARTURI && !m_ExtraInfo.album_art_uri.IsEmpty()) {
- didl += "<upnp:albumArtURI";
- if (!m_ExtraInfo.album_art_uri_dlna_profile.IsEmpty()) {
- didl += " dlna:profileID=\"";
- PLT_Didl::AppendXmlEscape(didl, m_ExtraInfo.album_art_uri_dlna_profile);
- didl += "\"";
+ if ((mask & PLT_FILTER_MASK_ALBUMARTURI) && m_ExtraInfo.album_arts.GetItemCount()) {
+ NPT_List<PLT_AlbumArtInfo>::Iterator album_art = m_ExtraInfo.album_arts.GetFirstItem();
+ for (NPT_List<PLT_AlbumArtInfo>::Iterator iter = m_ExtraInfo.album_arts.GetFirstItem();
+ iter;
+ iter++) {
+ didl += "<upnp:albumArtURI";
+ if (!(*iter).dlna_profile.IsEmpty()) {
+ didl += " dlna:profileID=\"";
+ PLT_Didl::AppendXmlEscape(didl, (*iter).dlna_profile);
+ didl += "\"";
+ }
+ didl += ">";
+ PLT_Didl::AppendXmlEscape(didl, (*iter).uri);
+ didl += "</upnp:albumArtURI>";
}
- didl += ">";
- PLT_Didl::AppendXmlEscape(didl, m_ExtraInfo.album_art_uri);
- didl += "</upnp:albumArtURI>";
}
-
+
// description
- if (mask & PLT_FILTER_MASK_DESCRIPTION && !m_Description.long_description.IsEmpty()) {
+ if ((mask & PLT_FILTER_MASK_DESCRIPTION) && !m_Description.description.IsEmpty()) {
+ didl += "<dc:description>";
+ PLT_Didl::AppendXmlEscape(didl, m_Description.description);
+ didl += "</dc:description>";
+ }
+
+ // long description
+ if ((mask & PLT_FILTER_MASK_LONGDESCRIPTION) && !m_Description.long_description.IsEmpty()) {
didl += "<upnp:longDescription>";
PLT_Didl::AppendXmlEscape(didl, m_Description.long_description);
didl += "</upnp:longDescription>";
}
+
+ // icon
+ if ((mask & PLT_FILTER_MASK_ICON) && !m_Description.icon_uri.IsEmpty()) {
+ didl += "<upnp:icon>";
+ PLT_Didl::AppendXmlEscape(didl, m_Description.icon_uri);
+ didl += "</upnp:icon>";
+ }
// original track number
- if (mask & PLT_FILTER_MASK_ORIGINALTRACK && m_MiscInfo.original_track_number > 0) {
+ if ((mask & PLT_FILTER_MASK_ORIGINALTRACK) && m_MiscInfo.original_track_number > 0) {
didl += "<upnp:originalTrackNumber>";
didl += NPT_String::FromInteger(m_MiscInfo.original_track_number);
didl += "</upnp:originalTrackNumber>";
@@ -815,20 +325,20 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
}
// series title
- if (mask & PLT_FILTER_MASK_SERIESTITLE && !m_Recorded.series_title.IsEmpty()) {
+ if ((mask & PLT_FILTER_MASK_SERIESTITLE) && !m_Recorded.series_title.IsEmpty()) {
didl += "<upnp:seriesTitle>";
PLT_Didl::AppendXmlEscape(didl, m_Recorded.series_title);
didl += "</upnp:seriesTitle>";
}
// episode number
- if (mask & PLT_FILTER_MASK_EPISODE && m_Recorded.episode_number > 0) {
+ if ((mask & PLT_FILTER_MASK_EPISODE) && m_Recorded.episode_number > 0) {
didl += "<upnp:episodeNumber>";
didl += NPT_String::FromInteger(m_Recorded.episode_number);
didl += "</upnp:episodeNumber>";
}
- if (mask & PLT_FILTER_MASK_TOC & !m_MiscInfo.toc.IsEmpty()) {
+ if ((mask & PLT_FILTER_MASK_TOC) & !m_MiscInfo.toc.IsEmpty()) {
didl += "<upnp:toc>";
PLT_Didl::AppendXmlEscape(didl, m_MiscInfo.toc);
didl += "</upnp:toc>";
@@ -837,69 +347,70 @@ PLT_MediaObject::ToDidl(NPT_UInt32 mask, NPT_String& didl)
// resource
if (mask & PLT_FILTER_MASK_RES) {
for (NPT_Cardinal i=0; i<m_Resources.GetItemCount(); i++) {
- if (m_Resources[i].m_ProtocolInfo.IsValid()) {
- // protocol info is required
- didl += "<res";
-
- if (mask & PLT_FILTER_MASK_RES_DURATION && m_Resources[i].m_Duration != (NPT_UInt32)-1) {
- didl += " duration=\"";
- PLT_Didl::FormatTimeStamp(didl, m_Resources[i].m_Duration);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_SIZE && m_Resources[i].m_Size != (NPT_LargeSize)-1) {
- didl += " size=\"";
- didl += NPT_String::FromIntegerU(m_Resources[i].m_Size);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_PROTECTION && !m_Resources[i].m_Protection.IsEmpty()) {
- didl += " protection=\"";
- PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Protection);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_RESOLUTION && !m_Resources[i].m_Resolution.IsEmpty()) {
- didl += " resolution=\"";
- PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Resolution);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_BITRATE && m_Resources[i].m_Bitrate != (NPT_Size)-1) {
- didl += " bitrate=\"";
- didl += NPT_String::FromIntegerU(m_Resources[i].m_Bitrate);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_BITSPERSAMPLE && m_Resources[i].m_BitsPerSample != (NPT_Size)-1) {
- didl += " bitsPerSample=\"";
- didl += NPT_String::FromIntegerU(m_Resources[i].m_BitsPerSample);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_SAMPLEFREQUENCY && m_Resources[i].m_SampleFrequency != (NPT_Size)-1) {
- didl += " sampleFrequency=\"";
- didl += NPT_String::FromIntegerU(m_Resources[i].m_SampleFrequency);
- didl += "\"";
- }
-
- if (mask & PLT_FILTER_MASK_RES_NRAUDIOCHANNELS && m_Resources[i].m_NbAudioChannels != (NPT_Size)-1) {
- didl += " nrAudioChannels=\"";
- didl += NPT_String::FromIntegerU(m_Resources[i].m_NbAudioChannels);
- didl += "\"";
- }
-
- didl += " protocolInfo=\"";
- PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_ProtocolInfo.ToString());
- didl += "\">";
- PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Uri);
- didl += "</res>";
+ didl += "<res";
+
+ if ((mask & PLT_FILTER_MASK_RES_DURATION) && m_Resources[i].m_Duration != (NPT_UInt32)-1) {
+ didl += " duration=\"";
+ didl += PLT_Didl::FormatTimeStamp(m_Resources[i].m_Duration);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_SIZE) && m_Resources[i].m_Size != (NPT_LargeSize)-1) {
+ didl += " size=\"";
+ didl += NPT_String::FromIntegerU(m_Resources[i].m_Size);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_PROTECTION) && !m_Resources[i].m_Protection.IsEmpty()) {
+ didl += " protection=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Protection);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_RESOLUTION) && !m_Resources[i].m_Resolution.IsEmpty()) {
+ didl += " resolution=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Resolution);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_BITRATE) && m_Resources[i].m_Bitrate != (NPT_Size)-1) {
+ didl += " bitrate=\"";
+ didl += NPT_String::FromIntegerU(m_Resources[i].m_Bitrate);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_BITSPERSAMPLE) && m_Resources[i].m_BitsPerSample != (NPT_Size)-1) {
+ didl += " bitsPerSample=\"";
+ didl += NPT_String::FromIntegerU(m_Resources[i].m_BitsPerSample);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_SAMPLEFREQUENCY) && m_Resources[i].m_SampleFrequency != (NPT_Size)-1) {
+ didl += " sampleFrequency=\"";
+ didl += NPT_String::FromIntegerU(m_Resources[i].m_SampleFrequency);
+ didl += "\"";
+ }
+
+ if ((mask & PLT_FILTER_MASK_RES_NRAUDIOCHANNELS) && m_Resources[i].m_NbAudioChannels != (NPT_Size)-1) {
+ didl += " nrAudioChannels=\"";
+ didl += NPT_String::FromIntegerU(m_Resources[i].m_NbAudioChannels);
+ didl += "\"";
}
+
+ didl += " protocolInfo=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_ProtocolInfo.ToString());
+ didl += "\">";
+ PLT_Didl::AppendXmlEscape(didl, m_Resources[i].m_Uri);
+ didl += "</res>";
}
}
// class is required
- didl += "<upnp:class>";
+ didl += "<upnp:class";
+ if (!m_ObjectClass.friendly_name.IsEmpty()) {
+ didl += " name=\"" + m_ObjectClass.friendly_name+"\"";
+ }
+ didl += ">";
PLT_Didl::AppendXmlEscape(didl, m_ObjectClass.type);
didl += "</upnp:class>";
@@ -917,32 +428,53 @@ PLT_MediaObject::FromDidl(NPT_XmlElementNode* entry)
NPT_Result res;
// check if item is restricted (is default true?)
- if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "restricted", str))) {
+ if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "restricted", str, "", 5))) {
m_Restricted = PLT_Service::IsTrue(str);
}
+
+ // read non-required elements
+ PLT_XmlHelper::GetChildText(entry, "creator", m_Creator, didl_namespace_dc, 256);
+ PLT_XmlHelper::GetChildText(entry, "date", m_Date, didl_namespace_dc, 256);
+
+ // parse date and make sure it's valid
+ NPT_String parsed_date;
+ for (int format=0; format<=NPT_DateTime::FORMAT_RFC_1036; format++) {
+ NPT_DateTime date;
+ if (NPT_SUCCEEDED(date.FromString(m_Date, (NPT_DateTime::Format)format))) {
+ parsed_date = date.ToString((NPT_DateTime::Format)format);
+ break;
+ }
+ }
+ m_Date = parsed_date;
res = PLT_XmlHelper::GetAttribute(entry, "id", m_ObjectID);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
+ NPT_CHECK_SEVERE(res);
res = PLT_XmlHelper::GetAttribute(entry, "parentID", m_ParentID);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
+ NPT_CHECK_SEVERE(res);
- res = PLT_XmlHelper::GetAttribute(entry, "refID", m_ReferenceID);
+ PLT_XmlHelper::GetAttribute(entry, "refID", m_ReferenceID);
res = PLT_XmlHelper::GetChildText(entry, "title", m_Title, didl_namespace_dc);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
-
+ NPT_CHECK_SEVERE(res);
+
res = PLT_XmlHelper::GetChildText(entry, "class", m_ObjectClass.type, didl_namespace_upnp);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
-
- // read non-required elements
- PLT_XmlHelper::GetChildText(entry, "creator", m_Creator, didl_namespace_dc);
- PLT_XmlHelper::GetChildText(entry, "date", m_Date, didl_namespace_dc);
+ NPT_CHECK_SEVERE(res);
+
+ // DLNA 7.3.17.3 max bytes for dc:title and upnp:class is 256 bytes
+ m_Title = m_Title.SubString(0, 256);
+ m_ObjectClass.type = m_ObjectClass.type.SubString(0, 256);
PLT_XmlHelper::GetChildren(entry, children, "artist", didl_namespace_upnp);
m_People.artists.FromDidl(children);
+
+ PLT_XmlHelper::GetChildren(entry, children, "author", didl_namespace_upnp);
+ m_People.authors.FromDidl(children);
+
+ PLT_XmlHelper::GetChildren(entry, children, "actors", didl_namespace_upnp);
+ m_People.actors.FromDidl(children);
- PLT_XmlHelper::GetChildText(entry, "album", m_Affiliation.album, didl_namespace_upnp);
+ PLT_XmlHelper::GetChildText(entry, "album", m_Affiliation.album, didl_namespace_upnp, 256);
PLT_XmlHelper::GetChildText(entry, "programTitle", m_Recorded.program_title, didl_namespace_upnp);
PLT_XmlHelper::GetChildText(entry, "seriesTitle", m_Recorded.series_title, didl_namespace_upnp);
PLT_XmlHelper::GetChildText(entry, "episodeNumber", str, didl_namespace_upnp);
@@ -954,81 +486,94 @@ PLT_MediaObject::FromDidl(NPT_XmlElementNode* entry)
PLT_XmlHelper::GetChildren(entry, children, "genre", didl_namespace_upnp);
for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
if (children[i]->GetText()) {
- m_Affiliation.genre.Add(*children[i]->GetText());
+ m_Affiliation.genres.Add(children[i]->GetText()->SubString(0, 256));
}
}
-
- PLT_XmlHelper::GetChildText(entry, "albumArtURI", m_ExtraInfo.album_art_uri, didl_namespace_upnp);
+
+ PLT_XmlHelper::GetChildText(entry, "description", m_Description.description, didl_namespace_dc);
PLT_XmlHelper::GetChildText(entry, "longDescription", m_Description.long_description, didl_namespace_upnp);
- PLT_XmlHelper::GetChildText(entry, "originalTrackNumber", str, didl_namespace_upnp);
+ PLT_XmlHelper::GetChildText(entry, "icon", m_Description.icon_uri, didl_namespace_upnp);
PLT_XmlHelper::GetChildText(entry, "toc", m_MiscInfo.toc, didl_namespace_upnp);
+
+ // album arts
+ children.Clear();
+ PLT_XmlHelper::GetChildren(entry, children, "albumArtURI", didl_namespace_upnp);
+ for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
+ if (children[i]->GetText()) {
+ PLT_AlbumArtInfo info;
+ info.uri = children[i]->GetText()->SubString(0, 1024);
+ PLT_XmlHelper::GetAttribute(children[i], "profileID", info.dlna_profile, didl_namespace_dlna);
+ m_ExtraInfo.album_arts.Add(info);
+ }
+ }
+
+ PLT_XmlHelper::GetChildText(entry, "originalTrackNumber", str, didl_namespace_upnp);
if (NPT_FAILED(str.ToInteger(value))) value = 0;
m_MiscInfo.original_track_number = value;
children.Clear();
PLT_XmlHelper::GetChildren(entry, children, "res");
- if (children.GetItemCount() > 0) {
- for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
- PLT_MediaItemResource resource;
- if (children[i]->GetText() == NULL) {
- NPT_LOG_WARNING("No resource text");
- continue;
- }
+ for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
+ PLT_MediaItemResource resource;
+
+ // extract url
+ if (children[i]->GetText() == NULL) {
+ NPT_LOG_WARNING_1("No resource text found in: %s", (const char*)PLT_XmlHelper::Serialize(*children[i]));
+ } else {
+ resource.m_Uri = children[i]->GetText()->SubString(0, 1024);
- resource.m_Uri = *children[i]->GetText();
-
// basic uri validation, ignoring scheme (could be rtsp)
- // do not try to parse ip, it could be a FQDN address
- // and it would take too long to resolve at this point
NPT_HttpUrl url(resource.m_Uri, true);
if (!url.IsValid()) {
NPT_LOG_WARNING_1("Invalid resource uri: %s", (const char*)resource.m_Uri);
continue;
}
- NPT_String protocol_info;
- res = PLT_XmlHelper::GetAttribute(children[i], "protocolInfo", protocol_info);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
+ }
+ // extract protocol info
+ NPT_String protocol_info;
+ res = PLT_XmlHelper::GetAttribute(children[i], "protocolInfo", protocol_info, "", 256);
+ if (NPT_FAILED(res)) {
+ NPT_LOG_WARNING_1("No protocol info found in: %s", (const char*)PLT_XmlHelper::Serialize(*children[i]));
+ } else {
resource.m_ProtocolInfo = PLT_ProtocolInfo(protocol_info);
if (!resource.m_ProtocolInfo.IsValid()) {
NPT_LOG_WARNING_1("Invalid resource protocol info: %s", (const char*)protocol_info);
- continue;
}
-
- PLT_XmlHelper::GetAttribute(children[i], "protection", resource.m_Protection);
- PLT_XmlHelper::GetAttribute(children[i], "resolution", resource.m_Resolution);
+ }
- if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(children[i], "size", str))) {
- if (NPT_FAILED(str.ToInteger64(resource.m_Size))) resource.m_Size = (NPT_Size)-1;
- }
+ // extract known attributes
+ PLT_XmlHelper::GetAttribute(children[i], "protection", resource.m_Protection, "", 256);
+ PLT_XmlHelper::GetAttribute(children[i], "resolution", resource.m_Resolution, "", 256);
- if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(children[i], "duration", str))) {
- if (NPT_FAILED(PLT_Didl::ParseTimeStamp(str, resource.m_Duration))) {
- // if error while converting, ignore and set to -1 to indicate we don't know the duration
- resource.m_Duration = (NPT_UInt32)-1;
- PLT_XmlHelper::RemoveAttribute(children[i], "duration");
- } else {
- // DLNA: reformat duration in case it was not compliant
- str = "";
- PLT_Didl::FormatTimeStamp(str, resource.m_Duration);
- PLT_XmlHelper::SetAttribute(children[i], "duration", str);
- }
- }
- m_Resources.Add(resource);
+ if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(children[i], "size", str, "", 256))) {
+ if (NPT_FAILED(str.ToInteger64(resource.m_Size))) resource.m_Size = (NPT_Size)-1;
}
+
+ if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(children[i], "duration", str, "", 256))) {
+ if (NPT_FAILED(PLT_Didl::ParseTimeStamp(str, resource.m_Duration))) {
+ // if error while converting, ignore and set to -1 to indicate we don't know the duration
+ resource.m_Duration = (NPT_UInt32)-1;
+ PLT_XmlHelper::RemoveAttribute(children[i], "duration");
+ } else {
+ // DLNA: reformat duration in case it was not compliant
+ str = PLT_Didl::FormatTimeStamp(resource.m_Duration);
+ PLT_XmlHelper::SetAttribute(children[i], "duration", str);
+ }
+ }
+ m_Resources.Add(resource);
}
- // reserialize the entry didl as a we might need to pass it to a renderer
+ // re serialize the entry didl as a we might need to pass it to a renderer
// we may have modified the tree to "fix" issues, so as not to break a renderer
// (don't write xml prefix as this didl could be part of a larger document)
- res = PLT_XmlHelper::Serialize(*entry, xml, false);
- NPT_CHECK_LABEL_SEVERE(res, cleanup);
+ //res = PLT_XmlHelper::Serialize(*entry, xml, false);
+ m_Didl = "";
+ res = ToDidl(PLT_FILTER_MASK_ALL, m_Didl);
+ NPT_CHECK_SEVERE(res);
- m_Didl = didl_header + xml + didl_footer;
+ m_Didl = didl_header + m_Didl + didl_footer;
return NPT_SUCCESS;
-
-cleanup:
- return res;
}
/*----------------------------------------------------------------------
@@ -1065,32 +610,38 @@ PLT_MediaItem::~PLT_MediaItem()
| PLT_MediaItem::ToDidl
+---------------------------------------------------------------------*/
NPT_Result
+PLT_MediaItem::ToDidl(const NPT_String& filter, NPT_String& didl)
+{
+ return PLT_MediaObject::ToDidl(filter, didl);
+}
+
+/*----------------------------------------------------------------------
+| PLT_MediaItem::ToDidl
++---------------------------------------------------------------------*/
+NPT_Result
PLT_MediaItem::ToDidl(NPT_UInt32 mask, NPT_String& didl)
{
- NPT_String tmp;
- // Allocate enough space for a big string we're going to concatenate in
- tmp.Reserve(2048);
+ didl += "<item id=\"";
- tmp = "<item id=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ObjectID);
+ didl += "\" parentID=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ParentID);
- PLT_Didl::AppendXmlEscape(tmp, m_ObjectID);
- tmp += "\" parentID=\"";
- PLT_Didl::AppendXmlEscape(tmp, m_ParentID);
- if(!m_ReferenceID.IsEmpty()) {
- tmp += "\" refID=\"";
- PLT_Didl::AppendXmlEscape(tmp, m_ReferenceID);
+ if ((mask & PLT_FILTER_MASK_REFID) && !m_ReferenceID.IsEmpty()) {
+ didl += "\" refID=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ReferenceID);
}
- tmp += "\" restricted=\"";
- tmp += m_Restricted?"1\"":"0\"";
- tmp += ">";
+ didl += "\" restricted=\"";
+ didl += m_Restricted?"1\"":"0\"";
+
+ didl += ">";
- NPT_CHECK_SEVERE(PLT_MediaObject::ToDidl(mask, tmp));
+ NPT_CHECK_SEVERE(PLT_MediaObject::ToDidl(mask, didl));
/* close tag */
- tmp += "</item>";
+ didl += "</item>";
- didl += tmp;
return NPT_SUCCESS;
}
@@ -1103,10 +654,18 @@ PLT_MediaItem::FromDidl(NPT_XmlElementNode* entry)
/* reset first */
Reset();
- if (entry->GetTag().Compare("item", true) != 0)
- return NPT_ERROR_INTERNAL;
+ if (entry->GetTag().Compare("item", true) != 0) {
+ NPT_CHECK_SEVERE(NPT_ERROR_INTERNAL);
+ }
- return PLT_MediaObject::FromDidl(entry);
+ NPT_Result result = PLT_MediaObject::FromDidl(entry);
+
+ // make sure we have at least one valid resource
+ if (m_Resources.GetItemCount() == 0) {
+ NPT_CHECK_SEVERE(NPT_ERROR_INVALID_PARAMETERS);
+ }
+
+ return result;
}
/*----------------------------------------------------------------------
@@ -1131,8 +690,9 @@ NPT_Result
PLT_MediaContainer::Reset()
{
m_SearchClasses.Clear();
- m_Searchable = true;
- m_ChildrenCount = -1;
+ m_Searchable = false;
+ m_ChildrenCount = -1;
+ m_ContainerUpdateID = 0;
return PLT_MediaObject::Reset();
}
@@ -1141,43 +701,72 @@ PLT_MediaContainer::Reset()
| PLT_MediaContainer::ToDidl
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaContainer::ToDidl(NPT_UInt32 mask, NPT_String& didl)
+PLT_MediaContainer::ToDidl(const NPT_String& filter, NPT_String& didl)
{
- NPT_String tmp;
- // Allocate enough space for a big string we're going to concatenate in
- tmp.Reserve(2048);
+ return PLT_MediaObject::ToDidl(filter, didl);
+}
- tmp = "<container id=\"";
+/*----------------------------------------------------------------------
+| PLT_MediaContainer::ToDidl
++---------------------------------------------------------------------*/
+NPT_Result
+PLT_MediaContainer::ToDidl(NPT_UInt32 mask, NPT_String& didl)
+{
+ // container id property
+ didl += "<container id=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ObjectID);
- PLT_Didl::AppendXmlEscape(tmp, m_ObjectID);
- tmp += "\" parentID=\"";
- if(!m_ReferenceID.IsEmpty()) {
- tmp += "\" refID=\"";
- PLT_Didl::AppendXmlEscape(tmp, m_ReferenceID);
+ // parent id property
+ didl += "\" parentID=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ParentID);
+
+ // ref id
+ if ((mask & PLT_FILTER_MASK_REFID) && !m_ReferenceID.IsEmpty()) {
+ didl += "\" refID=\"";
+ PLT_Didl::AppendXmlEscape(didl, m_ReferenceID);
}
- PLT_Didl::AppendXmlEscape(tmp, m_ParentID);
- tmp += "\" restricted=\"";
- tmp += m_Restricted?"1\"":"0\"";
+ // restricted property
+ didl += "\" restricted=\"";
+ didl += m_Restricted?"1\"":"0\"";
+
+ // searchable property
if (mask & PLT_FILTER_MASK_SEARCHABLE) {
- tmp += " searchable=\"";
- tmp += m_Searchable?"1\"":"0\"";
+ didl += " searchable=\"";
+ didl += m_Searchable?"1\"":"0\"";
}
- if (mask & PLT_FILTER_MASK_CHILDCOUNT && m_ChildrenCount != -1) {
- tmp += " childCount=\"";
- tmp += NPT_String::FromInteger(m_ChildrenCount);
- tmp += "\"";
+ // childcount property
+ if ((mask & PLT_FILTER_MASK_CHILDCOUNT) && m_ChildrenCount != -1) {
+ didl += " childCount=\"";
+ didl += NPT_String::FromInteger(m_ChildrenCount);
+ didl += "\"";
}
- tmp += ">";
+ didl += ">";
- NPT_CHECK_SEVERE(PLT_MediaObject::ToDidl(mask, tmp));
+ if ((mask & PLT_FILTER_MASK_SEARCHCLASS) && m_SearchClasses.GetItemCount()) {
+ NPT_List<PLT_SearchClass>::Iterator search_class = m_SearchClasses.GetFirstItem();
+ while (search_class) {
+ didl += "<upnp:searchClass includeDerived=\"";
+ didl += (*search_class).include_derived?"1\"":"0\"";
- /* close tag */
- tmp += "</container>";
+ // frienly name is any
+ if (!(*search_class).friendly_name.IsEmpty()) {
+ didl += " name=\"" + (*search_class).friendly_name + "\"";
+ }
+ didl += ">";
+ didl += (*search_class).type;
+ didl += "</upnp:searchClass>";
- didl += tmp;
+ ++search_class;
+ }
+ }
+
+ NPT_CHECK_SEVERE(PLT_MediaObject::ToDidl(mask, didl));
+
+ /* close tag */
+ didl += "</container>";
return NPT_SUCCESS;
}
@@ -1197,16 +786,47 @@ PLT_MediaContainer::FromDidl(NPT_XmlElementNode* entry)
return NPT_ERROR_INTERNAL;
// check if item is searchable (is default true?)
- if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "searchable", str))) {
+ if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "searchable", str, "", 5))) {
m_Searchable = PLT_Service::IsTrue(str);
}
// look for childCount
- if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "childCount", str))) {
+ if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(entry, "childCount", str, "", 256))) {
NPT_UInt32 count;
NPT_CHECK_SEVERE(str.ToInteger(count));
m_ChildrenCount = count;
}
+ // upnp:searchClass child elements
+ NPT_Array<NPT_XmlElementNode*> children;
+ PLT_XmlHelper::GetChildren(entry, children, "upnp:searchClass");
+
+ for (NPT_Cardinal i=0; i<children.GetItemCount(); i++) {
+ PLT_SearchClass search_class;
+
+ // extract url
+ if (children[i]->GetText() == NULL) {
+ NPT_LOG_WARNING_1("No searchClass text found in: %s",
+ (const char*)PLT_XmlHelper::Serialize(*children[i]));
+ continue;
+ }
+
+ // DLNA 7.3.17.4
+ search_class.type = children[i]->GetText()->SubString(0, 256);
+
+ // extract optional attribute name
+ PLT_XmlHelper::GetAttribute(children[i], "name", search_class.friendly_name);
+
+ // includeDerived property
+ if (NPT_FAILED(PLT_XmlHelper::GetAttribute(children[i], "includeDerived", str))) {
+ NPT_LOG_WARNING_1("No required attribute searchClass@includeDerived found in: %s",
+ (const char*)PLT_XmlHelper::Serialize(*children[i]));
+ continue;
+ }
+
+ search_class.include_derived = PLT_Service::IsTrue(str);
+ m_SearchClasses.Add(search_class);
+ }
+
return PLT_MediaObject::FromDidl(entry);
}
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h
index 11a5910721..3ebc3b09ae 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaItem.h
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Item
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Media Object reprensentation.
+ */
+
#ifndef _PLT_MEDIA_ITEM_H_
#define _PLT_MEDIA_ITEM_H_
@@ -39,15 +44,14 @@
+---------------------------------------------------------------------*/
#include "Neptune.h"
#include "PltHttp.h"
-
-/*----------------------------------------------------------------------
-| forward declarations
-+---------------------------------------------------------------------*/
-class PLT_MediaServer;
+#include "PltProtocolInfo.h"
/*----------------------------------------------------------------------
| typedefs
+---------------------------------------------------------------------*/
+/**
+ The PLT_ObjectClass struct is used to assign a type to a PLT_MediaObject.
+ */
typedef struct {
NPT_String type;
NPT_String friendly_name;
@@ -86,16 +90,16 @@ typedef struct {
PLT_PersonRoles artists;
PLT_PersonRoles actors;
PLT_PersonRoles authors;
- NPT_String producer;
- NPT_String director;
- NPT_String publisher;
- NPT_String contributor; // should match m_Creator (dc:creator)
+ NPT_String producer; //TODO: can be multiple
+ NPT_String director; //TODO: can be multiple
+ NPT_String publisher; //TODO: can be multiple
+ NPT_String contributor; // should match m_Creator (dc:creator) //TODO: can be multiple
} PLT_PeopleInfo;
typedef struct {
- NPT_List<NPT_String> genre;
- NPT_String album;
- NPT_String playlist; // dc:title of the playlist item the content belongs too
+ NPT_List<NPT_String> genres;
+ NPT_String album; //TODO: can be multiple
+ NPT_String playlist; // dc:title of the playlist item the content belongs too //TODO: can be multiple
} PLT_AffiliationInfo;
typedef struct {
@@ -104,98 +108,46 @@ typedef struct {
NPT_String icon_uri;
NPT_String region;
NPT_String rating;
- NPT_String rights;
+ NPT_String rights; //TODO: can be multiple
NPT_String date;
NPT_String language;
} PLT_Description;
typedef struct {
- NPT_String album_art_uri;
- NPT_String album_art_uri_dlna_profile;
+ NPT_String uri;
+ NPT_String dlna_profile;
+} PLT_AlbumArtInfo;
+
+typedef struct {
+ NPT_List<PLT_AlbumArtInfo> album_arts;
NPT_String artist_discography_uri;
NPT_String lyrics_uri;
- NPT_List<NPT_String> relation; // dc:relation
+ NPT_List<NPT_String> relations; // dc:relation
} PLT_ExtraInfo;
typedef struct {
NPT_UInt32 dvdregioncode;
NPT_UInt32 original_track_number;
NPT_String toc;
- NPT_String user_annotation;
+ NPT_String user_annotation; //TODO: can be multiple
} PLT_MiscInfo;
typedef struct {
- int total;
- int used;
- int free;
- int max_partition;
- NPT_String medium;
+ NPT_UInt64 total;
+ NPT_UInt64 used;
+ NPT_UInt64 free;
+ NPT_UInt64 max_partition;
+ NPT_UInt64 medium;
} PLT_StorageInfo;
typedef struct {
NPT_String program_title;
NPT_String series_title;
- int episode_number;
+ NPT_UInt32 episode_number;
} PLT_RecordedInfo;
/*----------------------------------------------------------------------
-| PLT_ProtocolInfo class
-+---------------------------------------------------------------------*/
-class PLT_ProtocolInfo
-{
-public:
- class FieldEntry {
- public:
- FieldEntry(const char* key, const char* value) :
- m_Key(key), m_Value(value) {}
- NPT_String m_Key;
- NPT_String m_Value;
- };
-
- PLT_ProtocolInfo();
- PLT_ProtocolInfo(const char* protocol_info);
- PLT_ProtocolInfo(const char* protocol,
- const char* mask,
- const char* content_type,
- const char* extra);
- const NPT_String& GetProtocol() const { return m_Protocol; }
- const NPT_String& GetMask() const { return m_Mask; }
- const NPT_String& GetContentType() const { return m_ContentType; }
- const NPT_String& GetExtra() const { return m_Extra; }
-
- const NPT_String& GetDLNA_PN() const { return m_DLNA_PN; }
-
- bool IsValid() { return m_Valid; }
- NPT_String ToString() const;
-
- bool Match(const PLT_ProtocolInfo& other) const;
-
-private:
- NPT_Result ValidateField(const char* val,
- const char* valid_chars,
- NPT_Cardinal num_chars = 0); // 0 means variable number of chars
- NPT_Result ParseExtra(NPT_List<FieldEntry>& entries);
- NPT_Result ValidateExtra();
-
-private:
- NPT_String m_Protocol;
- NPT_String m_Mask;
- NPT_String m_ContentType;
- NPT_String m_Extra;
-
- NPT_String m_DLNA_PN;
- NPT_String m_DLNA_OP;
- NPT_String m_DLNA_PS;
- NPT_String m_DLNA_CI;
- NPT_String m_DLNA_FLAGS;
- NPT_String m_DLNA_MAXSP;
-
- NPT_List<FieldEntry> m_DLNA_OTHER;
- bool m_Valid;
-};
-
-/*----------------------------------------------------------------------
-| PLT_MediaItemResource class
+| PLT_MediaItemResource
+---------------------------------------------------------------------*/
class PLT_MediaItemResource
{
@@ -217,30 +169,30 @@ public:
};
/*----------------------------------------------------------------------
-| PLT_MediaObject class
+| PLT_MediaObject
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaObject class is any data entity that can be returned by a
+ ContentDirectory Service from a browsing or searching action. This is the
+ base class from which PLT_MediaItem and PLT_MediaContainer derive.
+ */
class PLT_MediaObject
{
-public:
+protected:
+ NPT_IMPLEMENT_DYNAMIC_CAST(PLT_MediaObject)
+
PLT_MediaObject() {}
+
+public:
virtual ~PLT_MediaObject() {}
bool IsContainer() { return m_ObjectClass.type.StartsWith("object.container"); }
- static const char* GetMimeType(const NPT_String& filename,
- const PLT_HttpRequestContext* context = NULL);
- static const char* GetMimeTypeFromExtension(const NPT_String& extension,
- const PLT_HttpRequestContext* context = NULL);
- static NPT_String GetProtocolInfo(const char* filename,
- bool with_dlna_extension = true,
- const PLT_HttpRequestContext* context = NULL);
- static NPT_String GetMimeTypeFromProtocolInfo(const char* protocol_info);
static const char* GetUPnPClass(const char* filename,
const PLT_HttpRequestContext* context = NULL);
- static const char* GetDlnaExtension(const char* mime_type,
- const PLT_HttpRequestContext* context = NULL);
virtual NPT_Result Reset();
+ virtual NPT_Result ToDidl(const NPT_String& filter, NPT_String& didl);
virtual NPT_Result ToDidl(NPT_UInt32 mask, NPT_String& didl);
virtual NPT_Result FromDidl(NPT_XmlElementNode* entry);
@@ -277,30 +229,45 @@ public:
};
/*----------------------------------------------------------------------
-| PLT_MediaItem class
+| PLT_MediaItem
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaItem class represents a first-level class derived directly from
+ PLT_MediaObject. It most often represents a single piece of AV data.
+ */
class PLT_MediaItem : public PLT_MediaObject
{
public:
+ NPT_IMPLEMENT_DYNAMIC_CAST_D(PLT_MediaItem, PLT_MediaObject)
+
PLT_MediaItem();
virtual ~PLT_MediaItem();
// PLT_MediaObject methods
+ NPT_Result ToDidl(const NPT_String& filter, NPT_String& didl);
NPT_Result ToDidl(NPT_UInt32 mask, NPT_String& didl);
NPT_Result FromDidl(NPT_XmlElementNode* entry);
};
/*----------------------------------------------------------------------
-| PLT_MediaContainer class
+| PLT_MediaContainer
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaContainer class represents a first-level class derived directly
+ from PLT_MediaObject. A PLT_MediaContainer represents a collection of
+ PLT_MediaObject instances.
+ */
class PLT_MediaContainer : public PLT_MediaObject
{
public:
+ NPT_IMPLEMENT_DYNAMIC_CAST_D(PLT_MediaContainer, PLT_MediaObject)
+
PLT_MediaContainer();
virtual ~PLT_MediaContainer();
// PLT_MediaObject methods
NPT_Result Reset();
+ NPT_Result ToDidl(const NPT_String& filter, NPT_String& didl);
NPT_Result ToDidl(NPT_UInt32 mask, NPT_String& didl);
NPT_Result FromDidl(NPT_XmlElementNode* entry);
@@ -311,12 +278,16 @@ public:
bool m_Searchable;
/* container info related */
- NPT_Int32 m_ChildrenCount;
+ NPT_Int32 m_ChildrenCount;
+ NPT_UInt32 m_ContainerUpdateID;
};
/*----------------------------------------------------------------------
-| PLT_MediaObjectList class
+| PLT_MediaObjectList
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaObjectList class is a list of PLT_MediaObject instances.
+ */
class PLT_MediaObjectList : public NPT_List<PLT_MediaObject*>
{
public:
@@ -330,5 +301,4 @@ protected:
typedef NPT_Reference<PLT_MediaObjectList> PLT_MediaObjectListReference;
typedef NPT_Reference<PLT_MediaObject> PLT_MediaObjectReference;
-
#endif /* _PLT_MEDIA_ITEM_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.cpp
deleted file mode 100644
index f7841f0246..0000000000
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*****************************************************************
-|
-| Platinum - AV Media Playlist
-|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
-| All rights reserved.
-| http://www.plutinosoft.com
-|
-| This program is free software; you can redistribute it and/or
-| modify it under the terms of the GNU General Public License
-| as published by the Free Software Foundation; either version 2
-| of the License, or (at your option) any later version.
-|
-| OEMs, ISVs, VARs and other distributors that combine and
-| distribute commercially licensed software with Platinum software
-| and do not wish to distribute the source code for the commercially
-| licensed software under version 2, or (at your option) any later
-| version, of the GNU General Public License (the "GPL") must enter
-| into a commercial license agreement with Plutinosoft, LLC.
-|
-| 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 General Public License for more details.
-|
-| You should have received a copy of the GNU General Public License
-| along with this program; see the file LICENSE.txt. If not, write to
-| the Free Software Foundation, Inc.,
-| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-| http://www.gnu.org/licenses/gpl-2.0.html
-|
-****************************************************************/
-
-/*----------------------------------------------------------------------
-| includes
-+---------------------------------------------------------------------*/
-#include "PltMediaPlaylist.h"
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist::PLT_MediaPlaylist
-+---------------------------------------------------------------------*/
-PLT_MediaPlaylist::PLT_MediaPlaylist()
-{
- m_List = new PLT_MediaItemList();
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist::~PLT_MediaPlaylist
-+---------------------------------------------------------------------*/
-PLT_MediaPlaylist::~PLT_MediaPlaylist(void)
-{
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist::Clear
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaPlaylist::Clear(void)
-{
- m_List->Apply(NPT_ObjectDeleter<PLT_MediaItem>());
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist::Clear
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaPlaylist::Queue(PLT_MediaItem* item)
-{
- PLT_MediaItem* new_item = new PLT_MediaItem(*item);
- m_List->Add(new_item);
- return NPT_SUCCESS;
-}
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist::Queue
-+---------------------------------------------------------------------*/
-NPT_Result
-PLT_MediaPlaylist::Queue(PLT_MediaItemList* list)
-{
- list->Apply(PLT_MediaItemQueueIterator(this));
- return NPT_SUCCESS;
-}
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.h
deleted file mode 100644
index a53766bec8..0000000000
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaPlaylist.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*****************************************************************
-|
-| Platinum - AV Media Playlist
-|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
-| All rights reserved.
-| http://www.plutinosoft.com
-|
-| This program is free software; you can redistribute it and/or
-| modify it under the terms of the GNU General Public License
-| as published by the Free Software Foundation; either version 2
-| of the License, or (at your option) any later version.
-|
-| OEMs, ISVs, VARs and other distributors that combine and
-| distribute commercially licensed software with Platinum software
-| and do not wish to distribute the source code for the commercially
-| licensed software under version 2, or (at your option) any later
-| version, of the GNU General Public License (the "GPL") must enter
-| into a commercial license agreement with Plutinosoft, LLC.
-|
-| 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 General Public License for more details.
-|
-| You should have received a copy of the GNU General Public License
-| along with this program; see the file LICENSE.txt. If not, write to
-| the Free Software Foundation, Inc.,
-| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-| http://www.gnu.org/licenses/gpl-2.0.html
-|
-****************************************************************/
-
-#ifndef _PLT_MEDIA_PLAYLIST_H_
-#define _PLT_MEDIA_PLAYLIST_H_
-
-/*----------------------------------------------------------------------
-| includes
-+---------------------------------------------------------------------*/
-#include "Neptune.h"
-#include "PltMediaItem.h"
-
-/*----------------------------------------------------------------------
-| typedefs
-+---------------------------------------------------------------------*/
-typedef NPT_List<PLT_MediaItem*> PLT_MediaItemList;
-typedef NPT_Reference<PLT_MediaItemList> PLT_MediaItemListReference;
-
-/*----------------------------------------------------------------------
-| PLT_MediaPlaylist class
-+---------------------------------------------------------------------*/
-class PLT_MediaPlaylist
-{
-public:
- PLT_MediaPlaylist();
- ~PLT_MediaPlaylist(void);
-
- NPT_Result Clear();
- NPT_Result Queue(PLT_MediaItem* item);
- NPT_Result Queue(PLT_MediaItemList* list);
- template <typename X>
- NPT_Result Apply(const X& function) {
- return m_List->Apply(function);
- }
-
-private:
- PLT_MediaItemListReference m_List;
-};
-
-/*----------------------------------------------------------------------
-| PLT_MediaItemQueueIterator class
-+---------------------------------------------------------------------*/
-class PLT_MediaItemQueueIterator
-{
-public:
- PLT_MediaItemQueueIterator(PLT_MediaPlaylist* playlist) : m_Playlist(playlist) {}
- NPT_Result operator()(PLT_MediaItem*& item) const {
- return m_Playlist->Queue(item);
- }
-
-private:
- PLT_MediaPlaylist* m_Playlist;
-};
-
-#endif /* _PLT_MEDIA_PLAYLIST_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.cpp
index fc065e0a28..990869a485 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.cpp
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Server Device
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -41,7 +42,6 @@
#include "PltTaskManager.h"
#include "PltHttpServer.h"
#include "PltDidl.h"
-#include "PltMetadataHandler.h"
NPT_SET_LOCAL_LOGGER("platinum.media.server")
@@ -49,7 +49,6 @@ NPT_SET_LOCAL_LOGGER("platinum.media.server")
| forward references
+---------------------------------------------------------------------*/
extern NPT_UInt8 MS_ConnectionManagerSCPD[];
-extern NPT_UInt8 MS_ContentDirectorySCPD[];
extern NPT_UInt8 MS_ContentDirectorywSearchSCPD[];
const char* BrowseFlagsStr[] = {
@@ -71,12 +70,12 @@ PLT_MediaServer::PLT_MediaServer(const char* friendly_name,
friendly_name,
show_ip,
port,
- port_rebind)
+ port_rebind),
+ m_Delegate(NULL)
{
m_ModelDescription = "Plutinosoft AV Media Server Device";
m_ModelName = "AV Media Server Device";
- m_ModelNumber = "1.0";
- m_ModelURL = "http://www.plutinosoft.com/blog/projects/platinum";
+ m_ModelURL = "http://www.plutinosoft.com/platinum";
m_DlnaDoc = "DMS-1.50";
}
@@ -91,35 +90,35 @@ PLT_MediaServer::~PLT_MediaServer()
| PLT_MediaServer::SetupServices
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaServer::SetupServices(PLT_DeviceData& data)
+PLT_MediaServer::SetupServices()
{
PLT_Service* service;
{
service = new PLT_Service(
- &data,
+ this,
"urn:schemas-upnp-org:service:ContentDirectory:1",
- "urn:upnp-org:serviceId:ContentDirectory");
+ "urn:upnp-org:serviceId:ContentDirectory",
+ "ContentDirectory");
NPT_CHECK_FATAL(service->SetSCPDXML((const char*) MS_ContentDirectorywSearchSCPD));
- NPT_CHECK_FATAL(service->InitURLs("ContentDirectory", data.GetUUID()));
- NPT_CHECK_FATAL(data.AddService(service));
+ NPT_CHECK_FATAL(AddService(service));
- service->SetStateVariable("ContainerUpdateIDs", "0");
- service->SetStateVariableRate("ContainerUpdateIDs", NPT_TimeInterval(2, 0));
+ service->SetStateVariable("ContainerUpdateIDs", "");
+ service->SetStateVariableRate("ContainerUpdateIDs", NPT_TimeInterval(2.));
service->SetStateVariable("SystemUpdateID", "0");
- service->SetStateVariableRate("SystemUpdateID", NPT_TimeInterval(2, 0));
- service->SetStateVariable("SearchCapability", "upnp:class");
- service->SetStateVariable("SortCapability", "");
+ service->SetStateVariableRate("SystemUpdateID", NPT_TimeInterval(2.));
+ service->SetStateVariable("SearchCapability", "@id,@refID,dc:title,upnp:class,upnp:genre,upnp:artist,upnp:author,upnp:author@role,upnp:album,dc:creator,res@size,res@duration,res@protocolInfo,res@protection,dc:publisher,dc:language,upnp:originalTrackNumber,dc:date,upnp:producer,upnp:rating,upnp:actor,upnp:director,upnp:toc,dc:description,microsoft:userRatingInStars,microsoft:userEffectiveRatingInStars,microsoft:userRating,microsoft:userEffectiveRating,microsoft:serviceProvider,microsoft:artistAlbumArtist,microsoft:artistPerformer,microsoft:artistConductor,microsoft:authorComposer,microsoft:authorOriginalLyricist,microsoft:authorWriter,upnp:userAnnotation,upnp:channelName,upnp:longDescription,upnp:programTitle");
+ service->SetStateVariable("SortCapability", "dc:title,upnp:genre,upnp:album,dc:creator,res@size,res@duration,res@bitrate,dc:publisher,dc:language,upnp:originalTrackNumber,dc:date,upnp:producer,upnp:rating,upnp:actor,upnp:director,upnp:toc,dc:description,microsoft:year,microsoft:userRatingInStars,microsoft:userEffectiveRatingInStars,microsoft:userRating,microsoft:userEffectiveRating,microsoft:serviceProvider,microsoft:artistAlbumArtist,microsoft:artistPerformer,microsoft:artistConductor,microsoft:authorComposer,microsoft:authorOriginalLyricist,microsoft:authorWriter,microsoft:sourceUrl,upnp:userAnnotation,upnp:channelName,upnp:longDescription,upnp:programTitle");
}
{
service = new PLT_Service(
- &data,
+ this,
"urn:schemas-upnp-org:service:ConnectionManager:1",
- "urn:upnp-org:serviceId:ConnectionManager");
+ "urn:upnp-org:serviceId:ConnectionManager",
+ "ConnectionManager");
NPT_CHECK_FATAL(service->SetSCPDXML((const char*) MS_ConnectionManagerSCPD));
- NPT_CHECK_FATAL(service->InitURLs("ConnectionManager", data.GetUUID()));
- NPT_CHECK_FATAL(data.AddService(service));
+ NPT_CHECK_FATAL(AddService(service));
service->SetStateVariable("CurrentConnectionIDs", "0");
service->SetStateVariable("SinkProtocolInfo", "");
@@ -130,6 +129,24 @@ PLT_MediaServer::SetupServices(PLT_DeviceData& data)
}
/*----------------------------------------------------------------------
+| PLT_MediaServer::UpdateSystemUpdateID
++---------------------------------------------------------------------*/
+void
+PLT_MediaServer::UpdateSystemUpdateID(NPT_UInt32 update)
+{
+ NPT_COMPILER_UNUSED(update);
+}
+
+/*----------------------------------------------------------------------
+| PLT_MediaServer::UpdateContainerUpdateID
++---------------------------------------------------------------------*/
+void PLT_MediaServer::UpdateContainerUpdateID(const char* id, NPT_UInt32 update)
+{
+ NPT_COMPILER_UNUSED(id);
+ NPT_COMPILER_UNUSED(update);
+}
+
+/*----------------------------------------------------------------------
| PLT_MediaServer::OnAction
+---------------------------------------------------------------------*/
NPT_Result
@@ -172,6 +189,20 @@ PLT_MediaServer::OnAction(PLT_ActionReference& action,
}
/*----------------------------------------------------------------------
+| PLT_FileMediaServer::ProcessHttpGetRequest
++---------------------------------------------------------------------*/
+NPT_Result
+PLT_MediaServer::ProcessHttpGetRequest(NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& context,
+ NPT_HttpResponse& response)
+{
+ /* Try to handle file request */
+ if (m_Delegate) return m_Delegate->ProcessFileRequest(request, context, response);
+
+ return NPT_ERROR_NO_SUCH_ITEM;
+}
+
+/*----------------------------------------------------------------------
| PLT_MediaServer::OnGetCurrentConnectionIDs
+---------------------------------------------------------------------*/
NPT_Result
@@ -271,10 +302,10 @@ PLT_MediaServer::OnGetSystemUpdateID(PLT_ActionReference& action,
}
/*----------------------------------------------------------------------
-| PLT_MediaServer::GetBrowseFlag
+| PLT_MediaServer::ParseBrowseFlag
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaServer::GetBrowseFlag(const char* str, BrowseFlags& flag)
+PLT_MediaServer::ParseBrowseFlag(const char* str, BrowseFlags& flag)
{
if (NPT_String::Compare(str, BrowseFlagsStr[0], true) == 0) {
flag = BROWSEMETADATA;
@@ -345,7 +376,7 @@ PLT_MediaServer::OnBrowse(PLT_ActionReference& action,
/* extract flag */
BrowseFlags flag;
- if (NPT_FAILED(GetBrowseFlag(browse_flag_val, flag))) {
+ if (NPT_FAILED(ParseBrowseFlag(browse_flag_val, flag))) {
/* error */
NPT_LOG_WARNING_1("BrowseFlag value not allowed (%s)", (const char*)browse_flag_val);
action->SetError(402, "Invalid args");
@@ -363,7 +394,7 @@ PLT_MediaServer::OnBrowse(PLT_ActionReference& action,
return NPT_FAILURE;
}
- /* parse sort criteria */
+ /* parse sort criteria for validation */
if (NPT_FAILED(ParseSort(sort, sort_list))) {
NPT_LOG_WARNING_1("Unsupported or invalid sort criteria error (%s)",
sort.GetChars());
@@ -371,7 +402,7 @@ PLT_MediaServer::OnBrowse(PLT_ActionReference& action,
return NPT_FAILURE;
}
- NPT_LOG_INFO_6("Received %s from %s for id = %s with filter = %s, start = %d, count = %d",
+ NPT_LOG_FINE_6("Processing %s from %s with id=\"%s\", filter=\"%s\", start=%d, count=%d",
(const char*)browse_flag_val,
(const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
(const char*)object_id,
@@ -387,7 +418,7 @@ PLT_MediaServer::OnBrowse(PLT_ActionReference& action,
filter,
starting_index,
requested_count,
- sort_list,
+ sort,
context);
} else {
res = OnBrowseDirectChildren(
@@ -396,7 +427,7 @@ PLT_MediaServer::OnBrowse(PLT_ActionReference& action,
filter,
starting_index,
requested_count,
- sort_list,
+ sort,
context);
}
@@ -454,7 +485,7 @@ PLT_MediaServer::OnSearch(PLT_ActionReference& action,
return NPT_FAILURE;
}
- NPT_LOG_INFO_5("Received Search from %s for id = %s with search = %s, start = %d, count = %d",
+ NPT_LOG_INFO_5("Processing Search from %s with id=\"%s\", search=\"%s\", start=%d, count=%d",
(const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
(const char*)container_id,
(const char*)search,
@@ -468,7 +499,7 @@ PLT_MediaServer::OnSearch(PLT_ActionReference& action,
filter,
starting_index,
requested_count,
- sort_list,
+ sort,
context);
} else {
res = OnSearchContainer(
@@ -478,7 +509,7 @@ PLT_MediaServer::OnSearch(PLT_ActionReference& action,
filter,
starting_index,
requested_count,
- sort_list,
+ sort,
context);
}
@@ -493,14 +524,23 @@ PLT_MediaServer::OnSearch(PLT_ActionReference& action,
| PLT_MediaServer::OnBrowseMetadata
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaServer::OnBrowseMetadata(PLT_ActionReference& /* action */,
- const char* /* object_id */,
- const char* /* filter */,
- NPT_UInt32 /* starting_index */,
- NPT_UInt32 /* requested_count */,
- const NPT_List<NPT_String>& /* sort_criteria */,
- const PLT_HttpRequestContext& /* context */)
+PLT_MediaServer::OnBrowseMetadata(PLT_ActionReference& action,
+ const char* object_id,
+ const char* filter,
+ NPT_UInt32 starting_index,
+ NPT_UInt32 requested_count,
+ const char* sort_criteria,
+ const PLT_HttpRequestContext& context)
{
+ if (m_Delegate) {
+ return m_Delegate->OnBrowseMetadata(action,
+ object_id,
+ filter,
+ starting_index,
+ requested_count,
+ sort_criteria,
+ context);
+ }
return NPT_ERROR_NOT_IMPLEMENTED;
}
@@ -508,14 +548,23 @@ PLT_MediaServer::OnBrowseMetadata(PLT_ActionReference& /* action */,
| PLT_MediaServer::OnBrowseDirectChildren
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaServer::OnBrowseDirectChildren(PLT_ActionReference& /* action */,
- const char* /* object_id */,
- const char* /* filter */,
- NPT_UInt32 /* starting_index */,
- NPT_UInt32 /* requested_count */,
- const NPT_List<NPT_String>& /* sort_criteria */,
- const PLT_HttpRequestContext& /* context */)
+PLT_MediaServer::OnBrowseDirectChildren(PLT_ActionReference& action,
+ const char* object_id,
+ const char* filter,
+ NPT_UInt32 starting_index,
+ NPT_UInt32 requested_count,
+ const char* sort_criteria,
+ const PLT_HttpRequestContext& context)
{
+ if (m_Delegate) {
+ return m_Delegate->OnBrowseDirectChildren(action,
+ object_id,
+ filter,
+ starting_index,
+ requested_count,
+ sort_criteria,
+ context);
+ }
return NPT_ERROR_NOT_IMPLEMENTED;
}
@@ -523,14 +572,24 @@ PLT_MediaServer::OnBrowseDirectChildren(PLT_ActionReference& /* action
| PLT_MediaServer::OnSearchContainer
+---------------------------------------------------------------------*/
NPT_Result
-PLT_MediaServer::OnSearchContainer(PLT_ActionReference& /* action */,
- const char* /* object_id */,
- const char* /* search_criteria */,
- const char* /* filter */,
- NPT_UInt32 /* starting_index */,
- NPT_UInt32 /* requested_count */,
- const NPT_List<NPT_String>& /* sort_criteria */,
- const PLT_HttpRequestContext& /* context */)
+PLT_MediaServer::OnSearchContainer(PLT_ActionReference& action,
+ const char* object_id,
+ const char* search_criteria,
+ const char* filter,
+ NPT_UInt32 starting_index,
+ NPT_UInt32 requested_count,
+ const char* sort_criteria,
+ const PLT_HttpRequestContext& context)
{
+ if (m_Delegate) {
+ return m_Delegate->OnSearchContainer(action,
+ object_id,
+ search_criteria,
+ filter,
+ starting_index,
+ requested_count,
+ sort_criteria,
+ context);
+ }
return NPT_ERROR_NOT_IMPLEMENTED;
}
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.h
index d277b0aa6f..fb4f9f3288 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltMediaServer.h
@@ -2,7 +2,7 @@
|
| Platinum - AV Media Server Device
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Media Server.
+ */
+
#ifndef _PLT_MEDIA_SERVER_H_
#define _PLT_MEDIA_SERVER_H_
@@ -46,40 +51,91 @@
+---------------------------------------------------------------------*/
#define MAX_PATH_LENGTH 1024
-/* BrowseFlags */
-enum BrowseFlags {
- BROWSEMETADATA,
- BROWSEDIRECTCHILDREN
-};
-
/*----------------------------------------------------------------------
-| forward declarations
+| PLT_MediaServerDelegate
+---------------------------------------------------------------------*/
-extern const char* BrowseFlagsStr[];
-class PLT_HttpFileServerHandler;
+/**
+ The PLT_MediaServerDelegate class is an interface for delegating the handling
+ of the required UPnP AV ContentDirectory service actions. It also handles
+ resource HTTP requests (downloading).
+ */
+class PLT_MediaServerDelegate
+{
+public:
+ PLT_MediaServerDelegate() {}
+ virtual ~PLT_MediaServerDelegate() {}
+
+ virtual NPT_Result OnBrowseMetadata(PLT_ActionReference& /*action*/,
+ const char* /*object_id*/,
+ const char* /*filter*/,
+ NPT_UInt32 /*starting_index*/,
+ NPT_UInt32 /*requested_count*/,
+ const char* /*sort_criteria*/,
+ const PLT_HttpRequestContext& /*context*/) = 0;
+ virtual NPT_Result OnBrowseDirectChildren(PLT_ActionReference& /*action*/,
+ const char* /*object_id*/,
+ const char* /*filter*/,
+ NPT_UInt32 /*starting_index*/,
+ NPT_UInt32 /*requested_count*/,
+ const char* /*sort_criteria*/,
+ const PLT_HttpRequestContext& /*context*/) = 0;
+ virtual NPT_Result OnSearchContainer(PLT_ActionReference& /*action*/,
+ const char* /*container_id*/,
+ const char* /*search_criteria*/,
+ const char* /*filter*/,
+ NPT_UInt32 /*starting_index*/,
+ NPT_UInt32 /*requested_count*/,
+ const char* /*sort_criteria*/,
+ const PLT_HttpRequestContext& /*context*/) = 0;
+ virtual NPT_Result ProcessFileRequest(NPT_HttpRequest& /*request*/,
+ const NPT_HttpRequestContext& /*context*/,
+ NPT_HttpResponse& /*response*/) = 0;
+};
/*----------------------------------------------------------------------
-| PLT_MediaServer class
+| PLT_MediaServer
+---------------------------------------------------------------------*/
+/**
+ The PLT_MediaServer class implements the base class for a UPnP AV
+ Media Server device.
+ */
class PLT_MediaServer : public PLT_DeviceHost
{
public:
+ /* BrowseFlags */
+ enum BrowseFlags {
+ BROWSEMETADATA,
+ BROWSEDIRECTCHILDREN
+ };
+
+ // class methods
+ static NPT_Result ParseBrowseFlag(const char* str, BrowseFlags& flag);
+ static NPT_Result ParseSort(const NPT_String& sort, NPT_List<NPT_String>& list);
+
+ // constructor
PLT_MediaServer(const char* friendly_name,
bool show_ip = false,
const char* uuid = NULL,
NPT_UInt16 port = 0,
bool port_rebind = false);
+
+ // methods
+ virtual void SetDelegate(PLT_MediaServerDelegate* delegate) { m_Delegate = delegate; }
+ PLT_MediaServerDelegate* GetDelegate() { return m_Delegate; }
+ virtual void UpdateSystemUpdateID(NPT_UInt32 update);
+ virtual void UpdateContainerUpdateID(const char* id, NPT_UInt32 update);
+
+protected:
virtual ~PLT_MediaServer();
-
+
// PLT_DeviceHost methods
- virtual NPT_Result SetupServices(PLT_DeviceData& data);
+ virtual NPT_Result SetupServices();
virtual NPT_Result OnAction(PLT_ActionReference& action,
const PLT_HttpRequestContext& context);
-
- // class methods
- static NPT_Result GetBrowseFlag(const char* str, BrowseFlags& flag);
-
-protected:
+ virtual NPT_Result ProcessHttpGetRequest(NPT_HttpRequest& request,
+ const NPT_HttpRequestContext& context,
+ NPT_HttpResponse& response);
+
// ConnectionManager
virtual NPT_Result OnGetCurrentConnectionIDs(PLT_ActionReference& action,
const PLT_HttpRequestContext& context);
@@ -106,14 +162,14 @@ protected:
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
virtual NPT_Result OnBrowseDirectChildren(PLT_ActionReference& action,
const char* object_id,
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
virtual NPT_Result OnSearchContainer(PLT_ActionReference& action,
const char* container_id,
@@ -121,11 +177,11 @@ protected:
const char* filter,
NPT_UInt32 starting_index,
NPT_UInt32 requested_count,
- const NPT_List<NPT_String>& sort_criteria,
+ const char* sort_criteria,
const PLT_HttpRequestContext& context);
-
- // methods
- virtual NPT_Result ParseSort(const NPT_String& sort, NPT_List<NPT_String>& list);
+
+private:
+ PLT_MediaServerDelegate* m_Delegate;
};
#endif /* _PLT_MEDIA_SERVER_H_ */
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
index 38ee23996e..2bd23f8c9b 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.cpp
@@ -2,7 +2,7 @@
|
| Platinum - Synchronous Media Browser
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -35,7 +36,6 @@
| includes
+---------------------------------------------------------------------*/
#include "PltSyncMediaBrowser.h"
-#include <algorithm>
NPT_SET_LOCAL_LOGGER("platinum.media.server.syncbrowser")
@@ -208,6 +208,7 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_BrowseDataReference& browse_data,
NPT_Result res;
browse_data->shared_var.SetValue(0);
+ browse_data->info.si = index;
// send off the browse packet. Note that this will
// not block. There is a call to WaitForResponse in order
@@ -238,8 +239,9 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference& device,
{
NPT_Result res = NPT_FAILURE;
NPT_Int32 index = start;
- NPT_UInt32 count = 0;
- bool cache = m_UseCache && !metadata && start == 0 && max_results == 0;
+
+ // only cache metadata or if starting from 0 and asking for maximum
+ bool cache = m_UseCache && (metadata || (start == 0 && max_results == 0));
// reset output params
list = NULL;
@@ -248,7 +250,7 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference& device,
if (cache && NPT_SUCCEEDED(m_Cache.Get(device->GetUUID(), object_id, list))) return NPT_SUCCESS;
do {
- PLT_BrowseDataReference browse_data(new PLT_BrowseData());
+ PLT_BrowseDataReference browse_data(new PLT_BrowseData(), true);
// send off the browse packet. Note that this will
// not block. There is a call to WaitForResponse in order
@@ -267,14 +269,10 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference& device,
NPT_CHECK_LABEL_WARNING(res, done);
}
- if (browse_data->info.nr == 0)
+ // server returned no more, bail now
+ if (browse_data->info.items->GetItemCount() == 0)
break;
- if (browse_data->info.nr != browse_data->info.items->GetItemCount()) {
- NPT_LOG_WARNING_2("Server unexpected number of items (%d vs %d)", browse_data->info.items->GetItemCount(), browse_data->info.nr);
- }
- count += std::max<NPT_UInt32>(browse_data->info.nr, browse_data->info.items->GetItemCount());
-
if (list.IsNull()) {
list = browse_data->info.items;
} else {
@@ -291,12 +289,13 @@ PLT_SyncMediaBrowser::BrowseSync(PLT_DeviceDataReference& device,
// nothing is returned back by the server.
// Unless we were told to stop after reaching a certain amount to avoid
// length delays
- if ((browse_data->info.tm && browse_data->info.tm <= count) ||
- (max_results && count >= max_results))
+ // (some servers may return a total matches out of whack at some point too)
+ if ((browse_data->info.tm && browse_data->info.tm <= list->GetItemCount()) ||
+ (max_results && list->GetItemCount() >= max_results))
break;
// ask for the next chunk of entries
- index = count;
+ index = list->GetItemCount();
} while(1);
done:
@@ -306,7 +305,7 @@ done:
}
// clear entire cache data for device if failed, the device could be gone
- if (NPT_FAILED(res) && m_UseCache) m_Cache.Clear(device->GetUUID());
+ if (NPT_FAILED(res) && cache) m_Cache.Clear(device->GetUUID());
return res;
}
diff --git a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
index 3bf6ee3e62..e628af9f58 100644
--- a/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
+++ b/lib/libUPnP/Platinum/Source/Devices/MediaServer/PltSyncMediaBrowser.h
@@ -2,7 +2,7 @@
|
| Platinum - Synchronous Media Browser
|
-| Copyright (c) 2004-2008, Plutinosoft, LLC.
+| Copyright (c) 2004-2010, Plutinosoft, LLC.
| All rights reserved.
| http://www.plutinosoft.com
|
@@ -17,7 +17,8 @@
| licensed software under version 2, or (at your option) any later
| version, of the GNU General Public License (the "GPL") must enter
| into a commercial license agreement with Plutinosoft, LLC.
-|
+| licensing@plutinosoft.com
+|
| 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
@@ -31,6 +32,10 @@
|
****************************************************************/
+/** @file
+ UPnP AV Media Controller synchronous implementation.
+ */
+
#ifndef _PLT_SYNC_MEDIA_BROWSER_
#define _PLT_SYNC_MEDIA_BROWSER_
@@ -113,7 +118,7 @@ protected:
NPT_Int32 index,
NPT_Int32 count,
bool browse_metadata = false,
- const char* filter = "*",
+ const char* filter = "dc:date,upnp:genre,res,res@duration,res@size,upnp:albumArtURI,upnp:album,upnp:artist,upnp:author,searchable,childCount", // explicitely specify res otherwise WMP won't return a URL!
const char* sort = "");
private:
NPT_Result Find(const char* ip, PLT_DeviceDataReference& device);
@@ -123,7 +128,7 @@ private:
NPT_Lock<PLT_DeviceMap> m_MediaServers;
PLT_MediaContainerChangesListener* m_ContainerListener;
bool m_UseCache;
- PLT_MediaCache m_Cache;
+ PLT_MediaCache<PLT_MediaObjectListReference,NPT_String> m_Cache;
};
/*----------------------------------------------------------------------