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