xref: /haiku/src/kits/media/MediaNode.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
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 
52 using std::nothrow;
53 using std::nothrow_t;
54 
55 #undef TRACE
56 //#define TRACE_MEDIA_NODE
57 #ifdef TRACE_MEDIA_NODE
58   #define TRACE printf
59 #else
60   #define TRACE(x...)
61 #endif
62 
63 // Don't rename this one, it's used and exported for binary compatibility
64 int32 BMediaNode::_m_changeTag = 0;
65 
66 // media_node
67 
68 const media_node media_node::null;
69 
media_node()70 media_node::media_node()
71 	:
72 	node(-1),
73 	port(-1),
74 	kind(0)
75 {
76 }
77 
78 
~media_node()79 media_node::~media_node()
80 {
81 }
82 
83 // media_input
84 
media_input()85 media_input::media_input()
86 {
87 	name[0] = '\0';
88 }
89 
90 
~media_input()91 media_input::~media_input()
92 {
93 }
94 
95 // media_output
96 
media_output()97 media_output::media_output()
98 {
99 	name[0] = '\0';
100 }
101 
102 
~media_output()103 media_output::~media_output()
104 {
105 }
106 
107 // live_node_info
108 
live_node_info()109 live_node_info::live_node_info()
110 	:
111 	hint_point(0.0f, 0.0f)
112 {
113 	name[0] = '\0';
114 }
115 
116 
~live_node_info()117 live_node_info::~live_node_info()
118 {
119 }
120 
121 // BMediaNode
122 
~BMediaNode()123 BMediaNode::~BMediaNode()
124 {
125 	CALLED();
126 	// BeBook: UnregisterNode() unregisters a node from the Media Server.
127 	// It's called automatically by the BMediaNode destructor, but it might
128 	// be convenient to call it sometime before you delete your node instance,
129 	// depending on your implementation and circumstances.
130 
131 	// First we remove the time source
132 	if (fTimeSource) {
133 		fTimeSource->RemoveMe(this);
134 		fTimeSource->Release();
135 		fTimeSource = NULL;
136 	}
137 
138 	// Attention! We do not delete their control ports, since they are only a
139 	// shadow object, and the real one still exists
140 	if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0) {
141 		if (fControlPort > 0)
142 			delete_port(fControlPort);
143 	} else {
144 		TRACE("BMediaNode::~BMediaNode: shadow timesource,"
145 			" not unregistering\n");
146 	}
147 }
148 
149 
150 BMediaNode*
Acquire()151 BMediaNode::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 
164 BMediaNode*
Release()165 BMediaNode::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 
194 const char*
Name() const195 BMediaNode::Name() const
196 {
197 	CALLED();
198 	return fName;
199 }
200 
201 
202 media_node_id
ID() const203 BMediaNode::ID() const
204 {
205 	CALLED();
206 	return fNodeID;
207 }
208 
209 
210 uint64
Kinds() const211 BMediaNode::Kinds() const
212 {
213 	CALLED();
214 	return fKinds & NODE_KIND_USER_MASK;
215 }
216 
217 
218 media_node
Node() const219 BMediaNode::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 
232 BMediaNode::run_mode
RunMode() const233 BMediaNode::RunMode() const
234 {
235 	CALLED();
236 	return fRunMode;
237 }
238 
239 
240 BTimeSource*
TimeSource() const241 BMediaNode::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 
275 port_id
ControlPort() const276 BMediaNode::ControlPort() const
277 {
278 	PRINT(7, "CALLED BMediaNode::ControlPort()\n");
279 	return fControlPort;
280 }
281 
282 
283 status_t
ReportError(node_error what,const BMessage * info)284 BMediaNode::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 
310 status_t
NodeStopped(bigtime_t whenPerformance)311 BMediaNode::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  */
333 void
TimerExpired(bigtime_t notifyPoint,int32 cookie,status_t error)334 BMediaNode::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 
BMediaNode(const char * name)344 BMediaNode::BMediaNode(const char* name)
345 {
346 	TRACE("BMediaNode::BMediaNode: name '%s'\n", name);
347 	_InitObject(name, NODE_JUST_CREATED_ID, 0);
348 }
349 
350 
351 status_t
WaitForMessage(bigtime_t waitUntil,uint32 flags,void * _reserved_)352 BMediaNode::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 
477 void
Start(bigtime_t performance_time)478 BMediaNode::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 
491 void
Stop(bigtime_t performance_time,bool immediate)492 BMediaNode::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 
505 void
Seek(bigtime_t media_time,bigtime_t performance_time)506 BMediaNode::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 
520 void
SetRunMode(run_mode mode)521 BMediaNode::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 
535 void
TimeWarp(bigtime_t at_real_time,bigtime_t to_performance_time)536 BMediaNode::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
537 {
538 	CALLED();
539 	// May be overriden by derived classes.
540 }
541 
542 
543 void
Preroll()544 BMediaNode::Preroll()
545 {
546 	CALLED();
547 	// May be overriden by derived classes.
548 }
549 
550 
551 void
SetTimeSource(BTimeSource * time_source)552 BMediaNode::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 
567 status_t
HandleMessage(int32 message,const void * data,size_t size)568 BMediaNode::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 
789 void
HandleBadMessage(int32 code,const void * buffer,size_t size)790 BMediaNode::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 
809 void
AddNodeKind(uint64 kind)810 BMediaNode::AddNodeKind(uint64 kind)
811 {
812 	TRACE("BMediaNode::AddNodeKind: node %" B_PRId32 ", this %p\n", fNodeID,
813 		this);
814 	fKinds |= kind;
815 }
816 
817 
818 void*
operator new(size_t size)819 BMediaNode::operator new(size_t size)
820 {
821 	CALLED();
822 	return ::operator new(size);
823 }
824 
825 
826 void*
operator new(size_t size,const nothrow_t &)827 BMediaNode::operator new(size_t size, const nothrow_t&) throw()
828 {
829 	CALLED();
830 	return ::operator new(size, nothrow);
831 }
832 
833 
834 void
operator delete(void * ptr)835 BMediaNode::operator delete(void* ptr)
836 {
837 	CALLED();
838 	::operator delete(ptr);
839 }
840 
841 
842 void
operator delete(void * ptr,const nothrow_t &)843 BMediaNode::operator delete(void* ptr, const nothrow_t&) throw()
844 {
845 	CALLED();
846 	::operator delete(ptr, nothrow);
847 }
848 
849 
850 status_t
RequestCompleted(const media_request_info & info)851 BMediaNode::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 
867 status_t
DeleteHook(BMediaNode * node)868 BMediaNode::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 
880 void
NodeRegistered()881 BMediaNode::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 
890 status_t
GetNodeAttributes(media_node_attribute * outAttributes,size_t inMaxCount)891 BMediaNode::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 
901 status_t
AddTimer(bigtime_t at_performance_time,int32 cookie)902 BMediaNode::AddTimer(bigtime_t at_performance_time, int32 cookie)
903 {
904 	CALLED();
905 	return B_ERROR;
906 }
907 
908 
_Reserved_MediaNode_0(void *)909 status_t BMediaNode::_Reserved_MediaNode_0(void*) { return B_ERROR; }
_Reserved_MediaNode_1(void *)910 status_t BMediaNode::_Reserved_MediaNode_1(void*) { return B_ERROR; }
_Reserved_MediaNode_2(void *)911 status_t BMediaNode::_Reserved_MediaNode_2(void*) { return B_ERROR; }
_Reserved_MediaNode_3(void *)912 status_t BMediaNode::_Reserved_MediaNode_3(void*) { return B_ERROR; }
_Reserved_MediaNode_4(void *)913 status_t BMediaNode::_Reserved_MediaNode_4(void*) { return B_ERROR; }
_Reserved_MediaNode_5(void *)914 status_t BMediaNode::_Reserved_MediaNode_5(void*) { return B_ERROR; }
_Reserved_MediaNode_6(void *)915 status_t BMediaNode::_Reserved_MediaNode_6(void*) { return B_ERROR; }
_Reserved_MediaNode_7(void *)916 status_t BMediaNode::_Reserved_MediaNode_7(void*) { return B_ERROR; }
_Reserved_MediaNode_8(void *)917 status_t BMediaNode::_Reserved_MediaNode_8(void*) { return B_ERROR; }
_Reserved_MediaNode_9(void *)918 status_t BMediaNode::_Reserved_MediaNode_9(void*) { return B_ERROR; }
_Reserved_MediaNode_10(void *)919 status_t BMediaNode::_Reserved_MediaNode_10(void*) { return B_ERROR; }
_Reserved_MediaNode_11(void *)920 status_t BMediaNode::_Reserved_MediaNode_11(void*) { return B_ERROR; }
_Reserved_MediaNode_12(void *)921 status_t BMediaNode::_Reserved_MediaNode_12(void*) { return B_ERROR; }
_Reserved_MediaNode_13(void *)922 status_t BMediaNode::_Reserved_MediaNode_13(void*) { return B_ERROR; }
_Reserved_MediaNode_14(void *)923 status_t BMediaNode::_Reserved_MediaNode_14(void*) { return B_ERROR; }
_Reserved_MediaNode_15(void *)924 status_t BMediaNode::_Reserved_MediaNode_15(void*) { return B_ERROR; }
925 
926 /*
927 private unimplemented
928 BMediaNode::BMediaNode()
929 BMediaNode::BMediaNode(const BMediaNode &clone)
930 BMediaNode &BMediaNode::operator=(const BMediaNode &clone)
931 */
932 
933 void
_InitObject(const char * name,media_node_id id,uint64 kinds)934 BMediaNode::_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 
BMediaNode(const char * name,media_node_id id,uint32 kinds)965 BMediaNode::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 
973 int32
NewChangeTag()974 BMediaNode::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 
991 int32
IncrementChangeTag()992 BMediaNode::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 
1004 int32
ChangeTag()1005 BMediaNode::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 
1016 int32
MintChangeTag()1017 BMediaNode::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 
1029 status_t
ApplyChangeTag(int32 previously_reserved)1030 BMediaNode::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