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