xref: /haiku/src/kits/media/MediaNode.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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 == GENERAL_PURPOSE_WAKEUP) return B_OK;	// no action needed
381 
382 	if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
383 		TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
384 		if (B_OK == BMediaNode::HandleMessage(message, data, size))
385 			return B_OK;
386 	}
387 
388 	if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) {
389 		if (!fProducerThis)
390 			fProducerThis = dynamic_cast<BBufferProducer *>(this);
391 		TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n",
392 			fProducerThis);
393 		if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage(
394 				message, data, size) == B_OK) {
395 			return B_OK;
396 		}
397 	}
398 
399 	if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) {
400 		if (!fConsumerThis)
401 			fConsumerThis = dynamic_cast<BBufferConsumer *>(this);
402 		TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n",
403 			fConsumerThis);
404 		if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage(
405 			message, data, size) == B_OK) {
406 			return B_OK;
407 		}
408 	}
409 
410 	if (message > FILEINTERFACE_MESSAGE_START
411 		&& message < FILEINTERFACE_MESSAGE_END) {
412 		if (!fFileInterfaceThis)
413 			fFileInterfaceThis = dynamic_cast<BFileInterface *>(this);
414 		TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n",
415 			fFileInterfaceThis);
416 		if (fFileInterfaceThis
417 			&& fFileInterfaceThis->BFileInterface::HandleMessage(
418 				message, data, size) == B_OK) {
419 			return B_OK;
420 		}
421 	}
422 
423 	if (message > CONTROLLABLE_MESSAGE_START
424 		&& message < CONTROLLABLE_MESSAGE_END) {
425 		if (!fControllableThis)
426 			fControllableThis = dynamic_cast<BControllable *>(this);
427 		TRACE("BMediaNode::WaitForMessage calling BControllable %p\n",
428 			fControllableThis);
429 		if (fControllableThis
430 			&& fControllableThis->BControllable::HandleMessage(
431 				message, data, size) == B_OK) {
432 			return B_OK;
433 		}
434 	}
435 
436 	if (message > TIMESOURCE_MESSAGE_START
437 		&& message < TIMESOURCE_MESSAGE_END) {
438 		if (!fTimeSourceThis)
439 			fTimeSourceThis = dynamic_cast<BTimeSource *>(this);
440 		TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n",
441 			fTimeSourceThis);
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 (B_OK == HandleMessage(message, data, size))
450 		return B_OK;
451 
452 	HandleBadMessage(message, data, size);
453 
454 	return B_ERROR;
455 }
456 
457 
458 /* virtual */ 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 /* virtual */ void
473 BMediaNode::Stop(bigtime_t performance_time,
474 				 bool immediate)
475 {
476 	CALLED();
477 	// This hook function is called when a node is stopped
478 	// by a call to the BMediaRoster. The specified
479 	// performanceTime, the time at which the node
480 	// should stop running, may be in the future.
481 	// It may be overriden by derived classes.
482 	// The BMediaEventLooper class handles this event!
483 	// The BMediaNode class does nothing here.
484 }
485 
486 
487 /* virtual */ void
488 BMediaNode::Seek(bigtime_t media_time,
489 				 bigtime_t performance_time)
490 {
491 	CALLED();
492 	// This hook function is called when a node is asked
493 	// to seek to the specified mediaTime by a call to
494 	// the BMediaRoster. The specified performanceTime,
495 	// the time at which the node should begin the seek
496 	// operation, may be in the future.
497 	// It may be overriden by derived classes.
498 	// The BMediaEventLooper class handles this event!
499 	// The BMediaNode class does nothing here.
500 }
501 
502 
503 /* virtual */ void
504 BMediaNode::SetRunMode(run_mode mode)
505 {
506 	CALLED();
507 
508 	// this is a hook function, and
509 	// may be overriden by derived classes.
510 
511 	// the functionality here is only to
512 	// support those people that don't
513 	// use the roster to set the run mode
514 	fRunMode = mode;
515 }
516 
517 
518 /* virtual */ void
519 BMediaNode::TimeWarp(bigtime_t at_real_time,
520 					 bigtime_t to_performance_time)
521 {
522 	CALLED();
523 	// May be overriden by derived classes.
524 }
525 
526 
527 /* virtual */ void
528 BMediaNode::Preroll()
529 {
530 	CALLED();
531 	// May be overriden by derived classes.
532 }
533 
534 
535 /* virtual */ void
536 BMediaNode::SetTimeSource(BTimeSource *time_source)
537 {
538 	CALLED();
539 	// this is a hook function, and
540 	// may be overriden by derived classes.
541 
542 	if (time_source == NULL || time_source == fTimeSource)
543 		return;
544 
545 	// we just trip into debugger, code that tries to do this is broken.
546 	debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n");
547 }
548 
549 /*************************************************************
550  * public BMediaNode
551  *************************************************************/
552 
553 /* virtual */ status_t
554 BMediaNode::HandleMessage(int32 message,
555 						  const void *data,
556 						  size_t size)
557 {
558 	TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID);
559 	switch (message) {
560 		case NODE_FINAL_RELEASE:
561 		{
562 			// const node_final_release_command *command = static_cast<const node_final_release_command *>(data);
563 			// This is called by the media server to delete the object
564 			// after is has been released by all nodes that are using it.
565 			// We forward the function to the BMediaRoster, since the
566 			// deletion must be done from a different thread, or the
567 			// outermost destructor that will exit the thread that is
568 			// reading messages from the port (this thread contex) will
569 			// quit, and ~BMediaNode destructor won't be called ever.
570 
571 			TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", this);
572 			BMessage msg(NODE_FINAL_RELEASE);
573 			msg.AddPointer("node", this);
574 			BMediaRoster::Roster()->PostMessage(&msg);
575 
576 			return B_OK;
577 		}
578 
579 		case NODE_START:
580 		{
581 			const node_start_command *command = static_cast<const node_start_command *>(data);
582 			TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID);
583 			Start(command->performance_time);
584 			return B_OK;
585 		}
586 
587 		case NODE_STOP:
588 		{
589 			const node_stop_command *command = static_cast<const node_stop_command *>(data);
590 			TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID);
591 			Stop(command->performance_time, command->immediate);
592 			return B_OK;
593 		}
594 
595 		case NODE_SEEK:
596 		{
597 			const node_seek_command *command = static_cast<const node_seek_command *>(data);
598 			TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID);
599 			Seek(command->media_time, command->performance_time);
600 			return B_OK;
601 		}
602 
603 		case NODE_SET_RUN_MODE:
604 		{
605 			const node_set_run_mode_command *command = static_cast<const node_set_run_mode_command *>(data);
606 			TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE, node %ld\n", fNodeID);
607 			// when changing this, also change PRODUCER_SET_RUN_MODE_DELAY
608 			fRunMode = command->mode;
609 			SetRunMode(fRunMode);
610 			return B_OK;
611 		}
612 
613 		case NODE_TIME_WARP:
614 		{
615 			const node_time_warp_command *command = static_cast<const node_time_warp_command *>(data);
616 			TRACE("BMediaNode::HandleMessage NODE_TIME_WARP, node %ld\n", fNodeID);
617 			TimeWarp(command->at_real_time, command->to_performance_time);
618 			return B_OK;
619 		}
620 
621 		case NODE_PREROLL:
622 		{
623 			TRACE("BMediaNode::HandleMessage NODE_PREROLL, node %ld\n", fNodeID);
624 			Preroll();
625 			return B_OK;
626 		}
627 
628 		case NODE_SET_TIMESOURCE:
629 		{
630 			const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data);
631 
632 			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id);
633 
634 			fTimeSourceID = command->timesource_id;
635 
636 			if (fTimeSource) {
637 				// as this node already had a timesource, we need
638 				// we need to remove this node from time source control
639 				fTimeSource->RemoveMe(this);
640 				// Then release the time source
641 				fTimeSource->Release();
642 				// force next call to TimeSource() to create a new object
643 				fTimeSource = 0;
644 			}
645 
646 			// create new time source object
647 			fTimeSource = TimeSource();
648 			// and call the SetTimeSource hook function to notify
649 			// any derived class
650 			SetTimeSource(fTimeSource);
651 
652 			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id);
653 
654 			return B_OK;
655 		}
656 
657 		case NODE_GET_TIMESOURCE:
658 		{
659 			const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data);
660 			TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE, node %ld\n", fNodeID);
661 			node_get_timesource_reply reply;
662 			reply.timesource_id = fTimeSourceID;
663 			request->SendReply(B_OK, &reply, sizeof(reply));
664 			return B_OK;
665 		}
666 
667 		case NODE_REQUEST_COMPLETED:
668 		{
669 			const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data);
670 			TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED, node %ld\n", fNodeID);
671 			RequestCompleted(command->info);
672 			return B_OK;
673 		}
674 
675 	};
676 	return B_ERROR;
677 }
678 
679 
680 void
681 BMediaNode::HandleBadMessage(int32 code,
682 							 const void *buffer,
683 							 size_t size)
684 {
685 	CALLED();
686 
687 	TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size);
688 	if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) {
689 		ERROR("BMediaNode::HandleBadMessage: unknown code!\n");
690 	} else {
691 		/* All messages targeted to nodes should be handled here,
692 		 * messages targetted to the wrong node should be handled
693 		 * by returning an error, not by stalling the sender.
694 		 */
695 		const request_data *request = static_cast<const request_data *>(buffer);
696 		reply_data reply;
697 		request->SendReply(B_ERROR, &reply, sizeof(reply));
698 	}
699 }
700 
701 
702 void
703 BMediaNode::AddNodeKind(uint64 kind)
704 {
705 	TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this);
706 
707 	fKinds |= kind;
708 }
709 
710 
711 void *
712 BMediaNode::operator new(size_t size)
713 {
714 	CALLED();
715 	return ::operator new(size);
716 }
717 
718 void *
719 BMediaNode::operator new(size_t size,
720 						 const nothrow_t &) throw()
721 {
722 	CALLED();
723 	return ::operator new(size, nothrow);
724 }
725 
726 void
727 BMediaNode::operator delete(void *ptr)
728 {
729 	CALLED();
730 	::operator delete(ptr);
731 }
732 
733 void
734 BMediaNode::operator delete(void * ptr,
735 							const nothrow_t &) throw()
736 {
737 	CALLED();
738 	::operator delete(ptr, nothrow);
739 }
740 
741 /*************************************************************
742  * protected BMediaNode
743  *************************************************************/
744 
745 /* virtual */ status_t
746 BMediaNode::RequestCompleted(const media_request_info &info)
747 {
748 	CALLED();
749 	// This function is called whenever a request issued by the node is completed.
750 	// May be overriden by derived classes.
751 	// info.change_tag can be used to match up requests against
752 	// the accompaning calles from
753 	// BBufferConsumer::RequestFormatChange()
754 	// BBufferConsumer::SetOutputBuffersFor()
755 	// BBufferConsumer::SetOutputEnabled()
756 	// BBufferConsumer::SetVideoClippingFor()
757 	return B_OK;
758 }
759 
760 /*************************************************************
761  * private BMediaNode
762  *************************************************************/
763 
764 int32
765 BMediaNode::IncrementChangeTag()
766 {
767 	CALLED();
768 	// Only present in BeOS R4
769 	// Obsoleted in BeOS R4.5 and later
770 	// "updates the change tag, so that downstream consumers know that the node is in a new state."
771 	// not supported, only for binary compatibility
772 	return 0;
773 }
774 
775 
776 int32
777 BMediaNode::ChangeTag()
778 {
779 	UNIMPLEMENTED();
780 	// Only present in BeOS R4
781 	// Obsoleted in BeOS R4.5 and later
782 	// "returns the node's current change tag value."
783 	// not supported, only for binary compatibility
784 	return 0;
785 }
786 
787 
788 int32
789 BMediaNode::MintChangeTag()
790 {
791 	UNIMPLEMENTED();
792 	// Only present in BeOS R4
793 	// Obsoleted in BeOS R4.5 and later
794 	// "mints a new, reserved, change tag."
795 	// "Call ApplyChangeTag() to apply it to the node"
796 	// not supported, only for binary compatibility
797 	return 0;
798 }
799 
800 
801 status_t
802 BMediaNode::ApplyChangeTag(int32 previously_reserved)
803 {
804 	UNIMPLEMENTED();
805 	// Only present in BeOS R4
806 	// Obsoleted in BeOS R4.5 and later
807 	// "this returns B_OK if the new change tag is"
808 	// "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change"
809 	// "count you tried to apply is already obsolete."
810 	// not supported, only for binary compatibility
811 	return B_OK;
812 }
813 
814 /*************************************************************
815  * protected BMediaNode
816  *************************************************************/
817 
818 /* virtual */ status_t
819 BMediaNode::DeleteHook(BMediaNode *node)
820 {
821 	CALLED();
822 	delete this; // delete "this" or "node", both are the same
823 	return B_OK;
824 }
825 
826 
827 /* virtual */ void
828 BMediaNode::NodeRegistered()
829 {
830 	CALLED();
831 	// The Media Server calls this hook function after the node has been registered.
832 	// May be overriden by derived classes.
833 }
834 
835 /*************************************************************
836  * public BMediaNode
837  *************************************************************/
838 
839 /* virtual */ status_t
840 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes,
841 							  size_t inMaxCount)
842 {
843 	UNIMPLEMENTED();
844 
845 	return B_ERROR;
846 }
847 
848 
849 /* virtual */ status_t
850 BMediaNode::AddTimer(bigtime_t at_performance_time,
851 					 int32 cookie)
852 {
853 	UNIMPLEMENTED();
854 
855 	return B_ERROR;
856 }
857 
858 
859 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; }
860 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; }
861 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; }
862 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; }
863 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; }
864 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; }
865 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; }
866 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; }
867 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; }
868 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; }
869 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; }
870 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; }
871 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; }
872 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; }
873 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; }
874 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; }
875 
876 /*
877 private unimplemented
878 BMediaNode::BMediaNode()
879 BMediaNode::BMediaNode(const BMediaNode &clone)
880 BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
881 */
882 
883 void
884 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds)
885 {
886 	TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this);
887 
888 	fNodeID = id;
889 	fRefCount = 1;
890 	fName[0] = 0;
891 	if (name)
892 		strlcpy(fName, name, B_MEDIA_NAME_LENGTH);
893 	fRunMode = B_INCREASE_LATENCY;
894 	fKinds = kinds;
895 	fProducerThis = 0;
896 	fConsumerThis = 0;
897 	fFileInterfaceThis = 0;
898 	fControllableThis = 0;
899 	fTimeSourceThis = 0;
900 
901 	// create control port
902 	fControlPort = create_port(64, fName);
903 
904 	// nodes are assigned the system time source by default
905 	fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID;
906 
907 	// We can't create the timesource object here, because
908 	// every timesource is a BMediaNode, which would result
909 	// in infinite recursions
910 	fTimeSource = NULL;
911 }
912 
913 
914 BMediaNode::BMediaNode(const char *name,
915 					   media_node_id id,
916 					   uint32 kinds)
917 {
918 	TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds);
919 	_InitObject(name, id, kinds);
920 }
921 
922 
923 /*************************************************************
924  * protected BMediaNode
925  *************************************************************/
926 
927 /* static */ int32
928 BMediaNode::NewChangeTag()
929 {
930 	CALLED();
931 	// change tags have been used in BeOS R4 to match up
932 	// format change requests between producer and consumer,
933 	// This has changed starting with R4.5
934 	// now "change tags" are used with
935 	// BMediaNode::RequestCompleted()
936 	// and
937 	// BBufferConsumer::RequestFormatChange()
938 	// BBufferConsumer::SetOutputBuffersFor()
939 	// BBufferConsumer::SetOutputEnabled()
940 	// BBufferConsumer::SetVideoClippingFor()
941 	return atomic_add(&BMediaNode::_m_changeTag,1);
942 }
943