2 * Copyright 2009-2012, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT license.
7 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files or portions
11 * thereof (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so, subject
15 * to the following conditions:
17 * * Redistributions of source code must retain the above copyright notice,
18 * this list of conditions and the following disclaimer.
20 * * Redistributions in binary form must reproduce the above copyright notice
21 * in the binary, as well as this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided with
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 #include <Controllable.h>
40 #include <ParameterWeb.h>
42 #include <TimeSource.h>
45 #include <DataExchange.h>
46 #include <Notifications.h>
49 namespace BPrivate
{ namespace media
{
51 /*! A helper class for the communication with the media server that
52 takes care of large buffers that need an area.
54 class ReceiveTransfer
{
56 ReceiveTransfer(const area_request_data
& request
, const void* smallBuffer
)
58 if (request
.area
== -1 && smallBuffer
!= NULL
) {
59 // small data transfer uses buffer in reply
61 fData
= const_cast<void*>(smallBuffer
);
62 // The caller is actually responsible to enforce the const;
63 // we don't touch the data.
65 // large data transfer, clone area
66 fArea
= clone_area("get parameter data clone", &fData
,
67 B_ANY_ADDRESS
, B_READ_AREA
| B_WRITE_AREA
, request
.area
);
69 ERROR("BControllabe: cloning area failed: %s\n",
82 status_t
InitCheck() const
84 return fData
!= NULL
? B_OK
: fArea
;
98 } // namespace BPrivate
100 using BPrivate::media::ReceiveTransfer
;
103 // #pragma mark - protected
106 BControllable::~BControllable()
116 // #pragma mark - public
128 BControllable::LockParameterWeb()
134 if (atomic_add(&fBen
, 1) > 0) {
137 status
= acquire_sem(fSem
);
138 } while (status
== B_INTERRUPTED
);
140 return status
== B_OK
;
148 BControllable::UnlockParameterWeb()
154 if (atomic_add(&fBen
, -1) > 1)
159 // #pragma mark - protected
162 BControllable::BControllable()
163 : BMediaNode("this one is never called"),
165 fSem(create_sem(0, "BControllable lock")),
170 AddNodeKind(B_CONTROLLABLE
);
175 BControllable::SetParameterWeb(BParameterWeb
* web
)
180 BParameterWeb
* old
= fWeb
;
184 // initialize BParameterWeb member variable
185 fWeb
->fNode
= Node();
188 UnlockParameterWeb();
190 if (old
!= web
&& web
!= NULL
)
191 BPrivate::media::notifications::WebChanged(Node());
198 BControllable::HandleMessage(int32 message
, const void* data
, size_t size
)
200 PRINT(4, "BControllable::HandleMessage %#lx, node %ld\n", message
, ID());
203 case CONTROLLABLE_GET_PARAMETER_DATA
:
205 const controllable_get_parameter_data_request
& request
206 = *static_cast<const controllable_get_parameter_data_request
*>(
208 controllable_get_parameter_data_reply reply
;
210 ReceiveTransfer
transfer(request
, reply
.raw_data
);
211 if (transfer
.InitCheck() != B_OK
) {
212 request
.SendReply(transfer
.InitCheck(), &reply
, sizeof(reply
));
216 reply
.size
= request
.request_size
;
217 status_t status
= GetParameterValue(request
.parameter_id
,
218 &reply
.last_change
, transfer
.Data(), &reply
.size
);
220 request
.SendReply(status
, &reply
, sizeof(reply
));
224 case CONTROLLABLE_SET_PARAMETER_DATA
:
226 const controllable_set_parameter_data_request
& request
227 = *static_cast<const controllable_set_parameter_data_request
*>(
229 controllable_set_parameter_data_reply reply
;
231 ReceiveTransfer
transfer(request
, request
.raw_data
);
232 if (transfer
.InitCheck() != B_OK
) {
233 request
.SendReply(transfer
.InitCheck(), &reply
, sizeof(reply
));
237 // NOTE: This is not very fair, but the alternative
238 // would have been to mess with friends classes and
240 bigtime_t perfTime
= 0;
241 if (request
.when
== -1)
242 perfTime
= TimeSource()->Now();
244 perfTime
= request
.when
;
246 SetParameterValue(request
.parameter_id
, perfTime
,
247 transfer
.Data(), request
.size
);
248 request
.SendReply(B_OK
, &reply
, sizeof(reply
));
252 case CONTROLLABLE_GET_PARAMETER_WEB
:
254 const controllable_get_parameter_web_request
& request
255 = *static_cast<const controllable_get_parameter_web_request
*>(
257 controllable_get_parameter_web_reply reply
;
259 status_t status
= B_OK
;
260 bool wasLocked
= true;
261 if (!LockParameterWeb()) {
266 if (status
== B_OK
&& fWeb
!= NULL
) {
267 if (fWeb
->FlattenedSize() > request
.max_size
) {
268 // parameter web too large
273 ReceiveTransfer
transfer(request
, NULL
);
274 status
= transfer
.InitCheck();
275 if (status
== B_OK
) {
276 reply
.code
= fWeb
->TypeCode();
277 reply
.size
= fWeb
->FlattenedSize();
278 status
= fWeb
->Flatten(transfer
.Data(), reply
.size
);
279 if (status
!= B_OK
) {
280 ERROR("BControllable::HandleMessage "
281 "CONTROLLABLE_GET_PARAMETER_WEB Flatten failed\n");
284 printf("BControllable::HandleMessage CONTROLLABLE_GET_PARAMETER_WEB %ld bytes, 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n",
285 reply
.size
, ((uint32
*)buffer
)[0], ((uint32
*)buffer
)[1], ((uint32
*)buffer
)[2], ((uint32
*)buffer
)[3]);
296 UnlockParameterWeb();
298 request
.SendReply(status
, &reply
, sizeof(reply
));
302 case CONTROLLABLE_START_CONTROL_PANEL
:
304 const controllable_start_control_panel_request
* request
305 = static_cast<const controllable_start_control_panel_request
*>(
307 controllable_start_control_panel_reply reply
;
308 BMessenger targetMessenger
;
309 status_t status
= StartControlPanel(&targetMessenger
);
310 if (status
!= B_OK
) {
311 ERROR("BControllable::HandleMessage "
312 "CONTROLLABLE_START_CONTROL_PANEL failed\n");
314 reply
.result
= status
;
315 reply
.team
= targetMessenger
.Team();
316 request
->SendReply(status
, &reply
, sizeof(reply
));
329 BControllable::BroadcastChangedParameter(int32 id
)
332 return BPrivate::media::notifications::ParameterChanged(Node(), id
);
337 BControllable::BroadcastNewParameterValue(bigtime_t when
, int32 id
,
338 void* newValue
, size_t valueSize
)
341 return BPrivate::media::notifications::NewParameterValue(Node(), id
, when
,
342 newValue
, valueSize
);
347 BControllable::StartControlPanel(BMessenger
* _messenger
)
352 BMediaAddOn
* addon
= AddOn(&internalId
);
354 ERROR("BControllable::StartControlPanel not instantiated per AddOn\n");
358 image_id imageID
= addon
->ImageID();
360 if (imageID
<= 0 || get_image_info(imageID
, &info
) != B_OK
) {
361 ERROR("BControllable::StartControlPanel Error accessing image\n");
366 if (get_ref_for_path(info
.name
, &ref
) != B_OK
) {
367 ERROR("BControllable::StartControlPanel Error getting ref\n");
371 // The first argument is "node=id" with id meaning the media_node_id
373 snprintf(arg
, sizeof(arg
), "node=%d", (int)ID());
376 if (be_roster
->Launch(&ref
, 1, (const char* const*)&arg
, &team
) != B_OK
) {
377 ERROR("BControllable::StartControlPanel Error launching application\n");
380 printf("BControllable::StartControlPanel done with id: %" B_PRId32
"\n",
384 *_messenger
= BMessenger(NULL
, team
);
391 BControllable::ApplyParameterData(const void* value
, size_t size
)
400 BControllable::MakeParameterData(const int32
* controls
, int32 count
,
401 void* buffer
, size_t* ioSize
)
409 // #pragma mark - private
412 status_t
BControllable::_Reserved_Controllable_0(void *) { return B_ERROR
; }
413 status_t
BControllable::_Reserved_Controllable_1(void *) { return B_ERROR
; }
414 status_t
BControllable::_Reserved_Controllable_2(void *) { return B_ERROR
; }
415 status_t
BControllable::_Reserved_Controllable_3(void *) { return B_ERROR
; }
416 status_t
BControllable::_Reserved_Controllable_4(void *) { return B_ERROR
; }
417 status_t
BControllable::_Reserved_Controllable_5(void *) { return B_ERROR
; }
418 status_t
BControllable::_Reserved_Controllable_6(void *) { return B_ERROR
; }
419 status_t
BControllable::_Reserved_Controllable_7(void *) { return B_ERROR
; }
420 status_t
BControllable::_Reserved_Controllable_8(void *) { return B_ERROR
; }
421 status_t
BControllable::_Reserved_Controllable_9(void *) { return B_ERROR
; }
422 status_t
BControllable::_Reserved_Controllable_10(void *) { return B_ERROR
; }
423 status_t
BControllable::_Reserved_Controllable_11(void *) { return B_ERROR
; }
424 status_t
BControllable::_Reserved_Controllable_12(void *) { return B_ERROR
; }
425 status_t
BControllable::_Reserved_Controllable_13(void *) { return B_ERROR
; }
426 status_t
BControllable::_Reserved_Controllable_14(void *) { return B_ERROR
; }
427 status_t
BControllable::_Reserved_Controllable_15(void *) { return B_ERROR
; }