1 /* 2 * Copyright 2002, 2003 Marcus Overhagen, Jérôme Duval. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "DefaultManager.h" 8 9 #include <Application.h> 10 #include <Directory.h> 11 #include <File.h> 12 #include <FindDirectory.h> 13 #include <MediaNode.h> 14 #include <OS.h> 15 #include <Path.h> 16 #include <TimeSource.h> 17 #include <string.h> 18 19 #include "debug.h" 20 #include "DormantNodeManager.h" 21 #include "media_server.h" 22 #include "NodeManager.h" 23 24 25 /* no locking used in this file, we assume that the caller (NodeManager) does it. 26 */ 27 28 29 #define MAX_NODE_INFOS 10 30 #define MAX_INPUT_INFOS 10 31 32 const uint32 kMsgHeader = 'sepx'; 33 const uint32 kMsgTypeVideoIn = 0xffffffef; 34 const uint32 kMsgTypeVideoOut = 0xffffffee; 35 const uint32 kMsgTypeAudioIn = 0xfffffffe; 36 const uint32 kMsgTypeAudioOut = 0xffffffff; 37 38 const char *kDefaultManagerType = "be:_default"; 39 const char *kDefaultManagerAddon = "be:_addon_id"; 40 const char *kDefaultManagerFlavorId = "be:_internal_id"; 41 const char *kDefaultManagerFlavorName = "be:_flavor_name"; 42 const char *kDefaultManagerPath = "be:_path"; 43 const char *kDefaultManagerInput = "be:_input_id"; 44 45 const char *kDefaultManagerSettingsDirectory = "Media"; 46 const char *kDefaultManagerSettingsFile = "MDefaultManager"; 47 48 49 DefaultManager::DefaultManager() 50 : 51 fMixerConnected(false), 52 fPhysicalVideoOut(-1), 53 fPhysicalVideoIn(-1), 54 fPhysicalAudioOut(-1), 55 fPhysicalAudioIn(-1), 56 fSystemTimeSource(-1), 57 fTimeSource(-1), 58 fAudioMixer(-1), 59 fPhysicalAudioOutInputID(0), 60 fRescanThread(-1), 61 fRescanRequested(0), 62 fRescanLock("rescan default manager"), 63 fRoster(NULL) 64 { 65 strcpy(fPhysicalAudioOutInputName, "default"); 66 fBeginHeader[0] = 0xab00150b; 67 fBeginHeader[1] = 0x18723462; 68 fBeginHeader[2] = 0x00000002; 69 fEndHeader[0] = 0x7465726d; 70 fEndHeader[1] = 0x6d666c67; 71 fEndHeader[2] = 0x00000002; 72 73 fRoster = BMediaRoster::Roster(); 74 if (fRoster == NULL) 75 TRACE("DefaultManager: The roster is NULL\n"); 76 } 77 78 79 DefaultManager::~DefaultManager() 80 { 81 } 82 83 84 // this is called by the media_server *before* any add-ons have been loaded 85 status_t 86 DefaultManager::LoadState() 87 { 88 CALLED(); 89 status_t err = B_OK; 90 BPath path; 91 if ((err = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK) 92 return err; 93 94 path.Append(kDefaultManagerSettingsDirectory); 95 path.Append(kDefaultManagerSettingsFile); 96 97 BFile file(path.Path(), B_READ_ONLY); 98 99 uint32 categoryCount; 100 ssize_t size = sizeof(uint32) * 3; 101 if (file.Read(fBeginHeader, size) < size) 102 return B_ERROR; 103 TRACE("0x%08lx %ld\n", fBeginHeader[0], fBeginHeader[0]); 104 TRACE("0x%08lx %ld\n", fBeginHeader[1], fBeginHeader[1]); 105 TRACE("0x%08lx %ld\n", fBeginHeader[2], fBeginHeader[2]); 106 size = sizeof(uint32); 107 if (file.Read(&categoryCount, size) < size) { 108 fprintf(stderr, 109 "DefaultManager::LoadState() failed to read categoryCount\n"); 110 return B_ERROR; 111 } 112 TRACE("DefaultManager::LoadState() categoryCount %ld\n", categoryCount); 113 while (categoryCount--) { 114 BMessage settings; 115 uint32 msg_header; 116 uint32 default_type; 117 if (file.Read(&msg_header, size) < size) { 118 fprintf(stderr, 119 "DefaultManager::LoadState() failed to read msg_header\n"); 120 return B_ERROR; 121 } 122 if (file.Read(&default_type, size) < size) { 123 fprintf(stderr, 124 "DefaultManager::LoadState() failed to read default_type\n"); 125 return B_ERROR; 126 } 127 if (settings.Unflatten(&file) == B_OK) 128 fMsgList.AddItem(new BMessage(settings)); 129 else 130 fprintf(stderr, "DefaultManager::LoadState() failed to unflatten\n"); 131 } 132 size = sizeof(uint32) * 3; 133 if (file.Read(fEndHeader,size) < size) { 134 fprintf(stderr, 135 "DefaultManager::LoadState() failed to read fEndHeader\n"); 136 return B_ERROR; 137 } 138 139 TRACE("LoadState returns B_OK\n"); 140 return B_OK; 141 } 142 143 144 status_t 145 DefaultManager::SaveState(NodeManager *node_manager) 146 { 147 CALLED(); 148 status_t err = B_OK; 149 BPath path; 150 BList list; 151 if ((err = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true)) != B_OK) 152 return err; 153 path.Append(kDefaultManagerSettingsDirectory); 154 if ((err = create_directory(path.Path(), 0755)) != B_OK) 155 return err; 156 path.Append(kDefaultManagerSettingsFile); 157 158 uint32 default_types[] = {kMsgTypeVideoIn, kMsgTypeVideoOut, 159 kMsgTypeAudioIn, kMsgTypeAudioOut}; 160 media_node_id media_node_ids[] = {fPhysicalVideoIn, fPhysicalVideoOut, 161 fPhysicalAudioIn, fPhysicalAudioOut}; 162 for (uint32 i = 0; i < sizeof(default_types) / sizeof(default_types[0]); 163 i++) { 164 165 // we call the node manager to have more infos about nodes 166 dormant_node_info info; 167 media_node node; 168 entry_ref ref; 169 if (node_manager->GetCloneForID(media_node_ids[i], be_app->Team(), 170 &node) != B_OK 171 || node_manager->GetDormantNodeInfo(node, &info) != B_OK 172 || node_manager->ReleaseNodeReference(media_node_ids[i], 173 be_app->Team()) != B_OK 174 || node_manager->GetAddOnRef(info.addon, &ref) != B_OK) { 175 if (media_node_ids[i] != -1) { 176 // failed to get node info thus just return 177 return B_ERROR; 178 } 179 continue; 180 } 181 182 BMessage *settings = new BMessage(); 183 settings->AddInt32(kDefaultManagerType, default_types[i]); 184 BPath path(&ref); 185 settings->AddInt32(kDefaultManagerAddon, info.addon); 186 settings->AddInt32(kDefaultManagerFlavorId, info.flavor_id); 187 settings->AddInt32(kDefaultManagerInput, 188 default_types[i] == kMsgTypeAudioOut ? fPhysicalAudioOutInputID : 0); 189 settings->AddString(kDefaultManagerFlavorName, info.name); 190 settings->AddString(kDefaultManagerPath, path.Path()); 191 192 list.AddItem(settings); 193 TRACE("message %s added\n", info.name); 194 } 195 196 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 197 198 if (file.Write(fBeginHeader, sizeof(uint32)*3) < (int32)sizeof(uint32)*3) 199 return B_ERROR; 200 int32 categoryCount = list.CountItems(); 201 if (file.Write(&categoryCount, sizeof(uint32)) < (int32)sizeof(uint32)) 202 return B_ERROR; 203 204 for (int32 i = 0; i < categoryCount; i++) { 205 BMessage *settings = (BMessage *)list.ItemAt(i); 206 uint32 default_type; 207 if (settings->FindInt32(kDefaultManagerType, 208 (int32*)&default_type) < B_OK) 209 return B_ERROR; 210 if (file.Write(&kMsgHeader, sizeof(uint32)) < (int32)sizeof(uint32)) 211 return B_ERROR; 212 if (file.Write(&default_type, sizeof(uint32)) < (int32)sizeof(uint32)) 213 return B_ERROR; 214 if (settings->Flatten(&file) < B_OK) 215 return B_ERROR; 216 delete settings; 217 } 218 if (file.Write(fEndHeader, sizeof(uint32)*3) < (int32)sizeof(uint32)*3) 219 return B_ERROR; 220 221 return B_OK; 222 } 223 224 225 status_t 226 DefaultManager::Set(media_node_id node_id, const char *input_name, 227 int32 input_id, node_type type) 228 { 229 CALLED(); 230 TRACE("DefaultManager::Set type : %i, node : %li, input : %li\n", type, 231 node_id, input_id); 232 switch (type) { 233 case VIDEO_INPUT: 234 fPhysicalVideoIn = node_id; 235 return B_OK; 236 case AUDIO_INPUT: 237 fPhysicalAudioIn = node_id; 238 return B_OK; 239 case VIDEO_OUTPUT: 240 fPhysicalVideoOut = node_id; 241 return B_OK; 242 case AUDIO_MIXER: 243 return B_ERROR; 244 case AUDIO_OUTPUT: 245 fPhysicalAudioOut = node_id; 246 fPhysicalAudioOutInputID = input_id; 247 strcpy(fPhysicalAudioOutInputName, 248 input_name ? input_name : "<null>"); 249 return B_OK; 250 case TIME_SOURCE: 251 return B_ERROR; 252 253 // called by the media_server's ServerApp::StartSystemTimeSource() 254 case SYSTEM_TIME_SOURCE: 255 { 256 ASSERT(fSystemTimeSource == -1); 257 fSystemTimeSource = node_id; 258 return B_OK; 259 } 260 261 default: 262 { 263 ERROR("DefaultManager::Set Error: called with unknown type %d\n", 264 type); 265 return B_ERROR; 266 } 267 } 268 } 269 270 271 status_t 272 DefaultManager::Get(media_node_id *nodeid, char *input_name, int32 *inputid, 273 node_type type) 274 { 275 CALLED(); 276 switch (type) { 277 case VIDEO_INPUT: // output: nodeid 278 if (fPhysicalVideoIn == -1) 279 return B_NAME_NOT_FOUND; 280 *nodeid = fPhysicalVideoIn; 281 return B_OK; 282 283 case AUDIO_INPUT: // output: nodeid 284 if (fPhysicalAudioIn == -1) 285 return B_NAME_NOT_FOUND; 286 *nodeid = fPhysicalAudioIn; 287 return B_OK; 288 289 case VIDEO_OUTPUT: // output: nodeid 290 if (fPhysicalVideoOut == -1) 291 return B_NAME_NOT_FOUND; 292 *nodeid = fPhysicalVideoOut; 293 return B_OK; 294 295 case AUDIO_OUTPUT: // output: nodeid 296 if (fPhysicalAudioOut == -1) 297 return B_NAME_NOT_FOUND; 298 *nodeid = fPhysicalAudioOut; 299 return B_OK; 300 301 case AUDIO_OUTPUT_EX: // output: nodeid, input_name, input_id 302 if (fPhysicalAudioOut == -1) 303 return B_NAME_NOT_FOUND; 304 *nodeid = fPhysicalAudioOut; 305 *inputid = fPhysicalAudioOutInputID; 306 strcpy(input_name, fPhysicalAudioOutInputName); 307 return B_OK; 308 309 case AUDIO_MIXER: // output: nodeid 310 if (fAudioMixer == -1) 311 return B_NAME_NOT_FOUND; 312 *nodeid = fAudioMixer; 313 return B_OK; 314 315 case TIME_SOURCE: 316 if (fTimeSource != -1) 317 *nodeid = fTimeSource; 318 else 319 *nodeid = fSystemTimeSource; 320 return B_OK; 321 322 case SYSTEM_TIME_SOURCE: 323 *nodeid = fSystemTimeSource; 324 return B_OK; 325 326 default: 327 { 328 ERROR("DefaultManager::Get Error: called with unknown type %d\n", 329 type); 330 return B_ERROR; 331 } 332 } 333 } 334 335 336 // this is called by the media_server *after* the initial add-on loading 337 // has been done 338 status_t 339 DefaultManager::Rescan() 340 { 341 BAutolock locker(fRescanLock); 342 atomic_add(&fRescanRequested, 1); 343 if (fRescanThread < 0) { 344 fRescanThread = spawn_thread(rescan_thread, "rescan defaults", 345 B_NORMAL_PRIORITY - 2, this); 346 resume_thread(fRescanThread); 347 } 348 349 return B_OK; 350 } 351 352 353 int32 354 DefaultManager::rescan_thread(void *arg) 355 { 356 reinterpret_cast<DefaultManager *>(arg)->_RescanThread(); 357 return 0; 358 } 359 360 361 void 362 DefaultManager::_RescanThread() 363 { 364 TRACE("DefaultManager::_RescanThread() enter\n"); 365 366 BAutolock locker(fRescanLock); 367 368 while (atomic_and(&fRescanRequested, 0) != 0) { 369 locker.Unlock(); 370 371 // We do not search for the system time source, 372 // it should already exist 373 ASSERT(fSystemTimeSource != -1); 374 375 if (fPhysicalVideoOut == -1) { 376 _FindPhysical(&fPhysicalVideoOut, kMsgTypeVideoOut, false, 377 B_MEDIA_RAW_VIDEO); 378 _FindPhysical(&fPhysicalVideoOut, kMsgTypeVideoOut, false, 379 B_MEDIA_ENCODED_VIDEO); 380 } 381 if (fPhysicalVideoIn == -1) { 382 _FindPhysical(&fPhysicalVideoIn, kMsgTypeVideoIn, true, 383 B_MEDIA_RAW_VIDEO); 384 _FindPhysical(&fPhysicalVideoIn, kMsgTypeVideoIn, true, 385 B_MEDIA_ENCODED_VIDEO); 386 } 387 if (fPhysicalAudioOut == -1) 388 _FindPhysical(&fPhysicalAudioOut, kMsgTypeAudioOut, false, 389 B_MEDIA_RAW_AUDIO); 390 if (fPhysicalAudioIn == -1) 391 _FindPhysical(&fPhysicalAudioIn, kMsgTypeAudioIn, true, 392 B_MEDIA_RAW_AUDIO); 393 if (fAudioMixer == -1) 394 _FindAudioMixer(); 395 396 // The normal time source is searched for after the 397 // Physical Audio Out has been created. 398 if (fTimeSource == -1) 399 _FindTimeSource(); 400 401 // Connect the mixer and physical audio out (soundcard) 402 if (!fMixerConnected && fAudioMixer != -1 && fPhysicalAudioOut != -1) { 403 fMixerConnected = _ConnectMixerToOutput() == B_OK; 404 if (!fMixerConnected) 405 TRACE("DefaultManager: failed to connect mixer and " 406 "soundcard\n"); 407 } else { 408 TRACE("DefaultManager: Did not try to connect mixer and " 409 "soundcard\n"); 410 } 411 412 if (fMixerConnected) { 413 add_on_server_rescan_finished_notify_command cmd; 414 SendToAddOnServer(ADD_ON_SERVER_RESCAN_FINISHED_NOTIFY, &cmd, 415 sizeof(cmd)); 416 } 417 418 locker.Lock(); 419 } 420 421 fRescanThread = -1; 422 423 BMessage msg(MEDIA_SERVER_RESCAN_COMPLETED); 424 be_app->PostMessage(&msg); 425 426 TRACE("DefaultManager::_RescanThread() leave\n"); 427 } 428 429 430 void 431 DefaultManager::_FindPhysical(volatile media_node_id *id, uint32 default_type, 432 bool isInput, media_type type) 433 { 434 live_node_info info[MAX_NODE_INFOS]; 435 media_format format; 436 int32 count; 437 status_t rv; 438 BMessage *msg = NULL; 439 BPath msgPath; 440 dormant_node_info msgDninfo; 441 int32 input_id; 442 bool isAudio = (type == B_MEDIA_RAW_AUDIO) 443 || (type == B_MEDIA_ENCODED_AUDIO); 444 445 for (int32 i = 0; i < fMsgList.CountItems(); i++) { 446 msg = (BMessage *)fMsgList.ItemAt(i); 447 int32 msgType; 448 if (msg->FindInt32(kDefaultManagerType, &msgType) == B_OK 449 && ((uint32)msgType == default_type)) { 450 const char *name = NULL; 451 const char *path = NULL; 452 msg->FindInt32(kDefaultManagerAddon, &msgDninfo.addon); 453 msg->FindInt32(kDefaultManagerFlavorId, &msgDninfo.flavor_id); 454 msg->FindInt32(kDefaultManagerInput, &input_id); 455 msg->FindString(kDefaultManagerFlavorName, &name); 456 msg->FindString(kDefaultManagerPath, &path); 457 if (name) 458 strcpy(msgDninfo.name, name); 459 if (path) 460 msgPath = BPath(path); 461 break; 462 } 463 } 464 465 memset(&format, 0, sizeof(format)); 466 format.type = type; 467 count = MAX_NODE_INFOS; 468 rv = fRoster->GetLiveNodes(&info[0], &count, 469 isInput ? NULL : &format, isInput ? &format : NULL, NULL, 470 isInput ? B_BUFFER_PRODUCER | B_PHYSICAL_INPUT 471 : B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT); 472 if (rv != B_OK || count < 1) { 473 TRACE("Couldn't find physical %s %s node\n", 474 isAudio ? "audio" : "video", isInput ? "input" : "output"); 475 return; 476 } 477 for (int i = 0; i < count; i++) 478 TRACE("info[%d].name %s\n", i, info[i].name); 479 480 for (int i = 0; i < count; i++) { 481 if (isAudio) { 482 if (isInput) { 483 if (0 == strcmp(info[i].name, "None In")) { 484 // we keep the Null audio driver if none else matchs 485 *id = info[i].node.node; 486 continue; 487 } 488 // skip the Firewire audio driver 489 if (0 == strcmp(info[i].name, "DV Input")) 490 continue; 491 } else { 492 if (0 == strcmp(info[i].name, "None Out")) { 493 // we keep the Null audio driver if none else matchs 494 *id = info[i].node.node; 495 if (msg) 496 fPhysicalAudioOutInputID = input_id; 497 continue; 498 } 499 // skip the Firewire audio driver 500 if (0 == strcmp(info[i].name, "DV Output")) 501 continue; 502 } 503 } 504 if (msg) { // we have a default info msg 505 dormant_node_info dninfo; 506 if (fRoster->GetDormantNodeFor(info[i].node, 507 &dninfo) != B_OK) { 508 ERROR("Couldn't GetDormantNodeFor\n"); 509 continue; 510 } 511 if (dninfo.flavor_id != msgDninfo.flavor_id 512 || strcmp(dninfo.name, msgDninfo.name) != 0) { 513 ERROR("Doesn't match flavor or name\n"); 514 continue; 515 } 516 BPath path; 517 if (gDormantNodeManager->FindAddOnPath(&path, dninfo.addon) != B_OK 518 || path != msgPath) { 519 ERROR("Doesn't match : path\n"); 520 continue; 521 } 522 } 523 TRACE("Default physical %s %s \"%s\" created!\n", 524 isAudio ? "audio" : "video", isInput ? "input" : "output", 525 info[i].name); 526 *id = info[i].node.node; 527 if (msg && isAudio && !isInput) 528 fPhysicalAudioOutInputID = input_id; 529 return; 530 } 531 } 532 533 534 void 535 DefaultManager::_FindTimeSource() 536 { 537 live_node_info info[MAX_NODE_INFOS]; 538 media_format input; /* a physical audio output has a logical data input (DAC)*/ 539 int32 count; 540 status_t rv; 541 542 /* First try to use the current default physical audio out 543 */ 544 if (fPhysicalAudioOut != -1) { 545 media_node clone; 546 if (fRoster->GetNodeFor(fPhysicalAudioOut, 547 &clone) == B_OK) { 548 if (clone.kind & B_TIME_SOURCE) { 549 fTimeSource = clone.node; 550 fRoster->StartTimeSource(clone, 551 system_time() + 1000); 552 fRoster->ReleaseNode(clone); 553 TRACE("Default DAC timesource created!\n"); 554 return; 555 } 556 fRoster->ReleaseNode(clone); 557 } else { 558 TRACE("Default DAC is not a timesource!\n"); 559 } 560 } else { 561 TRACE("Default DAC node does not exist!\n"); 562 } 563 564 /* Now try to find another physical audio out node 565 */ 566 memset(&input, 0, sizeof(input)); 567 input.type = B_MEDIA_RAW_AUDIO; 568 count = MAX_NODE_INFOS; 569 rv = fRoster->GetLiveNodes(&info[0], &count, &input, NULL, NULL, 570 B_TIME_SOURCE | B_PHYSICAL_OUTPUT); 571 if (rv == B_OK && count >= 1) { 572 for (int i = 0; i < count; i++) 573 printf("info[%d].name %s\n", i, info[i].name); 574 575 for (int i = 0; i < count; i++) { 576 // The BeOS R5 None Out node pretend to be a physical time source, 577 // that is pretty dumb 578 // skip the Null audio driver 579 if (0 == strcmp(info[i].name, "None Out")) 580 continue; 581 // skip the Firewire audio driver 582 if (0 != strstr(info[i].name, "DV Output")) 583 continue; 584 TRACE("Default DAC timesource \"%s\" created!\n", info[i].name); 585 fTimeSource = info[i].node.node; 586 fRoster->StartTimeSource(info[i].node, 587 system_time() + 1000); 588 return; 589 } 590 } else { 591 TRACE("Couldn't find DAC timesource node\n"); 592 } 593 594 /* XXX we might use other audio or video clock timesources 595 */ 596 } 597 598 599 void 600 DefaultManager::_FindAudioMixer() 601 { 602 live_node_info info; 603 int32 count; 604 status_t rv; 605 606 if (fRoster == NULL) 607 fRoster = BMediaRoster::Roster(); 608 609 count = 1; 610 rv = fRoster->GetLiveNodes(&info, &count, NULL, NULL, NULL, 611 B_BUFFER_PRODUCER | B_BUFFER_CONSUMER | B_SYSTEM_MIXER); 612 if (rv != B_OK || count != 1) { 613 TRACE("Couldn't find audio mixer node\n"); 614 return; 615 } 616 fAudioMixer = info.node.node; 617 TRACE("Default audio mixer node created\n"); 618 } 619 620 621 status_t 622 DefaultManager::_ConnectMixerToOutput() 623 { 624 media_node timesource; 625 media_node mixer; 626 media_node soundcard; 627 media_input inputs[MAX_INPUT_INFOS]; 628 media_input input; 629 media_output output; 630 media_input newinput; 631 media_output newoutput; 632 media_format format; 633 BTimeSource * ts; 634 bigtime_t start_at; 635 int32 count; 636 status_t rv; 637 638 if (fRoster == NULL) 639 fRoster = BMediaRoster::Roster(); 640 641 rv = fRoster->GetNodeFor(fPhysicalAudioOut, &soundcard); 642 if (rv != B_OK) { 643 TRACE("DefaultManager: failed to find soundcard (physical audio " 644 "output)\n"); 645 return B_ERROR; 646 } 647 648 rv = fRoster->GetNodeFor(fAudioMixer, &mixer); 649 if (rv != B_OK) { 650 fRoster->ReleaseNode(soundcard); 651 TRACE("DefaultManager: failed to find mixer\n"); 652 return B_ERROR; 653 } 654 655 // we now have the mixer and soundcard nodes, 656 // find a free input/output and connect them 657 658 rv = fRoster->GetFreeOutputsFor(mixer, &output, 1, &count, 659 B_MEDIA_RAW_AUDIO); 660 if (rv != B_OK || count != 1) { 661 TRACE("DefaultManager: can't find free mixer output\n"); 662 rv = B_ERROR; 663 goto finish; 664 } 665 666 rv = fRoster->GetFreeInputsFor(soundcard, inputs, MAX_INPUT_INFOS, &count, 667 B_MEDIA_RAW_AUDIO); 668 if (rv != B_OK || count < 1) { 669 TRACE("DefaultManager: can't find free soundcard inputs\n"); 670 rv = B_ERROR; 671 goto finish; 672 } 673 674 for (int32 i = 0; i < count; i++) { 675 input = inputs[i]; 676 if (input.destination.id == fPhysicalAudioOutInputID) 677 break; 678 } 679 680 for (int i = 0; i < 6; i++) { 681 switch (i) { 682 case 0: 683 TRACE("DefaultManager: Trying connect in native format (1)\n"); 684 if (fRoster->GetFormatFor(input, &format) != B_OK) { 685 ERROR("DefaultManager: GetFormatFor failed\n"); 686 continue; 687 } 688 // XXX BeOS R5 multiaudio node bug workaround 689 if (format.u.raw_audio.channel_count == 1) { 690 TRACE("##### WARNING! DefaultManager: ignored mono format\n"); 691 continue; 692 } 693 break; 694 695 case 1: 696 TRACE("DefaultManager: Trying connect in format 1\n"); 697 memset(&format, 0, sizeof(format)); 698 format.type = B_MEDIA_RAW_AUDIO; 699 format.u.raw_audio.frame_rate = 44100; 700 format.u.raw_audio.channel_count = 2; 701 format.u.raw_audio.format = 0x2; 702 break; 703 704 case 2: 705 TRACE("DefaultManager: Trying connect in format 2\n"); 706 memset(&format, 0, sizeof(format)); 707 format.type = B_MEDIA_RAW_AUDIO; 708 format.u.raw_audio.frame_rate = 48000; 709 format.u.raw_audio.channel_count = 2; 710 format.u.raw_audio.format = 0x2; 711 break; 712 713 case 3: 714 TRACE("DefaultManager: Trying connect in format 3\n"); 715 memset(&format, 0, sizeof(format)); 716 format.type = B_MEDIA_RAW_AUDIO; 717 break; 718 719 case 4: 720 // BeOS R5 multiaudio node bug workaround 721 TRACE("DefaultManager: Trying connect in native format (2)\n"); 722 if (fRoster->GetFormatFor(input, &format) != B_OK) { 723 ERROR("DefaultManager: GetFormatFor failed\n"); 724 continue; 725 } 726 break; 727 728 case 5: 729 TRACE("DefaultManager: Trying connect in format 4\n"); 730 memset(&format, 0, sizeof(format)); 731 break; 732 733 } 734 rv = fRoster->Connect(output.source, input.destination, &format, 735 &newoutput, &newinput); 736 if (rv == B_OK) 737 break; 738 } 739 if (rv != B_OK) { 740 ERROR("DefaultManager: connect failed\n"); 741 goto finish; 742 } 743 744 fRoster->SetRunModeNode(mixer, BMediaNode::B_INCREASE_LATENCY); 745 fRoster->SetRunModeNode(soundcard, BMediaNode::B_RECORDING); 746 747 fRoster->GetTimeSource(×ource); 748 fRoster->SetTimeSourceFor(mixer.node, timesource.node); 749 fRoster->SetTimeSourceFor(soundcard.node, timesource.node); 750 fRoster->PrerollNode(mixer); 751 fRoster->PrerollNode(soundcard); 752 753 ts = fRoster->MakeTimeSourceFor(mixer); 754 start_at = ts->Now() + 50000; 755 fRoster->StartNode(mixer, start_at); 756 fRoster->StartNode(soundcard, start_at); 757 ts->Release(); 758 759 finish: 760 fRoster->ReleaseNode(mixer); 761 fRoster->ReleaseNode(soundcard); 762 fRoster->ReleaseNode(timesource); 763 return rv; 764 } 765 766 767 void 768 DefaultManager::Dump() 769 { 770 } 771 772 773 void 774 DefaultManager::CleanupTeam(team_id team) 775 { 776 } 777