improved: upnp caching, now refreshes the current directory or cache when a container...
[xbmc:xbmc-antiquated.git] / xbmc / lib / libUPnP / Platinum / Source / Devices / MediaServer / PltMediaBrowser.cpp
1 /*****************************************************************
2 |
3 |   Platinum - AV Media Browser (Media Server Control Point)
4 |
5 | Copyright (c) 2004-2008, Plutinosoft, LLC.
6 | All rights reserved.
7 | http://www.plutinosoft.com
8 |
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
13 |
14 | OEMs, ISVs, VARs and other distributors that combine and 
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20
21 | This program is distributed in the hope that it will be useful,
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 | GNU General Public License for more details.
25 |
26 | You should have received a copy of the GNU General Public License
27 | along with this program; see the file LICENSE.txt. If not, write to
28 | the Free Software Foundation, Inc., 
29 | 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
30 | http://www.gnu.org/licenses/gpl-2.0.html
31 |
32 ****************************************************************/
33
34 /*----------------------------------------------------------------------
35 |   includes
36 +---------------------------------------------------------------------*/
37 #include "Neptune.h"
38 #include "PltMediaBrowser.h"
39 #include "PltDidl.h"
40 #include "PltMediaBrowserListener.h"
41
42 NPT_SET_LOCAL_LOGGER("platinum.media.server.browser")
43
44 /*----------------------------------------------------------------------
45 |   PLT_MediaBrowser::PLT_MediaBrowser
46 +---------------------------------------------------------------------*/
47 PLT_MediaBrowser::PLT_MediaBrowser(PLT_CtrlPointReference&   ctrl_point, 
48                                    PLT_MediaBrowserListener* listener) :
49     m_CtrlPoint(ctrl_point),
50     m_Listener(listener)
51 {
52     m_CtrlPoint->AddListener(this);
53 }
54
55 /*----------------------------------------------------------------------
56 |   PLT_MediaBrowser::~PLT_MediaBrowser
57 +---------------------------------------------------------------------*/
58 PLT_MediaBrowser::~PLT_MediaBrowser()
59 {
60     m_CtrlPoint->RemoveListener(this);
61 }
62
63 /*----------------------------------------------------------------------
64 |   PLT_MediaBrowser::OnDeviceAdded
65 +---------------------------------------------------------------------*/
66 NPT_Result
67 PLT_MediaBrowser::OnDeviceAdded(PLT_DeviceDataReference& device)
68 {
69     // verify the device implements the function we need
70     PLT_Service* serviceCDS;
71     PLT_Service* serviceCMR;
72     NPT_String type;
73     
74     type = "urn:schemas-upnp-org:service:ContentDirectory:1";
75     if (NPT_FAILED(device->FindServiceByType(type, serviceCDS))) {
76         NPT_LOG_WARNING_2("Service %s not found in device \"%s\"", 
77             type.GetChars(),
78             device->GetFriendlyName().GetChars());
79         return NPT_FAILURE;
80     }
81     
82     type = "urn:schemas-upnp-org:service:ConnectionManager:1";
83     if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) {
84         NPT_LOG_WARNING_2("Service %s not found in device \"%s\"", 
85             type.GetChars(), 
86             device->GetFriendlyName().GetChars());
87         return NPT_FAILURE;
88     }    
89     
90     {
91         NPT_AutoLock lock(m_MediaServers);
92
93         PLT_DeviceDataReference data;
94         NPT_String uuid = device->GetUUID();
95         // is it a new device?
96         if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) {
97             NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid);
98             return NPT_FAILURE;
99         }
100
101         NPT_LOG_FINE("Device Found:");
102         device->ToLog(NPT_LOG_LEVEL_FINE);
103
104         m_MediaServers.Add(device);
105     }
106
107     if (m_Listener) m_Listener->OnMSAddedRemoved(device, 1);
108
109     m_CtrlPoint->Subscribe(serviceCDS);
110     m_CtrlPoint->Subscribe(serviceCMR);
111
112     return NPT_SUCCESS;
113 }
114
115 /*----------------------------------------------------------------------
116 |   PLT_MediaBrowser::OnDeviceRemoved
117 +---------------------------------------------------------------------*/
118 NPT_Result 
119 PLT_MediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference& device)
120 {
121     PLT_DeviceDataReference data;
122
123     {
124         NPT_AutoLock lock(m_MediaServers);
125
126         // only release if we have kept it around
127         NPT_String uuid = device->GetUUID();
128         // is it a new device?
129         if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) {
130             NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid);
131             return NPT_FAILURE;
132         }
133
134         NPT_LOG_FINE("Device Removed:");
135         device->ToLog(NPT_LOG_LEVEL_FINE);
136
137         m_MediaServers.Remove(device);
138     }
139
140     if (m_Listener) m_Listener->OnMSAddedRemoved(device, 0);
141     return NPT_SUCCESS;
142 }
143
144 /*----------------------------------------------------------------------
145 |   PLT_MediaBrowser::Browse
146 +---------------------------------------------------------------------*/
147 NPT_Result 
148 PLT_MediaBrowser::Browse(PLT_DeviceDataReference&   device, 
149                          const char*                obj_id,
150                          NPT_UInt32                 start_index,
151                          NPT_UInt32                 count,
152                          bool                       browse_metadata,
153                          const char*                filter,
154                          const char*                sort_criteria,
155                          void*                      userdata)
156 {
157     // look for the service
158     PLT_Service* service;
159     NPT_String type;
160
161     type = "urn:schemas-upnp-org:service:ContentDirectory:1";
162     if (NPT_FAILED(device->FindServiceByType(type, service))) {
163         NPT_LOG_WARNING_1("Service %s not found", (const char*)type);
164         return NPT_FAILURE;
165     }
166
167     PLT_ActionDesc* action_desc = service->FindActionDesc("Browse");
168     if (action_desc == NULL) {
169         NPT_LOG_WARNING("Action Browse not found in service");
170         return NPT_FAILURE;
171     }
172
173     PLT_ActionReference action(new PLT_Action(action_desc));
174
175     // Set the object id
176     PLT_Arguments args;
177     if (NPT_FAILED(action->SetArgumentValue("ObjectID", obj_id))) {
178         return NPT_ERROR_INVALID_PARAMETERS;
179     }
180
181     // set the browse_flag
182     if (NPT_FAILED(action->SetArgumentValue("BrowseFlag", browse_metadata?"BrowseMetadata":"BrowseDirectChildren"))) {
183         return NPT_ERROR_INVALID_PARAMETERS;
184     }
185  
186     // set the Filter
187     if (NPT_FAILED(action->SetArgumentValue("Filter", filter))) {
188         return NPT_ERROR_INVALID_PARAMETERS;
189     }
190
191     // set the Starting Index
192     if (NPT_FAILED(action->SetArgumentValue("StartingIndex", NPT_String::FromInteger(start_index)))) {
193         return NPT_ERROR_INVALID_PARAMETERS;
194     }
195
196     // set the Requested Count
197     if (NPT_FAILED(action->SetArgumentValue("RequestedCount", NPT_String::FromInteger(count)))) {
198         return NPT_ERROR_INVALID_PARAMETERS;
199     }
200
201     // set the Requested Count
202     if (NPT_FAILED(action->SetArgumentValue("SortCriteria", sort_criteria))) {
203         return NPT_ERROR_INVALID_PARAMETERS;
204     }
205
206     // invoke the action
207     if (NPT_FAILED(m_CtrlPoint->InvokeAction(action, userdata))) {
208         return NPT_ERROR_INVALID_PARAMETERS;
209     }
210
211     return NPT_SUCCESS;
212 }
213
214 /*----------------------------------------------------------------------
215 |   PLT_MediaBrowser::OnActionResponse
216 +---------------------------------------------------------------------*/
217 NPT_Result
218 PLT_MediaBrowser::OnActionResponse(NPT_Result res, PLT_ActionReference& action, void* userdata)
219 {
220     PLT_DeviceDataReference device;
221
222     {
223         NPT_AutoLock lock(m_MediaServers);
224         NPT_String uuid = action->GetActionDesc()->GetService()->GetDevice()->GetUUID();
225         if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), device))) {
226             NPT_LOG_WARNING_1("Device (%s) not found in our list of servers", (const char*)uuid);
227             return NPT_FAILURE;
228         }
229     }
230
231     NPT_String actionName = action->GetActionDesc()->GetName();
232
233     // Browse action response
234     if (actionName.Compare("Browse", true) == 0) {
235         return OnBrowseResponse(res, device, action, userdata);
236     }
237
238     return NPT_SUCCESS;
239 }
240
241 /*----------------------------------------------------------------------
242 |   PLT_MediaBrowser::OnBrowseResponse
243 +---------------------------------------------------------------------*/
244 NPT_Result
245 PLT_MediaBrowser::OnBrowseResponse(NPT_Result res, PLT_DeviceDataReference& device, PLT_ActionReference& action, void* userdata)
246 {
247     NPT_String value;
248     PLT_BrowseInfo info;
249     NPT_String unescaped;
250
251     if (NPT_FAILED(res) || action->GetErrorCode() != 0) {
252         goto bad_action;
253     }
254
255     if (NPT_FAILED(action->GetArgumentValue("ObjectID", info.object_id)))  {
256         goto bad_action;
257     }
258     if (NPT_FAILED(action->GetArgumentValue("UpdateID", value)) || 
259         value.GetLength() == 0 || 
260         NPT_FAILED(value.ToInteger(info.uid))) {
261         goto bad_action;
262     }
263     if (NPT_FAILED(action->GetArgumentValue("NumberReturned", value)) || 
264         value.GetLength() == 0 || 
265         NPT_FAILED(value.ToInteger(info.nr))) {
266         goto bad_action;
267     }
268     if (NPT_FAILED(action->GetArgumentValue("TotalMatches", value)) || 
269         value.GetLength() == 0 || 
270         NPT_FAILED(value.ToInteger(info.tm))) {
271         goto bad_action;
272     }
273     if (NPT_FAILED(action->GetArgumentValue("Result", value)) || 
274         value.GetLength() == 0) {
275         goto bad_action;
276     }
277     
278     if (NPT_FAILED(PLT_Didl::FromDidl(value, info.items))) {
279         goto bad_action;
280     }
281
282     if (m_Listener) m_Listener->OnMSBrowseResult(NPT_SUCCESS, device, &info, userdata);
283     return NPT_SUCCESS;
284
285 bad_action:
286     if (m_Listener) m_Listener->OnMSBrowseResult(NPT_FAILURE, device, NULL, userdata);
287     return NPT_FAILURE;
288 }
289
290 /*----------------------------------------------------------------------
291 |   PLT_MediaBrowser::OnEventNotify
292 +---------------------------------------------------------------------*/
293 NPT_Result
294 PLT_MediaBrowser::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars)
295 {
296
297     PLT_DeviceDataReference data;
298
299     {
300         NPT_AutoLock lock(m_MediaServers);
301         NPT_String uuid = service->GetDevice()->GetUUID();
302         if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) {
303             NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid);
304             return NPT_FAILURE;
305         }
306     }
307
308     if (m_Listener) m_Listener->OnMSStateVariablesChanged(service, vars);
309     return NPT_SUCCESS;
310 }