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