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