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 31 /* to comply with the license above, do not remove the following line */ 32 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002, 2003 " 33 "Marcus Overhagen <Marcus@Overhagen.de>"; 34 35 36 #include <stdio.h> 37 #include <string.h> 38 39 #include <Alert.h> 40 #include <Autolock.h> 41 #include <Directory.h> 42 #include <Roster.h> 43 #include <MediaDefs.h> 44 #include <MediaFormats.h> 45 #include <Messenger.h> 46 #include <Server.h> 47 48 #include <syscalls.h> 49 50 #include "AppManager.h" 51 #include "BufferManager.h" 52 #include "DataExchange.h" 53 #include "MediaDebug.h" 54 #include "MediaFilesManager.h" 55 #include "MediaMisc.h" 56 #include "NodeManager.h" 57 #include "NotificationManager.h" 58 #include "ServerInterface.h" 59 #include "media_server.h" 60 61 62 AppManager* gAppManager; 63 BufferManager* gBufferManager; 64 MediaFilesManager* gMediaFilesManager; 65 NodeManager* gNodeManager; 66 NotificationManager* gNotificationManager; 67 68 69 #define REPLY_TIMEOUT ((bigtime_t)500000) 70 71 72 class ServerApp : public BServer { 73 public: 74 ServerApp(status_t& error); 75 virtual ~ServerApp(); 76 77 protected: 78 virtual void ArgvReceived(int32 argc, char** argv); 79 virtual void ReadyToRun(); 80 virtual bool QuitRequested(); 81 virtual void MessageReceived(BMessage* message); 82 83 private: 84 void _HandleMessage(int32 code, const void* data, 85 size_t size); 86 void _LaunchAddOnServer(); 87 void _QuitAddOnServer(); 88 89 private: 90 port_id _ControlPort() const { return fControlPort; } 91 92 static int32 _ControlThread(void* arg); 93 94 BLocker fLocker; 95 port_id fControlPort; 96 thread_id fControlThread; 97 }; 98 99 100 ServerApp::ServerApp(status_t& error) 101 : 102 BServer(B_MEDIA_SERVER_SIGNATURE, true, &error), 103 fLocker("media server locker") 104 { 105 gNotificationManager = new NotificationManager; 106 gBufferManager = new BufferManager; 107 gAppManager = new AppManager; 108 gNodeManager = new NodeManager; 109 gMediaFilesManager = new MediaFilesManager; 110 111 fControlPort = create_port(64, MEDIA_SERVER_PORT_NAME); 112 fControlThread = spawn_thread(_ControlThread, "media_server control", 105, 113 this); 114 resume_thread(fControlThread); 115 116 if (be_roster->StartWatching(BMessenger(this, this), 117 B_REQUEST_QUIT) != B_OK) { 118 TRACE("ServerApp: Can't find the registrar."); 119 } 120 } 121 122 123 ServerApp::~ServerApp() 124 { 125 TRACE("ServerApp::~ServerApp()\n"); 126 127 delete_port(fControlPort); 128 wait_for_thread(fControlThread, NULL); 129 130 if (be_roster->StopWatching(BMessenger(this, this)) != B_OK) 131 TRACE("ServerApp: Can't unregister roster notifications."); 132 133 delete gNotificationManager; 134 delete gBufferManager; 135 delete gAppManager; 136 delete gNodeManager; 137 delete gMediaFilesManager; 138 } 139 140 141 void 142 ServerApp::ReadyToRun() 143 { 144 gNodeManager->LoadState(); 145 146 // make sure any previous media_addon_server is gone 147 _QuitAddOnServer(); 148 // and start a new one 149 _LaunchAddOnServer(); 150 151 } 152 153 154 bool 155 ServerApp::QuitRequested() 156 { 157 TRACE("ServerApp::QuitRequested()\n"); 158 gMediaFilesManager->SaveState(); 159 gNodeManager->SaveState(); 160 161 _QuitAddOnServer(); 162 163 return true; 164 } 165 166 167 void 168 ServerApp::ArgvReceived(int32 argc, char **argv) 169 { 170 for (int arg = 1; arg < argc; arg++) { 171 if (strstr(argv[arg], "dump") != NULL) { 172 gAppManager->Dump(); 173 gNodeManager->Dump(); 174 gBufferManager->Dump(); 175 gNotificationManager->Dump(); 176 gMediaFilesManager->Dump(); 177 } 178 if (strstr(argv[arg], "buffer") != NULL) 179 gBufferManager->Dump(); 180 if (strstr(argv[arg], "node") != NULL) 181 gNodeManager->Dump(); 182 if (strstr(argv[arg], "files") != NULL) 183 gMediaFilesManager->Dump(); 184 if (strstr(argv[arg], "quit") != NULL) 185 PostMessage(B_QUIT_REQUESTED); 186 } 187 } 188 189 190 void 191 ServerApp::_LaunchAddOnServer() 192 { 193 // Try to launch media_addon_server by mime signature. 194 // If it fails (for example on the Live CD, where the executable 195 // hasn't yet been mimesetted), try from this application's 196 // directory 197 status_t err = be_roster->Launch(B_MEDIA_ADDON_SERVER_SIGNATURE); 198 if (err == B_OK) 199 return; 200 201 app_info info; 202 BEntry entry; 203 BDirectory dir; 204 entry_ref ref; 205 206 err = GetAppInfo(&info); 207 err |= entry.SetTo(&info.ref); 208 err |= entry.GetParent(&entry); 209 err |= dir.SetTo(&entry); 210 err |= entry.SetTo(&dir, "media_addon_server"); 211 err |= entry.GetRef(&ref); 212 213 if (err == B_OK) 214 be_roster->Launch(&ref); 215 if (err == B_OK) 216 return; 217 218 BAlert* alert = new BAlert("media_server", "Launching media_addon_server " 219 "failed.\n\nmedia_server will terminate", "OK"); 220 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 221 alert->Go(); 222 fprintf(stderr, "Launching media_addon_server (%s) failed: %s\n", 223 B_MEDIA_ADDON_SERVER_SIGNATURE, strerror(err)); 224 exit(1); 225 } 226 227 228 void 229 ServerApp::_QuitAddOnServer() 230 { 231 // nothing to do if it's already terminated 232 if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) 233 return; 234 235 // send a quit request to the media_addon_server 236 BMessenger msger(B_MEDIA_ADDON_SERVER_SIGNATURE); 237 if (!msger.IsValid()) { 238 ERROR("Trouble terminating media_addon_server. Messenger invalid\n"); 239 } else { 240 BMessage msg(B_QUIT_REQUESTED); 241 status_t err = msger.SendMessage(&msg, (BHandler *)NULL, 2000000); 242 // 2 sec timeout 243 if (err != B_OK) { 244 ERROR("Trouble terminating media_addon_server (2): %s\n", 245 strerror(err)); 246 } 247 } 248 249 // wait 5 seconds for it to terminate 250 for (int i = 0; i < 50; i++) { 251 if (!be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) 252 return; 253 snooze(100000); // 100 ms 254 } 255 256 // try to kill it (or many of them), up to 10 seconds 257 for (int i = 0; i < 50; i++) { 258 team_id id = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE); 259 if (id < 0) 260 break; 261 kill_team(id); 262 snooze(200000); // 200 ms 263 } 264 265 if (be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) { 266 ERROR("Trouble terminating media_addon_server, it's still running\n"); 267 } 268 } 269 270 271 void 272 ServerApp::_HandleMessage(int32 code, const void* data, size_t size) 273 { 274 TRACE("ServerApp::HandleMessage %#" B_PRIx32 " enter\n", code); 275 switch (code) { 276 case SERVER_CHANGE_FLAVOR_INSTANCES_COUNT: 277 { 278 const server_change_flavor_instances_count_request& request 279 = *static_cast< 280 const server_change_flavor_instances_count_request*>(data); 281 server_change_flavor_instances_count_reply reply; 282 status_t status = B_BAD_VALUE; 283 284 if (request.delta == 1) { 285 status = gNodeManager->IncrementFlavorInstancesCount( 286 request.add_on_id, request.flavor_id, request.team); 287 } else if (request.delta == -1) { 288 status = gNodeManager->DecrementFlavorInstancesCount( 289 request.add_on_id, request.flavor_id, request.team); 290 } 291 request.SendReply(status, &reply, sizeof(reply)); 292 break; 293 } 294 295 case SERVER_RESCAN_DEFAULTS: 296 { 297 gNodeManager->RescanDefaultNodes(); 298 break; 299 } 300 301 case SERVER_REGISTER_APP: 302 { 303 const server_register_app_request& request = *static_cast< 304 const server_register_app_request*>(data); 305 server_register_app_reply reply; 306 307 status_t status = gAppManager->RegisterTeam(request.team, 308 request.messenger); 309 request.SendReply(status, &reply, sizeof(reply)); 310 break; 311 } 312 313 case SERVER_UNREGISTER_APP: 314 { 315 const server_unregister_app_request& request = *static_cast< 316 const server_unregister_app_request*>(data); 317 server_unregister_app_reply reply; 318 319 status_t status = gAppManager->UnregisterTeam(request.team); 320 request.SendReply(status, &reply, sizeof(reply)); 321 break; 322 } 323 324 case SERVER_GET_ADD_ON_REF: 325 { 326 const server_get_add_on_ref_request& request = *static_cast< 327 const server_get_add_on_ref_request*>(data); 328 server_get_add_on_ref_reply reply; 329 330 entry_ref ref; 331 reply.result = gNodeManager->GetAddOnRef(request.add_on_id, &ref); 332 reply.ref = ref; 333 334 request.SendReply(reply.result, &reply, sizeof(reply)); 335 break; 336 } 337 338 case SERVER_NODE_ID_FOR: 339 { 340 const server_node_id_for_request& request 341 = *static_cast<const server_node_id_for_request*>(data); 342 server_node_id_for_reply reply; 343 344 status_t status = gNodeManager->FindNodeID(request.port, 345 &reply.node_id); 346 request.SendReply(status, &reply, sizeof(reply)); 347 break; 348 } 349 350 case SERVER_GET_LIVE_NODE_INFO: 351 { 352 const server_get_live_node_info_request& request = *static_cast< 353 const server_get_live_node_info_request*>(data); 354 server_get_live_node_info_reply reply; 355 356 status_t status = gNodeManager->GetLiveNodeInfo(request.node, 357 &reply.live_info); 358 request.SendReply(status, &reply, sizeof(reply)); 359 break; 360 } 361 362 case SERVER_GET_LIVE_NODES: 363 { 364 const server_get_live_nodes_request& request 365 = *static_cast<const server_get_live_nodes_request*>(data); 366 server_get_live_nodes_reply reply; 367 LiveNodeList nodes; 368 369 status_t status = gNodeManager->GetLiveNodes(nodes, 370 request.max_count, 371 request.has_input ? &request.input_format : NULL, 372 request.has_output ? &request.output_format : NULL, 373 request.has_name ? request.name : NULL, request.require_kinds); 374 375 reply.count = nodes.size(); 376 reply.area = -1; 377 378 live_node_info* infos = reply.live_info; 379 area_id area = -1; 380 381 if (reply.count > MAX_LIVE_INFO) { 382 // We create an area here, and transfer it to the client 383 size_t size = (reply.count * sizeof(live_node_info) 384 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 385 386 area = create_area("get live nodes", (void**)&infos, 387 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 388 if (area < 0) { 389 reply.area = area; 390 reply.count = 0; 391 } 392 } 393 394 for (int32 index = 0; index < reply.count; index++) 395 infos[index] = nodes[index]; 396 397 if (area >= 0) { 398 // transfer the area to the target team 399 reply.area = _kern_transfer_area(area, &reply.address, 400 B_ANY_ADDRESS, request.team); 401 if (reply.area < 0) { 402 delete_area(area); 403 reply.count = 0; 404 } 405 } 406 407 status = request.SendReply(status, &reply, sizeof(reply)); 408 if (status != B_OK && reply.area >= 0) { 409 // if we couldn't send the message, delete the area 410 delete_area(reply.area); 411 } 412 break; 413 } 414 415 case SERVER_GET_NODE_FOR: 416 { 417 const server_get_node_for_request& request 418 = *static_cast<const server_get_node_for_request*>(data); 419 server_get_node_for_reply reply; 420 421 status_t status = gNodeManager->GetCloneForID(request.node_id, 422 request.team, &reply.clone); 423 request.SendReply(status, &reply, sizeof(reply)); 424 break; 425 } 426 427 case SERVER_RELEASE_NODE: 428 { 429 const server_release_node_request& request 430 = *static_cast<const server_release_node_request*>(data); 431 server_release_node_reply reply; 432 433 status_t status = gNodeManager->ReleaseNode(request.node, 434 request.team); 435 request.SendReply(status, &reply, sizeof(reply)); 436 break; 437 } 438 439 case SERVER_RELEASE_NODE_ALL: 440 { 441 const server_release_node_request& request 442 = *static_cast<const server_release_node_request*>(data); 443 server_release_node_reply reply; 444 445 status_t status = gNodeManager->ReleaseNodeAll(request.node.node); 446 request.SendReply(status, &reply, sizeof(reply)); 447 break; 448 } 449 450 case SERVER_REGISTER_NODE: 451 { 452 const server_register_node_request& request 453 = *static_cast<const server_register_node_request*>(data); 454 server_register_node_reply reply; 455 456 status_t status = gNodeManager->RegisterNode(request.add_on_id, 457 request.flavor_id, request.name, request.kinds, request.port, 458 request.team, request.timesource_id, &reply.node_id); 459 request.SendReply(status, &reply, sizeof(reply)); 460 break; 461 } 462 463 case SERVER_UNREGISTER_NODE: 464 { 465 const server_unregister_node_request& request 466 = *static_cast<const server_unregister_node_request*>(data); 467 server_unregister_node_reply reply; 468 469 status_t status = gNodeManager->UnregisterNode(request.node_id, 470 request.team, &reply.add_on_id, &reply.flavor_id); 471 request.SendReply(status, &reply, sizeof(reply)); 472 break; 473 } 474 475 case SERVER_PUBLISH_INPUTS: 476 { 477 const server_publish_inputs_request& request 478 = *static_cast<const server_publish_inputs_request*>(data); 479 server_publish_inputs_reply reply; 480 status_t status; 481 482 if (request.count <= MAX_INPUTS) { 483 status = gNodeManager->PublishInputs(request.node, 484 request.inputs, request.count); 485 } else { 486 media_input* inputs; 487 area_id clone; 488 clone = clone_area("media_inputs clone", (void**)&inputs, 489 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request.area); 490 if (clone < B_OK) { 491 ERROR("SERVER_PUBLISH_INPUTS: failed to clone area, " 492 "error %#" B_PRIx32 "\n", clone); 493 status = clone; 494 } else { 495 status = gNodeManager->PublishInputs(request.node, inputs, 496 request.count); 497 delete_area(clone); 498 } 499 } 500 request.SendReply(status, &reply, sizeof(reply)); 501 break; 502 } 503 504 case SERVER_PUBLISH_OUTPUTS: 505 { 506 const server_publish_outputs_request& request 507 = *static_cast<const server_publish_outputs_request*>(data); 508 server_publish_outputs_reply reply; 509 status_t status; 510 511 if (request.count <= MAX_OUTPUTS) { 512 status = gNodeManager->PublishOutputs(request.node, 513 request.outputs, request.count); 514 } else { 515 media_output* outputs; 516 area_id clone; 517 clone = clone_area("media_outputs clone", (void**)&outputs, 518 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request.area); 519 if (clone < B_OK) { 520 ERROR("SERVER_PUBLISH_OUTPUTS: failed to clone area, " 521 "error %#" B_PRIx32 "\n", clone); 522 status = clone; 523 } else { 524 status = gNodeManager->PublishOutputs(request.node, outputs, 525 request.count); 526 delete_area(clone); 527 } 528 } 529 request.SendReply(status, &reply, sizeof(reply)); 530 break; 531 } 532 533 case SERVER_GET_NODE: 534 { 535 const server_get_node_request& request 536 = *static_cast<const server_get_node_request*>(data); 537 server_get_node_reply reply; 538 539 status_t status = gNodeManager->GetClone(request.type, request.team, 540 &reply.node, reply.input_name, &reply.input_id); 541 request.SendReply(status, &reply, sizeof(reply)); 542 break; 543 } 544 545 case SERVER_SET_NODE: 546 { 547 const server_set_node_request& request 548 = *static_cast<const server_set_node_request*>(data); 549 server_set_node_reply reply; 550 551 status_t status = gNodeManager->SetDefaultNode(request.type, 552 request.use_node ? &request.node : NULL, 553 request.use_dni ? &request.dni : NULL, 554 request.use_input ? &request.input : NULL); 555 request.SendReply(status, &reply, sizeof(reply)); 556 break; 557 } 558 559 case SERVER_GET_DORMANT_NODE_FOR: 560 { 561 const server_get_dormant_node_for_request& request 562 = *static_cast<const server_get_dormant_node_for_request*>( 563 data); 564 server_get_dormant_node_for_reply reply; 565 566 status_t status = gNodeManager->GetDormantNodeInfo(request.node, 567 &reply.node_info); 568 request.SendReply(status, &reply, sizeof(reply)); 569 break; 570 } 571 572 case SERVER_GET_INSTANCES_FOR: 573 { 574 const server_get_instances_for_request& request 575 = *static_cast<const server_get_instances_for_request*>(data); 576 server_get_instances_for_reply reply; 577 578 status_t status = gNodeManager->GetInstances(request.add_on_id, 579 request.flavor_id, reply.node_id, &reply.count, 580 min_c(request.max_count, MAX_NODE_ID)); 581 if (reply.count == MAX_NODE_ID 582 && request.max_count > MAX_NODE_ID) { 583 // TODO: might be fixed by using an area 584 PRINT(1, "Warning: SERVER_GET_INSTANCES_FOR: returning " 585 "possibly truncated list of node id's\n"); 586 } 587 request.SendReply(status, &reply, sizeof(reply)); 588 break; 589 } 590 591 case SERVER_SET_NODE_TIMESOURCE: 592 { 593 const server_set_node_timesource_request& request 594 = *static_cast<const server_set_node_timesource_request*>(data); 595 server_set_node_timesource_reply reply; 596 status_t result = gNodeManager->SetNodeTimeSource(request.node_id, 597 request.timesource_id); 598 request.SendReply(result, &reply, sizeof(reply)); 599 break; 600 } 601 602 case SERVER_REGISTER_ADD_ON: 603 { 604 const server_register_add_on_request& request = *static_cast< 605 const server_register_add_on_request*>(data); 606 server_register_add_on_reply reply; 607 608 gNodeManager->RegisterAddOn(request.ref, &reply.add_on_id); 609 request.SendReply(B_OK, &reply, sizeof(reply)); 610 break; 611 } 612 613 case SERVER_UNREGISTER_ADD_ON: 614 { 615 const server_unregister_add_on_command& request = *static_cast< 616 const server_unregister_add_on_command*>(data); 617 gNodeManager->UnregisterAddOn(request.add_on_id); 618 break; 619 } 620 621 case SERVER_REGISTER_DORMANT_NODE: 622 { 623 const server_register_dormant_node_command& command 624 = *static_cast<const server_register_dormant_node_command*>( 625 data); 626 if (command.purge_id > 0) 627 gNodeManager->InvalidateDormantFlavorInfo(command.purge_id); 628 629 dormant_flavor_info dormantFlavorInfo; 630 status_t status = dormantFlavorInfo.Unflatten(command.type, 631 command.flattened_data, command.flattened_size); 632 if (status == B_OK) 633 gNodeManager->AddDormantFlavorInfo(dormantFlavorInfo); 634 break; 635 } 636 637 case SERVER_GET_DORMANT_NODES: 638 { 639 const server_get_dormant_nodes_request& request 640 = *static_cast<const server_get_dormant_nodes_request*>(data); 641 642 server_get_dormant_nodes_reply reply; 643 reply.count = request.max_count; 644 645 dormant_node_info* infos 646 = new(std::nothrow) dormant_node_info[reply.count]; 647 if (infos != NULL) { 648 reply.result = gNodeManager->GetDormantNodes(infos, 649 &reply.count, 650 request.has_input ? &request.input_format : NULL, 651 request.has_output ? &request.output_format : NULL, 652 request.has_name ? request.name : NULL, 653 request.require_kinds, request.deny_kinds); 654 } else 655 reply.result = B_NO_MEMORY; 656 657 if (reply.result != B_OK) 658 reply.count = 0; 659 660 request.SendReply(reply.result, &reply, sizeof(reply)); 661 if (reply.count > 0) { 662 write_port(request.reply_port, 0, infos, 663 reply.count * sizeof(dormant_node_info)); 664 } 665 delete[] infos; 666 break; 667 } 668 669 case SERVER_GET_DORMANT_FLAVOR_INFO: 670 { 671 const server_get_dormant_flavor_info_request& request 672 = *static_cast<const server_get_dormant_flavor_info_request*>( 673 data); 674 dormant_flavor_info dormantFlavorInfo; 675 676 status_t status = gNodeManager->GetDormantFlavorInfoFor( 677 request.add_on_id, request.flavor_id, &dormantFlavorInfo); 678 if (status != B_OK) { 679 server_get_dormant_flavor_info_reply reply; 680 reply.result = status; 681 request.SendReply(reply.result, &reply, sizeof(reply)); 682 } else { 683 size_t replySize 684 = sizeof(server_get_dormant_flavor_info_reply) 685 + dormantFlavorInfo.FlattenedSize(); 686 server_get_dormant_flavor_info_reply* reply 687 = (server_get_dormant_flavor_info_reply*)malloc( 688 replySize); 689 if (reply != NULL) { 690 reply->type = dormantFlavorInfo.TypeCode(); 691 reply->flattened_size = dormantFlavorInfo.FlattenedSize(); 692 reply->result = dormantFlavorInfo.Flatten( 693 reply->flattened_data, reply->flattened_size); 694 695 request.SendReply(reply->result, reply, replySize); 696 free(reply); 697 } else { 698 server_get_dormant_flavor_info_reply reply; 699 reply.result = B_NO_MEMORY; 700 request.SendReply(reply.result, &reply, sizeof(reply)); 701 } 702 } 703 break; 704 } 705 706 case SERVER_SET_NODE_CREATOR: 707 { 708 const server_set_node_creator_request& request 709 = *static_cast<const server_set_node_creator_request*>(data); 710 server_set_node_creator_reply reply; 711 status_t status = gNodeManager->SetNodeCreator(request.node, 712 request.creator); 713 request.SendReply(status, &reply, sizeof(reply)); 714 break; 715 } 716 717 case SERVER_GET_SHARED_BUFFER_AREA: 718 { 719 const server_get_shared_buffer_area_request& request 720 = *static_cast<const server_get_shared_buffer_area_request*>( 721 data); 722 server_get_shared_buffer_area_reply reply; 723 724 reply.area = gBufferManager->SharedBufferListArea(); 725 request.SendReply(reply.area >= 0 ? B_OK : reply.area, &reply, 726 sizeof(reply)); 727 break; 728 } 729 730 case SERVER_REGISTER_BUFFER: 731 { 732 const server_register_buffer_request& request 733 = *static_cast<const server_register_buffer_request*>(data); 734 server_register_buffer_reply reply; 735 status_t status; 736 737 if (request.info.buffer == 0) { 738 reply.info = request.info; 739 // size, offset, flags, area is kept 740 // get a new beuffer id into reply.info.buffer 741 status = gBufferManager->RegisterBuffer(request.team, 742 request.info.size, request.info.flags, 743 request.info.offset, request.info.area, 744 &reply.info.buffer); 745 } else { 746 reply.info = request.info; // buffer id is kept 747 status = gBufferManager->RegisterBuffer(request.team, 748 request.info.buffer, &reply.info.size, &reply.info.flags, 749 &reply.info.offset, &reply.info.area); 750 } 751 request.SendReply(status, &reply, sizeof(reply)); 752 break; 753 } 754 755 case SERVER_UNREGISTER_BUFFER: 756 { 757 const server_unregister_buffer_command& request = *static_cast< 758 const server_unregister_buffer_command*>(data); 759 760 gBufferManager->UnregisterBuffer(request.team, request.buffer_id); 761 break; 762 } 763 764 case SERVER_GET_MEDIA_FILE_TYPES: 765 { 766 const server_get_media_types_request& request 767 = *static_cast<const server_get_media_types_request*>(data); 768 769 server_get_media_types_reply reply; 770 area_id area = gMediaFilesManager->GetTypesArea(reply.count); 771 if (area >= 0) { 772 // transfer the area to the target team 773 reply.area = _kern_transfer_area(area, &reply.address, 774 B_ANY_ADDRESS, request.team); 775 if (reply.area < 0) { 776 delete_area(area); 777 reply.area = B_ERROR; 778 reply.count = 0; 779 } 780 } 781 782 status_t status = request.SendReply( 783 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply)); 784 if (status != B_OK) { 785 // if we couldn't send the message, delete the area 786 delete_area(reply.area); 787 } 788 break; 789 } 790 791 case SERVER_GET_MEDIA_FILE_ITEMS: 792 { 793 const server_get_media_items_request& request 794 = *static_cast<const server_get_media_items_request*>(data); 795 796 server_get_media_items_reply reply; 797 area_id area = gMediaFilesManager->GetItemsArea(request.type, 798 reply.count); 799 if (area >= 0) { 800 // transfer the area to the target team 801 reply.area = _kern_transfer_area(area, &reply.address, 802 B_ANY_ADDRESS, request.team); 803 if (reply.area < 0) { 804 delete_area(area); 805 reply.area = B_ERROR; 806 reply.count = 0; 807 } 808 } else 809 reply.area = area; 810 811 status_t status = request.SendReply( 812 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply)); 813 if (status != B_OK) { 814 // if we couldn't send the message, delete the area 815 delete_area(reply.area); 816 } 817 break; 818 } 819 820 case SERVER_GET_REF_FOR: 821 { 822 const server_get_ref_for_request& request 823 = *static_cast<const server_get_ref_for_request*>(data); 824 server_get_ref_for_reply reply; 825 entry_ref* ref; 826 827 status_t status = gMediaFilesManager->GetRefFor(request.type, 828 request.item, &ref); 829 if (status == B_OK) 830 reply.ref = *ref; 831 832 request.SendReply(status, &reply, sizeof(reply)); 833 break; 834 } 835 836 case SERVER_SET_REF_FOR: 837 { 838 const server_set_ref_for_request& request 839 = *static_cast<const server_set_ref_for_request*>(data); 840 server_set_ref_for_reply reply; 841 entry_ref ref = request.ref; 842 843 status_t status = gMediaFilesManager->SetRefFor(request.type, 844 request.item, ref); 845 request.SendReply(status, &reply, sizeof(reply)); 846 break; 847 } 848 849 case SERVER_INVALIDATE_MEDIA_ITEM: 850 { 851 const server_invalidate_item_request& request 852 = *static_cast<const server_invalidate_item_request*>(data); 853 server_invalidate_item_reply reply; 854 855 status_t status = gMediaFilesManager->InvalidateItem(request.type, 856 request.item); 857 request.SendReply(status, &reply, sizeof(reply)); 858 break; 859 } 860 861 case SERVER_REMOVE_MEDIA_ITEM: 862 { 863 const server_remove_media_item_request& request 864 = *static_cast<const server_remove_media_item_request*>(data); 865 server_remove_media_item_reply reply; 866 867 status_t status = gMediaFilesManager->RemoveItem(request.type, 868 request.item); 869 request.SendReply(status, &reply, sizeof(reply)); 870 break; 871 } 872 873 case SERVER_GET_ITEM_AUDIO_GAIN: 874 { 875 const server_get_item_audio_gain_request& request 876 = *static_cast<const server_get_item_audio_gain_request*>(data); 877 server_get_item_audio_gain_reply reply; 878 879 status_t status = gMediaFilesManager->GetAudioGainFor(request.type, 880 request.item, &reply.gain); 881 request.SendReply(status, &reply, sizeof(reply)); 882 break; 883 } 884 885 case SERVER_SET_ITEM_AUDIO_GAIN: 886 { 887 const server_set_item_audio_gain_request& request 888 = *static_cast<const server_set_item_audio_gain_request*>(data); 889 server_set_ref_for_reply reply; 890 891 status_t status = gMediaFilesManager->SetAudioGainFor(request.type, 892 request.item, request.gain); 893 request.SendReply(status, &reply, sizeof(reply)); 894 break; 895 } 896 897 default: 898 printf("media_server: received unknown message code %#08" B_PRIx32 899 "\n", code); 900 } 901 TRACE("ServerApp::HandleMessage %#" B_PRIx32 " leave\n", code); 902 } 903 904 905 status_t 906 ServerApp::_ControlThread(void* _server) 907 { 908 ServerApp* server = (ServerApp*)_server; 909 910 char data[B_MEDIA_MESSAGE_SIZE]; 911 ssize_t size; 912 int32 code; 913 while ((size = read_port_etc(server->_ControlPort(), &code, data, 914 sizeof(data), 0, 0)) > 0) { 915 server->_HandleMessage(code, data, size); 916 } 917 918 return B_OK; 919 } 920 921 922 void 923 ServerApp::MessageReceived(BMessage* msg) 924 { 925 TRACE("ServerApp::MessageReceived %" B_PRIu32 " enter\n", msg->what); 926 switch (msg->what) { 927 case MEDIA_SERVER_REQUEST_NOTIFICATIONS: 928 case MEDIA_SERVER_CANCEL_NOTIFICATIONS: 929 case MEDIA_SERVER_SEND_NOTIFICATIONS: 930 gNotificationManager->EnqueueMessage(msg); 931 break; 932 933 case MEDIA_FILES_MANAGER_SAVE_TIMER: 934 gMediaFilesManager->TimerMessage(); 935 break; 936 937 case MEDIA_SERVER_ADD_SYSTEM_BEEP_EVENT: 938 gMediaFilesManager->HandleAddSystemBeepEvent(msg); 939 break; 940 941 case MEDIA_SERVER_RESCAN_COMPLETED: 942 gAppManager->NotifyRosters(); 943 break; 944 945 case B_SOME_APP_QUIT: 946 { 947 BString mimeSig; 948 if (msg->FindString("be:signature", &mimeSig) != B_OK) 949 return; 950 951 if (mimeSig == B_MEDIA_ADDON_SERVER_SIGNATURE) 952 gNodeManager->CleanupDormantFlavorInfos(); 953 954 team_id id; 955 if (msg->FindInt32("team", &id) == B_OK 956 && gAppManager->HasTeam(id)) { 957 gAppManager->UnregisterTeam(id); 958 } 959 break; 960 } 961 962 default: 963 BApplication::MessageReceived(msg); 964 TRACE("\nmedia_server: unknown message received!\n"); 965 break; 966 } 967 TRACE("ServerApp::MessageReceived %" B_PRIu32 " leave\n", msg->what); 968 } 969 970 971 // #pragma mark - 972 973 974 int 975 main() 976 { 977 status_t status; 978 ServerApp app(status); 979 980 if (status == B_OK) 981 app.Run(); 982 983 return status == B_OK ? EXIT_SUCCESS : EXIT_FAILURE; 984 } 985