1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 // NodeManager.cpp
33
34 #include "NodeManager.h"
35
36 #include "AddOnHost.h"
37 #include "Connection.h"
38 #include "NodeGroup.h"
39 #include "NodeRef.h"
40
41 #include <Debug.h>
42 #include <MediaRoster.h>
43
44 #include <algorithm>
45 #include <cstring>
46 #include <functional>
47 #include <list>
48 #include <set>
49 // Locale Kit
50 #undef B_CATALOG
51 #define B_CATALOG (&sCatalog)
52 #include <Catalog.h>
53
54 #undef B_TRANSLATION_CONTEXT
55 #define B_TRANSLATION_CONTEXT "NodeManager"
56
57 #include "set_tools.h"
58 #include "functional_tools.h"
59
60 #include "node_manager_impl.h"
61
62 using namespace std;
63
64 __USE_CORTEX_NAMESPACE
65
66 #define D_METHOD(x) //PRINT (x)
67 #define D_MESSAGE(x) //PRINT (x)
68 #define D_ROSTER(x) //PRINT (x)
69 #define D_LOCK(x) //PRINT (x)
70
71 static BCatalog sCatalog("x-vnd.Cortex.NodeManager");
72
73 // -------------------------------------------------------- //
74 // messaging constants
75 // -------------------------------------------------------- //
76
77 // B_MEDIA_CONNECTION_BROKEN
78 const char* const _connectionField = "__connection_id";
79 const char* const _sourceNodeField = "__source_node_id";
80 const char* const _destNodeField = "__destination_node_id";
81
82
83
84
85 // -------------------------------------------------------- //
86 // *** hooks
87 // -------------------------------------------------------- //
88
89 // [e.moon 7nov99] these hooks are called during processing of
90 // BMediaRoster messages, before any notification is sent to
91 // observers. For example, if a B_MEDIA_NODES_CREATED message
92 // were received describing 3 new nodes, nodeCreated() would be
93 // called 3 times before the notification was sent.
94
nodeCreated(NodeRef * ref)95 void NodeManager::nodeCreated(
96 NodeRef* ref) {}
97
nodeDeleted(const NodeRef * ref)98 void NodeManager::nodeDeleted(
99 const NodeRef* ref) {}
100
connectionMade(Connection * connection)101 void NodeManager::connectionMade(
102 Connection* connection) {}
103
connectionBroken(const Connection * connection)104 void NodeManager::connectionBroken(
105 const Connection* connection) {}
106
connectionFailed(const media_output & output,const media_input & input,const media_format & format,status_t error)107 void NodeManager::connectionFailed(
108 const media_output & output,
109 const media_input & input,
110 const media_format & format,
111 status_t error) {}
112
113 // -------------------------------------------------------- //
114 // helpers
115 // -------------------------------------------------------- //
116
117 class _for_each_state {
118 public:
119 // marks nodes visited
120 set<media_node_id> visited;
121 };
122
123 // [e.moon 28sep99] graph crawling
124 // - does NOT apply operation to origin node.
125 // - if inGroup is non-0, visits only nodes in that group.
126 //
127 // [e.moon 13oct99]: no longer supports locking (use _lockAllGroups() to
128 // be sure all nodes are locked, if necessary.)
129
130 template<class Op>
_do_for_each_connected(NodeManager * manager,NodeRef * origin,NodeGroup * inGroup,bool recurse,Op operation,_for_each_state * state)131 void _do_for_each_connected(
132 NodeManager* manager,
133 NodeRef* origin,
134 NodeGroup* inGroup,
135 bool recurse,
136 Op operation,
137 _for_each_state* state) {
138
139 // PRINT(("### _do_for_each_connected()\n"));
140
141 ASSERT(manager->IsLocked());
142
143 ASSERT(origin);
144 ASSERT(state);
145 status_t err __attribute__((unused));
146
147 if(state->visited.find(origin->id()) != state->visited.end()) {
148 // PRINT(("### already visited\n"));
149 // already visited
150 return;
151 }
152
153 // used to walk connections
154 vector<Connection> connections;
155
156 // mark visited
157 state->visited.insert(origin->id());
158
159 // walk input connections
160 origin->getInputConnections(connections);
161 for(uint32 n = 0; n < connections.size(); ++n) {
162
163 if(!connections[n].isValid())
164 continue;
165
166 // PRINT(("# source: %ld\n", connections[n].sourceNode()));
167
168 NodeRef* targetRef;
169 err = manager->getNodeRef(
170 connections[n].sourceNode(),
171 &targetRef);
172 ASSERT(err == B_OK);
173 ASSERT(targetRef);
174
175 if(inGroup && targetRef->group() != inGroup) {
176 // PRINT(("# .group mismatch\n"));
177 // don't need to visit
178 return;
179 }
180
181 // invoke operation
182 // if(lockRef)
183 // targetRef->lock();
184 operation(targetRef);
185 // if(lockRef)
186 // targetRef->unlock();
187
188 // recurse?
189 if(recurse)
190 _do_for_each_connected(
191 manager,
192 targetRef,
193 inGroup,
194 true,
195 operation,
196 state);
197 }
198
199 // walk output connections
200 connections.clear();
201 origin->getOutputConnections(connections);
202 for(uint32 n = 0; n < connections.size(); ++n) {
203 // PRINT(("# dest: %ld\n", connections[n].destinationNode()));
204
205 if(!connections[n].isValid())
206 continue;
207
208 NodeRef* targetRef;
209 err = manager->getNodeRef(
210 connections[n].destinationNode(),
211 &targetRef);
212 ASSERT(err == B_OK);
213 ASSERT(targetRef);
214
215 if(inGroup && targetRef->group() != inGroup) {
216 // PRINT(("# .group mismatch\n"));
217 // don't need to visit
218 return;
219 }
220
221 // invoke operation
222 // if(lockRef)
223 // targetRef->lock();
224 operation(targetRef);
225 // if(lockRef)
226 // targetRef->unlock();
227
228 // recurse?
229 if(recurse)
230 _do_for_each_connected(
231 manager,
232 targetRef,
233 inGroup,
234 true,
235 operation,
236 state);
237 }
238 }
239
240 // dtor helpers
_clearGroup(NodeGroup * group)241 inline void NodeManager::_clearGroup(
242 NodeGroup* group) {
243 Autolock _l(group);
244 D_METHOD((
245 "NodeManager::_clearGroup()\n"));
246
247 // stop group before clearing [10aug99]
248 group->_stop();
249
250 int32 n;
251 while((n = group->countNodes()) > 0) {
252 group->removeNode(n-1);
253 }
254
255 // // [e.moon 7nov99] release the group
256 // status_t err = remove_observer(this, group);
257 // if(err < B_OK) {
258 // // spew diagnostics
259 // PRINT((
260 // "!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n"
261 // " %s\n",
262 // group->id(),
263 // strerror(err)));
264 // }
265 }
266
_freeConnection(Connection * connection)267 inline void NodeManager::_freeConnection(
268 Connection* connection) {
269 ASSERT(connection);
270
271 D_METHOD((
272 "NodeManager::_freeConnection(%ld)\n", connection->id()));
273 status_t err;
274
275 // break if internal & still valid
276 if(
277 connection->isValid() &&
278 connection->flags() & Connection::INTERNAL &&
279 !(connection->flags() & Connection::LOCKED)) {
280
281 D_METHOD((
282 "! breaking connection:\n"
283 " source node: %ld\n"
284 " source id: %ld\n"
285 " source port: %ld\n"
286 " dest node: %ld\n"
287 " dest id: %ld\n"
288 " dest port: %ld\n",
289 connection->sourceNode(),
290 connection->source().id, connection->source().port,
291 connection->destinationNode(),
292 connection->destination().id, connection->destination().port));
293
294 // do it
295 D_ROSTER(("# roster->Disconnect()\n"));
296 err = roster->Disconnect(
297 connection->sourceNode(),
298 connection->source(),
299 connection->destinationNode(),
300 connection->destination());
301
302 if(err < B_OK) {
303 D_METHOD((
304 "!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n"
305 " %s\n",
306 connection->outputName(), connection->inputName(),
307 strerror(err)));
308 }
309 }
310
311 // delete
312 delete connection;
313 }
314
315 // -------------------------------------------------------- //
316 // *** ctor/dtor
317 // -------------------------------------------------------- //
318
319
~NodeManager()320 NodeManager::~NodeManager() {
321 D_METHOD((
322 "~NodeManager()\n"));
323 ASSERT(IsLocked());
324
325 // make a list of nodes to be released
326 list<NodeRef*> deadNodes;
327
328 for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
329 it != m_nodeRefMap.end(); ++it) {
330 deadNodes.push_back((*it).second);
331 }
332
333 // ungroup all nodes
334
335 // [e.moon 13oct99] making PPC compiler happy
336 // for_each(
337 // m_nodeGroupSet.begin(),
338 // m_nodeGroupSet.end(),
339 // bound_method(
340 // *this,
341 // &NodeManager::_clearGroup
342 // )
343 // );
344 for(node_group_set::iterator it = m_nodeGroupSet.begin();
345 it != m_nodeGroupSet.end(); ++it) {
346 _clearGroup(*it);
347 }
348
349 // delete groups
350 ptr_set_delete(
351 m_nodeGroupSet.begin(),
352 m_nodeGroupSet.end());
353 m_nodeGroupSet.clear();
354
355
356 // deallocate all connections; disconnect internal nodes
357 // [e.moon 13oct99] making PPC compiler happy
358 // for_each(
359 // m_conSourceMap.begin(),
360 // m_conSourceMap.end(),
361 // unary_map_function(
362 // m_conSourceMap,
363 // bound_method(
364 // *this,
365 // &NodeManager::_freeConnection
366 // )
367 // )
368 // );
369 for(con_map::iterator it = m_conSourceMap.begin();
370 it != m_conSourceMap.end(); ++it) {
371 _freeConnection((*it).second);
372 }
373 m_conSourceMap.clear();
374 m_conDestinationMap.clear();
375
376 // release all nodes
377 for(list<NodeRef*>::const_iterator it = deadNodes.begin();
378 it != deadNodes.end(); ++it) {
379 (*it)->release();
380 }
381
382 if(m_nodeRefMap.size()) {
383 // +++++ nodes will only remain if they have observers; cope!
384 PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap.size()));
385
386 deadNodes.clear();
387 for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
388 it != m_nodeRefMap.end(); ++it)
389 deadNodes.push_back((*it).second);
390
391 ptr_set_delete(
392 deadNodes.begin(),
393 deadNodes.end());
394 }
395
396 // for_each(
397 // m_nodeRefMap.begin(),
398 // m_nodeRefMap.end(),
399 // unary_map_function(
400 // m_nodeRefMap,
401 // mem_fun(
402 // &NodeRef::release
403 // )
404 // )
405 // );
406 //
407 // // delete all nodes
408 // ptr_map_delete(
409 // m_nodeRefMap.begin(),
410 // m_nodeRefMap.end());
411 //
412 //
413 // PRINT((
414 // "~NodeManager() done\n"));
415 //
416 }
417
418 const char* const
419 NodeManager::s_defaultGroupPrefix = B_TRANSLATE("No name");
420 const char* const
421 NodeManager::s_timeSourceGroup = B_TRANSLATE("Time sources");
422 const char* const
423 NodeManager::s_audioInputGroup = B_TRANSLATE("System audio input");
424 const char* const
425 NodeManager::s_videoInputGroup = B_TRANSLATE("System video input");
426 const char* const
427 NodeManager::s_audioMixerGroup = B_TRANSLATE("System audio mixer");
428 const char* const
429 NodeManager::s_videoOutputGroup = B_TRANSLATE("System video output");
430
NodeManager(bool useAddOnHost)431 NodeManager::NodeManager(
432 bool useAddOnHost) :
433
434 ObservableLooper("NodeManager"),
435 roster(BMediaRoster::Roster()),
436 m_audioInputNode(0),
437 m_videoInputNode(0),
438 m_audioMixerNode(0),
439 m_audioOutputNode(0),
440 m_videoOutputNode(0),
441 m_nextConID(1),
442 m_existingNodesInit(false),
443 m_useAddOnHost(useAddOnHost) {
444
445 D_METHOD((
446 "NodeManager()\n"));
447
448 ASSERT(roster);
449
450 // create refs for common nodes
451 _initCommonNodes();
452
453 // start the looper
454 Run();
455
456 // initialize connection to the media roster
457 D_ROSTER(("# roster->StartWatching(%p)\n", this));
458 roster->StartWatching(BMessenger(this));
459 }
460
461 // -------------------------------------------------------- //
462 // *** operations
463 // -------------------------------------------------------- //
464
465 // * ACCESS
466
467 // fetches NodeRef corresponding to a given ID; returns
468 // B_BAD_VALUE if no matching entry was found (and writes
469 // a 0 into the provided pointer.)
470
getNodeRef(media_node_id id,NodeRef ** outRef) const471 status_t NodeManager::getNodeRef(
472 media_node_id id,
473 NodeRef** outRef) const {
474 Autolock _l(this);
475
476 D_METHOD((
477 "NodeManager::getNodeRef(%ld)\n", id));
478
479 node_ref_map::const_iterator it = m_nodeRefMap.find(id);
480 if(it == m_nodeRefMap.end()) {
481 *outRef = 0;
482 return B_BAD_VALUE;
483 }
484
485 *outRef = (*it).second;
486 return B_OK;
487 }
488
489 // [13aug99]
490 // fetches Connection corresponding to a given source/destination
491 // on a given node. Returns an invalid connection and B_BAD_VALUE
492 // if no matching connection was found.
493
findConnection(media_node_id node,const media_source & source,Connection * outConnection) const494 status_t NodeManager::findConnection(
495 media_node_id node,
496 const media_source& source,
497 Connection* outConnection) const {
498 Autolock _l(this);
499
500 D_METHOD((
501 "NodeManager::findConnection()\n"));
502 ASSERT(source != media_source::null);
503
504 con_map::const_iterator it = m_conSourceMap.lower_bound(node);
505 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(node);
506 for(; it != itEnd; ++it)
507 if((*it).second->source() == source) {
508 // copy connection
509 *outConnection = *((*it).second);
510 return B_OK;
511 }
512
513 *outConnection = Connection();
514 return B_BAD_VALUE;
515 }
516
findConnection(media_node_id node,const media_destination & destination,Connection * outConnection) const517 status_t NodeManager::findConnection(
518 media_node_id node,
519 const media_destination& destination,
520 Connection* outConnection) const {
521 Autolock _l(this);
522
523 D_METHOD((
524 "NodeManager::findConnection()\n"));
525 ASSERT(destination != media_destination::null);
526
527 con_map::const_iterator it = m_conDestinationMap.lower_bound(node);
528 con_map::const_iterator itEnd = m_conDestinationMap.upper_bound(node);
529 for(; it != itEnd; ++it)
530 if((*it).second->destination() == destination) {
531 // copy connection
532 *outConnection = *((*it).second);
533 return B_OK;
534 }
535
536 *outConnection = Connection();
537 return B_BAD_VALUE;
538 }
539
540 // [e.moon 28sep99]
541 // fetches a Connection matching the given source and destination
542 // nodes. Returns an invalid connection and B_BAD_VALUE if
543 // no matching connection was found
544
findConnection(media_node_id sourceNode,media_node_id destinationNode,Connection * outConnection) const545 status_t NodeManager::findConnection(
546 media_node_id sourceNode,
547 media_node_id destinationNode,
548 Connection* outConnection) const {
549 Autolock _l(this);
550
551 D_METHOD((
552 "NodeManager::findConnection(source %ld, dest %ld)\n", sourceNode, destinationNode));
553
554 con_map::const_iterator it = m_conSourceMap.lower_bound(sourceNode);
555 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(sourceNode);
556 for(; it != itEnd; ++it) {
557 if((*it).second->destinationNode() == destinationNode) {
558 *outConnection = *((*it).second);
559 return B_OK;
560 }
561 }
562
563 *outConnection = Connection();
564 return B_BAD_VALUE;
565 }
566
567 // [e.moon 28sep99]
568 // tries to find a route from 'nodeA' to 'nodeB'; returns
569 // true if one exists, false if not.
570
571 class NodeManager::_find_route_state {
572 public:
573 set<media_node_id> visited;
574 };
575
findRoute(media_node_id nodeA,media_node_id nodeB)576 bool NodeManager::findRoute(
577 media_node_id nodeA,
578 media_node_id nodeB) {
579 Autolock _l(this);
580
581 D_METHOD((
582 "NodeManager::findRoute(%ld, %ld)\n", nodeA, nodeB));
583 status_t err;
584
585 NodeRef* ref;
586 err = getNodeRef(nodeA, &ref);
587 if(err < B_OK) {
588 PRINT((
589 "!!! NodeManager::findRoute(%" B_PRId32 ", %" B_PRId32
590 "): no ref for node %" B_PRId32 "\n", nodeA, nodeB, nodeA));
591 return false;
592 }
593
594 _find_route_state st;
595 return _find_route_recurse(ref, nodeB, &st);
596 }
597
598 // implementation of above
599
_find_route_recurse(NodeRef * origin,media_node_id target,_find_route_state * state)600 bool NodeManager::_find_route_recurse(
601 NodeRef* origin,
602 media_node_id target,
603 _find_route_state* state) {
604
605 ASSERT(IsLocked());
606 ASSERT(origin);
607 ASSERT(state);
608 status_t err __attribute__((unused));
609
610 // node already visited?
611 if(state->visited.find(origin->id()) != state->visited.end()) {
612 return false;
613 }
614
615 // mark node visited
616 state->visited.insert(origin->id());
617
618 vector<Connection> connections;
619
620 // walk input connections
621 origin->getInputConnections(connections);
622 for(uint32 n = 0; n < connections.size(); ++n) {
623
624 if(!connections[n].isValid())
625 continue;
626
627 // test against target
628 if(connections[n].sourceNode() == target)
629 return true; // SUCCESS
630
631 // recurse
632 NodeRef* ref;
633 err = getNodeRef(
634 connections[n].sourceNode(),
635 &ref);
636 ASSERT(err == B_OK);
637 ASSERT(ref);
638
639 if(_find_route_recurse(
640 ref,
641 target,
642 state))
643 return true; // SUCCESS
644 }
645
646 // walk output connections
647 connections.clear();
648 origin->getOutputConnections(connections);
649 for(uint32 n = 0; n < connections.size(); ++n) {
650
651 if(!connections[n].isValid())
652 continue;
653
654 // test against target
655 if(connections[n].destinationNode() == target)
656 return true; // SUCCESS
657
658 // recurse
659 NodeRef* ref;
660 err = getNodeRef(
661 connections[n].destinationNode(),
662 &ref);
663 ASSERT(err == B_OK);
664 ASSERT(ref);
665
666 if(_find_route_recurse(
667 ref,
668 target,
669 state))
670 return true; // SUCCESS
671 }
672
673 return false; // FAILED
674 }
675
676
677
678 // fetches Connection corresponding to a given source or
679 // destination; Returns an invalid connection and B_BAD_VALUE if
680 // none found.
681 // * Note: this is the slowest possible way to look up a
682 // connection. Since the low-level source/destination
683 // structures don't include a node ID, and a destination
684 // port can differ from its node's control port, a linear
685 // search of all known connections is performed. Only
686 // use these methods if you have no clue what node the
687 // connection corresponds to.
688
findConnection(const media_source & source,Connection * outConnection) const689 status_t NodeManager::findConnection(
690 const media_source& source,
691 Connection* outConnection) const {
692 Autolock _l(this);
693
694 D_METHOD((
695 "NodeManager::findConnection()\n"));
696 ASSERT(source != media_source::null);
697
698 for(con_map::const_iterator it = m_conSourceMap.begin();
699 it != m_conSourceMap.end(); ++it) {
700 if((*it).second->source() == source) {
701 // copy connection
702 *outConnection = *((*it).second);
703 return B_OK;
704 }
705 }
706
707 *outConnection = Connection();
708 return B_BAD_VALUE;
709 }
710
findConnection(const media_destination & destination,Connection * outConnection) const711 status_t NodeManager::findConnection(
712 const media_destination& destination,
713 Connection* outConnection) const {
714 Autolock _l(this);
715
716 D_METHOD((
717 "NodeManager::findConnection()\n"));
718 ASSERT(destination != media_destination::null);
719
720 for(con_map::const_iterator it = m_conDestinationMap.begin();
721 it != m_conDestinationMap.end(); ++it) {
722 if((*it).second->destination() == destination) {
723 // copy connection
724 *outConnection = *((*it).second);
725 return B_OK;
726 }
727 }
728
729 *outConnection = Connection();
730 return B_BAD_VALUE;
731 }
732
733
734 // fetch NodeRefs for system nodes (if a particular node doesn't
735 // exist, these methods return 0)
736
audioInputNode() const737 NodeRef* NodeManager::audioInputNode() const {
738 Autolock _l(this);
739 return m_audioInputNode;
740 }
videoInputNode() const741 NodeRef* NodeManager::videoInputNode() const {
742 Autolock _l(this);
743 return m_videoInputNode;
744 }
audioMixerNode() const745 NodeRef* NodeManager::audioMixerNode() const {
746 Autolock _l(this);
747 return m_audioMixerNode;
748 }
audioOutputNode() const749 NodeRef* NodeManager::audioOutputNode() const {
750 Autolock _l(this);
751 return m_audioOutputNode;
752 }
videoOutputNode() const753 NodeRef* NodeManager::videoOutputNode() const {
754 Autolock _l(this);
755 return m_videoOutputNode;
756 }
757
758 // fetch groups by index
759 // - you can write-lock the manager during sets of calls to these methods;
760 // this ensures that the group set won't change. The methods do lock
761 // the group internally, so locking isn't explicitly required.
762
countGroups() const763 uint32 NodeManager::countGroups() const {
764 Autolock _l(this);
765 D_METHOD((
766 "NodeManager::countGroups()\n"));
767
768 return m_nodeGroupSet.size();
769 }
770
groupAt(uint32 index) const771 NodeGroup* NodeManager::groupAt(
772 uint32 index) const {
773 Autolock _l(this);
774 D_METHOD((
775 "NodeManager::groupAt()\n"));
776
777 return (index < m_nodeGroupSet.size()) ?
778 m_nodeGroupSet[index] :
779 0;
780 }
781
782 // look up a group by unique ID; returns B_BAD_VALUE if no
783 // matching group was found
784
findGroup(uint32 id,NodeGroup ** outGroup) const785 status_t NodeManager::findGroup(uint32 id, NodeGroup** outGroup) const
786 {
787 Autolock _l(this);
788 D_METHOD(("NodeManager::findGroup(id)\n"));
789
790 node_group_set::const_iterator it;
791 for (it = m_nodeGroupSet.begin(); it != m_nodeGroupSet.end(); it++)
792 {
793 if ((*it)->id() == id) {
794 *outGroup = *it;
795 return B_OK;
796 }
797 }
798
799 *outGroup = 0;
800 return B_BAD_VALUE;
801 }
802
803 // look up a group by name; returns B_NAME_NOT_FOUND if
804 // no group matching the name was found.
805
findGroup(const char * name,NodeGroup ** outGroup) const806 status_t NodeManager::findGroup(const char* name, NodeGroup** outGroup) const
807 {
808 Autolock _l(this);
809 D_METHOD(("NodeManager::findGroup(name)\n"));
810
811 node_group_set::const_iterator it;
812 for (it = m_nodeGroupSet.begin(); it != m_nodeGroupSet.end(); it++)
813 {
814 if (strcmp((*it)->name(), name) == 0) {
815 *outGroup = *it;
816 return B_OK;
817 }
818 }
819
820 *outGroup = 0;
821 return B_BAD_VALUE;
822 }
823
824 // merge the given source group to the given destination;
825 // empties and releases the source group
826
mergeGroups(NodeGroup * sourceGroup,NodeGroup * destinationGroup)827 status_t NodeManager::mergeGroups(
828 NodeGroup* sourceGroup,
829 NodeGroup* destinationGroup) {
830 Autolock _l(this);
831 D_METHOD((
832 "NodeManager::mergeGroups(name)\n"));
833
834 // [5feb00 c.lenz] already merged
835 if(sourceGroup->id() == destinationGroup->id())
836 return B_OK;
837
838 if(sourceGroup->isReleased() || destinationGroup->isReleased())
839 return B_NOT_ALLOWED;
840
841 for(uint32 n = sourceGroup->countNodes(); n; --n) {
842 NodeRef* node = sourceGroup->nodeAt(n-1);
843 ASSERT(node);
844 status_t err __attribute__((unused)) = sourceGroup->removeNode(n-1);
845 ASSERT(err == B_OK);
846 err = destinationGroup->addNode(node);
847 ASSERT(err == B_OK);
848 }
849
850 // [7nov99 e.moon] delete the source group
851 _removeGroup(sourceGroup);
852 sourceGroup->release();
853
854 return B_OK;
855 }
856
857 // [e.moon 28sep99]
858 // split group: given two nodes currently in the same group
859 // that are not connected (directly OR indirectly),
860 // this method removes outsideNode, and all nodes connected
861 // to outsideNode, from the common group. These nodes are
862 // then added to a new group, returned in 'outGroup'. The
863 // new group has " split" appended to the end of the original
864 // group's name.
865 //
866 // Returns B_NOT_ALLOWED if any of the above conditions aren't
867 // met (ie. the nodes are in different groups or an indirect
868 // route exists from one to the other), or B_OK if the group
869 // was split successfully.
870
871
872 class _changeNodeGroupFn {
873 public:
874 NodeGroup* newGroup;
875
_changeNodeGroupFn(NodeGroup * _newGroup)876 _changeNodeGroupFn(
877 NodeGroup* _newGroup) : newGroup(_newGroup) {
878 ASSERT(newGroup);
879 }
880
operator ()(NodeRef * node)881 void operator()(
882 NodeRef* node) {
883
884 PRINT((
885 "_changeNodeGroupFn(): '%s'\n", node->name()));
886
887 status_t err __attribute__((unused));
888 NodeGroup* oldGroup = node->group();
889 if(oldGroup) {
890 err = oldGroup->removeNode(node);
891 ASSERT(err == B_OK);
892 }
893
894 err = newGroup->addNode(node);
895 ASSERT(err == B_OK);
896 }
897 };
898
splitGroup(NodeRef * insideNode,NodeRef * outsideNode,NodeGroup ** outGroup)899 status_t NodeManager::splitGroup(
900 NodeRef* insideNode,
901 NodeRef* outsideNode,
902 NodeGroup** outGroup) {
903
904 ASSERT(insideNode);
905 ASSERT(outsideNode);
906
907 Autolock _l(this);
908
909 // ensure that no route exists from insideNode to outsideNode
910 if(findRoute(insideNode->id(), outsideNode->id())) {
911 PRINT((
912 "!!! NodeManager::splitGroup(): route exists from %" B_PRId32
913 " to %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
914 return B_NOT_ALLOWED;
915 }
916
917 // make sure the nodes share a common group
918 NodeGroup* oldGroup = insideNode->group();
919 if(!oldGroup) {
920 PRINT(("!!! NodeManager::splitGroup(): invalid group\n"));
921 return B_NOT_ALLOWED;
922 }
923 if(oldGroup != outsideNode->group()) {
924 PRINT((
925 "!!! NodeManager::splitGroup(): mismatched groups for %" B_PRId32
926 " and %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
927 return B_NOT_ALLOWED;
928 }
929
930 Autolock _l_old_group(oldGroup);
931
932 // create the new group
933 BString nameBuffer = oldGroup->name();
934 nameBuffer << " split";
935
936 NodeGroup* newGroup = createGroup(
937 nameBuffer.String(),
938 oldGroup->runMode());
939 *outGroup = newGroup;
940
941 // move nodes connected to outsideNode from old to new group
942 _changeNodeGroupFn fn(newGroup);
943 fn(outsideNode);
944
945 _for_each_state st;
946 _do_for_each_connected(
947 this,
948 outsideNode,
949 oldGroup,
950 true,
951 fn,
952 &st);
953
954 // [e.moon 1dec99] a single-node group takes that node's name
955 if(newGroup->countNodes() == 1)
956 newGroup->setName(newGroup->nodeAt(0)->name());
957
958 if(oldGroup->countNodes() == 1)
959 oldGroup->setName(oldGroup->nodeAt(0)->name());
960
961 return B_OK;
962 }
963
964
965 // * INSTANTIATION & CONNECTION
966 // Use these calls rather than the associated BMediaRoster()
967 // methods to assure that the nodes and connections you set up
968 // can be properly serialized & reconstituted.
969
970 // basic BMediaRoster::InstantiateDormantNode() wrapper
971
instantiate(const dormant_node_info & info,NodeRef ** outRef,bigtime_t timeout,uint32 nodeFlags)972 status_t NodeManager::instantiate(
973 const dormant_node_info& info,
974 NodeRef** outRef,
975 bigtime_t timeout,
976 uint32 nodeFlags) {
977
978 Autolock _l(this);
979 status_t err;
980 D_METHOD((
981 "NodeManager::instantiate()\n"));
982
983 // * instantiate
984
985 media_node node;
986
987 if(m_useAddOnHost) {
988 err = AddOnHost::InstantiateDormantNode(
989 info, &node, timeout);
990
991 if(err < B_OK) {
992 node = media_node::null;
993
994 // attempt to relaunch
995 BMessenger mess;
996 err = AddOnHost::Launch(&mess);
997 if(err < B_OK) {
998 PRINT((
999 "!!! NodeManager::instantiate(): giving up on AddOnHost\n"));
1000
1001 m_useAddOnHost = false;
1002 }
1003 else {
1004 err = AddOnHost::InstantiateDormantNode(
1005 info, &node, timeout);
1006 }
1007 }
1008 }
1009
1010 if(!m_useAddOnHost || node == media_node::null) {
1011 D_ROSTER((
1012 "# roster->InstantiateDormantNode()\n"));
1013 err = roster->InstantiateDormantNode(info, &node);
1014 }
1015
1016 if(err < B_OK) {
1017 *outRef = 0;
1018 return err;
1019 }
1020
1021 if(node == media_node::null) {
1022 // [e.moon 23oct99] +++++
1023 // instantiating a soundcard input/output (emu10k or sonic_vibes)
1024 // produces a node ID of -1 (R4.5.2 x86)
1025 //
1026 PRINT((
1027 "! InstantiateDormantNode(): invalid media node\n"));
1028
1029 // bail out
1030 *outRef = 0;
1031 return B_BAD_INDEX;
1032 }
1033
1034 // * create NodeRef
1035 NodeRef* ref = new NodeRef(
1036 node,
1037 this,
1038 nodeFlags, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1039 NodeRef::_INTERNAL);
1040
1041 ref->_setAddonHint(&info);
1042 _addRef(ref);
1043
1044 // * return it
1045 *outRef = ref;
1046 return B_OK;
1047 }
1048
1049 // SniffRef/Instantiate.../SetRefFor: a one-call interface
1050 // to create a node capable of playing a given media file.
1051
instantiate(const entry_ref & file,uint64 requireNodeKinds,NodeRef ** outRef,bigtime_t timeout,uint32 nodeFlags,bigtime_t * outDuration)1052 status_t NodeManager::instantiate(
1053 const entry_ref& file,
1054 uint64 requireNodeKinds,
1055 NodeRef** outRef,
1056 bigtime_t timeout,
1057 uint32 nodeFlags,
1058 bigtime_t* outDuration) {
1059
1060 D_METHOD((
1061 "NodeManager::instantiate(ref)\n"));
1062
1063 // [no lock needed; calls the full form of instantiate()]
1064
1065 status_t err;
1066
1067 // * Find matching add-on
1068 dormant_node_info info;
1069
1070 D_ROSTER((
1071 "# roster->SniffRef()\n"));
1072 err = roster->SniffRef(
1073 file,
1074 requireNodeKinds,
1075 &info);
1076 if(err < B_OK) {
1077 *outRef = 0;
1078 return err;
1079 }
1080
1081 // * Instantiate
1082 err = instantiate(info, outRef, timeout, nodeFlags);
1083
1084 if(err < B_OK)
1085 return err;
1086
1087 ASSERT(*outRef);
1088
1089 // * Set file to play
1090 bigtime_t dur;
1091 D_ROSTER(("# roster->SetRefFor()\n"));
1092 err = roster->SetRefFor(
1093 (*outRef)->node(),
1094 file,
1095 false,
1096 &dur);
1097
1098 if(err < B_OK) {
1099 PRINT((
1100 "* SetRefFor() failed: %s\n", strerror(err)));
1101 }
1102 else if(outDuration)
1103 *outDuration = dur;
1104
1105 // * update info [e.moon 29sep99]
1106 Autolock _l(*outRef);
1107 (*outRef)->_setAddonHint(&info, &file);
1108
1109 return err;
1110 }
1111
1112 // use this method to reference nodes internal to your
1113 // application.
1114
reference(BMediaNode * node,NodeRef ** outRef,uint32 nodeFlags)1115 status_t NodeManager::reference(
1116 BMediaNode* node,
1117 NodeRef** outRef,
1118 uint32 nodeFlags) {
1119
1120 Autolock _l(this);
1121 D_METHOD((
1122 "NodeManager::reference()\n"));
1123
1124 // should this node be marked _NO_RELEASE?
1125 NodeRef* ref = new NodeRef(node->Node(), this, nodeFlags, 0);
1126 _addRef(ref);
1127
1128 *outRef = ref;
1129 return B_OK;
1130 }
1131
1132 // the most flexible form of connect(): set the template
1133 // format as you would for BMediaRoster::Connect().
1134
connect(const media_output & output,const media_input & input,const media_format & templateFormat,Connection * outConnection)1135 status_t NodeManager::connect(
1136 const media_output& output,
1137 const media_input& input,
1138 const media_format& templateFormat,
1139 Connection* outConnection /*=0*/) {
1140
1141 Autolock _l(this);
1142 status_t err;
1143 D_METHOD((
1144 "NodeManager::connect()\n"));
1145
1146 // * Find (& create if necessary) NodeRefs
1147
1148 NodeRef* outputRef;
1149 if(getNodeRef(output.node.node, &outputRef) < B_OK)
1150 outputRef = _addRefFor(output.node, 0);
1151
1152 NodeRef* inputRef;
1153 if(getNodeRef(input.node.node, &inputRef) < B_OK)
1154 inputRef = _addRefFor(input.node, 0);
1155
1156 // * Connect the nodes
1157
1158 media_output finalOutput;
1159 media_input finalInput;
1160 media_format finalFormat = templateFormat;
1161
1162 D_ROSTER(("# roster->Connect()\n"));
1163 err = roster->Connect(
1164 output.source,
1165 input.destination,
1166 &finalFormat,
1167 &finalOutput,
1168 &finalInput);
1169
1170 if(err < B_OK) {
1171 if(outConnection)
1172 *outConnection = Connection();
1173 connectionFailed(output, input, templateFormat, err);
1174 return err;
1175 }
1176
1177 // * Create Connection instance; mark it INTERNAL
1178 // to automatically remove it upon shutdown.
1179
1180 D_METHOD((
1181 "! creating connection:\n"
1182 " source id: %" B_PRId32 "\n"
1183 " source port: %" B_PRId32 "\n"
1184 " dest id: %" B_PRId32 "\n"
1185 " dest port: %" B_PRId32 "\n",
1186 finalOutput.source.id, finalOutput.source.port,
1187 finalInput.destination.id, finalInput.destination.port));
1188
1189 uint32 cflags = Connection::INTERNAL;
1190 if(outputRef->m_info.node.kind & B_FILE_INTERFACE) {
1191 // 3aug99:
1192 // workaround for bug 19990802-12798:
1193 // connections involving a file-interface node aren't removed
1194 cflags |= Connection::LOCKED;
1195 }
1196
1197 Connection* con = new Connection(
1198 m_nextConID++,
1199 output.node,
1200 finalOutput.source,
1201 finalOutput.name,
1202 input.node,
1203 finalInput.destination,
1204 finalInput.name,
1205 finalFormat,
1206 cflags);
1207
1208 con->setOutputHint(
1209 output.name,
1210 output.format);
1211
1212 con->setInputHint(
1213 input.name,
1214 input.format);
1215
1216 con->setRequestedFormat(
1217 templateFormat);
1218
1219 _addConnection(con);
1220
1221 // [e.moon 10aug99]
1222 // fetch updated latencies;
1223 // [e.moon 28sep99]
1224 // scan all nodes connected directly OR indirectly to the
1225 // newly-connected nodes and update their latencies -- this includes
1226 // recalculating the node's 'producer delay' if in B_RECORDING mode.
1227
1228 _updateLatenciesFrom(inputRef, true);
1229
1230 // copy connection
1231 if(outConnection) {
1232 *outConnection = *con;
1233 }
1234 return B_OK;
1235 }
1236
1237 // format-guessing form of connect(): tries to find
1238 // a common format between output & input before connection;
1239 // returns B_MEDIA_BAD_FORMAT if no common format appears
1240 // possible.
1241 //
1242 // NOTE: the specifics of the input and output formats are ignored;
1243 // this method only looks at the format type, and properly
1244 // handles wildcards at that level (B_MEDIA_NO_TYPE).
1245
connect(const media_output & output,const media_input & input,Connection * outConnection)1246 status_t NodeManager::connect(
1247 const media_output& output,
1248 const media_input& input,
1249 Connection* outConnection /*=0*/) {
1250
1251 D_METHOD((
1252 "NodeManager::connect(guess)\n"));
1253
1254 // [no lock needed; calls the full form of connect()]
1255
1256 // defer to the pickier endpoint
1257 media_format f;
1258
1259 if(output.format.type > B_MEDIA_UNKNOWN_TYPE) {
1260 f = output.format;
1261 if ((input.format.type > B_MEDIA_UNKNOWN_TYPE) &&
1262 (f.type != input.format.type)) {
1263 connectionFailed(output, input, f, B_MEDIA_BAD_FORMAT);
1264 return B_MEDIA_BAD_FORMAT;
1265 }
1266 }
1267 else if(input.format.type > B_MEDIA_UNKNOWN_TYPE) {
1268 f = input.format;
1269 // output node doesn't care
1270 }
1271 else {
1272 // about as non-picky as two nodes can possibly be
1273 f.type = B_MEDIA_UNKNOWN_TYPE;
1274 }
1275
1276 // +++++ ? revert to wildcard ?
1277
1278 // let the nodes try to work out a common format from here
1279 return connect(
1280 output,
1281 input,
1282 f,
1283 outConnection);
1284 }
1285
1286 // disconnects the connection represented by the provided
1287 // Connection object. if successful, returns B_OK.
1288
disconnect(const Connection & connection)1289 status_t NodeManager::disconnect(
1290 const Connection& connection) {
1291
1292 Autolock _l(this);
1293 status_t err;
1294 D_METHOD((
1295 "NodeManager::disconnect()\n"));
1296
1297 // don't bother trying to disconnect an invalid connection
1298 if(!connection.isValid())
1299 return B_NOT_ALLOWED;
1300
1301 // make sure connection can be released
1302 if(connection.flags() & Connection::LOCKED) {
1303 PRINT((
1304 "NodeManager::disconnect(): connection locked:\n"
1305 " %" B_PRId32 ":%s -> %" B_PRId32 ":%s\n",
1306 connection.sourceNode(),
1307 connection.outputName(),
1308 connection.destinationNode(),
1309 connection.inputName()));
1310 return B_NOT_ALLOWED;
1311 }
1312
1313 D_METHOD((
1314 "! breaking connection:\n"
1315 " source node: %" B_PRId32 "\n"
1316 " source id: %" B_PRId32 "\n"
1317 " source port: %" B_PRId32 "\n"
1318 " dest node: %" B_PRId32 "\n"
1319 " dest id: %" B_PRId32 "\n"
1320 " dest port: %" B_PRId32 "\n",
1321 connection.sourceNode(),
1322 connection.source().id, connection.source().port,
1323 connection.destinationNode(),
1324 connection.destination().id, connection.destination().port));
1325
1326 // do it
1327 D_ROSTER(("# roster->Disconnect()\n"));
1328 err = roster->Disconnect(
1329 connection.sourceNode(),
1330 connection.source(),
1331 connection.destinationNode(),
1332 connection.destination());
1333
1334 // mark disconnected
1335 if(err == B_OK) {
1336 con_map::iterator it = m_conSourceMap.lower_bound(connection.sourceNode());
1337 con_map::iterator itEnd = m_conSourceMap.upper_bound(connection.sourceNode());
1338 for(; it != itEnd; ++it)
1339 if((*it).second->id() == connection.id()) {
1340 (*it).second->m_disconnected = true;
1341 break;
1342 }
1343 ASSERT(it != itEnd);
1344
1345 // [e.moon 28sep99]
1346 // fetch updated latencies;
1347 // scan all nodes connected directly OR indirectly to the
1348 // newly-connected nodes and update their latencies -- this includes
1349 // recalculating the node's 'producer delay' if in B_RECORDING mode.
1350
1351 NodeRef* ref;
1352 if(getNodeRef(connection.sourceNode(), &ref) == B_OK)
1353 _updateLatenciesFrom(ref, true);
1354 if(getNodeRef(connection.destinationNode(), &ref) == B_OK)
1355 _updateLatenciesFrom(ref, true);
1356
1357 } else {
1358 // +++++ if this failed, somebody somewhere is mighty confused
1359 PRINT((
1360 "NodeManager::disconnect(): Disconnect() failed:\n %s\n",
1361 strerror(err)));
1362 }
1363
1364 return err;
1365 }
1366
1367 // * GROUP CREATION
1368
createGroup(const char * name,BMediaNode::run_mode runMode)1369 NodeGroup* NodeManager::createGroup(
1370 const char* name,
1371 BMediaNode::run_mode runMode) {
1372
1373 Autolock _l(this);
1374 D_METHOD((
1375 "NodeManager::createGroup()\n"));
1376
1377 NodeGroup* g = new NodeGroup(name, this, runMode);
1378 _addGroup(g);
1379
1380 return g;
1381 }
1382
1383 // -------------------------------------------------------- //
1384 // *** node/connection iteration
1385 // *** MUST BE LOCKED for any of these calls
1386 // -------------------------------------------------------- //
1387
1388 // usage:
1389 // For the first call, pass 'cookie' a pointer to a void* set to 0.
1390 // Returns B_BAD_INDEX when the set of nodes has been exhausted (and
1391 // re-zeroes the cookie, cleaning up any unused memory.)
1392
getNextRef(NodeRef ** ref,void ** cookie)1393 status_t NodeManager::getNextRef(
1394 NodeRef** ref,
1395 void** cookie) {
1396 ASSERT(IsLocked());
1397 ASSERT(cookie);
1398
1399 if(!*cookie)
1400 *cookie = new node_ref_map::iterator(m_nodeRefMap.begin());
1401
1402 node_ref_map::iterator* pit = (node_ref_map::iterator*)*cookie;
1403
1404 // at end of set?
1405 if(*pit == m_nodeRefMap.end()) {
1406 delete pit;
1407 *cookie = 0;
1408 return B_BAD_INDEX;
1409 }
1410
1411 // return next entry
1412 *ref = (*(*pit)).second;
1413 ++(*pit);
1414 return B_OK;
1415 }
1416
1417 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
disposeRefCookie(void ** cookie)1418 void NodeManager::disposeRefCookie(
1419 void** cookie) {
1420
1421 if(!cookie)
1422 return;
1423
1424 node_ref_map::iterator* it =
1425 reinterpret_cast<node_ref_map::iterator*>(*cookie);
1426 ASSERT(it);
1427 if(it)
1428 delete it;
1429 }
1430
getNextConnection(Connection * connection,void ** cookie)1431 status_t NodeManager::getNextConnection(
1432 Connection* connection,
1433 void** cookie) {
1434 ASSERT(IsLocked());
1435 ASSERT(cookie);
1436
1437 if(!*cookie)
1438 *cookie = new con_map::iterator(m_conSourceMap.begin());
1439
1440 con_map::iterator* pit = (con_map::iterator*)*cookie;
1441
1442 // at end of set?
1443 if(*pit == m_conSourceMap.end()) {
1444 delete pit;
1445 *cookie = 0;
1446 return B_BAD_INDEX;
1447 }
1448
1449 // return next entry (ewww)
1450 *connection = *((*(*pit)).second);
1451 ++(*pit);
1452 return B_OK;
1453 }
1454
1455 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
disposeConnectionCookie(void ** cookie)1456 void NodeManager::disposeConnectionCookie(
1457 void** cookie) {
1458
1459 if(!cookie)
1460 return;
1461
1462 con_map::iterator* it =
1463 reinterpret_cast<con_map::iterator*>(*cookie);
1464 ASSERT(it);
1465 if(it)
1466 delete it;
1467 }
1468
1469
1470 // -------------------------------------------------------- //
1471 // *** BHandler impl
1472 // -------------------------------------------------------- //
1473
1474 // +++++ support all Media Roster messages! +++++
1475
1476 // [e.moon 7nov99] implemented observer pattern for NodeGroup
MessageReceived(BMessage * message)1477 void NodeManager::MessageReceived(BMessage* message) {
1478
1479 D_MESSAGE((
1480 "NodeManager::MessageReceived(): %c%c%c%c\n",
1481 message->what >> 24,
1482 (message->what >> 16) & 0xff,
1483 (message->what >> 8) & 0xff,
1484 (message->what) & 0xff));
1485
1486 switch(message->what) {
1487
1488 // *** Media Roster messages ***
1489
1490 case B_MEDIA_NODE_CREATED:
1491 if(_handleNodesCreated(message) == B_OK)
1492 notify(message);
1493 break;
1494
1495 case B_MEDIA_NODE_DELETED:
1496 _handleNodesDeleted(message);
1497 notify(message);
1498 break;
1499
1500 case B_MEDIA_CONNECTION_MADE:
1501 _handleConnectionMade(message);
1502 notify(message);
1503 break;
1504
1505 case B_MEDIA_CONNECTION_BROKEN:
1506 _handleConnectionBroken(message); // augments message!
1507 notify(message);
1508 break;
1509
1510 case B_MEDIA_FORMAT_CHANGED:
1511 _handleFormatChanged(message);
1512 notify(message);
1513 break;
1514
1515 default:
1516 _inherited::MessageReceived(message);
1517 break;
1518 }
1519 }
1520
1521 // -------------------------------------------------------- //
1522 // *** IObservable hooks
1523 // -------------------------------------------------------- //
1524
observerAdded(const BMessenger & observer)1525 void NodeManager::observerAdded(
1526 const BMessenger& observer) {
1527
1528 BMessage m(M_OBSERVER_ADDED);
1529 m.AddMessenger("target", BMessenger(this));
1530 observer.SendMessage(&m);
1531 }
1532
1533
observerRemoved(const BMessenger & observer)1534 void NodeManager::observerRemoved(
1535 const BMessenger& observer) {
1536
1537 BMessage m(M_OBSERVER_REMOVED);
1538 m.AddMessenger("target", BMessenger(this));
1539 observer.SendMessage(&m);
1540 }
1541
notifyRelease()1542 void NodeManager::notifyRelease() {
1543
1544 BMessage m(M_RELEASED);
1545 m.AddMessenger("target", BMessenger(this));
1546 notify(&m);
1547 }
1548
releaseComplete()1549 void NodeManager::releaseComplete() {
1550 // tear down media roster connection
1551 D_ROSTER(("# roster->StopWatching()\n"));
1552 status_t err = roster->StopWatching(
1553 BMessenger(this));
1554 if(err < B_OK) {
1555 PRINT((
1556 "* roster->StopWatching() failed: %s\n", strerror(err)));
1557 }
1558 }
1559
1560
1561 // -------------------------------------------------------- //
1562 // *** ILockable impl.
1563 // -------------------------------------------------------- //
1564
lock(lock_t type,bigtime_t timeout)1565 bool NodeManager::lock(
1566 lock_t type,
1567 bigtime_t timeout) {
1568
1569 D_LOCK(("*** NodeManager::lock(): %ld\n", find_thread(0)));
1570
1571 status_t err = LockWithTimeout(timeout);
1572
1573
1574 D_LOCK(("*** NodeManager::lock() ACQUIRED: %ld\n", find_thread(0)));
1575
1576 return err == B_OK;
1577 }
1578
unlock(lock_t type)1579 bool NodeManager::unlock(
1580 lock_t type) {
1581
1582 D_LOCK(("*** NodeManager::unlock(): %ld\n", find_thread(0)));
1583
1584 Unlock();
1585
1586 D_LOCK(("*** NodeManager::unlock() RELEASED: %ld\n", find_thread(0)));
1587
1588 return true;
1589 }
1590
isLocked(lock_t type) const1591 bool NodeManager::isLocked(
1592 lock_t type) const {
1593
1594 return IsLocked();
1595 }
1596
1597 // -------------------------------------------------------- //
1598 // *** internal operations (LOCK REQUIRED)
1599 // -------------------------------------------------------- //
1600
_initCommonNodes()1601 void NodeManager::_initCommonNodes() {
1602
1603 ASSERT(IsLocked());
1604 status_t err;
1605 media_node node;
1606
1607 D_METHOD((
1608 "NodeManager::_initCommonNodes()\n"));
1609
1610 uint32 disableTransport =
1611 (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
1612
1613 // video input
1614 D_ROSTER(("# roster->GetVideoInput()\n"));
1615 err = roster->GetVideoInput(&node);
1616 if(err == B_OK)
1617 m_videoInputNode = _addRefFor(
1618 node,
1619 _userFlagsForKind(node.kind),
1620 _implFlagsForKind(node.kind));
1621
1622 // video output
1623 D_ROSTER(("# roster->GetVideoOutput()\n"));
1624 err = roster->GetVideoOutput(&node);
1625 if(err == B_OK) {
1626 if(m_videoInputNode && node.node == m_videoInputNode->id()) {
1627 // input and output nodes identical
1628 // [e.moon 20dec99]
1629 m_videoOutputNode = m_videoInputNode;
1630 }
1631 else {
1632 m_videoOutputNode = _addRefFor(
1633 node,
1634 _userFlagsForKind(node.kind) & ~NodeRef::NO_START_STOP,
1635 _implFlagsForKind(node.kind));
1636 }
1637 }
1638
1639 // audio mixer
1640 D_ROSTER(("# roster->GetAudioMixer()\n"));
1641 err = roster->GetAudioMixer(&node);
1642 if(err == B_OK)
1643 m_audioMixerNode = _addRefFor(
1644 node,
1645 _userFlagsForKind(node.kind) | disableTransport,
1646 _implFlagsForKind(node.kind));
1647
1648 // audio input
1649 D_ROSTER(("# roster->GetAudioInput()\n"));
1650 err = roster->GetAudioInput(&node);
1651 if(err == B_OK)
1652 m_audioInputNode = _addRefFor(
1653 node,
1654 _userFlagsForKind(node.kind),
1655 _implFlagsForKind(node.kind));
1656
1657 // audio output
1658 D_ROSTER(("# roster->GetAudioOutput()\n"));
1659 err = roster->GetAudioOutput(&node);
1660 if(err == B_OK) {
1661 if(m_audioInputNode && node.node == m_audioInputNode->id()) {
1662 // input and output nodes identical
1663 // [e.moon 20dec99]
1664 m_audioOutputNode = m_audioInputNode;
1665
1666 // disable transport controls (the default audio output must always
1667 // be running, and can't be seeked.)
1668
1669 m_audioOutputNode->setFlags(
1670 m_audioOutputNode->flags() | disableTransport);
1671 }
1672 else {
1673 m_audioOutputNode = _addRefFor(
1674 node,
1675 _userFlagsForKind(node.kind) | disableTransport,
1676 _implFlagsForKind(node.kind));
1677 }
1678 }
1679 }
1680
_addRef(NodeRef * ref)1681 void NodeManager::_addRef(
1682 NodeRef* ref) {
1683
1684 ASSERT(ref);
1685 ASSERT(IsLocked());
1686
1687 D_METHOD((
1688 "NodeManager::_addRef()\n"));
1689
1690 // precondition: no NodeRef yet exists for this node
1691 // +++++
1692 // [e.moon 21oct99]
1693 // <markjan@xs4all.nl> sez this fails on startup w/ MediaKit 10.5
1694 ASSERT(
1695 m_nodeRefMap.find(ref->id()) == m_nodeRefMap.end());
1696
1697 // add it
1698 // [e.moon 13oct99] PPC-friendly
1699 m_nodeRefMap.insert(node_ref_map::value_type(ref->id(), ref));
1700
1701 // [e.moon 8nov99] call hook
1702 nodeCreated(ref);
1703 }
1704
_removeRef(media_node_id id)1705 void NodeManager::_removeRef(
1706 media_node_id id) {
1707 ASSERT(IsLocked());
1708
1709 D_METHOD((
1710 "NodeManager::_removeRef()\n"));
1711
1712 node_ref_map::iterator it = m_nodeRefMap.find(id);
1713
1714 // precondition: a NodeRef w/ matching ID is in the map
1715 ASSERT(it != m_nodeRefMap.end());
1716
1717 // [e.moon 8nov99] call hook
1718 nodeDeleted((*it).second);
1719
1720 // remove it
1721 m_nodeRefMap.erase(it);
1722 }
1723
1724 // create, add, return a NodeRef for the given external node;
1725 // must not already exist
_addRefFor(const media_node & node,uint32 nodeFlags,uint32 nodeImplFlags)1726 NodeRef* NodeManager::_addRefFor(
1727 const media_node& node,
1728 uint32 nodeFlags,
1729 uint32 nodeImplFlags) {
1730
1731 ASSERT(IsLocked());
1732
1733 D_METHOD((
1734 "NodeManager::_addRefFor()\n"));
1735
1736 // precondition: no NodeRef yet exists for this node
1737 ASSERT(
1738 m_nodeRefMap.find(node.node) == m_nodeRefMap.end());
1739
1740 // // precondition: the node actually exists
1741 // live_node_info info;
1742 // D_ROSTER(("# roster->GetLiveNodeInfo()\n"));
1743 // ASSERT(roster->GetLiveNodeInfo(node, &info) == B_OK);
1744
1745 // * create & add ref
1746 NodeRef* ref = new NodeRef(node, this, nodeFlags, nodeImplFlags);
1747 _addRef(ref);
1748
1749 return ref;
1750 }
1751
_addConnection(Connection * connection)1752 void NodeManager::_addConnection(
1753 Connection* connection) {
1754
1755 ASSERT(connection);
1756 ASSERT(IsLocked());
1757
1758 D_METHOD((
1759 "NodeManager::_addConnection()\n"));
1760
1761 // precondition: not already entered in either source or dest map
1762 // +++++ a more rigorous test would be a very good thing
1763 #ifdef DEBUG
1764 for(con_map::iterator it = m_conSourceMap.lower_bound(connection->sourceNode());
1765 it != m_conSourceMap.upper_bound(connection->sourceNode()); ++it) {
1766 ASSERT((*it).second->id() != connection->id());
1767 }
1768 for(con_map::iterator it = m_conDestinationMap.lower_bound(connection->destinationNode());
1769 it != m_conDestinationMap.upper_bound(connection->destinationNode()); ++it) {
1770 ASSERT((*it).second->id() != connection->id());
1771 }
1772 #endif
1773
1774 // add to both maps
1775 // [e.moon 13oct99] PPC-friendly
1776 m_conSourceMap.insert(
1777 con_map::value_type(
1778 connection->sourceNode(),
1779 connection));
1780 m_conDestinationMap.insert(
1781 con_map::value_type(
1782 connection->destinationNode(),
1783 connection));
1784
1785 // [e.moon 8nov99] call hook
1786 connectionMade(connection);
1787 }
1788
_removeConnection(const Connection & connection)1789 void NodeManager::_removeConnection(
1790 const Connection& connection) {
1791
1792 ASSERT(IsLocked());
1793 con_map::iterator itSource, itDestination;
1794
1795 D_METHOD((
1796 "NodeManager::_removeConnection()\n"));
1797
1798 // [e.moon 8nov99] call hook
1799 connectionBroken(&connection);
1800
1801 // precondition: one entry in both source & dest maps
1802 // +++++ a more rigorous test would be a very good thing
1803
1804 for(
1805 itSource = m_conSourceMap.lower_bound(connection.sourceNode());
1806 itSource != m_conSourceMap.upper_bound(connection.sourceNode());
1807 ++itSource)
1808 if((*itSource).second->id() == connection.id())
1809 break;
1810
1811 ASSERT(itSource != m_conSourceMap.end());
1812
1813 for(
1814 itDestination = m_conDestinationMap.lower_bound(connection.destinationNode());
1815 itDestination != m_conDestinationMap.upper_bound(connection.destinationNode());
1816 ++itDestination)
1817 if((*itDestination).second->id() == connection.id())
1818 break;
1819
1820 ASSERT(itDestination != m_conDestinationMap.end());
1821
1822 // delete & remove from both maps
1823 delete (*itSource).second;
1824 m_conSourceMap.erase(itSource);
1825 m_conDestinationMap.erase(itDestination);
1826 }
1827
_addGroup(NodeGroup * group)1828 void NodeManager::_addGroup(
1829 NodeGroup* group) {
1830
1831 ASSERT(group);
1832 ASSERT(IsLocked());
1833
1834 D_METHOD((
1835 "NodeManager::_addGroup()\n"));
1836
1837 // precondition: group not already in set
1838 ASSERT(
1839 find(
1840 m_nodeGroupSet.begin(),
1841 m_nodeGroupSet.end(),
1842 group) == m_nodeGroupSet.end());
1843
1844 // add
1845 m_nodeGroupSet.push_back(group);
1846
1847 // // [e.moon 7nov99] observe
1848 // add_observer(this, group);
1849 }
1850
_removeGroup(NodeGroup * group)1851 void NodeManager::_removeGroup(
1852 NodeGroup* group) {
1853
1854 ASSERT(group);
1855 ASSERT(IsLocked());
1856
1857 D_METHOD((
1858 "NodeManager::_removeGroup()\n"));
1859
1860 node_group_set::iterator it = find(
1861 m_nodeGroupSet.begin(),
1862 m_nodeGroupSet.end(),
1863 group);
1864
1865 // precondition: group in set
1866 if(it == m_nodeGroupSet.end()) {
1867 PRINT((
1868 "* NodeManager::_removeGroup(%" B_PRId32 "): group not in set.\n",
1869 group->id()));
1870 return;
1871 }
1872
1873 // remove it
1874 m_nodeGroupSet.erase(it);
1875 }
1876
1877 // -------------------------------------------------------- //
1878 // *** Message Handlers ***
1879 // -------------------------------------------------------- //
1880
1881
1882 // now returns B_OK iff the message should be relayed to observers
1883 // [e.moon 11oct99]
1884
_handleNodesCreated(BMessage * message)1885 inline status_t NodeManager::_handleNodesCreated(
1886 BMessage* message) {
1887 ASSERT(IsLocked());
1888
1889 status_t err = B_OK;
1890
1891 // fetch number of new nodes
1892 type_code type;
1893 int32 count;
1894 err = message->GetInfo("media_node_id", &type, &count);
1895 if(err < B_OK) {
1896 PRINT((
1897 "* NodeManager::_handleNodesCreated(): GetInfo() failed:\n"
1898 " %s\n",
1899 strerror(err)));
1900 return err;
1901 }
1902 if(!count) {
1903 PRINT((
1904 "* NodeManager::_handleNodesCreated(): no node IDs in message.\n"));
1905 return err;
1906 }
1907
1908 D_METHOD((
1909 "NodeManager::_handleNodesCreated(): %" B_PRId32 " nodes\n",
1910 count));
1911
1912 // * Create NodeRef instances for the listed nodes.
1913 // If this is the first message received from the Media Roster,
1914 // no connection info will be received for these nodes; store them
1915 // for now (indexed by service-thread port) and figure the connections
1916 // afterwards.
1917 // These nodes are mapped by port ID because that's the only criterion
1918 // available for matching a media_source to a node.
1919
1920 typedef map<port_id, NodeRef*> port_ref_map;
1921 port_ref_map* initialNodes = m_existingNodesInit ? 0 : new port_ref_map;
1922
1923 bool refsCreated = false;
1924
1925 for(int32 n = 0; n < count; ++n) {
1926 // fetch ID of next node
1927 int32 id;
1928 err = message->FindInt32("media_node_id", n, &id);
1929 if(err < B_OK) {
1930 PRINT((
1931 "* NodeManager::_handleNodesCreated(): FindInt32() failed:\n"
1932 " %s", strerror(err)));
1933 continue;
1934 }
1935
1936 // look up the node
1937 media_node node;
1938 err = roster->GetNodeFor(id, &node);
1939 if(err < B_OK) {
1940 PRINT((
1941 "* NodeManager::_handleNodesCreated(): roster->GetNodeFor(%"
1942 B_PRId32 ") failed:\n"
1943 " %s\n",
1944 id, strerror(err)));
1945 continue;
1946 }
1947
1948 // look for an existing NodeRef; if not found, create one:
1949 NodeRef* ref = 0;
1950 if(getNodeRef(node.node, &ref) < B_OK) {
1951 // create one
1952 ref = _addRefFor(
1953 node,
1954 _userFlagsForKind(node.kind), // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1955 _implFlagsForKind(node.kind) | NodeRef::_CREATE_NOTIFIED);
1956
1957 refsCreated = true;
1958
1959 // // [e.moon 7nov99] call hook
1960 // nodeCreated(ref);
1961
1962 } else {
1963 // PRINT((
1964 // "* NodeManager::_handleNodesCreated():\n"
1965 // " found existing ref for '%s' (%ld)\n",
1966 // ref->name(), id));
1967
1968
1969 // set _CREATE_NOTIFIED to prevent notification from being passed on
1970 // twice [e.moon 11oct99]
1971 if(!(ref->m_implFlags & NodeRef::_CREATE_NOTIFIED)) {
1972 ref->m_implFlags |= NodeRef::_CREATE_NOTIFIED;
1973 refsCreated = true;
1974 }
1975
1976 // release the (duplicate) media_node reference
1977 err = roster->ReleaseNode(node);
1978 if(err < B_OK) {
1979 PRINT((
1980 "* NodeManager::_handleNodesCreated(): roster->ReleaseNode(%"
1981 B_PRId32 ") failed:\n"
1982 " %s\n",
1983 id, strerror(err)));
1984 }
1985 }
1986
1987 // add to the 'initial nodes' set if necessary
1988 // [e.moon 13oct99] PPC-friendly
1989 if(initialNodes)
1990 initialNodes->insert(
1991 port_ref_map::value_type(
1992 node.port, ref));
1993 }
1994
1995 if(initialNodes) {
1996 // populate current connections from each node in the set
1997 // PRINT((
1998 // "* NodeManager::_handleNodesCreated(): POPULATING CONNECTIONS (%ld)\n",
1999 // initialNodes->size()));
2000
2001 for(port_ref_map::const_iterator itDest = initialNodes->begin();
2002 itDest != initialNodes->end(); ++itDest) {
2003
2004 // walk each connected input for this node; find corresponding
2005 // output & fill in a new Connection instance.
2006
2007 NodeRef* destRef = (*itDest).second;
2008 ASSERT(destRef);
2009 if(!(destRef->kind() & B_BUFFER_CONSUMER))
2010 // no inputs
2011 continue;
2012
2013 vector<media_input> inputs;
2014 err = destRef->getConnectedInputs(inputs);
2015
2016 // +++++ FAILED ON STARTUP [e.moon 28sep99]; haven't reproduced yet
2017 // [21oct99] failed again
2018 //ASSERT(err == B_OK);
2019 if(err < B_OK) {
2020 PRINT((
2021 "!!! NodeManager::_handleNodesCreated():\n"
2022 " NodeRef('%s')::getConnectedInputs() failed:\n"
2023 " %s\n",
2024 destRef->name(), strerror(err)));
2025
2026 continue;
2027 }
2028
2029
2030 // PRINT((" - %s: %ld inputs\n", destRef->name(), inputs.size()));
2031
2032 for(vector<media_input>::const_iterator itInput = inputs.begin();
2033 itInput != inputs.end(); ++itInput) {
2034
2035 // look for a matching source node by port ID:
2036 const media_input& input = *itInput;
2037 port_ref_map::const_iterator itSource = initialNodes->find(
2038 input.source.port);
2039
2040 if(itSource == initialNodes->end()) {
2041 // source not found!
2042 PRINT((
2043 "* NodeManager::_handleNodesCreated():\n"
2044 " Building initial Connection set: couldn't find source node\n"
2045 " connected to input '%s' of '%s' (source port %" B_PRId32 ").\n",
2046 input.name, destRef->name(), input.source.port));
2047 continue;
2048 }
2049
2050 // found it; fetch matching output
2051 NodeRef* sourceRef = (*itSource).second;
2052 ASSERT(sourceRef);
2053 media_output output;
2054 err = sourceRef->findOutput(input.source, &output);
2055 if(err < B_OK) {
2056 PRINT((
2057 "* NodeManager::_handleNodesCreated():\n"
2058 " Building initial Connection set: couldn't find output\n"
2059 " in node '%s' connected to input '%s' of '%s'.\n",
2060 sourceRef->name(),
2061 input.name, destRef->name()));
2062 continue;
2063 }
2064
2065 // sanity check
2066 // ASSERT(input.source == output.source);
2067 // ASSERT(input.destination == output.destination);
2068 // diagnostics [e.moon 11jan00]
2069 if(input.source != output.source ||
2070 input.destination != output.destination) {
2071 PRINT((
2072 "!!! NodeManager::_handleNodesCreated():\n"
2073 " input/output mismatch for connection\n"
2074 " '%s' (%s) -> '%s' (%s)\n"
2075 " input.source: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2076 " output.source: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2077 " input.destination: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2078 " output.destination: port %" B_PRId32 ", ID %" B_PRId32 "\n\n",
2079 sourceRef->name(), output.name,
2080 destRef->name(), input.name,
2081 input.source.port, input.source.id,
2082 output.source.port, output.source.id,
2083 input.destination.port, input.destination.id,
2084 output.destination.port, output.destination.id));
2085 continue;
2086 }
2087
2088 // instantiate & add connection
2089
2090 Connection* con = new Connection(
2091 m_nextConID++,
2092 output.node,
2093 output.source,
2094 output.name,
2095 input.node,
2096 input.destination,
2097 input.name,
2098 input.format,
2099 0);
2100
2101 _addConnection(con);
2102
2103 // // [e.moon 7nov99] call hook
2104 // connectionMade(con);
2105
2106 // PRINT((
2107 // "* NodeManager::_handleNodesCreated(): Found initial connection:\n"
2108 // " %s:%s -> %s:%s\n",
2109 // sourceRef->name(), con->outputName(),
2110 // destRef->name(), con->inputName()));
2111
2112 } // for(vector<media_input> ...
2113
2114 } // for(port_ref_map ...
2115
2116 // mark the ordeal as over & done with
2117 m_existingNodesInit = true;
2118 // clean up
2119 delete initialNodes;
2120 }
2121
2122 // don't relay message if no new create notifications were received [e.moon 11oct99]
2123 return refsCreated ? B_OK : B_ERROR;
2124 }
2125
_handleNodesDeleted(BMessage * message)2126 inline void NodeManager::_handleNodesDeleted(
2127 BMessage* message) {
2128 ASSERT(IsLocked());
2129
2130 D_METHOD((
2131 "NodeManager::_handleNodesDeleted()\n"));
2132
2133 // walk the list of deleted nodes, removing & cleaning up refs
2134 // (and any straggler connections)
2135
2136 type_code type;
2137 int32 count;
2138 status_t err = message->GetInfo("media_node_id", &type, &count);
2139 if(err < B_OK) {
2140 PRINT((
2141 "* NodeManager::_handleNodesDeleted(): GetInfo() failed:\n"
2142 " %s\n",
2143 strerror(err)));
2144 return;
2145 }
2146 if(!count)
2147 return;
2148
2149 for(int32 n = 0; n < count; n++) {
2150
2151 int32 id;
2152 err = message->FindInt32("media_node_id", n, &id);
2153 if(err < B_OK) {
2154 PRINT((
2155 "* NodeManager::_handleNodesDeleted(): FindInt32() failed\n"
2156 " %s\n",
2157 strerror(err)));
2158 continue;
2159 }
2160
2161 // fetch ref
2162 NodeRef* ref;
2163 err = getNodeRef(id, &ref);
2164 if(err < B_OK) {
2165 PRINT((
2166 "* NodeManager::_handleNodesDeleted(): getNodeRef(%" B_PRId32
2167 ") failed\n"
2168 " %s\n",
2169 id, strerror(err)));
2170 continue;
2171 }
2172
2173 // find & remove any 'stuck' connections; notify any observers
2174 // that the connections have been removed
2175 vector<Connection> stuckConnections;
2176 ref->getInputConnections(stuckConnections);
2177 ref->getOutputConnections(stuckConnections);
2178
2179 BMessage message(B_MEDIA_CONNECTION_BROKEN);
2180
2181 for(uint32 n = 0; n < stuckConnections.size(); ++n) {
2182 Connection& c = stuckConnections[n];
2183
2184 // generate a complete B_MEDIA_CONNECTION_BROKEN message
2185 // +++++ the message format may be extended in the future -- ick
2186
2187 message.AddData("source", B_RAW_TYPE, &c.source(), sizeof(media_source));
2188 message.AddData("destination", B_RAW_TYPE, &c.destination(), sizeof(media_destination));
2189 message.AddInt32(_connectionField, c.id());
2190 message.AddInt32(_sourceNodeField, c.sourceNode());
2191 message.AddInt32(_destNodeField, c.destinationNode());
2192
2193 _removeConnection(c);
2194 }
2195
2196 // +++++ don't notify if no stuck connections were found
2197 notify(&message);
2198
2199 // ungroup if necessary
2200 if(ref->m_group) {
2201 ASSERT(!ref->isReleased());
2202 ref->m_group->removeNode(ref);
2203 }
2204
2205 // [e.moon 23oct99] mark the node released!
2206 ref->m_nodeReleased = true;
2207
2208 // // [e.moon 7nov99] call hook
2209 // nodeDeleted(ref);
2210
2211 // release it
2212 ref->release();
2213
2214 } // for(int32 n ...
2215 }
2216
_handleConnectionMade(BMessage * message)2217 inline void NodeManager::_handleConnectionMade(
2218 BMessage* message) {
2219 ASSERT(IsLocked());
2220 D_METHOD((
2221 "NodeManager::_handleConnectionMade()\n"));
2222 status_t err;
2223
2224 for(int32 n = 0;;++n) {
2225 media_input input;
2226 media_output output;
2227 const void* data;
2228 ssize_t dataSize;
2229
2230 // fetch output
2231 err = message->FindData("output", B_RAW_TYPE, n, &data, &dataSize);
2232 if(err < B_OK) {
2233 if(!n) {
2234 PRINT((
2235 "* NodeManager::_handleConnectionMade(): no entries in message.\n"));
2236 }
2237 break;
2238 }
2239 if(dataSize < ssize_t(sizeof(media_output))) {
2240 PRINT((
2241 "* NodeManager::_handleConnectionMade(): not enough data for output.\n"));
2242 break;
2243 }
2244 output = *(media_output*)data;
2245
2246 // fetch input
2247 err = message->FindData("input", B_RAW_TYPE, n, &data, &dataSize);
2248 if(err < B_OK) {
2249 if(!n) {
2250 PRINT((
2251 "* NodeManager::_handleConnectionMade(): no complete entries in message.\n"));
2252 }
2253 break;
2254 }
2255 if(dataSize < ssize_t(sizeof(media_input))) {
2256 PRINT((
2257 "* NodeManager::_handleConnectionMade(): not enough data for input.\n"));
2258 break;
2259 }
2260 input = *(media_input*)data;
2261
2262 // look for existing Connection instance
2263 Connection found;
2264 err = findConnection(
2265 output.node.node,
2266 output.source,
2267 &found);
2268 if(err == B_OK) {
2269 PRINT((
2270 " - existing connection for %s -> %s found\n",
2271 found.outputName(), found.inputName()));
2272 continue;
2273 }
2274
2275 // instantiate & add Connection
2276 Connection* con = new Connection(
2277 m_nextConID++,
2278 output.node,
2279 output.source,
2280 output.name,
2281 input.node,
2282 input.destination,
2283 input.name,
2284 input.format,
2285 0);
2286
2287 _addConnection(con);
2288 }
2289 }
2290
2291 // augments message with source and destination node ID's
_handleConnectionBroken(BMessage * message)2292 inline void NodeManager::_handleConnectionBroken(
2293 BMessage* message) {
2294
2295 D_METHOD((
2296 "NodeManager::_handleConnectionBroken()\n"));
2297 status_t err;
2298
2299 // walk the listed connections
2300 for(int32 n=0;;n++) {
2301 media_source source;
2302
2303 const void* data;
2304 ssize_t dataSize;
2305
2306 // fetch source
2307 err = message->FindData("source", B_RAW_TYPE, n, &data, &dataSize);
2308 if(err < B_OK) {
2309 if(!n) {
2310 PRINT((
2311 "* NodeManager::_handleConnectionBroken(): incomplete entry in message.\n"));
2312 }
2313 break;
2314 }
2315 if(dataSize < ssize_t(sizeof(media_source))) {
2316 PRINT((
2317 "* NodeManager::_handleConnectionBroken(): not enough data for source.\n"));
2318 continue;
2319 }
2320 source = *(media_source*)data;
2321
2322 // look up the connection +++++ SLOW +++++
2323 Connection con;
2324 err = findConnection(source, &con);
2325 if(err < B_OK) {
2326 PRINT((
2327 "* NodeManager::_handleConnectionBroken(): connection not found:\n"
2328 " %" B_PRId32 ":%" B_PRId32 "\n",
2329 source.port, source.id));
2330
2331 // add empty entry to message
2332 message->AddInt32(_connectionField, 0);
2333 message->AddInt32(_sourceNodeField, 0);
2334 message->AddInt32(_destNodeField, 0);
2335 continue;
2336 }
2337
2338 // add entry to the message
2339 message->AddInt32(_connectionField, con.id());
2340 message->AddInt32(_sourceNodeField, con.sourceNode());
2341 message->AddInt32(_destNodeField, con.destinationNode());
2342
2343 // // [e.moon 7nov99] call hook
2344 // connectionBroken(&con);
2345
2346 // home free; delete the connection
2347 _removeConnection(con);
2348
2349 } // for(int32 n ...
2350 }
2351
2352 inline void
_handleFormatChanged(BMessage * message)2353 NodeManager::_handleFormatChanged(BMessage *message)
2354 {
2355 D_METHOD((
2356 "NodeManager::_handleFormatChanged()\n"));
2357 status_t err;
2358
2359 ssize_t dataSize;
2360
2361 // fetch source
2362 media_source* source;
2363 err = message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize);
2364 if(err < B_OK) {
2365 PRINT((
2366 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2367 return;
2368 }
2369
2370 // fetch destination
2371 media_destination* destination;
2372 err = message->FindData("be:destination", B_RAW_TYPE, (const void**)&destination, &dataSize);
2373 if(err < B_OK) {
2374 PRINT((
2375 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2376 return;
2377 }
2378
2379 // fetch format
2380 media_format* format;
2381 err = message->FindData("be:format", B_RAW_TYPE, (const void**)&format, &dataSize);
2382 if(err < B_OK) {
2383 PRINT((
2384 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2385 return;
2386 }
2387
2388 // find matching connection
2389 for(con_map::const_iterator it = m_conSourceMap.begin();
2390 it != m_conSourceMap.end(); ++it) {
2391 if((*it).second->source() == *source) {
2392 if((*it).second->destination() != *destination) {
2393 // connection defunct
2394 return;
2395 }
2396
2397 // found
2398 (*it).second->m_format = *format;
2399
2400 // attach node IDs to message
2401 message->AddInt32(_connectionField, (*it).second->id());
2402 message->AddInt32(_sourceNodeField, (*it).second->sourceNode());
2403 message->AddInt32(_destNodeField, (*it).second->destinationNode());
2404
2405 break;
2406 }
2407 }
2408 }
2409
2410
2411 // return flags appropriate for an external
2412 // node with the given 'kind'
2413
_userFlagsForKind(uint32 kind)2414 inline uint32 NodeManager::_userFlagsForKind(
2415 uint32 kind) {
2416
2417 uint32 f = 0;
2418 if(
2419 // kind & B_TIME_SOURCE ||
2420 kind & B_PHYSICAL_OUTPUT
2421 // || kind & B_SYSTEM_MIXER [now in initCommonNodes() e.moon 17nov99]
2422 )
2423 f |= (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
2424
2425 // // [28sep99 e.moon] physical inputs may not be stopped for now; at
2426 // // least one sound input node (for emu10k) stops working when requested
2427 // // to stop.
2428 // // +++++ should this logic be in initCommonNodes()?
2429 // if(
2430 // kind & B_PHYSICAL_INPUT)
2431 // f |= NodeRef::NO_STOP;
2432
2433 return f;
2434 }
2435
_implFlagsForKind(uint32 kind)2436 inline uint32 NodeManager::_implFlagsForKind(
2437 uint32 kind) {
2438
2439 return 0;
2440 }
2441
2442 // [e.moon 28sep99] latency updating
2443 // These methods must set the recording-mode delay for
2444 // any B_RECORDING nodes they handle.
2445
2446 // +++++ abstract to 'for each' and 'for each from'
2447 // methods (template or callback?)
2448
2449
2450 // refresh cached latency for every node in the given group
2451 // (or all nodes if no group given.)
2452
_updateLatencies(NodeGroup * group)2453 inline void NodeManager::_updateLatencies(
2454 NodeGroup* group) {
2455
2456 ASSERT(IsLocked());
2457 if(group) {
2458 ASSERT(group->isLocked());
2459 }
2460
2461 if(group) {
2462 for(NodeGroup::node_set::iterator it = group->m_nodes.begin();
2463 it != group->m_nodes.end(); ++it) {
2464
2465 (*it)->_updateLatency();
2466 }
2467 }
2468 else {
2469 for(node_ref_map::iterator it = m_nodeRefMap.begin();
2470 it != m_nodeRefMap.end(); ++it) {
2471
2472 (*it).second->_updateLatency();
2473 }
2474 }
2475 }
2476
2477 // refresh cached latency for every node attached to
2478 // AND INCLUDING the given origin node.
2479 // if 'recurse' is true, affects indirectly attached
2480 // nodes as well.
2481
2482
_updateLatenciesFrom(NodeRef * origin,bool recurse)2483 inline void NodeManager::_updateLatenciesFrom(
2484 NodeRef* origin,
2485 bool recurse) {
2486
2487 ASSERT(IsLocked());
2488
2489 // PRINT(("### NodeManager::_updateLatenciesFrom()\n"));
2490
2491 origin->lock();
2492 origin->_updateLatency();
2493 origin->unlock();
2494
2495 _lockAllGroups(); // [e.moon 13oct99]
2496
2497 _for_each_state st;
2498 _do_for_each_connected(
2499 this,
2500 origin,
2501 0, // all groups
2502 recurse,
2503 #if __GNUC__ <= 2
2504 mem_fun(&NodeRef::_updateLatency),
2505 #else
2506 [](NodeRef* node) { return node->_updateLatency(); },
2507 #endif
2508 &st);
2509
2510 _unlockAllGroups(); // [e.moon 13oct99]
2511 }
2512
2513 // a bit of unpleasantness [e.moon 13oct99]
_lockAllGroups()2514 void NodeManager::_lockAllGroups() {
2515
2516 ASSERT(IsLocked());
2517 for(node_group_set::iterator it = m_nodeGroupSet.begin();
2518 it != m_nodeGroupSet.end(); ++it) {
2519 (*it)->lock();
2520 }
2521 }
2522
_unlockAllGroups()2523 void NodeManager::_unlockAllGroups() {
2524 ASSERT(IsLocked());
2525 for(node_group_set::iterator it = m_nodeGroupSet.begin();
2526 it != m_nodeGroupSet.end(); ++it) {
2527 (*it)->unlock();
2528 }
2529 }
2530
2531
2532 // END -- NodeManager.cpp --
2533