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