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