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