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