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