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