xref: /haiku/src/kits/media/Controllable.cpp (revision cfc3fa87da824bdf593eb8b817a83b6376e77935)
1 /*
2  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 #include <OS.h>
31 #include <Controllable.h>
32 #include <ParameterWeb.h>
33 #include <Roster.h>
34 #include "debug.h"
35 #include "DataExchange.h"
36 #include "Notifications.h"
37 
38 /*************************************************************
39  * protected BControllable
40  *************************************************************/
41 
42 BControllable::~BControllable()
43 {
44 	CALLED();
45 	if (fSem > 0)
46 		delete_sem(fSem);
47 	if (fWeb)
48 		delete fWeb;
49 }
50 
51 /*************************************************************
52  * public BControllable
53  *************************************************************/
54 
55 BParameterWeb *
56 BControllable::Web()
57 {
58 	CALLED();
59 	BParameterWeb *temp;
60 	LockParameterWeb();
61 	temp = fWeb;
62 	UnlockParameterWeb();
63 	return temp;
64 }
65 
66 
67 bool
68 BControllable::LockParameterWeb()
69 {
70 	CALLED();
71 	status_t rv;
72 	if (fSem <= 0)
73 		return false;
74 	if (atomic_add(&fBen, 1) > 0) {
75 		while (B_INTERRUPTED == (rv = acquire_sem(fSem)))
76 			;
77 		return rv == B_OK;
78 	}
79 	return true;
80 }
81 
82 /*************************************************************
83  * protected BControllable
84  *************************************************************/
85 
86 void
87 BControllable::UnlockParameterWeb()
88 {
89 	CALLED();
90 	if (fSem <= 0)
91 		return;
92 	if (atomic_add(&fBen, -1) > 1)
93 		release_sem(fSem);
94 }
95 
96 
97 BControllable::BControllable() :
98 	BMediaNode("this one is never called"),
99 	fWeb(0),
100 	fSem(create_sem(0, "BControllable lock")),
101 	fBen(0)
102 {
103 	CALLED();
104 
105 	AddNodeKind(B_CONTROLLABLE);
106 }
107 
108 
109 status_t
110 BControllable::SetParameterWeb(BParameterWeb *web)
111 {
112 	CALLED();
113 	BParameterWeb *old;
114 	LockParameterWeb();
115 	old = fWeb;
116 	fWeb = web;
117 
118 	if (fWeb)
119 		fWeb->mNode = Node(); // initialize BParameterWeb member variable
120 
121 	UnlockParameterWeb();
122 	if (old != web && web != 0)
123 		BPrivate::media::notifications::WebChanged(Node());
124 	if (old)
125 		delete old;
126 	return B_OK;
127 }
128 
129 
130 status_t
131 BControllable::HandleMessage(int32 message, const void *data, size_t size)
132 {
133 	PRINT(4, "BControllable::HandleMessage %#lx, node %ld\n", message, ID());
134 
135 	status_t rv;
136 	switch (message) {
137 		case CONTROLLABLE_GET_PARAMETER_DATA:
138 		{
139 			const controllable_get_parameter_data_request *request = static_cast<const controllable_get_parameter_data_request *>(data);
140 			controllable_get_parameter_data_reply reply;
141 			area_id area;
142 			void *data;
143 
144 			if (request->area == -1) {
145 				// small data transfer uses buffer in reply
146 				area = -1;
147 				data = reply.rawdata;
148 			} else {
149 				// large data transfer, clone area
150 				area = clone_area("get parameter data clone", &data, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
151 				if (area < B_OK) {
152 					ERROR("CONTROLLABLE_GET_PARAMETER_DATA cloning area failed\n");
153 					request->SendReply(B_NO_MEMORY, &reply, sizeof(reply));
154 					return B_OK;
155 				}
156 			}
157 			reply.size = request->requestsize;
158 			rv = GetParameterValue(request->parameter_id, &reply.last_change, data, &reply.size);
159 			if (area != -1)
160 				delete_area(area);
161 			request->SendReply(rv, &reply, sizeof(reply));
162 			return B_OK;
163 		}
164 
165 		case CONTROLLABLE_SET_PARAMETER_DATA:
166 		{
167 			const controllable_set_parameter_data_request *request = static_cast<const controllable_set_parameter_data_request *>(data);
168 			controllable_set_parameter_data_reply reply;
169 			area_id area;
170 			const void *data;
171 
172 			if (request->area == -1) {
173 				// small data transfer uses buffer in request
174 				area = -1;
175 				data = request->rawdata;
176 			} else {
177 				// large data transfer, clone area
178 				area = clone_area("set parameter data clone", (void **)&data, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
179 				if (area < B_OK) {
180 					ERROR("CONTROLLABLE_SET_PARAMETER_DATA cloning area failed\n");
181 					request->SendReply(B_NO_MEMORY, &reply, sizeof(reply));
182 					return B_OK;
183 				}
184 			}
185 			SetParameterValue(request->parameter_id, request->when, data, request->size);
186 			if (area != -1)
187 				delete_area(area);
188 			request->SendReply(B_OK, &reply, sizeof(reply));
189 			return B_OK;
190 		}
191 
192 		case CONTROLLABLE_GET_PARAMETER_WEB:
193 		{
194 			const controllable_get_parameter_web_request *request = static_cast<const controllable_get_parameter_web_request *>(data);
195 			controllable_get_parameter_web_reply reply;
196 			bool waslocked = LockParameterWeb();
197 			if (fWeb != NULL && fWeb->FlattenedSize() > request->maxsize) {
198 				reply.code = 0;
199 				reply.size = -1; // parameter web too large
200 				rv = B_OK;
201 			} else if (fWeb != NULL && fWeb->FlattenedSize() <= request->maxsize) {
202 				void *buffer;
203 				area_id area;
204 				area = clone_area("cloned parameter web", &buffer, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
205 				if (area < B_OK) {
206 					ERROR("BControllable::HandleMessage CONTROLLABLE_GET_PARAMETER_WEB clone_area failed\n");
207 					rv = B_ERROR;
208 				} else {
209 					reply.code = fWeb->TypeCode();
210 					reply.size = fWeb->FlattenedSize();
211 					rv = fWeb->Flatten(buffer, reply.size);
212 					if (rv != B_OK) {
213 						ERROR("BControllable::HandleMessage CONTROLLABLE_GET_PARAMETER_WEB Flatten failed\n");
214 					} else {
215 						printf("BControllable::HandleMessage CONTROLLABLE_GET_PARAMETER_WEB %ld bytes, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
216 							reply.size, ((uint32*)buffer)[0], ((uint32*)buffer)[1], ((uint32*)buffer)[2], ((uint32*)buffer)[3]);
217 					}
218 					delete_area(area);
219 				}
220 			} else {
221 				reply.code = 0;
222 				reply.size = 0; // no parameter web
223 				rv = B_OK;
224 			}
225 			if (waslocked)
226 				UnlockParameterWeb();
227 			request->SendReply(rv, &reply, sizeof(reply));
228 			return B_OK;
229 		}
230 
231 		case CONTROLLABLE_START_CONTROL_PANEL:
232 		{
233 			const controllable_start_control_panel_request *request = static_cast<const controllable_start_control_panel_request*>(data);
234 			controllable_start_control_panel_reply reply;
235 			BMessenger targetMessenger;
236 			rv = StartControlPanel(&targetMessenger);
237 			if (rv != B_OK) {
238 				ERROR("BControllable::HandleMessage CONTROLLABLE_START_CONTROL_PANEL failed\n");
239 			}
240 			reply.result = rv;
241 			reply.team = targetMessenger.Team();
242 			request->SendReply(rv, &reply, sizeof(reply));
243 			return B_OK;
244 		}
245 	}
246 	return B_ERROR;
247 }
248 
249 
250 status_t
251 BControllable::BroadcastChangedParameter(int32 id)
252 {
253 	CALLED();
254 	return BPrivate::media::notifications::ParameterChanged(Node(), id);
255 }
256 
257 
258 status_t
259 BControllable::BroadcastNewParameterValue(bigtime_t when,
260 										  int32 id,
261 										  void *newValue,
262 										  size_t valueSize)
263 {
264 	CALLED();
265 	return BPrivate::media::notifications::NewParameterValue(Node(), id, when, newValue, valueSize);
266 }
267 
268 
269 status_t
270 BControllable::StartControlPanel(BMessenger *out_messenger)
271 {
272 	CALLED();
273 
274 	int32 internalId;
275 	BMediaAddOn* addon = AddOn(&internalId);
276 	if (!addon) {
277 		ERROR("BControllable::StartControlPanel not instantiated per AddOn\n");
278 		return B_ERROR;
279 	}
280 
281 	image_id imageId = addon->ImageID();
282 	image_info info;
283 	if ((imageId <= 0) || (get_image_info(imageId, &info) != B_OK)) {
284 		ERROR("BControllable::StartControlPanel Error accessing image\n");
285 		return B_BAD_VALUE;
286 	}
287 
288 	team_id id;
289 	entry_ref ref;
290 
291 	if (BEntry(info.name).GetRef(&ref) != B_OK) {
292 		ERROR("BControllable::StartControlPanel Error getting ref\n");
293 		return B_BAD_VALUE;
294 	}
295 
296 	// The first argument is "node=id" with id meaning the media_node_id
297 	char *arg = (char*) malloc(10);
298 	sprintf(arg, "node=%d" , (int) ID());
299 
300 	if (be_roster->Launch(&ref, 1, &arg, &id) != B_OK) {
301 		free(arg);
302 		ERROR("BControllable::StartControlPanel Error launching application\n");
303 		return B_BAD_VALUE;
304 	}
305 	printf("BControllable::StartControlPanel done with id: %ld\n", id);
306 	free(arg);
307 
308 	if (out_messenger)
309 		*out_messenger = BMessenger(0, id);
310 
311 	return B_OK;
312 }
313 
314 
315 status_t
316 BControllable::ApplyParameterData(const void *value,
317 								  size_t size)
318 {
319 	UNIMPLEMENTED();
320 
321 	return B_ERROR;
322 }
323 
324 
325 status_t
326 BControllable::MakeParameterData(const int32 *controls,
327 								 int32 count,
328 								 void *buf,
329 								 size_t *ioSize)
330 {
331 	UNIMPLEMENTED();
332 
333 	return B_ERROR;
334 }
335 
336 /*************************************************************
337  * private BControllable
338  *************************************************************/
339 
340 /*
341 private unimplemented
342 BControllable::BControllable(const BControllable &clone)
343 BControllable & BControllable::operator=(const BControllable &clone)
344 */
345 
346 status_t BControllable::_Reserved_Controllable_0(void *) { return B_ERROR; }
347 status_t BControllable::_Reserved_Controllable_1(void *) { return B_ERROR; }
348 status_t BControllable::_Reserved_Controllable_2(void *) { return B_ERROR; }
349 status_t BControllable::_Reserved_Controllable_3(void *) { return B_ERROR; }
350 status_t BControllable::_Reserved_Controllable_4(void *) { return B_ERROR; }
351 status_t BControllable::_Reserved_Controllable_5(void *) { return B_ERROR; }
352 status_t BControllable::_Reserved_Controllable_6(void *) { return B_ERROR; }
353 status_t BControllable::_Reserved_Controllable_7(void *) { return B_ERROR; }
354 status_t BControllable::_Reserved_Controllable_8(void *) { return B_ERROR; }
355 status_t BControllable::_Reserved_Controllable_9(void *) { return B_ERROR; }
356 status_t BControllable::_Reserved_Controllable_10(void *) { return B_ERROR; }
357 status_t BControllable::_Reserved_Controllable_11(void *) { return B_ERROR; }
358 status_t BControllable::_Reserved_Controllable_12(void *) { return B_ERROR; }
359 status_t BControllable::_Reserved_Controllable_13(void *) { return B_ERROR; }
360 status_t BControllable::_Reserved_Controllable_14(void *) { return B_ERROR; }
361 status_t BControllable::_Reserved_Controllable_15(void *) { return B_ERROR; }
362 
363 
364