1 /* 2 * Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>, 3 * Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>, 4 * All Rights Reserved. Distributed under the terms of the MIT license. 5 */ 6 #include "NodeManager.h" 7 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <MediaRoster.h> 12 #include <scheduler.h> 13 #include <TimeSource.h> 14 15 #include "AudioProducer.h" 16 #include "AudioSupplier.h" 17 #include "VideoConsumer.h" 18 #include "VideoProducer.h" 19 #include "VideoSupplier.h" 20 21 // debugging 22 //#define TRACE_NODE_MANAGER 23 #ifdef TRACE_NODE_MANAGER 24 # define TRACE(x...) printf(x) 25 # define ERROR(x...) fprintf(stderr, x) 26 #else 27 # define TRACE(x...) 28 # define ERROR(x...) fprintf(stderr, x) 29 #endif 30 31 #define print_error(str, status) printf(str ", error: %s\n", strerror(status)) 32 33 NodeManager::Connection::Connection() 34 : connected(false) 35 { 36 memset(&format, 0, sizeof(media_format)); 37 } 38 39 // constructor 40 NodeManager::NodeManager() 41 : PlaybackManager(), 42 fMediaRoster(NULL), 43 fAudioProducer(NULL), 44 fVideoConsumer(NULL), 45 fVideoProducer(NULL), 46 fTimeSource(media_node::null), 47 fAudioConnection(), 48 fVideoConnection(), 49 fPerformanceTimeBase(0), 50 fStatus(B_NO_INIT), 51 fVideoTarget(NULL), 52 fAudioSupplier(NULL), 53 fVideoSupplier(NULL), 54 fVideoBounds(0, 0, -1, -1), 55 fPeakListener(NULL) 56 { 57 } 58 59 // destructor 60 NodeManager::~NodeManager() 61 { 62 _StopNodes(); 63 _TearDownNodes(); 64 } 65 66 // Init 67 status_t 68 NodeManager::Init(BRect videoBounds, float videoFrameRate, 69 color_space preferredVideoFormat, float audioFrameRate, 70 uint32 audioChannels, int32 loopingMode, bool loopingEnabled, 71 float speed, uint32 enabledNodes, bool useOverlays) 72 { 73 // init base class 74 PlaybackManager::Init(videoFrameRate, loopingMode, loopingEnabled, speed); 75 76 // get some objects from a derived class 77 if (!fVideoTarget) 78 fVideoTarget = CreateVideoTarget(); 79 80 if (!fVideoSupplier) 81 fVideoSupplier = CreateVideoSupplier(); 82 83 if (!fAudioSupplier) 84 fAudioSupplier = CreateAudioSupplier(); 85 86 return FormatChanged(videoBounds, videoFrameRate, preferredVideoFormat, 87 audioFrameRate, audioChannels, enabledNodes, useOverlays, true); 88 } 89 90 // InitCheck 91 status_t 92 NodeManager::InitCheck() 93 { 94 return fStatus; 95 } 96 97 // SetPlayMode 98 void 99 NodeManager::SetPlayMode(int32 mode, bool continuePlaying) 100 { 101 // if (fMediaRoster && fMediaRoster->Lock()) { 102 // BMediaNode::run_mode runMode = mode > 0 ? 103 // BMediaNode::B_DROP_DATA : BMediaNode::B_OFFLINE; 104 // fMediaRoster->SetRunModeNode(fVideoConnection.consumer, runMode); 105 // fMediaRoster->Unlock(); 106 // } 107 108 PlaybackManager::SetPlayMode(mode, continuePlaying); 109 } 110 111 // CleanupNodes 112 status_t 113 NodeManager::CleanupNodes() 114 { 115 _StopNodes(); 116 return _TearDownNodes(false); 117 } 118 119 // FormatChanged 120 status_t 121 NodeManager::FormatChanged(BRect videoBounds, float videoFrameRate, 122 color_space preferredVideoFormat, float audioFrameRate, 123 uint32 audioChannels, uint32 enabledNodes, bool useOverlays, bool force) 124 { 125 TRACE("NodeManager::FormatChanged()\n"); 126 127 if (!force && videoBounds == VideoBounds() 128 && videoFrameRate == FramesPerSecond()) { 129 TRACE(" -> reusing existing nodes\n"); 130 // TODO: if enabledNodes would indicate that audio or video 131 // is no longer needed, or, worse yet, suddenly needed when 132 // it wasn't before, then we should not return here! 133 return B_OK; 134 } 135 136 if (videoFrameRate != FramesPerSecond()) { 137 TRACE(" -> need to Init()\n"); 138 PlaybackManager::Init(videoFrameRate, LoopMode(), IsLoopingEnabled(), 139 Speed(), MODE_PLAYING_PAUSED_FORWARD, CurrentFrame()); 140 } 141 142 _StopNodes(); 143 _TearDownNodes(); 144 145 SetVideoBounds(videoBounds); 146 147 status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes, 148 useOverlays, audioFrameRate, audioChannels); 149 if (ret == B_OK) 150 _StartNodes(); 151 else 152 fprintf(stderr, "unable to setup nodes: %s\n", strerror(ret)); 153 154 return ret; 155 } 156 157 // RealTimeForTime 158 bigtime_t 159 NodeManager::RealTimeForTime(bigtime_t time) const 160 { 161 bigtime_t result = 0; 162 if (fVideoProducer) { 163 result = fVideoProducer->TimeSource()->RealTimeFor( 164 fPerformanceTimeBase + time, 0); 165 } else if (fAudioProducer) { 166 result = fAudioProducer->TimeSource()->RealTimeFor( 167 fPerformanceTimeBase + time, 0); 168 } 169 //printf("NodeManager::RealTimeForTime(%lld) -> %lld\n", time, result); 170 return result; 171 } 172 173 // TimeForRealTime 174 bigtime_t 175 NodeManager::TimeForRealTime(bigtime_t time) const 176 { 177 bigtime_t result = 0; 178 if (fVideoProducer) { 179 result = fVideoProducer->TimeSource()->PerformanceTimeFor(time) 180 - fPerformanceTimeBase; 181 } else if (fAudioProducer) { 182 result = fAudioProducer->TimeSource()->PerformanceTimeFor(time) 183 - fPerformanceTimeBase; 184 } 185 return result; 186 } 187 188 // SetCurrentAudioTime 189 void 190 NodeManager::SetCurrentAudioTime(bigtime_t time) 191 { 192 //printf("NodeManager::SetCurrentAudioTime(%lld)\n", time); 193 PlaybackManager::SetCurrentAudioTime(time); 194 if (!fVideoProducer) { 195 // running without video, update video time as well 196 PlaybackManager::SetCurrentVideoTime(time); 197 } 198 } 199 200 // SetVideoBounds 201 void 202 NodeManager::SetVideoBounds(BRect bounds) 203 { 204 if (bounds != fVideoBounds) { 205 fVideoBounds = bounds; 206 NotifyVideoBoundsChanged(fVideoBounds); 207 } 208 } 209 210 // VideoBounds 211 BRect 212 NodeManager::VideoBounds() const 213 { 214 return fVideoBounds; 215 } 216 217 // SetVideoTarget 218 void 219 NodeManager::SetVideoTarget(VideoTarget* videoTarget) 220 { 221 if (videoTarget != fVideoTarget) { 222 fVideoTarget = videoTarget; 223 if (fVideoConsumer) 224 fVideoConsumer->SetTarget(fVideoTarget); 225 } 226 } 227 228 // GetVideoTarget 229 VideoTarget* 230 NodeManager::GetVideoTarget() const 231 { 232 return fVideoTarget; 233 } 234 235 // SetVolume 236 void 237 NodeManager::SetVolume(float percent) 238 { 239 // TODO: would be nice to set the volume on the system mixer input of 240 // our audio node... 241 } 242 243 // SetPeakListener 244 void 245 NodeManager::SetPeakListener(BHandler* handler) 246 { 247 fPeakListener = handler; 248 if (fAudioProducer) 249 fAudioProducer->SetPeakListener(fPeakListener); 250 } 251 252 // #pragma mark - 253 254 // _SetUpNodes 255 status_t 256 NodeManager::_SetUpNodes(color_space preferredVideoFormat, uint32 enabledNodes, 257 bool useOverlays, float audioFrameRate, uint32 audioChannels) 258 { 259 TRACE("NodeManager::_SetUpNodes()\n"); 260 261 // find the media roster 262 fStatus = B_OK; 263 fMediaRoster = BMediaRoster::Roster(&fStatus); 264 if (fStatus != B_OK) { 265 print_error("Can't find the media roster", fStatus); 266 fMediaRoster = NULL; 267 return fStatus; 268 } 269 if (!fMediaRoster->Lock()) 270 return B_ERROR; 271 272 // find the time source 273 fStatus = fMediaRoster->GetTimeSource(&fTimeSource); 274 if (fStatus != B_OK) { 275 print_error("Can't get a time source", fStatus); 276 fMediaRoster->Unlock(); 277 return fStatus; 278 } 279 280 // setup the video nodes 281 if (enabledNodes != AUDIO_ONLY) { 282 fStatus = _SetUpVideoNodes(preferredVideoFormat, useOverlays); 283 if (fStatus != B_OK) { 284 print_error("Error setting up video nodes", fStatus); 285 fMediaRoster->Unlock(); 286 return fStatus; 287 } 288 } else 289 printf("running without video node\n"); 290 291 // setup the audio nodes 292 if (enabledNodes != VIDEO_ONLY) { 293 fStatus = _SetUpAudioNodes(audioFrameRate, audioChannels); 294 if (fStatus != B_OK) { 295 print_error("Error setting up audio nodes", fStatus); 296 fMediaRoster->Unlock(); 297 return fStatus; 298 } 299 fNoAudio = false; 300 } else { 301 fNoAudio = true; 302 printf("running without audio node\n"); 303 } 304 305 // we're done mocking with the media roster 306 fMediaRoster->Unlock(); 307 308 return fStatus; 309 } 310 311 312 // _SetUpVideoNodes 313 status_t 314 NodeManager::_SetUpVideoNodes(color_space preferredVideoFormat, 315 bool useOverlays) 316 { 317 // create the video producer node 318 fVideoProducer = new VideoProducer(NULL, "MediaPlayer video out", 0, 319 this, fVideoSupplier); 320 321 // register the producer node 322 fStatus = fMediaRoster->RegisterNode(fVideoProducer); 323 if (fStatus != B_OK) { 324 print_error("Can't register the video producer", fStatus); 325 return fStatus; 326 } 327 328 // make sure the Media Roster knows that we're using the node 329 // fMediaRoster->GetNodeFor(fVideoProducer->Node().node, 330 // &fVideoConnection.producer); 331 fVideoConnection.producer = fVideoProducer->Node(); 332 333 // create the video consumer node 334 fVideoConsumer = new VideoConsumer("MediaPlayer video in", NULL, 0, this, 335 fVideoTarget); 336 337 // register the consumer node 338 fStatus = fMediaRoster->RegisterNode(fVideoConsumer); 339 if (fStatus != B_OK) { 340 print_error("Can't register the video consumer", fStatus); 341 return fStatus; 342 } 343 344 // make sure the Media Roster knows that we're using the node 345 // fMediaRoster->GetNodeFor(fVideoConsumer->Node().node, 346 // &fVideoConnection.consumer); 347 fVideoConnection.consumer = fVideoConsumer->Node(); 348 349 // find free producer output 350 media_input videoInput; 351 media_output videoOutput; 352 int32 count = 1; 353 fStatus = fMediaRoster->GetFreeOutputsFor(fVideoConnection.producer, 354 &videoOutput, 1, &count, B_MEDIA_RAW_VIDEO); 355 if (fStatus != B_OK || count < 1) { 356 fStatus = B_RESOURCE_UNAVAILABLE; 357 print_error("Can't find an available video stream", fStatus); 358 return fStatus; 359 } 360 361 // find free consumer input 362 count = 1; 363 fStatus = fMediaRoster->GetFreeInputsFor(fVideoConnection.consumer, 364 &videoInput, 1, &count, B_MEDIA_RAW_VIDEO); 365 if (fStatus != B_OK || count < 1) { 366 fStatus = B_RESOURCE_UNAVAILABLE; 367 print_error("Can't find an available connection to the video window", 368 fStatus); 369 return fStatus; 370 } 371 372 // connect the nodes 373 media_format format; 374 format.type = B_MEDIA_RAW_VIDEO; 375 media_raw_video_format videoFormat = { 376 FramesPerSecond(), 1, 0, 377 fVideoBounds.IntegerWidth(), 378 B_VIDEO_TOP_LEFT_RIGHT, 1, 1, 379 { 380 preferredVideoFormat, 381 fVideoBounds.IntegerWidth() + 1, 382 fVideoBounds.IntegerHeight() + 1, 383 0, 0, 0 384 } 385 }; 386 format.u.raw_video = videoFormat; 387 388 // connect video producer to consumer (hopefully using overlays) 389 fVideoConsumer->SetTryOverlay(useOverlays); 390 fStatus = fMediaRoster->Connect(videoOutput.source, videoInput.destination, 391 &format, &videoOutput, &videoInput); 392 393 if (fStatus != B_OK) { 394 print_error("Can't connect the video source to the video window... " 395 "trying without overlays", fStatus); 396 397 uint32 flags = 0; 398 bool supported = bitmaps_support_space( 399 format.u.raw_video.display.format, &flags); 400 if (!supported || (flags & B_VIEWS_SUPPORT_DRAW_BITMAP) == 0) { 401 // cannot create bitmaps with such a color space 402 // or BViews don't support drawing it, fallback to B_RGB32 403 format.u.raw_video.display.format = B_RGB32; 404 printf("NodeManager::_SetupVideoNodes() - falling back to " 405 "B_RGB32\n"); 406 } 407 408 fVideoConsumer->SetTryOverlay(false); 409 // connect video producer to consumer (not using overlays and using 410 // a colorspace that BViews support drawing) 411 fStatus = fMediaRoster->Connect(videoOutput.source, 412 videoInput.destination, &format, &videoOutput, &videoInput); 413 } 414 // bail if second attempt failed too 415 if (fStatus != B_OK) { 416 print_error("Can't connect the video source to the video window", 417 fStatus); 418 return fStatus; 419 } 420 421 // the inputs and outputs might have been reassigned during the 422 // nodes' negotiation of the Connect(). That's why we wait until 423 // after Connect() finishes to save their contents. 424 fVideoConnection.format = format; 425 fVideoConnection.source = videoOutput.source; 426 fVideoConnection.destination = videoInput.destination; 427 fVideoConnection.connected = true; 428 429 // set time sources 430 fStatus = fMediaRoster->SetTimeSourceFor(fVideoConnection.producer.node, 431 fTimeSource.node); 432 if (fStatus != B_OK) { 433 print_error("Can't set the timesource for the video source", fStatus); 434 return fStatus; 435 } 436 437 fStatus = fMediaRoster->SetTimeSourceFor(fVideoConsumer->ID(), 438 fTimeSource.node); 439 if (fStatus != B_OK) { 440 print_error("Can't set the timesource for the video window", fStatus); 441 return fStatus; 442 } 443 444 return fStatus; 445 } 446 447 // _SetUpAudioNodes 448 status_t 449 NodeManager::_SetUpAudioNodes(float audioFrameRate, uint32 audioChannels) 450 { 451 fAudioProducer = new AudioProducer("MediaPlayer audio out", fAudioSupplier); 452 fAudioProducer->SetPeakListener(fPeakListener); 453 fStatus = fMediaRoster->RegisterNode(fAudioProducer); 454 if (fStatus != B_OK) { 455 print_error("unable to register audio producer node!\n", fStatus); 456 return fStatus; 457 } 458 // make sure the Media Roster knows that we're using the node 459 // fMediaRoster->GetNodeFor(fAudioProducer->Node().node, 460 // &fAudioConnection.producer); 461 fAudioConnection.producer = fAudioProducer->Node(); 462 463 // connect to the mixer 464 fStatus = fMediaRoster->GetAudioMixer(&fAudioConnection.consumer); 465 if (fStatus != B_OK) { 466 print_error("unable to get the system mixer", fStatus); 467 return fStatus; 468 } 469 470 fMediaRoster->SetTimeSourceFor(fAudioConnection.producer.node, 471 fTimeSource.node); 472 473 // got the nodes; now we find the endpoints of the connection 474 media_input mixerInput; 475 media_output soundOutput; 476 int32 count = 1; 477 fStatus = fMediaRoster->GetFreeOutputsFor(fAudioConnection.producer, 478 &soundOutput, 1, &count); 479 if (fStatus != B_OK) { 480 print_error("unable to get a free output from the producer node", 481 fStatus); 482 return fStatus; 483 } 484 count = 1; 485 fStatus = fMediaRoster->GetFreeInputsFor(fAudioConnection.consumer, 486 &mixerInput, 1, &count); 487 if (fStatus != B_OK) { 488 print_error("unable to get a free input to the mixer", fStatus); 489 return fStatus; 490 } 491 492 // got the endpoints; now we connect it! 493 media_format audioFormat; 494 audioFormat.type = B_MEDIA_RAW_AUDIO; 495 audioFormat.u.raw_audio = media_raw_audio_format::wildcard; 496 audioFormat.u.raw_audio.frame_rate = audioFrameRate; 497 audioFormat.u.raw_audio.channel_count = audioChannels; 498 fStatus = fMediaRoster->Connect(soundOutput.source, mixerInput.destination, 499 &audioFormat, &soundOutput, &mixerInput); 500 if (fStatus != B_OK) { 501 print_error("unable to connect audio nodes", fStatus); 502 return fStatus; 503 } 504 505 // the inputs and outputs might have been reassigned during the 506 // nodes' negotiation of the Connect(). That's why we wait until 507 // after Connect() finishes to save their contents. 508 fAudioConnection.format = audioFormat; 509 fAudioConnection.source = soundOutput.source; 510 fAudioConnection.destination = mixerInput.destination; 511 fAudioConnection.connected = true; 512 513 // Set an appropriate run mode for the producer 514 fMediaRoster->SetRunModeNode(fAudioConnection.producer, 515 BMediaNode::B_INCREASE_LATENCY); 516 517 return fStatus; 518 } 519 520 // _TearDownNodes 521 status_t 522 NodeManager::_TearDownNodes(bool disconnect) 523 { 524 TRACE("NodeManager::_TearDownNodes()\n"); 525 status_t err = B_OK; 526 fMediaRoster = BMediaRoster::Roster(&err); 527 if (err != B_OK) { 528 fprintf(stderr, "NodeManager::_TearDownNodes() - error getting media " 529 "roster: %s\n", strerror(err)); 530 fMediaRoster = NULL; 531 } 532 // begin mucking with the media roster 533 bool mediaRosterLocked = false; 534 if (fMediaRoster && fMediaRoster->Lock()) 535 mediaRosterLocked = true; 536 537 if (fVideoConsumer && fVideoProducer && fVideoConnection.connected) { 538 // disconnect 539 if (fMediaRoster) { 540 TRACE(" disconnecting video...\n"); 541 err = fMediaRoster->Disconnect(fVideoConnection.producer.node, 542 fVideoConnection.source, fVideoConnection.consumer.node, 543 fVideoConnection.destination); 544 if (err < B_OK) 545 print_error("unable to disconnect video nodes", err); 546 } else { 547 fprintf(stderr, "NodeManager::_TearDownNodes() - cannot " 548 "disconnect video nodes, no media server!\n"); 549 } 550 fVideoConnection.connected = false; 551 } 552 if (fVideoProducer) { 553 TRACE(" releasing video producer...\n"); 554 fVideoProducer->Release(); 555 fVideoProducer = NULL; 556 } 557 if (fVideoConsumer) { 558 TRACE(" releasing video consumer...\n"); 559 fVideoConsumer->Release(); 560 fVideoConsumer = NULL; 561 } 562 if (fAudioProducer) { 563 disconnect = fAudioConnection.connected; 564 // Ordinarily we'd stop *all* of the nodes in the chain at this point. 565 // However, one of the nodes is the System Mixer, and stopping the 566 // Mixer is a Bad Idea (tm). So, we just disconnect from it, and 567 // release our references to the nodes that we're using. We *are* 568 // supposed to do that even for global nodes like the Mixer. 569 if (fMediaRoster && disconnect) { 570 TRACE(" disconnecting audio...\n"); 571 err = fMediaRoster->Disconnect(fAudioConnection.producer.node, 572 fAudioConnection.source, fAudioConnection.consumer.node, 573 fAudioConnection.destination); 574 if (err < B_OK) { 575 print_error("unable to disconnect audio nodes", err); 576 disconnect = false; 577 } 578 } else { 579 fprintf(stderr, "NodeManager::_TearDownNodes() - cannot " 580 "disconnect audio nodes, no media server!\n"); 581 } 582 583 TRACE(" releasing audio producer...\n"); 584 fAudioProducer->Release(); 585 fAudioProducer = NULL; 586 fAudioConnection.connected = false; 587 588 if (fMediaRoster && disconnect) { 589 TRACE(" releasing audio consumer...\n"); 590 fMediaRoster->ReleaseNode(fAudioConnection.consumer); 591 } else { 592 fprintf(stderr, "NodeManager::_TearDownNodes() - cannot release " 593 "audio consumer (system mixer)!\n"); 594 } 595 } 596 // we're done mucking with the media roster 597 if (mediaRosterLocked && fMediaRoster) 598 fMediaRoster->Unlock(); 599 TRACE("NodeManager::_TearDownNodes() done\n"); 600 return err; 601 } 602 603 // _StartNodes 604 status_t 605 NodeManager::_StartNodes() 606 { 607 status_t status = B_NO_INIT; 608 if (!fMediaRoster) 609 return status; 610 // begin mucking with the media roster 611 if (!fMediaRoster->Lock()) 612 return B_ERROR; 613 614 bigtime_t latency = 0; 615 bigtime_t initLatency = 0; 616 if (fVideoProducer && fVideoConsumer) { 617 // figure out what recording delay to use 618 status = fMediaRoster->GetLatencyFor(fVideoConnection.producer, 619 &latency); 620 if (status < B_OK) { 621 print_error("error getting latency for video producer", 622 status); 623 } else 624 TRACE("video latency: %Ld\n", latency); 625 status = fMediaRoster->SetProducerRunModeDelay( 626 fVideoConnection.producer, latency); 627 if (status < B_OK) { 628 print_error("error settings run mode delay for video producer", 629 status); 630 } 631 632 // start the nodes 633 status = fMediaRoster->GetInitialLatencyFor( 634 fVideoConnection.producer, &initLatency); 635 if (status < B_OK) { 636 print_error("error getting initial latency for video producer", 637 status); 638 } 639 } 640 initLatency += estimate_max_scheduling_latency(); 641 642 if (fAudioProducer) { 643 // TODO: was this supposed to be added to initLatency?!? 644 bigtime_t audioLatency = 0; 645 status = fMediaRoster->GetLatencyFor(fAudioConnection.producer, 646 &audioLatency); 647 TRACE("audio latency: %Ld\n", audioLatency); 648 } 649 650 BTimeSource* timeSource; 651 if (fVideoProducer) { 652 timeSource = fMediaRoster->MakeTimeSourceFor( 653 fVideoConnection.producer); 654 } else { 655 timeSource = fMediaRoster->MakeTimeSourceFor( 656 fAudioConnection.producer); 657 } 658 bool running = timeSource->IsRunning(); 659 660 // workaround for people without sound cards 661 // because the system time source won't be running 662 bigtime_t real = BTimeSource::RealTime(); 663 if (!running) { 664 status = fMediaRoster->StartTimeSource(fTimeSource, real); 665 if (status != B_OK) { 666 timeSource->Release(); 667 print_error("cannot start time source!", status); 668 return status; 669 } 670 status = fMediaRoster->SeekTimeSource(fTimeSource, 0, real); 671 if (status != B_OK) { 672 timeSource->Release(); 673 print_error("cannot seek time source!", status); 674 return status; 675 } 676 } 677 678 bigtime_t perf = timeSource->PerformanceTimeFor(real + latency 679 + initLatency); 680 printf("performance time for %lld: %lld\n", real + latency 681 + initLatency, perf); 682 683 timeSource->Release(); 684 685 // start the nodes 686 if (fVideoProducer && fVideoConsumer) { 687 status = fMediaRoster->StartNode(fVideoConnection.consumer, perf); 688 if (status != B_OK) { 689 print_error("Can't start the video consumer", status); 690 return status; 691 } 692 status = fMediaRoster->StartNode(fVideoConnection.producer, perf); 693 if (status != B_OK) { 694 print_error("Can't start the video producer", status); 695 return status; 696 } 697 } 698 699 if (fAudioProducer) { 700 status = fMediaRoster->StartNode(fAudioConnection.producer, perf); 701 if (status != B_OK) { 702 print_error("Can't start the audio producer", status); 703 return status; 704 } 705 } 706 707 fPerformanceTimeBase = perf; 708 709 // done mucking with the media roster 710 fMediaRoster->Unlock(); 711 712 return status; 713 } 714 715 // _StopNodes 716 void 717 NodeManager::_StopNodes() 718 { 719 TRACE("NodeManager::_StopNodes()\n"); 720 fMediaRoster = BMediaRoster::Roster(); 721 if (fMediaRoster != NULL && fMediaRoster->Lock()) { 722 // begin mucking with the media roster 723 if (fVideoProducer != NULL) { 724 TRACE(" stopping video producer...\n"); 725 fMediaRoster->StopNode(fVideoConnection.producer, 0, true); 726 } 727 if (fAudioProducer != NULL) { 728 TRACE(" stopping audio producer...\n"); 729 fMediaRoster->StopNode(fAudioConnection.producer, 0, true); 730 // synchronous stop 731 } 732 if (fVideoConsumer != NULL) { 733 TRACE(" stopping video consumer...\n"); 734 fMediaRoster->StopNode(fVideoConnection.consumer, 0, true); 735 } 736 TRACE(" all nodes stopped\n"); 737 // done mucking with the media roster 738 fMediaRoster->Unlock(); 739 } 740 TRACE("NodeManager::_StopNodes() done\n"); 741 } 742 743