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