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