The browsing issue that was reported on Samsung Series F was actually only present when a custom root container was being specified (http://sourceforge.net/p/minidlna/patches/121/). So instead of disabling DCM10, fix our X_GetFeatureList response when a custom root container is set. If the custom root is Browse Folders, then drop the user straight to folder browsing for that media type. If it's something other than folder browsing, just set all media type roots to the custom root container. For future reference, the DCM10 flag enables (at least) video bookmark support and Samsung "BasicView" support; so selecting, for example, Videos from the Samsung UI can send you straight to the Videos section of the media library.
302 lines
6.2 KiB
C
302 lines
6.2 KiB
C
/* MiniDLNA media server
|
|
* Copyright (C) 2013 NETGEAR
|
|
*
|
|
* This file is part of MiniDLNA.
|
|
*
|
|
* MiniDLNA is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* MiniDLNA is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "clients.h"
|
|
#include "getifaddr.h"
|
|
#include "log.h"
|
|
|
|
struct client_type_s client_types[] =
|
|
{
|
|
{ 0,
|
|
0,
|
|
"Unknown",
|
|
NULL,
|
|
EMatchNone
|
|
},
|
|
|
|
{ EXbox,
|
|
FLAG_MIME_AVI_AVI | FLAG_MS_PFS,
|
|
"Xbox 360",
|
|
"Xbox/",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EPS3,
|
|
FLAG_DLNA | FLAG_MIME_AVI_DIVX,
|
|
"PLAYSTATION 3",
|
|
"PLAYSTATION",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EPS3,
|
|
FLAG_DLNA | FLAG_MIME_AVI_DIVX,
|
|
"PLAYSTATION 3",
|
|
"PLAYSTATION 3",
|
|
EXAVClientInfo
|
|
},
|
|
|
|
/* Samsung Series [CDE] BDPs and TVs must be separated, or some of our
|
|
* advertised extra features trigger a folder browsing bug on BDPs. */
|
|
/* User-Agent: DLNADOC/1.50 SEC_HHP_BD-D5100/1.0 */
|
|
{ ESamsungSeriesCDEBDP,
|
|
FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE,
|
|
"Samsung Series [CDEF] BDP",
|
|
"SEC_HHP_BD",
|
|
EUserAgent
|
|
},
|
|
|
|
/* User-Agent: DLNADOC/1.50 SEC_HHP_[TV]UE40D7000/1.0 */
|
|
/* User-Agent: DLNADOC/1.50 SEC_HHP_ Family TV/1.0 */
|
|
{ ESamsungSeriesCDE,
|
|
FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE | FLAG_SAMSUNG_DCM10,
|
|
"Samsung Series [CDEF]",
|
|
"SEC_HHP_",
|
|
EUserAgent
|
|
},
|
|
|
|
{ ESamsungSeriesA,
|
|
FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE,
|
|
"Samsung Series A",
|
|
"SamsungWiselinkPro",
|
|
EUserAgent
|
|
},
|
|
|
|
{ ESamsungSeriesB,
|
|
FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE,
|
|
"Samsung Series B",
|
|
"Samsung DTV DMR",
|
|
EModelName
|
|
},
|
|
|
|
/* User-Agent: Panasonic MIL DLNA CP UPnP/1.0 DLNADOC/1.50 */
|
|
{ EPanasonic,
|
|
FLAG_DLNA | FLAG_FORCE_SORT,
|
|
"Panasonic",
|
|
"Panasonic",
|
|
EUserAgent
|
|
},
|
|
|
|
/* User-Agent: IPI/1.0 UPnP/1.0 DLNADOC/1.50 */
|
|
{ ENetFrontLivingConnect,
|
|
FLAG_DLNA | FLAG_FORCE_SORT | FLAG_CAPTION_RES,
|
|
"NetFront Living Connect",
|
|
"IPI/1",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EDenonReceiver,
|
|
FLAG_DLNA,
|
|
"Denon Receiver",
|
|
"bridgeCo-DMP/3",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EFreeBox,
|
|
FLAG_RESIZE_THUMBS,
|
|
"FreeBox",
|
|
"fbxupnpav/",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EPopcornHour,
|
|
FLAG_MIME_FLAC_FLAC,
|
|
"Popcorn Hour",
|
|
"SMP8634",
|
|
EUserAgent
|
|
},
|
|
|
|
/* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Blu-ray Disc Player"; mv="2.0" */
|
|
/* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BLU-RAY HOME THEATRE SYSTEM"; mv="2.0"; */
|
|
/* Sony SMP-100 needs the same treatment as their BDP-S370 */
|
|
/* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Media Player"; mv="2.0" */
|
|
{ ESonyBDP,
|
|
FLAG_DLNA,
|
|
"Sony BDP",
|
|
"mv=\"2.0\"",
|
|
EXAVClientInfo
|
|
},
|
|
|
|
/* User-Agent: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0 */
|
|
{ ELGDevice,
|
|
FLAG_DLNA | FLAG_CAPTION_RES,
|
|
"LG",
|
|
"LGE_DLNA_SDK",
|
|
EUserAgent
|
|
},
|
|
|
|
/* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BRAVIA KDL-40EX503"; mv="1.7"; */
|
|
{ ESonyBravia,
|
|
FLAG_DLNA,
|
|
"Sony Bravia",
|
|
"BRAVIA",
|
|
EXAVClientInfo
|
|
},
|
|
|
|
/* X-AV-Client-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="INTERNET TV NSX-40GT 1"; mv="0.1"; */
|
|
{ ESonyInternetTV,
|
|
FLAG_DLNA,
|
|
"Sony Internet TV",
|
|
"INTERNET TV",
|
|
EXAVClientInfo
|
|
},
|
|
|
|
{ ENetgearEVA2000,
|
|
FLAG_MS_PFS | FLAG_RESIZE_THUMBS,
|
|
"EVA2000",
|
|
"Verismo,",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EDirecTV,
|
|
FLAG_RESIZE_THUMBS,
|
|
"DirecTV",
|
|
"DIRECTV ",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EToshibaTV,
|
|
FLAG_DLNA,
|
|
"Toshiba TV",
|
|
"UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2",
|
|
EUserAgent
|
|
},
|
|
|
|
{ ERokuSoundBridge,
|
|
FLAG_MS_PFS | FLAG_AUDIO_ONLY | FLAG_MIME_WAV_WAV | FLAG_FORCE_SORT,
|
|
"Roku SoundBridge",
|
|
"Roku SoundBridge",
|
|
EModelName
|
|
},
|
|
|
|
{ EMarantzDMP,
|
|
FLAG_DLNA | FLAG_MIME_WAV_WAV,
|
|
"marantz DMP",
|
|
"marantz DMP",
|
|
EFriendlyNameSSDP
|
|
},
|
|
|
|
{ EMediaRoom,
|
|
FLAG_MS_PFS,
|
|
"MS MediaRoom",
|
|
"Microsoft-IPTV-Client",
|
|
EUserAgent
|
|
},
|
|
|
|
{ ELifeTab,
|
|
FLAG_MS_PFS,
|
|
"LIFETAB",
|
|
"LIFETAB",
|
|
EFriendlyName
|
|
},
|
|
|
|
{ EAsusOPlay,
|
|
FLAG_DLNA | FLAG_MIME_AVI_AVI | FLAG_CAPTION_RES,
|
|
"Asus OPlay Mini/Mini+",
|
|
"O!Play",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EBubbleUPnP,
|
|
FLAG_CAPTION_RES,
|
|
"BubbleUPnP",
|
|
"BubbleUPnP",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EStandardDLNA150,
|
|
FLAG_DLNA | FLAG_MIME_AVI_AVI,
|
|
"Generic DLNA 1.5",
|
|
"DLNADOC/1.50",
|
|
EUserAgent
|
|
},
|
|
|
|
{ EStandardUPnP,
|
|
0,
|
|
"Generic UPnP 1.0",
|
|
"UPnP/1.0",
|
|
EUserAgent
|
|
},
|
|
|
|
{ 0, 0, NULL, 0 }
|
|
};
|
|
|
|
struct client_cache_s clients[CLIENT_CACHE_SLOTS];
|
|
|
|
struct client_cache_s *
|
|
SearchClientCache(struct in_addr addr, int quiet)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < CLIENT_CACHE_SLOTS; i++)
|
|
{
|
|
if (clients[i].addr.s_addr == addr.s_addr)
|
|
{
|
|
/* Invalidate this client cache if it's older than 1 hour */
|
|
if ((time(NULL) - clients[i].age) > 3600)
|
|
{
|
|
unsigned char mac[6];
|
|
if (get_remote_mac(addr, mac) == 0 &&
|
|
memcmp(mac, clients[i].mac, 6) == 0)
|
|
{
|
|
/* Same MAC as last time when we were able to identify the client,
|
|
* so extend the timeout by another hour. */
|
|
clients[i].age = time(NULL);
|
|
}
|
|
else
|
|
{
|
|
memset(&clients[i], 0, sizeof(struct client_cache_s));
|
|
return NULL;
|
|
}
|
|
}
|
|
if (!quiet)
|
|
DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [%s/entry %d]\n",
|
|
clients[i].type->name, i);
|
|
return &clients[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct client_cache_s *
|
|
AddClientCache(struct in_addr addr, int type)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < CLIENT_CACHE_SLOTS; i++)
|
|
{
|
|
if (clients[i].addr.s_addr)
|
|
continue;
|
|
get_remote_mac(addr, clients[i].mac);
|
|
clients[i].addr = addr;
|
|
clients[i].type = &client_types[type];
|
|
clients[i].age = time(NULL);
|
|
DPRINTF(E_DEBUG, L_HTTP, "Added client [%s/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n",
|
|
client_types[type].name, inet_ntoa(clients[i].addr),
|
|
clients[i].mac[0], clients[i].mac[1], clients[i].mac[2],
|
|
clients[i].mac[3], clients[i].mac[4], clients[i].mac[5], i);
|
|
return &clients[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|