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