xref: /haiku/src/kits/media/MediaNode.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 /*
2  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 #include <MediaRoster.h>
31 #include <MediaNode.h>
32 #include <TimeSource.h>
33 #include <BufferConsumer.h>
34 #include <BufferProducer.h>
35 #include <Controllable.h>
36 #include <FileInterface.h>
37 #include <string.h>
38 #include "debug.h"
39 #include "MediaMisc.h"
40 #include "MediaRosterEx.h"
41 #include "DataExchange.h"
42 #include "ServerInterface.h"
43 #include "Notifications.h"
44 #include "TimeSourceObject.h"
45 #include "TimeSourceObjectManager.h"
46 
47 using std::nothrow;
48 using std::nothrow_t;
49 
50 // don't rename this one, it's used and exported for binary compatibility
51 int32 BMediaNode::_m_changeTag = 0;
52 
53 /*************************************************************
54  * media_node
55  *************************************************************/
56 
57 // final & verified
58 media_node::media_node()
59 	: node(-1),
60 	port(-1),
61 	kind(0)
62 {
63 }
64 
65 // final & verified
66 media_node::~media_node()
67 {
68 }
69 
70 /*************************************************************
71  * static media_node variables
72  *************************************************************/
73 
74 // final & verified
75 media_node media_node::null;
76 
77 /*************************************************************
78  * media_input
79  *************************************************************/
80 
81 // final
82 media_input::media_input()
83 {
84 	name[0] = '\0';
85 }
86 
87 // final
88 media_input::~media_input()
89 {
90 }
91 
92 /*************************************************************
93  * media_output
94  *************************************************************/
95 
96 // final
97 media_output::media_output()
98 {
99 	name[0] = '\0';
100 }
101 
102 // final
103 media_output::~media_output()
104 {
105 }
106 
107 /*************************************************************
108  * live_node_info
109  *************************************************************/
110 
111 // final & verified
112 live_node_info::live_node_info()
113 	: hint_point(0.0f, 0.0f)
114 {
115 	name[0] = '\0';
116 }
117 
118 // final & verified
119 live_node_info::~live_node_info()
120 {
121 }
122 
123 /*************************************************************
124  * protected BMediaNode
125  *************************************************************/
126 
127 /* virtual */
128 BMediaNode::~BMediaNode()
129 {
130 	CALLED();
131 	// BeBook: UnregisterNode() unregisters a node from the Media Server. It's called automatically
132 	// BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before
133 	// BeBook: you delete your node instance, depending on your implementation and circumstances.
134 
135 	// first we remove the time source
136 	if (fTimeSource) {
137 		fTimeSource->RemoveMe(this);
138 		fTimeSource->Release();
139 		fTimeSource = NULL;
140 	}
141 
142 	// Attention! We do not unregister TimeSourceObject nodes,
143 	// or delete their control ports, since they are only a
144 	// shadow object, and the real one still exists
145 	if (0 == (fKinds & NODE_KIND_SHADOW_TIMESOURCE)) {
146 		BMediaRoster::Roster()->UnregisterNode(this);
147 
148 		if (fControlPort > 0)
149 			delete_port(fControlPort);
150 	} else {
151 		TRACE("BMediaNode::~BMediaNode: shadow timesource, not unregistering\n");
152 	}
153 }
154 
155 /*************************************************************
156  * public BMediaNode
157  *************************************************************/
158 
159 BMediaNode *
160 BMediaNode::Acquire()
161 {
162 	CALLED();
163 	atomic_add(&fRefCount,1);
164 	return this;
165 }
166 
167 
168 BMediaNode *
169 BMediaNode::Release()
170 {
171 	CALLED();
172 	if (atomic_add(&fRefCount, -1) == 1) {
173 		TRACE("BMediaNode::Release() saving node %ld configuration\n", fNodeID);
174 		MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(this);
175 		if (DeleteHook(this) != B_OK) {
176 			ERROR("BMediaNode::Release(): DeleteHook failed\n");
177 			return Acquire();
178 		}
179 		return NULL;
180 	}
181 	return this;
182 }
183 
184 
185 const char *
186 BMediaNode::Name() const
187 {
188 	CALLED();
189 	return fName;
190 }
191 
192 
193 media_node_id
194 BMediaNode::ID() const
195 {
196 	CALLED();
197 	return fNodeID;
198 }
199 
200 
201 uint64
202 BMediaNode::Kinds() const
203 {
204 	CALLED();
205 	return fKinds & NODE_KIND_USER_MASK;
206 }
207 
208 
209 media_node
210 BMediaNode::Node() const
211 {
212 	CALLED();
213 	media_node temp;
214 	temp.node = ID();
215 	temp.port = ControlPort(); // we *must* call ControlPort(), some derived nodes use it to start the port read thread!
216 	temp.kind = Kinds();
217 	return temp;
218 }
219 
220 
221 BMediaNode::run_mode
222 BMediaNode::RunMode() const
223 {
224 	CALLED();
225 	return fRunMode;
226 }
227 
228 
229 BTimeSource *
230 BMediaNode::TimeSource() const
231 {
232 	PRINT(7, "CALLED BMediaNode::TimeSource()\n");
233 
234 	// return the currently assigned time source
235 	if (fTimeSource != 0)
236 		return fTimeSource;
237 
238 	TRACE("BMediaNode::TimeSource node %ld enter\n", ID());
239 
240 	// If the node doesn't have a time source object, we need to create one.
241 	// If the node is still unregistered, we can't call MakeTimeSourceFor(),
242 	// but since the node does still have the default system time source, we
243 	// can use GetSystemTimeSource
244 
245 	BMediaNode *self = const_cast<BMediaNode *>(this);
246 //	if (fTimeSourceID == NODE_SYSTEM_TIMESOURCE_ID) {
247 //		self->fTimeSource = _TimeSourceObjectManager->GetSystemTimeSource();
248 //	} else {
249 		self->fTimeSource = MediaRosterEx(BMediaRoster::Roster())->MakeTimeSourceObject(fTimeSourceID);
250 //	}
251 	ASSERT(fTimeSource == self->fTimeSource);
252 
253 	if (fTimeSource == 0) {
254 		ERROR("BMediaNode::TimeSource: MakeTimeSourceFor failed\n");
255 	} else {
256 		ASSERT(fTimeSourceID == fTimeSource->ID());
257 		fTimeSource->AddMe(self);
258 	}
259 
260 	TRACE("BMediaNode::TimeSource node %ld leave\n", ID());
261 
262 	return fTimeSource;
263 }
264 
265 
266 /* virtual */ port_id
267 BMediaNode::ControlPort() const
268 {
269 	PRINT(7, "CALLED BMediaNode::ControlPort()\n");
270 	return fControlPort;
271 }
272 
273 
274 /*************************************************************
275  * protected BMediaNode
276  *************************************************************/
277 
278 status_t
279 BMediaNode::ReportError(node_error what,
280 						const BMessage *info)
281 {
282 	CALLED();
283 
284 	// sanity check the what value
285 	switch (what) {
286 		case BMediaNode::B_NODE_FAILED_START:
287 		case BMediaNode::B_NODE_FAILED_STOP:
288 		case BMediaNode::B_NODE_FAILED_SEEK:
289 		case BMediaNode::B_NODE_FAILED_SET_RUN_MODE:
290 		case BMediaNode::B_NODE_FAILED_TIME_WARP:
291 		case BMediaNode::B_NODE_FAILED_PREROLL:
292 		case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR:
293 		case BMediaNode::B_NODE_IN_DISTRESS:
294 			break;
295 		default:
296 			ERROR("BMediaNode::ReportError: invalid what!\n");
297 			return B_BAD_VALUE;
298 	}
299 
300 	// Transmits the error code specified by what to anyone
301 	// that's receiving notifications from this node
302 	return BPrivate::media::notifications::ReportError(Node(), what, info);
303 }
304 
305 
306 status_t
307 BMediaNode::NodeStopped(bigtime_t whenPerformance)
308 {
309 	UNIMPLEMENTED();
310 	// called by derived classes when they have
311 	// finished handling a stop request.
312 
313 	// notify anyone who is listening for stop notifications!
314 	BPrivate::media::notifications::NodeStopped(Node(), whenPerformance);
315 
316 	// XXX If your node is a BBufferProducer, downstream consumers
317 	// XXX will be notified that your node stopped (automatically, no less)
318 	// XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call.
319 
320 	return B_OK;
321 }
322 
323 
324 void
325 BMediaNode::TimerExpired(bigtime_t notifyPoint,
326 						 int32 cookie,
327 						 status_t error)
328 {
329 	UNIMPLEMENTED();
330 	// Used with AddTimer
331 	// This will, in turn, cause the BMediaRoster::SyncToNode() call
332 	// that instigated the timer to return to the caller.
333 	// Probably only important to classes derived from BTimeSource.
334 }
335 
336 
337 /* explicit */
338 BMediaNode::BMediaNode(const char *name)
339 {
340 	TRACE("BMediaNode::BMediaNode: name '%s'\n", name);
341 	_InitObject(name, NODE_JUST_CREATED_ID, 0);
342 }
343 
344 
345 status_t
346 BMediaNode::WaitForMessage(bigtime_t waitUntil,
347 						   uint32 flags,
348 						   void *_reserved_)
349 {
350 	PRINT(6, "CALLED BMediaNode::WaitForMessage()\n");
351 
352 	// This function waits until either real time specified by
353 	// waitUntil or a message is received on the control port.
354 	// The flags are currently unused and should be 0.
355 
356 	char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used
357 	int32 message;
358 	ssize_t size;
359 
360 	size = read_port_etc(ControlPort(), &message, data, sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil);
361 	if (size <= 0) {
362 		if (size != B_TIMED_OUT)
363 			ERROR("BMediaNode::WaitForMessage: read_port_etc error 0x%08lx\n",size);
364 		return size; // returns the error code
365 	}
366 
367 	PRINT(7, "BMediaNode::WaitForMessage %#lx, node %ld, this %p\n", message, fNodeID, this);
368 
369 	if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
370 		PRINT(4, "BMediaNode::WaitForMessage calling BMediaNode\n");
371 		if (B_OK == BMediaNode::HandleMessage(message, data, size))
372 			return B_OK;
373 	}
374 
375 	if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) {
376 		if (!fProducerThis)
377 			fProducerThis = dynamic_cast<BBufferProducer *>(this);
378 		PRINT(4, "BMediaNode::WaitForMessage calling BBufferProducer %p\n", fProducerThis);
379 		if (fProducerThis && B_OK == fProducerThis->BBufferProducer::HandleMessage(message, data, size))
380 			return B_OK;
381 	}
382 
383 	if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) {
384 		if (!fConsumerThis)
385 			fConsumerThis = dynamic_cast<BBufferConsumer *>(this);
386 		PRINT(4, "BMediaNode::WaitForMessage calling BBufferConsumer %p\n", fConsumerThis);
387 		if (fConsumerThis && B_OK == fConsumerThis->BBufferConsumer::HandleMessage(message, data, size))
388 			return B_OK;
389 	}
390 
391 	if (message > FILEINTERFACE_MESSAGE_START && message < FILEINTERFACE_MESSAGE_END) {
392 		if (!fFileInterfaceThis)
393 			fFileInterfaceThis = dynamic_cast<BFileInterface *>(this);
394 		PRINT(4, "BMediaNode::WaitForMessage calling BFileInterface %p\n", fFileInterfaceThis);
395 		if (fFileInterfaceThis && B_OK == fFileInterfaceThis->BFileInterface::HandleMessage(message, data, size))
396 			return B_OK;
397 	}
398 
399 	if (message > CONTROLLABLE_MESSAGE_START && message < CONTROLLABLE_MESSAGE_END) {
400 		if (!fControllableThis)
401 			fControllableThis = dynamic_cast<BControllable *>(this);
402 		PRINT(4, "BMediaNode::WaitForMessage calling BControllable %p\n", fControllableThis);
403 		if (fControllableThis && B_OK == fControllableThis->BControllable::HandleMessage(message, data, size))
404 			return B_OK;
405 	}
406 
407 	if (message > TIMESOURCE_MESSAGE_START && message < TIMESOURCE_MESSAGE_END) {
408 		if (!fTimeSourceThis)
409 			fTimeSourceThis = dynamic_cast<BTimeSource *>(this);
410 		PRINT(4, "BMediaNode::WaitForMessage calling BTimeSource %p\n", fTimeSourceThis);
411 		if (fTimeSourceThis && B_OK == fTimeSourceThis->BTimeSource::HandleMessage(message, data, size))
412 			return B_OK;
413 	}
414 
415 	PRINT(4, "BMediaNode::WaitForMessage calling default\n");
416 	if (B_OK == HandleMessage(message, data, size))
417 		return B_OK;
418 
419 	HandleBadMessage(message, data, size);
420 
421 	return B_ERROR;
422 }
423 
424 
425 /* virtual */ void
426 BMediaNode::Start(bigtime_t performance_time)
427 {
428 	CALLED();
429 	// This hook function is called when a node is started
430 	// by a call to the BMediaRoster. The specified
431 	// performanceTime, the time at which the node
432 	// should start running, may be in the future.
433 	// It may be overriden by derived classes.
434 	// The BMediaEventLooper class handles this event!
435 	// The BMediaNode class does nothing here.
436 }
437 
438 
439 /* virtual */ void
440 BMediaNode::Stop(bigtime_t performance_time,
441 				 bool immediate)
442 {
443 	CALLED();
444 	// This hook function is called when a node is stopped
445 	// by a call to the BMediaRoster. The specified
446 	// performanceTime, the time at which the node
447 	// should stop running, may be in the future.
448 	// It may be overriden by derived classes.
449 	// The BMediaEventLooper class handles this event!
450 	// The BMediaNode class does nothing here.
451 }
452 
453 
454 /* virtual */ void
455 BMediaNode::Seek(bigtime_t media_time,
456 				 bigtime_t performance_time)
457 {
458 	CALLED();
459 	// This hook function is called when a node is asked
460 	// to seek to the specified mediaTime by a call to
461 	// the BMediaRoster. The specified performanceTime,
462 	// the time at which the node should begin the seek
463 	// operation, may be in the future.
464 	// It may be overriden by derived classes.
465 	// The BMediaEventLooper class handles this event!
466 	// The BMediaNode class does nothing here.
467 }
468 
469 
470 /* virtual */ void
471 BMediaNode::SetRunMode(run_mode mode)
472 {
473 	CALLED();
474 
475 	// this is a hook function, and
476 	// may be overriden by derived classes.
477 
478 	// the functionality here is only to
479 	// support those people that don't
480 	// use the roster to set the run mode
481 	fRunMode = mode;
482 }
483 
484 
485 /* virtual */ void
486 BMediaNode::TimeWarp(bigtime_t at_real_time,
487 					 bigtime_t to_performance_time)
488 {
489 	CALLED();
490 	// May be overriden by derived classes.
491 }
492 
493 
494 /* virtual */ void
495 BMediaNode::Preroll()
496 {
497 	CALLED();
498 	// May be overriden by derived classes.
499 }
500 
501 
502 /* virtual */ void
503 BMediaNode::SetTimeSource(BTimeSource *time_source)
504 {
505 	CALLED();
506 	// this is a hook function, and
507 	// may be overriden by derived classes.
508 
509 	if (time_source == NULL || time_source == fTimeSource)
510 		return;
511 
512 	// we just trip into debugger, code that tries to do this is broken.
513 	debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n");
514 }
515 
516 /*************************************************************
517  * public BMediaNode
518  *************************************************************/
519 
520 /* virtual */ status_t
521 BMediaNode::HandleMessage(int32 message,
522 						  const void *data,
523 						  size_t size)
524 {
525 	PRINT(4, "BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID);
526 	switch (message) {
527 		case NODE_FINAL_RELEASE:
528 		{
529 			// const node_final_release_command *command = static_cast<const node_final_release_command *>(data);
530 			// This is called by the media server to delete the object
531 			// after is has been released by all nodes that are using it.
532 			// We forward the function to the BMediaRoster, since the
533 			// deletion must be done from a different thread, or the
534 			// outermost destructor that will exit the thread that is
535 			// reading messages from the port (this thread contex) will
536 			// quit, and ~BMediaNode destructor won't be called ever.
537 
538 			TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", this);
539 			BMessage msg(NODE_FINAL_RELEASE);
540 			msg.AddPointer("node", this);
541 			BMediaRoster::Roster()->PostMessage(&msg);
542 
543 			return B_OK;
544 		}
545 
546 		case NODE_START:
547 		{
548 			const node_start_command *command = static_cast<const node_start_command *>(data);
549 			printf("NODE_START, node %ld\n", fNodeID);
550 			Start(command->performance_time);
551 			return B_OK;
552 		}
553 
554 		case NODE_STOP:
555 		{
556 			const node_stop_command *command = static_cast<const node_stop_command *>(data);
557 			printf("NODE_STOP, node %ld\n", fNodeID);
558 			Stop(command->performance_time, command->immediate);
559 			return B_OK;
560 		}
561 
562 		case NODE_SEEK:
563 		{
564 			const node_seek_command *command = static_cast<const node_seek_command *>(data);
565 			printf("NODE_SEEK, node %ld\n", fNodeID);
566 			Seek(command->media_time, command->performance_time);
567 			return B_OK;
568 		}
569 
570 		case NODE_SET_RUN_MODE:
571 		{
572 			const node_set_run_mode_command *command = static_cast<const node_set_run_mode_command *>(data);
573 			// when changing this, also change PRODUCER_SET_RUN_MODE_DELAY
574 			fRunMode = command->mode;
575 			SetRunMode(fRunMode);
576 			return B_OK;
577 		}
578 
579 		case NODE_TIME_WARP:
580 		{
581 			const node_time_warp_command *command = static_cast<const node_time_warp_command *>(data);
582 			TimeWarp(command->at_real_time, command->to_performance_time);
583 			return B_OK;
584 		}
585 
586 		case NODE_PREROLL:
587 		{
588 			Preroll();
589 			return B_OK;
590 		}
591 
592 		case NODE_SET_TIMESOURCE:
593 		{
594 			const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data);
595 
596 			TRACE("NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id);
597 
598 			fTimeSourceID = command->timesource_id;
599 
600 			if (fTimeSource) {
601 				// as this node already had a timesource, we need
602 				// we need to remove this node from time source control
603 				fTimeSource->RemoveMe(this);
604 				// Then release the time source
605 				fTimeSource->Release();
606 				// force next call to TimeSource() to create a new object
607 				fTimeSource = 0;
608 			}
609 
610 			// create new time source object
611 			fTimeSource = TimeSource();
612 			// and call the SetTimeSource hook function to notify
613 			// any derived class
614 			SetTimeSource(fTimeSource);
615 
616 			TRACE("NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id);
617 
618 			return B_OK;
619 		}
620 
621 		case NODE_GET_TIMESOURCE:
622 		{
623 			const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data);
624 			node_get_timesource_reply reply;
625 			reply.timesource_id = fTimeSourceID;
626 			request->SendReply(B_OK, &reply, sizeof(reply));
627 			return B_OK;
628 		}
629 
630 		case NODE_REQUEST_COMPLETED:
631 		{
632 			const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data);
633 			RequestCompleted(command->info);
634 			return B_OK;
635 		}
636 
637 	};
638 	return B_ERROR;
639 }
640 
641 
642 void
643 BMediaNode::HandleBadMessage(int32 code,
644 							 const void *buffer,
645 							 size_t size)
646 {
647 	CALLED();
648 
649 	TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size);
650 	if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) {
651 		ERROR("BMediaNode::HandleBadMessage: unknown code!\n");
652 	} else {
653 		/* All messages targeted to nodes should be handled here,
654 		 * messages targetted to the wrong node should be handled
655 		 * by returning an error, not by stalling the sender.
656 		 */
657 		const request_data *request = static_cast<const request_data *>(buffer);
658 		reply_data reply;
659 		request->SendReply(B_ERROR, &reply, sizeof(reply));
660 	}
661 }
662 
663 
664 void
665 BMediaNode::AddNodeKind(uint64 kind)
666 {
667 	TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this);
668 
669 	fKinds |= kind;
670 }
671 
672 
673 void *
674 BMediaNode::operator new(size_t size)
675 {
676 	CALLED();
677 	return ::operator new(size);
678 }
679 
680 void *
681 BMediaNode::operator new(size_t size,
682 						 const nothrow_t &) throw()
683 {
684 	CALLED();
685 	return ::operator new(size, nothrow);
686 }
687 
688 void
689 BMediaNode::operator delete(void *ptr)
690 {
691 	CALLED();
692 	::operator delete(ptr);
693 }
694 
695 void
696 BMediaNode::operator delete(void * ptr,
697 							const nothrow_t &) throw()
698 {
699 	CALLED();
700 	::operator delete(ptr, nothrow);
701 }
702 
703 /*************************************************************
704  * protected BMediaNode
705  *************************************************************/
706 
707 /* virtual */ status_t
708 BMediaNode::RequestCompleted(const media_request_info &info)
709 {
710 	CALLED();
711 	// This function is called whenever a request issued by the node is completed.
712 	// May be overriden by derived classes.
713 	// info.change_tag can be used to match up requests against
714 	// the accompaning calles from
715 	// BBufferConsumer::RequestFormatChange()
716 	// BBufferConsumer::SetOutputBuffersFor()
717 	// BBufferConsumer::SetOutputEnabled()
718 	// BBufferConsumer::SetVideoClippingFor()
719 	return B_OK;
720 }
721 
722 /*************************************************************
723  * private BMediaNode
724  *************************************************************/
725 
726 int32
727 BMediaNode::IncrementChangeTag()
728 {
729 	CALLED();
730 	// Only present in BeOS R4
731 	// Obsoleted in BeOS R4.5 and later
732 	// "updates the change tag, so that downstream consumers know that the node is in a new state."
733 	// not supported, only for binary compatibility
734 	return 0;
735 }
736 
737 
738 int32
739 BMediaNode::ChangeTag()
740 {
741 	UNIMPLEMENTED();
742 	// Only present in BeOS R4
743 	// Obsoleted in BeOS R4.5 and later
744 	// "returns the node's current change tag value."
745 	// not supported, only for binary compatibility
746 	return 0;
747 }
748 
749 
750 int32
751 BMediaNode::MintChangeTag()
752 {
753 	UNIMPLEMENTED();
754 	// Only present in BeOS R4
755 	// Obsoleted in BeOS R4.5 and later
756 	// "mints a new, reserved, change tag."
757 	// "Call ApplyChangeTag() to apply it to the node"
758 	// not supported, only for binary compatibility
759 	return 0;
760 }
761 
762 
763 status_t
764 BMediaNode::ApplyChangeTag(int32 previously_reserved)
765 {
766 	UNIMPLEMENTED();
767 	// Only present in BeOS R4
768 	// Obsoleted in BeOS R4.5 and later
769 	// "this returns B_OK if the new change tag is"
770 	// "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change"
771 	// "count you tried to apply is already obsolete."
772 	// not supported, only for binary compatibility
773 	return B_OK;
774 }
775 
776 /*************************************************************
777  * protected BMediaNode
778  *************************************************************/
779 
780 /* virtual */ status_t
781 BMediaNode::DeleteHook(BMediaNode *node)
782 {
783 	CALLED();
784 	delete this; // delete "this" or "node", both are the same
785 	return B_OK;
786 }
787 
788 
789 /* virtual */ void
790 BMediaNode::NodeRegistered()
791 {
792 	CALLED();
793 	// The Media Server calls this hook function after the node has been registered.
794 	// May be overriden by derived classes.
795 }
796 
797 /*************************************************************
798  * public BMediaNode
799  *************************************************************/
800 
801 /* virtual */ status_t
802 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes,
803 							  size_t inMaxCount)
804 {
805 	UNIMPLEMENTED();
806 
807 	return B_ERROR;
808 }
809 
810 
811 /* virtual */ status_t
812 BMediaNode::AddTimer(bigtime_t at_performance_time,
813 					 int32 cookie)
814 {
815 	UNIMPLEMENTED();
816 
817 	return B_ERROR;
818 }
819 
820 
821 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; }
822 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; }
823 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; }
824 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; }
825 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; }
826 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; }
827 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; }
828 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; }
829 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; }
830 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; }
831 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; }
832 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; }
833 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; }
834 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; }
835 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; }
836 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; }
837 
838 /*
839 private unimplemented
840 BMediaNode::BMediaNode()
841 BMediaNode::BMediaNode(const BMediaNode &clone)
842 BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
843 */
844 
845 void
846 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds)
847 {
848 	TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this);
849 
850 	fNodeID = id;
851 	fRefCount = 1;
852 	fName[0] = 0;
853 	if (name) {
854 		strncpy(fName, name, B_MEDIA_NAME_LENGTH - 1);
855 		fName[B_MEDIA_NAME_LENGTH - 1] = 0;
856 	}
857 	fRunMode = B_INCREASE_LATENCY;
858 	_mChangeCount = 0;			//	deprecated
859 	_mChangeCountReserved = 0;	//	deprecated
860 	fKinds = kinds;
861 	fProducerThis = 0;
862 	fConsumerThis = 0;
863 	fFileInterfaceThis = 0;
864 	fControllableThis = 0;
865 	fTimeSourceThis = 0;
866 
867 	// create control port
868 	fControlPort = create_port(64, fName);
869 
870 	// nodes are assigned the system time source by default
871 	fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID;
872 
873 	// We can't create the timesource object here, because
874 	// every timesource is a BMediaNode, which would result
875 	// in infinite recursions
876 	fTimeSource = NULL;
877 }
878 
879 
880 BMediaNode::BMediaNode(const char *name,
881 					   media_node_id id,
882 					   uint32 kinds)
883 {
884 	TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds);
885 	_InitObject(name, id, kinds);
886 }
887 
888 
889 /*************************************************************
890  * protected BMediaNode
891  *************************************************************/
892 
893 /* static */ int32
894 BMediaNode::NewChangeTag()
895 {
896 	CALLED();
897 	// change tags have been used in BeOS R4 to match up
898 	// format change requests between producer and consumer,
899 	// This has changed starting with R4.5
900 	// now "change tags" are used with
901 	// BMediaNode::RequestCompleted()
902 	// and
903 	// BBufferConsumer::RequestFormatChange()
904 	// BBufferConsumer::SetOutputBuffersFor()
905 	// BBufferConsumer::SetOutputEnabled()
906 	// BBufferConsumer::SetVideoClippingFor()
907 	return atomic_add(&BMediaNode::_m_changeTag,1);
908 }
909