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 "MediaDebug.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
52using std::nothrow;
53using 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
64int32 BMediaNode::_m_changeTag = 0;
65
66// media_node
67
68media_node media_node::null;
69
70media_node::media_node()
71	:
72	node(-1),
73	port(-1),
74	kind(0)
75{
76}
77
78
79media_node::~media_node()
80{
81}
82
83// media_input
84
85media_input::media_input()
86{
87	name[0] = '\0';
88}
89
90
91media_input::~media_input()
92{
93}
94
95// media_output
96
97media_output::media_output()
98{
99	name[0] = '\0';
100}
101
102
103media_output::~media_output()
104{
105}
106
107// live_node_info
108
109live_node_info::live_node_info()
110	:
111	hint_point(0.0f, 0.0f)
112{
113	name[0] = '\0';
114}
115
116
117live_node_info::~live_node_info()
118{
119}
120
121// BMediaNode
122
123BMediaNode::~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
150BMediaNode*
151BMediaNode::Acquire()
152{
153	CALLED();
154	if (atomic_add(&fRefCount,1) == 0) {
155		status_t status = B_ERROR;
156		BMediaRoster* roster = BMediaRoster::Roster(&status);
157		if (roster != NULL && status == B_OK)
158			MediaRosterEx(roster)->RegisterLocalNode(this);
159	}
160	return this;
161}
162
163
164BMediaNode*
165BMediaNode::Release()
166{
167	CALLED();
168	if (atomic_add(&fRefCount, -1) == 1) {
169		status_t status = B_ERROR;
170		BMediaRoster* roster = BMediaRoster::Roster(&status);
171		if (roster != NULL && status == B_OK) {
172			MediaRosterEx(roster)->UnregisterLocalNode(this);
173
174			// Only addons needs the configuration to be saved.
175			int32 id;
176			if (AddOn(&id) != NULL) {
177				TRACE("BMediaNode::Release() saving node %ld"
178					" configuration\n", fNodeID);
179				MediaRosterEx(roster)->SaveNodeConfiguration(this);
180			}
181
182			if (DeleteHook(this) != B_OK) {
183				ERROR("BMediaNode::Release(): DeleteHook failed\n");
184				return Acquire();
185			}
186			return NULL;
187		}
188		TRACE("BMediaRoster::Release() the media roster is 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	// We *must* call ControlPort(), some derived nodes
225	// use it to start the port read thread!
226	temp.port = ControlPort();
227	temp.kind = Kinds();
228	return temp;
229}
230
231
232BMediaNode::run_mode
233BMediaNode::RunMode() const
234{
235	CALLED();
236	return fRunMode;
237}
238
239
240BTimeSource*
241BMediaNode::TimeSource() const
242{
243	PRINT(7, "CALLED BMediaNode::TimeSource()\n");
244
245	// Return the currently assigned time source
246	if (fTimeSource != 0)
247		return fTimeSource;
248
249	TRACE("BMediaNode::TimeSource node %ld enter\n", ID());
250
251	// If the node doesn't have a time source object, we need to create one.
252	// If the node is still unregistered, we can't call MakeTimeSourceFor(),
253	// but since the node does still have the default system time source, we
254	// can use GetSystemTimeSource
255
256	BMediaNode* self = const_cast<BMediaNode*>(this);
257	self->fTimeSource = MediaRosterEx(
258		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
275port_id
276BMediaNode::ControlPort() const
277{
278	PRINT(7, "CALLED BMediaNode::ControlPort()\n");
279	return fControlPort;
280}
281
282
283status_t
284BMediaNode::ReportError(node_error what, const BMessage* info)
285{
286	CALLED();
287
288	// Sanity check the what value
289	switch (what) {
290		case BMediaNode::B_NODE_FAILED_START:
291		case BMediaNode::B_NODE_FAILED_STOP:
292		case BMediaNode::B_NODE_FAILED_SEEK:
293		case BMediaNode::B_NODE_FAILED_SET_RUN_MODE:
294		case BMediaNode::B_NODE_FAILED_TIME_WARP:
295		case BMediaNode::B_NODE_FAILED_PREROLL:
296		case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR:
297		case BMediaNode::B_NODE_IN_DISTRESS:
298			break;
299		default:
300			ERROR("BMediaNode::ReportError: invalid what!\n");
301			return B_BAD_VALUE;
302	}
303
304	// Transmits the error code specified by what to anyone
305	// that's receiving notifications from this node
306	return BPrivate::media::notifications::ReportError(Node(), what, info);
307}
308
309
310status_t
311BMediaNode::NodeStopped(bigtime_t whenPerformance)
312{
313	UNIMPLEMENTED();
314	// Called by derived classes when they have
315	// finished handling a stop request.
316
317	// Notify anyone who is listening for stop notifications!
318	BPrivate::media::notifications::NodeStopped(Node(), whenPerformance);
319
320	// NOTE: If your node is a BBufferProducer, downstream consumers
321	// will be notified that your node stopped (automatically, no less) through
322	// the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call.
323
324	return B_OK;
325}
326
327
328/*
329 * Used in couple with AddTimer, this will cause the BMediaRoster::SyncToNode()
330 * call that requested the timer to return to the caller with an appropriate
331 * value.
332 */
333void
334BMediaNode::TimerExpired(bigtime_t notifyPoint, int32 cookie, status_t error)
335{
336	CALLED();
337	if (write_port((port_id)cookie, 0, &error, sizeof(error)) < 0) {
338		TRACE("BMediaNode::TimerExpired: error writing port" B_PRId32
339			", at notifyPoint" B_PRId64 "\n", cookie, notifyPoint);
340	}
341}
342
343
344BMediaNode::BMediaNode(const char* name)
345{
346	TRACE("BMediaNode::BMediaNode: name '%s'\n", name);
347	_InitObject(name, NODE_JUST_CREATED_ID, 0);
348}
349
350
351status_t
352BMediaNode::WaitForMessage(bigtime_t waitUntil, uint32 flags,
353	void* _reserved_)
354{
355	TRACE("entering: BMediaNode::WaitForMessage()\n");
356
357	// This function waits until either real time specified by
358	// waitUntil or a message is received on the control port.
359	// The flags are currently unused and should be 0.
360	// Note: about 16 KByte stack used
361	char data[B_MEDIA_MESSAGE_SIZE];
362	int32 message;
363	ssize_t size;
364
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)
388		return B_OK;
389
390	if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) {
391		TRACE("BMediaNode::WaitForMessage calling BMediaNode\n");
392
393		if (B_OK == BMediaNode::HandleMessage(message, data, size))
394			return B_OK;
395	}
396
397	if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) {
398		if (!fProducerThis)
399			fProducerThis = dynamic_cast<BBufferProducer*>(this);
400
401		TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n",
402			fProducerThis);
403
404		if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage(
405				message, data, size) == B_OK) {
406			return B_OK;
407		}
408	}
409
410	if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) {
411		if (!fConsumerThis)
412			fConsumerThis = dynamic_cast<BBufferConsumer*>(this);
413
414		TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n",
415			fConsumerThis);
416
417		if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage(
418			message, data, size) == B_OK) {
419			return B_OK;
420		}
421	}
422
423	if (message > FILEINTERFACE_MESSAGE_START
424		&& message < FILEINTERFACE_MESSAGE_END) {
425		if (!fFileInterfaceThis)
426			fFileInterfaceThis = dynamic_cast<BFileInterface*>(this);
427
428		TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n",
429			fFileInterfaceThis);
430
431		if (fFileInterfaceThis
432			&& fFileInterfaceThis->BFileInterface::HandleMessage(
433				message, data, size) == B_OK) {
434			return B_OK;
435		}
436	}
437
438	if (message > CONTROLLABLE_MESSAGE_START
439		&& message < CONTROLLABLE_MESSAGE_END) {
440		if (!fControllableThis)
441			fControllableThis = dynamic_cast<BControllable*>(this);
442
443		TRACE("BMediaNode::WaitForMessage calling BControllable %p\n",
444			fControllableThis);
445
446		if (fControllableThis
447			&& fControllableThis->BControllable::HandleMessage(
448				message, data, size) == B_OK) {
449			return B_OK;
450		}
451	}
452
453	if (message > TIMESOURCE_MESSAGE_START
454		&& message < TIMESOURCE_MESSAGE_END) {
455		if (!fTimeSourceThis)
456			fTimeSourceThis = dynamic_cast<BTimeSource*>(this);
457
458		TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n",
459			fTimeSourceThis);
460
461		if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage(
462				message, data, size) == B_OK) {
463			return B_OK;
464		}
465	}
466
467	TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n");
468	if (HandleMessage(message, data, size) == B_OK)
469		return B_OK;
470
471	HandleBadMessage(message, data, size);
472
473	return B_ERROR;
474}
475
476
477void
478BMediaNode::Start(bigtime_t performance_time)
479{
480	CALLED();
481	// This hook function is called when a node is started
482	// by a call to the BMediaRoster. The specified
483	// performanceTime, the time at which the node
484	// should start running, may be in the future.
485	// It may be overriden by derived classes.
486	// The BMediaEventLooper class handles this event!
487	// The BMediaNode class does nothing here.
488}
489
490
491void
492BMediaNode::Stop(bigtime_t performance_time, bool immediate)
493{
494	CALLED();
495	// This hook function is called when a node is stopped
496	// by a call to the BMediaRoster. The specified
497	// performanceTime, the time at which the node
498	// should stop running, may be in the future.
499	// It may be overriden by derived classes.
500	// The BMediaEventLooper class handles this event!
501	// The BMediaNode class does nothing here.
502}
503
504
505void
506BMediaNode::Seek(bigtime_t media_time, bigtime_t performance_time)
507{
508	CALLED();
509	// This hook function is called when a node is asked
510	// to seek to the specified mediaTime by a call to
511	// the BMediaRoster. The specified performanceTime,
512	// the time at which the node should begin the seek
513	// operation, may be in the future.
514	// It may be overriden by derived classes.
515	// The BMediaEventLooper class handles this event!
516	// The BMediaNode class does nothing here.
517}
518
519
520void
521BMediaNode::SetRunMode(run_mode mode)
522{
523	CALLED();
524
525	// This is a hook function, and
526	// may be overriden by derived classes.
527
528	// The functionality here is only to
529	// support those people that don't
530	// use the roster to set the run mode
531	fRunMode = mode;
532}
533
534
535void
536BMediaNode::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
537{
538	CALLED();
539	// May be overriden by derived classes.
540}
541
542
543void
544BMediaNode::Preroll()
545{
546	CALLED();
547	// May be overriden by derived classes.
548}
549
550
551void
552BMediaNode::SetTimeSource(BTimeSource* time_source)
553{
554	CALLED();
555	// This is a hook function, and
556	// may be overriden by derived classes.
557
558	if (time_source == NULL || time_source == fTimeSource)
559		return;
560
561	// We just trip into debugger, code that tries to do this is broken.
562	debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, "
563		"use BMediaRoster::SetTimeSourceFor()!\n");
564}
565
566
567status_t
568BMediaNode::HandleMessage(int32 message, const void* data, size_t size)
569{
570	TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID);
571	switch (message) {
572		case NODE_FINAL_RELEASE:
573		{
574			TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n",
575				this);
576
577			// This is called by the media server to delete the object
578			// after is has been released by all nodes that are using it.
579			// We forward the function to the BMediaRoster, since the
580			// deletion must be done from a different thread, or the
581			// outermost destructor that will exit the thread that is
582			// reading messages from the port (this thread contex) will
583			// quit, and ~BMediaNode destructor won't be called ever.
584			BMessage msg(NODE_FINAL_RELEASE);
585			msg.AddPointer("node", this);
586			BMediaRoster::Roster()->PostMessage(&msg);
587			return B_OK;
588		}
589
590		case NODE_START:
591		{
592			const node_start_command* command
593				= static_cast<const node_start_command*>(data);
594			TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID);
595			Start(command->performance_time);
596			return B_OK;
597		}
598
599		case NODE_STOP:
600		{
601			const node_stop_command* command
602				= static_cast<const node_stop_command*>(data);
603			TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID);
604			Stop(command->performance_time, command->immediate);
605			return B_OK;
606		}
607
608		case NODE_SEEK:
609		{
610			const node_seek_command* command
611				= static_cast<const node_seek_command*>(data);
612			TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID);
613			Seek(command->media_time, command->performance_time);
614			return B_OK;
615		}
616
617		case NODE_SET_RUN_MODE:
618		{
619			const node_set_run_mode_command* command
620				= static_cast<const node_set_run_mode_command*>(data);
621			TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE,"
622				" node %ld\n", fNodeID);
623			// Need to change PRODUCER_SET_RUN_MODE_DELAY
624			fRunMode = command->mode;
625			SetRunMode(fRunMode);
626			return B_OK;
627		}
628
629		case NODE_TIME_WARP:
630		{
631			const node_time_warp_command* command
632				= static_cast<const node_time_warp_command*>(data);
633			TRACE("BMediaNode::HandleMessage NODE_TIME_WARP,"
634				" node %ld\n", fNodeID);
635			TimeWarp(command->at_real_time, command->to_performance_time);
636			return B_OK;
637		}
638
639		case NODE_PREROLL:
640		{
641			TRACE("BMediaNode::HandleMessage NODE_PREROLL, "
642				" node %ld\n", fNodeID);
643			Preroll();
644			return B_OK;
645		}
646
647		case NODE_ROLL:
648		{
649			const node_roll_command* command
650				= static_cast<const node_roll_command*>(data);
651
652			TRACE("BMediaNode::HandleMessage NODE_ROLL, node %ld\n",
653				fNodeID);
654
655			if (command->seek_media_time != B_INFINITE_TIMEOUT)
656				Seek(command->seek_media_time,
657					command->start_performance_time);
658
659			Start(command->start_performance_time);
660			Stop(command->stop_performance_time, false);
661			return B_OK;
662		}
663
664		case NODE_SYNC_TO:
665		{
666			const node_sync_to_request* request
667				= static_cast<const node_sync_to_request*>(data);
668			node_sync_to_reply reply;
669
670			TRACE("BMediaNode::HandleMessage NODE_SYNC_TO, node %ld\n",
671				fNodeID);
672
673			// If AddTimer return an error the caller will know that the node
674			// doesn't support this feature or there was a problem when adding
675			// it, this will result in SyncToNode returning immediately
676			// to the caller with an error.
677			status_t status = AddTimer(request->performance_time,
678				request->port);
679
680			request->SendReply(status, &reply, sizeof(reply));
681			return B_OK;
682		}
683
684		case NODE_SET_TIMESOURCE:
685		{
686			const node_set_timesource_command* command
687				= static_cast<const node_set_timesource_command*>(data);
688
689			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE,"
690				" node %ld, timesource %ld enter\n",
691				fNodeID, command->timesource_id);
692
693			fTimeSourceID = command->timesource_id;
694
695			if (fTimeSource) {
696				// As this node already had a timesource, to remove this node
697				// from time source control
698				fTimeSource->RemoveMe(this);
699				// Release the time source
700				fTimeSource->Release();
701				// Force next call to TimeSource() to create a new object
702				fTimeSource = 0;
703			}
704
705			// Create new time source object and call the SetTimeSource
706			// hook function to notify any derived class
707			fTimeSource = TimeSource();
708			SetTimeSource(fTimeSource);
709
710			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld,"
711				"timesource %ld leave\n", fNodeID, command->timesource_id);
712
713			return B_OK;
714		}
715
716		case NODE_GET_TIMESOURCE:
717		{
718			const node_get_timesource_request* request
719				= static_cast<const node_get_timesource_request*>(data);
720
721			TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE,"
722				" node %ld\n", fNodeID);
723
724			node_get_timesource_reply reply;
725			reply.timesource_id = fTimeSourceID;
726			request->SendReply(B_OK, &reply, sizeof(reply));
727			return B_OK;
728		}
729
730		case NODE_GET_ATTRIBUTES_FOR:
731		{
732			const node_get_attributes_for_request *request =
733				(const node_get_attributes_for_request*) data;
734
735			TRACE("BMediaNode::HandleMessage NODE_GET_ATTRIBUTES_FOR,"
736				"node %ld\n", fNodeID);
737
738			node_get_attributes_for_reply reply;
739
740			media_node_attribute* addr;
741			area_id dataArea = clone_area("client attributes area",
742				(void**)&addr, B_ANY_ADDRESS, B_WRITE_AREA,
743				request->area);
744
745			if (dataArea < 0) {
746				ERROR("NODE_GET_ATTRIBUTES_FOR can't clone area\n");
747				return B_NO_MEMORY;
748			}
749
750			status_t status = GetNodeAttributes(addr, request->count);
751			if (status == B_OK) {
752				// NOTE: we do it because there's not an easy way
753				// to guess the number of attributes filled.
754				size_t i;
755				for (i = 0; i < request->count; i++) {
756					if (addr[i].what <= 0)
757						break;
758				}
759				reply.filled_count = i;
760			}
761			request->SendReply(status, &reply, sizeof(reply));
762			delete_area(dataArea);
763			return B_OK;
764		}
765
766		case NODE_REQUEST_COMPLETED:
767		{
768			const node_request_completed_command* command
769				= static_cast<const node_request_completed_command*>(data);
770			TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED,"
771				" node %ld\n", fNodeID);
772			RequestCompleted(command->info);
773			return B_OK;
774		}
775
776		default:
777			return B_ERROR;
778
779	}
780	return B_ERROR;
781}
782
783
784void
785BMediaNode::HandleBadMessage(int32 code, const void* buffer, size_t size)
786{
787	CALLED();
788
789	TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n",
790		code, buffer, size);
791	if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) {
792		ERROR("BMediaNode::HandleBadMessage: unknown code!\n");
793	} else {
794		 // All messages targeted to nodes should be handled here,
795		 // messages targetted to the wrong node should be handled
796		 // by returning an error, not by stalling the sender.
797		const request_data* request = static_cast<const request_data* >(buffer);
798		reply_data reply;
799		request->SendReply(B_ERROR, &reply, sizeof(reply));
800	}
801}
802
803
804void
805BMediaNode::AddNodeKind(uint64 kind)
806{
807	TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this);
808	fKinds |= kind;
809}
810
811
812void*
813BMediaNode::operator new(size_t size)
814{
815	CALLED();
816	return ::operator new(size);
817}
818
819
820void*
821BMediaNode::operator new(size_t size, const nothrow_t&) throw()
822{
823	CALLED();
824	return ::operator new(size, nothrow);
825}
826
827
828void
829BMediaNode::operator delete(void* ptr)
830{
831	CALLED();
832	::operator delete(ptr);
833}
834
835
836void
837BMediaNode::operator delete(void* ptr, const nothrow_t&) throw()
838{
839	CALLED();
840	::operator delete(ptr, nothrow);
841}
842
843
844status_t
845BMediaNode::RequestCompleted(const media_request_info& info)
846{
847	CALLED();
848	// This function is called whenever
849	// a request issued by the node is completed.
850	// May be overriden by derived classes.
851	// info.change_tag can be used to match up requests against
852	// the accompaning calles from
853	// BBufferConsumer::RequestFormatChange()
854	// BBufferConsumer::SetOutputBuffersFor()
855	// BBufferConsumer::SetOutputEnabled()
856	// BBufferConsumer::SetVideoClippingFor()
857	return B_OK;
858}
859
860
861status_t
862BMediaNode::DeleteHook(BMediaNode* node)
863{
864	CALLED();
865	// Attention! We do not unregister TimeSourceObject nodes,
866	// since they are only a shadow object, and the real one still exists
867	if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0)
868		BMediaRoster::Roster()->UnregisterNode(this);
869	delete this; // delete "this" or "node", both are the same
870	return B_OK;
871}
872
873
874void
875BMediaNode::NodeRegistered()
876{
877	CALLED();
878	// The Media Server calls this hook function
879	// after the node has been registered.
880	// May be overriden by derived classes.
881}
882
883
884status_t
885BMediaNode::GetNodeAttributes(media_node_attribute* outAttributes,
886	size_t inMaxCount)
887{
888	CALLED();
889	// This is implemented by derived classes that fills
890	// it's own attributes to a max of inMaxCount elements.
891	return B_ERROR;
892}
893
894
895status_t
896BMediaNode::AddTimer(bigtime_t at_performance_time, int32 cookie)
897{
898	CALLED();
899	return B_ERROR;
900}
901
902
903status_t BMediaNode::_Reserved_MediaNode_0(void*) { return B_ERROR; }
904status_t BMediaNode::_Reserved_MediaNode_1(void*) { return B_ERROR; }
905status_t BMediaNode::_Reserved_MediaNode_2(void*) { return B_ERROR; }
906status_t BMediaNode::_Reserved_MediaNode_3(void*) { return B_ERROR; }
907status_t BMediaNode::_Reserved_MediaNode_4(void*) { return B_ERROR; }
908status_t BMediaNode::_Reserved_MediaNode_5(void*) { return B_ERROR; }
909status_t BMediaNode::_Reserved_MediaNode_6(void*) { return B_ERROR; }
910status_t BMediaNode::_Reserved_MediaNode_7(void*) { return B_ERROR; }
911status_t BMediaNode::_Reserved_MediaNode_8(void*) { return B_ERROR; }
912status_t BMediaNode::_Reserved_MediaNode_9(void*) { return B_ERROR; }
913status_t BMediaNode::_Reserved_MediaNode_10(void*) { return B_ERROR; }
914status_t BMediaNode::_Reserved_MediaNode_11(void*) { return B_ERROR; }
915status_t BMediaNode::_Reserved_MediaNode_12(void*) { return B_ERROR; }
916status_t BMediaNode::_Reserved_MediaNode_13(void*) { return B_ERROR; }
917status_t BMediaNode::_Reserved_MediaNode_14(void*) { return B_ERROR; }
918status_t BMediaNode::_Reserved_MediaNode_15(void*) { return B_ERROR; }
919
920/*
921private unimplemented
922BMediaNode::BMediaNode()
923BMediaNode::BMediaNode(const BMediaNode &clone)
924BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
925*/
926
927void
928BMediaNode::_InitObject(const char* name, media_node_id id, uint64 kinds)
929{
930	TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this);
931
932	fNodeID = id;
933	fRefCount = 1;
934	fName[0] = 0;
935	if (name)
936		strlcpy(fName, name, B_MEDIA_NAME_LENGTH);
937	fRunMode = B_INCREASE_LATENCY;
938	fKinds = kinds;
939	fProducerThis = 0;
940	fConsumerThis = 0;
941	fFileInterfaceThis = 0;
942	fControllableThis = 0;
943	fTimeSourceThis = 0;
944
945	// Create control port
946	fControlPort = create_port(64, fName);
947
948	// Nodes are assigned the system time source by default
949	fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID;
950
951	// We can't create the timesource object here, because
952	// every timesource is a BMediaNode, which would result
953	// in infinite recursions
954	fTimeSource = NULL;
955}
956
957
958BMediaNode::BMediaNode(const char* name, media_node_id id, uint32 kinds)
959{
960	TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n",
961		name, id, kinds);
962	_InitObject(name, id, kinds);
963}
964
965
966int32
967BMediaNode::NewChangeTag()
968{
969	CALLED();
970	// Change tags have been used in BeOS R4 to match up
971	// format change requests between producer and consumer,
972	// This has changed starting with R4.5
973	// now "change tags" are used with the following functions:
974	// BMediaNode::RequestCompleted()
975	// BBufferConsumer::RequestFormatChange()
976	// BBufferConsumer::SetOutputBuffersFor()
977	// BBufferConsumer::SetOutputEnabled()
978	// BBufferConsumer::SetVideoClippingFor()
979	return atomic_add(&BMediaNode::_m_changeTag,1);
980}
981
982// BeOS R4 deprecated API
983
984int32
985BMediaNode::IncrementChangeTag()
986{
987	CALLED();
988	// Only present in BeOS R4
989	// Obsoleted in BeOS R4.5 and later
990	// "updates the change tag, so that downstream consumers
991	// know that the node is in a new state."
992	// not supported, only for binary compatibility
993	return 0;
994}
995
996
997int32
998BMediaNode::ChangeTag()
999{
1000	UNIMPLEMENTED();
1001	// Only present in BeOS R4
1002	// Obsoleted in BeOS R4.5 and later
1003	// "returns the node's current change tag value."
1004	// not supported, only for binary compatibility
1005	return 0;
1006}
1007
1008
1009int32
1010BMediaNode::MintChangeTag()
1011{
1012	UNIMPLEMENTED();
1013	// Only present in BeOS R4
1014	// Obsoleted in BeOS R4.5 and later
1015	// "mints a new, reserved, change tag."
1016	// "Call ApplyChangeTag() to apply it to the node"
1017	// not supported, only for binary compatibility
1018	return 0;
1019}
1020
1021
1022status_t
1023BMediaNode::ApplyChangeTag(int32 previously_reserved)
1024{
1025	UNIMPLEMENTED();
1026	// Only present in BeOS R4
1027	// Obsoleted in BeOS R4.5 and later
1028	// "this returns B_OK if the new change tag is"
1029	// "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change"
1030	// "count you tried to apply is already obsolete."
1031	// not supported, only for binary compatibility
1032	return B_OK;
1033}
1034