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
68const media_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 %" B_PRId32
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 %" B_PRId32 " 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 %" B_PRId32 " 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: %#" B_PRIx32 ", node %"
385		B_PRId32 ", this %p\n", 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 %#" B_PRIx32", node %" B_PRId32 "\n",
571		message, fNodeID);
572	switch (message) {
573		case NODE_FINAL_RELEASE:
574		{
575			TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n",
576				this);
577
578			// This is called by the media server to delete the object
579			// after is has been released by all nodes that are using it.
580			// We forward the function to the BMediaRoster, since the
581			// deletion must be done from a different thread, or the
582			// outermost destructor that will exit the thread that is
583			// reading messages from the port (this thread contex) will
584			// quit, and ~BMediaNode destructor won't be called ever.
585			BMessage msg(NODE_FINAL_RELEASE);
586			msg.AddPointer("node", this);
587			BMediaRoster::Roster()->PostMessage(&msg);
588			return B_OK;
589		}
590
591		case NODE_START:
592		{
593			const node_start_command* command
594				= static_cast<const node_start_command*>(data);
595			TRACE("BMediaNode::HandleMessage NODE_START, node %" B_PRId32 "\n",
596				fNodeID);
597			Start(command->performance_time);
598			return B_OK;
599		}
600
601		case NODE_STOP:
602		{
603			const node_stop_command* command
604				= static_cast<const node_stop_command*>(data);
605			TRACE("BMediaNode::HandleMessage NODE_STOP, node %" B_PRId32 "\n",
606				fNodeID);
607			Stop(command->performance_time, command->immediate);
608			return B_OK;
609		}
610
611		case NODE_SEEK:
612		{
613			const node_seek_command* command
614				= static_cast<const node_seek_command*>(data);
615			TRACE("BMediaNode::HandleMessage NODE_SEEK, node %" B_PRId32 "\n",
616				fNodeID);
617			Seek(command->media_time, command->performance_time);
618			return B_OK;
619		}
620
621		case NODE_SET_RUN_MODE:
622		{
623			const node_set_run_mode_command* command
624				= static_cast<const node_set_run_mode_command*>(data);
625			TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE,"
626				" node %" B_PRId32 "\n", fNodeID);
627			// Need to change PRODUCER_SET_RUN_MODE_DELAY
628			fRunMode = command->mode;
629			SetRunMode(fRunMode);
630			return B_OK;
631		}
632
633		case NODE_TIME_WARP:
634		{
635			const node_time_warp_command* command
636				= static_cast<const node_time_warp_command*>(data);
637			TRACE("BMediaNode::HandleMessage NODE_TIME_WARP,"
638				" node %" B_PRId32 "\n", fNodeID);
639			TimeWarp(command->at_real_time, command->to_performance_time);
640			return B_OK;
641		}
642
643		case NODE_PREROLL:
644		{
645			TRACE("BMediaNode::HandleMessage NODE_PREROLL, "
646				" node %" B_PRId32 "\n", fNodeID);
647			Preroll();
648			return B_OK;
649		}
650
651		case NODE_ROLL:
652		{
653			const node_roll_command* command
654				= static_cast<const node_roll_command*>(data);
655
656			TRACE("BMediaNode::HandleMessage NODE_ROLL, node %" B_PRId32 "\n",
657				fNodeID);
658
659			if (command->seek_media_time != B_INFINITE_TIMEOUT)
660				Seek(command->seek_media_time,
661					command->start_performance_time);
662
663			Start(command->start_performance_time);
664			Stop(command->stop_performance_time, false);
665			return B_OK;
666		}
667
668		case NODE_SYNC_TO:
669		{
670			const node_sync_to_request* request
671				= static_cast<const node_sync_to_request*>(data);
672			node_sync_to_reply reply;
673
674			TRACE("BMediaNode::HandleMessage NODE_SYNC_TO, node %" B_PRId32
675				"\n", fNodeID);
676
677			// If AddTimer return an error the caller will know that the node
678			// doesn't support this feature or there was a problem when adding
679			// it, this will result in SyncToNode returning immediately
680			// to the caller with an error.
681			status_t status = AddTimer(request->performance_time,
682				request->port);
683
684			request->SendReply(status, &reply, sizeof(reply));
685			return B_OK;
686		}
687
688		case NODE_SET_TIMESOURCE:
689		{
690			const node_set_timesource_command* command
691				= static_cast<const node_set_timesource_command*>(data);
692
693			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE,"
694				" node %" B_PRId32 ", timesource %" B_PRId32 " enter\n",
695				fNodeID, command->timesource_id);
696
697			fTimeSourceID = command->timesource_id;
698
699			if (fTimeSource) {
700				// As this node already had a timesource, to remove this node
701				// from time source control
702				fTimeSource->RemoveMe(this);
703				// Release the time source
704				fTimeSource->Release();
705				// Force next call to TimeSource() to create a new object
706				fTimeSource = 0;
707			}
708
709			// Create new time source object and call the SetTimeSource
710			// hook function to notify any derived class
711			fTimeSource = TimeSource();
712			SetTimeSource(fTimeSource);
713
714			TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %"
715				B_PRId32 ", timesource %" B_PRId32 " leave\n", fNodeID,
716				command->timesource_id);
717
718			return B_OK;
719		}
720
721		case NODE_GET_TIMESOURCE:
722		{
723			const node_get_timesource_request* request
724				= static_cast<const node_get_timesource_request*>(data);
725
726			TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE,"
727				" node %" B_PRId32 "\n", fNodeID);
728
729			node_get_timesource_reply reply;
730			reply.timesource_id = fTimeSourceID;
731			request->SendReply(B_OK, &reply, sizeof(reply));
732			return B_OK;
733		}
734
735		case NODE_GET_ATTRIBUTES_FOR:
736		{
737			const node_get_attributes_for_request *request =
738				(const node_get_attributes_for_request*) data;
739
740			TRACE("BMediaNode::HandleMessage NODE_GET_ATTRIBUTES_FOR,"
741				"node %" B_PRId32 "\n", fNodeID);
742
743			node_get_attributes_for_reply reply;
744
745			media_node_attribute* addr;
746			area_id dataArea = clone_area("client attributes area",
747				(void**)&addr, B_ANY_ADDRESS, B_WRITE_AREA,
748				request->area);
749
750			if (dataArea < 0) {
751				ERROR("NODE_GET_ATTRIBUTES_FOR can't clone area\n");
752				return B_NO_MEMORY;
753			}
754
755			status_t status = GetNodeAttributes(addr, request->count);
756			if (status == B_OK) {
757				// NOTE: we do it because there's not an easy way
758				// to guess the number of attributes filled.
759				size_t i;
760				for (i = 0; i < request->count; i++) {
761					if (addr[i].what <= 0)
762						break;
763				}
764				reply.filled_count = i;
765			}
766			request->SendReply(status, &reply, sizeof(reply));
767			delete_area(dataArea);
768			return B_OK;
769		}
770
771		case NODE_REQUEST_COMPLETED:
772		{
773			const node_request_completed_command* command
774				= static_cast<const node_request_completed_command*>(data);
775			TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED,"
776				" node %" B_PRId32 "\n", fNodeID);
777			RequestCompleted(command->info);
778			return B_OK;
779		}
780
781		default:
782			return B_ERROR;
783
784	}
785	return B_ERROR;
786}
787
788
789void
790BMediaNode::HandleBadMessage(int32 code, const void* buffer, size_t size)
791{
792	CALLED();
793
794	TRACE("BMediaNode::HandleBadMessage: code %#08" B_PRIx32 ", buffer %p, size %"
795		B_PRIuSIZE "\n", code, buffer, size);
796	if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) {
797		ERROR("BMediaNode::HandleBadMessage: unknown code!\n");
798	} else {
799		 // All messages targeted to nodes should be handled here,
800		 // messages targetted to the wrong node should be handled
801		 // by returning an error, not by stalling the sender.
802		const request_data* request = static_cast<const request_data* >(buffer);
803		reply_data reply;
804		request->SendReply(B_ERROR, &reply, sizeof(reply));
805	}
806}
807
808
809void
810BMediaNode::AddNodeKind(uint64 kind)
811{
812	TRACE("BMediaNode::AddNodeKind: node %" B_PRId32 ", this %p\n", fNodeID,
813		this);
814	fKinds |= kind;
815}
816
817
818void*
819BMediaNode::operator new(size_t size)
820{
821	CALLED();
822	return ::operator new(size);
823}
824
825
826void*
827BMediaNode::operator new(size_t size, const nothrow_t&) throw()
828{
829	CALLED();
830	return ::operator new(size, nothrow);
831}
832
833
834void
835BMediaNode::operator delete(void* ptr)
836{
837	CALLED();
838	::operator delete(ptr);
839}
840
841
842void
843BMediaNode::operator delete(void* ptr, const nothrow_t&) throw()
844{
845	CALLED();
846	::operator delete(ptr, nothrow);
847}
848
849
850status_t
851BMediaNode::RequestCompleted(const media_request_info& info)
852{
853	CALLED();
854	// This function is called whenever
855	// a request issued by the node is completed.
856	// May be overriden by derived classes.
857	// info.change_tag can be used to match up requests against
858	// the accompaning calles from
859	// BBufferConsumer::RequestFormatChange()
860	// BBufferConsumer::SetOutputBuffersFor()
861	// BBufferConsumer::SetOutputEnabled()
862	// BBufferConsumer::SetVideoClippingFor()
863	return B_OK;
864}
865
866
867status_t
868BMediaNode::DeleteHook(BMediaNode* node)
869{
870	CALLED();
871	// Attention! We do not unregister TimeSourceObject nodes,
872	// since they are only a shadow object, and the real one still exists
873	if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0)
874		BMediaRoster::Roster()->UnregisterNode(this);
875	delete this; // delete "this" or "node", both are the same
876	return B_OK;
877}
878
879
880void
881BMediaNode::NodeRegistered()
882{
883	CALLED();
884	// The Media Server calls this hook function
885	// after the node has been registered.
886	// May be overriden by derived classes.
887}
888
889
890status_t
891BMediaNode::GetNodeAttributes(media_node_attribute* outAttributes,
892	size_t inMaxCount)
893{
894	CALLED();
895	// This is implemented by derived classes that fills
896	// it's own attributes to a max of inMaxCount elements.
897	return B_ERROR;
898}
899
900
901status_t
902BMediaNode::AddTimer(bigtime_t at_performance_time, int32 cookie)
903{
904	CALLED();
905	return B_ERROR;
906}
907
908
909status_t BMediaNode::_Reserved_MediaNode_0(void*) { return B_ERROR; }
910status_t BMediaNode::_Reserved_MediaNode_1(void*) { return B_ERROR; }
911status_t BMediaNode::_Reserved_MediaNode_2(void*) { return B_ERROR; }
912status_t BMediaNode::_Reserved_MediaNode_3(void*) { return B_ERROR; }
913status_t BMediaNode::_Reserved_MediaNode_4(void*) { return B_ERROR; }
914status_t BMediaNode::_Reserved_MediaNode_5(void*) { return B_ERROR; }
915status_t BMediaNode::_Reserved_MediaNode_6(void*) { return B_ERROR; }
916status_t BMediaNode::_Reserved_MediaNode_7(void*) { return B_ERROR; }
917status_t BMediaNode::_Reserved_MediaNode_8(void*) { return B_ERROR; }
918status_t BMediaNode::_Reserved_MediaNode_9(void*) { return B_ERROR; }
919status_t BMediaNode::_Reserved_MediaNode_10(void*) { return B_ERROR; }
920status_t BMediaNode::_Reserved_MediaNode_11(void*) { return B_ERROR; }
921status_t BMediaNode::_Reserved_MediaNode_12(void*) { return B_ERROR; }
922status_t BMediaNode::_Reserved_MediaNode_13(void*) { return B_ERROR; }
923status_t BMediaNode::_Reserved_MediaNode_14(void*) { return B_ERROR; }
924status_t BMediaNode::_Reserved_MediaNode_15(void*) { return B_ERROR; }
925
926/*
927private unimplemented
928BMediaNode::BMediaNode()
929BMediaNode::BMediaNode(const BMediaNode &clone)
930BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
931*/
932
933void
934BMediaNode::_InitObject(const char* name, media_node_id id, uint64 kinds)
935{
936	TRACE("BMediaNode::_InitObject: nodeid %" B_PRId32 ", this %p\n", id,
937		this);
938
939	fNodeID = id;
940	fRefCount = 1;
941	fName[0] = 0;
942	if (name)
943		strlcpy(fName, name, B_MEDIA_NAME_LENGTH);
944	fRunMode = B_INCREASE_LATENCY;
945	fKinds = kinds;
946	fProducerThis = 0;
947	fConsumerThis = 0;
948	fFileInterfaceThis = 0;
949	fControllableThis = 0;
950	fTimeSourceThis = 0;
951
952	// Create control port
953	fControlPort = create_port(64, fName);
954
955	// Nodes are assigned the system time source by default
956	fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID;
957
958	// We can't create the timesource object here, because
959	// every timesource is a BMediaNode, which would result
960	// in infinite recursions
961	fTimeSource = NULL;
962}
963
964
965BMediaNode::BMediaNode(const char* name, media_node_id id, uint32 kinds)
966{
967	TRACE("BMediaNode::BMediaNode: name '%s', nodeid %" B_PRId32 ", kinds %#"
968		B_PRIx32 "\n", name, id, kinds);
969	_InitObject(name, id, kinds);
970}
971
972
973int32
974BMediaNode::NewChangeTag()
975{
976	CALLED();
977	// Change tags have been used in BeOS R4 to match up
978	// format change requests between producer and consumer,
979	// This has changed starting with R4.5
980	// now "change tags" are used with the following functions:
981	// BMediaNode::RequestCompleted()
982	// BBufferConsumer::RequestFormatChange()
983	// BBufferConsumer::SetOutputBuffersFor()
984	// BBufferConsumer::SetOutputEnabled()
985	// BBufferConsumer::SetVideoClippingFor()
986	return atomic_add(&BMediaNode::_m_changeTag,1);
987}
988
989// BeOS R4 deprecated API
990
991int32
992BMediaNode::IncrementChangeTag()
993{
994	CALLED();
995	// Only present in BeOS R4
996	// Obsoleted in BeOS R4.5 and later
997	// "updates the change tag, so that downstream consumers
998	// know that the node is in a new state."
999	// not supported, only for binary compatibility
1000	return 0;
1001}
1002
1003
1004int32
1005BMediaNode::ChangeTag()
1006{
1007	UNIMPLEMENTED();
1008	// Only present in BeOS R4
1009	// Obsoleted in BeOS R4.5 and later
1010	// "returns the node's current change tag value."
1011	// not supported, only for binary compatibility
1012	return 0;
1013}
1014
1015
1016int32
1017BMediaNode::MintChangeTag()
1018{
1019	UNIMPLEMENTED();
1020	// Only present in BeOS R4
1021	// Obsoleted in BeOS R4.5 and later
1022	// "mints a new, reserved, change tag."
1023	// "Call ApplyChangeTag() to apply it to the node"
1024	// not supported, only for binary compatibility
1025	return 0;
1026}
1027
1028
1029status_t
1030BMediaNode::ApplyChangeTag(int32 previously_reserved)
1031{
1032	UNIMPLEMENTED();
1033	// Only present in BeOS R4
1034	// Obsoleted in BeOS R4.5 and later
1035	// "this returns B_OK if the new change tag is"
1036	// "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change"
1037	// "count you tried to apply is already obsolete."
1038	// not supported, only for binary compatibility
1039	return B_OK;
1040}
1041