1135446Strhodes/*
2193149Sdougb * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3135446Strhodes *
4135446Strhodes * Permission is hereby granted, free of charge, to any person obtaining
5193149Sdougb * a copy of this software and associated documentation files or portions
6135446Strhodes * thereof (the "Software"), to deal in the Software without restriction,
7135446Strhodes * including without limitation the rights to use, copy, modify, merge,
8135446Strhodes * publish, distribute, sublicense, and/or sell copies of the Software,
9135446Strhodes * and to permit persons to whom the Software is furnished to do so, subject
10135446Strhodes * to the following conditions:
11135446Strhodes *
12135446Strhodes *  * Redistributions of source code must retain the above copyright notice,
13135446Strhodes *    this list of conditions and the following disclaimer.
14135446Strhodes *
15135446Strhodes *  * Redistributions in binary form must reproduce the above copyright notice
16135446Strhodes *    in the  binary, as well as this list of conditions and the following
17135446Strhodes *    disclaimer in the documentation and/or other materials provided with
18234010Sdougb *    the distribution.
19135446Strhodes *
20135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21135446Strhodes * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22135446Strhodes * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23170222Sdougb * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24170222Sdougb * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25135446Strhodes * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26135446Strhodes * THE SOFTWARE.
27135446Strhodes *
28135446Strhodes */
29170222Sdougb//#define DEBUG 7
30135446Strhodes#include <MediaRoster.h>
31135446Strhodes#include <MediaNode.h>
32135446Strhodes#include <TimeSource.h>
33165071Sdougb#include <BufferConsumer.h>
34135446Strhodes#include <BufferProducer.h>
35170222Sdougb#include <Controllable.h>
36135446Strhodes#include <FileInterface.h>
37135446Strhodes#include <string.h>
38135446Strhodes#include "debug.h"
39135446Strhodes#include "MediaMisc.h"
40135446Strhodes#include "MediaRosterEx.h"
41135446Strhodes#include "DataExchange.h"
42135446Strhodes#include "ServerInterface.h"
43135446Strhodes#include "Notifications.h"
44135446Strhodes#include "TimeSourceObject.h"
45165071Sdougb#include "TimeSourceObjectManager.h"
46165071Sdougb
47170222Sdougbusing std::nothrow;
48135446Strhodesusing std::nothrow_t;
49135446Strhodes
50135446Strhodes#undef TRACE
51135446Strhodes//#define TRACE_MEDIA_NODE
52135446Strhodes#ifdef TRACE_MEDIA_NODE
53135446Strhodes  #define TRACE printf
54135446Strhodes#else
55135446Strhodes  #define TRACE(x...)
56135446Strhodes#endif
57135446Strhodes
58135446Strhodes
59135446Strhodes// don't rename this one, it's used and exported for binary compatibility
60135446Strhodesint32 BMediaNode::_m_changeTag = 0;
61165071Sdougb
62170222Sdougb/*************************************************************
63135446Strhodes * media_node
64135446Strhodes *************************************************************/
65135446Strhodes
66135446Strhodes// final & verified
67135446Strhodesmedia_node::media_node()
68165071Sdougb	: node(-1),
69170222Sdougb	port(-1),
70135446Strhodes	kind(0)
71135446Strhodes{
72135446Strhodes}
73135446Strhodes
74135446Strhodes// final & verified
75135446Strhodesmedia_node::~media_node()
76135446Strhodes{
77135446Strhodes}
78165071Sdougb
79170222Sdougb/*************************************************************
80135446Strhodes * static media_node variables
81135446Strhodes *************************************************************/
82135446Strhodes
83135446Strhodes// final & verified
84135446Strhodesmedia_node media_node::null;
85135446Strhodes
86135446Strhodes/*************************************************************
87135446Strhodes * media_input
88 *************************************************************/
89
90// final
91media_input::media_input()
92{
93	name[0] = '\0';
94}
95
96// final
97media_input::~media_input()
98{
99}
100
101/*************************************************************
102 * media_output
103 *************************************************************/
104
105// final
106media_output::media_output()
107{
108	name[0] = '\0';
109}
110
111// final
112media_output::~media_output()
113{
114}
115
116/*************************************************************
117 * live_node_info
118 *************************************************************/
119
120// final & verified
121live_node_info::live_node_info()
122	: hint_point(0.0f, 0.0f)
123{
124	name[0] = '\0';
125}
126
127// final & verified
128live_node_info::~live_node_info()
129{
130}
131
132/*************************************************************
133 * protected BMediaNode
134 *************************************************************/
135
136/* virtual */
137BMediaNode::~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
168BMediaNode *
169BMediaNode::Acquire()
170{
171	CALLED();
172	atomic_add(&fRefCount,1);
173	return this;
174}
175
176
177BMediaNode *
178BMediaNode::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
194const char *
195BMediaNode::Name() const
196{
197	CALLED();
198	return fName;
199}
200
201
202media_node_id
203BMediaNode::ID() const
204{
205	CALLED();
206	return fNodeID;
207}
208
209
210uint64
211BMediaNode::Kinds() const
212{
213	CALLED();
214	return fKinds & NODE_KIND_USER_MASK;
215}
216
217
218media_node
219BMediaNode::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
230BMediaNode::run_mode
231BMediaNode::RunMode() const
232{
233	CALLED();
234	return fRunMode;
235}
236
237
238BTimeSource *
239BMediaNode::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
276BMediaNode::ControlPort() const
277{
278	PRINT(7, "CALLED BMediaNode::ControlPort()\n");
279	return fControlPort;
280}
281
282
283/*************************************************************
284 * protected BMediaNode
285 *************************************************************/
286
287status_t
288BMediaNode::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
315status_t
316BMediaNode::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
333void
334BMediaNode::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 */
347BMediaNode::BMediaNode(const char *name)
348{
349	TRACE("BMediaNode::BMediaNode: name '%s'\n", name);
350	_InitObject(name, NODE_JUST_CREATED_ID, 0);
351}
352
353
354status_t
355BMediaNode::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
459BMediaNode::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
473BMediaNode::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
488BMediaNode::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
504BMediaNode::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
519BMediaNode::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
528BMediaNode::Preroll()
529{
530	CALLED();
531	// May be overriden by derived classes.
532}
533
534
535/* virtual */ void
536BMediaNode::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
554BMediaNode::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
680void
681BMediaNode::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
702void
703BMediaNode::AddNodeKind(uint64 kind)
704{
705	TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this);
706
707	fKinds |= kind;
708}
709
710
711void *
712BMediaNode::operator new(size_t size)
713{
714	CALLED();
715	return ::operator new(size);
716}
717
718void *
719BMediaNode::operator new(size_t size,
720						 const nothrow_t &) throw()
721{
722	CALLED();
723	return ::operator new(size, nothrow);
724}
725
726void
727BMediaNode::operator delete(void *ptr)
728{
729	CALLED();
730	::operator delete(ptr);
731}
732
733void
734BMediaNode::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
746BMediaNode::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
764int32
765BMediaNode::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
776int32
777BMediaNode::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
788int32
789BMediaNode::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
801status_t
802BMediaNode::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
819BMediaNode::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
828BMediaNode::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
840BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes,
841							  size_t inMaxCount)
842{
843	UNIMPLEMENTED();
844
845	return B_ERROR;
846}
847
848
849/* virtual */ status_t
850BMediaNode::AddTimer(bigtime_t at_performance_time,
851					 int32 cookie)
852{
853	UNIMPLEMENTED();
854
855	return B_ERROR;
856}
857
858
859status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; }
860status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; }
861status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; }
862status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; }
863status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; }
864status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; }
865status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; }
866status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; }
867status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; }
868status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; }
869status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; }
870status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; }
871status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; }
872status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; }
873status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; }
874status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; }
875
876/*
877private unimplemented
878BMediaNode::BMediaNode()
879BMediaNode::BMediaNode(const BMediaNode &clone)
880BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
881*/
882
883void
884BMediaNode::_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
914BMediaNode::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
928BMediaNode::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