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