From 4f69a0a84dcfc186b6a1f19908d136446da650cb Mon Sep 17 00:00:00 2001 From: Fedor Kozhevnikov Date: Sun, 17 Apr 2011 22:02:47 -0400 Subject: [PATCH] MiniDLNA: 1.0.19.1 cvs 2011-04-14 --- release/src/router/minidlna/getifaddr.c | 40 ++++- release/src/router/minidlna/minidlna.c | 14 +- release/src/router/minidlna/minidlnatypes.h | 1 + release/src/router/minidlna/minissdp.c | 5 +- release/src/router/minidlna/scanner.c | 4 +- release/src/router/minidlna/upnpglobalvars.h | 2 +- release/src/router/minidlna/upnphttp.c | 5 + release/src/router/minidlna/upnphttp.h | 2 + release/src/router/minidlna/upnpsoap.c | 212 +++++++++++++++++---------- 9 files changed, 198 insertions(+), 87 deletions(-) diff --git a/release/src/router/minidlna/getifaddr.c b/release/src/router/minidlna/getifaddr.c index 44b002ba3f..068422badc 100644 --- a/release/src/router/minidlna/getifaddr.c +++ b/release/src/router/minidlna/getifaddr.c @@ -1,4 +1,4 @@ -/* $Id: getifaddr.c,v 1.12 2010/11/11 23:48:13 jmaggard Exp $ */ +/* $Id: getifaddr.c,v 1.13 2011/04/11 22:52:34 jmaggard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * @@ -54,6 +54,9 @@ getifaddr(const char * ifname, char * buf, int len) struct ifreq ifr; int ifrlen; struct sockaddr_in * addr; + uint32_t mask; + int i; + ifrlen = sizeof(ifr); s = socket(PF_INET, SOCK_DGRAM, 0); if(s < 0) @@ -75,6 +78,24 @@ getifaddr(const char * ifname, char * buf, int len) close(s); return -1; } + if(ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) == 0) + { + addr = (struct sockaddr_in *)&ifr.ifr_netmask; + mask = ntohl(addr->sin_addr.s_addr); + for (i = 0; i < 32; i++) + { + if ((mask >> i) & 1) + break; + } + mask = 32 - i; + if (mask) + { + i = strlen(buf); + snprintf(buf+i, len-i, "/%u", mask); + } + } + else + DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFNETMASK, ...): %s\n", strerror(errno)); close(s); return 0; } @@ -86,6 +107,7 @@ getsysaddr(char * buf, int len) int s = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in addr; struct ifreq ifr; + uint32_t mask; int ret = -1; for (i=1; i > 0; i++) @@ -98,6 +120,8 @@ getsysaddr(char * buf, int len) memcpy(&addr, &ifr.ifr_addr, sizeof(addr)); if(strncmp(inet_ntoa(addr.sin_addr), "127.", 4) == 0) continue; + if(ioctl(s, SIOCGIFNETMASK, &ifr, sizeof(struct ifreq)) < 0) + continue; if(!inet_ntop(AF_INET, &addr.sin_addr, buf, len)) { DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno)); @@ -105,6 +129,20 @@ getsysaddr(char * buf, int len) break; } ret = 0; + + memcpy(&addr, &ifr.ifr_netmask, sizeof(addr)); + mask = ntohl(addr.sin_addr.s_addr); + for (i = 0; i < 32; i++) + { + if ((mask >> i) & 1) + break; + } + mask = 32 - i; + if (mask) + { + i = strlen(buf); + snprintf(buf+i, len-i, "/%u", mask); + } break; } close(s); diff --git a/release/src/router/minidlna/minidlna.c b/release/src/router/minidlna/minidlna.c index e0820356b9..3a0570cd43 100644 --- a/release/src/router/minidlna/minidlna.c +++ b/release/src/router/minidlna/minidlna.c @@ -194,7 +194,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) lan_addr->str[n] = '\0'; if(!inet_aton(lan_addr->str, &lan_addr->addr)) { - DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str); + DPRINTF(E_OFF, L_GENERAL, "Error parsing address: %s\n", str); return -1; } lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0); @@ -344,7 +344,7 @@ init(int argc, char * * argv) enum media_types type; char * path; char real_path[PATH_MAX]; - char ext_ip_addr[INET_ADDRSTRLEN] = {'\0'}; + char ext_ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; /* first check if "-f" option is used */ for(i=2; i= 0) + if(getifaddr(ary_options[i].value, ext_ip_addr, sizeof(ext_ip_addr)) >= 0) { if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) n_lan_addr++; @@ -649,7 +649,7 @@ init(int argc, char * * argv) int address_already_there = 0; int j; i++; - if( getifaddr(argv[i], ext_ip_addr, INET_ADDRSTRLEN) < 0 ) + if( getifaddr(argv[i], ext_ip_addr, sizeof(ext_ip_addr)) < 0 ) { fprintf(stderr, "Network interface '%s' not found.\n", argv[i]); @@ -699,9 +699,9 @@ init(int argc, char * * argv) /* If no IP was specified, try to detect one */ if( n_lan_addr < 1 ) { - if( (getsysaddr(ext_ip_addr, INET_ADDRSTRLEN) < 0) && - (getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) && - (getifaddr("eth1", ext_ip_addr, INET_ADDRSTRLEN) < 0) ) + if( (getsysaddr(ext_ip_addr, sizeof(ext_ip_addr)) < 0) && + (getifaddr("eth0", ext_ip_addr, sizeof(ext_ip_addr)) < 0) && + (getifaddr("eth1", ext_ip_addr, sizeof(ext_ip_addr)) < 0) ) { DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); } diff --git a/release/src/router/minidlna/minidlnatypes.h b/release/src/router/minidlna/minidlnatypes.h index 8bb6783fbc..dec1ba74e4 100644 --- a/release/src/router/minidlna/minidlnatypes.h +++ b/release/src/router/minidlna/minidlnatypes.h @@ -69,6 +69,7 @@ enum client_types { ESonyBDP, ESonyBravia, ERokuSoundBridge, + EToshibaTV, EStandardDLNA150 = 100 }; diff --git a/release/src/router/minidlna/minissdp.c b/release/src/router/minidlna/minissdp.c index b72c95dd49..35a9e2a826 100644 --- a/release/src/router/minidlna/minissdp.c +++ b/release/src/router/minidlna/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.15 2011/04/09 01:37:11 jmaggard Exp $ */ +/* $Id: minissdp.c,v 1.16 2011/04/12 20:55:32 jmaggard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * @@ -434,6 +434,7 @@ close: model = GetValueFromNameValueList(&xml, "modelName"); if( model ) { + DPRINTF(E_DEBUG, L_SSDP, "Model: %s\n", model); if (strstr(model, "Roku SoundBridge")) { type = ERokuSoundBridge; @@ -453,7 +454,7 @@ close: continue; get_remote_mac(dest.sin_addr, clients[client].mac); clients[client].addr = dest.sin_addr; - DPRINTF(E_DEBUG, L_HTTP, "Added client [%d/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", + DPRINTF(E_DEBUG, L_SSDP, "Added client [%d/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", type, inet_ntoa(clients[client].addr), clients[client].mac[0], clients[client].mac[1], clients[client].mac[2], clients[client].mac[3], clients[client].mac[4], clients[client].mac[5], client); diff --git a/release/src/router/minidlna/scanner.c b/release/src/router/minidlna/scanner.c index fbca68dcd0..ba585101af 100644 --- a/release/src/router/minidlna/scanner.c +++ b/release/src/router/minidlna/scanner.c @@ -279,7 +279,7 @@ insert_containers(const char * name, const char *path, const char * refID, const strcpy(last_artist.name, artist); last_artistAlbum.name[0] = '\0'; /* Add this file to the "- All Albums -" container as well */ - container = insert_container(_("- All Albums -"), last_artist.parentID, NULL, "storageFolder", artist, genre, NULL); + container = insert_container(_("- All Albums -"), last_artist.parentID, NULL, "album", artist, genre, NULL); sprintf(last_artistAlbumAll.parentID, "%s$%llX", last_artist.parentID, container>>32); last_artistAlbumAll.objectID = (int)container; } @@ -320,7 +320,7 @@ insert_containers(const char * name, const char *path, const char * refID, const strcpy(last_genre.name, genre); last_genreArtist.name[0] = '\0'; /* Add this file to the "- All Artists -" container as well */ - container = insert_container(_("- All Artists -"), last_genre.parentID, NULL, "storageFolder", NULL, genre, NULL); + container = insert_container(_("- All Artists -"), last_genre.parentID, NULL, "person", NULL, genre, NULL); sprintf(last_genreArtistAll.parentID, "%s$%llX", last_genre.parentID, container>>32); last_genreArtistAll.objectID = (int)container; } diff --git a/release/src/router/minidlna/upnpglobalvars.h b/release/src/router/minidlna/upnpglobalvars.h index 2fe7a74ed8..d9a39d3968 100644 --- a/release/src/router/minidlna/upnpglobalvars.h +++ b/release/src/router/minidlna/upnpglobalvars.h @@ -56,7 +56,7 @@ #include -#define MINIDLNA_VERSION "1.0.19" +#define MINIDLNA_VERSION "1.0.19.1" #ifdef NETGEAR # define SERVER_NAME "ReadyDLNA" diff --git a/release/src/router/minidlna/upnphttp.c b/release/src/router/minidlna/upnphttp.c index e4375073b3..029041cba2 100644 --- a/release/src/router/minidlna/upnphttp.c +++ b/release/src/router/minidlna/upnphttp.c @@ -314,6 +314,11 @@ intervening space) by either an integer or the keyword "infinite". */ h->req_client = EMediaRoom; h->reqflags |= FLAG_MS_PFS; } + else if(strstrc(p, "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", '\r')) + { + h->req_client = EToshibaTV; + h->reqflags |= FLAG_DLNA; + } else if(strstrc(p, "DLNADOC/1.50", '\r')) { h->req_client = EStandardDLNA150; diff --git a/release/src/router/minidlna/upnphttp.h b/release/src/router/minidlna/upnphttp.h index 91df730f07..64108e6b0b 100644 --- a/release/src/router/minidlna/upnphttp.h +++ b/release/src/router/minidlna/upnphttp.h @@ -112,6 +112,8 @@ struct upnphttp { #define FLAG_MS_PFS 0x02000000 // Microsoft PlaysForSure client #define FLAG_AUDIO_ONLY 0x04000000 +#define FLAG_FREE_OBJECT_ID 0x00000001 + /* New_upnphttp() */ struct upnphttp * New_upnphttp(int); diff --git a/release/src/router/minidlna/upnpsoap.c b/release/src/router/minidlna/upnpsoap.c index 62dacb8853..6cbff1c0ac 100644 --- a/release/src/router/minidlna/upnpsoap.c +++ b/release/src/router/minidlna/upnpsoap.c @@ -551,18 +551,17 @@ parse_sort_criteria(char * sortCriteria, int * error) return order; } -static void add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, char *detailID, struct Response *passed_args) +inline static void +add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, + char *detailID, struct Response *passed_args) { int ret; int dstw = reqw; int dsth = reqh; char str_buf[256]; - if( passed_args->flags & FLAG_NO_RESIZE ) - { return; - } ret = sprintf(str_buf, "<res "); memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); @@ -588,6 +587,55 @@ static void add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_p passed_args->size += ret; } +inline static void +add_res(char *size, char *duration, char *bitrate, char *sampleFrequency, + char *nrAudioChannels, char *resolution, char *dlna_pn, char *mime, + char *detailID, char *ext, struct Response *passed_args) +{ + int ret; + char str_buf[256]; + + ret = sprintf(str_buf, "<res "); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + if( size && (passed_args->filter & FILTER_RES_SIZE) ) { + ret = sprintf(str_buf, "size=\"%s\" ", size); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + if( duration && (passed_args->filter & FILTER_RES_DURATION) ) { + ret = sprintf(str_buf, "duration=\"%s\" ", duration); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) { + ret = sprintf(str_buf, "bitrate=\"%s\" ", bitrate); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + if( sampleFrequency && (passed_args->filter & FILTER_RES_SAMPLEFREQUENCY) ) { + ret = sprintf(str_buf, "sampleFrequency=\"%s\" ", sampleFrequency); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + if( nrAudioChannels && (passed_args->filter & FILTER_RES_NRAUDIOCHANNELS) ) { + ret = sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + if( resolution && (passed_args->filter & FILTER_RES_RESOLUTION) ) { + ret = sprintf(str_buf, "resolution=\"%s\" ", resolution); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; + } + ret = snprintf(str_buf, sizeof(str_buf), "protocolInfo=\"http-get:*:%s:%s\">" + "http://%s:%d/MediaItems/%s.%s" + "</res>", + mime, dlna_pn, lan_addr[0].str, runtime_vars.port, detailID, ext); + memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); + passed_args->size += ret; +} + #define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, o.DETAIL_ID, o.CLASS," \ " d.SIZE, d.TITLE, d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST," \ " d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, d.TRACK, d.DATE, d.RESOLUTION," \ @@ -679,20 +727,6 @@ callback(void *args, int argc, char **argv, char **azColName) strcpy(mime+8, "mkv"); } } - else if( passed_args->client == ESonyBDP || passed_args->client == ESonyBravia ) - { - if( passed_args->client == ESonyBDP && - (strcmp(mime+6, "x-matroska") == 0 || - strcmp(mime+6, "mpeg") == 0) ) - { - strcpy(mime+6, "divx"); - } - /* BRAVIA KDL-##*X### series TVs do natively support AVC/AC3 in TS, but - require profile to be renamed (applies to _T and _ISO variants also) */ - modifyString(dlna_buf, "AVC_TS_MP_SD_AC3", "AVC_TS_HD_50_AC3", 0); - modifyString(dlna_buf, "AVC_TS_MP_HD_AC3", "AVC_TS_HD_50_AC3", 0); - modifyString(dlna_buf, "AVC_TS_HP_HD_AC3", "AVC_TS_HD_50_AC3", 0); - } } else if( *mime == 'a' ) { @@ -820,48 +854,8 @@ callback(void *args, int argc, char **argv, char **azColName) memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); passed_args->size += ret; } - ret = sprintf(str_buf, "<res "); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - if( size && (passed_args->filter & FILTER_RES_SIZE) ) { - ret = sprintf(str_buf, "size=\"%s\" ", size); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - if( duration && (passed_args->filter & FILTER_RES_DURATION) ) { - ret = sprintf(str_buf, "duration=\"%s\" ", duration); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) { - if( passed_args->flags & FLAG_MS_PFS ) - ret = sprintf(str_buf, "bitrate=\"%d\" ", atoi(bitrate)/1024); - else - ret = sprintf(str_buf, "bitrate=\"%s\" ", bitrate); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - if( sampleFrequency && (passed_args->filter & FILTER_RES_SAMPLEFREQUENCY) ) { - ret = sprintf(str_buf, "sampleFrequency=\"%s\" ", sampleFrequency); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - if( nrAudioChannels && (passed_args->filter & FILTER_RES_NRAUDIOCHANNELS) ) { - ret = sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - if( resolution && (passed_args->filter & FILTER_RES_RESOLUTION) ) { - ret = sprintf(str_buf, "resolution=\"%s\" ", resolution); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; - } - ret = sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">" - "http://%s:%d/MediaItems/%s.%s" - "</res>", - mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID, ext); - memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); - passed_args->size += ret; + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); if( (*mime == 'i') && (passed_args->client != EFreeBox) ) { #if 1 //JPEG_RESIZE int srcw = atoi(strsep(&resolution, "x")); @@ -882,6 +876,76 @@ callback(void *args, int argc, char **argv, char **azColName) passed_args->size += ret; } } + else if( *mime == 'v' ) { + switch( passed_args->client ) { + case EToshibaTV: + if( dlna_pn && + (strncmp(dlna_pn, "MPEG_TS_HD_NA", 13) == 0 || + strncmp(dlna_pn, "MPEG_TS_SD_NA", 13) == 0 || + strncmp(dlna_pn, "AVC_TS_MP_HD_AC3", 16) == 0)) + { + sprintf(dlna_buf, "DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + break; + case ESonyBDP: + if( dlna_pn && + (strncmp(dlna_pn, "AVC_TS", 6) == 0 || + strncmp(dlna_pn, "MPEG_TS", 7) == 0) ) + { + if( strncmp(dlna_pn, "MPEG_TS_SD_NA", 13) != 0 ) + { + sprintf(dlna_buf, "DLNA.ORG_PN=MPEG_TS_SD_NA;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + if( strncmp(dlna_pn, "MPEG_TS_SD_EU", 13) != 0 ) + { + sprintf(dlna_buf, "DLNA.ORG_PN=MPEG_TS_SD_EU;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + } + else if( (dlna_pn && + (strncmp(dlna_pn, "AVC_MP4", 7) == 0 || + strncmp(dlna_pn, "MPEG4_P2_MP4", 12) == 0)) || + strcmp(mime+6, "x-matroska") == 0 || + strcmp(mime+6, "x-msvideo") == 0 || + strcmp(mime+6, "mpeg") == 0 ) + { + strcpy(mime+6, "avi"); + if( !dlna_pn || strncmp(dlna_pn, "MPEG_PS_NTSC", 12) != 0 ) + { + sprintf(dlna_buf, "DLNA.ORG_PN=MPEG_PS_NTSC;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + if( !dlna_pn || strncmp(dlna_pn, "MPEG_PS_PAL", 11) != 0 ) + { + sprintf(dlna_buf, "DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + } + break; + case ESonyBravia: + /* BRAVIA KDL-##*X### series TVs do natively support AVC/AC3 in TS, but + require profile to be renamed (applies to _T and _ISO variants also) */ + if( dlna_pn && + (strncmp(dlna_pn, "AVC_TS_MP_SD_AC3", 16) == 0 || + strncmp(dlna_pn, "AVC_TS_MP_HD_AC3", 16) == 0 || + strncmp(dlna_pn, "AVC_TS_HP_HD_AC3", 16) == 0)) + { + sprintf(dlna_buf, "DLNA.ORG_PN=AVC_TS_HD_50_AC3;DLNA.ORG_OP=01;DLNA.ORG_CI=0"); + add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, + resolution, dlna_buf, mime, detailID, ext, passed_args); + } + break; + default: + break; + } + } } ret = sprintf(str_buf, "</item>"); } @@ -1023,22 +1087,19 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) args.requested = RequestedCount; args.client = h->req_client; args.flags = h->reqflags; - if( h->reqflags & FLAG_MS_PFS ) + if( args.flags & FLAG_MS_PFS ) { - if( strchr(ObjectId, '$') || (strcmp(ObjectId, "0") == 0) ) - { - ObjectId = sqlite3_mprintf("%s", ObjectId); - } - else + if( !strchr(ObjectId, '$') && (strcmp(ObjectId, "0") != 0) ) { ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS" " where OBJECT_ID in " "('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')", ObjectId, ObjectId, ObjectId); if( ptr ) + { ObjectId = ptr; - else - ObjectId = sqlite3_mprintf("%s", ObjectId); + args.flags |= FLAG_FREE_OBJECT_ID; + } } } DPRINTF(E_DEBUG, L_HTTP, "Browsing ContentDirectory:\n" @@ -1051,6 +1112,12 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) ObjectId, RequestedCount, StartingIndex, BrowseFlag, Filter, SortCriteria); + if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectId, "0") == 0) ) + { + ObjectId = sqlite3_mprintf("%s", MUSIC_ID); + args.flags |= FLAG_FREE_OBJECT_ID; + } + if( strcmp(BrowseFlag+6, "Metadata") == 0 ) { args.requested = 1; @@ -1082,13 +1149,12 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) else asprintf(&orderBy, "order by length(OBJECT_ID), OBJECT_ID"); } - else if( strncmp(ObjectId, MUSIC_ID, strlen(MUSIC_ID)) == 0 ) + else if( args.client == ERokuSoundBridge ) { #ifdef __sparc__ if( totalMatches < 10000 ) #endif asprintf(&orderBy, "order by o.CLASS, d.DISC, d.TRACK, d.TITLE"); - } } /* If it's a DLNA client, return an error for bad sort criteria */ @@ -1134,11 +1200,9 @@ browse_error: ClearNameValueList(&data); if( orderBy ) free(orderBy); - free(resp); - if( h->reqflags & FLAG_MS_PFS ) - { + if( args.flags & FLAG_FREE_OBJECT_ID ) sqlite3_free(ObjectId); - } + free(resp); } static void -- 2.11.4.GIT