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 /* to comply with the license above, do not remove the following line */ 31 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>"; 32 33 #include <Application.h> 34 #include <stdio.h> 35 #include <Messenger.h> 36 #include <MediaDefs.h> 37 #include <MediaFormats.h> 38 #include <Autolock.h> 39 #include <string.h> 40 #include "MMediaFilesManager.h" 41 #include "NotificationManager.h" 42 #include "ServerInterface.h" 43 #include "DataExchange.h" 44 #include "BufferManager.h" 45 #include "NodeManager.h" 46 #include "AppManager.h" 47 #include "MediaMisc.h" 48 #include "media_server.h" 49 #include "debug.h" 50 51 /* 52 * 53 * An implementation of a new media_server for the OpenBeOS MediaKit 54 * Started by Marcus Overhagen <marcus@overhagen.de> on 2001-10-25 55 * 56 */ 57 58 NotificationManager *gNotificationManager; 59 BufferManager *gBufferManager; 60 AppManager *gAppManager; 61 NodeManager *gNodeManager; 62 MMediaFilesManager *gMMediaFilesManager; 63 64 namespace BPrivate { namespace media { 65 extern team_id team; 66 } } // BPrivate::media 67 68 69 #define REPLY_TIMEOUT ((bigtime_t)500000) 70 71 class ServerApp : BApplication 72 { 73 public: 74 ServerApp(); 75 ~ServerApp(); 76 77 bool QuitRequested(); 78 void HandleMessage(int32 code, void *data, size_t size); 79 void ArgvReceived(int32 argc, char **argv); 80 static int32 controlthread(void *arg); 81 // void StartSystemTimeSource(); 82 83 /* functionality not yet implemented 84 00014a00 T _ServerApp::_ServerApp(void) 85 00014e1c T _ServerApp::~_ServerApp(void) 86 00014ff4 T _ServerApp::MessageReceived(BMessage *); 87 00015840 T _ServerApp::QuitRequested(void) 88 00015b50 T _ServerApp::_DoNotify(command_data *) 89 00015d18 T _ServerApp::_UnregisterApp(long, bool) 90 00018e90 T _ServerApp::AddOnHost(void) 91 00019530 T _ServerApp::AboutRequested(void) 92 00019d04 T _ServerApp::AddPurgableBufferGroup(long, long, long, void *) 93 00019db8 T _ServerApp::CancelPurgableBufferGroupCleanup(long) 94 00019e50 T _ServerApp::DirtyWork(void) 95 0001a4bc T _ServerApp::ArgvReceived(long, char **) 96 0001a508 T _ServerApp::CleanupPurgedBufferGroup(_ServerApp::purgable_buffer_group const &, bool) 97 0001a5dc T _ServerApp::DirtyWorkLaunch(void *) 98 0001a634 T _ServerApp::SetQuitMode(bool) 99 0001a648 T _ServerApp::IsQuitMode(void) const 100 0001a658 T _ServerApp::BroadcastCurrentStateTo(BMessenger &) 101 0001adcc T _ServerApp::ReadyToRun(void) 102 */ 103 104 private: 105 port_id control_port; 106 thread_id control_thread; 107 108 BLocker *fLocker; 109 110 void MessageReceived(BMessage *msg); 111 typedef BApplication inherited; 112 }; 113 114 ServerApp::ServerApp() 115 : BApplication(NEW_MEDIA_SERVER_SIGNATURE), 116 fLocker(new BLocker("media server locker")) 117 { 118 119 gNotificationManager = new NotificationManager; 120 gBufferManager = new BufferManager; 121 gAppManager = new AppManager; 122 gNodeManager = new NodeManager; 123 gMMediaFilesManager = new MMediaFilesManager; 124 125 control_port = create_port(64, MEDIA_SERVER_PORT_NAME); 126 control_thread = spawn_thread(controlthread, "media_server control", 105, this); 127 resume_thread(control_thread); 128 129 // StartSystemTimeSource(); 130 gNodeManager->LoadState(); 131 gAppManager->StartAddonServer(); 132 } 133 134 ServerApp::~ServerApp() 135 { 136 TRACE("ServerApp::~ServerApp()\n"); 137 delete gNotificationManager; 138 delete gBufferManager; 139 delete gAppManager; 140 delete gNodeManager; 141 delete gMMediaFilesManager; 142 delete fLocker; 143 delete_port(control_port); 144 status_t err; 145 wait_for_thread(control_thread,&err); 146 } 147 148 void ServerApp::ArgvReceived(int32 argc, char **argv) 149 { 150 for (int arg = 1; arg < argc; arg++) { 151 if (strstr(argv[arg], "dump")) { 152 gAppManager->Dump(); 153 gNodeManager->Dump(); 154 gBufferManager->Dump(); 155 gNotificationManager->Dump(); 156 gMMediaFilesManager->Dump(); 157 } 158 if (strstr(argv[arg], "buffer")) { 159 gBufferManager->Dump(); 160 } 161 if (strstr(argv[arg], "node")) { 162 gNodeManager->Dump(); 163 } 164 if (strstr(argv[arg], "quit")) { 165 PostMessage(B_QUIT_REQUESTED); 166 } 167 } 168 } 169 170 bool 171 ServerApp::QuitRequested() 172 { 173 TRACE("ServerApp::QuitRequested()\n"); 174 gNodeManager->SaveState(); 175 gAppManager->TerminateAddonServer(); 176 return true; 177 } 178 179 /* 180 void 181 ServerApp::StartSystemTimeSource() 182 { 183 TRACE("StartSystemTimeSource enter\n"); 184 status_t rv; 185 186 TRACE("StartSystemTimeSource creating object\n"); 187 188 // register a dummy node 189 media_node node; 190 rv = gNodeManager->RegisterNode(&node.node, -1, 0, "System Clock", B_TIME_SOURCE, SYSTEM_TIMESOURCE_CONTROL_PORT, BPrivate::media::team); 191 ASSERT(rv == B_OK); 192 193 ASSERT(node.node == NODE_SYSTEM_TIMESOURCE_ID); 194 195 TRACE("StartSystemTimeSource setting as default\n"); 196 197 rv = gNodeManager->SetDefaultNode(SYSTEM_TIME_SOURCE, &node, NULL, NULL); 198 ASSERT(rv == B_OK); 199 200 TRACE("StartSystemTimeSource leave\n"); 201 } 202 */ 203 204 void 205 ServerApp::HandleMessage(int32 code, void *data, size_t size) 206 { 207 status_t rv; 208 TRACE("ServerApp::HandleMessage %#lx enter\n", code); 209 switch (code) { 210 case SERVER_CHANGE_ADDON_FLAVOR_INSTANCES_COUNT: 211 { 212 const server_change_addon_flavor_instances_count_request *request = reinterpret_cast<const server_change_addon_flavor_instances_count_request *>(data); 213 server_change_addon_flavor_instances_count_reply reply; 214 ASSERT(request->delta == 1 || request->delta == -1); 215 if (request->delta == 1) 216 rv = gNodeManager->IncrementAddonFlavorInstancesCount(request->addonid, request->flavorid, request->team); 217 else 218 rv = gNodeManager->DecrementAddonFlavorInstancesCount(request->addonid, request->flavorid, request->team); 219 request->SendReply(rv, &reply, sizeof(reply)); 220 break; 221 } 222 223 case SERVER_RESCAN_DEFAULTS: 224 { 225 gNodeManager->RescanDefaultNodes(); 226 break; 227 } 228 229 case SERVER_REGISTER_ADDONSERVER: 230 { 231 const server_register_addonserver_request *request = reinterpret_cast<const server_register_addonserver_request *>(data); 232 server_register_addonserver_reply reply; 233 rv = gAppManager->RegisterAddonServer(request->team); 234 request->SendReply(rv, &reply, sizeof(reply)); 235 break; 236 } 237 238 case SERVER_REGISTER_APP: 239 { 240 const server_register_app_request *request = reinterpret_cast<const server_register_app_request *>(data); 241 server_register_app_reply reply; 242 rv = gAppManager->RegisterTeam(request->team, request->messenger); 243 request->SendReply(rv, &reply, sizeof(reply)); 244 break; 245 } 246 247 case SERVER_UNREGISTER_APP: 248 { 249 const server_unregister_app_request *request = reinterpret_cast<const server_unregister_app_request *>(data); 250 server_unregister_app_reply reply; 251 rv = gAppManager->UnregisterTeam(request->team); 252 request->SendReply(rv, &reply, sizeof(reply)); 253 break; 254 } 255 256 case SERVER_GET_MEDIAADDON_REF: 257 { 258 server_get_mediaaddon_ref_request *msg = (server_get_mediaaddon_ref_request *)data; 259 server_get_mediaaddon_ref_reply reply; 260 entry_ref tempref; 261 reply.result = gNodeManager->GetAddonRef(&tempref, msg->addonid); 262 reply.ref = tempref; 263 write_port(msg->reply_port, 0, &reply, sizeof(reply)); 264 break; 265 } 266 267 case SERVER_NODE_ID_FOR: 268 { 269 const server_node_id_for_request *request = reinterpret_cast<const server_node_id_for_request *>(data); 270 server_node_id_for_reply reply; 271 rv = gNodeManager->FindNodeId(&reply.nodeid, request->port); 272 request->SendReply(rv, &reply, sizeof(reply)); 273 break; 274 } 275 276 case SERVER_GET_LIVE_NODE_INFO: 277 { 278 const server_get_live_node_info_request *request = reinterpret_cast<const server_get_live_node_info_request *>(data); 279 server_get_live_node_info_reply reply; 280 rv = gNodeManager->GetLiveNodeInfo(&reply.live_info, request->node); 281 request->SendReply(rv, &reply, sizeof(reply)); 282 break; 283 } 284 285 case SERVER_GET_LIVE_NODES: 286 { 287 const server_get_live_nodes_request *request = reinterpret_cast<const server_get_live_nodes_request *>(data); 288 server_get_live_nodes_reply reply; 289 Stack<live_node_info> livenodes; 290 rv = gNodeManager->GetLiveNodes( 291 &livenodes, 292 request->maxcount, 293 request->has_input ? &request->inputformat : NULL, 294 request->has_output ? &request->outputformat : NULL, 295 request->has_name ? request->name : NULL, 296 request->require_kinds); 297 reply.count = livenodes.CountItems(); 298 if (reply.count <= MAX_LIVE_INFO) { 299 for (int32 index = 0; index < reply.count; index++) 300 livenodes.Pop(&reply.live_info[index]); 301 reply.area = -1; 302 } else { 303 // we create an area here, and pass it to the library, where it will be deleted. 304 live_node_info *start_addr; 305 size_t size; 306 size = ((reply.count * sizeof(live_node_info)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 307 reply.area = create_area("get live nodes", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 308 if (reply.area < B_OK) { 309 ERROR("SERVER_GET_LIVE_NODES: failed to create area, error %#lx\n", reply.area); 310 reply.count = 0; 311 rv = B_ERROR; 312 } else { 313 for (int32 index = 0; index < reply.count; index++) 314 livenodes.Pop(&start_addr[index]); 315 } 316 } 317 rv = request->SendReply(rv, &reply, sizeof(reply)); 318 if (rv != B_OK) 319 delete_area(reply.area); // if we couldn't send the message, delete the area 320 break; 321 } 322 323 case SERVER_GET_NODE_FOR: 324 { 325 const server_get_node_for_request *request = reinterpret_cast<const server_get_node_for_request *>(data); 326 server_get_node_for_reply reply; 327 rv = gNodeManager->GetCloneForId(&reply.clone, request->nodeid, request->team); 328 request->SendReply(rv, &reply, sizeof(reply)); 329 break; 330 } 331 332 case SERVER_RELEASE_NODE: 333 { 334 const server_release_node_request *request = reinterpret_cast<const server_release_node_request *>(data); 335 server_release_node_reply reply; 336 rv = gNodeManager->ReleaseNode(request->node, request->team); 337 request->SendReply(rv, &reply, sizeof(reply)); 338 break; 339 } 340 341 case SERVER_REGISTER_NODE: 342 { 343 const server_register_node_request *request = reinterpret_cast<const server_register_node_request *>(data); 344 server_register_node_reply reply; 345 rv = gNodeManager->RegisterNode(&reply.nodeid, request->addon_id, request->addon_flavor_id, request->name, request->kinds, request->port, request->team); 346 request->SendReply(rv, &reply, sizeof(reply)); 347 break; 348 } 349 350 case SERVER_UNREGISTER_NODE: 351 { 352 const server_unregister_node_request *request = reinterpret_cast<const server_unregister_node_request *>(data); 353 server_unregister_node_reply reply; 354 rv = gNodeManager->UnregisterNode(&reply.addonid, &reply.flavorid, request->nodeid, request->team); 355 request->SendReply(rv, &reply, sizeof(reply)); 356 break; 357 } 358 359 case SERVER_PUBLISH_INPUTS: 360 { 361 const server_publish_inputs_request *request = reinterpret_cast<const server_publish_inputs_request *>(data); 362 server_publish_inputs_reply reply; 363 if (request->count <= MAX_INPUTS) { 364 rv = gNodeManager->PublishInputs(request->node, request->inputs, request->count); 365 } else { 366 media_input *inputs; 367 area_id clone; 368 clone = clone_area("media_inputs clone", reinterpret_cast<void **>(&inputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area); 369 if (clone < B_OK) { 370 ERROR("SERVER_PUBLISH_INPUTS: failed to clone area, error %#lx\n", clone); 371 rv = B_ERROR; 372 } else { 373 rv = gNodeManager->PublishInputs(request->node, inputs, request->count); 374 delete_area(clone); 375 } 376 } 377 request->SendReply(rv, &reply, sizeof(reply)); 378 break; 379 } 380 381 case SERVER_PUBLISH_OUTPUTS: 382 { 383 const server_publish_outputs_request *request = reinterpret_cast<const server_publish_outputs_request *>(data); 384 server_publish_outputs_reply reply; 385 if (request->count <= MAX_OUTPUTS) { 386 rv = gNodeManager->PublishOutputs(request->node, request->outputs, request->count); 387 } else { 388 media_output *outputs; 389 area_id clone; 390 clone = clone_area("media_outputs clone", reinterpret_cast<void **>(&outputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area); 391 if (clone < B_OK) { 392 ERROR("SERVER_PUBLISH_OUTPUTS: failed to clone area, error %#lx\n", clone); 393 rv = B_ERROR; 394 } else { 395 rv = gNodeManager->PublishOutputs(request->node, outputs, request->count); 396 delete_area(clone); 397 } 398 } 399 request->SendReply(rv, &reply, sizeof(reply)); 400 break; 401 } 402 403 case SERVER_GET_NODE: 404 { 405 const server_get_node_request *request = reinterpret_cast<const server_get_node_request *>(data); 406 server_get_node_reply reply; 407 rv = gNodeManager->GetClone(&reply.node, reply.input_name, &reply.input_id, request->type, request->team); 408 request->SendReply(rv, &reply, sizeof(reply)); 409 break; 410 } 411 412 case SERVER_SET_NODE: 413 { 414 const server_set_node_request *request = reinterpret_cast<const server_set_node_request *>(data); 415 server_set_node_reply reply; 416 rv = gNodeManager->SetDefaultNode(request->type, request->use_node ? &request->node : NULL, request->use_dni ? &request->dni : NULL, request->use_input ? &request->input : NULL); 417 request->SendReply(rv, &reply, sizeof(reply)); 418 break; 419 } 420 421 case SERVER_GET_DORMANT_NODE_FOR: 422 { 423 const server_get_dormant_node_for_request *request = reinterpret_cast<const server_get_dormant_node_for_request *>(data); 424 server_get_dormant_node_for_reply reply; 425 rv = gNodeManager->GetDormantNodeInfo(&reply.node_info, request->node); 426 request->SendReply(rv, &reply, sizeof(reply)); 427 break; 428 } 429 430 case SERVER_GET_INSTANCES_FOR: 431 { 432 const server_get_instances_for_request *request = reinterpret_cast<const server_get_instances_for_request *>(data); 433 server_get_instances_for_reply reply; 434 rv = gNodeManager->GetInstances(reply.node_id, &reply.count, min_c(request->maxcount, MAX_NODE_ID), request->addon_id, request->addon_flavor_id); 435 if (reply.count == MAX_NODE_ID && request->maxcount > MAX_NODE_ID) { // XXX might be fixed by using an area 436 PRINT(1, "Warning: SERVER_GET_INSTANCES_FOR: returning possibly truncated list of node id's\n"); 437 } 438 request->SendReply(rv, &reply, sizeof(reply)); 439 break; 440 } 441 442 case SERVER_REGISTER_MEDIAADDON: 443 { 444 server_register_mediaaddon_request *msg = (server_register_mediaaddon_request *)data; 445 server_register_mediaaddon_reply reply; 446 gNodeManager->RegisterAddon(msg->ref, &reply.addonid); 447 write_port(msg->reply_port, 0, &reply, sizeof(reply)); 448 break; 449 } 450 451 case SERVER_UNREGISTER_MEDIAADDON: 452 { 453 server_unregister_mediaaddon_command *msg = (server_unregister_mediaaddon_command *)data; 454 gNodeManager->UnregisterAddon(msg->addonid); 455 break; 456 } 457 458 case SERVER_REGISTER_DORMANT_NODE: 459 { 460 xfer_server_register_dormant_node *msg = (xfer_server_register_dormant_node *)data; 461 dormant_flavor_info dfi; 462 if (msg->purge_id > 0) 463 gNodeManager->InvalidateDormantFlavorInfo(msg->purge_id); 464 rv = dfi.Unflatten(msg->dfi_type, &(msg->dfi), msg->dfi_size); 465 ASSERT(rv == B_OK); 466 gNodeManager->AddDormantFlavorInfo(dfi); 467 break; 468 } 469 470 case SERVER_GET_DORMANT_NODES: 471 { 472 xfer_server_get_dormant_nodes *msg = (xfer_server_get_dormant_nodes *)data; 473 xfer_server_get_dormant_nodes_reply reply; 474 dormant_node_info * infos = new dormant_node_info[msg->maxcount]; 475 reply.count = msg->maxcount; 476 reply.result = gNodeManager->GetDormantNodes( 477 infos, 478 &reply.count, 479 msg->has_input ? &msg->inputformat : NULL, 480 msg->has_output ? &msg->outputformat : NULL, 481 msg->has_name ? msg->name : NULL, 482 msg->require_kinds, 483 msg->deny_kinds); 484 if (reply.result != B_OK) 485 reply.count = 0; 486 write_port(msg->reply_port, 0, &reply, sizeof(reply)); 487 if (reply.count > 0) 488 write_port(msg->reply_port, 0, infos, reply.count * sizeof(dormant_node_info)); 489 delete [] infos; 490 break; 491 } 492 493 case SERVER_GET_DORMANT_FLAVOR_INFO: 494 { 495 xfer_server_get_dormant_flavor_info *msg = (xfer_server_get_dormant_flavor_info *)data; 496 dormant_flavor_info dfi; 497 status_t rv; 498 499 rv = gNodeManager->GetDormantFlavorInfoFor(msg->addon, msg->flavor_id, &dfi); 500 if (rv != B_OK) { 501 xfer_server_get_dormant_flavor_info_reply reply; 502 reply.result = rv; 503 write_port(msg->reply_port, 0, &reply, sizeof(reply)); 504 } else { 505 xfer_server_get_dormant_flavor_info_reply *reply; 506 int replysize; 507 replysize = sizeof(xfer_server_get_dormant_flavor_info_reply) + dfi.FlattenedSize(); 508 reply = (xfer_server_get_dormant_flavor_info_reply *)malloc(replysize); 509 510 reply->dfi_size = dfi.FlattenedSize(); 511 reply->dfi_type = dfi.TypeCode(); 512 reply->result = dfi.Flatten(reply->dfi, reply->dfi_size); 513 write_port(msg->reply_port, 0, reply, replysize); 514 free(reply); 515 } 516 break; 517 } 518 519 case SERVER_SET_NODE_CREATOR: 520 { 521 const server_set_node_creator_request *request = reinterpret_cast<const server_set_node_creator_request *>(data); 522 server_set_node_creator_reply reply; 523 rv = gNodeManager->SetNodeCreator(request->node, request->creator); 524 request->SendReply(rv, &reply, sizeof(reply)); 525 break; 526 } 527 528 case SERVER_GET_SHARED_BUFFER_AREA: 529 { 530 const server_get_shared_buffer_area_request *request = reinterpret_cast<const server_get_shared_buffer_area_request *>(data); 531 server_get_shared_buffer_area_reply reply; 532 533 reply.area = gBufferManager->SharedBufferListID(); 534 request->SendReply(B_OK, &reply, sizeof(reply)); 535 break; 536 } 537 538 case SERVER_REGISTER_BUFFER: 539 { 540 const server_register_buffer_request *request = reinterpret_cast<const server_register_buffer_request *>(data); 541 server_register_buffer_reply reply; 542 status_t status; 543 if (request->info.buffer == 0) { 544 reply.info = request->info; //size, offset, flags, area is kept 545 // get a new beuffer id into reply.info.buffer 546 status = gBufferManager->RegisterBuffer(request->team, request->info.size, request->info.flags, request->info.offset, request->info.area, &reply.info.buffer); 547 } else { 548 reply.info = request->info; //buffer id is kept 549 status = gBufferManager->RegisterBuffer(request->team, request->info.buffer, &reply.info.size, &reply.info.flags, &reply.info.offset, &reply.info.area); 550 } 551 request->SendReply(status, &reply, sizeof(reply)); 552 break; 553 } 554 555 case SERVER_UNREGISTER_BUFFER: 556 { 557 const server_unregister_buffer_command *cmd = reinterpret_cast<const server_unregister_buffer_command *>(data); 558 559 gBufferManager->UnregisterBuffer(cmd->team, cmd->bufferid); 560 break; 561 } 562 563 case SERVER_REWINDTYPES: 564 { 565 const server_rewindtypes_request *request = reinterpret_cast<const server_rewindtypes_request *>(data); 566 server_rewindtypes_reply reply; 567 568 BString **types = NULL; 569 570 rv = gMMediaFilesManager->RewindTypes( 571 &types, &reply.count); 572 if(reply.count>0) { 573 // we create an area here, and pass it to the library, where it will be deleted. 574 char *start_addr; 575 size_t size = ((reply.count * B_MEDIA_NAME_LENGTH) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 576 reply.area = create_area("rewind types", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 577 if (reply.area < B_OK) { 578 ERROR("SERVER_REWINDTYPES: failed to create area, error %s\n", strerror(reply.area)); 579 reply.count = 0; 580 rv = B_ERROR; 581 } else { 582 for (int32 index = 0; index < reply.count; index++) 583 strncpy(start_addr + B_MEDIA_NAME_LENGTH * index, types[index]->String(), B_MEDIA_NAME_LENGTH); 584 } 585 } 586 587 delete types; 588 589 rv = request->SendReply(rv, &reply, sizeof(reply)); 590 if (rv != B_OK) 591 delete_area(reply.area); // if we couldn't send the message, delete the area 592 break; 593 } 594 595 case SERVER_REWINDREFS: 596 { 597 const server_rewindrefs_request *request = reinterpret_cast<const server_rewindrefs_request *>(data); 598 server_rewindrefs_reply reply; 599 600 BString **items = NULL; 601 602 rv = gMMediaFilesManager->RewindRefs(request->type, 603 &items, &reply.count); 604 // we create an area here, and pass it to the library, where it will be deleted. 605 if(reply.count>0) { 606 char *start_addr; 607 size_t size = ((reply.count * B_MEDIA_NAME_LENGTH) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 608 reply.area = create_area("rewind refs", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 609 if (reply.area < B_OK) { 610 ERROR("SERVER_REWINDREFS: failed to create area, error %s\n", strerror(reply.area)); 611 reply.count = 0; 612 rv = B_ERROR; 613 } else { 614 for (int32 index = 0; index < reply.count; index++) 615 strncpy(start_addr + B_MEDIA_NAME_LENGTH * index, items[index]->String(), B_MEDIA_NAME_LENGTH); 616 } 617 } 618 619 delete items; 620 621 rv = request->SendReply(rv, &reply, sizeof(reply)); 622 if (rv != B_OK) 623 delete_area(reply.area); // if we couldn't send the message, delete the area 624 break; 625 } 626 627 case SERVER_GETREFFOR: 628 { 629 const server_getreffor_request *request = reinterpret_cast<const server_getreffor_request *>(data); 630 server_getreffor_reply reply; 631 entry_ref *ref; 632 633 rv = gMMediaFilesManager->GetRefFor(request->type, request->item, &ref); 634 if(rv==B_OK) { 635 reply.ref = *ref; 636 } 637 request->SendReply(rv, &reply, sizeof(reply)); 638 break; 639 } 640 641 case SERVER_SETREFFOR: 642 { 643 const server_setreffor_request *request = reinterpret_cast<const server_setreffor_request *>(data); 644 server_setreffor_reply reply; 645 entry_ref ref = request->ref; 646 647 rv = gMMediaFilesManager->SetRefFor(request->type, request->item, ref); 648 request->SendReply(rv, &reply, sizeof(reply)); 649 break; 650 } 651 652 case SERVER_REMOVEREFFOR: 653 { 654 const server_removereffor_request *request = reinterpret_cast<const server_removereffor_request *>(data); 655 server_removereffor_reply reply; 656 entry_ref ref = request->ref; 657 658 rv = gMMediaFilesManager->RemoveRefFor(request->type, request->item, ref); 659 request->SendReply(rv, &reply, sizeof(reply)); 660 break; 661 } 662 663 case SERVER_REMOVEITEM: 664 { 665 const server_removeitem_request *request = reinterpret_cast<const server_removeitem_request *>(data); 666 server_removeitem_reply reply; 667 668 rv = gMMediaFilesManager->RemoveItem(request->type, request->item); 669 request->SendReply(rv, &reply, sizeof(reply)); 670 break; 671 } 672 673 default: 674 printf("media_server: received unknown message code %#08lx\n",code); 675 } 676 TRACE("ServerApp::HandleMessage %#lx leave\n", code); 677 } 678 679 int32 680 ServerApp::controlthread(void *arg) 681 { 682 char data[B_MEDIA_MESSAGE_SIZE]; 683 ServerApp *app; 684 ssize_t size; 685 int32 code; 686 687 app = (ServerApp *)arg; 688 while ((size = read_port_etc(app->control_port, &code, data, sizeof(data), 0, 0)) > 0) 689 app->HandleMessage(code, data, size); 690 691 return 0; 692 } 693 694 void ServerApp::MessageReceived(BMessage *msg) 695 { 696 TRACE("ServerApp::MessageReceived %lx enter\n", msg->what); 697 switch (msg->what) { 698 case MEDIA_SERVER_REQUEST_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break; 699 case MEDIA_SERVER_CANCEL_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break; 700 case MEDIA_SERVER_SEND_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break; 701 case MMEDIAFILESMANAGER_SAVE_TIMER: gMMediaFilesManager->TimerMessage(); break; 702 default: 703 printf("\nnew media server: unknown message received\n"); 704 msg->PrintToStream(); 705 } 706 TRACE("ServerApp::MessageReceived %lx leave\n", msg->what); 707 } 708 709 int main() 710 { 711 new ServerApp; 712 be_app->Run(); 713 delete be_app; 714 return 0; 715 } 716