xref: /haiku/src/kits/media/MediaNode.cpp (revision d7e489f80a82a0dc5974df1e780d7a908129bab4)
1 /***********************************************************************
2  * AUTHOR: Marcus Overhagen
3  *   FILE: MediaNode.cpp
4  *  DESCR:
5  ***********************************************************************/
6 #include <MediaRoster.h>
7 #include <MediaNode.h>
8 #include <TimeSource.h>
9 #include <BufferConsumer.h>
10 #include <BufferProducer.h>
11 #include <Controllable.h>
12 #include <FileInterface.h>
13 #include <string.h>
14 #define DEBUG 3
15 #include <Debug.h>
16 #include "debug.h"
17 #include "DataExchange.h"
18 #include "SystemTimeSource.h"
19 #include "ServerInterface.h"
20 #include "Notifications.h"
21 
22 // don't rename this one, it's used and exported for binary compatibility
23 int32 BMediaNode::_m_changeTag = 0;
24 
25 /*************************************************************
26  * media_node
27  *************************************************************/
28 
29 // final & verified
30 media_node::media_node()
31 	: node(-1),
32 	port(-1),
33 	kind(0)
34 {
35 }
36 
37 // final & verified
38 media_node::~media_node()
39 {
40 }
41 
42 /*************************************************************
43  * static media_node variables
44  *************************************************************/
45 
46 // final & verified
47 media_node media_node::null;
48 
49 /*************************************************************
50  * media_input
51  *************************************************************/
52 
53 // final
54 media_input::media_input()
55 {
56 	name[0] = '\0';
57 }
58 
59 // final
60 media_input::~media_input()
61 {
62 }
63 
64 /*************************************************************
65  * media_output
66  *************************************************************/
67 
68 // final
69 media_output::media_output()
70 {
71 	name[0] = '\0';
72 }
73 
74 // final
75 media_output::~media_output()
76 {
77 }
78 
79 /*************************************************************
80  * live_node_info
81  *************************************************************/
82 
83 // final & verified
84 live_node_info::live_node_info()
85 	: hint_point(0.0f,0.0f)
86 {
87 	name[0] = '\0';
88 }
89 
90 // final & verified
91 live_node_info::~live_node_info()
92 {
93 }
94 
95 /*************************************************************
96  * protected BMediaNode
97  *************************************************************/
98 
99 /* virtual */
100 BMediaNode::~BMediaNode()
101 {
102 	CALLED();
103 
104 	// BeBook: UnregisterNode() unregisters a node from the Media Server. It's called automatically
105 	// BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before
106 	// BeBook: you delete your node instance, depending on your implementation and circumstances.
107 	(BMediaRoster::Roster())->UnregisterNode(this);
108 
109 	if (fControlPort != -1)
110 		delete_port(fControlPort);
111 	if (fTimeSource)
112 		fTimeSource->Release();
113 }
114 
115 /*************************************************************
116  * public BMediaNode
117  *************************************************************/
118 
119 BMediaNode *
120 BMediaNode::Acquire()
121 {
122 	CALLED();
123 	atomic_add(&fRefCount,1);
124 	return this;
125 }
126 
127 
128 BMediaNode *
129 BMediaNode::Release()
130 {
131 	CALLED();
132 	if (atomic_add(&fRefCount,-1) == 1) {
133 		if (DeleteHook(this) != B_OK) {
134 			TRACE("BMediaNode::Release(): DeleteHook failed\n");
135 			return Acquire();
136 		}
137 		return NULL;
138 	}
139 	return this;
140 }
141 
142 
143 const char *
144 BMediaNode::Name() const
145 {
146 	CALLED();
147 	return fName;
148 }
149 
150 
151 media_node_id
152 BMediaNode::ID() const
153 {
154 	CALLED();
155 	return fNodeID;
156 }
157 
158 
159 uint64
160 BMediaNode::Kinds() const
161 {
162 	CALLED();
163 	return fKinds;
164 }
165 
166 
167 media_node
168 BMediaNode::Node() const
169 {
170 	CALLED();
171 	media_node temp;
172 	temp.node = ID();
173 	temp.port = ControlPort();
174 	temp.kind = Kinds();
175 	return temp;
176 }
177 
178 
179 BMediaNode::run_mode
180 BMediaNode::RunMode() const
181 {
182 	CALLED();
183 	return fRunMode;
184 }
185 
186 
187 BTimeSource *
188 BMediaNode::TimeSource() const
189 {
190 	CALLED();
191 	if (fTimeSource == 0)
192 		const_cast<BMediaNode *>(this)->fTimeSource = new _SysTimeSource;
193 	return fTimeSource;
194 }
195 
196 
197 /* virtual */ port_id
198 BMediaNode::ControlPort() const
199 {
200 	CALLED();
201 	return fControlPort;
202 }
203 
204 
205 /*************************************************************
206  * protected BMediaNode
207  *************************************************************/
208 
209 status_t
210 BMediaNode::ReportError(node_error what,
211 						const BMessage *info)
212 {
213 	CALLED();
214 
215 	// sanity check the what value
216 	switch (what) {
217 		case BMediaNode::B_NODE_FAILED_START:
218 		case BMediaNode::B_NODE_FAILED_STOP:
219 		case BMediaNode::B_NODE_FAILED_SEEK:
220 		case BMediaNode::B_NODE_FAILED_SET_RUN_MODE:
221 		case BMediaNode::B_NODE_FAILED_TIME_WARP:
222 		case BMediaNode::B_NODE_FAILED_PREROLL:
223 		case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR:
224 		case BMediaNode::B_NODE_IN_DISTRESS:
225 			break;
226 		default:
227 			TRACE("BMediaNode::ReportError: invalid what!\n");
228 			return B_BAD_VALUE;
229 	}
230 
231 	// Transmits the error code specified by what to anyone
232 	// that's receiving notifications from this node
233 	return BPrivate::media::notifications::ReportError(Node(), what, info);
234 }
235 
236 
237 status_t
238 BMediaNode::NodeStopped(bigtime_t whenPerformance)
239 {
240 	UNIMPLEMENTED();
241 	// called by derived classes when they have
242 	// finished handling a stop request.
243 
244 	// notify anyone who is listening for stop notifications!
245 	BPrivate::media::notifications::NodeStopped(Node(), whenPerformance);
246 
247 	// XXX If your node is a BBufferProducer, downstream consumers
248 	// XXX will be notified that your node stopped (automatically, no less)
249 	// XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call.
250 
251 	return B_OK;
252 }
253 
254 
255 void
256 BMediaNode::TimerExpired(bigtime_t notifyPoint,
257 						 int32 cookie,
258 						 status_t error)
259 {
260 	UNIMPLEMENTED();
261 	// Used with AddTimer
262 	// This will, in turn, cause the BMediaRoster::SyncToNode() call
263 	// that instigated the timer to return to the caller.
264 	// Probably only important to classes derived from BTimeSource.
265 }
266 
267 
268 /* explicit */
269 BMediaNode::BMediaNode(const char *name)
270 {
271 	TRACE("BMediaNode::BMediaNode: name '%s'\n", name);
272 	_InitObject(name, -1, 0);
273 }
274 
275 
276 status_t
277 BMediaNode::WaitForMessage(bigtime_t waitUntil,
278 						   uint32 flags,
279 						   void *_reserved_)
280 {
281 	CALLED();
282 	ASSERT(this != 0);
283 	// This function waits until either real time specified by
284 	// waitUntil or a message is received on the control port.
285 	// The flags are currently unused and should be 0.
286 
287 	char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used
288 	int32 message;
289 	ssize_t size;
290 
291 	size = read_port_etc(fControlPort, &message, data, sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil);
292 	if (size <= 0) {
293 		if (size != B_TIMED_OUT)
294 			TRACE("BMediaNode::WaitForMessage: read_port_etc error 0x%08lx\n",size);
295 		return size; // returns the error code
296 	}
297 
298 	TRACE("BMediaNode::WaitForMessage %#lx, node %ld, this %p\n", message, fNodeID, this);
299 
300 	if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
301 		TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
302 		if (B_OK == BMediaNode::HandleMessage(message, data, size))
303 			return B_OK;
304 	}
305 
306 	if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) {
307 		if (!fProducerThis)
308 			fProducerThis = dynamic_cast<BBufferProducer *>(this);
309 		TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", fProducerThis);
310 		if (fProducerThis && B_OK == fProducerThis->BBufferProducer::HandleMessage(message, data, size))
311 			return B_OK;
312 	}
313 
314 	if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) {
315 		if (!fConsumerThis)
316 			fConsumerThis = dynamic_cast<BBufferConsumer *>(this);
317 		TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", fConsumerThis);
318 		if (fConsumerThis && B_OK == fConsumerThis->BBufferConsumer::HandleMessage(message, data, size))
319 			return B_OK;
320 	}
321 
322 	if (message > FILEINTERFACE_MESSAGE_START && message < FILEINTERFACE_MESSAGE_END) {
323 		if (!fFileInterfaceThis)
324 			fFileInterfaceThis = dynamic_cast<BFileInterface *>(this);
325 		TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", fFileInterfaceThis);
326 		if (fFileInterfaceThis && B_OK == fFileInterfaceThis->BFileInterface::HandleMessage(message, data, size))
327 			return B_OK;
328 	}
329 
330 	if (fControllableThis && message > CONTROLLABLE_MESSAGE_START && message < CONTROLLABLE_MESSAGE_END) {
331 		if (!fControllableThis)
332 			fControllableThis = dynamic_cast<BControllable *>(this);
333 		TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", fControllableThis);
334 		if (fControllableThis && B_OK == fControllableThis->BControllable::HandleMessage(message, data, size))
335 			return B_OK;
336 	}
337 
338 	if (fTimeSourceThis && message > TIMESOURECE_MESSAGE_START && message < TIMESOURECE_MESSAGE_END) {
339 		if (!fTimeSourceThis)
340 			fTimeSourceThis = dynamic_cast<BTimeSource *>(this);
341 		TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", fTimeSourceThis);
342 		if (fTimeSourceThis && B_OK == fTimeSourceThis->BTimeSource::HandleMessage(message, data, size))
343 			return B_OK;
344 	}
345 
346 	TRACE("BMediaNode::WaitForMessage calling default\n");
347 	if (B_OK == HandleMessage(message, data, size))
348 		return B_OK;
349 
350 	HandleBadMessage(message, data, size);
351 
352 	return B_ERROR;
353 }
354 
355 
356 /* virtual */ void
357 BMediaNode::Start(bigtime_t performance_time)
358 {
359 	CALLED();
360 	// This hook function is called when a node is started
361 	// by a call to the BMediaRoster. The specified
362 	// performanceTime, the time at which the node
363 	// should start running, may be in the future.
364 	// It may be overriden by derived classes.
365 	// The BMediaEventLooper class handles this event!
366 	// The BMediaNode class does nothing here.
367 }
368 
369 
370 /* virtual */ void
371 BMediaNode::Stop(bigtime_t performance_time,
372 				 bool immediate)
373 {
374 	CALLED();
375 	// This hook function is called when a node is stopped
376 	// by a call to the BMediaRoster. The specified
377 	// performanceTime, the time at which the node
378 	// should stop running, may be in the future.
379 	// It may be overriden by derived classes.
380 	// The BMediaEventLooper class handles this event!
381 	// The BMediaNode class does nothing here.
382 }
383 
384 
385 /* virtual */ void
386 BMediaNode::Seek(bigtime_t media_time,
387 				 bigtime_t performance_time)
388 {
389 	CALLED();
390 	// This hook function is called when a node is asked
391 	// to seek to the specified mediaTime by a call to
392 	// the BMediaRoster. The specified performanceTime,
393 	// the time at which the node should begin the seek
394 	// operation, may be in the future.
395 	// It may be overriden by derived classes.
396 	// The BMediaEventLooper class handles this event!
397 	// The BMediaNode class does nothing here.
398 }
399 
400 
401 /* virtual */ void
402 BMediaNode::SetRunMode(run_mode mode)
403 {
404 	CALLED();
405 
406 	// this is a hook function, and
407 	// may be overriden by derived classes.
408 
409 	// the functionality here is only to
410 	// support those people that don't
411 	// use the roster to set the run mode
412 	fRunMode = mode;
413 }
414 
415 
416 /* virtual */ void
417 BMediaNode::TimeWarp(bigtime_t at_real_time,
418 					 bigtime_t to_performance_time)
419 {
420 	CALLED();
421 	// May be overriden by derived classes.
422 }
423 
424 
425 /* virtual */ void
426 BMediaNode::Preroll()
427 {
428 	CALLED();
429 	// May be overriden by derived classes.
430 }
431 
432 
433 /* virtual */ void
434 BMediaNode::SetTimeSource(BTimeSource *time_source)
435 {
436 	CALLED();
437 	return;// XXX
438 
439 	// this is a hook function, and
440 	// may be overriden by derived classes.
441 
442 	// the functionality here is only to
443 	// support those people that don't
444 	// use the roster to set a time source
445 	if (time_source == fTimeSource)
446 		return;
447 	if (time_source == NULL)
448 		return;
449 	if (fTimeSource)
450 		fTimeSource->Release();
451 	fTimeSource = dynamic_cast<BTimeSource *>(time_source->Acquire());
452 	fTimeSourceID = fTimeSource->ID();
453 }
454 
455 /*************************************************************
456  * public BMediaNode
457  *************************************************************/
458 
459 /* virtual */ status_t
460 BMediaNode::HandleMessage(int32 message,
461 						  const void *data,
462 						  size_t size)
463 {
464 //	CALLED();
465 	TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID);
466 	switch (message) {
467 		case NODE_START:
468 		{
469 			const xfer_node_start *request = (const xfer_node_start *)data;
470 			Start(request->performance_time);
471 			return B_OK;
472 		}
473 
474 		case NODE_STOP:
475 		{
476 			const xfer_node_stop *request = (const xfer_node_stop *)data;
477 			Stop(request->performance_time, request->immediate);
478 			return B_OK;
479 		}
480 
481 		case NODE_SEEK:
482 		{
483 			const xfer_node_seek *request = (const xfer_node_seek *)data;
484 			Seek(request->media_time, request->performance_time);
485 			return B_OK;
486 		}
487 
488 		case NODE_SET_RUN_MODE:
489 		{
490 			const xfer_node_set_run_mode *request = (const xfer_node_set_run_mode *)data;
491 			fRunMode = request->mode;
492 			SetRunMode(fRunMode);
493 			return B_OK;
494 		}
495 
496 		case NODE_TIME_WARP:
497 		{
498 			const xfer_node_time_warp *request = (const xfer_node_time_warp *)data;
499 			TimeWarp(request->at_real_time,request->to_performance_time);
500 			return B_OK;
501 		}
502 
503 		case NODE_PREROLL:
504 		{
505 			Preroll();
506 			return B_OK;
507 		}
508 
509 		case NODE_SET_TIMESOURCE:
510 		{
511 			const xfer_node_set_timesource *request = (const xfer_node_set_timesource *)data;
512 			bool first = (fTimeSourceID == 0);
513 			if (fTimeSource)
514 				fTimeSource->Release();
515 			fTimeSourceID = request->timesource_id;
516 			fTimeSource = 0; // XXX create timesource object here
517 			fTimeSource = new _SysTimeSource;
518 			if (!first)
519 				SetTimeSource(fTimeSource);
520 			return B_OK;
521 		}
522 
523 		case NODE_REQUEST_COMPLETED:
524 		{
525 			const xfer_node_request_completed *request = (const xfer_node_request_completed *)data;
526 			RequestCompleted(request->info);
527 			return B_OK;
528 		}
529 
530 	};
531 	return B_ERROR;
532 }
533 
534 
535 void
536 BMediaNode::HandleBadMessage(int32 code,
537 							 const void *buffer,
538 							 size_t size)
539 {
540 	CALLED();
541 
542 	TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size);
543 	if (code < NODE_MESSAGE_START || code > TIMESOURECE_MESSAGE_END) {
544 		TRACE("BMediaNode::HandleBadMessage: unknown code!\n");
545 	} else {
546 		/* All messages targeted to nodes should be handled here,
547 		 * messages targetted to the wrong node should be handled
548 		 * by returning an error, not by stalling the sender.
549 		 */
550 		const request_data *request = static_cast<const request_data *>(buffer);
551 		reply_data reply;
552 		request->SendReply(B_ERROR, &reply, sizeof(reply));
553 	}
554 }
555 
556 
557 void
558 BMediaNode::AddNodeKind(uint64 kind)
559 {
560 	TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this);
561 
562 	fKinds |= kind;
563 }
564 
565 
566 void *
567 BMediaNode::operator new(size_t size)
568 {
569 	CALLED();
570 	return ::operator new(size);
571 }
572 
573 void *
574 BMediaNode::operator new(size_t size,
575 						 const nothrow_t &) throw()
576 {
577 	CALLED();
578 	return ::operator new(size, nothrow);
579 }
580 
581 void
582 BMediaNode::operator delete(void *ptr)
583 {
584 	CALLED();
585 	::operator delete(ptr);
586 }
587 
588 void
589 BMediaNode::operator delete(void * ptr,
590 							const nothrow_t &) throw()
591 {
592 	CALLED();
593 	::operator delete(ptr, nothrow);
594 }
595 
596 /*************************************************************
597  * protected BMediaNode
598  *************************************************************/
599 
600 /* virtual */ status_t
601 BMediaNode::RequestCompleted(const media_request_info &info)
602 {
603 	CALLED();
604 	// This function is called whenever a request issued by the node is completed.
605 	// May be overriden by derived classes.
606 	// info.change_tag can be used to match up requests against
607 	// the accompaning calles from
608 	// BBufferConsumer::RequestFormatChange()
609 	// BBufferConsumer::SetOutputBuffersFor()
610 	// BBufferConsumer::SetOutputEnabled()
611 	// BBufferConsumer::SetVideoClippingFor()
612 	return B_OK;
613 }
614 
615 /*************************************************************
616  * private BMediaNode
617  *************************************************************/
618 
619 int32
620 BMediaNode::IncrementChangeTag()
621 {
622 	CALLED();
623 	// Only present in BeOS R4
624 	// Obsoleted in BeOS R4.5 and later
625 	// "updates the change tag, so that downstream consumers know that the node is in a new state."
626 	// not supported, only for binary compatibility
627 	return 0;
628 }
629 
630 
631 int32
632 BMediaNode::ChangeTag()
633 {
634 	UNIMPLEMENTED();
635 	// Only present in BeOS R4
636 	// Obsoleted in BeOS R4.5 and later
637 	// "returns the node's current change tag value."
638 	// not supported, only for binary compatibility
639 	return 0;
640 }
641 
642 
643 int32
644 BMediaNode::MintChangeTag()
645 {
646 	UNIMPLEMENTED();
647 	// Only present in BeOS R4
648 	// Obsoleted in BeOS R4.5 and later
649 	// "mints a new, reserved, change tag."
650 	// "Call ApplyChangeTag() to apply it to the node"
651 	// not supported, only for binary compatibility
652 	return 0;
653 }
654 
655 
656 status_t
657 BMediaNode::ApplyChangeTag(int32 previously_reserved)
658 {
659 	UNIMPLEMENTED();
660 	// Only present in BeOS R4
661 	// Obsoleted in BeOS R4.5 and later
662 	// "this returns B_OK if the new change tag is"
663 	// "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change"
664 	// "count you tried to apply is already obsolete."
665 	// not supported, only for binary compatibility
666 	return B_OK;
667 }
668 
669 /*************************************************************
670  * protected BMediaNode
671  *************************************************************/
672 
673 /* virtual */ status_t
674 BMediaNode::DeleteHook(BMediaNode *node)
675 {
676 	CALLED();
677 	delete this; // delete "this" or "node" ???
678 	return B_OK;
679 }
680 
681 
682 /* virtual */ void
683 BMediaNode::NodeRegistered()
684 {
685 	CALLED();
686 	// The Media Server calls this hook function after the node has been registered.
687 	// May be overriden by derived classes.
688 }
689 
690 /*************************************************************
691  * public BMediaNode
692  *************************************************************/
693 
694 /* virtual */ status_t
695 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes,
696 							  size_t inMaxCount)
697 {
698 	UNIMPLEMENTED();
699 
700 	return B_ERROR;
701 }
702 
703 
704 /* virtual */ status_t
705 BMediaNode::AddTimer(bigtime_t at_performance_time,
706 					 int32 cookie)
707 {
708 	UNIMPLEMENTED();
709 
710 	return B_ERROR;
711 }
712 
713 
714 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; }
715 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; }
716 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; }
717 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; }
718 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; }
719 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; }
720 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; }
721 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; }
722 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; }
723 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; }
724 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; }
725 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; }
726 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; }
727 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; }
728 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; }
729 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; }
730 
731 /*
732 private unimplemented
733 BMediaNode::BMediaNode()
734 BMediaNode::BMediaNode(const BMediaNode &clone)
735 BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
736 */
737 
738 void
739 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds)
740 {
741 	TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this);
742 
743 	fNodeID = id;
744 	fTimeSource = 0;
745 	fRefCount = 1;
746 	fName[0] = 0;
747 	if (name) {
748 		strncpy(fName, name, B_MEDIA_NAME_LENGTH - 1);
749 		fName[B_MEDIA_NAME_LENGTH - 1] = 0;
750 	}
751 	fRunMode = B_INCREASE_LATENCY;
752 	_mChangeCount = 0;			//	deprecated
753 	_mChangeCountReserved = 0;	//	deprecated
754 	fKinds = kinds;
755 	fTimeSourceID = -1;
756 	fProducerThis = 0;
757 	fConsumerThis = 0;
758 	fFileInterfaceThis = 0;
759 	fControllableThis = 0;
760 	fTimeSourceThis = 0;
761 
762 	// create control port
763 	fControlPort = create_port(64,fName);
764 }
765 
766 
767 BMediaNode::BMediaNode(const char *name,
768 					   media_node_id id,
769 					   uint32 kinds)
770 {
771 	TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds);
772 	_InitObject(name, id, kinds);
773 }
774 
775 
776 /*************************************************************
777  * protected BMediaNode
778  *************************************************************/
779 
780 /* static */ int32
781 BMediaNode::NewChangeTag()
782 {
783 	CALLED();
784 	// change tags have been used in BeOS R4 to match up
785 	// format change requests between producer and consumer,
786 	// This has changed starting with R4.5
787 	// now "change tags" are used with
788 	// BMediaNode::RequestCompleted()
789 	// and
790 	// BBufferConsumer::RequestFormatChange()
791 	// BBufferConsumer::SetOutputBuffersFor()
792 	// BBufferConsumer::SetOutputEnabled()
793 	// BBufferConsumer::SetVideoClippingFor()
794 	return atomic_add(&BMediaNode::_m_changeTag,1);
795 }
796 
797 
798