1 
2 /*
3  *			GPAC - Multimedia Framework C SDK
4  *
5  *			Authors: Jean Le Feuvre
6  *			Copyright (c) Telecom ParisTech 2009-2012
7  *			All rights reserved
8  *
9  *  This file is part of GPAC / Platinum UPnP module
10  *
11  *  GPAC is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU Lesser General Public License as published by
13  *  the Free Software Foundation; either version 2, or (at your option)
14  *  any later version.
15  *
16  *  GPAC is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU Lesser General Public License for more details.
20  *
21  *  You should have received a copy of the GNU Lesser General Public
22  *  License along with this library; see the file COPYING.  If not, write to
23  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  *
26  *	----------------------------------------------------------------------------------
27  *		PLATINUM IS LICENSED UNDER GPL or commercial agreement - cf platinum license
28  *	----------------------------------------------------------------------------------
29  *
30  */
31 
32 
33 #include "GPACPlatinum.h"
34 
GPAC_MediaController(PLT_CtrlPointReference & ctrlPoint,GF_UPnP * upnp)35 GPAC_MediaController::GPAC_MediaController(PLT_CtrlPointReference& ctrlPoint, GF_UPnP *upnp)
36 {
37 	m_MediaController = new PLT_MediaController(ctrlPoint, this);
38 	m_MediaBrowser = new PLT_MediaBrowser(ctrlPoint, this);
39 
40 	m_MediaServers = gf_list_new();
41 	m_MediaRenderers = gf_list_new();
42 	m_ControlPointLock = gf_mx_new("AVControlPoint");
43 	m_pUPnP = upnp;
44 }
45 
46 
~GPAC_MediaController()47 GPAC_MediaController::~GPAC_MediaController()
48 {
49 	delete m_MediaController;
50 	m_MediaController=NULL;
51 	delete m_MediaBrowser;
52 	m_MediaBrowser=NULL;
53 
54 	while (gf_list_count(m_MediaServers)) {
55 		GPAC_MediaServerItem*ms = (GPAC_MediaServerItem*)gf_list_get(m_MediaServers, 0);
56 		gf_list_rem(m_MediaServers, 0);
57 		delete ms;
58 	}
59 	gf_list_del(m_MediaServers);
60 
61 	while (gf_list_count(m_MediaRenderers)) {
62 		GPAC_MediaRendererItem *ms = (GPAC_MediaRendererItem *)gf_list_get(m_MediaRenderers, 0);
63 		gf_list_rem(m_MediaRenderers, 0);
64 		delete ms;
65 	}
66 	gf_list_del(m_MediaRenderers);
67 
68 	gf_mx_del(m_ControlPointLock);
69 }
70 
71 
72 
73 
74 bool
OnMRAdded(PLT_DeviceDataReference & device)75 GPAC_MediaController::OnMRAdded(PLT_DeviceDataReference& device)
76 {
77 	NPT_String uuid = device->GetUUID();
78 
79 	gf_mx_p(m_ControlPointLock);
80 
81 	// test if it's a media renderer
82 	PLT_Service* service;
83 	if (NPT_SUCCEEDED(device->FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", service))) {
84 		gf_list_add(m_MediaRenderers, new GPAC_MediaRendererItem(device, uuid) );
85 	}
86 	m_pUPnP->OnMediaRendererAdd(device, 1);
87 	gf_mx_v(m_ControlPointLock);
88 	return true;
89 }
90 
91 
92 void
OnMRRemoved(PLT_DeviceDataReference & device)93 GPAC_MediaController::OnMRRemoved(PLT_DeviceDataReference& device)
94 {
95 	NPT_String uuid = device->GetUUID();
96 
97 	gf_mx_p(m_ControlPointLock);
98 
99 	u32 i, count;
100 	count = gf_list_count(m_MediaRenderers);
101 	for (i=0; i<count; i++) {
102 		GPAC_MediaRendererItem *ms = (GPAC_MediaRendererItem *) gf_list_get(m_MediaRenderers, i);
103 		if (ms->m_UUID==uuid) {
104 			delete ms;
105 			gf_list_rem(m_MediaRenderers, i);
106 			break;
107 		}
108 	}
109 
110 	m_pUPnP->OnMediaRendererAdd(device, 0);
111 	gf_mx_v(m_ControlPointLock);
112 }
113 
114 bool
OnMSAdded(PLT_DeviceDataReference & device)115 GPAC_MediaController::OnMSAdded(PLT_DeviceDataReference& device)
116 {
117 	NPT_String uuid = device->GetUUID();
118 
119 	gf_mx_p(m_ControlPointLock);
120 	// test if it's a media server
121 	PLT_Service* service;
122 	if (NPT_SUCCEEDED(device->FindServiceByType("urn:schemas-upnp-org:service:ContentDirectory:1", service))) {
123 		gf_list_add(m_MediaServers, new GPAC_MediaServerItem(device, uuid) );
124 	}
125 	m_pUPnP->OnMediaServerAdd(device, 1);
126 	gf_mx_v(m_ControlPointLock);
127 	return true;
128 }
129 
130 
131 void
OnMSRemoved(PLT_DeviceDataReference & device)132 GPAC_MediaController::OnMSRemoved(PLT_DeviceDataReference& device)
133 {
134 	NPT_String uuid = device->GetUUID();
135 
136 	gf_mx_p(m_ControlPointLock);
137 	u32 i, count;
138 	count = gf_list_count(m_MediaServers);
139 	for (i=0; i<count; i++) {
140 		GPAC_MediaServerItem *ms = (GPAC_MediaServerItem *) gf_list_get(m_MediaServers, i);
141 		if (ms->m_UUID==uuid) {
142 			delete ms;
143 			gf_list_rem(m_MediaServers, i);
144 			break;
145 		}
146 	}
147 	m_pUPnP->OnMediaServerAdd(device, 0);
148 	gf_mx_v(m_ControlPointLock);
149 }
150 
151 
152 
153 NPT_Result
OnActionResponse(NPT_Result res,PLT_ActionReference & action,void * userdata)154 GPAC_MediaController::OnActionResponse(NPT_Result           res,
155                                        PLT_ActionReference& action,
156                                        void*                userdata)
157 {
158 	return NPT_SUCCESS;
159 }
160 
OnEventNotify(PLT_Service * service,NPT_List<PLT_StateVariable * > * vars)161 NPT_Result GPAC_MediaController::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars)
162 {
163 	return NPT_SUCCESS;
164 }
165 
OnMRStateVariablesChanged(PLT_Service * service,NPT_List<PLT_StateVariable * > * vars)166 void GPAC_MediaController::OnMRStateVariablesChanged(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars )
167 {
168 	u32 count;
169 	u32 i;
170 	s32 render_idx = -1;
171 
172 	count = gf_list_count(m_MediaRenderers);
173 	for (i=0; i<count; i++) {
174 		GPAC_MediaRendererItem *mr = (GPAC_MediaRendererItem *) gf_list_get(m_MediaRenderers, i);
175 		if ( mr->m_device.AsPointer() == service->GetDevice() ) {
176 			render_idx = i;
177 			break;
178 		}
179 	}
180 	if (render_idx < 0) return;
181 
182 	count = vars->GetItemCount();
183 	for (i=0; i<count; i++) {
184 		PLT_StateVariable *svar;
185 		vars->Get(i, svar);
186 		if (svar->GetName() == NPT_String("AbsoluteTimePosition")) {
187 			u32 h, m, s;
188 			if (sscanf((char *) svar->GetValue(), "%d:%d:%d", &h, &m, &s)==3) {
189 				Double time = h*3600 + m*60 + s;
190 				this->m_pUPnP->onTimeChanged(render_idx, time);
191 			}
192 		}
193 		else if (svar->GetName() == NPT_String("CurrentTrackDuration")) {
194 			u32 h, m, s;
195 			if (sscanf((char *) svar->GetValue(), "%d:%d:%d", &h, &m, &s)==3) {
196 				Double time = h*3600 + m*60 + s;
197 				this->m_pUPnP->onDurationChanged(render_idx, time);
198 			}
199 		}
200 
201 	}
202 }
203 
204 
OnBrowseResult(NPT_Result res,PLT_DeviceDataReference & device,PLT_BrowseInfo * info,void * userdata)205 void GPAC_MediaController::OnBrowseResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_BrowseInfo* info, void* userdata)
206 {
207 	NPT_COMPILER_UNUSED(device);
208 
209 	NPT_COMPILER_UNUSED(device);
210 
211 	if (!userdata) return;
212 
213 	GPAC_BrowseDataReference* data = (GPAC_BrowseDataReference*) userdata;
214 	(*data)->res = res;
215 	if (NPT_SUCCEEDED(res) && info) {
216 		(*data)->info = *info;
217 	}
218 	(*data)->shared_var.SetValue(1);
219 	delete data;
220 }
221 
222 void
OnMSStateVariablesChanged(PLT_Service * service,NPT_List<PLT_StateVariable * > * vars)223 GPAC_MediaController::OnMSStateVariablesChanged(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars)
224 {
225 	GPAC_MediaServerItem *ms = NULL;
226 	gf_mx_p(m_ControlPointLock);
227 
228 	u32 i, count;
229 	count = gf_list_count(m_MediaServers);
230 	for (i=0; i<count; i++) {
231 		GPAC_MediaServerItem *ms = (GPAC_MediaServerItem *) gf_list_get(m_MediaServers, i);
232 		if (ms->m_UUID==service->GetDevice()->GetUUID()) {
233 			break;
234 		}
235 		ms = NULL;
236 	}
237 
238 	if (!ms) {
239 		gf_mx_v(m_ControlPointLock);
240 		return;
241 	}
242 
243 	PLT_StateVariable* var = PLT_StateVariable::Find(*vars, "ContainerUpdateIDs");
244 	if (var) {
245 		// variable found, parse value
246 		NPT_String value = var->GetValue();
247 		NPT_String item_id, update_id;
248 		int index;
249 
250 		while (value.GetLength()) {
251 			// look for container id
252 			index = value.Find(',');
253 			if (index < 0) break;
254 			item_id = value.Left(index);
255 			value = value.SubString(index+1);
256 
257 			// look for update id
258 			if (value.GetLength()) {
259 				index = value.Find(',');
260 				update_id = (index<0)?value:value.Left(index);
261 				value = (index<0)?"":value.SubString(index+1);
262 
263 				m_pUPnP->ContainerChanged(ms->m_device, item_id, update_id);
264 			}
265 		}
266 	}
267 	gf_mx_v(m_ControlPointLock);
268 }
269 
270 NPT_Result
WaitForResponse(NPT_SharedVariable & shared_var)271 GPAC_MediaController::WaitForResponse(NPT_SharedVariable& shared_var)
272 {
273 	return shared_var.WaitUntilEquals(1, 30000);
274 }
275 
276 
277 NPT_Result
Browse(GPAC_BrowseDataReference & browse_data,PLT_DeviceDataReference & device,const char * object_id,NPT_Int32 index,NPT_Int32 count,bool browse_metadata,const char * filter,const char * sort)278 GPAC_MediaController::Browse(GPAC_BrowseDataReference& browse_data,
279                              PLT_DeviceDataReference& device,
280                              const char*              object_id,
281                              NPT_Int32                index,
282                              NPT_Int32                count,
283                              bool                     browse_metadata,
284                              const char*              filter,
285                              const char*              sort)
286 {
287 	NPT_Result res;
288 
289 	browse_data->shared_var.SetValue(0);
290 
291 	// send off the browse packet.  Note that this will
292 	// not block.  There is a call to WaitForResponse in order
293 	// to block until the response comes back.
294 	res = m_MediaBrowser->Browse(device,
295 	                             (const char*)object_id,
296 	                             index,
297 	                             count,
298 	                             browse_metadata,
299 	                             filter,
300 	                             sort,
301 	                             new GPAC_BrowseDataReference(browse_data));
302 	NPT_CHECK_SEVERE(res);
303 
304 	return WaitForResponse(browse_data->shared_var);
305 }
306 
307 NPT_Result
Browse(GPAC_MediaServerItem * server,const char * object_id,const char * filter)308 GPAC_MediaController::Browse(GPAC_MediaServerItem *server, const char *object_id, const char *filter)
309 {
310 	NPT_Result res = NPT_FAILURE;
311 	NPT_Int32  index = 0;
312 
313 	// reset output params
314 	server->m_BrowseResults = NULL;
315 
316 
317 	do {
318 		GPAC_BrowseDataReference browse_data(new GPAC_BrowseData());
319 
320 		// send off the browse packet.  Note that this will
321 		// not block.  There is a call to WaitForResponse in order
322 		// to block until the response comes back.
323 		res = Browse(browse_data,
324 		             server->m_device,
325 		             (const char*)object_id,
326 		             index,
327 		             1024,
328 		             false,
329 		             filter,
330 		             "");
331 		NPT_CHECK_LABEL_WARNING(res, done);
332 
333 		if (NPT_FAILED(browse_data->res)) {
334 			res = browse_data->res;
335 			NPT_CHECK_LABEL_WARNING(res, done);
336 		}
337 
338 		if (browse_data->info.items->GetItemCount() == 0)
339 			break;
340 
341 		if (server->m_BrowseResults.IsNull()) {
342 			server->m_BrowseResults = browse_data->info.items;
343 		} else {
344 			server->m_BrowseResults->Add(*browse_data->info.items);
345 			// clear the list items so that the data inside is not
346 			// cleaned up by PLT_MediaItemList dtor since we copied
347 			// each pointer into the new list.
348 			browse_data->info.items->Clear();
349 		}
350 
351 		// stop now if our list contains exactly what the server said it had
352 		if (browse_data->info.tm && browse_data->info.tm == server->m_BrowseResults->GetItemCount())
353 			break;
354 
355 		// ask for the next chunk of entries
356 		index = server->m_BrowseResults->GetItemCount();
357 	} while(1);
358 
359 done:
360 	return res;
361 }
362 
363