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, request.timesource_id, &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_SET_NODE_TIMESOURCE: 584 { 585 const server_set_node_timesource_request& request 586 = *static_cast<const server_set_node_timesource_request*>(data); 587 server_set_node_timesource_reply reply; 588 status_t result = gNodeManager->SetNodeTimeSource(request.node_id, 589 request.timesource_id); 590 request.SendReply(result, &reply, sizeof(reply)); 591 break; 592 } 593 594 case SERVER_REGISTER_ADD_ON: 595 { 596 const server_register_add_on_request& request = *static_cast< 597 const server_register_add_on_request*>(data); 598 server_register_add_on_reply reply; 599 600 gNodeManager->RegisterAddOn(request.ref, &reply.add_on_id); 601 request.SendReply(B_OK, &reply, sizeof(reply)); 602 break; 603 } 604 605 case SERVER_UNREGISTER_ADD_ON: 606 { 607 const server_unregister_add_on_command& request = *static_cast< 608 const server_unregister_add_on_command*>(data); 609 gNodeManager->UnregisterAddOn(request.add_on_id); 610 break; 611 } 612 613 case SERVER_REGISTER_DORMANT_NODE: 614 { 615 const server_register_dormant_node_command& command 616 = *static_cast<const server_register_dormant_node_command*>( 617 data); 618 if (command.purge_id > 0) 619 gNodeManager->InvalidateDormantFlavorInfo(command.purge_id); 620 621 dormant_flavor_info dormantFlavorInfo; 622 status_t status = dormantFlavorInfo.Unflatten(command.type, 623 command.flattened_data, command.flattened_size); 624 if (status == B_OK) 625 gNodeManager->AddDormantFlavorInfo(dormantFlavorInfo); 626 break; 627 } 628 629 case SERVER_GET_DORMANT_NODES: 630 { 631 const server_get_dormant_nodes_request& request 632 = *static_cast<const server_get_dormant_nodes_request*>(data); 633 634 server_get_dormant_nodes_reply reply; 635 reply.count = request.max_count; 636 637 dormant_node_info* infos 638 = new(std::nothrow) dormant_node_info[reply.count]; 639 if (infos != NULL) { 640 reply.result = gNodeManager->GetDormantNodes(infos, 641 &reply.count, 642 request.has_input ? &request.input_format : NULL, 643 request.has_output ? &request.output_format : NULL, 644 request.has_name ? request.name : NULL, 645 request.require_kinds, request.deny_kinds); 646 } else 647 reply.result = B_NO_MEMORY; 648 649 if (reply.result != B_OK) 650 reply.count = 0; 651 652 request.SendReply(reply.result, &reply, sizeof(reply)); 653 if (reply.count > 0) { 654 write_port(request.reply_port, 0, infos, 655 reply.count * sizeof(dormant_node_info)); 656 } 657 delete[] infos; 658 break; 659 } 660 661 case SERVER_GET_DORMANT_FLAVOR_INFO: 662 { 663 const server_get_dormant_flavor_info_request& request 664 = *static_cast<const server_get_dormant_flavor_info_request*>( 665 data); 666 dormant_flavor_info dormantFlavorInfo; 667 668 status_t status = gNodeManager->GetDormantFlavorInfoFor( 669 request.add_on_id, request.flavor_id, &dormantFlavorInfo); 670 if (status != B_OK) { 671 server_get_dormant_flavor_info_reply reply; 672 reply.result = status; 673 request.SendReply(reply.result, &reply, sizeof(reply)); 674 } else { 675 size_t replySize 676 = sizeof(server_get_dormant_flavor_info_reply) 677 + dormantFlavorInfo.FlattenedSize(); 678 server_get_dormant_flavor_info_reply* reply 679 = (server_get_dormant_flavor_info_reply*)malloc( 680 replySize); 681 if (reply != NULL) { 682 reply->type = dormantFlavorInfo.TypeCode(); 683 reply->flattened_size = dormantFlavorInfo.FlattenedSize(); 684 reply->result = dormantFlavorInfo.Flatten( 685 reply->flattened_data, reply->flattened_size); 686 687 request.SendReply(reply->result, reply, replySize); 688 free(reply); 689 } else { 690 server_get_dormant_flavor_info_reply reply; 691 reply.result = B_NO_MEMORY; 692 request.SendReply(reply.result, &reply, sizeof(reply)); 693 } 694 } 695 break; 696 } 697 698 case SERVER_SET_NODE_CREATOR: 699 { 700 const server_set_node_creator_request& request 701 = *static_cast<const server_set_node_creator_request*>(data); 702 server_set_node_creator_reply reply; 703 status_t status = gNodeManager->SetNodeCreator(request.node, 704 request.creator); 705 request.SendReply(status, &reply, sizeof(reply)); 706 break; 707 } 708 709 case SERVER_GET_SHARED_BUFFER_AREA: 710 { 711 const server_get_shared_buffer_area_request& request 712 = *static_cast<const server_get_shared_buffer_area_request*>( 713 data); 714 server_get_shared_buffer_area_reply reply; 715 716 reply.area = gBufferManager->SharedBufferListArea(); 717 request.SendReply(reply.area >= 0 ? B_OK : reply.area, &reply, 718 sizeof(reply)); 719 break; 720 } 721 722 case SERVER_REGISTER_BUFFER: 723 { 724 const server_register_buffer_request& request 725 = *static_cast<const server_register_buffer_request*>(data); 726 server_register_buffer_reply reply; 727 status_t status; 728 729 if (request.info.buffer == 0) { 730 reply.info = request.info; 731 // size, offset, flags, area is kept 732 // get a new beuffer id into reply.info.buffer 733 status = gBufferManager->RegisterBuffer(request.team, 734 request.info.size, request.info.flags, 735 request.info.offset, request.info.area, 736 &reply.info.buffer); 737 } else { 738 reply.info = request.info; // buffer id is kept 739 status = gBufferManager->RegisterBuffer(request.team, 740 request.info.buffer, &reply.info.size, &reply.info.flags, 741 &reply.info.offset, &reply.info.area); 742 } 743 request.SendReply(status, &reply, sizeof(reply)); 744 break; 745 } 746 747 case SERVER_UNREGISTER_BUFFER: 748 { 749 const server_unregister_buffer_command& request = *static_cast< 750 const server_unregister_buffer_command*>(data); 751 752 gBufferManager->UnregisterBuffer(request.team, request.buffer_id); 753 break; 754 } 755 756 case SERVER_GET_MEDIA_FILE_TYPES: 757 { 758 const server_get_media_types_request& request 759 = *static_cast<const server_get_media_types_request*>(data); 760 761 server_get_media_types_reply reply; 762 area_id area = gMediaFilesManager->GetTypesArea(reply.count); 763 if (area >= 0) { 764 // transfer the area to the target team 765 reply.area = _kern_transfer_area(area, &reply.address, 766 B_ANY_ADDRESS, request.team); 767 if (reply.area < 0) { 768 delete_area(area); 769 reply.area = B_ERROR; 770 reply.count = 0; 771 } 772 } 773 774 status_t status = request.SendReply( 775 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply)); 776 if (status != B_OK) { 777 // if we couldn't send the message, delete the area 778 delete_area(reply.area); 779 } 780 break; 781 } 782 783 case SERVER_GET_MEDIA_FILE_ITEMS: 784 { 785 const server_get_media_items_request& request 786 = *static_cast<const server_get_media_items_request*>(data); 787 788 server_get_media_items_reply reply; 789 area_id area = gMediaFilesManager->GetItemsArea(request.type, 790 reply.count); 791 if (area >= 0) { 792 // transfer the area to the target team 793 reply.area = _kern_transfer_area(area, &reply.address, 794 B_ANY_ADDRESS, request.team); 795 if (reply.area < 0) { 796 delete_area(area); 797 reply.area = B_ERROR; 798 reply.count = 0; 799 } 800 } else 801 reply.area = area; 802 803 status_t status = request.SendReply( 804 reply.area < 0 ? reply.area : B_OK, &reply, sizeof(reply)); 805 if (status != B_OK) { 806 // if we couldn't send the message, delete the area 807 delete_area(reply.area); 808 } 809 break; 810 } 811 812 case SERVER_GET_REF_FOR: 813 { 814 const server_get_ref_for_request& request 815 = *static_cast<const server_get_ref_for_request*>(data); 816 server_get_ref_for_reply reply; 817 entry_ref* ref; 818 819 status_t status = gMediaFilesManager->GetRefFor(request.type, 820 request.item, &ref); 821 if (status == B_OK) 822 reply.ref = *ref; 823 824 request.SendReply(status, &reply, sizeof(reply)); 825 break; 826 } 827 828 case SERVER_SET_REF_FOR: 829 { 830 const server_set_ref_for_request& request 831 = *static_cast<const server_set_ref_for_request*>(data); 832 server_set_ref_for_reply reply; 833 entry_ref ref = request.ref; 834 835 status_t status = gMediaFilesManager->SetRefFor(request.type, 836 request.item, ref); 837 request.SendReply(status, &reply, sizeof(reply)); 838 break; 839 } 840 841 case SERVER_INVALIDATE_MEDIA_ITEM: 842 { 843 const server_invalidate_item_request& request 844 = *static_cast<const server_invalidate_item_request*>(data); 845 server_invalidate_item_reply reply; 846 847 status_t status = gMediaFilesManager->InvalidateItem(request.type, 848 request.item); 849 request.SendReply(status, &reply, sizeof(reply)); 850 break; 851 } 852 853 case SERVER_REMOVE_MEDIA_ITEM: 854 { 855 const server_remove_media_item_request& request 856 = *static_cast<const server_remove_media_item_request*>(data); 857 server_remove_media_item_reply reply; 858 859 status_t status = gMediaFilesManager->RemoveItem(request.type, 860 request.item); 861 request.SendReply(status, &reply, sizeof(reply)); 862 break; 863 } 864 865 case SERVER_GET_ITEM_AUDIO_GAIN: 866 { 867 const server_get_item_audio_gain_request& request 868 = *static_cast<const server_get_item_audio_gain_request*>(data); 869 server_get_item_audio_gain_reply reply; 870 871 status_t status = gMediaFilesManager->GetAudioGainFor(request.type, 872 request.item, &reply.gain); 873 request.SendReply(status, &reply, sizeof(reply)); 874 break; 875 } 876 877 case SERVER_SET_ITEM_AUDIO_GAIN: 878 { 879 const server_set_item_audio_gain_request& request 880 = *static_cast<const server_set_item_audio_gain_request*>(data); 881 server_set_ref_for_reply reply; 882 883 status_t status = gMediaFilesManager->SetAudioGainFor(request.type, 884 request.item, request.gain); 885 request.SendReply(status, &reply, sizeof(reply)); 886 break; 887 } 888 889 default: 890 printf("media_server: received unknown message code %#08" B_PRIx32 891 "\n", code); 892 } 893 TRACE("ServerApp::HandleMessage %#" B_PRIx32 " leave\n", code); 894 } 895 896 897 status_t 898 ServerApp::_ControlThread(void* _server) 899 { 900 ServerApp* server = (ServerApp*)_server; 901 902 char data[B_MEDIA_MESSAGE_SIZE]; 903 ssize_t size; 904 int32 code; 905 while ((size = read_port_etc(server->_ControlPort(), &code, data, 906 sizeof(data), 0, 0)) > 0) { 907 server->_HandleMessage(code, data, size); 908 } 909 910 return B_OK; 911 } 912 913 914 void 915 ServerApp::MessageReceived(BMessage* msg) 916 { 917 TRACE("ServerApp::MessageReceived %lx enter\n", msg->what); 918 switch (msg->what) { 919 case MEDIA_SERVER_REQUEST_NOTIFICATIONS: 920 case MEDIA_SERVER_CANCEL_NOTIFICATIONS: 921 case MEDIA_SERVER_SEND_NOTIFICATIONS: 922 gNotificationManager->EnqueueMessage(msg); 923 break; 924 925 case MEDIA_FILES_MANAGER_SAVE_TIMER: 926 gMediaFilesManager->TimerMessage(); 927 break; 928 929 case MEDIA_SERVER_ADD_SYSTEM_BEEP_EVENT: 930 gMediaFilesManager->HandleAddSystemBeepEvent(msg); 931 break; 932 default: 933 BApplication::MessageReceived(msg); 934 printf("\nmedia_server: unknown message received:\n"); 935 msg->PrintToStream(); 936 break; 937 } 938 TRACE("ServerApp::MessageReceived %lx leave\n", msg->what); 939 } 940 941 942 // #pragma mark - 943 944 945 int 946 main() 947 { 948 new ServerApp; 949 be_app->Run(); 950 delete be_app; 951 return 0; 952 } 953