* Improve support for the NETGEAR Digital Entertainer Live (EVA2000).
This commit is contained in:
parent
9806103335
commit
bec766497a
@ -77,6 +77,7 @@ enum client_types {
|
|||||||
ERokuSoundBridge,
|
ERokuSoundBridge,
|
||||||
EToshibaTV,
|
EToshibaTV,
|
||||||
ELGDevice,
|
ELGDevice,
|
||||||
|
ENetgearEVA2000,
|
||||||
EStandardDLNA150 = 100
|
EStandardDLNA150 = 100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -334,6 +334,11 @@ intervening space) by either an integer or the keyword "infinite". */
|
|||||||
h->req_client = ELGDevice;
|
h->req_client = ELGDevice;
|
||||||
h->reqflags |= FLAG_DLNA;
|
h->reqflags |= FLAG_DLNA;
|
||||||
}
|
}
|
||||||
|
else if(strncmp(p, "Verismo,", 8)==0)
|
||||||
|
{
|
||||||
|
h->req_client = ENetgearEVA2000;
|
||||||
|
h->reqflags |= FLAG_MS_PFS;
|
||||||
|
}
|
||||||
else if(strstrc(p, "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", '\r'))
|
else if(strstrc(p, "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", '\r'))
|
||||||
{
|
{
|
||||||
h->req_client = EToshibaTV;
|
h->req_client = EToshibaTV;
|
||||||
@ -1364,12 +1369,12 @@ SendResp_caption(struct upnphttp * h, char * object)
|
|||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
"EXT:\r\n"
|
"EXT:\r\n"
|
||||||
"Server: " MINIDLNA_SERVER_STRING "\r\n\r\n",
|
"Server: " MINIDLNA_SERVER_STRING "\r\n\r\n",
|
||||||
size, date);
|
(intmax_t)size, date);
|
||||||
|
|
||||||
if( send_data(h, header, ret, MSG_MORE) == 0 )
|
if( send_data(h, header, ret, MSG_MORE) == 0 )
|
||||||
{
|
{
|
||||||
if( h->req_command != EHead )
|
if( h->req_command != EHead )
|
||||||
send_file(h, fd, 0, size);
|
send_file(h, fd, 0, size-1);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
65
upnpsoap.c
65
upnpsoap.c
@ -767,11 +767,12 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID);
|
lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef PFS_HACK
|
|
||||||
if( (passed_args->flags & FLAG_MS_PFS) && *mime == 'i' ) {
|
if( (passed_args->flags & FLAG_MS_PFS) && *mime == 'i' ) {
|
||||||
ret = strcatf(str, "<upnp:album>%s</upnp:album>", "[No Keywords]");
|
if( passed_args->client == EMediaRoom && !album )
|
||||||
|
ret = strcatf(str, "<upnp:album>%s</upnp:album>", "[No Keywords]");
|
||||||
|
|
||||||
if( tn && atoi(tn) ) {
|
/* EVA2000 doesn't seem to handle embedded thumbnails */
|
||||||
|
if( passed_args->client != ENetgearEVA2000 && tn && atoi(tn) ) {
|
||||||
ret = strcatf(str, "<upnp:albumArtURI>"
|
ret = strcatf(str, "<upnp:albumArtURI>"
|
||||||
"http://%s:%d/Thumbnails/%s.jpg"
|
"http://%s:%d/Thumbnails/%s.jpg"
|
||||||
"</upnp:albumArtURI>",
|
"</upnp:albumArtURI>",
|
||||||
@ -783,7 +784,6 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
lan_addr[passed_args->iface].str, runtime_vars.port, detailID);
|
lan_addr[passed_args->iface].str, runtime_vars.port, detailID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if( passed_args->filter & FILTER_RES ) {
|
if( passed_args->filter & FILTER_RES ) {
|
||||||
mime_to_ext(mime, ext);
|
mime_to_ext(mime, ext);
|
||||||
if( (passed_args->client == EFreeBox) && tn && atoi(tn) ) {
|
if( (passed_args->client == EFreeBox) && tn && atoi(tn) ) {
|
||||||
@ -796,7 +796,6 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels,
|
add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels,
|
||||||
resolution, dlna_buf, mime, detailID, ext, passed_args);
|
resolution, dlna_buf, mime, detailID, ext, passed_args);
|
||||||
if( (*mime == 'i') && (passed_args->client != EFreeBox) ) {
|
if( (*mime == 'i') && (passed_args->client != EFreeBox) ) {
|
||||||
#if 1 //JPEG_RESIZE
|
|
||||||
int srcw = atoi(strsep(&resolution, "x"));
|
int srcw = atoi(strsep(&resolution, "x"));
|
||||||
int srch = atoi(resolution);
|
int srch = atoi(resolution);
|
||||||
if( !dlna_pn ) {
|
if( !dlna_pn ) {
|
||||||
@ -805,7 +804,6 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
if( !dlna_pn || !strncmp(dlna_pn, "JPEG_L", 6) || !strncmp(dlna_pn, "JPEG_M", 6) ) {
|
if( !dlna_pn || !strncmp(dlna_pn, "JPEG_L", 6) || !strncmp(dlna_pn, "JPEG_M", 6) ) {
|
||||||
add_resized_res(srcw, srch, 640, 480, "JPEG_SM", detailID, passed_args);
|
add_resized_res(srcw, srch, 640, 480, "JPEG_SM", detailID, passed_args);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if( tn && atoi(tn) ) {
|
if( tn && atoi(tn) ) {
|
||||||
ret = strcatf(str, "<res protocolInfo=\"http-get:*:%s:%s\">"
|
ret = strcatf(str, "<res protocolInfo=\"http-get:*:%s:%s\">"
|
||||||
"http://%s:%d/Thumbnails/%s.jpg"
|
"http://%s:%d/Thumbnails/%s.jpg"
|
||||||
@ -963,7 +961,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
struct NameValueParserData data;
|
struct NameValueParserData data;
|
||||||
|
|
||||||
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
|
||||||
char * ObjectId = GetValueFromNameValueList(&data, "ObjectID");
|
char * ObjectID = GetValueFromNameValueList(&data, "ObjectID");
|
||||||
char * Filter = GetValueFromNameValueList(&data, "Filter");
|
char * Filter = GetValueFromNameValueList(&data, "Filter");
|
||||||
char * BrowseFlag = GetValueFromNameValueList(&data, "BrowseFlag");
|
char * BrowseFlag = GetValueFromNameValueList(&data, "BrowseFlag");
|
||||||
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
||||||
@ -979,15 +977,11 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) )
|
if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 402, "Invalid Args");
|
SoapError(h, 402, "Invalid Args");
|
||||||
if( h->reqflags & FLAG_MS_PFS )
|
|
||||||
ObjectId = sqlite3_malloc(1);
|
|
||||||
goto browse_error;
|
goto browse_error;
|
||||||
}
|
}
|
||||||
if( !ObjectId && !(ObjectId = GetValueFromNameValueList(&data, "ContainerID")) )
|
if( !ObjectID && !(ObjectID = GetValueFromNameValueList(&data, "ContainerID")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 701, "No such object error");
|
SoapError(h, 701, "No such object error");
|
||||||
if( h->reqflags & FLAG_MS_PFS )
|
|
||||||
ObjectId = sqlite3_malloc(1);
|
|
||||||
goto browse_error;
|
goto browse_error;
|
||||||
}
|
}
|
||||||
memset(&args, 0, sizeof(args));
|
memset(&args, 0, sizeof(args));
|
||||||
@ -996,7 +990,6 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
str.data = malloc(DEFAULT_RESP_SIZE);
|
str.data = malloc(DEFAULT_RESP_SIZE);
|
||||||
str.size = DEFAULT_RESP_SIZE;
|
str.size = DEFAULT_RESP_SIZE;
|
||||||
str.off = sprintf(str.data, "%s", resp0);
|
str.off = sprintf(str.data, "%s", resp0);
|
||||||
args.str = &str;
|
|
||||||
/* See if we need to include DLNA namespace reference */
|
/* See if we need to include DLNA namespace reference */
|
||||||
args.iface = h->iface;
|
args.iface = h->iface;
|
||||||
args.filter = set_filter_flags(Filter, h->req_client);
|
args.filter = set_filter_flags(Filter, h->req_client);
|
||||||
@ -1010,17 +1003,18 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
args.requested = RequestedCount;
|
args.requested = RequestedCount;
|
||||||
args.client = h->req_client;
|
args.client = h->req_client;
|
||||||
args.flags = h->reqflags;
|
args.flags = h->reqflags;
|
||||||
|
args.str = &str;
|
||||||
if( args.flags & FLAG_MS_PFS )
|
if( args.flags & FLAG_MS_PFS )
|
||||||
{
|
{
|
||||||
if( !strchr(ObjectId, '$') && (strcmp(ObjectId, "0") != 0) )
|
if( !strchr(ObjectID, '$') && (strcmp(ObjectID, "0") != 0) )
|
||||||
{
|
{
|
||||||
ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS"
|
ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS"
|
||||||
" where OBJECT_ID in "
|
" where OBJECT_ID in "
|
||||||
"('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')",
|
"('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')",
|
||||||
ObjectId, ObjectId, ObjectId);
|
ObjectID, ObjectID, ObjectID);
|
||||||
if( ptr )
|
if( ptr )
|
||||||
{
|
{
|
||||||
ObjectId = ptr;
|
ObjectID = ptr;
|
||||||
args.flags |= FLAG_FREE_OBJECT_ID;
|
args.flags |= FLAG_FREE_OBJECT_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1032,12 +1026,12 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
" * BrowseFlag: %s\n"
|
" * BrowseFlag: %s\n"
|
||||||
" * Filter: %s\n"
|
" * Filter: %s\n"
|
||||||
" * SortCriteria: %s\n",
|
" * SortCriteria: %s\n",
|
||||||
ObjectId, RequestedCount, StartingIndex,
|
ObjectID, RequestedCount, StartingIndex,
|
||||||
BrowseFlag, Filter, SortCriteria);
|
BrowseFlag, Filter, SortCriteria);
|
||||||
|
|
||||||
if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectId, "0") == 0) )
|
if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectID, "0") == 0) )
|
||||||
{
|
{
|
||||||
ObjectId = sqlite3_mprintf("%s", MUSIC_ID);
|
ObjectID = sqlite3_mprintf("%s", MUSIC_ID);
|
||||||
args.flags |= FLAG_FREE_OBJECT_ID;
|
args.flags |= FLAG_FREE_OBJECT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,13 +1041,13 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
sql = sqlite3_mprintf( SELECT_COLUMNS
|
sql = sqlite3_mprintf( SELECT_COLUMNS
|
||||||
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||||
" where OBJECT_ID = '%s';"
|
" where OBJECT_ID = '%s';"
|
||||||
, ObjectId);
|
, ObjectID);
|
||||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||||
totalMatches = args.returned;
|
totalMatches = args.returned;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId);
|
ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectID);
|
||||||
totalMatches = (ret > 0) ? ret : 0;
|
totalMatches = (ret > 0) ? ret : 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if( SortCriteria )
|
if( SortCriteria )
|
||||||
@ -1065,9 +1059,9 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( strncmp(ObjectId, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 )
|
if( strncmp(ObjectID, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 )
|
||||||
{
|
{
|
||||||
if( strcmp(ObjectId, MUSIC_PLIST_ID) == 0 )
|
if( strcmp(ObjectID, MUSIC_PLIST_ID) == 0 )
|
||||||
asprintf(&orderBy, "order by d.TITLE");
|
asprintf(&orderBy, "order by d.TITLE");
|
||||||
else
|
else
|
||||||
asprintf(&orderBy, "order by length(OBJECT_ID), OBJECT_ID");
|
asprintf(&orderBy, "order by length(OBJECT_ID), OBJECT_ID");
|
||||||
@ -1090,7 +1084,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
sql = sqlite3_mprintf( SELECT_COLUMNS
|
sql = sqlite3_mprintf( SELECT_COLUMNS
|
||||||
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||||
" where PARENT_ID = '%s' %s limit %d, %d;",
|
" where PARENT_ID = '%s' %s limit %d, %d;",
|
||||||
ObjectId, orderBy, StartingIndex, RequestedCount);
|
ObjectID, orderBy, StartingIndex, RequestedCount);
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql);
|
DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql);
|
||||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||||
}
|
}
|
||||||
@ -1103,7 +1097,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
/* Does the object even exist? */
|
/* Does the object even exist? */
|
||||||
if( !totalMatches )
|
if( !totalMatches )
|
||||||
{
|
{
|
||||||
ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectId);
|
ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectID);
|
||||||
if( ret <= 0 )
|
if( ret <= 0 )
|
||||||
{
|
{
|
||||||
SoapError(h, 701, "No such object error");
|
SoapError(h, 701, "No such object error");
|
||||||
@ -1120,7 +1114,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
browse_error:
|
browse_error:
|
||||||
ClearNameValueList(&data);
|
ClearNameValueList(&data);
|
||||||
if( args.flags & FLAG_FREE_OBJECT_ID )
|
if( args.flags & FLAG_FREE_OBJECT_ID )
|
||||||
sqlite3_free(ObjectId);
|
sqlite3_free(ObjectID);
|
||||||
free(orderBy);
|
free(orderBy);
|
||||||
free(str.data);
|
free(str.data);
|
||||||
}
|
}
|
||||||
@ -1164,8 +1158,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) )
|
if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 701, "No such object error");
|
SoapError(h, 701, "No such object error");
|
||||||
if( h->reqflags & FLAG_MS_PFS )
|
|
||||||
ContainerID = sqlite3_malloc(1);
|
|
||||||
goto search_error;
|
goto search_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1182,29 +1174,26 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
{
|
{
|
||||||
ret = strcatf(&str, DLNA_NAMESPACE);
|
ret = strcatf(&str, DLNA_NAMESPACE);
|
||||||
}
|
}
|
||||||
ret = strcatf(&str, ">\n");
|
strcatf(&str, ">\n");
|
||||||
|
|
||||||
args.returned = 0;
|
args.returned = 0;
|
||||||
args.requested = RequestedCount;
|
args.requested = RequestedCount;
|
||||||
args.client = h->req_client;
|
args.client = h->req_client;
|
||||||
args.flags = h->reqflags;
|
args.flags = h->reqflags;
|
||||||
args.str = &str;
|
args.str = &str;
|
||||||
if( h->reqflags & FLAG_MS_PFS )
|
if( args.flags & FLAG_MS_PFS )
|
||||||
{
|
{
|
||||||
if( strchr(ContainerID, '$') || (strcmp(ContainerID, "0") == 0) )
|
if( !strchr(ContainerID, '$') && (strcmp(ContainerID, "0") != 0) )
|
||||||
{
|
|
||||||
ContainerID = sqlite3_mprintf("%s", ContainerID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS"
|
ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS"
|
||||||
" where OBJECT_ID in "
|
" where OBJECT_ID in "
|
||||||
"('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')",
|
"('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')",
|
||||||
ContainerID, ContainerID, ContainerID);
|
ContainerID, ContainerID, ContainerID);
|
||||||
if( ptr )
|
if( ptr )
|
||||||
|
{
|
||||||
ContainerID = ptr;
|
ContainerID = ptr;
|
||||||
else
|
args.flags |= FLAG_FREE_OBJECT_ID;
|
||||||
ContainerID = sqlite3_mprintf("%s", ContainerID);
|
}
|
||||||
}
|
}
|
||||||
#if 0 // Looks like the 360 already does this
|
#if 0 // Looks like the 360 already does this
|
||||||
/* Sort by track number for some containers */
|
/* Sort by track number for some containers */
|
||||||
@ -1354,7 +1343,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
BuildSendAndCloseSoapResp(h, str.data, str.off);
|
BuildSendAndCloseSoapResp(h, str.data, str.off);
|
||||||
search_error:
|
search_error:
|
||||||
ClearNameValueList(&data);
|
ClearNameValueList(&data);
|
||||||
if( h->reqflags & FLAG_MS_PFS )
|
if( args.flags & FLAG_FREE_OBJECT_ID )
|
||||||
sqlite3_free(ContainerID);
|
sqlite3_free(ContainerID);
|
||||||
free(orderBy);
|
free(orderBy);
|
||||||
free(newSearchCriteria);
|
free(newSearchCriteria);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user