summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY4
-rw-r--r--README40
-rw-r--r--common.cpp20
-rw-r--r--common.h124
-rw-r--r--database/database.cpp15
-rw-r--r--database/database.h347
-rw-r--r--database/metadata.cpp88
-rw-r--r--database/metadata.h149
-rw-r--r--database/object.cpp112
-rw-r--r--database/object.h1420
-rw-r--r--database/resources.cpp14
-rw-r--r--database/resources.h111
-rw-r--r--misc/avdetector.cpp2
-rw-r--r--misc/avdetector.h19
-rw-r--r--misc/config.cpp18
-rw-r--r--misc/config.h49
-rw-r--r--misc/menusetup.cpp4
-rw-r--r--misc/menusetup.h31
-rw-r--r--misc/search.cpp66
-rw-r--r--misc/search.h76
-rw-r--r--misc/util.cpp19
-rw-r--r--misc/util.h101
-rw-r--r--receiver/filehandle.h90
-rw-r--r--receiver/livereceiver.cpp28
-rw-r--r--receiver/livereceiver.h66
-rw-r--r--receiver/recplayer.cpp10
-rw-r--r--receiver/recplayer.h18
-rw-r--r--server/server.cpp54
-rw-r--r--server/server.h65
-rw-r--r--upnp.cpp17
-rw-r--r--upnp.h80
-rw-r--r--upnpcomponents/connectionmanager.cpp48
-rw-r--r--upnpcomponents/connectionmanager.h40
-rw-r--r--upnpcomponents/contentdirectory.cpp8
-rw-r--r--upnpcomponents/contentdirectory.h20
-rw-r--r--upnpcomponents/dlna.cpp8
-rw-r--r--upnpcomponents/dlna.h108
-rw-r--r--upnpcomponents/upnpservice.cpp4
-rw-r--r--upnpcomponents/upnpservice.h106
-rw-r--r--upnpcomponents/upnpwebserver.cpp42
-rw-r--r--upnpcomponents/upnpwebserver.h45
41 files changed, 3154 insertions, 532 deletions
diff --git a/HISTORY b/HISTORY
index 854250e..a510f03 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,10 @@
VDR Plugin 'upnp' Revision History
----------------------------------
+2009-11-19: Version 0.0.1-alpha4
+
+- New: Added options for verbosity level and autodetect settings.
+
2009-10-23: Version 0.0.1-alpha1
- Fixed #185: Database rejected statements with single quotes inside strings
diff --git a/README b/README
index 1557c0b..1eba683 100644
--- a/README
+++ b/README
@@ -53,6 +53,29 @@ The command line settings are:
Supported ports:
0 (auto detect)
49152-65535 (user defined)
+ -d --autodetect Force auto detection
+ Use this option to
+ overwrite the setup menu
+ options.
+ -v --verbose Increase verbosity level
+ The more v options the
+ higher the output level
+
+The verbose option can be more than once. With each option the verbosity level
+will be increased. The maximum level is 5. Further options are silently ignored.
+
+ -v Print most important messages
+ -vv Print messages from the components
+ i.e. the webserver, CDS, CMS, etc.
+ -vvv Print messages from receivers and players
+ and other additional components
+ -vvvv You can't get enough, hum?
+ This will print SQL messages and DIDL
+ messages
+ -vvvvv Can you read the matrix? You can't?
+ Then try first reading SQL statements,
+ fetches, buffer and parser outputs or
+ any other outputs.
If not options are set, menu options will be used.
@@ -68,7 +91,18 @@ Dependencies:
This plugin is tested with and requires the following libraries to work:
-libupnp-1.6.6
-libsqlite-3.6
+libupnp-1.6.6 The UPnP SDK
+libsqlite-3.6 SQLite 3 Database
+libavcodec-svn20090303 FFMPEG Library for analyzing audio video codecs
+libavformat-svn20090303 FFMPEG Library for analyzing audio video formats
+boost::spirit Grammar parser
+boost::function Boost function library
+boost::bind Boost bind library
-libupnp-1.8.0 is known not to work with this plugin!
+The boost libraries are usually available in a packed version, so that only a
+single installation is required. The FFMPEG libraries comes with FFMPEG itself.
+
+ATTENTION: DO NOT USE ANOTHER VERSION OF LIBUPNP.
+
+libupnp-1.8.0 is known not to work with this plugin! Versions below 1.6.6 may
+work. However, there may exist some unknown issues.
diff --git a/common.cpp b/common.cpp
index 946c48f..f32f9b2 100644
--- a/common.cpp
+++ b/common.cpp
@@ -7,9 +7,12 @@
#include <stdarg.h>
#include "common.h"
+#include "misc/config.h"
DLNAProfile DLNA_PROFILE_MPEG_TS_SD_EU = { "MPEG_TS_SD_EU", "video/vnd.dlna.mpeg-tts" };
DLNAProfile DLNA_PROFILE_AVC_TS_HD_EU = { "AVC_TS_HD_EU", "video/vnd.dlna.mpeg-tts" };
+DLNAProfile DLNA_PROFILE_MPEG_TS_SD_EU_ISO = { "MPEG_TS_SD_EU_ISO", "video/mpeg" };
+DLNAProfile DLNA_PROFILE_AVC_TS_HD_EU_ISO = { "AVC_TS_HD_EU_ISO", "video/mpeg" };
DLNAProfile DLNA_PROFILE_MPEG1_L3 = { "MP3", "audio/mpeg" };
DLNAIconProfile DLNA_ICON_JPEG_SM_24 = { "image/jpeg", 48, 48, 24 };
@@ -19,11 +22,14 @@ DLNAIconProfile DLNA_ICON_PNG_LRG_24A = { "image/png", 120, 120, 24 };
#define MESSAGE_SIZE 256
-void message(const char* File, int Line, const char* Format, ...){
- va_list ap;
- char Message[MESSAGE_SIZE];
- snprintf(Message, MESSAGE_SIZE, "(%s:%d) %s\n", File, Line, Format);
- va_start(ap, Format);
- vprintf(Message, ap);
- va_end(ap);
+void message(int Level, const char* , int , const char* Format, ...){
+ if(Level && cUPnPConfig::verbosity >= Level){
+ va_list ap;
+ char Message[MESSAGE_SIZE];
+
+ snprintf(Message, sizeof(Message), "[%d] %s", cThread::ThreadId(), Format);
+ va_start(ap, Format);
+ vsyslog(LOG_NOTICE, Message, ap);
+ va_end(ap);
+ }
} \ No newline at end of file
diff --git a/common.h b/common.h
index 6dc7975..6caa065 100644
--- a/common.h
+++ b/common.h
@@ -91,7 +91,7 @@
#define att(s) strchr(s,'@')!=NULL?strchr(s,'@')+1:NULL
#define prop(s) substr(s, 0, strchr(s,'@')-s)
-void message(const char* File, int Line, const char* Format, ...) __attribute__ ((format (printf, 3, 4)));
+void message(int level, const char* File, int Line, const char* Format, ...) __attribute__ ((format (printf, 4, 5)));
/****************************************************
*
@@ -154,12 +154,48 @@ void message(const char* File, int Line, const char* Format, ...) __attribute__
* Messages are additional information about the servers behavior. This will
* be useful for debugging.
*/
-#ifdef DEBUG
-#define MESSAGE(s...) message(__FILE__, __LINE__, "UPnP server message: " s)
+#ifndef DEBUG
+#define MESSAGE(l,s...) message(l,__FILE__, __LINE__, "UPnP server message: " s)
#else
-#define MESSAGE(s...) dsyslog("UPnP server message: " s)
+#define MESSAGE(l,s...) dsyslog("UPnP server message: " s)
#endif
+
+/**
+ * Define at which level the different messages will be printed
+ *
+ * The log levels reach from 1 to 5, where 1 is the highest log
+ * priority and 5 the lowest. 0 will deactivate the logging of
+ * the message. If you want to specifiy a certain level, add
+ * 'v' options as many as required for the log level.
+ *
+ * @example
+ * - \-v Show warnings
+ * - \-vv Log level 1
+ * - \-vvv Log level 2
+ * - \-vvvv Log level 3
+ * - \-vvvvv Log level 4
+ * - \-vvvvvv Log level 5
+ */
+#define VERBOSE_SQL 4
+#define VERBOSE_SQL_FETCHES 5
+#define VERBOSE_SQL_STATEMENTS 5
+#define VERBOSE_DIDL 4
+#define VERBOSE_LIVE_TV 3
+#define VERBOSE_RECORDS 3
+#define VERBOSE_CUSTOMFILES 3
+#define VERBOSE_SDK 1
+#define VERBOSE_EPG_UPDATES 3
+#define VERBOSE_WEBSERVER 2
+#define VERBOSE_MODIFICATIONS 2
+#define VERBOSE_METADATA 3
+#define VERBOSE_CUSTOM_OUTPUT 5
+#define VERBOSE_PARSERS 5
+#define VERBOSE_BUFFERS 5
+#define VERBOSE_CDS 2
+#define VERBOSE_CMS 2
+#define VERBOSE_OBJECTS 3
+
/****************************************************
*
* 1.3 Plugin constants
@@ -648,17 +684,17 @@ enum UPnPWriteStatus {
* The following operation field assumes that s0 is NOT changing. Only changes to sN are permitted.
* If s0 and/or sN changes these fields must be set to false. Use DLNA_FLAG_*_BASED_SEEK flags instead.
*/
-#define DLNA_OPERATION_NONE 00 // No seek operations supported
-#define DLNA_OPERATION_TIME_SEEK_RANGE 10 // is the server supporting time based seeks?
-#define DLNA_OPERATION_RANGE 01 // or byte based seeks?
+#define DLNA_OPERATION_NONE 00 ///< No seek operations supported
+#define DLNA_OPERATION_TIME_SEEK_RANGE 10 ///< is the server supporting time based seeks?
+#define DLNA_OPERATION_RANGE 01 ///< or byte based seeks?
-#define DLNA_CONVERSION_TRANSCODED 1 // the content was converted from one media format to another
-#define DLNA_CONVERSION_NONE 0 // the content is available without conversion
+#define DLNA_CONVERSION_TRANSCODED 1 ///< the content was converted from one media format to another
+#define DLNA_CONVERSION_NONE 0 ///< the content is available without conversion
-#define DLNA_SUPPORTED_PLAYSPEEDS "2,4,8,-2,-4,-8"; // 1 is required, but omited in the PS parameter
+#define DLNA_SUPPORTED_PLAYSPEEDS "2,4,8,-2,-4,-8"; ///< 1 is required, but omited in the PS parameter
-#define DLNA_TRANSFER_PROTOCOL_HTTP 1 // use http tranfer
-#define DLNA_TRANSFER_PROTOCOL_RTP 2 // use rtp tranfer
+#define DLNA_TRANSFER_PROTOCOL_HTTP 1 ///< use http tranfer
+#define DLNA_TRANSFER_PROTOCOL_RTP 2 ///< use rtp tranfer
/****************************************************
*
@@ -666,21 +702,21 @@ enum UPnPWriteStatus {
*
****************************************************/
-#define DLNA_FLAG_SENDER_PACED 1 << 31 // is the server setting the pace (i.e. RTP)?
-#define DLNA_FLAG_TIME_BASED_SEEK 1 << 30 // is the server supporting time based seeks?
-#define DLNA_FLAG_BYTE_BASED_SEEK 1 << 29 // or byte based seeking?
-#define DLNA_FLAG_PLAY_CONTAINER 1 << 28 // is it possible to play all contents of a container?
-#define DLNA_FLAG_S0_INCREASE 1 << 27 // is the beginning changing (time shift)?
-#define DLNA_FLAG_SN_INCREASE 1 << 26 // is the end changing (live-TV)?
-#define DLNA_FLAG_RTSP_PAUSE 1 << 25 // is pausing rtp streams permitted?
-#define DLNA_FLAG_STREAMING_TRANSFER 1 << 24 // is the transfer a stream (Audio/AV)?
-#define DLNA_FLAG_INTERACTIVE_TRANSFER 1 << 23 // is the transfer interactiv (printings)?
-#define DLNA_FLAG_BACKGROUND_TRANSFER 1 << 22 // is the tranfer done in background (downloaded)?
-#define DLNA_FLAG_CONNECTION_STALLING 1 << 21 // can the connection be paused on HTTP streams?
-#define DLNA_FLAG_VERSION_1_5 1 << 20 // does the server complies with DLNA V1.5
-#define DLNA_FLAG_CLEARTEXT_CONTENT 1 << 16 // (Link Protection) currently not used
-#define DLNA_FLAG_CLEARTEXT_BYTE_FULL_SEEK 1 << 15 // (Link Protection) currently not used
-#define DLNA_FLAG_CLEARTEXT_LIMITED_SEEK 1 << 14 // (Link Protection) currently not used
+#define DLNA_FLAG_SENDER_PACED 1 << 31 ///< is the server setting the pace (i.e. RTP)?
+#define DLNA_FLAG_TIME_BASED_SEEK 1 << 30 ///< is the server supporting time based seeks?
+#define DLNA_FLAG_BYTE_BASED_SEEK 1 << 29 ///< or byte based seeking?
+#define DLNA_FLAG_PLAY_CONTAINER 1 << 28 ///< is it possible to play all contents of a container?
+#define DLNA_FLAG_S0_INCREASE 1 << 27 ///< is the beginning changing (time shift)?
+#define DLNA_FLAG_SN_INCREASE 1 << 26 ///< is the end changing (live-TV)?
+#define DLNA_FLAG_RTSP_PAUSE 1 << 25 ///< is pausing rtp streams permitted?
+#define DLNA_FLAG_STREAMING_TRANSFER 1 << 24 ///< is the transfer a stream (Audio/AV)?
+#define DLNA_FLAG_INTERACTIVE_TRANSFER 1 << 23 ///< is the transfer interactiv (printings)?
+#define DLNA_FLAG_BACKGROUND_TRANSFER 1 << 22 ///< is the tranfer done in background (downloaded)?
+#define DLNA_FLAG_CONNECTION_STALLING 1 << 21 ///< can the connection be paused on HTTP streams?
+#define DLNA_FLAG_VERSION_1_5 1 << 20 ///< does the server complies with DLNA V1.5
+#define DLNA_FLAG_CLEARTEXT_CONTENT 1 << 16 ///< (Link Protection) currently not used
+#define DLNA_FLAG_CLEARTEXT_BYTE_FULL_SEEK 1 << 15 ///< (Link Protection) currently not used
+#define DLNA_FLAG_CLEARTEXT_LIMITED_SEEK 1 << 14 ///< (Link Protection) currently not used
#define DLNA_FLAGS_PLUGIN_SUPPORT DLNA_FLAG_BYTE_BASED_SEEK | \
DLNA_FLAG_SN_INCREASE | \
@@ -703,29 +739,37 @@ enum UPnPWriteStatus {
* label field as it seams to be not needed.
*/
struct DLNAProfile {
- const char* ID;
- const char* mime;
+ const char* ID; ///< the DLNA profile ID
+ const char* mime; ///< the mime type of the resource
};
+/**
+ * The DLNA profile for a icon image
+ *
+ * This complies with the DLNA media format guidelines. It contains a valid
+ * mime type, the resolution of the image and the corresponding bit depth
+ */
struct DLNAIconProfile {
- const char* mime;
- unsigned short width;
- unsigned short height;
- unsigned char bitDepth;
+ const char* mime; ///< the mime type of the image
+ unsigned short width; ///< image width in pixel
+ unsigned short height; ///< image height in pixel
+ unsigned char bitDepth; ///< bit depth in bits per pixel
};
/* Images */
/* Audio */
-extern DLNAProfile DLNA_PROFILE_MPEG1_L3; // MP3
+extern DLNAProfile DLNA_PROFILE_MPEG1_L3; ///< DLNA MP3 Profile
/* Video */
-extern DLNAProfile DLNA_PROFILE_MPEG_TS_SD_EU; // This is the profile for DVB-TV
-extern DLNAProfile DLNA_PROFILE_AVC_TS_HD_EU; // This is the profile for DVB-TV
+extern DLNAProfile DLNA_PROFILE_MPEG_TS_SD_EU; ///< DLNA Profile for DVB Television broadcasts
+extern DLNAProfile DLNA_PROFILE_AVC_TS_HD_EU; ///< DLNA Profile for HD DVB Television broadcasts
+extern DLNAProfile DLNA_PROFILE_MPEG_TS_SD_EU_ISO; ///< DLNA Profile for DVB Television broadcasts without timestamp
+extern DLNAProfile DLNA_PROFILE_AVC_TS_HD_EU_ISO; ///< DLNA Profile for HD DVB Television broadcasts without timestamp
/* Icons */
-extern DLNAIconProfile DLNA_ICON_JPEG_SM_24;
-extern DLNAIconProfile DLNA_ICON_JPEG_LRG_24;
-extern DLNAIconProfile DLNA_ICON_PNG_SM_24A;
-extern DLNAIconProfile DLNA_ICON_PNG_LRG_24A;
+extern DLNAIconProfile DLNA_ICON_JPEG_SM_24; ///< DLNA icon profile of small jpeg images
+extern DLNAIconProfile DLNA_ICON_JPEG_LRG_24; ///< DLNA icon profile of large jpeg images
+extern DLNAIconProfile DLNA_ICON_PNG_SM_24A; ///< DLNA icon profile of small png images
+extern DLNAIconProfile DLNA_ICON_PNG_LRG_24A; ///< DLNA icon profile of large png images
/****************************************************
*
diff --git a/database/database.cpp b/database/database.cpp
index b3d11b2..e47dcbf 100644
--- a/database/database.cpp
+++ b/database/database.cpp
@@ -46,9 +46,7 @@ int cSQLiteDatabase::exec(const char* Statement){
return -1;
}
this->mRows = new cRows;
-#ifdef SQLITE_PRINT_STATEMENTS
- MESSAGE("SQLite: %s", Statement);
-#endif
+ MESSAGE(VERBOSE_SQL_STATEMENTS,"SQLite: %s", Statement);
if(sqlite3_exec(this->mDatabase, Statement, cSQLiteDatabase::getResultRow, (cSQLiteDatabase*)this, &Error)!=SQLITE_OK){
ERROR("Database error: %s", Error);
ERROR("Statement was: %s", Statement);
@@ -143,13 +141,12 @@ bool cRow::fetchColumn(cString* Column, cString* Value){
return ret;
}
+
bool cRow::fetchColumn(char** Column, char** Value){
if(currentCol>=this->ColCount){
return false;
}
- #ifdef SQLITE_PRINT_FETCHES
- MESSAGE("Fetching column %s='%s' (%d/%d)", this->Columns[currentCol], this->Values[currentCol], currentCol+1, this->ColCount);
- #endif
+ MESSAGE(VERBOSE_SQL_FETCHES,"Fetching column %s='%s' (%d/%d)", this->Columns[currentCol], this->Values[currentCol], currentCol+1, this->ColCount);
*Column = strdup0(this->Columns[currentCol]);
if(this->Values[currentCol]){
*Value = strcasecmp(this->Values[currentCol],"NULL")?strdup(this->Values[currentCol]):NULL;
@@ -169,7 +166,7 @@ int cSQLiteDatabase::initialize(){
sqlite3_close(this->mDatabase);
return -1;
}
- MESSAGE("Database file %s opened.", *File);
+ MESSAGE(VERBOSE_SDK,"Database file %s opened.", *File);
if(this->initializeTables()){
ERROR("Error while creating tables");
return -1;
@@ -191,17 +188,19 @@ void cSQLiteDatabase::startTransaction(){
}
}
this->execStatement("BEGIN TRANSACTION");
- MESSAGE("Start new transaction");
+ MESSAGE(VERBOSE_SQL,"Start new transaction");
this->mActiveTransaction = true;
}
void cSQLiteDatabase::commitTransaction(){
this->execStatement("COMMIT TRANSACTION");
+ MESSAGE(VERBOSE_SQL,"Commited transaction");
this->mActiveTransaction = false;
}
void cSQLiteDatabase::rollbackTransaction(){
this->execStatement("ROLLBACK TRANSACTION");
+ MESSAGE(VERBOSE_SQL,"Rolled back transaction");
this->mActiveTransaction = false;
}
diff --git a/database/database.h b/database/database.h
index 041772e..5bb595f 100644
--- a/database/database.h
+++ b/database/database.h
@@ -12,8 +12,6 @@
#include <vdr/tools.h>
#include "../common.h"
-#define SQLITE_PRINT_STATEMENTS
-#define SQLITE_PRINT_FETCHES
#define SQLITE_CASCADE_DELETES
#define PK_OBJECTS TOSTRING(1)
@@ -144,7 +142,7 @@
"FOR EACH ROW BEGIN "\
"SELECT CASE "\
"WHEN ("\
- "((SELECT " SQLITE_COL_OBJECTID " FROM " TableA " "\
+ "((SELECT " SQLITE_COL_OBJECTID " FROM " SQLITE_TABLE_OBJECTS " "\
"WHERE " SQLITE_COL_OBJECTID "=NEW." SQLITE_COL_OBJECTID " "\
"AND " SQLITE_COL_CLASS " LIKE '" Class "%%') IS NULL)"\
") THEN "\
@@ -238,11 +236,11 @@
#define SQLITE_DELETE_PARENT_TRIGGER SQLITE_DELETE_REFERENCE_TRIGGER(SQLITE_TABLE_OBJECTS, SQLITE_COL_PARENTID)
#endif
- /**********************************************\
- * *
- * Primary keys *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Primary keys *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_PRIMARY_KEYS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_PRIMARY_KEYS \
@@ -274,11 +272,11 @@
"UPDATE " SQLITE_TABLE_PRIMARY_KEYS " SET Key=Key+1 WHERE KeyID=" PK_OBJECTS "; "\
"END;"
- /**********************************************\
- * *
- * System settings *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* System settings *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_SYSTEM "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_SYSTEM " "\
@@ -294,11 +292,11 @@
"WHEN ((SELECT Key FROM " SQLITE_TABLE_SYSTEM " WHERE Key=NEW.Key) IS NULL) "\
"BEGIN INSERT INTO " SQLITE_TABLE_SYSTEM " (Key) VALUES (NEW.Key); END;"
- /**********************************************\
- * *
- * Fast item finder *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Fast item finder *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_ITEMFINDER "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_ITEMFINDER " "\
@@ -310,11 +308,11 @@
#define SQLITE_TRIGGER_D_OBJECTS_ITEMFINDER SQLITE_DELETE_TRIGGER(SQLITE_TABLE_OBJECTS,\
SQLITE_TABLE_ITEMFINDER)
- /**********************************************\
- * *
- * Objects *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Objects *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_OBJECTS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_OBJECTS \
@@ -369,11 +367,11 @@
SQLITE_COL_PARENTID " must uniquely be -1') "\
"END; END;"
- /**********************************************\
- * *
- * Items *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Items *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_ITEMS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_ITEMS \
@@ -403,11 +401,11 @@
#define SQLITE_TRIGGER_D_ITEMS_ITEMS SQLITE_DELETE_REFERENCE_TRIGGER(SQLITE_TABLE_ITEMS, SQLITE_COL_REFERENCEID)
- /**********************************************\
- * *
- * Containers *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Containers *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_CONTAINER "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_CONTAINERS \
@@ -429,11 +427,11 @@
SQLITE_TABLE_CONTAINERS,\
UPNP_CLASS_CONTAINER)
- /**********************************************\
- * *
- * Video items *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Video items *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_VIDEOITEMS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_VIDEOITEMS \
@@ -461,11 +459,11 @@
SQLITE_TABLE_VIDEOITEMS, \
UPNP_CLASS_VIDEO)
- /**********************************************\
- * *
- * Audio items *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Audio items *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_AUDIOITEMS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_AUDIOITEMS \
@@ -488,11 +486,11 @@
SQLITE_TABLE_AUDIOITEMS, \
UPNP_CLASS_AUDIO)
- /**********************************************\
- * *
- * Image items *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Image items *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_IMAGEITEMS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_IMAGEITEMS \
@@ -517,11 +515,11 @@
SQLITE_TABLE_IMAGEITEMS, \
UPNP_CLASS_IMAGE)
- /**********************************************\
- * *
- * Video broadcasts *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Video broadcasts *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_VIDEOBROADCASTS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_VIDEOBROADCASTS \
@@ -543,11 +541,11 @@
SQLITE_TABLE_VIDEOBROADCASTS,\
UPNP_CLASS_VIDEOBC)
- /**********************************************\
- * *
- * Audio broadcasts *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Audio broadcasts *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_AUDIOBROADCASTS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_AUDIOBROADCASTS \
@@ -570,11 +568,11 @@
SQLITE_TABLE_AUDIOBROADCASTS,\
UPNP_CLASS_AUDIOBC)
- /**********************************************\
- * *
- * Movies *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Movies *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_MOVIES "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_MOVIES \
@@ -598,11 +596,11 @@
SQLITE_TABLE_MOVIES,\
UPNP_CLASS_MOVIE)
- /**********************************************\
- * *
- * Photos *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Photos *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_PHOTOS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_PHOTOS \
@@ -621,11 +619,11 @@
SQLITE_TABLE_PHOTOS,\
UPNP_CLASS_PHOTO)
- /**********************************************\
- * *
- * Albums *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Albums *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_ALBUMS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_ALBUMS \
@@ -651,11 +649,11 @@
SQLITE_TABLE_ALBUMS,\
UPNP_CLASS_ALBUM)
- /**********************************************\
- * *
- * Playlists *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Playlists *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_PLAYLISTS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_PLAYLISTS \
@@ -683,11 +681,11 @@
SQLITE_TABLE_PLAYLISTS,\
UPNP_CLASS_PLAYLISTCONT)
- /**********************************************\
- * *
- * Search classes *
- * *
- \**********************************************/
+/**********************************************\
+* *
+* Search classes *
+* *
+\**********************************************/
#define SQLITE_CREATE_TABLE_SEARCHCLASS "CREATE TABLE IF NOT EXISTS "\
SQLITE_TABLE_SEARCHCLASS \
@@ -798,6 +796,13 @@
class cSQLiteDatabase;
+/**
+ * Result row of a SQL SELECT request
+ *
+ * This is a single row of a {\c SQL SELECT} request.
+ *
+ * @see cRows
+ */
class cRow : public cListObject {
friend class cSQLiteDatabase;
private:
@@ -808,11 +813,50 @@ private:
cRow();
public:
virtual ~cRow();
+ /**
+ * Number of columns in this row
+ *
+ * @return the number of rows
+ */
int Count(){ return this->ColCount; }
- bool fetchColumn(cString* Column, cString* Value);
- bool fetchColumn(char** Column, char** Value);
+ /**
+ * Fetches a Column
+ *
+ * This will fetch a column of this row and stores the name of the column
+ * in the first parameter and the value in the second parameter.
+ *
+ * @return returns
+ * - \bc true, if more columns to come
+ * - \bc false, if the column is its last in this row.
+ */
+ bool fetchColumn(
+ cString* Column, /**< The name of the current column */
+ cString* Value /**< The value of the current value */
+ );
+
+ /**
+ * Fetches a Column
+ *
+ * This will fetch a column of this row and stores the name of the column
+ * in the first parameter and the value in the second parameter.
+ *
+ * @return returns
+ * - \bc true, if more columns to come
+ * - \bc false, if the column is its last in this row.
+ */
+ bool fetchColumn(
+ char** Column, /**< The name of the current column */
+ char** Value /**< The value of the current column */
+ );
};
+/**
+ * Result rows of a SQL SELECT request
+ *
+ * Contains the rows of a SQL SELECT request
+ *
+ * @see cRow
+ */
class cRows : public cList<cRow> {
friend class cSQLiteDatabase;
private:
@@ -820,9 +864,29 @@ private:
cRows();
public:
virtual ~cRows();
- bool fetchRow(cRow** Row);
+ /**
+ * Fetches a row from the result
+ *
+ * This fetches the next row in the resultset by storing the contents of
+ * that row in the first parameter.
+ *
+ * @return returns
+ * - \bc true, if more rows to come
+ * - \bc false, if the row is its last in this resultset.
+ */
+ bool fetchRow(
+ cRow** Row /**< The Pointer of the row */
+ );
};
+/**
+ * SQLite Database
+ *
+ * This is a wrapper class for a SQLite3 database connection
+ * It supports simple execution functions.
+ *
+ * On requests with returns any results a instance of \c cRows* will be created.
+ */
class cSQLiteDatabase {
friend class cStatement;
private:
@@ -839,17 +903,122 @@ private:
static int getResultRow(void* DB, int NumCols, char** Values, char** ColNames);
int exec(const char* Statement);
public:
- static const char* sprintf(const char* Format, ...);
+ /**
+ * Prints a SQLite escaped text
+ *
+ * Returns a formated text with special characters to escape SQLite special
+ * characters like "'". Additionally to the well known characters of \a printf
+ * the following are allowed:
+ *
+ * - \bc q, like s, escapes single quotes in strings
+ * - \bc Q, like q, surrounds the escaped string with additional
+ * single quotes
+ * - \bc z, frees the string after reading and coping it
+ *
+ * @see sprintf()
+ * @return the formated string
+ */
+ static const char* sprintf(
+ const char* Format, /**< The format string */
+ ... /**< optional properties which will be passed to sprintf */
+ );
virtual ~cSQLiteDatabase();
+ /**
+ * Returns the instance of the database
+ *
+ * Returns the instance of the SQLite database. This will create a single
+ * instance of none is existing on the very first call. A subsequent call
+ * will return the same instance.
+ *
+ * @return the database instance
+ */
static cSQLiteDatabase* getInstance();
+ /**
+ * Row count of the last result
+ *
+ * Returns the row count of the last {\c SQL SELECT} request.
+ *
+ * @see cRows
+ * @return the result row count
+ */
int getResultCount() const { return this->mRows->Count(); }
+ /**
+ * The last \c INSERT RowID
+ *
+ * Returns the primary key of the last inserted row.
+ * This will only work if there are no successive calls to the database.
+ *
+ * @return the last insert RowID
+ */
long getLastInsertRowID() const;
+ /**
+ * Result set of the last request
+ *
+ * Returns the result rows of the SQL SELECT request.
+ * This might be NULL, if the last statement was not a SELECT.
+ *
+ * @see cRows
+ * @return the result rows of the last \c SELECT statement.
+ */
cRows* getResultRows() const { return this->mRows; }
- int execStatement(const char* Statement, ...);
+ /**
+ * Executes a SQL statement
+ *
+ * This will execute the statement in the first parameter. If it is followed
+ * by any optional parameters it will be formated using the same function as
+ * in \c cSQLiteDatabase::sprintf().
+ *
+ * \sa cSQLiteDatabase::sprintf().
+ *
+ * @return returns an integer representing
+ * - \bc -1, in case of an error
+ * - \bc 0, when the statement was executed successfuly
+ */
+ int execStatement(
+ const char* Statement , /**< Statement to be executed */
+ ... /**< optional parameters passed to the format string */
+ );
+ /**
+ * Starts a transaction
+ *
+ * This starts a new transaction and commits or rolls back a previous.
+ *
+ * @see cSQLiteDatabase::setAutoCommit
+ * @see cSQLiteDatabase::commitTransaction
+ */
void startTransaction();
+ /**
+ * Commits a transaction
+ *
+ * This function commits the transaction and writes all changes to the
+ * database
+ *
+ * @see cSQLiteDatabase::startTransaction
+ */
void commitTransaction();
+ /**
+ * Performs a rollback on a transaction
+ *
+ * This function performs a rollback. No changes will be made to the
+ * database
+ *
+ * @see cSQLiteDatabase::rollbackTransaction
+ */
void rollbackTransaction();
- void setAutoCommit(bool Commit=true){ this->mAutoCommit = Commit; }
+ /**
+ * Set the commit behavior
+ *
+ * This function sets the auto commit behavior on new transactions with
+ * \sa cSQLiteDatabase::startTransaction.
+ *
+ * - \bc true, commits the last transaction before starting a
+ * new one
+ * - \bc false, performs a rollback on the old transaction
+ *
+ */
+ void setAutoCommit(
+ bool Commit=true /**< Switches the behavior of auto commit */
+ ){ this->mAutoCommit = Commit; }
};
#endif /* _DATABASE_H */ \ No newline at end of file
diff --git a/database/metadata.cpp b/database/metadata.cpp
index 3316522..91c512f 100644
--- a/database/metadata.cpp
+++ b/database/metadata.cpp
@@ -44,7 +44,7 @@ cMediaDatabase::~cMediaDatabase(){
}
bool cMediaDatabase::init(){
- MESSAGE("Initializing...");
+ MESSAGE(VERBOSE_SDK,"Initializing...");
if(this->prepareDatabase()){
ERROR("Initializing of database failed.");
return false;
@@ -122,7 +122,7 @@ cUPnPObjectID cMediaDatabase::getNextObjectID(){
int cMediaDatabase::addFastFind(cUPnPClassObject* Object, const char* FastFind){
if(!Object || !FastFind){
- MESSAGE("Invalid fast find parameters");
+ MESSAGE(VERBOSE_OBJECTS,"Invalid fast find parameters");
return -1;
}
@@ -140,7 +140,7 @@ int cMediaDatabase::addFastFind(cUPnPClassObject* Object, const char* FastFind){
cUPnPClassObject* cMediaDatabase::getObjectByFastFind(const char* FastFind){
if(!FastFind) return NULL;
- MESSAGE("Try to find Object with identifier %s", FastFind);
+ MESSAGE(VERBOSE_OBJECTS,"Try to find Object with identifier %s", FastFind);
cString Column, Value;
if(this->mDatabase->execStatement("SELECT %s FROM %s WHERE %s=%Q",
SQLITE_COL_OBJECTID,
@@ -166,14 +166,14 @@ cUPnPClassObject* cMediaDatabase::getObjectByFastFind(const char* FastFind){
}
cUPnPClassObject* cMediaDatabase::getObjectByID(cUPnPObjectID ID){
- MESSAGE("Try to find Object with ID '%s'", *ID);
+ MESSAGE(VERBOSE_OBJECTS, "Try to find Object with ID '%s'", *ID);
cUPnPClassObject* Object;
if((Object = this->mObjects->Get((unsigned int)ID))){
- MESSAGE("Found cached object with ID '%s'", *ID);
+ MESSAGE(VERBOSE_OBJECTS, "Found cached object with ID '%s'", *ID);
}
else if((Object = this->mFactory->getObject(ID))){
//this->cacheObject(Object);
- MESSAGE("Found object with ID '%s' in database", *ID);
+ MESSAGE(VERBOSE_OBJECTS, "Found object with ID '%s' in database", *ID);
}
else {
ERROR("No object with such ID '%s'", *ID);
@@ -184,14 +184,14 @@ cUPnPClassObject* cMediaDatabase::getObjectByID(cUPnPObjectID ID){
void cMediaDatabase::cacheObject(cUPnPClassObject* Object){
if(this->mObjects->Get((unsigned int)Object->getID())==NULL){
- MESSAGE("Added %s to cache.", *Object->getID());
+ MESSAGE(VERBOSE_OBJECTS ,"Added %s to cache.", *Object->getID());
this->mObjects->Add(Object, (unsigned int)Object->getID());
}
}
int cMediaDatabase::prepareDatabase(){
if(this->getObjectByID(0)==NULL){
- MESSAGE("Creating database structure");
+ MESSAGE(VERBOSE_SDK, "Creating database structure");
cUPnPClassContainer* Root = (cUPnPClassContainer*)this->mFactory->createObject(UPNP_CLASS_CONTAINER, _(PLUGIN_SHORT_NAME));
Root->setID(0);
if(this->mFactory->saveObject(Root)) return -1;
@@ -248,7 +248,7 @@ int cMediaDatabase::prepareDatabase(){
}
int cMediaDatabase::loadChannels(){
- MESSAGE("Loading channels");
+ MESSAGE(VERBOSE_LIVE_TV ,"Loading channels");
cUPnPClassContainer* TV = (cUPnPClassContainer*)this->getObjectByID(3);
if(TV){
bool noResource = false;
@@ -262,7 +262,7 @@ int cMediaDatabase::loadChannels(){
bool inList = false;
tChannelID ChannelID = Channel->GetChannelID();
- MESSAGE("Determine if the channel %s is already listed", *ChannelID.ToString());
+ MESSAGE(VERBOSE_LIVE_TV, "Determine if the channel %s is already listed", *ChannelID.ToString());
cUPnPClassVideoBroadcast* ChannelItem = NULL;
ChannelItem = (cUPnPClassVideoBroadcast*)this->getObjectByFastFind(ChannelID.ToString());
@@ -271,18 +271,18 @@ int cMediaDatabase::loadChannels(){
if(!inList){
if(Channel->GroupSep()){
- MESSAGE("Skipping group '%s'", Channel->Name());
+ MESSAGE(VERBOSE_LIVE_TV, "Skipping group '%s'", Channel->Name());
// Skip channel groups
// Channel groups may be supported theoretically. However, DLNA states that a tuner needs
// a consecutive list of channels. A simple work-around may be a virtual tuner for each group.
}
else if(Channel->Vpid()==0){
// TODO: add radio support
- MESSAGE("Skipping radio '%s'", Channel->Name());
+ MESSAGE(VERBOSE_LIVE_TV, "Skipping radio '%s'", Channel->Name());
}
else {
noResource = false;
- MESSAGE("Adding channel '%s' ID:%s", Channel->Name(), *ChannelID.ToString());
+ MESSAGE(VERBOSE_LIVE_TV, "Adding channel '%s' ID:%s", Channel->Name(), *ChannelID.ToString());
ChannelItem = (cUPnPClassVideoBroadcast*)this->mFactory->createObject(UPNP_CLASS_VIDEOBC, Channel->Name());
ChannelItem->setChannelName(Channel->Name());
ChannelItem->setChannelNr(Channel->Number());
@@ -301,7 +301,7 @@ int cMediaDatabase::loadChannels(){
this->mFactory->deleteObject(ChannelItem);
return -1;
}
- MESSAGE("Successfuly added channel");
+ MESSAGE(VERBOSE_LIVE_TV, "Successfuly added channel");
}
else {
// Delete temporarily created object with no resource
@@ -310,7 +310,7 @@ int cMediaDatabase::loadChannels(){
}
}
else {
- MESSAGE("Skipping %s, already in database", Channel->Name());
+ MESSAGE(VERBOSE_LIVE_TV, "Skipping %s, already in database", Channel->Name());
}
}
}
@@ -318,7 +318,7 @@ int cMediaDatabase::loadChannels(){
}
int cMediaDatabase::loadRecordings(){
- MESSAGE("Loading recordings");
+ MESSAGE(VERBOSE_RECORDS, "Loading recordings");
cUPnPClassContainer* Records = (cUPnPClassContainer*)this->getObjectByID(4);
if(Records){
bool noResource = false;
@@ -330,7 +330,7 @@ int cMediaDatabase::loadRecordings(){
// Iterating the records
bool inList = false;
- MESSAGE("Determine if the channel %s is already listed", Recording->FileName());
+ MESSAGE(VERBOSE_RECORDS, "Determine if the channel %s is already listed", Recording->FileName());
cUPnPClassMovie *MovieItem = NULL;
@@ -342,7 +342,7 @@ int cMediaDatabase::loadRecordings(){
noResource = false;
const cRecordingInfo* RecInfo = Recording->Info();
- MESSAGE("Adding movie '%s' File name:%s", RecInfo->Title(), Recording->FileName());
+ MESSAGE(VERBOSE_RECORDS, "Adding movie '%s' File name:%s", RecInfo->Title(), Recording->FileName());
MovieItem = (cUPnPClassMovie*)this->mFactory->createObject(UPNP_CLASS_MOVIE, RecInfo->Title());
MovieItem->setDescription(RecInfo->ShortText());
@@ -366,7 +366,7 @@ int cMediaDatabase::loadRecordings(){
this->mFactory->deleteObject(MovieItem);
return -1;
}
- MESSAGE("Successfuly added movie");
+ MESSAGE(VERBOSE_RECORDS, "Successfuly added movie");
}
else {
// Delete temporarily created object with no resource
@@ -374,7 +374,7 @@ int cMediaDatabase::loadRecordings(){
}
}
else {
- MESSAGE("Skipping %s, already in Database", Recording->FileName());
+ MESSAGE(VERBOSE_RECORDS, "Skipping %s, already in Database", Recording->FileName());
}
}
}
@@ -386,7 +386,7 @@ void cMediaDatabase::Action(){
while(this->Running()){
if(cSchedules::Modified() >= LastEPGUpdate){
- MESSAGE("Schedule changed. Updating...");
+ MESSAGE(VERBOSE_EPG_UPDATES, "Schedule changed. Updating...");
updateChannelEPG();
LastEPGUpdate = cSchedules::Modified();
}
@@ -399,19 +399,19 @@ void cMediaDatabase::updateChannelEPG(){
cUPnPClassContainer* TV = (cUPnPClassContainer*)this->getObjectByID(3);
if(TV){
// Iterating channels
- MESSAGE("Getting schedule...");
+ MESSAGE(VERBOSE_EPG_UPDATES, "Getting schedule...");
cSchedulesLock SchedulesLock;
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
cList<cUPnPClassObject>* List = TV->getObjectList();
- MESSAGE("TV folder has %d items", List->Count());
+ MESSAGE(VERBOSE_EPG_UPDATES, "TV folder has %d items", List->Count());
for(cUPnPClassVideoBroadcast* ChannelItem = (cUPnPClassVideoBroadcast*)List->First();
ChannelItem;
ChannelItem = (cUPnPClassVideoBroadcast*)List->Next(ChannelItem)
){
- MESSAGE("Find channel by number %d", ChannelItem->getChannelNr());
+ MESSAGE(VERBOSE_EPG_UPDATES, "Find channel by number %d", ChannelItem->getChannelNr());
cChannel* Channel = Channels.GetByNumber(ChannelItem->getChannelNr());
- MESSAGE("Found channel with ID %s", *Channel->GetChannelID().ToString());
+ MESSAGE(VERBOSE_EPG_UPDATES, "Found channel with ID %s", *Channel->GetChannelID().ToString());
const cSchedule* Schedule = Schedules->GetSchedule(Channel);
const cEvent* Event = Schedule?Schedule->GetPresentEvent():NULL;
@@ -420,10 +420,10 @@ void cMediaDatabase::updateChannelEPG(){
time_t LastEPGChange = Event->StartTime();
time_t LastObjectChange = ChannelItem->modified();
- MESSAGE("Last event start: %s", ctime(&LastEPGChange));
- MESSAGE("Last object modification: %s", ctime(&LastObjectChange));
+ MESSAGE(VERBOSE_EPG_UPDATES, "Last event start: %s", ctime(&LastEPGChange));
+ MESSAGE(VERBOSE_EPG_UPDATES, "Last object modification: %s", ctime(&LastObjectChange));
if(LastEPGChange >= LastObjectChange){
- MESSAGE("Updating details");
+ MESSAGE(VERBOSE_EPG_UPDATES, "Updating details");
if(Event){
ChannelItem->setTitle(Event->Title()?Event->Title():Channel->Name());
@@ -439,11 +439,11 @@ void cMediaDatabase::updateChannelEPG(){
this->mFactory->saveObject(ChannelItem);
}
else {
- MESSAGE("Channel did not change");
+ MESSAGE(VERBOSE_EPG_UPDATES, "Channel did not change");
}
}
else {
- MESSAGE("No EPG data");
+ MESSAGE(VERBOSE_EPG_UPDATES, "No EPG data");
ChannelItem->setTitle(Channel->Name());
ChannelItem->setLongDescription(NULL);
ChannelItem->setDescription(NULL);
@@ -452,19 +452,27 @@ void cMediaDatabase::updateChannelEPG(){
}
}
-int cMediaDatabase::browse(cUPnPResultSet** Results, const char* ID, bool BrowseMetadata, const char* Filter, unsigned int Offset, unsigned int Count, const char* SortCriteria){
+int cMediaDatabase::browse(
+ OUT cUPnPResultSet** Results,
+ IN const char* ID,
+ IN bool BrowseMetadata,
+ IN const char* Filter,
+ IN unsigned int Offset,
+ IN unsigned int Count,
+ IN const char* SortCriteria
+){
*Results = new cUPnPResultSet;
(*Results)->mNumberReturned = 0;
(*Results)->mTotalMatches = 0;
(*Results)->mResult = NULL;
- MESSAGE("===== Browsing =====");
- MESSAGE("ID: %s", ID);
- MESSAGE("Browse %s", BrowseMetadata?"metadata":"children");
- MESSAGE("Filter: %s", Filter);
- MESSAGE("Offset: %d", Offset);
- MESSAGE("Count: %d", Count);
- MESSAGE("Sort: %s", SortCriteria);
+ MESSAGE(VERBOSE_DIDL, "===== Browsing =====");
+ MESSAGE(VERBOSE_DIDL, "ID: %s", ID);
+ MESSAGE(VERBOSE_DIDL, "Browse %s", BrowseMetadata?"metadata":"children");
+ MESSAGE(VERBOSE_DIDL, "Filter: %s", Filter);
+ MESSAGE(VERBOSE_DIDL, "Offset: %d", Offset);
+ MESSAGE(VERBOSE_DIDL, "Count: %d", Count);
+ MESSAGE(VERBOSE_DIDL, "Sort: %s", SortCriteria);
cUPnPObjectID ObjectID = atoi(ID);
@@ -498,7 +506,7 @@ int cMediaDatabase::browse(cUPnPResultSet** Results, const char* ID, bool Browse
if(SortCriterias){
for(cSortCrit* SortBy = SortCriterias->First(); SortBy ; SortBy = SortCriterias->Next(SortBy)){
- MESSAGE("Sorting by %s %s", SortBy->Property, SortBy->SortDescending?"ascending":"descending");
+ MESSAGE(VERBOSE_DIDL, "Sorting by %s %s", SortBy->Property, SortBy->SortDescending?"ascending":"descending");
Children->SortBy(SortBy->Property, SortBy->SortDescending);
}
}
@@ -507,7 +515,7 @@ int cMediaDatabase::browse(cUPnPResultSet** Results, const char* ID, bool Browse
if(Count==0) Count = Container->getChildCount();
while(Offset-- && (Child = Children->Next(Child))){}
for(; Count && Child ; Child = Children->Next(Child), Count--){
- MESSAGE("Appending %s to didl", Child->getTitle());
+ MESSAGE(VERBOSE_DIDL, "Appending %s to didl", Child->getTitle());
ixmlNode_appendChild(Root, Child->createDIDLFragment(DIDLDoc, FilterList));
(*Results)->mNumberReturned++;
}
diff --git a/database/metadata.h b/database/metadata.h
index 6e3732c..4868231 100644
--- a/database/metadata.h
+++ b/database/metadata.h
@@ -16,17 +16,25 @@
#include "object.h"
#include "resources.h"
+/**
+ * The result set of a request
+ *
+ * This contains the results of a previous \e Browse or \e Search request.
+ */
struct cUPnPResultSet {
- int mNumberReturned;
- int mTotalMatches;
- const char* mResult;
-};
-
-struct cSearchCriteria {
- const char* Property;
- bool Descending;
+ int mNumberReturned; ///< The number of returned matches
+ int mTotalMatches; ///< The total amount of matches
+ const char* mResult; ///< The DIDL-Lite fragment
};
+/**
+ * The media database
+ *
+ * This class is the global object manager. It holds every object in a local cache.
+ * Only this class is allowed to create new objects.
+ *
+ * @see cUPnPClassObject
+ */
class cMediaDatabase : public cThread {
friend class cUPnPServer;
friend class cUPnPObjectMediator;
@@ -47,15 +55,130 @@ private:
void updateSystemID();
virtual void Action();
public:
+ /**
+ * Returns the SystemUpdateID
+ *
+ * This returns the \e SystemUpdateID. This changes whenever anything changed
+ * within the content directory. This value will be sent through the UPnP
+ * network every 2 seconds.
+ *
+ * @return the SystemUpdateID
+ */
unsigned int getSystemUpdateID();
+ /**
+ * Returns a CSV list with ContainerUpdateIDs
+ *
+ * This list contains an unordered list of ordered pairs of ContainerID and
+ * its ContainerUpdateID. It contains only recent changes which are not yet
+ * beeing evented. This means that evented updates will be removed from list.
+ *
+ * @return CSV list of ContainerUpdateIDs
+ */
const char* getContainerUpdateIDs();
+ /**
+ * Constructor
+ *
+ * This creates an instance of the media database.
+ */
cMediaDatabase();
virtual ~cMediaDatabase();
- int addFastFind(cUPnPClassObject* Object, const char* FastFind);
- cUPnPClassObject* getObjectByFastFind(const char* FastFind);
- cUPnPClassObject* getObjectByID(cUPnPObjectID ID);
- int browse(OUT cUPnPResultSet** Results, IN const char* ID, IN bool BrowseMetadata, IN const char* Filter = "*", IN unsigned int Offset = 0, IN unsigned int Count = 0, IN const char* SortCriteria = "");
- int search(OUT cUPnPResultSet** Results, IN const char* ID, IN const char* Search, IN const char* Filter = "*", IN unsigned int Offset = 0, IN unsigned int Count = 0, IN const char* SortCriteria = "");
+ /**
+ * Add a Fastfind
+ *
+ * This creates a \e Fastfind entry. It is a string which can be used to
+ * relocate a objectID. Usually this is a file name or another ID with which
+ * the related object can be found.
+ *
+ * @return returns
+ * - \bc -1, if the creation was successful
+ * - \bc 0, otherwise
+ */
+ int addFastFind(
+ cUPnPClassObject* Object, ///< the object, which should be registered
+ const char* FastFind ///< the string with which the object shall be
+ ///< relocated
+ );
+ /**
+ * Finds a object by Fastfind
+ *
+ * This returns the object via the \e Fastfind string. The object must be
+ * previosly registered via \c cMediaDatabase::addFastFind().
+ *
+ * It tries to find the object in the internal object cache. If this fails,
+ * the object will be loaded from the database.
+ *
+ * @see cMediaDatabase::addFastFind
+ * @return The object associated with FastFind
+ */
+ cUPnPClassObject* getObjectByFastFind(
+ const char* FastFind ///< the string with which the object shall be
+ ///< relocated
+ );
+ /**
+ * Finds a object by its ObjectID
+ *
+ * This returns the object via its \e ObjectID.
+ *
+ * It tries to find the object in the internal object cache. If this fails,
+ * the object will be loaded from the database.
+ *
+ * @return The object associated with FastFind
+ */
+ cUPnPClassObject* getObjectByID(
+ cUPnPObjectID ID ///< The ObjectID of the requested object
+ );
+ /**
+ * Performs a browse on the database
+ *
+ * This performs a browse request on the database and returns a structure
+ * containing the matching count and DIDL-Lite fragement which is sent to
+ * the control point.
+ *
+ * @return returns an integer representing one of the following:
+ * - \bc UPNP_CDS_E_INVALID_SORT_CRITERIA, when the sort criteria is malformed
+ * - \bc UPNP_CDS_E_CANT_PROCESS_REQUEST, when there is an internal error while
+ * processing the request
+ * - \bc UPNP_CDS_E_NO_SUCH_OBJECT, when the requested ObjectID does not exist
+ * - \bc UPNP_SOAP_E_ACTION_FAILED, when the action failed due any reasons
+ * - \bc UPNP_E_SUCCESS, if the request was successful
+ */
+ int browse(
+ OUT cUPnPResultSet** Results, ///< the result of the request
+ IN const char* ID, ///< the objectID of the request
+ IN bool BrowseMetadata, ///< \b true to browse metadata, \b false otherwise
+ IN const char* Filter = "*", ///< the filter applied to the returned metadata
+ IN unsigned int Offset = 0, ///< the starting offset
+ IN unsigned int Count = 0, ///< maximum count returned
+ IN const char* SortCriteria = "" ///< sorts the results before returning them
+ );
+ /**
+ * Performs a search on the database
+ *
+ * This performs a search request on the database and returns a structure
+ * containing the matching count and DIDL-Lite fragement which is sent to
+ * the control point.
+ *
+ * @note
+ * The submitted ID must be a ContainerID. Searches are performed only
+ * in this container.
+ *
+ * @return returns an integer representing one of the following:
+ * - \bc UPNP_CDS_E_INVALID_SORT_CRITERIA, when the sort criteria is malformed
+ * - \bc UPNP_CDS_E_CANT_PROCESS_REQUEST, when there is an internal error while
+ * processing the request
+ * - \bc UPNP_CDS_E_NO_SUCH_OBJECT, when the requested ObjectID does not exist
+ * - \bc UPNP_SOAP_E_ACTION_FAILED, when the action failed due any reasons
+ * - \bc UPNP_E_SUCCESS, if the request was successful
+ */
+ int search(
+ OUT cUPnPResultSet** Results, ///< the result of the request
+ IN const char* ID, ///< the ContainerID
+ IN const char* Search, ///< the search string
+ IN const char* Filter = "*", ///< the filter applied to the returned metadata
+ IN unsigned int Offset = 0, ///< the starting offset
+ IN unsigned int Count = 0, ///< maximum count returned
+ IN const char* SortCriteria = "" ///< sorts the results before returning them
+ );
};
#endif /* _METADATA_H */
diff --git a/database/object.cpp b/database/object.cpp
index 94d9415..f6875f9 100644
--- a/database/object.cpp
+++ b/database/object.cpp
@@ -150,7 +150,7 @@ void cUPnPClassObject::clearSortCriteria(){
}
int cUPnPClassObject::setID(cUPnPObjectID ID){
- MESSAGE("Set ID from %s to %s", *this->getID(),*ID);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Set ID from %s to %s", *this->getID(),*ID);
if((int)ID < 0){
ERROR("Invalid object ID '%s'",*ID);
return -1;
@@ -162,7 +162,7 @@ int cUPnPClassObject::setID(cUPnPObjectID ID){
int cUPnPClassObject::setParent(cUPnPClassContainer* Parent){
if(Parent==NULL){
- MESSAGE("Object '%s' elected as root object", *this->getID());
+ MESSAGE(VERBOSE_MODIFICATIONS, "Object '%s' elected as root object", *this->getID());
}
// unregister from old parent
if(this->mParent && Parent != this->mParent){
@@ -316,7 +316,7 @@ bool cUPnPClassObject::setProperty(const char* Property, const char* Value){
}
int cUPnPClassObject::addResource(cUPnPResource* Resource){
- MESSAGE("Adding resource #%d", Resource->getID());
+ MESSAGE(VERBOSE_MODIFICATIONS, "Adding resource #%d", Resource->getID());
if(!Resource){
ERROR("No resource");
return -1;
@@ -374,10 +374,10 @@ bool cUPnPClassItem::setProperty(const char* Property, const char* Value){
IXML_Node* cUPnPClassItem::createDIDLFragment(IXML_Document* Document, cStringList* Filter){
this->mDIDLFragment = Document;
- MESSAGE("==(%s)= %s =====", *this->getID(), this->getTitle());
- MESSAGE("ParentID: %s", *this->getParentID());
- MESSAGE("Restricted: %s", this->isRestricted()?"1":"0");
- MESSAGE("Class: %s", this->getClass());
+ MESSAGE(VERBOSE_DIDL, "==(%s)= %s =====", *this->getID(), this->getTitle());
+ MESSAGE(VERBOSE_DIDL, "ParentID: %s", *this->getParentID());
+ MESSAGE(VERBOSE_DIDL, "Restricted: %s", this->isRestricted()?"1":"0");
+ MESSAGE(VERBOSE_DIDL, "Class: %s", this->getClass());
IXML_Node* Didl = ixmlNode_getFirstChild((IXML_Node*) this->mDIDLFragment);
@@ -404,13 +404,13 @@ IXML_Node* cUPnPClassItem::createDIDLFragment(IXML_Document* Document, cStringLi
// if(Filter==NULL || Filter->Find(UPNP_PROP_REFERENCEID)) ixmlAddProperty(this->mDIDLFragment, eItem, UPNP_PROP_REFERENCEID, *this->getReferenceID());
for(cUPnPResource* Resource = this->getResources()->First(); Resource; Resource = this->getResources()->Next(Resource)){
- MESSAGE("Resource: %s", Resource->getResource());
- MESSAGE("Protocolinfo: %s", Resource->getProtocolInfo());
+ MESSAGE(VERBOSE_DIDL, "Resource: %s", Resource->getResource());
+ MESSAGE(VERBOSE_DIDL, "Protocolinfo: %s", Resource->getProtocolInfo());
cString URLBase = cString::sprintf("http://%s:%d", UpnpGetServerIpAddress(), UpnpGetServerPort());
cString ResourceURL = cString::sprintf("%s%s/get?resId=%d", *URLBase, UPNP_DIR_SHARES, Resource->getID());
- MESSAGE("Resource-URI: %s", *ResourceURL);
+ MESSAGE(VERBOSE_DIDL, "Resource-URI: %s", *ResourceURL);
IXML_Element* eRes = ixmlDocument_createElement(this->mDIDLFragment, UPNP_PROP_RESOURCE);
IXML_Node* Res = ixmlDocument_createTextNode(this->mDIDLFragment, *ResourceURL);
@@ -451,10 +451,10 @@ cUPnPClassContainer::~cUPnPClassContainer(){
IXML_Node* cUPnPClassContainer::createDIDLFragment(IXML_Document* Document, cStringList* Filter){
this->mDIDLFragment = Document;
- MESSAGE("===(%s)= %s =====", *this->getID(), this->getTitle());
- MESSAGE("ParentID: %s", *this->getParentID());
- MESSAGE("Restricted: %s", this->isRestricted()?"1":"0");
- MESSAGE("Class: %s", this->getClass());
+ MESSAGE(VERBOSE_DIDL, "===(%s)= %s =====", *this->getID(), this->getTitle());
+ MESSAGE(VERBOSE_DIDL, "ParentID: %s", *this->getParentID());
+ MESSAGE(VERBOSE_DIDL, "Restricted: %s", this->isRestricted()?"1":"0");
+ MESSAGE(VERBOSE_DIDL, "Class: %s", this->getClass());
IXML_Node* Didl = ixmlNode_getFirstChild((IXML_Node*) this->mDIDLFragment);
IXML_Element* eItem = ixmlDocument_createElement(this->mDIDLFragment, "container");
@@ -521,7 +521,7 @@ bool cUPnPClassContainer::getProperty(const char* Property, char** Value) const
}
void cUPnPClassContainer::addObject(cUPnPClassObject* Object){
- MESSAGE("Adding object (ID:%s) to container (ID:%s)", *Object->getID(), *this->getID());
+ MESSAGE(VERBOSE_MODIFICATIONS, "Adding object (ID:%s) to container (ID:%s)", *Object->getID(), *this->getID());
Object->setParent(this);
this->mChildren->Add(Object);
this->mChildrenID->Add(Object, (unsigned int)Object->getID());
@@ -531,11 +531,11 @@ void cUPnPClassContainer::removeObject(cUPnPClassObject* Object){
this->mChildrenID->Del(Object, (unsigned int)Object->getID());
this->mChildren->Del(Object, false);
Object->mParent = NULL;
- MESSAGE("Removed object (ID:%s) from container (ID:%s)", *Object->getID(), *this->getID());
+ MESSAGE(VERBOSE_MODIFICATIONS, "Removed object (ID:%s) from container (ID:%s)", *Object->getID(), *this->getID());
}
cUPnPClassObject* cUPnPClassContainer::getObject(cUPnPObjectID ID) const {
- MESSAGE("Getting object (ID:%s)", *ID);
+ MESSAGE(VERBOSE_METADATA, "Getting object (ID:%s)", *ID);
if((int)ID < 0){
ERROR("Invalid object ID");
return NULL;
@@ -1011,9 +1011,9 @@ void cUPnPObjectFactory::registerMediator(const char* UPnPClass, cMediatorInterf
ERROR("Mediator is undefined");
return;
}
- MESSAGE("Registering mediator for class '%s'", UPnPClass);
+ MESSAGE(VERBOSE_SDK, "Registering mediator for class '%s'", UPnPClass);
this->mMediators[UPnPClass] = Mediator;
- MESSAGE("Now %d mediators registered", this->mMediators.size());
+ MESSAGE(VERBOSE_SDK, "Now %d mediators registered", this->mMediators.size());
return;
}
@@ -1027,10 +1027,10 @@ void cUPnPObjectFactory::unregisterMediator(const char* UPnPClass, bool freeMedi
ERROR("No such mediator found for class '%s'", UPnPClass);
return;
}
- MESSAGE("Unregistering mediator for class '%s'", UPnPClass);
+ MESSAGE(VERBOSE_SDK, "Unregistering mediator for class '%s'", UPnPClass);
this->mMediators.erase(MediatorIterator);
if(freeMediator) delete MediatorIterator->second;
- MESSAGE("Now %d mediators registered", this->mMediators.size());
+ MESSAGE(VERBOSE_SDK, "Now %d mediators registered", this->mMediators.size());
return;
}
@@ -1057,7 +1057,7 @@ cMediatorInterface* cUPnPObjectFactory::findMediatorByID(cUPnPObjectID ID){
cMediatorInterface* cUPnPObjectFactory::findMediatorByClass(const char* Class){
if(!Class){ ERROR("No class specified"); return NULL; }
- MESSAGE("Searching for mediator '%s' in %d mediators", Class, this->mMediators.size());
+ MESSAGE(VERBOSE_SQL, "Searching for mediator '%s' in %d mediators", Class, this->mMediators.size());
tMediatorMap::iterator MediatorIterator = this->mMediators.find(Class);
if(MediatorIterator==this->mMediators.end()){
ERROR("No matching mediator for class '%s'",Class);
@@ -1212,7 +1212,7 @@ cUPnPClassObject* cUPnPObjectMediator::getObject(cUPnPObjectID){ WARNING("Gettin
cUPnPClassObject* cUPnPObjectMediator::createObject(const char*, bool){ WARNING("Getting instance of class 'Object' forbidden"); return NULL; }
int cUPnPObjectMediator::objectToDatabase(cUPnPClassObject* Object){
- MESSAGE("Updating object #%s", *Object->getID());
+ MESSAGE(VERBOSE_MODIFICATIONS, "Updating object #%s", *Object->getID());
cString Format = "UPDATE %s SET %s WHERE %s='%s'";
//cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);";
cString Set=NULL;
@@ -1261,41 +1261,47 @@ int cUPnPObjectMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectI
}
while(Row->fetchColumn(&Column, &Value)){
if(!strcasecmp(Column, SQLITE_COL_OBJECTID)){
- if(Object->setID(atoi(Value))){
+ if(!*Value || Object->setID(atoi(Value))){
ERROR("Error while setting object ID");
return -1;
}
this->mMediaDatabase->cacheObject(Object);
}
else if(!strcasecmp(Column, SQLITE_COL_PARENTID)){
- cUPnPObjectID RefID = atoi(Value);
- cUPnPClassContainer* ParentObject;
- if(RefID == -1){
- ParentObject = NULL;
+ if(*Value){
+ cUPnPObjectID RefID = atoi(Value);
+ cUPnPClassContainer* ParentObject;
+ if(RefID == -1){
+ ParentObject = NULL;
+ }
+ else {
+ ParentObject = (cUPnPClassContainer*)this->mMediaDatabase->getObjectByID(RefID);
+ if(!ParentObject){
+ ERROR("No such parent with ID '%s' found.",*RefID);
+ return -1;
+ }
+ }
+ Object->setParent(ParentObject);
}
else {
- ParentObject = (cUPnPClassContainer*)this->mMediaDatabase->getObjectByID(RefID);
- if(!ParentObject){
- ERROR("No such parent with ID '%s' found.",*RefID);
- return -1;
- }
+ ERROR("Invalid parent ID");
+ return -1;
}
- Object->setParent(ParentObject);
}
else if(!strcasecmp(Column, SQLITE_COL_CLASS)){
- if(Object->setClass(Value)){
+ if(!*Value || Object->setClass(Value)){
ERROR("Error while setting class");
return -1;
}
}
else if(!strcasecmp(Column, SQLITE_COL_TITLE)){
- if(Object->setTitle(Value)){
+ if(!*Value || Object->setTitle(Value)){
ERROR("Error while setting title");
return -1;
}
}
else if(!strcasecmp(Column, SQLITE_COL_RESTRICTED)){
- if(Object->setRestricted(atoi(Value)==1?true:false)){
+ if(!*Value || Object->setRestricted(atoi(Value)==1?true:false)){
ERROR("Error while setting restriction");
return -1;
}
@@ -1307,7 +1313,7 @@ int cUPnPObjectMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectI
}
}
else if(!strcasecmp(Column, SQLITE_COL_WRITESTATUS)){
- if(Object->setWriteStatus(atoi(Value))){
+ if(*Value && Object->setWriteStatus(atoi(Value))){
ERROR("Error while setting write status");
return -1;
}
@@ -1369,7 +1375,7 @@ int cUPnPItemMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID
}
Rows = this->mDatabase->getResultRows();
if(!Rows->fetchRow(&Row)){
- MESSAGE("No item properties found");
+ MESSAGE(VERBOSE_SQL, "No item properties found");
return 0;
}
while(Row->fetchColumn(&Column, &Value)){
@@ -1393,14 +1399,14 @@ int cUPnPItemMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID
}
cUPnPClassItem* cUPnPItemMediator::getObject(cUPnPObjectID ID){
- MESSAGE("Getting Item with ID '%s'",*ID);
+ MESSAGE(VERBOSE_METADATA, "Getting Item with ID '%s'",*ID);
cUPnPClassItem* Object = new cUPnPClassItem;
if(this->databaseToObject(Object, ID)) return NULL;
return Object;
}
cUPnPClassItem* cUPnPItemMediator::createObject(const char* Title, bool Restricted){
- MESSAGE("Creating Item '%s'",Title);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Creating Item '%s'",Title);
cUPnPClassItem* Object = new cUPnPClassItem;
if(this->initializeObject(Object, UPNP_CLASS_ITEM, Title, Restricted)) return NULL;
return Object;
@@ -1468,7 +1474,7 @@ int cUPnPContainerMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObje
}
Rows = this->mDatabase->getResultRows();
if(!Rows->fetchRow(&Row)){
- MESSAGE("No item properties found");
+ MESSAGE(VERBOSE_SQL, "No item properties found");
return 0;
}
while(Row->fetchColumn(&Column, &Value)){
@@ -1532,14 +1538,14 @@ int cUPnPContainerMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObje
}
cUPnPClassContainer* cUPnPContainerMediator::createObject(const char* Title, bool Restricted){
- MESSAGE("Creating Container '%s'",Title);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Creating Container '%s'",Title);
cUPnPClassContainer* Object = new cUPnPClassContainer;
if(this->initializeObject(Object, UPNP_CLASS_CONTAINER, Title, Restricted)) return NULL;
return Object;
}
cUPnPClassContainer* cUPnPContainerMediator::getObject(cUPnPObjectID ID){
- MESSAGE("Getting Container with ID '%s'",*ID);
+ MESSAGE(VERBOSE_METADATA, "Getting Container with ID '%s'",*ID);
cUPnPClassContainer* Object = new cUPnPClassContainer;
if(this->databaseToObject(Object, ID)) return NULL;
return Object;
@@ -1555,14 +1561,14 @@ cUPnPVideoItemMediator::cUPnPVideoItemMediator(cMediaDatabase* MediaDatabase) :
cUPnPItemMediator(MediaDatabase){}
cUPnPClassVideoItem* cUPnPVideoItemMediator::createObject(const char* Title, bool Restricted){
- MESSAGE("Creating Video item '%s'",Title);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Creating Video item '%s'",Title);
cUPnPClassVideoItem* Object = new cUPnPClassVideoItem;
if(this->initializeObject(Object, UPNP_CLASS_VIDEO, Title, Restricted)) return NULL;
return Object;
}
cUPnPClassVideoItem* cUPnPVideoItemMediator::getObject(cUPnPObjectID ID){
- MESSAGE("Getting Video item with ID '%s'",*ID);
+ MESSAGE(VERBOSE_METADATA, "Getting Video item with ID '%s'",*ID);
cUPnPClassVideoItem* Object = new cUPnPClassVideoItem;
if(this->databaseToObject(Object, ID)) return NULL;
return Object;
@@ -1618,7 +1624,7 @@ int cUPnPVideoItemMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObje
}
Rows = this->mDatabase->getResultRows();
if(!Rows->fetchRow(&Row)){
- MESSAGE("No item properties found");
+ MESSAGE(VERBOSE_SQL, "No item properties found");
return 0;
}
while(Row->fetchColumn(&Column, &Value)){
@@ -1696,14 +1702,14 @@ cUPnPVideoBroadcastMediator::cUPnPVideoBroadcastMediator(cMediaDatabase* MediaDa
cUPnPVideoItemMediator(MediaDatabase){}
cUPnPClassVideoBroadcast* cUPnPVideoBroadcastMediator::createObject(const char* Title, bool Restricted){
- MESSAGE("Creating Video broadcast '%s'",Title);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Creating Video broadcast '%s'",Title);
cUPnPClassVideoBroadcast* Object = new cUPnPClassVideoBroadcast;
if(this->initializeObject(Object, UPNP_CLASS_VIDEOBC, Title, Restricted)) return NULL;
return Object;
}
cUPnPClassVideoBroadcast* cUPnPVideoBroadcastMediator::getObject(cUPnPObjectID ID){
- MESSAGE("Getting Video broadcast with ID '%s'",*ID);
+ MESSAGE(VERBOSE_METADATA, "Getting Video broadcast with ID '%s'",*ID);
cUPnPClassVideoBroadcast* Object = new cUPnPClassVideoBroadcast;
if(this->databaseToObject(Object, ID)) return NULL;
return Object;
@@ -1753,7 +1759,7 @@ int cUPnPVideoBroadcastMediator::databaseToObject(cUPnPClassObject* Object, cUPn
}
Rows = this->mDatabase->getResultRows();
if(!Rows->fetchRow(&Row)){
- MESSAGE("No item properties found");
+ MESSAGE(VERBOSE_SQL, "No item properties found");
return 0;
}
while(Row->fetchColumn(&Column, &Value)){
@@ -1795,14 +1801,14 @@ cUPnPMovieMediator::cUPnPMovieMediator(cMediaDatabase* MediaDatabase) :
cUPnPVideoItemMediator(MediaDatabase){}
cUPnPClassMovie* cUPnPMovieMediator::createObject(const char* Title, bool Restricted){
- MESSAGE("Creating movie '%s'",Title);
+ MESSAGE(VERBOSE_MODIFICATIONS, "Creating movie '%s'",Title);
cUPnPClassMovie* Object = new cUPnPClassMovie;
if(this->initializeObject(Object, UPNP_CLASS_MOVIE, Title, Restricted)) return NULL;
return Object;
}
cUPnPClassMovie* cUPnPMovieMediator::getObject(cUPnPObjectID ID){
- MESSAGE("Getting movie with ID '%s'",*ID);
+ MESSAGE(VERBOSE_METADATA, "Getting movie with ID '%s'",*ID);
cUPnPClassMovie* Object = new cUPnPClassMovie;
if(this->databaseToObject(Object, ID)) return NULL;
return Object;
@@ -1850,7 +1856,7 @@ int cUPnPMovieMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID
}
Rows = this->mDatabase->getResultRows();
if(!Rows->fetchRow(&Row)){
- MESSAGE("No item properties found");
+ MESSAGE(VERBOSE_SQL, "No item properties found");
return 0;
}
while(Row->fetchColumn(&Column, &Value)){
diff --git a/database/object.h b/database/object.h
index a38098d..245a617 100644
--- a/database/object.h
+++ b/database/object.h
@@ -17,37 +17,112 @@
#include <vector>
#include <upnp/ixml.h>
+/**
+ * UPnP Object ID
+ *
+ * This is a UPnP Object ID representation.
+ */
struct cUPnPObjectID {
- int _ID;
+ int _ID; ///< The UPnP Object ID
+ /**
+ * Constructor
+ *
+ * Creates invalid ID
+ */
cUPnPObjectID():_ID(-1){}
- cUPnPObjectID(long ID){ _ID = (int)ID; }
- cUPnPObjectID(int ID){ _ID = ID; }
- cUPnPObjectID &operator=(long ID){ _ID = ID; return *this; }
- cUPnPObjectID &operator=(int ID){ _ID = ID; return *this; }
- cUPnPObjectID &operator=(const cUPnPObjectID& ID){ if(this != &ID){ _ID = ID._ID; } return *this; }
+ /**
+ * Constructor
+ *
+ * Creates from long integer
+ */
+ cUPnPObjectID(
+ long ID ///< new ID
+ ){ _ID = (int)ID; }
+ /**
+ * Constructor
+ *
+ * Creates from integer
+ */
+ cUPnPObjectID(
+ int ID ///< new ID
+ ){ _ID = ID; }
+ /** Set the object ID */
+ cUPnPObjectID &operator=(
+ long ID ///< new ID
+ ){ _ID = ID; return *this; }
+ /** @overload cUPnPObjectID &operator=(long ID) */
+ cUPnPObjectID &operator=(
+ int ID ///< new ID
+ ){ _ID = ID; return *this; }
+ /** @overload cUPnPObjectID &operator=(long ID) */
+ cUPnPObjectID &operator=(
+ const cUPnPObjectID& ID ///< new ID
+ ){ if(this != &ID){ _ID = ID._ID; } return *this; }
+ /** Pre increment the ID */
cUPnPObjectID &operator++(){ _ID++; return *this; }
+ /** Post increment the ID */
cUPnPObjectID operator++(int){ cUPnPObjectID old = *this; _ID++; return old; }
+ /** Post decrement the ID */
cUPnPObjectID operator--(int){ cUPnPObjectID old = *this; _ID--; return old; }
+ /** Pre decrement the ID */
cUPnPObjectID &operator--(){ _ID--; return *this; }
- bool operator!=(long ID){ return _ID != ID; }
- bool operator==(long ID){ return _ID == ID; }
- bool operator!=(int ID){ return _ID != ID; }
- bool operator==(int ID){ return _ID == ID; }
- bool operator!=(const cUPnPObjectID& ID){ return *this == ID; }
- bool operator==(const cUPnPObjectID& ID){ return *this == ID; }
+ /** Not equal */
+ bool operator!=(
+ long ID ///< compare with this ID
+ ){ return _ID != ID; }
+ /** Equal */
+ bool operator==(
+ long ID ///< compare with this ID
+ ){ return _ID == ID; }
+ /** @overload bool operator!=(long ID) */
+ bool operator!=(
+ int ID ///< compare with this ID
+ ){ return _ID != ID; }
+ /** @overload bool operator==(long ID) */
+ bool operator==(
+ int ID ///< compare with this ID
+ ){ return _ID == ID; }
+ /** @overload bool operator!=(long ID) */
+ bool operator!=(
+ const cUPnPObjectID& ID ///< compare with this ID
+ ){ return *this == ID; }
+ /** @overload bool operator==(long ID) */
+ bool operator==(
+ const cUPnPObjectID& ID ///< compare with this ID
+ ){ return *this == ID; }
+ /** Casts to unsigned int */
operator unsigned int(){ return (unsigned int)_ID; }
+ /** Casts to int */
operator int(){ return _ID; }
+ /** Casts to long */
operator long(){ return (long)_ID; }
+ /** Casts to string */
const char* operator*(){ char* buf; return asprintf(&buf,"%d",_ID)?buf:NULL; }
};
+/**
+ * Structure of a UPnP Class
+ *
+ * This represents a UPnP Class
+ */
struct cClass {
- cString ID;
- bool includeDerived;
+ cString ID; ///< The upnp class ID
+ bool includeDerived; ///< flag, to indicate if derived classes are allowed
+ /**
+ * Compares two classes
+ *
+ * @param cmp the other class to compare with
+ */
bool operator==(const cClass &cmp){ return (!strcasecmp(cmp.ID,ID) && includeDerived==cmp.includeDerived); }
+ /*! @copydoc operator==(const cClass &cmp) */
bool operator!=(const cClass &cmp){ return !(*this==cmp); }
};
+/**
+ * UPnP Resource
+ *
+ * This contains all details about a resource
+ */
class cUPnPResource : public cListObject {
friend class cUPnPResourceMediator;
friend class cUPnPResources;
@@ -70,21 +145,137 @@ private:
unsigned int mColorDepth;
cUPnPResource();
public:
+ /**
+ * Get resource ID
+ *
+ * Gets the resource ID
+ *
+ * @return the resource ID
+ */
unsigned int getID() const { return this->mResourceID; }
+ /**
+ * Get the resources
+ *
+ * Returns the resource. This is in most cases the file name or resource locator
+ * where to find the resource
+ *
+ * @return the resource string
+ */
const char* getResource() const { return this->mResource; }
+ /**
+ * Get the duration
+ *
+ * Returns a date time string with the duration of the resource
+ *
+ * @return the duration of the resource
+ */
const char* getDuration() const { return this->mDuration; }
+ /**
+ * Get the resolution
+ *
+ * Returns the resolution string with the pattern width x height in pixels
+ *
+ * @return the resolution of the resource
+ */
const char* getResolution() const { return this->mResolution; }
+ /**
+ * Get the protocol info
+ *
+ * This returns the protocol info field of a resource
+ *
+ * @return the protocol info string
+ */
const char* getProtocolInfo() const { return this->mProtocolInfo; }
+ /**
+ * Get the content type
+ *
+ * Returns the mime type of the content of the resource
+ *
+ * @return the content type of the resource
+ */
const char* getContentType() const { return this->mContentType; }
+ /**
+ * Get the import URI
+ *
+ * This returns the import URI where the resource was located before importing
+ * it
+ *
+ * @return the import URI
+ */
const char* getImportURI() const { return this->mImportURI; }
+ /**
+ * Get the resource type
+ *
+ * This returns the resource type of the resource.
+ *
+ * @return the resource type
+ */
int getResourceType() const { return this->mResourceType; }
+ /**
+ * Get the size
+ *
+ * Returns the resource size or -1 if its unknown
+ *
+ * @return the resource size or -1 if unknown
+ */
unsigned long getSize() const { return this->mSize; }
+ /**
+ * Get the file size
+ *
+ * Returns the file size in bytes of the resource or 0 if its unknown or a
+ * stream
+ *
+ * @return the file size
+ */
off64_t getFileSize() const;
+ /**
+ * Get the last modification
+ *
+ * This returns the timestamp of the last modification to the file. If it
+ * is a stream, then its the current time.
+ *
+ * @return the timestamp with the last modification of the resource
+ */
time_t getLastModification() const;
+ /**
+ * Get the bitrate
+ *
+ * This returns the bitrate of the resource in bits per second.
+ *
+ * @return the bitrate of the resource
+ */
unsigned int getBitrate() const { return this->mBitrate; }
+ /**
+ * Get the sample frequency
+ *
+ * Returns the sample frequency in samples per second.
+ *
+ * @return the sample frequency of the resource
+ */
unsigned int getSampleFrequency() const { return this->mSampleFrequency; }
+ /**
+ * Get the bits per sample
+ *
+ * Returns the number of bits per sample.
+ *
+ * @return the bits per sample of the resource
+ */
unsigned int getBitsPerSample() const { return this->mBitsPerSample; }
+ /**
+ * Get number of audio channels
+ *
+ * Returns the number of audio channels of the audio stream in a video
+ *
+ * @return the number of audio channels
+ */
unsigned int getNrAudioChannels() const { return this->mNrAudioChannels; }
+ /**
+ * Get the color depth
+ *
+ * Returns the color depth of the resource in pits per pixel
+ *
+ * @return the color depth of the resource
+ */
unsigned int getColorDepth() const { return this->mColorDepth; }
};
@@ -93,79 +284,398 @@ class cUPnPObjectMediator;
class cUPnPContainerMediator;
class cUPnPClassContainer;
+/**
+ * List of UPnP Objects
+ *
+ * This is a cList of UPnP Objects
+ * The list can be sorted by using a specific property
+ */
class cUPnPObjects : public cList<cUPnPClassObject> {
public:
cUPnPObjects();
virtual ~cUPnPObjects();
- void SortBy(const char* Property, bool Descending = false);
+ /**
+ * Sorts the list
+ *
+ * This sorts the list by a specific property and a certain direction
+ */
+ void SortBy(
+ const char* Property, ///< the property used for sorting
+ bool Descending = false ///< the direction of the sort
+ );
};
+/**
+ * The UPnP class Object
+ *
+ * This is a UPnP class Object representation with all its properties.
+ */
class cUPnPClassObject : public cListObject {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPClassContainer;
private:
cUPnPObjectID mLastID;
- bool mDeleted; // is this Objected marked as deleted
+ bool mDeleted; // is this Objected marked as deleted, NOT used yet.
protected:
- time_t mLastModified;
- cUPnPObjectID mID; // The object ID
- cUPnPClassObject* mParent;
- cString mClass; // Class (Who am I?)
- cString mTitle; // Object title
- cString mCreator; // Creator of this object
- bool mRestricted; // Ability of changing metadata?
- int mWriteStatus; // Ability of writing resources?
- cList<cUPnPResource>* mResources; // The resources of this object
- cHash<cUPnPResource>* mResourcesID;
- IXML_Document* mDIDLFragment;
- cString mSortCriteria;
- bool mSortDescending;
+ time_t mLastModified; ///< The last modification of this property
+ cUPnPObjectID mID; ///< The object ID
+ cUPnPClassObject* mParent; ///< The parent object
+ cString mClass; ///< Class (Who am I?)
+ cString mTitle; ///< Object title
+ cString mCreator; ///< Creator of this object
+ bool mRestricted; ///< Ability of changing metadata?
+ int mWriteStatus; ///< Ability of writing resources?
+ cList<cUPnPResource>* mResources; ///< The resources of this object
+ cHash<cUPnPResource>* mResourcesID; ///< The resources of this object as hashmap
+ IXML_Document* mDIDLFragment; ///< The DIDL fragment of the object
+ cString mSortCriteria; ///< The sort criteria to sort with
+ bool mSortDescending; ///< The direction of the sort
cUPnPClassObject();
+ /**
+ * Set the Object ID
+ *
+ * This is only allowed by mediators and the media database. Manually editing
+ * the object ID may result in unpredictable behavior.
+ *
+ * @param ID the ObjectID of this object
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ */
int setID(cUPnPObjectID ID);
+ /**
+ * Set the Parent Object
+ *
+ * This is only allowed by mediators and the media database. Manually editing
+ * the parent may result in unpredictable behavior.
+ *
+ * @param Parent the parent of this object
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ */
int setParent(cUPnPClassContainer* Parent);
+ /**
+ * Set the object class
+ *
+ * This is only allowed by mediators and the media database. Manually editing
+ * the object class may result in unpredictable behavior.
+ *
+ * @param Class the class of this object
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ */
int setClass(const char* Class);
+ /**
+ * Set the modification time
+ *
+ * This sets the last modification time to the current timestamp. This is
+ * used to indicate when the object was updated the last time.
+ */
void setModified(void){ this->mLastModified = time(NULL); }
public:
+ /**
+ * Last modified
+ *
+ * Returns when the object was modified the last time.
+ *
+ * @return last modification timestamp
+ */
time_t modified() const { return this->mLastModified; }
virtual ~cUPnPClassObject();
+ /**
+ * Compares a object
+ *
+ * This compares a given object with this object
+ * It uses the SortCriteria to compare them.
+ *
+ * @return returns
+ * - \bc >0, if the object comes after this one
+ * - \bc 0, if the objects have the same property
+ * - \bc <0, if the object comes before this one
+ * @param ListObject the object to compare with
+ */
virtual int Compare(const cListObject& ListObject) const;
+ /**
+ * Get the properties of the object
+ *
+ * This returns a property list with all the properties which can be obtained
+ * or set with \c getProperty or \c setProperty.
+ *
+ * @return a stringlist with the properties
+ */
virtual cStringList* getPropertyList();
+ /**
+ * Gets a property
+ *
+ * Returns the value of a specified property. The value is converted into a
+ * string.
+ *
+ * @return returns
+ * - \bc true, if the property exists
+ * - \bc false, otherwise
+ * @param Property the property which should be returned
+ * @param Value the value of that property
+ */
virtual bool getProperty(const char* Property, char** Value) const ;
+ /**
+ * Sets a property
+ *
+ * Sets the value of a specified property. The value is converted from string
+ * into the propper data type
+ *
+ * @return returns
+ * - \bc true, if the property exists
+ * - \bc false, otherwise
+ * @param Property the property which should be set
+ * @param Value the value of that property
+ */
virtual bool setProperty(const char* Property, const char* Value);
+ /**
+ * Converts to container
+ *
+ * This will convert the object into a container if it is one. If not, it
+ * returns \bc NULL.
+ *
+ * @return returns
+ * - \bc NULL, if it is not a container
+ * - a container representation of this object
+ */
virtual cUPnPClassContainer* getContainer(){ return NULL; }
+ /**
+ * Create the DIDL fragment
+ *
+ * This creates the DIDL-Lite fragment of the object. The DIDL is written to the
+ * specified \em IXML document. The details of the output can be controlled via
+ * the filter stringlist
+ *
+ * @return the DIDL fragment of the object
+ * @param Document the IXML document where to write the contents
+ * @param Filter the string list with the filter criteria
+ */
virtual IXML_Node* createDIDLFragment(IXML_Document* Document, cStringList* Filter) = 0;
+ /**
+ * Is this a container?
+ *
+ * Returns if this object is a container or not
+ *
+ * @return returns
+ * - \bc true, if it is a container
+ * - \bc false, otherwise
+ */
bool isContainer(){ return this->getContainer()==NULL?false:true; }
+ /**
+ * Set the sort criteria
+ *
+ * This sets a certain criteria which the object can be compared with.
+ *
+ * @param Property the property to sort after
+ * @param Descending sort the objects in descending order
+ */
void setSortCriteria(const char* Property, bool Descending = false);
+ /**
+ * Clears the sort criteria
+ *
+ * Clears the property of the sort criteria and sets the descending flag to
+ * false.
+ */
void clearSortCriteria();
/******* Setter *******/
+ /**
+ * Set the title
+ *
+ * This sets the title of the object. It is a required metadata information.
+ * It must not be \bc NULL or an empty string.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Title the title of the object
+ */
int setTitle(const char* Title);
+ /**
+ * Set the creator
+ *
+ * The creator of an object is primarily the creator or owner of the object
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Creator the creator of the object
+ */
int setCreator(const char* Creator);
+ /**
+ * Set the restriction
+ *
+ * This sets the restriction flag. If the object is restricted, no modifications
+ * to its metadata by the user are allowed.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Restricted \bc true, to disallow modification, \bc false to allow it
+ */
int setRestricted(bool Restricted);
+ /**
+ * Set the write status
+ *
+ * This sets the write status of a resource. With this indicator, you can set
+ * the modifiabilty of resources by a control point.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Status the write status
+ */
int setWriteStatus(int Status);
+ /**
+ * Set the resources
+ *
+ * This sets the list of resources of an object. The list usally contain a
+ * single resource. However, multiple resources a also very common.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Resources the resource list of this object
+ */
int setResources(cList<cUPnPResource>* Resources);
+ /**
+ * Add resource to list
+ *
+ * This adds the specified resource to the resource list of the object
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Resource the resource to be added
+ */
int addResource(cUPnPResource* Resource);
+ /**
+ * Remove resource from list
+ *
+ * This removes the specified resource from the resource list of the object
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Resource the resource to be removed
+ */
int removeResource(cUPnPResource* Resource);
/******* Getter *******/
+ /**
+ * Get the object ID
+ *
+ * This returns the object ID of the object.
+ *
+ * @return the object ID
+ */
cUPnPObjectID getID() const { return this->mID; }
+ /**
+ * Get the parent ID
+ *
+ * This returns the ID of the parent container object, associated with this object.
+ * It is \bc -1, if the object is the root object.
+ *
+ * @return the parent ID
+ */
cUPnPObjectID getParentID() const { return this->mParent?this->mParent->getID():cUPnPObjectID(-1); }
+ /**
+ * Get the parent object
+ *
+ * This returns the parent container object, associated with this object. It is
+ * \bc NULL, if the object is the root object.
+ *
+ * @return the parent object
+ */
cUPnPClassContainer* getParent() const { return (cUPnPClassContainer*)this->mParent; }
+ /**
+ * Get the title
+ *
+ * This returns the title of the object. This may be the title of an item or
+ * the folder name in case of a container.
+ *
+ * @return the title of the object
+ */
const char* getTitle() const { return this->mTitle; }
+ /**
+ * Get the object class
+ *
+ * This returns the object class of the object. The classes are defined by
+ * the UPnP Working Committee. However, custom classes which are derived from
+ * a standardized class are also possible.
+ *
+ * @return the class of the object
+ */
const char* getClass() const { return this->mClass; }
+ /**
+ * Get the creator
+ *
+ * This returns the creator of the object. Usually, this is the primary
+ * content creator or the owner of the object
+ *
+ * @return the creator of the object
+ */
const char* getCreator() const { return this->mCreator; }
+ /**
+ * Is the resource restricted?
+ *
+ * Returns \bc true, if the object is restricted or \bc false, otherwise.
+ * When the object is restricted, then modifications to the metadata of the
+ * object are disallowed.
+ *
+ * @return returns
+ * - \bc true, if the object is restricted
+ * - \bc false, otherwise
+ */
bool isRestricted() const { return this->mRestricted; }
+ /**
+ * Get write status
+ *
+ * This returns the write status of the object. It gives information, if the
+ * resource is modifiable.
+ *
+ * @return the write status
+ */
int getWriteStatus() const { return this->mWriteStatus; }
+ /**
+ * Get a resource by its ID
+ *
+ * Returns the resource with the specified resource ID.
+ *
+ * @return the resource by ID
+ * @param ResourceID the resource ID of the demanded resource
+ */
cUPnPResource* getResource(unsigned int ResourceID) const { return this->mResourcesID->Get(ResourceID); }
+ /**
+ * Get the resources
+ *
+ * This returns a list with resources associated with this object.
+ *
+ * @return the resources of this object
+ */
cList<cUPnPResource>* getResources() const { return this->mResources; }
};
+/**
+ * The UPnP class Item
+ *
+ * This is a UPnP class Item representation with all its properties.
+ */
class cUPnPClassItem : public cUPnPClassObject {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPItemMediator;
protected:
// cUPnPObjectID mReferenceID;
- cUPnPClassItem* mReference;
+ cUPnPClassItem* mReference; ///< The reference item
+ /**
+ * Constructor of an item
+ *
+ * This creates a new instance of an item
+ */
cUPnPClassItem();
public:
virtual ~cUPnPClassItem(){};
@@ -174,28 +684,78 @@ public:
virtual bool setProperty(const char* Property, const char* Value);
virtual bool getProperty(const char* Property, char** Value) const;
/******** Setter ********/
+ /**
+ * Set a reference item
+ *
+ * This sets a reference item. Its comparable with symlinks in *nix systems
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Reference the reference item
+ */
int setReference(cUPnPClassItem* Reference);
/******** Getter ********/
+ /**
+ * Get the referenced item
+ *
+ * This returns the referenced item of this item
+ *
+ * @return the referenced item
+ */
cUPnPClassItem* getReference() const { return this->mReference; }
+ /**
+ * Get the reference ID
+ *
+ * This returns the object ID of the referenced item or \b -1, if
+ * no reference exists.
+ *
+ * @return the reference ID
+ */
cUPnPObjectID getReferenceID() const { return this->mReference?this->mReference->getID():cUPnPObjectID(-1); }
};
typedef std::vector<cClass> tClassVector;
+/**
+ * The UPnP class Container
+ *
+ * This is a UPnP class Container representation with all its properties.
+ */
class cUPnPClassContainer : public cUPnPClassObject {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPContainerMediator;
protected:
- cString mContainerType;
- tClassVector mSearchClasses;
- tClassVector mCreateClasses;
- bool mSearchable;
- unsigned int mUpdateID;
- cUPnPObjects* mChildren;
- cHash<cUPnPClassObject>* mChildrenID;
+ cString mContainerType; ///< DLNA container type
+ tClassVector mSearchClasses; ///< Classes which are searchable
+ tClassVector mCreateClasses; ///< Classes which are creatable
+ bool mSearchable; ///< Is the Container searchable?
+ unsigned int mUpdateID; ///< The containerUpdateID
+ cUPnPObjects* mChildren; ///< List of children
+ cHash<cUPnPClassObject>* mChildrenID; ///< List of children as hash map
+ /**
+ * Update the container
+ *
+ * This performs an update, which acutally increases the containerUpdateID.
+ */
void update();
+ /**
+ * Sets the containerUpdateID
+ *
+ * This method should only be used when the containerUpdateID is loaded from
+ * the database.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param UID the containerUpdateID
+ */
int setUpdateID(unsigned int UID);
+ /**
+ * Constructor of a container
+ *
+ * This creates a new instance of a container
+ */
cUPnPClassContainer();
public:
virtual ~cUPnPClassContainer();
@@ -204,44 +764,231 @@ public:
virtual bool setProperty(const char* Property, const char* Value);
virtual bool getProperty(const char* Property, char** Value) const;
virtual cUPnPClassContainer* getContainer(){ return this; }
+ /**
+ * Add a child
+ *
+ * This adds the specified child to this container. The parent container of the
+ * child will be set to this container.
+ *
+ * @param Object the child to be added
+ */
void addObject(cUPnPClassObject* Object);
+ /**
+ * Remove a child
+ *
+ * This removes the specified child from the list of children. The child will
+ * also loose its parent container, so that there is no link between left.
+ *
+ * @param Object the child to be removed
+ */
void removeObject(cUPnPClassObject* Object);
+ /**
+ * Get a child by ID
+ *
+ * Returns the child, which is specified by the \c ObjectID.
+ *
+ * @return the child with the specified ID
+ * @param ID the \c ObjectID of the child
+ */
cUPnPClassObject* getObject(cUPnPObjectID ID) const;
+ /**
+ * Get the list of children
+ *
+ * This returns a list of the children of the container.
+ *
+ * @return the list of children
+ */
cUPnPObjects* getObjectList() const { return this->mChildren; }
+ /**
+ * Add a search class
+ *
+ * This adds a search class to the search classes vector
+ *
+ * @return returns
+ * - \bc 0, if adding was successful
+ * - \bc <0, otherwise
+ * @param SearchClass the new class to be added
+ */
int addSearchClass(cClass SearchClass);
+ /**
+ * Remove a search class
+ *
+ * This removes a search class from the search classes vector
+ *
+ * @return returns
+ * - \bc 0, if deleting was successful
+ * - \bc <0, otherwise
+ * @param SearchClass the class to be deleted
+ */
int delSearchClass(cClass SearchClass);
+ /**
+ * Add a create class
+ *
+ * This adds a create class to the create classes vector
+ *
+ * @return returns
+ * - \bc 0, if adding was successful
+ * - \bc <0, otherwise
+ * @param CreateClass the new class to be added
+ */
int addCreateClass(cClass CreateClass);
+ /**
+ * Remove a create class
+ *
+ * This removes a create class from the create classes vector
+ *
+ * @return returns
+ * - \bc 0, if deleting was successful
+ * - \bc <0, otherwise
+ * @param CreateClass the class to be deleted
+ */
int delCreateClass(cClass CreateClass);
/******** Setter ********/
+ /**
+ * Set the DLNA container type
+ *
+ * This sets the DLNA container type. It must be a valid container type value.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Type the DLNA container type
+ */
int setContainerType(const char* Type);
+ /**
+ * Sets the search classes
+ *
+ * This sets the search classes, which allows the user to search only for
+ * these classes in the current container and its children. If the vector
+ * is empty the search can return any match. If the additional flag \bc
+ * derived is set, then also any derived classes are matched.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param SearchClasses a vector container the allowed search classes
+ */
int setSearchClasses(std::vector<cClass> SearchClasses);
+ /**
+ * Sets the create classes
+ *
+ * This sets the create classes, which allows the user to create new objects
+ * in this container, if \em restricted is \bc false.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param CreateClasses a vector containing the create classes
+ */
int setCreateClasses(std::vector<cClass> CreateClasses);
+ /**
+ * Sets the searchable flag
+ *
+ * This sets the searchable flag, which allows or disallows search on this
+ * container.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Searchable \bc true, to enable or \bc false, to disable searching
+ */
int setSearchable(bool Searchable);
/******** Getter ********/
+ /**
+ * Get the DLNA container type
+ *
+ * This returns the DLNA container type. Currently there are only these possible
+ * values beside \bc NULL:
+ * - \bc TUNER_1_0
+ *
+ * @return the DLNA container type
+ */
const char* getContainerType() const { return this->mContainerType; }
+ /**
+ * Get the search classes
+ *
+ * This returns a vector container all possible search classes. This are classes,
+ * which can be used for searching in this container.
+ *
+ * @return a vector with all search classes
+ */
const std::vector<cClass>* getSearchClasses() const { return &(this->mSearchClasses); }
+ /**
+ * Get the create classes
+ *
+ * This returns a vector containing all possible create classes. This are classes,
+ * which can be created in this container. For instance a TV container can only create
+ * items of the class VideoBroadcast. The vector is empty when creation of new items
+ * by the user is not allowed.
+ *
+ * @return a vector with create classes
+ */
const std::vector<cClass>* getCreateClasses() const { return &(this->mCreateClasses); }
+ /**
+ * Is this container searchable
+ *
+ * This returns \bc true, if the container can be search via \em Search or
+ * \bc false, otherwise.
+ *
+ * @return returns
+ * - \bc true, if the container is searchable
+ * - \bc false, otherwise
+ */
bool isSearchable() const { return this->mSearchable; }
+ /**
+ * Get the number of children
+ *
+ * This returns the total number of children of this container
+ *
+ * @return the number of childen
+ */
unsigned int getChildCount() const { return this->mChildren->Count(); }
+ /**
+ * Get the containerUpdateID
+ *
+ * This returns the containerUpdateID
+ *
+ * @return the containerUpdateID of this container
+ */
unsigned int getUpdateID() const { return this->mUpdateID; }
+ /**
+ * Has the container been updated?
+ *
+ * This returns \bc true, if the container was recently updated or
+ * \bc false, otherwise
+ *
+ * @return returns
+ * - \bc true, if the container was updated
+ * - \bc false, otherwise
+ */
bool isUpdated();
};
+/**
+ * The UPnP class VideoItem
+ *
+ * This is a UPnP class VideoItem representation with all its properties.
+ */
class cUPnPClassVideoItem : public cUPnPClassItem {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPVideoItemMediator;
protected:
- cString mGenre; // Genre
- cString mDescription; // Description
- cString mLongDescription; // a longer description
- cString mPublishers; // CSV of Publishers
- cString mLanguage; // RFC 1766 Language code
- cString mRelations; // Relation to other contents
- cString mProducers; // CSV of Producers
- cString mRating; // Rating (for parential control)
- cString mActors; // CSV of Actors
- cString mDirectors; // CSV of Directors
+ cString mGenre; ///< Genre of the video
+ cString mDescription; ///< Description
+ cString mLongDescription; ///< a longer description
+ cString mPublishers; ///< CSV of Publishers
+ cString mLanguage; ///< RFC 1766 Language code
+ cString mRelations; ///< Relation to other contents
+ cString mProducers; ///< CSV of Producers
+ cString mRating; ///< Rating (for parential control)
+ cString mActors; ///< CSV of Actors
+ cString mDirectors; ///< CSV of Directors
+ /**
+ * Constructor of a video item
+ *
+ * This creates a new instance of a video item
+ */
cUPnPClassVideoItem();
public:
virtual ~cUPnPClassVideoItem();
@@ -250,36 +997,230 @@ public:
virtual bool setProperty(const char* Property, const char* Value);
virtual bool getProperty(const char* Property, char** Value) const;
/******** Setter ********/
+ /**
+ * Set a long description
+ *
+ * A long description may hold information about the content or the story
+ * of a video
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param LongDescription the content or story of a video
+ */
int setLongDescription(const char* LongDescription);
+ /**
+ * Set a description
+ *
+ * A description may hold short information about the content or the story
+ * of a video. Unlike a long description, this contains just a very short
+ * brief like a subtitle or the episode title.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Description the description of a video
+ */
int setDescription(const char* Description);
+ /**
+ * Set the publishers
+ *
+ * This is a CSV list of publishers, who distributes the video.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Publishers a CSV list of publishers
+ */
int setPublishers(const char* Publishers);
+ /**
+ * Set a genre
+ *
+ * This is a CSV list of genre of a video. This may be something like
+ * "Western" or "SciFi". Actually, there is no standardized rule for
+ * a genre name, which results in an ambiguous definition of certain
+ * genre, like Thriller and Horror.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Genre a CSV list of genre
+ */
int setGenre(const char* Genre);
+ /**
+ * Set the language
+ *
+ * This sets the language of a video. It is defined by RFC 1766.
+ * A valid language definition is \em "de-DE" or \em "en-US".
+ *
+ * @see http://www.ietf.org/rfc/rfc1766.txt
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Language the language (RFC 1766)
+ */
int setLanguage(const char* Language);
+ /**
+ * Sets a relation URL
+ *
+ * This sets a CSV list of relation URLs, where to find additional
+ * information about the movie. The URLs may not contain commas and they
+ * must be properly escaped as in RFC 2396
+ *
+ * @see http://www.ietf.org/rfc/rfc2396.txt
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Relations a CSV list with relations
+ */
int setRelations(const char* Relations);
+ /**
+ * Sets the directors
+ *
+ * This sets a CSV list of directors.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Directors a CSV list of directors
+ */
int setDirectors(const char* Directors);
+ /**
+ * Sets the actors
+ *
+ * This sets a CSV list of actors in a video. This usually contain the main actors.
+ * However, also other actors appearing in the video can be mentioned here.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Actors a CSV list of actors
+ */
int setActors(const char* Actors);
+ /**
+ * Sets the producers
+ *
+ * This sets a CSV list of producers of a video. These are the people who are
+ * involed in the production of a video
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Producers a CSV list of producers
+ */
int setProducers(const char* Producers);
+ /**
+ * Sets the rating
+ *
+ * This is a rating, which can be used for parential control issues.
+ *
+ * @see http://en.wikipedia.org/wiki/Motion_picture_rating_system
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Rating the rating of a video
+ */
int setRating(const char* Rating);
/******** Getter ********/
+ /**
+ * Get the genres
+ *
+ * This returns a CSV list of genre
+ *
+ * @return the genre of a video
+ */
const char* getGenre() const { return this->mGenre; }
+ /**
+ * Get the long description
+ *
+ * This returns the long description of a video
+ *
+ * @return the long description of a video
+ */
const char* getLongDescription() const { return this->mLongDescription; }
+ /**
+ * Get the description
+ *
+ * This returns the description of a video
+ *
+ * @return the description of a video
+ */
const char* getDescription() const { return this->mDescription; }
+ /**
+ * Get the publishers
+ *
+ * This returns a CSV list of publishers of the video
+ *
+ * @return a CSV list of publishers
+ */
const char* getPublishers() const { return this->mPublishers; }
+ /**
+ * Get the language
+ *
+ * This returns the language of the video
+ *
+ * @return the language
+ */
const char* getLanguage() const { return this->mLanguage; }
+ /**
+ * Get the relations
+ *
+ * This returns a CSV list of relation URLs.
+ *
+ * @return a CSV list of relation URLs
+ */
const char* getRelations() const { return this->mRelations; }
+ /**
+ * Get the actors
+ *
+ * This returns a CSV list of actors in the video
+ *
+ * @return a CSV list of actors
+ */
const char* getActors() const { return this->mActors; }
+ /**
+ * Get the producers
+ *
+ * This returns a CSV list of producers of a video
+ *
+ * @return a CSV list of producers
+ */
const char* getProducers() const { return this->mProducers; }
+ /**
+ * Get the directors
+ *
+ * This returns a CSV list of directors
+ *
+ * @return a CSV list of directors
+ */
const char* getDirectors() const { return this->mDirectors; }
+ /**
+ * Get the rating
+ *
+ * This returns the rating used for parental control.
+ *
+ * @return the rating of a video
+ */
const char* getRating() const { return this->mRating; }
};
+/**
+ * The UPnP class Movie
+ *
+ * This is a UPnP class Movie representation with all its properties.
+ */
class cUPnPClassMovie : public cUPnPClassVideoItem {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPMovieMediator;
protected:
- int mDVDRegionCode;
- cString mStorageMedium;
+ int mDVDRegionCode; ///< The Region code of the movie (0 - 8)
+ cString mStorageMedium; ///< The storage medium where the movie is stored
+ /**
+ * Constructor of a movie
+ *
+ * This creates a new instance of a movie
+ */
cUPnPClassMovie();
public:
virtual ~cUPnPClassMovie();
@@ -288,22 +1229,75 @@ public:
virtual bool setProperty(const char* Property, const char* Value);
virtual bool getProperty(const char* Property, char** Value) const;
/******** Setter ********/
+ /**
+ * Sets the DVD region code
+ *
+ * For more information on this, see http://en.wikipedia.org/wiki/DVD_region_code
+ *
+ * The integer representation for \em ALL is 9.
+ *
+ * @see http://en.wikipedia.org/wiki/DVD_region_code
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param RegionCode the region code of this movie
+ */
int setDVDRegionCode(int RegionCode);
+ /**
+ * Sets the storage medium
+ *
+ * This will set the storage medium, where the movie resides. Valid media
+ * are defined in \link common.h \endlink
+ *
+ * @see common.h
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param StorageMedium the medium where the movie is located
+ */
int setStorageMedium(const char* StorageMedium);
/******** Getter ********/
+ /**
+ * Get the DVD region code
+ *
+ * This returns the DVD region code. For more information,
+ * see http://en.wikipedia.org/wiki/DVD_region_code
+ *
+ * The integer representation for \em ALL is 9.
+ *
+ * @see http://en.wikipedia.org/wiki/DVD_region_code
+ * @return the DVD region code
+ */
int getDVDRegionCode() const { return this->mDVDRegionCode; }
+ /**
+ * Get the storage medium
+ *
+ * This returns the storage medium, where the movie resides.
+ *
+ * @return the storage medium
+ */
const char* getStorageMedium() const { return this->mStorageMedium; }
};
+/**
+ * The UPnP class VideoBroadcast
+ *
+ * This is a UPnP class VideoBroadcast representation with all its properties.
+ */
class cUPnPClassVideoBroadcast : public cUPnPClassVideoItem {
friend class cMediaDatabase;
friend class cUPnPObjectMediator;
friend class cUPnPVideoBroadcastMediator;
protected:
- cString mIcon;
- cString mRegion;
- int mChannelNr;
- cString mChannelName;
+ cString mIcon; ///< The channel icon of the channel
+ cString mRegion; ///< The region where the channel can be received
+ int mChannelNr; ///< The channel number
+ cString mChannelName; ///< The channel name or provider name
+ /**
+ * Constructor of a video broadcast
+ *
+ * This creates a new instance of a video broadcast
+ */
cUPnPClassVideoBroadcast();
public:
virtual ~cUPnPClassVideoBroadcast();
@@ -312,29 +1306,166 @@ public:
virtual bool setProperty(const char* Property, const char* Value);
virtual bool getProperty(const char* Property, char** Value) const;
/******** Setter ********/
+ /**
+ * Set the channel icon
+ *
+ * This sets the channel icon of this channel. The resource must be a valid
+ * URI which can be obtained via the internal webserver
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param IconURI the URI to the icon file
+ */
int setIcon(const char* IconURI);
+ /**
+ * Set the channel region
+ *
+ * This sets the region of a channel, where it can be received
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param Region the location where the channel can be received
+ */
int setRegion(const char* Region);
+ /**
+ * Set channel number
+ *
+ * This sets the channel number, so that it can be used for directly navigation
+ * or channel up and down navigation respectively.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param ChannelNr the channel number
+ */
int setChannelNr(int ChannelNr);
+ /**
+ * Set the channel name
+ *
+ * This sets the channel name or the provider of the channel.
+ *
+ * @return returns
+ * - \bc 0, if setting was successful
+ * - \bc <0, otherwise
+ * @param ChannelName the channel name
+ */
int setChannelName(const char* ChannelName);
/******** Getter ********/
+ /**
+ * Get the channel icon
+ *
+ * This returns the channel icon of the channel.
+ *
+ * @return the channel icon
+ */
const char* getIcon() const { return this->mIcon; }
+ /**
+ * Get the region
+ *
+ * This returns the region, where the channel can be received
+ *
+ * @return the channel region
+ */
const char* getRegion() const { return this->mRegion; }
+ /**
+ * Get the channel number
+ *
+ * This returns the channel number
+ *
+ * @return the channel number
+ */
int getChannelNr() const { return this->mChannelNr; }
+ /**
+ * Get the channel name
+ *
+ * This returns the channel name or provider name respectively
+ *
+ * @return the channel name
+ */
const char* getChannelName() const { return this->mChannelName; }
};
+/**
+ * Mediator interface
+ *
+ * This is an interface for mediators used to communicate with the database.
+ * A mediator is applied to get, create, save or delete an UPnP object.
+ */
class cMediatorInterface {
public:
virtual ~cMediatorInterface(){};
+ /**
+ * Creates an object
+ *
+ * This creates a new UPnP object with the specific title and the restriction.
+ *
+ * @return the newly created object
+ * @param Title the title of that object
+ * @param Restricted the restriction of the object
+ */
virtual cUPnPClassObject* createObject(const char* Title, bool Restricted) = 0;
+ /**
+ * Get an object
+ *
+ * Retrieves a UPnP object from the database and stores its information in the
+ * object. The object is obtained via its object ID.
+ *
+ * @return the object, found in the database
+ * @param ID the object ID
+ */
virtual cUPnPClassObject* getObject(cUPnPObjectID ID) = 0;
+ /**
+ * Saves the object
+ *
+ * This saves the object in the database by updating the values in the database
+ * with those in the object.
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param Object the object to be saved
+ */
virtual int saveObject(cUPnPClassObject* Object) = 0;
+ /**
+ * Deletes the object
+ *
+ * This deletes the object in the database by removing all its children and then
+ * deleting the contents from the database
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param Object the object to be deleted
+ */
virtual int deleteObject(cUPnPClassObject* Object) = 0;
+ /**
+ * Clears the object
+ *
+ * This clears the object, i.e. all its children will be removed and deleted
+ * from the database
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param Object the object to be cleared
+ */
virtual int clearObject(cUPnPClassObject* Object) = 0;
};
typedef std::map<const char*, cMediatorInterface*, strCmp> tMediatorMap;
+/**
+ * The object factory
+ *
+ * This factory can create, delete, clear or save UPnP objects. It uses mediators
+ * to communicate with the persistance database to load or persist the objects.
+ *
+ * If a new type of object shall be stored in the database an according mediator
+ * is needed, which knows the internal database structure. It must implement the
+ * cMediatorInterface class to work with this factory.
+ */
class cUPnPObjectFactory {
private:
static cUPnPObjectFactory* mInstance;
@@ -344,84 +1475,257 @@ private:
cMediatorInterface* findMediatorByClass(const char* Class);
cUPnPObjectFactory();
public:
+ /**
+ * Return the instance of the factory
+ *
+ * This returns the instance of the factory. When the media database is
+ * initialized successfully, it usally has all known mediators already
+ * registered.
+ *
+ * @return the instance of the factory
+ */
static cUPnPObjectFactory* getInstance();
+ /**
+ * Register a mediator
+ *
+ * This registers a new mediator by the associated class. The mediator
+ * must implement the cMediatorInterface class to be used with this
+ * factory.
+ *
+ * @param UPnPClass the class of which the mediator is associated to
+ * @param Mediator the mediator itself
+ */
void registerMediator(const char* UPnPClass, cMediatorInterface* Mediator);
+ /**
+ * Unregisters a mediator
+ *
+ * This unregisters a mediator if it is not needed anylonger. If the optional
+ * parameter \c freeMediator is set, the object instance will be free'd after
+ * removing it from the list.
+ *
+ * @param UPnPClass the class of the associated mediator
+ * @param freeMediator flag to indicate if the mediator shall be free'd after removing
+ */
void unregisterMediator(const char* UPnPClass, bool freeMediator=true);
+ /**
+ * @copydoc cMediatorInterface::createObject(const char* Title, bool Restricted)
+ *
+ * @param UPnPClass the class of the new object
+ */
cUPnPClassObject* createObject(const char* UPnPClass, const char* Title, bool Restricted=true);
+ /*! @copydoc cMediatorInterface::getObject(cUPnPObjectID ID) */
cUPnPClassObject* getObject(cUPnPObjectID ID);
+ /*! @copydoc cMediatorInterface::saveObject(cUPnPClassObject* Object) */
int saveObject(cUPnPClassObject* Object);
+ /*! @copydoc cMediatorInterface::deleteObject(cUPnPClassObject* Object) */
int deleteObject(cUPnPClassObject* Object);
+ /*! @copydoc cMediatorInterface::clearObject(cUPnPClassObject* Object) */
int clearObject(cUPnPClassObject* Object);
};
class cMediaDatabase;
+/**
+ * Object Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPObjectMediator : public cMediatorInterface {
protected:
- cSQLiteDatabase* mDatabase;
- cMediaDatabase* mMediaDatabase;
- cUPnPObjectMediator(cMediaDatabase* MediaDatabase);
- virtual int initializeObject(cUPnPClassObject* Object, const char* Class, const char* Title, bool Restricted);
+ cSQLiteDatabase* mDatabase; ///< the SQLite 3 database wrapper
+ cMediaDatabase* mMediaDatabase; ///< the media database
+ /**
+ * Constructor of object mediator
+ *
+ * This constructs a new object mediator. This is actually not allowed because
+ * it is prohibited to create instances of the UPnP class Object
+ */
+ cUPnPObjectMediator(
+ cMediaDatabase* MediaDatabase ///< the media database
+ );
+ /**
+ * Initializes an object
+ *
+ * This initializes an object, which means, that it will be created in the database with
+ * the required details.
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ */
+ virtual int initializeObject(
+ cUPnPClassObject* Object, ///< the object to be initialized
+ const char* Class, ///< the class of the object
+ const char* Title, ///< the title of the object
+ bool Restricted ///< restriction of the object
+ );
+ /**
+ * Store the object in the database
+ *
+ * This stores the information of an object in the database
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param Object the object to be saved
+ */
virtual int objectToDatabase(cUPnPClassObject* Object);
+ /**
+ * Loads an object from database
+ *
+ * This loads an object from the database
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param Object the object to be loaded
+ * @param ID the object ID of that object
+ */
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
virtual ~cUPnPObjectMediator();
+ /*! @copydoc cMediatorInterface::createObject(const char* Title, bool Restricted) */
virtual cUPnPClassObject* createObject(const char* Title, bool Restricted);
- virtual cUPnPClassObject* getObject(cUPnPObjectID);
+ /*! @copydoc cMediatorInterface::getObject(cUPnPObjectID ID) */
+ virtual cUPnPClassObject* getObject(cUPnPObjectID ID);
+ /*! @copydoc cMediatorInterface::saveObject(cUPnPClassObject* Object) */
virtual int saveObject(cUPnPClassObject* Object);
+ /*! @copydoc cMediatorInterface::deleteObject(cUPnPClassObject* Object) */
virtual int deleteObject(cUPnPClassObject* Object);
+ /*! @copydoc cMediatorInterface::clearObject(cUPnPClassObject* Object) */
virtual int clearObject(cUPnPClassObject* Object);
};
+/**
+ * Item Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPItemMediator : public cUPnPObjectMediator {
protected:
+ /*! @copydoc cUPnPObjectMediator::objectToDatabase(cUPnPClassObject* Object) */
virtual int objectToDatabase(cUPnPClassObject* Object);
+ /*! @copydoc cUPnPObjectMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID) */
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
+ /**
+ * Constructor of item mediator
+ *
+ * This creates a new item mediator with which it is possible to create new
+ * instances of Item objects.
+ *
+ * @param MediaDatabase the media database
+ */
cUPnPItemMediator(cMediaDatabase* MediaDatabase);
virtual ~cUPnPItemMediator(){};
+ /*! @copydoc cUPnPObjectMediator::createObject(const char* Title, bool Restricted) */
virtual cUPnPClassItem* createObject(const char* Title, bool Restricted);
+ /*! @copydoc cUPnPObjectMediator::getObject(cUPnPObjectID ID) */
virtual cUPnPClassItem* getObject(cUPnPObjectID ID);
};
+/**
+ * VideoItem Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPVideoItemMediator : public cUPnPItemMediator {
protected:
virtual int objectToDatabase(cUPnPClassObject* Object);
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
+ /**
+ * Constructor of videoitem mediator
+ *
+ * This creates a new videoitem mediator with which it is possible to create new
+ * instances of VideoItem objects.
+ *
+ * @param MediaDatabase the media database
+ */
cUPnPVideoItemMediator(cMediaDatabase* MediaDatabase);
virtual ~cUPnPVideoItemMediator(){};
virtual cUPnPClassVideoItem* createObject(const char* Title, bool Restricted);
virtual cUPnPClassVideoItem* getObject(cUPnPObjectID ID);
};
+/**
+ * VideoBroadcast Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPVideoBroadcastMediator : public cUPnPVideoItemMediator {
protected:
virtual int objectToDatabase(cUPnPClassObject* Object);
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
+ /**
+ * Constructor of video broadcast mediator
+ *
+ * This creates a new video broadcast mediator with which it is possible to create new
+ * instances of VideoBroadcast objects.
+ *
+ * @param MediaDatabase the media database
+ */
cUPnPVideoBroadcastMediator(cMediaDatabase* MediaDatabase);
virtual ~cUPnPVideoBroadcastMediator(){};
virtual cUPnPClassVideoBroadcast* createObject(const char* Title, bool Restricted);
virtual cUPnPClassVideoBroadcast* getObject(cUPnPObjectID ID);
};
+/**
+ * Movie Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPMovieMediator : public cUPnPVideoItemMediator {
protected:
virtual int objectToDatabase(cUPnPClassObject* Object);
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
+ /**
+ * Constructor of movie mediator
+ *
+ * This creates a new movie mediator with which it is possible to create new
+ * instances of Movie objects.
+ *
+ * @param MediaDatabase the media database
+ */
cUPnPMovieMediator(cMediaDatabase* MediaDatabase);
virtual ~cUPnPMovieMediator(){};
virtual cUPnPClassMovie* createObject(const char* Title, bool Restricted);
virtual cUPnPClassMovie* getObject(cUPnPObjectID ID);
};
+/**
+ * Container Mediator
+ *
+ * This is the interface between the objects and the database. It is possible to
+ * create new objects, stores objects in the database as well as removing them from
+ * it.
+ */
class cUPnPContainerMediator : public cUPnPObjectMediator {
protected:
virtual int objectToDatabase(cUPnPClassObject* Object);
virtual int databaseToObject(cUPnPClassObject* Object, cUPnPObjectID ID);
public:
+ /**
+ * Constructor of container mediator
+ *
+ * This creates a new container mediator with which it is possible to create new
+ * instances of Container objects.
+ *
+ * @param MediaDatabase the media database
+ */
cUPnPContainerMediator(cMediaDatabase* MediaDatabase);
virtual ~cUPnPContainerMediator(){};
virtual cUPnPClassContainer* createObject(const char* Title, bool Restricted);
diff --git a/database/resources.cpp b/database/resources.cpp
index 7d01ceb..8f0dec4 100644
--- a/database/resources.cpp
+++ b/database/resources.cpp
@@ -75,11 +75,11 @@ int cUPnPResources::getResourcesOfObject(cUPnPClassObject* Object){
cUPnPResource* cUPnPResources::getResource(unsigned int ResourceID){
cUPnPResource* Resource;
if((Resource = this->mResources->Get(ResourceID))){
- MESSAGE("Found cached resource");
+ MESSAGE(VERBOSE_METADATA, "Found cached resource");
return Resource;
}
else if((Resource = this->mMediator->getResource(ResourceID))){
- MESSAGE("Found resource in database");
+ MESSAGE(VERBOSE_METADATA, "Found resource in database");
this->mResources->Add(Resource, ResourceID);
return Resource;
}
@@ -107,12 +107,12 @@ int cUPnPResources::createFromRecording(cUPnPClassVideoItem* Object, cRecording*
}
delete Detector;
- MESSAGE("To be continued, may it work with DLNA?! Guess, not!");
+ MESSAGE(VERBOSE_SDK, "To be continued, may it work with DLNA?! Guess, not!");
return 0;
}
int cUPnPResources::createFromFile(cUPnPClassItem* , cString ){
- MESSAGE("To be done");
+ MESSAGE(VERBOSE_SDK, "To be done");
return -1;
}
@@ -131,12 +131,12 @@ int cUPnPResources::createFromChannel(cUPnPClassVideoBroadcast* Object, cChannel
const char* ProtocolInfo = cDlna::getInstance()->getProtocolInfo(Profile);
- MESSAGE("Protocol info: %s", ProtocolInfo);
+ MESSAGE(VERBOSE_METADATA, "Protocol info: %s", ProtocolInfo);
// Adapted from streamdev
int index = 0;
for(int i=0; Channel->Apid(i)!=0; i++, index++){
- MESSAGE("Analog channel %d", i);
+ MESSAGE(VERBOSE_METADATA, "Analog channel %d", i);
cString ResourceFile = cString::sprintf("%s:%d", *Channel->GetChannelID().ToString(), index);
cUPnPResource* Resource = this->mMediator->newResource(Object, UPNP_RESOURCE_CHANNEL,ResourceFile, Profile->mime, ProtocolInfo);
Resource->mBitrate = 0;
@@ -153,7 +153,7 @@ int cUPnPResources::createFromChannel(cUPnPClassVideoBroadcast* Object, cChannel
this->mResources->Add(Resource, Resource->getID());
}
for(int i=0; Channel->Dpid(i)!=0; i++, index++){
- MESSAGE("Digital channel %d", i);
+ MESSAGE(VERBOSE_METADATA, "Digital channel %d", i);
cString ResourceFile = cString::sprintf("%s:%d", *Channel->GetChannelID().ToString(), index);
cUPnPResource* Resource = this->mMediator->newResource(Object, UPNP_RESOURCE_CHANNEL,ResourceFile, Profile->mime, ProtocolInfo);
Resource->mBitrate = 0;
diff --git a/database/resources.h b/database/resources.h
index 46ec0d5..8f7fa86 100644
--- a/database/resources.h
+++ b/database/resources.h
@@ -16,6 +16,12 @@
class cUPnPResourceMediator;
class cMediaDatabase;
+/**
+ * The resource manager
+ *
+ * This manages the resources in an internal cache. It may create a new resource
+ * from a channel, a recording or a custom file.
+ */
class cUPnPResources {
private:
cHash<cUPnPResource>* mResources;
@@ -24,16 +30,89 @@ private:
cSQLiteDatabase* mDatabase;
cUPnPResources();
public:
+ /**
+ * Fill object with its resources
+ *
+ * This will load all the resources from the database, which are associated
+ * to the given object
+ *
+ * @param Object the object, which shall be filled
+ * @return returns
+ * - \bc 0, if loading was successful
+ * - \bc <0, otherwise
+ */
int getResourcesOfObject(cUPnPClassObject* Object);
+ /**
+ * Loads all resources from database
+ *
+ * This loads all resources from the database into the internal cache.
+ *
+ * @return returns
+ * - \bc 0, if loading was successful
+ * - \bc <0, otherwise
+ */
int loadResources();
+ /*! @copydoc cUPnPResourceMediator::getResource */
cUPnPResource* getResource(unsigned int ResourceID);
virtual ~cUPnPResources();
+ /**
+ * Get the instance of the resource manager
+ *
+ * This returns the instance of the resource manager.
+ *
+ * @return the instance of the manager
+ */
static cUPnPResources* getInstance();
+ /**
+ * Create resource from channel
+ *
+ * This creates a new resource from the given channel. It determines what
+ * kind of video stream it is and further details if available. It stores
+ * the resource in the database after creating it.
+ *
+ * @param Object the videoBroadcast item which holds the resource
+ * @param Channel the VDR TV channel
+ * @return returns
+ * - \bc 0, if loading was successful
+ * - \bc <0, otherwise
+ */
int createFromChannel(cUPnPClassVideoBroadcast* Object, cChannel* Channel);
+ /**
+ * Create resource from recording
+ *
+ * This creates a new resource from the given recording. It determines what
+ * kind of video stream it is and further details if available. It stores
+ * the resource in the database after creating it.
+ *
+ * @param Object the videoItem item which holds the resource
+ * @param Recording the VDR TV recording
+ * @return returns
+ * - \bc 0, if loading was successful
+ * - \bc <0, otherwise
+ */
int createFromRecording(cUPnPClassVideoItem* Object, cRecording* Recording);
+ /**
+ * Create resource from file
+ *
+ * This creates a new resource from the given file. It determines all available
+ * information about the resource by analizing the content. It stores
+ * the resource in the database after creating it.
+ *
+ * @param Object the item which holds the resource
+ * @param File the file name
+ * @return returns
+ * - \bc 0, if loading was successful
+ * - \bc <0, otherwise
+ */
int createFromFile(cUPnPClassItem* Object, cString File);
};
+/**
+ * The resource mediator
+ *
+ * This is another mediator which communicates with the database. It manages the
+ * resources in the database
+ */
class cUPnPResourceMediator {
friend class cUPnPResources;
private:
@@ -42,8 +121,40 @@ private:
unsigned int getNextResourceID();
public:
virtual ~cUPnPResourceMediator();
+ /**
+ * Get a resource by ID
+ *
+ * This returns a resource by its resource ID
+ *
+ * @param ResourceID the resource ID of the demanded resource
+ * @return the requested resource
+ */
cUPnPResource* getResource(unsigned int ResourceID);
+ /**
+ * Saves the resource
+ *
+ * This updates the information in the database with those in the resource
+ * object
+ *
+ * @param Resource the resource which shall be saved
+ * @return returns
+ * - \bc 0, if saving was successful
+ * - \bc <0, if an error occured
+ */
int saveResource(cUPnPResource* Resource);
+ /**
+ * Create new resource
+ *
+ * This creates a new resource and stores the skeleton in the database. The
+ * newly created resource will only contain all required information.
+ *
+ * @param Object the Object which will hold the resource
+ * @param ResourceType the type of the resource
+ * @param ResourceFile the file or URL, where the resource can be located
+ * @param ContentType the mime type of the content
+ * @param ProtocolInfo the protocol information of the resource
+ * @return the newly created resource
+ */
cUPnPResource* newResource(cUPnPClassObject* Object, int ResourceType, cString ResourceFile, cString ContentType, cString ProtocolInfo);
};
diff --git a/misc/avdetector.cpp b/misc/avdetector.cpp
index d66988e..8f3bc8f 100644
--- a/misc/avdetector.cpp
+++ b/misc/avdetector.cpp
@@ -55,7 +55,7 @@ int cAudioVideoDetector::detectVideoProperties(cUPnPResource* Resource, const ch
unsigned int bitrate = CodecCtx->bit_rate;
const char* codecName = (Codec)?Codec->name:"unknown";
- MESSAGE("AVDetector: %s-stream %dx%d at %d bit/s", codecName, width, height, bitrate);
+ MESSAGE(VERBOSE_METADATA, "AVDetector: %s-stream %dx%d at %d bit/s", codecName, width, height, bitrate);
Resource->mBitrate = bitrate;
Resource->mSampleFrequency = CodecCtx->sample_rate;
diff --git a/misc/avdetector.h b/misc/avdetector.h
index 0b8bb81..b043c59 100644
--- a/misc/avdetector.h
+++ b/misc/avdetector.h
@@ -10,10 +10,29 @@
#include "../database/object.h"
+/**
+ * The audio/video detector
+ *
+ * This is the audio video detector, which analizes the audio and video stream
+ * of a file to gather more information about the resource. This is also
+ * required for determination of a suitable DLNA profile.
+ */
class cAudioVideoDetector {
public:
cAudioVideoDetector(){};
virtual ~cAudioVideoDetector(){};
+ /**
+ * Detect video properties
+ *
+ * This detects video properties of a video stream and stores them in the
+ * Resource object.
+ *
+ * @param Resource the resource, where to save the data
+ * @param Filename the file, which shall be read
+ * @return returns
+ * - \bc 0, if the detection was successful
+ * - \bc <0, otherwise
+ */
int detectVideoProperties(cUPnPResource* Resource, const char* Filename);
private:
};
diff --git a/misc/config.cpp b/misc/config.cpp
index 59bf4a6..1fa0ccb 100644
--- a/misc/config.cpp
+++ b/misc/config.cpp
@@ -32,6 +32,7 @@ cUPnPConfig* cUPnPConfig::get(){
}
cUPnPConfig* cUPnPConfig::mInstance = NULL;
+int cUPnPConfig::verbosity = 0;
bool cUPnPConfig::processArgs(int argc, char* argv[]){
// Implement command line argument processing here if applicable.
@@ -39,7 +40,9 @@ bool cUPnPConfig::processArgs(int argc, char* argv[]){
{"int", required_argument, NULL, 'i'},
{"address", required_argument, NULL, 'a'},
{"port", required_argument, NULL, 'p'},
- {"autodetect", no_argument, NULL, 'd'}
+ {"autodetect", no_argument, NULL, 'd'},
+ {"verbose", no_argument, NULL, 'v'},
+ {0, 0, 0, 0}
};
int c = 0;
@@ -55,8 +58,9 @@ bool cUPnPConfig::processArgs(int argc, char* argv[]){
bool success = true;
bool ifaceExcistent = false;
bool addExcistent = false;
+ static int verbose = 0;
- while((c = getopt_long(argc, argv, "i:a:p:v",long_options, NULL)) != -1){
+ while((c = getopt_long(argc, argv, "i:a:p:dv",long_options, NULL)) != -1){
switch(c){
case 'i':
if(addExcistent) { ERROR("Address given but must be absent!"); return false; }
@@ -78,6 +82,12 @@ bool cUPnPConfig::processArgs(int argc, char* argv[]){
break;
case 'd':
success = this->parseSetup(SETUP_SERVER_AUTO, optarg) && success;
+ break;
+ case 'v':
+ cUPnPConfig::verbosity++;
+ verbose++;
+ WARNING("Verbosity level: %i ", verbose);
+ break;
default:
return false;
}
@@ -90,11 +100,11 @@ bool cUPnPConfig::parseSetup(const char *Name, const char *Value)
{
const char* ptr;
if(*this->mParsedArgs && (ptr = strstr(this->mParsedArgs,Name))!=NULL){
- MESSAGE("Skipping %s=%s, was overridden in command line.",Name, Value);
+ MESSAGE(VERBOSE_SDK, "Skipping %s=%s, was overridden in command line.",Name, Value);
return true;
}
- MESSAGE("VARIABLE %s has value %s", Name, Value);
+ MESSAGE(VERBOSE_SDK, "VARIABLE %s has value %s", Name, Value);
// Parse your own setup parameters and store their values.
if (!strcasecmp(Name, SETUP_SERVER_ENABLED)) this->mEnable = atoi(Value);
else if (!strcasecmp(Name, SETUP_SERVER_AUTO)) this->mAutoSetup = atoi(Value);
diff --git a/misc/config.h b/misc/config.h
index 018213e..40ae6f7 100644
--- a/misc/config.h
+++ b/misc/config.h
@@ -11,21 +11,60 @@
#include <vdr/tools.h>
#include "../common.h"
+/**
+ * The configuration settings
+ *
+ * This holds the configurations for the server. It holds information about the
+ * network settings as well as some status flags.
+ */
class cUPnPConfig {
private:
static cUPnPConfig* mInstance;
cString mParsedArgs;
cUPnPConfig();
public:
- char* mInterface;
- char* mAddress;
- int mPort;
- int mEnable;
- int mAutoSetup;
+ static int verbosity; ///< the verbosity of the plugin, the higher the more messages
+ ///< are printed.
+ char* mInterface; ///< the network interface, which the server is bound to
+ char* mAddress; ///< the IP address which is used by the server
+ int mPort; ///< the port which the server is listening on
+ int mEnable; ///< indicates, if the server is enabled or not
+ int mAutoSetup; ///< indicates, if the settings are automatically detected
public:
virtual ~cUPnPConfig();
+ /**
+ * Get the configuration
+ *
+ * This returns the instance of the current configuration settings.
+ *
+ * @return the configuration object
+ */
static cUPnPConfig* get();
+ /**
+ * Parse setup variable
+ *
+ * This parses the setup variable with the according value. The value is a
+ * string representation and must be converted into the according data type.
+ *
+ * @return returns
+ * - \bc true, if parsing was successful
+ * - \bc false, otherwise
+ * @param Name the name of the variable
+ * @param Value the according value of the variable
+ */
bool parseSetup(const char* Name, const char* Value);
+ /**
+ * Processes the commandline arguments
+ *
+ * This processes the commandline arguments which the user specified at the
+ * start of the plugin.
+ *
+ * @return returns
+ * - \bc true, if processing was successful
+ * - \bc false, otherwise
+ * @param argc the number of arguments in the list
+ * @param argv the arguments as a char array
+ */
bool processArgs(int argc, char* argv[]);
};
diff --git a/misc/menusetup.cpp b/misc/menusetup.cpp
index 9e8386f..c385b2d 100644
--- a/misc/menusetup.cpp
+++ b/misc/menusetup.cpp
@@ -18,7 +18,7 @@
cMenuSetupUPnP::cMenuSetupUPnP(){
// Get server acitve state
- MESSAGE("Creating menu");
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Creating menu");
this->mCtrlBind = NULL;
this->mCtrlAutoMode = NULL;
this->mCtrlEnabled = NULL;
@@ -63,7 +63,7 @@ const char* const* cMenuSetupUPnP::getInterfaceList(int* count){
}
int cMenuSetupUPnP::getInterfaceIndex(const char* Interface){
- MESSAGE("Getting Index of %s", Interface);
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Getting Index of %s", Interface);
if(!Interface) return 0;
int count;
int Index = 0;
diff --git a/misc/menusetup.h b/misc/menusetup.h
index ae40e97..4e32efc 100644
--- a/misc/menusetup.h
+++ b/misc/menusetup.h
@@ -17,17 +17,42 @@
*
* This class shows and manages the settings within the VDR setup OSD
*
- * @author Denis Loh
- * @version 0.0.1
*/
class cMenuSetupUPnP : public cMenuSetupPage {
public:
cMenuSetupUPnP();
// virtual ~cMenuSetupUPnP();
- virtual eOSState ProcessKey(eKeys Key);
+ /**
+ * Processes a keystroke
+ *
+ * This processes a keystroke which is done by the user and updates the
+ * menu accordingly
+ *
+ * It returns the current state of the VDR after pressing a key
+ *
+ * @return The current state of the VDR
+ */
+ virtual eOSState ProcessKey(
+ eKeys Key ///< Key, pressed by the user
+ );
protected:
+ /**
+ * Stores the setup information
+ *
+ * This stores the setup information in the configuration file
+ */
virtual void Store(void);
+ /**
+ * Update the menu
+ *
+ * This updates the menu osd and refreshes the screen.
+ */
void Update(void);
+ /**
+ * Loads the setup information
+ *
+ * This loads the setup information from the configuration file
+ */
void Load(void);
private:
const char* const* getInterfaceList(int *count);
diff --git a/misc/search.cpp b/misc/search.cpp
index deee8b0..b3534f1 100644
--- a/misc/search.cpp
+++ b/misc/search.cpp
@@ -28,6 +28,7 @@ typedef function1<void, const char> charCallback;
typedef function1<void, int> intCallback;
// The defined ColumnNames
+/** @private */
struct cProperties : symbols<const char*> {
//struct cProperties : symbols<> {
cProperties(){
@@ -107,6 +108,7 @@ struct cProperties : symbols<const char*> {
}
} Properties;
+/** @private */
struct cOperators : symbols<const char*> {
cOperators(){
add
@@ -123,6 +125,7 @@ struct cOperators : symbols<const char*> {
}
} Operators;
+/** @private */
struct cConcatOperators : symbols<const char*> {
cConcatOperators(){
add
@@ -132,6 +135,7 @@ struct cConcatOperators : symbols<const char*> {
}
} ConcatOperators;
+/** @private */
struct cExistanceOperator : symbols<const char*> {
cExistanceOperator(){
add
@@ -145,6 +149,7 @@ struct cExistanceOperator : symbols<const char*> {
// This is the grammar including the functors which calls the member functions
// of search. The callback definitions at the end of the constructor are
// essential. DO NOT MODIFY if you don't know how!
+/** @private */
struct cSearchGrammar : public boost::spirit::grammar<cSearchGrammar> {
// The callbacks members
charCallback &endBrackedExp;
@@ -176,6 +181,7 @@ struct cSearchGrammar : public boost::spirit::grammar<cSearchGrammar> {
startBrackedExp(startBrackedExp){}
template <typename scanner>
+ /** @private */
struct definition {
boost::spirit::rule<scanner> searchCrit, searchExp, logOp, \
relExp, binOp, relOp, stringOp, \
@@ -278,6 +284,7 @@ struct cSearchGrammar : public boost::spirit::grammar<cSearchGrammar> {
};
};
+/** @private */
struct cSortGrammar : public boost::spirit::grammar<cSortGrammar> {
// The callback members
propCallback &pushProperty;
@@ -290,6 +297,7 @@ struct cSortGrammar : public boost::spirit::grammar<cSortGrammar> {
pushDirection(pushDirection){}
template <typename scanner>
+ /** @private */
struct definition {
boost::spirit::rule<scanner> sortCrit, sortExp, property, direction;
@@ -312,6 +320,7 @@ struct cSortGrammar : public boost::spirit::grammar<cSortGrammar> {
};
};
+/** @private */
struct cFilterGrammar : public boost::spirit::grammar<cFilterGrammar> {
// The callback members
propCallback &pushProperty;
@@ -324,6 +333,7 @@ struct cFilterGrammar : public boost::spirit::grammar<cFilterGrammar> {
pushAsterisk(pushAsterisk){}
template <typename scanner>
+ /** @private */
struct definition {
boost::spirit::rule<scanner> filterCrit, filterExp, property;
@@ -351,7 +361,7 @@ struct cFilterGrammar : public boost::spirit::grammar<cFilterGrammar> {
\**********************************************/
void cSearch::pushEndBrackedExp(const char){
- MESSAGE("Pushing closing bracket");
+ MESSAGE(VERBOSE_PARSERS, "Pushing closing bracket");
if(asprintf(&this->SQLWhereStmt, "%s)", this->SQLWhereStmt)==-1){
ERROR("Unable to allocate SQL Statement");
return;
@@ -369,21 +379,21 @@ void cSearch::pushExpression(const char*, const char*){
long int IntegerValue;
if(sscanf(Value, "%ld", &IntegerValue)!=EOF && sscanf(Value, "%*4d-%*2d-%*2d")==EOF){
- MESSAGE("Popping '%s %s %ld'",Property, Operator, IntegerValue);
+ MESSAGE(VERBOSE_PARSERS, "Popping '%s %s %ld'",Property, Operator, IntegerValue);
if(asprintf(&Statement, "%s %s %ld", Property, Operator, IntegerValue)==-1){
ERROR("Failed to allocated memory for statement.");
return;
}
}
else if(!strcasecmp(Operator, "IS")){
- MESSAGE("Popping '%s %s %s'", Property, Operator, Value);
+ MESSAGE(VERBOSE_PARSERS, "Popping '%s %s %s'", Property, Operator, Value);
if(asprintf(&Statement, "%s %s %s", Property, Operator, Value)==-1){
ERROR("Failed to allocated memory for statement.");
return;
}
}
else {
- MESSAGE("Popping '%s %s \"%s\"'",Property, Operator, Value);
+ MESSAGE(VERBOSE_PARSERS, "Popping '%s %s \"%s\"'",Property, Operator, Value);
if(asprintf(&Statement, "%s %s '%s'", Property, Operator, Value)==-1){
ERROR("Failed to allocated memory for statement.");
return;
@@ -401,12 +411,12 @@ void cSearch::pushExpression(const char*, const char*){
void cSearch::pushProperty(const char* Property){
this->CurrentProperty = strdup(Property);
- MESSAGE("Property %s added",Property);
+ MESSAGE(VERBOSE_PARSERS, "Property %s added",Property);
}
void cSearch::pushOperator(const char* Operator){
this->CurrentOperator = strdup(Operator);
- MESSAGE("Operator %s added",Operator);
+ MESSAGE(VERBOSE_PARSERS, "Operator %s added",Operator);
}
void cSearch::pushValue(const char* Start, const char* End){
@@ -414,13 +424,13 @@ void cSearch::pushValue(const char* Start, const char* End){
if(!Value || !strcmp(Value,"")) return;
this->CurrentValue = strdup(Value);
- MESSAGE("Value %s added", Value);
+ MESSAGE(VERBOSE_PARSERS, "Value %s added", Value);
}
void cSearch::pushExistance(const char* Exists){
this->CurrentValue = strdup(Exists);
this->CurrentOperator = strdup("IS");
- MESSAGE("Existance expression called. '%s'", Exists);
+ MESSAGE(VERBOSE_PARSERS, "Existance expression called. '%s'", Exists);
}
void cSearch::pushConcatOp(const char* Operator){
@@ -429,11 +439,11 @@ void cSearch::pushConcatOp(const char* Operator){
return;
}
- MESSAGE("Concatenation expression called. '%s'", Operator);
+ MESSAGE(VERBOSE_PARSERS, "Concatenation expression called. '%s'", Operator);
}
void cSearch::pushStartBrackedExp(const char){
- MESSAGE("Pushing opening bracket");
+ MESSAGE(VERBOSE_PARSERS, "Pushing opening bracket");
if(asprintf(&this->SQLWhereStmt, "%s(", this->SQLWhereStmt)==-1){
ERROR("Unable to allocate SQL Statement");
return;
@@ -478,13 +488,13 @@ bool cSearch::parseCriteria(const char* Search){
pushConcatOpCB,
startBrackedExpCB);
- MESSAGE("Starting search parsing");
+ MESSAGE(VERBOSE_PARSERS, "Starting search parsing");
if(boost::spirit::parse(Search, Grammar).full){
- MESSAGE("Parsing successful");
+ MESSAGE(VERBOSE_DIDL, "Parsed search expression successfuly");
}
else {
- ERROR("Parsing failed");
+ ERROR("Parsing search expression failed");
return false;
}
return true;
@@ -532,7 +542,7 @@ bool cFilterCriteria::parseFilter(const char* Filter){
this->mFilterList = new cStringList;
if(Filter && !strcasecmp(Filter, "")){
- MESSAGE("Empty filter");
+ MESSAGE(VERBOSE_PARSERS, "Empty filter");
return true;
}
@@ -542,7 +552,7 @@ bool cFilterCriteria::parseFilter(const char* Filter){
cFilterGrammar Grammar(pushPropertyCB, pushAsteriskCB);
if(boost::spirit::parse(Filter, Grammar).full){
- MESSAGE("Parse filter successful");
+ MESSAGE(VERBOSE_PARSERS, "Parse filter successful");
}
else {
ERROR("Parsing filter failed");
@@ -558,12 +568,12 @@ bool cFilterCriteria::parseFilter(const char* Filter){
\**********************************************/
void cFilterCriteria::pushProperty(const char* Property){
- MESSAGE("Pushing property");
+ MESSAGE(VERBOSE_PARSERS, "Pushing property");
this->mFilterList->Append(strdup(Property));
}
void cFilterCriteria::pushAsterisk(const char){
- MESSAGE("Pushing asterisk (*)");
+ MESSAGE(VERBOSE_PARSERS, "Pushing asterisk (*)");
if(this->mFilterList) delete this->mFilterList;
this->mFilterList = NULL;
return;
@@ -596,7 +606,7 @@ cList<cSortCrit>* cSortCriteria::parse(const char* Sort){
bool cSortCriteria::parseSort(const char* Sort){
if(!Sort || !strcasecmp(Sort, "")){
- MESSAGE("Empty Sort");
+ MESSAGE(VERBOSE_PARSERS, "Empty Sort");
return true;
}
@@ -606,7 +616,7 @@ bool cSortCriteria::parseSort(const char* Sort){
cSortGrammar Grammar(pushPropertyCB, pushDirectionCB);
if(boost::spirit::parse(Sort, Grammar).full){
- MESSAGE("Parse Sort successful");
+ MESSAGE(VERBOSE_PARSERS, "Parse Sort successful");
}
else {
ERROR("Parsing Sort failed");
@@ -622,14 +632,14 @@ bool cSortCriteria::parseSort(const char* Sort){
\**********************************************/
void cSortCriteria::pushProperty(const char* Property){
- MESSAGE("Pushing property '%s'", Property);
+ MESSAGE(VERBOSE_PARSERS, "Pushing property '%s'", Property);
this->mCurrentCrit->Property = strdup(Property);
this->mCriteriaList->Add(this->mCurrentCrit);
return;
}
void cSortCriteria::pushDirection(const char Direction){
- MESSAGE("Pushing direction '%c'", Direction);
+ MESSAGE(VERBOSE_PARSERS, "Pushing direction '%c'", Direction);
this->mCurrentCrit = new cSortCrit;
this->mCurrentCrit->SortDescending = (Direction=='-')?true:false;
return;
@@ -641,6 +651,7 @@ void cSortCriteria::pushDirection(const char Direction){
* *
\**********************************************/
+/** @private */
struct cWebserverSections : symbols<> {
cWebserverSections(){
add
@@ -649,6 +660,7 @@ struct cWebserverSections : symbols<> {
}
} WebserverSections;
+/** @private */
struct cWebserverMethods : symbols<int> {
cWebserverMethods(){
add
@@ -661,6 +673,7 @@ struct cWebserverMethods : symbols<int> {
}
} WebserverMethods;
+/** @private */
struct cPathParserGrammar : public boost::spirit::grammar<cPathParserGrammar> {
intCallback &pushSection;
@@ -678,6 +691,7 @@ struct cPathParserGrammar : public boost::spirit::grammar<cPathParserGrammar> {
pushPropertyValue(pushPropertyValue){}
template <typename scanner>
+ /** @private */
struct definition {
boost::spirit::rule<scanner> pathExp, section, method, methodProperties,
property, key, value, uncriticalChar;
@@ -742,7 +756,7 @@ bool cPathParser::parsePath(const char* Path, int* Section, int* Method, propert
cPathParserGrammar Grammar(pushSectionCB, pushMethodCB, pushPropertyKeyCB, pushPropertyValueCB);
if(boost::spirit::parse(Path, Grammar).full){
- MESSAGE("Parse path successful");
+ MESSAGE(VERBOSE_PARSERS, "Parse path successful");
*Section = this->mSection;
*Method = this->mMethod;
*Properties = this->mProperties;
@@ -765,7 +779,7 @@ bool cPathParser::parsePath(const char* Path, int* Section, int* Method, propert
void cPathParser::pushPropertyKey(const char* Start, const char* End){
char* Key = strndup(Start, End-Start);
- MESSAGE("Pushing key '%s'", Key);
+ MESSAGE(VERBOSE_PARSERS, "Pushing key '%s'", Key);
this->mKey = Key;
@@ -775,7 +789,7 @@ void cPathParser::pushPropertyKey(const char* Start, const char* End){
void cPathParser::pushPropertyValue(const char* Start, const char* End){
char* Value = strndup(Start, End-Start);
- MESSAGE("Pushing value '%s'", Value);
+ MESSAGE(VERBOSE_PARSERS, "Pushing value '%s'", Value);
// TODO: urlDecode Value
if(*this->mKey){
@@ -785,11 +799,11 @@ void cPathParser::pushPropertyValue(const char* Start, const char* End){
}
void cPathParser::pushMethod(int Method){
- MESSAGE("Pushing method '%d'", Method);
+ MESSAGE(VERBOSE_PARSERS, "Pushing method '%d'", Method);
this->mMethod = Method;
}
void cPathParser::pushSection(int Section){
- MESSAGE("Pushing section '%d'", Section);
+ MESSAGE(VERBOSE_PARSERS, "Pushing section '%d'", Section);
this->mSection = Section;
} \ No newline at end of file
diff --git a/misc/search.h b/misc/search.h
index df2442e..ef162b1 100644
--- a/misc/search.h
+++ b/misc/search.h
@@ -12,13 +12,27 @@
#include <vdr/tools.h>
#include "util.h"
+/**
+ * Sort criteria
+ *
+ * This is a structure for sorting objects. It has a certain property and
+ * a direction flag.
+ */
struct cSortCrit : public cListObject {
- const char* Property;
- bool SortDescending;
+ const char* Property; ///< the Property, which shall be sorted
+ bool SortDescending; ///< sort the objects in descending order
};
typedef std::map<const char*, const char*, strCmp> propertyMap;
+/**
+ * Web path parser
+ *
+ * Parses paths which came from the webserver. It splits the path into
+ * a section, a certain method and its properties.
+ *
+ * This can be used to easily determine which file was requested by a client
+ */
class cPathParser {
private:
cString mKey;
@@ -33,9 +47,30 @@ private:
cPathParser();
public:
virtual ~cPathParser();
- static bool parse(const char* Path, int* Section, int* Method, propertyMap* Properties);
+ /**
+ * Parses the path
+ *
+ * This will parse the path and stores the result in the pointers given.
+ *
+ * @return returns
+ * - \bc true, if the parsing was successful
+ * - \bc false, otherwise
+ */
+ static bool parse(
+ const char* Path, ///< the path which is parsed
+ int* Section, ///< the number of the registered section
+ int* Method, ///< the number of the registered method
+ propertyMap* Properties ///< the properties found in the path
+ );
};
+/**
+ * Creates a list with sort criteria
+ *
+ * This parser creates a list of sort criteria. It parses the sort criteria string
+ * from a \em Browse or \em Search request and stores the information in a \c cSortCrit
+ * structure.
+ */
class cSortCriteria {
private:
cSortCrit* mCurrentCrit;
@@ -47,9 +82,26 @@ private:
cSortCriteria();
public:
virtual ~cSortCriteria();
- static cList<cSortCrit>* parse(const char* Sort);
+ /**
+ * Parses the sort criteria
+ *
+ * This parses the sort criteria and returns a list with valid criterias
+ *
+ * @return returns
+ * - a list with valid sort criterias
+ * - \bc null, otherwise
+ */
+ static cList<cSortCrit>* parse(
+ const char* Sort ///< the string container the sort criteria
+ );
};
+/**
+ * Parses the filter criteria
+ *
+ * This parses the filter criteria which comes from a \em Browse or \em Search
+ * request.
+ */
class cFilterCriteria {
private:
cStringList* mFilterList;
@@ -60,9 +112,23 @@ private:
cStringList* getFilterList() const { return this->mFilterList; }
public:
virtual ~cFilterCriteria();
- static cStringList* parse(const char* Filter);
+ /**
+ * Parses the filter criteria
+ *
+ * This parses the filter criteria. It may be a empty string list, a \bc NULL
+ * pointer or a list with properties which shall be shown in the \em DIDL-Lite fragment.
+ *
+ * @return the stringlist containing the filter
+ */
+ static cStringList* parse(
+ const char* Filter ///< the filter string
+ );
};
+/**
+ * @private
+ * @todo This is implemented very soon
+ */
class cSearch {
private:
char* SQLWhereStmt;
diff --git a/misc/util.cpp b/misc/util.cpp
index dc75706..8cfc524 100644
--- a/misc/util.cpp
+++ b/misc/util.cpp
@@ -240,25 +240,6 @@ eOSState cMenuEditIpItem::ProcessKey(eKeys Key) {
return osContinue;
}
-const char* escapeSQLite(const char* Data, char** Buf){
- if(!Data){
- *Buf = NULL;
- }
- else {
- std::string NewData = "";
- int Char = 0;
- for(unsigned int i = 0; i < strlen(Data); i++){
- Char = Data[i];
- switch(Char){
- case L'\'': NewData += "''"; break;
- default: NewData += Data[i]; break;
- }
- }
- *Buf = strdup(NewData.c_str());
- }
- return (*Buf);
-}
-
const char* escapeXMLCharacters(const char* Data, char** Buf){
if(Data==NULL){
ERROR("Escape XML: No data to escape");
diff --git a/misc/util.h b/misc/util.h
index ffedd67..6ff2a54 100644
--- a/misc/util.h
+++ b/misc/util.h
@@ -14,19 +14,116 @@
#ifdef __cplusplus
extern "C" {
-struct strCmp { bool operator()(const char* s1, const char* s2) const { return (strcmp(s1,s2) < 0); }};
+#if 0
+}
+#endif
+/**
+ * Compares two strings
+ *
+ * This struct compares two strings and returns true on equality or false otherwise
+ * It is used in conjuction with hashmaps
+ */
+struct strCmp {
+ /**
+ * Compares two strings
+ * @return returns
+ * - \bc true, in case of equality
+ * - \bc false, otherwise
+ * @param s1 the first string
+ * @param s2 the second string
+ */
+ bool operator()(const char* s1, const char* s2) const { return (strcmp(s1,s2) < 0); }
+};
+/**
+ * Gets the IP address
+ *
+ * Returns the IP address of a given interface. The interface must be a valid interface
+ * identifier like eth0 or wlan1.
+ *
+ * @return a structure containing the IP address
+ * @param Interface to obtain the IP from
+ */
const sockaddr_in* getIPFromInterface(const char* Interface);
+/**
+ * Gets the MAC address
+ *
+ * Returns a string representation of the MAC address of a given interface. The interface
+ * must be a valid interface identifier like eth0 or wlan1.
+ *
+ * The pattern of the address is sixth byte hex number separated with ":"
+ *
+ * @return a string containing the MAC
+ * @param Interface to obtain the MAC from
+ */
const char* getMACFromInterface(const char* Interface);
+/**
+ * List with interfaces
+ *
+ * Returns an array with interfaces found on the system. The number of items
+ * in the array is stored in the parameter \c count.
+ *
+ * @return array list of interfaces
+ * @param count number of interfaces in the array
+ */
char** getNetworkInterfaces(int *count);
+/**
+ * First occurance of item
+ *
+ * Finds the first occurance of a specified item in a given \bc IXML document and returns its value.
+ * If an error occures, its code is stored in the last parameter \c 'error'.
+ *
+ * @return the value of the item
+ * @param doc the \c IXML document to be parsed
+ * @param item the item which shall be found
+ * @param error the error code in case of an error
+ */
char* ixmlGetFirstDocumentItem( IN IXML_Document * doc, IN const char *item, int* error );
+/**
+ * Adds a property
+ *
+ * This adds a UPnP property to an \bc IXML document.
+ * The property must have the pattern "namespace:property@attribute".
+ *
+ * @return returns
+ * - \bc <0, in case of an error
+ * - \bc 0, otherwise
+ * @param document the \c IXML document to put the parameter in
+ * @param node the specific node where to put the parameter
+ * @param upnpproperty the upnp property
+ * @param value the value of the upnp property
+ */
int ixmlAddProperty(IN IXML_Document* document, IN IXML_Element* node, const char* upnpproperty, const char* value );
+/**
+ * creates a part of a string
+ *
+ * This creates a substring of a string which begins at the given offset and has the
+ * specified lenght.
+ *
+ * @return the new string
+ * @param str the full string
+ * @param offset the starting index
+ * @param length the length of the new string
+ */
char* substr(const char* str, unsigned int offset, unsigned int length);
+#if 0
+{
+#endif
}
#endif
-const char* escapeSQLite(const char* Data, char** Buf);
+/**
+ * Escapes XML special characters
+ *
+ * This function escapes XML special characters, which must be transformed before
+ * inserting it into another XML document.
+ *
+ * @return the escaped document
+ * @param Data the data to escape
+ * @param Buf the pointer where the escaped document shall be stored
+ */
const char* escapeXMLCharacters(const char* Data, char** Buf);
+/** @private */
class cMenuEditIpItem: public cMenuEditItem {
private:
char *value;
diff --git a/receiver/filehandle.h b/receiver/filehandle.h
index 37f06e8..1dc57bf 100644
--- a/receiver/filehandle.h
+++ b/receiver/filehandle.h
@@ -11,12 +11,94 @@
#include <upnp/upnp.h>
#include "../common.h"
+/**
+ * Interface for File Handles
+ *
+ * This class is a pure virtual class to act as an interface for file handles
+ * used by the webserver.
+ */
class cFileHandle {
public:
- virtual void open(UpnpOpenFileMode mode) = 0;
- virtual int read(char* buf, size_t buflen) = 0;
- virtual int write(char* buf, size_t buflen) = 0;
- virtual int seek(off_t offset, int whence) = 0;
+ /**
+ * Opens the file
+ *
+ * Opens the file at the given mode. These can be:
+ * - \b UPNP_READ, to read from the file
+ * - \b UPNP_WRITE, to write to the file
+ *
+ * @param mode The file mode, i.e. one of the following
+ * - \b UPNP_READ
+ * - \b UPNP_WRITE
+ */
+ virtual void open(
+ UpnpOpenFileMode mode ///< The file mode, i.e. one of the following
+ ///< - \b UPNP_READ
+ ///< - \b UPNP_WRITE
+ ) = 0;
+ /**
+ * Reads from the file
+ *
+ * Reads from the file a certain amount of bytes and stores them in a buffer
+ *
+ * @return returns
+ * - \b <0, in case of an error
+ * - \b 0, when reading was successful
+ *
+ * @param buf The char buffer
+ * @param buflen The size of the buffer
+ */
+ virtual int read(
+ char* buf, ///< The char buffer
+ size_t buflen ///< The size of the buffer
+ ) = 0;
+ /**
+ * Writes to the file
+ *
+ * Writes to the file a certain amount of bytes which are stored in a buffer
+ *
+ * @return returns
+ * - \b <0, in case of an error
+ * - \b 0, when reading was successful
+ *
+ * @param buf The char buffer
+ * @param buflen The size of the buffer
+ */
+ virtual int write(
+ char* buf, ///< The char buffer
+ size_t buflen ///< The size of the buffer
+ ) = 0;
+ /**
+ * Seeks in the file
+ *
+ * Seeks in the file where the offset is the relativ position depending on
+ * the second parameter. This means, in case of
+ *
+ * - \b SEEK_SET, the offset is relative to the beginning of the file
+ * - \b SEEK_CUR, it is relative to the current position or
+ * - \b SEEK_END, relative to the end of the file.
+ *
+ * @return returns
+ * - \b <0, in case of an error
+ * - \b 0, when reading was successful
+ *
+ * @param offset The byte offset in the file
+ * @param whence one of the following
+ * - \b SEEK_SET,
+ * - \b SEEK_CUR,
+ * - \b SEEK_END
+ */
+ virtual int seek(
+ off_t offset, ///< The byte offset in the file
+ int whence ///< one of the following
+ ///< - \b SEEK_SET,
+ ///< - \b SEEK_CUR,
+ ///< - \b SEEK_END
+ ) = 0;
+ /**
+ * Closes the open file
+ *
+ * This will close open file handles and frees the memory obtained by it.
+ */
virtual void close() = 0;
virtual ~cFileHandle(){};
private:
diff --git a/receiver/livereceiver.cpp b/receiver/livereceiver.cpp
index 189f4a4..8ca560f 100644
--- a/receiver/livereceiver.cpp
+++ b/receiver/livereceiver.cpp
@@ -22,7 +22,7 @@ cLiveReceiver* cLiveReceiver::newInstance(cChannel* Channel, int Priority){
cLiveReceiver *Receiver = new cLiveReceiver(Channel, Device);
if(Receiver){
- MESSAGE("Receiver for channel \"%s\" created successfully.", Channel->Name());
+ MESSAGE(VERBOSE_SDK, "Receiver for channel \"%s\" created successfully.", Channel->Name());
return Receiver;
}
else {
@@ -62,13 +62,13 @@ void cLiveReceiver::open(UpnpOpenFileMode){
void cLiveReceiver::Activate(bool On){
if(On){
this->Start();
- MESSAGE("Live receiver started.");
+ MESSAGE(VERBOSE_LIVE_TV, "Live receiver started.");
}
else {
if(this->Running()){
this->Cancel(2);
}
- MESSAGE("Live receiver stopped");
+ MESSAGE(VERBOSE_LIVE_TV, "Live receiver stopped");
}
}
@@ -82,20 +82,20 @@ void cLiveReceiver::Receive(uchar* Data, int Length){
}
void cLiveReceiver::Action(void){
- MESSAGE("Started buffering...");
+ MESSAGE(VERBOSE_LIVE_TV, "Started buffering...");
while(this->Running()){
int bytesRead;
- //MESSAGE("Buffer is filled with %d bytes", this->mLiveBuffer->Available());
+ MESSAGE(VERBOSE_BUFFERS, "Buffer is filled with %d bytes", this->mLiveBuffer->Available());
uchar* bytes = this->mLiveBuffer->Get(bytesRead);
if(bytes){
int count = this->mFrameDetector->Analyze(bytes, bytesRead);
if(count){
- //MESSAGE("%d bytes analyzed", count);
- //MESSAGE("%2.2f FPS", this->mFrameDetector->FramesPerSecond());
+ MESSAGE(VERBOSE_BUFFERS, "%d bytes analyzed", count);
+ MESSAGE(VERBOSE_BUFFERS, "%2.2f FPS", this->mFrameDetector->FramesPerSecond());
if(!this->Running() && this->mFrameDetector->IndependentFrame())
break;
if(this->mFrameDetector->Synced()){
- //MESSAGE("Frame detector synced to data stream");
+ MESSAGE(VERBOSE_BUFFERS, "Frame detector synced to data stream");
if(this->mFrameDetector->IndependentFrame()){
this->mOutputBuffer->Put(this->mPatPmtGenerator.GetPat(), TS_SIZE);
int i = 0;
@@ -107,7 +107,7 @@ void cLiveReceiver::Action(void){
if(bytesWrote != count){
this->mLiveBuffer->ReportOverflow(count - bytesWrote);
}
- //MESSAGE("Wrote %d to output buffer", bytesWrote);
+ MESSAGE(VERBOSE_BUFFERS, "Wrote %d to output buffer", bytesWrote);
if(bytesWrote){
this->mLiveBuffer->Del(bytesWrote);
}
@@ -121,7 +121,7 @@ void cLiveReceiver::Action(void){
}
}
}
- MESSAGE("Receiver was detached from device");
+ MESSAGE(VERBOSE_LIVE_TV, "Receiver was detached from device");
}
int cLiveReceiver::read(char* buf, size_t buflen){
@@ -135,7 +135,7 @@ int cLiveReceiver::read(char* buf, size_t buflen){
WARNING("Too few data, waiting...");
cCondWait::SleepMs(RECEIVER_WAIT_ON_NODATA);
if(!this->IsAttached()){
- MESSAGE("Lost device...");
+ MESSAGE(VERBOSE_LIVE_TV, "Lost device...");
return 0;
}
WaitTimeout-=RECEIVER_WAIT_ON_NODATA;
@@ -160,7 +160,7 @@ int cLiveReceiver::read(char* buf, size_t buflen){
}
}
- MESSAGE("Read %d bytes from live feed", bytesRead);
+ MESSAGE(VERBOSE_BUFFERS, "Read %d bytes from live feed", bytesRead);
return bytesRead;
}
@@ -175,10 +175,10 @@ int cLiveReceiver::write(char*, size_t){
}
void cLiveReceiver::close(){
- MESSAGE("Closing live receiver");
+ MESSAGE(VERBOSE_SDK, "Closing live receiver");
this->Detach();
delete this->mOutputBuffer; this->mOutputBuffer = NULL;
delete this->mLiveBuffer; this->mLiveBuffer = NULL;
this->mFrameDetector = NULL;
- MESSAGE("Live receiver closed.");
+ MESSAGE(VERBOSE_LIVE_TV, "Live receiver closed.");
} \ No newline at end of file
diff --git a/receiver/livereceiver.h b/receiver/livereceiver.h
index 6b04619..92fe140 100644
--- a/receiver/livereceiver.h
+++ b/receiver/livereceiver.h
@@ -17,18 +17,78 @@
#define RECEIVER_WAIT_ON_NODATA 50 // 50 ms
#define RECEIVER_WAIT_ON_NODATA_TIMEOUT 1000 * 2 // 2s
+/**
+ * A receiver for live TV
+ *
+ * This is a receiver object which is attached to a VDR tv card device.
+ * It is receiving transport stream packages and generates a single MPEG2
+ * transport stream which can be distributed through the network.
+ *
+ */
class cLiveReceiver : public cReceiver, public cThread, public cFileHandle {
public:
- static cLiveReceiver* newInstance(cChannel *Channel, int Priority);
+ /**
+ * Creates a new receiver instance
+ *
+ * This will create a new instance of a live receiver for the specified
+ * channel at the specified priority level.
+ *
+ * A negativ priority means that the receiver may being detached from a
+ * device.
+ *
+ * The receiver must be free'd with delete after it is not used anylonger.
+ *
+ * @return returns a new liveReceiver instance
+ */
+ static cLiveReceiver* newInstance(
+ cChannel *Channel, ///< the channel which shall be tuned
+ int Priority ///< the priority level
+ );
virtual ~cLiveReceiver(void);
+ /*! @copydoc cFileHandle::open(UpnpOpenFileMode) */
virtual void open(UpnpOpenFileMode mode);
+ /*! @copydoc cFileHandle::read(char*,size_t) */
virtual int read(char* buf, size_t buflen);
+ /*! @copydoc cFileHandle::write(char*,size_t) */
virtual int write(char* buf, size_t buflen);
+ /*! @copydoc cFileHandle::seek(off_t,int) */
virtual int seek(off_t offset, int whence);
+ /*! @copydoc cFileHandle::close() */
virtual void close();
protected:
- virtual void Receive(uchar *Data, int Length);
- virtual void Activate(bool On);
+ /**
+ * Receives data from VDR
+ *
+ * This is the interface for receiving packet data from the VDR. It buffers
+ * the incoming transport stream packets in a linear ringbuffer and returns
+ * immediatelly
+ */
+ virtual void Receive(
+ uchar *Data, ///< The data received from VDR
+ int Length ///< The length of the data packet, usually 188 bytes
+ );
+ /**
+ * Activates the receiver
+ *
+ * This activates the receiver which initializes internal data structures to
+ * be prepared for receiving data from the VDR
+ *
+ * If the parameter is \bc true, the receiver will be activated. If it is
+ * \bc false, the receiver will be deactivated and stops its threads.
+ */
+ virtual void Activate(
+ bool On ///< Activates the receiver thread
+ );
+ /**
+ * The receiver thread action
+ *
+ * This actually is the receiver thread, which runs consequitivelly and
+ * buffers any received video data from the interal incoming buffer to the
+ * internal outgoing buffer.
+ *
+ * While doing so, it tries to syncronize with the stream and creates new
+ * MPEG2-TS PATs and PMTs for a single MPEG2-TS stream
+ */
virtual void Action(void);
private:
cLiveReceiver(cChannel *Channel, cDevice *Device);
diff --git a/receiver/recplayer.cpp b/receiver/recplayer.cpp
index d968ae7..a9ea85b 100644
--- a/receiver/recplayer.cpp
+++ b/receiver/recplayer.cpp
@@ -25,7 +25,7 @@ cRecordingPlayer::~cRecordingPlayer() {
}
cRecordingPlayer::cRecordingPlayer(cRecording *Recording) {
- MESSAGE("Created Recplayer");
+ MESSAGE(VERBOSE_SDK, "Created Recplayer");
this->mFile = NULL;
this->mTotalLenght = 0;
this->mRecording = Recording;
@@ -118,11 +118,11 @@ int cRecordingPlayer::seek(off_t offset, int origin){
}
void cRecordingPlayer::Scan(){
- MESSAGE("Scanning video files...");
+ MESSAGE(VERBOSE_RECORDS, "Scanning video files...");
// Reset the offsets
int i = 1;
while(this->mOffsets[i++]) this->mOffsets[i] = 0;
- MESSAGE("Offsets reseted.");
+ MESSAGE(VERBOSE_RECORDS, "Offsets reseted.");
i = 0;
FILE *File;
@@ -133,7 +133,7 @@ void cRecordingPlayer::Scan(){
}
fseek(File, 0, SEEK_END);
off_t offset = ftell(File);
- MESSAGE("File %d has its last offset at %ld", i, offset);
+ MESSAGE(VERBOSE_RECORDS, "File %d has its last offset at %ld", i, offset);
this->mOffsets[i+1] = this->mOffsets[i] + offset;
this->mTotalLenght = this->mOffsets[i+1];
i++;
@@ -150,7 +150,7 @@ FILE *cRecordingPlayer::GetFile(int Index){
if(this->mFile) fclose(this->mFile);
char *filename = new char[VDR_FILENAME_BUFSIZE];
snprintf(filename, VDR_FILENAME_BUFSIZE, VDR_RECORDFILE_PATTERN_TS, this->mRecording->FileName(), Index );
- MESSAGE("Filename: %s", filename);
+ MESSAGE(VERBOSE_BUFFERS, "Filename: %s", filename);
this->mFile = NULL;
if(this->mFile = fopen(filename, "r")){
this->mIndex = Index;
diff --git a/receiver/recplayer.h b/receiver/recplayer.h
index 8295539..a2e69ac 100644
--- a/receiver/recplayer.h
+++ b/receiver/recplayer.h
@@ -12,8 +12,26 @@
#include "filehandle.h"
#include <vdr/recording.h>
+/**
+ * The recording player
+ *
+ * This class provides the ability to play VDR records. The difference between
+ * usual files and VDR recording files is, that recordings are possibly splitted
+ * into multiple files. The class will scan those files and tries to dynamically
+ * navigate in them like it would do, if it is a single file.
+ *
+ */
class cRecordingPlayer : cFileHandle {
public:
+ /**
+ * Get a new instance of a recording player
+ *
+ * This returns a new instance of a recording player which plays the
+ * specified VDR recording.
+ *
+ * @param Recording the recording to play
+ * @return the new instance of the recording player
+ */
static cRecordingPlayer *newInstance(cRecording *Recording);
virtual ~cRecordingPlayer();
virtual void open(UpnpOpenFileMode mode);
diff --git a/server/server.cpp b/server/server.cpp
index 03750bd..d98c78b 100644
--- a/server/server.cpp
+++ b/server/server.cpp
@@ -50,7 +50,7 @@ cUPnPServer::~cUPnPServer() {
bool cUPnPServer::init(void){
- MESSAGE("Loading configuration...");
+ MESSAGE(VERBOSE_SDK, "Loading configuration...");
cUPnPConfig* config = cUPnPConfig::get();
this->enable(config->mEnable == 1 ? true : false);
if(!config->mAutoSetup){
@@ -80,7 +80,7 @@ bool cUPnPServer::init(void){
}
}
- MESSAGE("Initializing Intel UPnP SDK on %s:%d",inet_ntoa(this->mServerAddr->sin_addr), ntohs(this->mServerAddr->sin_port));
+ MESSAGE(VERBOSE_SDK, "Initializing Intel UPnP SDK on %s:%d",inet_ntoa(this->mServerAddr->sin_addr), ntohs(this->mServerAddr->sin_port));
int ret = 0;
ret = UpnpInit(inet_ntoa(this->mServerAddr->sin_addr), ntohs(this->mServerAddr->sin_port));
@@ -98,18 +98,18 @@ bool cUPnPServer::init(void){
ERROR("Unable to set IP address");
}
this->mServerAddr->sin_port = htons(UpnpGetServerPort());
- MESSAGE("Initializing succesfully at %s:%d", UpnpGetServerIpAddress(), UpnpGetServerPort());
+ MESSAGE(VERBOSE_SDK, "Initializing succesfully at %s:%d", UpnpGetServerIpAddress(), UpnpGetServerPort());
}
- MESSAGE("Setting maximum packet size for SOAP requests");
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Setting maximum packet size for SOAP requests");
UpnpSetMaxContentLength(UPNP_SOAP_MAX_LEN);
//set the root directory of the webserver
cString WebserverRootDir = cString::sprintf("%s%s", cPluginUpnp::getConfigDirectory(), UPNP_WEB_SERVER_ROOT_DIR);
- MESSAGE("Set web server root dir: %s", *WebserverRootDir );
+ MESSAGE(VERBOSE_SDK, "Set web server root dir: %s", *WebserverRootDir );
this->mWebServer = cUPnPWebServer::getInstance(WebserverRootDir);
- MESSAGE("Initializing web server.");
+ MESSAGE(VERBOSE_SDK, "Initializing web server.");
if (!this->mWebServer->init()) {
ERROR("Error while setting web server root dir - Errorcode: %d", ret);
return false;
@@ -120,7 +120,7 @@ bool cUPnPServer::init(void){
this->mDeviceDescription = cString(cDlna::getInstance()->getDeviceDescription(URLBase),true);
- MESSAGE("Register Media Server Device");
+ MESSAGE(VERBOSE_SDK, "Register Media Server Device");
ret = UpnpRegisterRootDevice2(UPNPREG_BUF_DESC,
this->mDeviceDescription, sizeof(this->mDeviceDescription), 1,
&cUPnPServer::upnpActionCallback,
@@ -131,14 +131,14 @@ bool cUPnPServer::init(void){
return false;
}
- MESSAGE("Unregister server to cleanup previously started servers");
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Unregister server to cleanup previously started servers");
ret = UpnpUnRegisterRootDevice(this->mDeviceHandle);
if (ret != UPNP_E_SUCCESS) {
WARNING("Unregistering old devices failed");
return false;
}
- MESSAGE("Register Media Server Device");
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Register Media Server Device");
ret = UpnpRegisterRootDevice2(UPNPREG_BUF_DESC,
this->mDeviceDescription, sizeof(this->mDeviceDescription), 1,
&cUPnPServer::upnpActionCallback,
@@ -149,16 +149,16 @@ bool cUPnPServer::init(void){
return false;
}
- MESSAGE("Initializing media database");
+ MESSAGE(VERBOSE_SDK, "Initializing media database");
this->mMediaDatabase = new cMediaDatabase;
if(!this->mMediaDatabase->init()){
ERROR("Error while initializing database");
return false;
}
- MESSAGE("Initializing connection manager");
+ MESSAGE(VERBOSE_SDK, "Initializing connection manager");
cUPnPServer::mConnectionManager = new cConnectionManager(this->mDeviceHandle);
- MESSAGE("Initializing content directory");
+ MESSAGE(VERBOSE_SDK, "Initializing content directory");
cUPnPServer::mContentDirectory = new cContentDirectory(this->mDeviceHandle, this->mMediaDatabase);
if(!cUPnPServer::mContentDirectory->Start()){
ERROR("Unable to start content directory thread");
@@ -166,7 +166,7 @@ bool cUPnPServer::init(void){
}
//send first advertisments
- MESSAGE("Send first advertisements to publish start in network");
+ MESSAGE(VERBOSE_SDK, "Send first advertisements to publish start in network");
ret = UpnpSendAdvertisement(this->mDeviceHandle, UPNP_ANNOUNCE_MAX_AGE);
if (ret != UPNP_E_SUCCESS) {
ERROR("Error while sending first advertisments - Errorcode: %d", ret);
@@ -177,20 +177,20 @@ bool cUPnPServer::init(void){
}
bool cUPnPServer::uninit(void) {
- MESSAGE("Shuting down content directory");
+ MESSAGE(VERBOSE_SDK, "Shuting down content directory");
delete cUPnPServer::mContentDirectory; cUPnPServer::mContentDirectory = NULL;
- MESSAGE("Shuting down connection manager");
+ MESSAGE(VERBOSE_SDK, "Shuting down connection manager");
delete cUPnPServer::mConnectionManager; cUPnPServer::mConnectionManager = NULL;
- MESSAGE("Closing metadata database");
+ MESSAGE(VERBOSE_SDK, "Closing metadata database");
delete this->mMediaDatabase; this->mMediaDatabase = NULL;
- MESSAGE("Closing the web server");
+ MESSAGE(VERBOSE_SDK, "Closing the web server");
this->mWebServer->uninit();
delete this->mWebServer;
- MESSAGE("Close Intel SDK");
+ MESSAGE(VERBOSE_SDK, "Close Intel SDK");
// unregiser media server device from UPnP SDK
int ret = UpnpUnRegisterRootDevice(this->mDeviceHandle);
if (ret != UPNP_E_SUCCESS) {
@@ -200,7 +200,7 @@ bool cUPnPServer::uninit(void) {
ret = UpnpFinish();
if (ret == UPNP_E_SUCCESS) {
- MESSAGE("Close Intel SDK Successfull");
+ MESSAGE(VERBOSE_SDK, "Close Intel SDK Successfull");
return true;
} else {
ERROR("Intel SDK unintialized or already closed - Errorcode: %d", ret);
@@ -277,7 +277,7 @@ bool cUPnPServer::autoDetectSettings(void){
char** Ifaces = getNetworkInterfaces(&count);
int i=0;
bool ret = false;
- MESSAGE("AUTODETECT: Found %d possible interfaces.", sizeof(Ifaces));
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "AUTODETECT: Found %d possible interfaces.", sizeof(Ifaces));
while(Ifaces[i]){
if(strcmp(Ifaces[i],"lo")!=0){
// true || false == true
@@ -288,7 +288,7 @@ bool cUPnPServer::autoDetectSettings(void){
}
delete [] Ifaces;
if(!ret){
- MESSAGE("AUTODETECT: No suitable interface. Giving up.");
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "AUTODETECT: No suitable interface. Giving up.");
return false;
}
this->setServerPort(0);
@@ -299,8 +299,8 @@ bool cUPnPServer::start(void){
if(!this->isRunning()){
// Put all the stuff which shall be started with the server in here
// if the startup failed due any reason return false!
- MESSAGE("Starting UPnP Server on %s:%d",inet_ntoa(this->getServerAddress()->sin_addr), ntohs(this->getServerAddress()->sin_port));
- MESSAGE("Using DLNA version: %s", DLNA_PROTOCOL_VERSION_STR);
+ MESSAGE(VERBOSE_SDK, "Starting UPnP Server on %s:%d",inet_ntoa(this->getServerAddress()->sin_addr), ntohs(this->getServerAddress()->sin_port));
+ MESSAGE(VERBOSE_SDK, "Using DLNA version: %s", DLNA_PROTOCOL_VERSION_STR);
this->mIsRunning = true;
// Start Media database thread
this->mMediaDatabase->Start();
@@ -310,7 +310,7 @@ bool cUPnPServer::start(void){
void cUPnPServer::stop(void){
if(this->isRunning()){
- MESSAGE("Call upnpServer STOP");
+ MESSAGE(VERBOSE_SDK, "Call upnpServer STOP");
this->uninit();
this->mIsRunning = false;
}
@@ -318,7 +318,7 @@ void cUPnPServer::stop(void){
}
bool cUPnPServer::restart(void){
- MESSAGE("Call upnpServer RESTART");
+ MESSAGE(VERBOSE_SDK, "Call upnpServer RESTART");
this->stop();
return this->start();
}
@@ -331,11 +331,11 @@ bool cUPnPServer::setInterface(const char* Interface){
if(Interface != NULL) this->mInterface = Interface;
if(*this->mInterface!=NULL){
- MESSAGE("Try to retrieve address for NIC %s",Interface);
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "Try to retrieve address for NIC %s",Interface);
const sockaddr_in* ipAddress = getIPFromInterface(Interface);
if(ipAddress!=NULL){
memcpy(&this->mServerAddr->sin_addr,&ipAddress->sin_addr,sizeof(ipAddress->sin_addr));
- MESSAGE("NIC %s has the following IP: %s", *this->mInterface, inet_ntoa(this->mServerAddr->sin_addr));
+ MESSAGE(VERBOSE_CUSTOM_OUTPUT, "NIC %s has the following IP: %s", *this->mInterface, inet_ntoa(this->mServerAddr->sin_addr));
this->stop();
return true;
}
diff --git a/server/server.h b/server/server.h
index 72ed2c8..c2a0e9a 100644
--- a/server/server.h
+++ b/server/server.h
@@ -20,6 +20,13 @@
#include "../upnpcomponents/contentdirectory.h"
#include "../upnp.h"
+/**
+ * The UPnP Server
+ *
+ * This is the core of the UPnP server. This handles all the components which
+ * are needed for a UPnP media server. Incoming messages are passed through it
+ * and it determines what to do.
+ */
class cUPnPServer {
friend class cPluginUpnp;
public:
@@ -42,7 +49,10 @@ public:
*
* This switch indicates if the server is startable or not
*
- * If it is set to FALSE, any invocation of start() will do nothing.
+ * If it is set to false, any invocation of start() will do nothing.
+ *
+ * @param enabled if \bc true, the server will be enabled. If \bc false it is
+ * disabled.
*/
void enable(bool enabled);
/**
@@ -50,7 +60,9 @@ public:
*
* This will start the UPnP server activities as a background task.
*
- * @return 1 when the server started successfully, 0 otherwise
+ * @return returns
+ * - \bc true, when the server started successfully
+ * - \bc false, otherwise
*/
bool start(void);
/**
@@ -60,7 +72,9 @@ public:
* It will stop the server functionalities, clear everything and
* start it again.
*
- * @return 1 when the server restarted successfully, 0 otherwise
+ * @return returns
+ * - \bc true, when the server restarted successfully
+ * - \bc false, otherwise
*/
bool restart(void);
/**
@@ -70,6 +84,16 @@ public:
* any clients and open ports will be closed.
*/
void stop(void);
+ /**
+ * Automatically detect settings
+ *
+ * This will automatically detect the network settings if the autodetection
+ * is turned on.
+ *
+ * @return returns
+ * - \bc true, if autoDetection was successful
+ * - \bc false, otherwise
+ */
bool autoDetectSettings(void);
/**
* Get the server address
@@ -82,7 +106,7 @@ public:
/**
* Get the interface the server listens to
*
- * Returns the network interface
+ * @return the network interface
*/
const char* getInterface(void) const { return this->mInterface; }
/**
@@ -98,13 +122,20 @@ public:
* Returns 1 when the port is valid, 0 otherwise
*
* @param port The port of the server
- * @return 1 if the new server address is set, 0 otherwise
+ * @return returns
+ * - \bc true, if the new server port is set
+ * - \bc false, otherwise
*/
bool setServerPort(unsigned short port);
/**
* The Interface to listen on
*
* Sets the listener interface, for instance 'eth1' or 'wlan0'
+ *
+ * @param Interface The interface of the server
+ * @return returns
+ * - \bc true, if the new server address is set
+ * - \bc false, otherwise
*/
bool setInterface(const char* Interface);
/**
@@ -115,7 +146,12 @@ public:
* changes through the system.
*
* This method should only be used in cases of fixed IP addresses
- * for example when no DHCP server is available.
+ * for example when no DHCP server is available.
+ *
+ * @param Address The address of the server
+ * @return returns
+ * - \bc true, if the new server address is set
+ * - \bc false, otherwise
*/
bool setAddress(const char* Address);
/**
@@ -123,6 +159,11 @@ public:
*
* If this is set to true, the setup will get it's information via
* auto detection
+ *
+ * @param enable \bc true enables and \bc false disables the auto detection
+ * @return returns
+ * - \bc true, if the new server address is set
+ * - \bc false, otherwise
*/
bool setAutoDetection(bool enable);
/**
@@ -130,7 +171,9 @@ public:
*
* This indicates if the server is currently enabled.
*
- * @return 1 if the server is enabled, 0 otherwise
+ * @return returns
+ * - \bc true, if the server is enabled
+ * - \bc false, otherwise
*/
bool isEnabled(void) const { return this->mIsEnabled; }
/**
@@ -138,13 +181,19 @@ public:
*
* If the server is enabled, this indicates if it is running.
*
- * @return 1 if the server is running, 0 otherwise
+ * @return returns
+ * - \bc true if the server is running
+ * - \bc false, otherwise
*/
bool isRunning(void) const { return this->mIsRunning; }
/**
* Is auto detection enabled or not
*
* Returns true or false if auto detection is enabled or not
+ *
+ * @return returns
+ * - \bc true, if autodetection is enabled
+ * - \bc false, otherwise
*/
bool isAutoDetectionEnabled() { return this->mIsAutoDetectionEnabled; }
protected:
diff --git a/upnp.cpp b/upnp.cpp
index 0aadcf0..1f8f4e4 100644
--- a/upnp.cpp
+++ b/upnp.cpp
@@ -65,7 +65,14 @@ const char *cPluginUpnp::CommandLineHelp(void)
" -p <port> --port=<port> The server port\n"
" Supported ports:\n"
" %5d (auto detect)\n"
- " %5d-%5d (user defined)\n",
+ " %5d-%5d (user defined)\n"
+ " -d --autodetect Force auto detection\n"
+ " Use this option to\n"
+ " overwrite the setup menu\n"
+ " options.\n"
+ " -v --verbose Increase verbosity level\n"
+ " The more v options the\n"
+ " higher the output level\n",
0,
SERVER_MIN_PORT,
SERVER_MAX_PORT
@@ -81,21 +88,21 @@ bool cPluginUpnp::ProcessArgs(int argc, char *argv[])
bool cPluginUpnp::Initialize(void)
{
// Initialize any background activities the plugin shall perform.
- MESSAGE("######### LETS GET READY TO RUMBLE #########");
+ MESSAGE(VERBOSE_SDK, "######### LETS GET READY TO RUMBLE #########");
cPluginUpnp::mConfigDirectory = strdup(cPlugin::ConfigDirectory(this->Name()));
if(!cPluginUpnp::getConfigDirectory()){
ERROR("Cannot set configuration directory");
return false;
}
- MESSAGE("Configuration directory: %s", cPluginUpnp::getConfigDirectory());
+ MESSAGE(VERBOSE_SDK, "Configuration directory: %s", cPluginUpnp::getConfigDirectory());
DatabaseLocker.Signal();
return this->mUpnpServer->init();
}
bool cPluginUpnp::Start(void)
{
- MESSAGE("Call plugin START");
+ MESSAGE(VERBOSE_SDK, "Call plugin START");
// Start any background activities the plugin shall perform.
return this->mUpnpServer->start();
//return true;
@@ -103,7 +110,7 @@ bool cPluginUpnp::Start(void)
void cPluginUpnp::Stop(void)
{
- MESSAGE("Call plugin STOP");
+ MESSAGE(VERBOSE_SDK, "Call plugin STOP");
// Stop any background activities the plugin is performing.
this->mUpnpServer->stop();
}
diff --git a/upnp.h b/upnp.h
index 5baa1cc..ab1b04a 100644
--- a/upnp.h
+++ b/upnp.h
@@ -15,6 +15,12 @@
class cUPnPServer;
+/**
+ * The UPnP/DLNA plugin
+ *
+ * This is a UPnP/DLNA media server plugin. It supports live-TV and recordings
+ * of the VDR as well as custom video files.
+ */
class cPluginUpnp : public cPlugin {
private:
// Add any member variables or functions you may need here.
@@ -23,20 +29,92 @@ private:
public:
cPluginUpnp(void);
virtual ~cPluginUpnp();
+ /**
+ * Get the version of the plugin
+ *
+ * Returns the version string of the plugin
+ *
+ * @return a string representation of the plugin version
+ */
virtual const char *Version(void);
+ /**
+ * Get the description
+ *
+ * This returns a brief description of the plugin and what it does.
+ *
+ * @return the description of the plugin
+ */
virtual const char *Description(void);
+ /**
+ * Get the command line help
+ *
+ * This returns the command line help output, which comes, when the user
+ * types \c --help into the command line.
+ *
+ * @return the command line help
+ */
virtual const char *CommandLineHelp(void);
+ /*! @copydoc cUPnPConfig::processArgs */
virtual bool ProcessArgs(int argc, char *argv[]);
+ /**
+ * Initializes the plugin
+ *
+ * This initializes any background activities of the plugin.
+ *
+ * @return returns
+ * - \bc true, if initializing was successful
+ * - \bc false, otherwise
+ */
virtual bool Initialize(void);
+ /**
+ * Starts the plugin
+ *
+ * This starts the plugin. It starts additional threads, which are required
+ * by the plugin.
+ *
+ * @return returns
+ * - \bc true, if starting was successful
+ * - \bc false, otherwise
+ */
virtual bool Start(void);
+ /**
+ * Stops the plugin
+ *
+ * This stops the plugin and all its components
+ */
virtual void Stop(void);
+ /**
+ * Message if still active
+ *
+ * This returns a message if the plugin is still active when a user attempts
+ * to shut down the VDR.
+ *
+ * @return the message shown on the screen.
+ */
virtual cString Active(void);
+ /**
+ * Setup menu
+ *
+ * This creates a new instance of the setup menu, which is shown to the user
+ * when he enters the VDR plugin setup menu
+ *
+ * @return the menu of the plugin
+ */
virtual cMenuSetupPage *SetupMenu(void);
+ /*! @copydoc cUPnPConfig::parseSetup */
virtual bool SetupParse(const char *Name, const char *Value);
+ /**
+ * Get the configuration directory
+ *
+ * This returns the directory, where configuration files are stored.
+ *
+ * @return the directory of the configuration files.
+ */
static const char* getConfigDirectory();
};
-extern cCondWait DatabaseLocker;
+extern cCondWait DatabaseLocker; ///< Locks the database to be loaded only if
+ ///< the configuration file directory is set
#endif /* _UPNP_H */
diff --git a/upnpcomponents/connectionmanager.cpp b/upnpcomponents/connectionmanager.cpp
index b2c7149..e0d9203 100644
--- a/upnpcomponents/connectionmanager.cpp
+++ b/upnpcomponents/connectionmanager.cpp
@@ -70,7 +70,7 @@ int cConnectionManager::execute(Upnp_Action_Request* Request){
}
int cConnectionManager::getProtocolInfo(Upnp_Action_Request* Request){
- MESSAGE("Protocol info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CMS, "Protocol info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
cString Result = cString::sprintf(
"<u:%sResponse xmlns:u=\"%s\"> \
<Source>%s</Source> \
@@ -87,7 +87,7 @@ int cConnectionManager::getProtocolInfo(Upnp_Action_Request* Request){
}
int cConnectionManager::getCurrentConnectionIDs(Upnp_Action_Request* Request){
- MESSAGE("Current connection IDs requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CMS, "Current connection IDs requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
cString Result;
const char* IDs = this->getConnectionIDsCVS();
if(!IDs){
@@ -109,7 +109,7 @@ int cConnectionManager::getCurrentConnectionIDs(Upnp_Action_Request* Request){
}
int cConnectionManager::getCurrentConnectionInfo(Upnp_Action_Request* Request){
- MESSAGE("Current connection info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CMS, "Current connection info requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
int ConnectionID;
if(this->parseIntegerValue(Request->ActionRequest, "ConnectionID", &ConnectionID) != 0){
@@ -156,7 +156,7 @@ int cConnectionManager::getCurrentConnectionInfo(Upnp_Action_Request* Request){
}
int cConnectionManager::prepareForConnection(Upnp_Action_Request* Request){
- MESSAGE("Request for a new connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CMS, "Request for a new connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
//char* Result = NULL;
char* RemoteProtocolInfo = NULL;
char* PeerConnectionManager = NULL;
@@ -198,7 +198,7 @@ int cConnectionManager::prepareForConnection(Upnp_Action_Request* Request){
}
int cConnectionManager::connectionComplete(Upnp_Action_Request* Request){
- MESSAGE("Request for closing an open connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CMS, "Request for closing an open connection by %s.", inet_ntoa(Request->CtrlPtIPAddr));
//char* Result = NULL;
int ConnectionID;
@@ -216,27 +216,27 @@ int cConnectionManager::connectionComplete(Upnp_Action_Request* Request){
return Request->ErrCode;
}
-bool cConnectionManager::setProtocolInfo(const char* ProtocolInfo){
- if(strcmp(this->mSupportedProtocols, ProtocolInfo)){
- // ProtocolInfo changed, save and invoke a event notification
- this->mSupportedProtocols = ProtocolInfo;
-
- IXML_Document* PropertySet = NULL;
- UpnpAddToPropertySet(&PropertySet, "SourceProtocolInfo", this->mSupportedProtocols);
- int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
- ixmlDocument_free(PropertySet);
-
- if(ret != UPNP_E_SUCCESS){
- ERROR("State change notification failed (Error code: %d)",ret);
- return false;
- }
- }
- return true;
-}
+//bool cConnectionManager::setProtocolInfo(const char* ProtocolInfo){
+// if(strcmp(this->mSupportedProtocols, ProtocolInfo)){
+// // ProtocolInfo changed, save and invoke a event notification
+// this->mSupportedProtocols = ProtocolInfo;
+//
+// IXML_Document* PropertySet = NULL;
+// UpnpAddToPropertySet(&PropertySet, "SourceProtocolInfo", this->mSupportedProtocols);
+// int ret = UpnpNotifyExt(this->mDeviceHandle, UPNP_DEVICE_UDN, UPNP_CMS_SERVICE_ID, PropertySet);
+// ixmlDocument_free(PropertySet);
+//
+// if(ret != UPNP_E_SUCCESS){
+// ERROR("State change notification failed (Error code: %d)",ret);
+// return false;
+// }
+// }
+// return true;
+//}
cVirtualConnection* cConnectionManager::createVirtualConnection(const char* RemoteProtocolInfo, const char* RemoteConnectionManager, int RemoteConnectionID, eDirection Direction){
static int lastConnectionID = 0;
- MESSAGE("Create virtual connection");
+ MESSAGE(VERBOSE_CMS, "Create virtual connection");
if(lastConnectionID == 2147483647) lastConnectionID = 1;
cVirtualConnection* Connection = new cVirtualConnection;
// AVT is available
@@ -268,7 +268,7 @@ cVirtualConnection* cConnectionManager::createVirtualConnection(const char* Remo
ERROR("State change notification failed (Error code: %d)",ret);
return NULL;
}
- MESSAGE("Notification of connection creation sent");
+ MESSAGE(VERBOSE_CMS, "Notification of connection creation sent");
this->mVirtualConnections->Add(Connection);
return Connection;
}
diff --git a/upnpcomponents/connectionmanager.h b/upnpcomponents/connectionmanager.h
index 202df59..4aa25f3 100644
--- a/upnpcomponents/connectionmanager.h
+++ b/upnpcomponents/connectionmanager.h
@@ -10,6 +10,11 @@
#include "upnpservice.h"
+/**
+ * Connection status
+ *
+ * The connection status of a certain virtual connection
+ */
enum eConnectionStatus {
OK,
CONTENT_FORMAT_MISMATCH,
@@ -18,11 +23,22 @@ enum eConnectionStatus {
UNKNOWN
};
+/**
+ * Direction
+ *
+ * The direction of a virtual connection. Input means client to server, Output
+ * server to client
+ */
enum eDirection {
OUTPUT,
INPUT
};
+/**
+ * Virtual connection
+ *
+ * A virtual connection managed by the connection manager service
+ */
class cVirtualConnection : public cListObject {
friend class cConnectionManager;
private:
@@ -41,15 +57,31 @@ private:
static int getConnectionStatus(const char* ConnectionStatus);
};
+/**
+ * The connection manager service
+ *
+ * This is the connection manager service which handles all incoming connection,
+ * creates and destroys connections to clients.
+ */
class cConnectionManager : public cUpnpService {
public:
- cConnectionManager(UpnpDevice_Handle DeviceHandle);
+ /**
+ * Constructor of a Connection manager
+ *
+ * This creates an instance of a <em>Connection Manager Service</em> and provides
+ * interfaces for executing actions and subscribing on events.
+ */
+ cConnectionManager(
+ UpnpDevice_Handle DeviceHandle ///< the UPnP device handle of this root device
+ );
virtual ~cConnectionManager();
- virtual int execute(Upnp_Action_Request* Request);
+ /*! @copydoc cUpnpService::subscribe(Upnp_Subscription_Request* Request) */
virtual int subscribe(Upnp_Subscription_Request* Request);
- bool setProtocolInfo(const char* ProtocolInfo);
-private:
+ /*! @copydoc cUpnpService::execute(Upnp_Action_Request* Request) */
+ virtual int execute(Upnp_Action_Request* Request);
+ /*! @copydoc cUpnpService::setError(Upnp_Action_Request* Request, int Error) */
virtual void setError(Upnp_Action_Request* Request, int Error);
+private:
int getProtocolInfo(Upnp_Action_Request* Request);
int getCurrentConnectionIDs(Upnp_Action_Request* Request);
int getCurrentConnectionInfo(Upnp_Action_Request* Request);
diff --git a/upnpcomponents/contentdirectory.cpp b/upnpcomponents/contentdirectory.cpp
index a9afdfa..494b638 100644
--- a/upnpcomponents/contentdirectory.cpp
+++ b/upnpcomponents/contentdirectory.cpp
@@ -40,7 +40,7 @@ int cContentDirectory::subscribe(Upnp_Subscription_Request* Request){
void cContentDirectory::Action(){
static int Retry = 5;
- MESSAGE("Start Content directory thread");
+ MESSAGE(VERBOSE_CDS, "Start Content directory thread");
while(this->Running()){
IXML_Document* PropertySet = NULL;
UpnpAddToPropertySet(&PropertySet, "SystemUpdateID", itoa(this->mMediaDatabase->getSystemUpdateID()));
@@ -84,7 +84,7 @@ int cContentDirectory::execute(Upnp_Action_Request* Request){
int cContentDirectory::browse(Upnp_Action_Request* Request){
- MESSAGE("Browse requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
+ MESSAGE(VERBOSE_CDS, "Browse requested by %s.", inet_ntoa(Request->CtrlPtIPAddr));
char* ObjectID = NULL;
if(this->parseStringValue(Request->ActionRequest, "ObjectID", &ObjectID)){
@@ -201,7 +201,7 @@ int cContentDirectory::getSystemUpdateID(Upnp_Action_Request* Request){
}
int cContentDirectory::getSearchCapabilities(Upnp_Action_Request* Request){
- MESSAGE("Sorry, no search capabilities yet");
+ MESSAGE(VERBOSE_CDS, "Sorry, no search capabilities yet");
cString Result = cString::sprintf(
"<u:%sResponse xmlns:u=\"%s\"> \
@@ -220,7 +220,7 @@ int cContentDirectory::getSearchCapabilities(Upnp_Action_Request* Request){
}
int cContentDirectory::getSortCapabilities(Upnp_Action_Request* Request){
- MESSAGE("Sorry, no sort capabilities yet");
+ MESSAGE(VERBOSE_CDS, "Sorry, no sort capabilities yet");
cString Result = cString::sprintf(
"<u:%sResponse xmlns:u=\"%s\"> \
diff --git a/upnpcomponents/contentdirectory.h b/upnpcomponents/contentdirectory.h
index a504fdc..7fb4bb9 100644
--- a/upnpcomponents/contentdirectory.h
+++ b/upnpcomponents/contentdirectory.h
@@ -12,12 +12,30 @@
#include "upnpservice.h"
#include "../database/metadata.h"
+/**
+ * The content directory service
+ *
+ * This is the content directory service which handles all incoming requests
+ * for contents managed by the media server.
+ */
class cContentDirectory : public cUpnpService, public cThread {
public:
- cContentDirectory(UpnpDevice_Handle DeviceHandle, cMediaDatabase* MediaDatabase);
+ /**
+ * Constructor of a Content Directory
+ *
+ * This creates an instance of a <em>Content Directory Service</em> and provides
+ * interfaces for executing actions and subscribing on events.
+ */
+ cContentDirectory(
+ UpnpDevice_Handle DeviceHandle, ///< The UPnP device handle of the root device
+ cMediaDatabase* MediaDatabase ///< the media database where requests are processed
+ );
virtual ~cContentDirectory();
+ /*! @copydoc cUpnpService::subscribe(Upnp_Subscription_Request* Request) */
virtual int subscribe(Upnp_Subscription_Request* Request);
+ /*! @copydoc cUpnpService::execute(Upnp_Action_Request* Request) */
virtual int execute(Upnp_Action_Request* Request);
+ /*! @copydoc cUpnpService::setError(Upnp_Action_Request* Request, int Error) */
virtual void setError(Upnp_Action_Request* Request, int Error);
private:
cMediaDatabase* mMediaDatabase;
diff --git a/upnpcomponents/dlna.cpp b/upnpcomponents/dlna.cpp
index eaa23c1..27f84f2 100644
--- a/upnpcomponents/dlna.cpp
+++ b/upnpcomponents/dlna.cpp
@@ -21,7 +21,7 @@ cDlna* cDlna::getInstance(void){
}
cDlna::cDlna() {
- this->mRegisteredProfiles = new cRegisteredProfiles;
+ this->mRegisteredProfiles = new cList<cRegisteredProfile>;
this->init();
}
@@ -47,6 +47,8 @@ void cDlna::registerProfile(DLNAProfile* Profile, int Op, const char* Ps, int Ci
void cDlna::registerMainProfiles(){
this->registerProfile(&DLNA_PROFILE_MPEG_TS_SD_EU, -1, NULL, -1, DLNA_FLAGS_PLUGIN_SUPPORT);
this->registerProfile(&DLNA_PROFILE_AVC_TS_HD_EU, -1, NULL, -1, DLNA_FLAGS_PLUGIN_SUPPORT);
+ this->registerProfile(&DLNA_PROFILE_MPEG_TS_SD_EU_ISO, -1, NULL, -1, DLNA_FLAGS_PLUGIN_SUPPORT);
+ this->registerProfile(&DLNA_PROFILE_AVC_TS_HD_EU_ISO, -1, NULL, -1, DLNA_FLAGS_PLUGIN_SUPPORT);
}
const char* cDlna::getSupportedProtocols(){
@@ -73,9 +75,9 @@ DLNAProfile* cDlna::getProfileOfChannel(cChannel* Channel){
switch(Channel->Vtype()){
case 0x02:
// MPEG2 Video
- return &DLNA_PROFILE_MPEG_TS_SD_EU;
+ return &DLNA_PROFILE_MPEG_TS_SD_EU_ISO;
case 0x1B:
- return &DLNA_PROFILE_AVC_TS_HD_EU;
+ return &DLNA_PROFILE_AVC_TS_HD_EU_ISO;
default:
ERROR("Unknown video type %d for channel %s!", Channel->Vtype(), Channel->Name());
return NULL;
diff --git a/upnpcomponents/dlna.h b/upnpcomponents/dlna.h
index c05d69a..80ac328 100644
--- a/upnpcomponents/dlna.h
+++ b/upnpcomponents/dlna.h
@@ -14,6 +14,12 @@
class cDlna;
+/**
+ * Registered DLNA profile
+ *
+ * This class contains information about a certain registered profile
+ * like play speeds or flags
+ */
class cRegisteredProfile : public cListObject {
friend class cDlna;
private:
@@ -27,10 +33,6 @@ public:
virtual ~cRegisteredProfile(){};
};
-class cRegisteredProfiles : public cList<cRegisteredProfile> {
- friend class cDlna;
-};
-
/**
* Enable DLNA compliant media transfer
*
@@ -41,23 +43,107 @@ class cRegisteredProfiles : public cList<cRegisteredProfile> {
class cDlna {
friend class cUPnPServer;
public:
+ /**
+ * Returns the instance of DLNA object
+ *
+ * This will create a DLNA object instance. It will return the same instance
+ * on subsequent calls.
+ *
+ * @return the DLNA object instance
+ */
static cDlna* getInstance(void);
virtual ~cDlna();
//const char* getProtocolInfo(UPnPObjectID OID);
- const char* getDeviceDescription(const char* URLBase);
- void registerProfile(DLNAProfile* Profile, int Op = -1, const char* Ps = NULL, int Ci = -1, unsigned int Flags = 0);
+ /**
+ * Device description document
+ *
+ * This will return the device description document with service type
+ * definitions as well as some DLNA specific information
+ *
+ * @return The description document
+ */
+ const char* getDeviceDescription(
+ const char* URLBase ///< the URLBase to be set in the document
+ );
+ /**
+ * Registeres a DLNA profile
+ *
+ * Registeres a DLNA profile with specific optional options
+ *
+ * @see common.h
+ */
+ void registerProfile(
+ DLNAProfile* Profile, ///< the DLNA profile
+ int Op = -1, ///< operation mode
+ const char* Ps = NULL, ///< play speed (CSV list)
+ int Ci = -1, ///< conversion indication flag
+ unsigned int Flags = 0 ///< DLNA flags
+ );
+ /**
+ * Registeres all known DLNA profiles
+ *
+ * Registeres all well known DLNA profiles with its known options
+ */
void registerMainProfiles();
+ /**
+ * CSV list of supported protocols
+ *
+ * Returns a comma separated list with all supported protocols. This
+ * means, it returns the list of protocols of the registered profiles.
+ *
+ * @return CSV list of registered protocols
+ */
const char* getSupportedProtocols();
- const char* getProtocolInfo(DLNAProfile *Prof);
- DLNAProfile* getProfileOfChannel(cChannel* Channel);
- DLNAProfile* getProfileOfRecording(cRecording* Recording);
- DLNAProfile* getProfileOfFile(cString File);
+ /**
+ * Protocol info of a specific DLNA profile
+ *
+ * Returns the protocol info string of a specific DLNA profile with its
+ * options and flags.
+ *
+ * @return the protocol info string of the profile
+ */
+ const char* getProtocolInfo(
+ DLNAProfile *Prof ///< the Profile of which the protocol info shall be returned
+ );
+ /**
+ * Profile of a channel
+ *
+ * Returns the DLNA profile of a VDR channel. It checks the video type to determine
+ * which profile will match.
+ *
+ * @return the matching DLNA profile
+ */
+ DLNAProfile* getProfileOfChannel(
+ cChannel* Channel ///< the channel of which the profile should created from
+ );
+ /**
+ * Profile of a recording
+ *
+ * Returns the DLNA profile of a VDR recording. It checks the video file to determine
+ * which profile will match.
+ *
+ * @return the matching DLNA profile
+ */
+ DLNAProfile* getProfileOfRecording(
+ cRecording* Recording ///< the recording of which the profile should be created from
+ );
+ /**
+ * Profile of a file
+ *
+ * Returns the DLNA profile of a file. It checks the content of the file with \em ffmpeg to
+ * determine which profile will match.
+ *
+ * @return the matching DLNA profile
+ */
+ DLNAProfile* getProfileOfFile(
+ cString File ///< the file of which the profile should be created from
+ );
private:
const char* getRegisteredProtocolInfoString(cRegisteredProfile *Profile);
cDlna();
void init(void);
static cDlna* mInstance;
- cRegisteredProfiles* mRegisteredProfiles;
+ cList<cRegisteredProfile>* mRegisteredProfiles;
};
#endif /* _DLNA_H */
diff --git a/upnpcomponents/upnpservice.cpp b/upnpcomponents/upnpservice.cpp
index a1d6a47..fc24cca 100644
--- a/upnpcomponents/upnpservice.cpp
+++ b/upnpcomponents/upnpservice.cpp
@@ -13,7 +13,7 @@ cUpnpService::cUpnpService(UpnpDevice_Handle DeviceHandle) {
this->mDeviceHandle = DeviceHandle;
}
-int cUpnpService::parseIntegerValue(IXML_Document* Document, const char* Item, int* Value){
+int cUpnpService::parseIntegerValue(IN IXML_Document* Document, IN const char* Item, OUT int* Value){
char* Val = NULL;
int Error = 0;
@@ -34,7 +34,7 @@ int cUpnpService::parseIntegerValue(IXML_Document* Document, const char* Item, i
return Error;
}
-int cUpnpService::parseStringValue(IXML_Document* Document, const char* Item, char** Value){
+int cUpnpService::parseStringValue(IN IXML_Document* Document, IN const char* Item, OUT char** Value){
char* Val = NULL;
int Error = 0;
diff --git a/upnpcomponents/upnpservice.h b/upnpcomponents/upnpservice.h
index c8630b5..df74d9b 100644
--- a/upnpcomponents/upnpservice.h
+++ b/upnpcomponents/upnpservice.h
@@ -10,17 +10,109 @@
#include <upnp/upnp.h>
+/**
+ * UPnP Service interface
+ *
+ * This is a service interface implemented by a UPnP service like CDS oder CMS
+ *
+ * It comes with some tool functions which are commonly useful for processing
+ * an event or action.
+ */
class cUpnpService {
public:
- cUpnpService(UpnpDevice_Handle DeviceHandle);
+ /**
+ * Constructor of a service
+ *
+ * @private
+ * @param DeviceHandle the UPnP device handle of this root device
+ */
+ cUpnpService(
+ UpnpDevice_Handle DeviceHandle ///< the UPnP device handle of this root device
+ );
virtual ~cUpnpService(){};
- virtual int subscribe(Upnp_Subscription_Request* Request) = 0;
- virtual int execute(Upnp_Action_Request* Request) = 0;
+ /**
+ * Subscribes to an event
+ *
+ * This is a callback function to register a new subscriber for an event.
+ *
+ * @return An integer representing one of the following:
+ * - \bc UPNP_E_SUCCESS, if subscription was okay
+ * - or any other non null value in case of an error
+ *
+ * @param Request Information about the subscription
+ */
+ virtual int subscribe(
+ Upnp_Subscription_Request* Request ///< Information about the subscription
+ ) = 0;
+ /**
+ * Executes an action
+ *
+ * This executes an action initialized by a control point. The result is
+ * stored in the first parameter.
+ *
+ * @return An integer representing one of the following:
+ * - \bc UPNP_E_SUCCESS, if subscription was okay
+ * - or any other non null value in case of an error
+ *
+ * @param Request Input and output parameters of an action
+ */
+ virtual int execute(
+ Upnp_Action_Request* Request ///< Input and output parameters of an action
+ ) = 0;
protected:
- virtual void setError(Upnp_Action_Request* Request, int Error);
- int parseIntegerValue(IN IXML_Document* Document, IN const char* Item, OUT int* Value);
- int parseStringValue(IN IXML_Document* Document, IN const char* Item, OUT char** Value);
- UpnpDevice_Handle mDeviceHandle;
+ /**
+ * Sets an error on an action request
+ *
+ * This function puts a error message into the action request structure
+ * according to its error code
+ *
+ * @param Request the action request, to set the error for
+ * @param Error the error code of which the message should be obtained
+ */
+ virtual void setError(
+ Upnp_Action_Request* Request, ///< the action request, to set the error for
+ int Error ///< the error code of which the message should be obtained
+ );
+ /**
+ * Parses an integer value
+ *
+ * This tool function parses an integer value from a given \em IXML document. It is searching
+ * for the very first occurance of the demanded item.
+ *
+ * @return Returns
+ * - \bc 0, if parsing was successful
+ * - \bc <0, if an error occured
+ *
+ * @param Document the document, which is parsed
+ * @param Item the demanded item
+ * @param Value the value of the item
+ */
+ int parseIntegerValue(
+ IN IXML_Document* Document, ///< the document, which is parsed
+ IN const char* Item, ///< the demanded item
+ OUT int* Value ///< the value of the item
+ );
+ /**
+ * Parses a string value
+ *
+ * This tool function parses a string value from a given \em IXML document. It is searching
+ * for the very first occurance of the demanded item.
+ *
+ * @return Returns
+ * - \bc 0, if parsing was successful
+ * - \bc <0, if an error occured
+ *
+ * @param Document the document, which is parsed
+ * @param Item the demanded item
+ * @param Value the value of the item
+ */
+ int parseStringValue(
+ IN IXML_Document* Document, ///< the document, which is parsed
+ IN const char* Item, ///< the demanded item
+ OUT char** Value ///< the value of the item
+ );
+
+ UpnpDevice_Handle mDeviceHandle; ///< the UPnP device handle of the root device
};
#endif /* _UPNPSERVICE_H */
diff --git a/upnpcomponents/upnpwebserver.cpp b/upnpcomponents/upnpwebserver.cpp
index 383b201..892f5b1 100644
--- a/upnpcomponents/upnpwebserver.cpp
+++ b/upnpcomponents/upnpwebserver.cpp
@@ -46,6 +46,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
+/** @private */
struct File_Info_
{
/** The length of the file. A length less than 0 indicates the size
@@ -73,6 +74,7 @@ struct File_Info_
};
+/** @private */
struct cWebFileHandle {
cString Filename;
off64_t Size;
@@ -108,13 +110,13 @@ UpnpVirtualDirCallbacks cUPnPWebServer::mVirtualDirCallbacks = {
};
bool cUPnPWebServer::init(){
- MESSAGE("Initialize callbacks for virtual directories.");
+ MESSAGE(VERBOSE_WEBSERVER, "Initialize callbacks for virtual directories.");
if(UpnpSetWebServerRootDir(this->mRootdir) == UPNP_E_INVALID_ARGUMENT){
ERROR("The root directory of the webserver is invalid.");
return false;
}
- MESSAGE("Setting up callbacks");
+ MESSAGE(VERBOSE_WEBSERVER, "Setting up callbacks");
if(UpnpSetVirtualDirCallbacks(&cUPnPWebServer::mVirtualDirCallbacks) == UPNP_E_INVALID_ARGUMENT){
ERROR("The virtual directory callbacks are invalid.");
@@ -126,7 +128,7 @@ bool cUPnPWebServer::init(){
return false;
}
- MESSAGE("Add virtual directories.");
+ MESSAGE(VERBOSE_WEBSERVER, "Add virtual directories.");
if(UpnpAddVirtualDir(UPNP_DIR_SHARES) == UPNP_E_INVALID_ARGUMENT){
ERROR("The virtual directory %s is invalid.",UPNP_DIR_SHARES);
return false;
@@ -135,7 +137,7 @@ bool cUPnPWebServer::init(){
}
bool cUPnPWebServer::uninit(){
- MESSAGE("Disabling the internal webserver");
+ MESSAGE(VERBOSE_WEBSERVER, "Disabling the internal webserver");
UpnpEnableWebserver(FALSE);
return true;
@@ -152,7 +154,7 @@ cUPnPWebServer* cUPnPWebServer::getInstance(const char* rootdir){
}
int cUPnPWebServer::getInfo(const char* filename, File_Info* info){
- MESSAGE("Getting information of file '%s'", filename);
+ MESSAGE(VERBOSE_WEBSERVER, "Getting information of file '%s'", filename);
propertyMap Properties;
int Method;
@@ -164,7 +166,7 @@ int cUPnPWebServer::getInfo(const char* filename, File_Info* info){
switch(Method){
case UPNP_WEB_METHOD_STREAM:
{
- MESSAGE("Stream request");
+ MESSAGE(VERBOSE_WEBSERVER, "Stream request");
propertyMap::iterator It = Properties.find("resId");
unsigned int ResourceID = 0;
if(It == Properties.end()){
@@ -188,12 +190,12 @@ int cUPnPWebServer::getInfo(const char* filename, File_Info* info){
finfo.last_modified = Resource->getLastModification();
memcpy(info, &finfo, sizeof(File_Info_));
- MESSAGE("==== File info of Resource #%d ====", Resource->getID());
- MESSAGE("Size: %lld", finfo.file_length);
- MESSAGE("Dir: %s", finfo.is_directory?"yes":"no");
- MESSAGE("Read: %s", finfo.is_readable?"allowed":"not allowed");
- MESSAGE("Last modified: %s", ctime(&(finfo.last_modified)));
- MESSAGE("Content-type: %s", finfo.content_type);
+ MESSAGE(VERBOSE_METADATA, "==== File info of Resource #%d ====", Resource->getID());
+ MESSAGE(VERBOSE_METADATA, "Size: %lld", finfo.file_length);
+ MESSAGE(VERBOSE_METADATA, "Dir: %s", finfo.is_directory?"yes":"no");
+ MESSAGE(VERBOSE_METADATA, "Read: %s", finfo.is_readable?"allowed":"not allowed");
+ MESSAGE(VERBOSE_METADATA, "Last modified: %s", ctime(&(finfo.last_modified)));
+ MESSAGE(VERBOSE_METADATA, "Content-type: %s", finfo.content_type);
}
}
}
@@ -222,7 +224,7 @@ int cUPnPWebServer::getInfo(const char* filename, File_Info* info){
}
UpnpWebFileHandle cUPnPWebServer::open(const char* filename, UpnpOpenFileMode mode){
- MESSAGE("File %s was opened for %s.",filename,mode==UPNP_READ ? "reading" : "writing");
+ MESSAGE(VERBOSE_WEBSERVER, "File %s was opened for %s.",filename,mode==UPNP_READ ? "reading" : "writing");
propertyMap Properties;
int Method;
@@ -235,7 +237,7 @@ UpnpWebFileHandle cUPnPWebServer::open(const char* filename, UpnpOpenFileMode mo
switch(Method){
case UPNP_WEB_METHOD_STREAM:
{
- MESSAGE("Stream request");
+ MESSAGE(VERBOSE_WEBSERVER, "Stream request");
propertyMap::iterator It = Properties.find("resId");
unsigned int ResourceID = 0;
if(It == Properties.end()){
@@ -258,7 +260,7 @@ UpnpWebFileHandle cUPnPWebServer::open(const char* filename, UpnpOpenFileMode mo
{
char* ChannelID = strtok(strdup(Resource->getResource()),":");
int AudioID = atoi(strtok(NULL,":"));
- MESSAGE("Try to create Receiver for Channel %s with Audio ID %d", ChannelID, AudioID);
+ MESSAGE(VERBOSE_LIVE_TV, "Try to create Receiver for Channel %s with Audio ID %d", ChannelID, AudioID);
cChannel* Channel = Channels.GetByChannelID(tChannelID::FromString(ChannelID));
if(!Channel){
ERROR("No such channel with ID %s", ChannelID);
@@ -303,32 +305,32 @@ UpnpWebFileHandle cUPnPWebServer::open(const char* filename, UpnpOpenFileMode mo
else {
return NULL;
}
- MESSAGE("Open the file handle");
+ MESSAGE(VERBOSE_WEBSERVER, "Open the file handle");
WebFileHandle->FileHandle->open(mode);
return (UpnpWebFileHandle)WebFileHandle;
}
int cUPnPWebServer::write(UpnpWebFileHandle fh, char* buf, size_t buflen){
cWebFileHandle* FileHandle = (cWebFileHandle*)fh;
- MESSAGE("Writing to %s", *FileHandle->Filename);
+ MESSAGE(VERBOSE_BUFFERS, "Writing to %s", *FileHandle->Filename);
return FileHandle->FileHandle->write(buf, buflen);
}
int cUPnPWebServer::read(UpnpWebFileHandle fh, char* buf, size_t buflen){
cWebFileHandle* FileHandle = (cWebFileHandle*)fh;
- MESSAGE("Reading from %s", *FileHandle->Filename);
+ MESSAGE(VERBOSE_BUFFERS, "Reading from %s", *FileHandle->Filename);
return FileHandle->FileHandle->read(buf, buflen);
}
int cUPnPWebServer::seek(UpnpWebFileHandle fh, off_t offset, int origin){
cWebFileHandle* FileHandle = (cWebFileHandle*)fh;
- MESSAGE("Seeking on %s", *FileHandle->Filename);
+ MESSAGE(VERBOSE_BUFFERS, "Seeking on %s", *FileHandle->Filename);
return FileHandle->FileHandle->seek(offset, origin);
}
int cUPnPWebServer::close(UpnpWebFileHandle fh){
cWebFileHandle *FileHandle = (cWebFileHandle *)fh;
- MESSAGE("Closing file %s", *FileHandle->Filename);
+ MESSAGE(VERBOSE_WEBSERVER, "Closing file %s", *FileHandle->Filename);
FileHandle->FileHandle->close();
delete FileHandle->FileHandle;
delete FileHandle;
diff --git a/upnpcomponents/upnpwebserver.h b/upnpcomponents/upnpwebserver.h
index 613f97b..0a49cf9 100644
--- a/upnpcomponents/upnpwebserver.h
+++ b/upnpcomponents/upnpwebserver.h
@@ -11,6 +11,13 @@
#include "../common.h"
#include <upnp/upnp.h>
+/**
+ * The internal webserver
+ *
+ * This is the internal webserver. It distributes all the contents of the
+ * UPnP-Server.
+ *
+ */
class cUPnPWebServer {
friend class cUPnPServer;
private:
@@ -19,11 +26,40 @@ private:
const char* mRootdir;
cUPnPWebServer(const char* root = "/");
protected:
- bool enable(bool enable);
public:
+ /**
+ * Initializes the webserver
+ *
+ * It enables the webserver which comes with the <em>Intel SDK</em> and creates
+ * virtual directories for shares media.
+ *
+ * @return returns
+ * - \bc true, if initializing was successful
+ * - \bc false, otherwise
+ */
bool init();
+ /**
+ * Uninitializes the webserver
+ *
+ * This stops the webserver.
+ *
+ * @return returns
+ * - \bc true, if initializing was successful
+ * - \bc false, otherwise
+ */
bool uninit();
- static cUPnPWebServer* getInstance(const char* rootdir = "/");
+ /**
+ * Returns the instance of the webserver
+ *
+ * Returns the instance of the webserver. This will create a single
+ * instance of none is existing on the very first call. A subsequent call
+ * will return the same instance.
+ *
+ * @return the instance of webserver
+ */
+ static cUPnPWebServer* getInstance(
+ const char* rootdir = "/" /**< the root directory of the webserver */
+ );
virtual ~cUPnPWebServer();
//};
@@ -32,6 +68,7 @@ public:
* The callback functions for the webserver
*
****************************************************/
+
/**
* Retrieve file information
*
@@ -48,8 +85,8 @@ public:
* Opens a file in a virtual directory with the specified mode.
*
* Possible modes are:
- * - UPNP_READ : Opens the file for reading
- * - UPNP_WRITE: Opens the file for writing
+ * - \b UPNP_READ, Opens the file for reading
+ * - \b UPNP_WRITE, Opens the file for writing
*
* It returns a file handle to the opened file, NULL otherwise
*