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