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