vfs: check userland buffers before reading them.
[haiku.git] / src / apps / cortex / NodeManager / NodeManager.cpp
bloba4313866feafe48dfb7c577ef5636a8b60fd69c3
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // NodeManager.cpp
34 #include "NodeManager.h"
36 #include "AddOnHost.h"
37 #include "Connection.h"
38 #include "NodeGroup.h"
39 #include "NodeRef.h"
41 #include <Debug.h>
42 #include <MediaRoster.h>
44 #include <algorithm>
45 #include <cstring>
46 #include <functional>
47 #include <list>
48 #include <set>
50 #include "set_tools.h"
51 #include "functional_tools.h"
53 #include "node_manager_impl.h"
55 using namespace std;
57 __USE_CORTEX_NAMESPACE
59 #define D_METHOD(x) //PRINT (x)
60 #define D_MESSAGE(x) //PRINT (x)
61 #define D_ROSTER(x) //PRINT (x)
62 #define D_LOCK(x) //PRINT (x)
64 // -------------------------------------------------------- //
65 // messaging constants
66 // -------------------------------------------------------- //
68 // B_MEDIA_CONNECTION_BROKEN
69 const char* const _connectionField = "__connection_id";
70 const char* const _sourceNodeField = "__source_node_id";
71 const char* const _destNodeField = "__destination_node_id";
76 // -------------------------------------------------------- //
77 // *** hooks
78 // -------------------------------------------------------- //
80 // [e.moon 7nov99] these hooks are called during processing of
81 // BMediaRoster messages, before any notification is sent to
82 // observers. For example, if a B_MEDIA_NODES_CREATED message
83 // were received describing 3 new nodes, nodeCreated() would be
84 // called 3 times before the notification was sent.
86 void NodeManager::nodeCreated(
87 NodeRef* ref) {}
89 void NodeManager::nodeDeleted(
90 const NodeRef* ref) {}
92 void NodeManager::connectionMade(
93 Connection* connection) {}
95 void NodeManager::connectionBroken(
96 const Connection* connection) {}
98 void NodeManager::connectionFailed(
99 const media_output & output,
100 const media_input & input,
101 const media_format & format,
102 status_t error) {}
104 // -------------------------------------------------------- //
105 // helpers
106 // -------------------------------------------------------- //
108 class _for_each_state {
109 public:
110 // marks nodes visited
111 set<media_node_id> visited;
114 // [e.moon 28sep99] graph crawling
115 // - does NOT apply operation to origin node.
116 // - if inGroup is non-0, visits only nodes in that group.
118 // [e.moon 13oct99]: no longer supports locking (use _lockAllGroups() to
119 // be sure all nodes are locked, if necessary.)
121 template<class Op>
122 void _do_for_each_connected(
123 NodeManager* manager,
124 NodeRef* origin,
125 NodeGroup* inGroup,
126 bool recurse,
127 Op operation,
128 _for_each_state* state) {
130 // PRINT(("### _do_for_each_connected()\n"));
132 ASSERT(manager->IsLocked());
134 ASSERT(origin);
135 ASSERT(state);
136 status_t err;
138 if(state->visited.find(origin->id()) != state->visited.end()) {
139 // PRINT(("### already visited\n"));
140 // already visited
141 return;
144 // used to walk connections
145 vector<Connection> connections;
147 // mark visited
148 state->visited.insert(origin->id());
150 // walk input connections
151 origin->getInputConnections(connections);
152 for(uint32 n = 0; n < connections.size(); ++n) {
154 if(!connections[n].isValid())
155 continue;
157 // PRINT(("# source: %ld\n", connections[n].sourceNode()));
159 NodeRef* targetRef;
160 err = manager->getNodeRef(
161 connections[n].sourceNode(),
162 &targetRef);
163 ASSERT(err == B_OK);
164 ASSERT(targetRef);
166 if(inGroup && targetRef->group() != inGroup) {
167 // PRINT(("# .group mismatch\n"));
168 // don't need to visit
169 return;
172 // invoke operation
173 // if(lockRef)
174 // targetRef->lock();
175 operation(targetRef);
176 // if(lockRef)
177 // targetRef->unlock();
179 // recurse?
180 if(recurse)
181 _do_for_each_connected(
182 manager,
183 targetRef,
184 inGroup,
185 true,
186 operation,
187 state);
190 // walk output connections
191 connections.clear();
192 origin->getOutputConnections(connections);
193 for(uint32 n = 0; n < connections.size(); ++n) {
194 // PRINT(("# dest: %ld\n", connections[n].destinationNode()));
196 if(!connections[n].isValid())
197 continue;
199 NodeRef* targetRef;
200 err = manager->getNodeRef(
201 connections[n].destinationNode(),
202 &targetRef);
203 ASSERT(err == B_OK);
204 ASSERT(targetRef);
206 if(inGroup && targetRef->group() != inGroup) {
207 // PRINT(("# .group mismatch\n"));
208 // don't need to visit
209 return;
212 // invoke operation
213 // if(lockRef)
214 // targetRef->lock();
215 operation(targetRef);
216 // if(lockRef)
217 // targetRef->unlock();
219 // recurse?
220 if(recurse)
221 _do_for_each_connected(
222 manager,
223 targetRef,
224 inGroup,
225 true,
226 operation,
227 state);
231 // dtor helpers
232 inline void NodeManager::_clearGroup(
233 NodeGroup* group) {
234 Autolock _l(group);
235 D_METHOD((
236 "NodeManager::_clearGroup()\n"));
238 // stop group before clearing [10aug99]
239 group->_stop();
241 int32 n;
242 while((n = group->countNodes()) > 0) {
243 group->removeNode(n-1);
246 // // [e.moon 7nov99] release the group
247 // status_t err = remove_observer(this, group);
248 // if(err < B_OK) {
249 // // spew diagnostics
250 // PRINT((
251 // "!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n"
252 // " %s\n",
253 // group->id(),
254 // strerror(err)));
255 // }
258 inline void NodeManager::_freeConnection(
259 Connection* connection) {
260 ASSERT(connection);
262 D_METHOD((
263 "NodeManager::_freeConnection(%ld)\n", connection->id()));
264 status_t err;
266 // break if internal & still valid
268 connection->isValid() &&
269 connection->flags() & Connection::INTERNAL &&
270 !(connection->flags() & Connection::LOCKED)) {
272 D_METHOD((
273 "! breaking connection:\n"
274 " source node: %ld\n"
275 " source id: %ld\n"
276 " source port: %ld\n"
277 " dest node: %ld\n"
278 " dest id: %ld\n"
279 " dest port: %ld\n",
280 connection->sourceNode(),
281 connection->source().id, connection->source().port,
282 connection->destinationNode(),
283 connection->destination().id, connection->destination().port));
285 // do it
286 D_ROSTER(("# roster->Disconnect()\n"));
287 err = roster->Disconnect(
288 connection->sourceNode(),
289 connection->source(),
290 connection->destinationNode(),
291 connection->destination());
293 if(err < B_OK) {
294 D_METHOD((
295 "!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n"
296 " %s\n",
297 connection->outputName(), connection->inputName(),
298 strerror(err)));
302 // delete
303 delete connection;
306 // -------------------------------------------------------- //
307 // *** ctor/dtor
308 // -------------------------------------------------------- //
311 NodeManager::~NodeManager() {
312 D_METHOD((
313 "~NodeManager()\n"));
314 ASSERT(IsLocked());
316 // make a list of nodes to be released
317 list<NodeRef*> deadNodes;
319 for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
320 it != m_nodeRefMap.end(); ++it) {
321 deadNodes.push_back((*it).second);
324 // ungroup all nodes
326 // [e.moon 13oct99] making PPC compiler happy
327 // for_each(
328 // m_nodeGroupSet.begin(),
329 // m_nodeGroupSet.end(),
330 // bound_method(
331 // *this,
332 // &NodeManager::_clearGroup
333 // )
334 // );
335 for(node_group_set::iterator it = m_nodeGroupSet.begin();
336 it != m_nodeGroupSet.end(); ++it) {
337 _clearGroup(*it);
340 // delete groups
341 ptr_set_delete(
342 m_nodeGroupSet.begin(),
343 m_nodeGroupSet.end());
344 m_nodeGroupSet.clear();
347 // deallocate all connections; disconnect internal nodes
348 // [e.moon 13oct99] making PPC compiler happy
349 // for_each(
350 // m_conSourceMap.begin(),
351 // m_conSourceMap.end(),
352 // unary_map_function(
353 // m_conSourceMap,
354 // bound_method(
355 // *this,
356 // &NodeManager::_freeConnection
357 // )
358 // )
359 // );
360 for(con_map::iterator it = m_conSourceMap.begin();
361 it != m_conSourceMap.end(); ++it) {
362 _freeConnection((*it).second);
364 m_conSourceMap.clear();
365 m_conDestinationMap.clear();
367 // release all nodes
368 for(list<NodeRef*>::const_iterator it = deadNodes.begin();
369 it != deadNodes.end(); ++it) {
370 (*it)->release();
373 if(m_nodeRefMap.size()) {
374 // +++++ nodes will only remain if they have observers; cope!
375 PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap.size()));
377 deadNodes.clear();
378 for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
379 it != m_nodeRefMap.end(); ++it)
380 deadNodes.push_back((*it).second);
382 ptr_set_delete(
383 deadNodes.begin(),
384 deadNodes.end());
387 // for_each(
388 // m_nodeRefMap.begin(),
389 // m_nodeRefMap.end(),
390 // unary_map_function(
391 // m_nodeRefMap,
392 // mem_fun(
393 // &NodeRef::release
394 // )
395 // )
396 // );
398 // // delete all nodes
399 // ptr_map_delete(
400 // m_nodeRefMap.begin(),
401 // m_nodeRefMap.end());
404 // PRINT((
405 // "~NodeManager() done\n"));
409 const char* const NodeManager::s_defaultGroupPrefix = "No Name";
410 const char* const NodeManager::s_timeSourceGroup = "Time Sources";
411 const char* const NodeManager::s_audioInputGroup = "System Audio Input";
412 const char* const NodeManager::s_videoInputGroup = "System Video Input";
413 const char* const NodeManager::s_audioMixerGroup = "System Audio Mixer";
414 const char* const NodeManager::s_videoOutputGroup = "System Video Output";
416 NodeManager::NodeManager(
417 bool useAddOnHost) :
419 ObservableLooper("NodeManager"),
420 roster(BMediaRoster::Roster()),
421 m_audioInputNode(0),
422 m_videoInputNode(0),
423 m_audioMixerNode(0),
424 m_audioOutputNode(0),
425 m_videoOutputNode(0),
426 m_nextConID(1),
427 m_existingNodesInit(false),
428 m_useAddOnHost(useAddOnHost) {
430 D_METHOD((
431 "NodeManager()\n"));
433 ASSERT(roster);
435 // create refs for common nodes
436 _initCommonNodes();
438 // start the looper
439 Run();
441 // initialize connection to the media roster
442 D_ROSTER(("# roster->StartWatching(%p)\n", this));
443 roster->StartWatching(BMessenger(this));
446 // -------------------------------------------------------- //
447 // *** operations
448 // -------------------------------------------------------- //
450 // * ACCESS
452 // fetches NodeRef corresponding to a given ID; returns
453 // B_BAD_VALUE if no matching entry was found (and writes
454 // a 0 into the provided pointer.)
456 status_t NodeManager::getNodeRef(
457 media_node_id id,
458 NodeRef** outRef) const {
459 Autolock _l(this);
461 D_METHOD((
462 "NodeManager::getNodeRef(%ld)\n", id));
464 node_ref_map::const_iterator it = m_nodeRefMap.find(id);
465 if(it == m_nodeRefMap.end()) {
466 *outRef = 0;
467 return B_BAD_VALUE;
470 *outRef = (*it).second;
471 return B_OK;
474 // [13aug99]
475 // fetches Connection corresponding to a given source/destination
476 // on a given node. Returns an invalid connection and B_BAD_VALUE
477 // if no matching connection was found.
479 status_t NodeManager::findConnection(
480 media_node_id node,
481 const media_source& source,
482 Connection* outConnection) const {
483 Autolock _l(this);
485 D_METHOD((
486 "NodeManager::findConnection()\n"));
487 ASSERT(source != media_source::null);
489 con_map::const_iterator it = m_conSourceMap.lower_bound(node);
490 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(node);
491 for(; it != itEnd; ++it)
492 if((*it).second->source() == source) {
493 // copy connection
494 *outConnection = *((*it).second);
495 return B_OK;
498 *outConnection = Connection();
499 return B_BAD_VALUE;
502 status_t NodeManager::findConnection(
503 media_node_id node,
504 const media_destination& destination,
505 Connection* outConnection) const {
506 Autolock _l(this);
508 D_METHOD((
509 "NodeManager::findConnection()\n"));
510 ASSERT(destination != media_destination::null);
512 con_map::const_iterator it = m_conDestinationMap.lower_bound(node);
513 con_map::const_iterator itEnd = m_conDestinationMap.upper_bound(node);
514 for(; it != itEnd; ++it)
515 if((*it).second->destination() == destination) {
516 // copy connection
517 *outConnection = *((*it).second);
518 return B_OK;
521 *outConnection = Connection();
522 return B_BAD_VALUE;
525 // [e.moon 28sep99]
526 // fetches a Connection matching the given source and destination
527 // nodes. Returns an invalid connection and B_BAD_VALUE if
528 // no matching connection was found
530 status_t NodeManager::findConnection(
531 media_node_id sourceNode,
532 media_node_id destinationNode,
533 Connection* outConnection) const {
534 Autolock _l(this);
536 D_METHOD((
537 "NodeManager::findConnection(source %ld, dest %ld)\n", sourceNode, destinationNode));
539 con_map::const_iterator it = m_conSourceMap.lower_bound(sourceNode);
540 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(sourceNode);
541 for(; it != itEnd; ++it) {
542 if((*it).second->destinationNode() == destinationNode) {
543 *outConnection = *((*it).second);
544 return B_OK;
548 *outConnection = Connection();
549 return B_BAD_VALUE;
552 // [e.moon 28sep99]
553 // tries to find a route from 'nodeA' to 'nodeB'; returns
554 // true if one exists, false if not.
556 class NodeManager::_find_route_state {
557 public:
558 set<media_node_id> visited;
561 bool NodeManager::findRoute(
562 media_node_id nodeA,
563 media_node_id nodeB) {
564 Autolock _l(this);
566 D_METHOD((
567 "NodeManager::findRoute(%ld, %ld)\n", nodeA, nodeB));
568 status_t err;
570 NodeRef* ref;
571 err = getNodeRef(nodeA, &ref);
572 if(err < B_OK) {
573 PRINT((
574 "!!! NodeManager::findRoute(%" B_PRId32 ", %" B_PRId32
575 "): no ref for node %" B_PRId32 "\n", nodeA, nodeB, nodeA));
576 return false;
579 _find_route_state st;
580 return _find_route_recurse(ref, nodeB, &st);
583 // implementation of above
585 bool NodeManager::_find_route_recurse(
586 NodeRef* origin,
587 media_node_id target,
588 _find_route_state* state) {
590 ASSERT(IsLocked());
591 ASSERT(origin);
592 ASSERT(state);
593 status_t err;
595 // node already visited?
596 if(state->visited.find(origin->id()) != state->visited.end()) {
597 return false;
600 // mark node visited
601 state->visited.insert(origin->id());
603 vector<Connection> connections;
605 // walk input connections
606 origin->getInputConnections(connections);
607 for(uint32 n = 0; n < connections.size(); ++n) {
609 if(!connections[n].isValid())
610 continue;
612 // test against target
613 if(connections[n].sourceNode() == target)
614 return true; // SUCCESS
616 // recurse
617 NodeRef* ref;
618 err = getNodeRef(
619 connections[n].sourceNode(),
620 &ref);
621 ASSERT(err == B_OK);
622 ASSERT(ref);
624 if(_find_route_recurse(
625 ref,
626 target,
627 state))
628 return true; // SUCCESS
631 // walk output connections
632 connections.clear();
633 origin->getOutputConnections(connections);
634 for(uint32 n = 0; n < connections.size(); ++n) {
636 if(!connections[n].isValid())
637 continue;
639 // test against target
640 if(connections[n].destinationNode() == target)
641 return true; // SUCCESS
643 // recurse
644 NodeRef* ref;
645 err = getNodeRef(
646 connections[n].destinationNode(),
647 &ref);
648 ASSERT(err == B_OK);
649 ASSERT(ref);
651 if(_find_route_recurse(
652 ref,
653 target,
654 state))
655 return true; // SUCCESS
658 return false; // FAILED
663 // fetches Connection corresponding to a given source or
664 // destination; Returns an invalid connection and B_BAD_VALUE if
665 // none found.
666 // * Note: this is the slowest possible way to look up a
667 // connection. Since the low-level source/destination
668 // structures don't include a node ID, and a destination
669 // port can differ from its node's control port, a linear
670 // search of all known connections is performed. Only
671 // use these methods if you have no clue what node the
672 // connection corresponds to.
674 status_t NodeManager::findConnection(
675 const media_source& source,
676 Connection* outConnection) const {
677 Autolock _l(this);
679 D_METHOD((
680 "NodeManager::findConnection()\n"));
681 ASSERT(source != media_source::null);
683 for(con_map::const_iterator it = m_conSourceMap.begin();
684 it != m_conSourceMap.end(); ++it) {
685 if((*it).second->source() == source) {
686 // copy connection
687 *outConnection = *((*it).second);
688 return B_OK;
692 *outConnection = Connection();
693 return B_BAD_VALUE;
696 status_t NodeManager::findConnection(
697 const media_destination& destination,
698 Connection* outConnection) const {
699 Autolock _l(this);
701 D_METHOD((
702 "NodeManager::findConnection()\n"));
703 ASSERT(destination != media_destination::null);
705 for(con_map::const_iterator it = m_conDestinationMap.begin();
706 it != m_conDestinationMap.end(); ++it) {
707 if((*it).second->destination() == destination) {
708 // copy connection
709 *outConnection = *((*it).second);
710 return B_OK;
714 *outConnection = Connection();
715 return B_BAD_VALUE;
719 // fetch NodeRefs for system nodes (if a particular node doesn't
720 // exist, these methods return 0)
722 NodeRef* NodeManager::audioInputNode() const {
723 Autolock _l(this);
724 return m_audioInputNode;
726 NodeRef* NodeManager::videoInputNode() const {
727 Autolock _l(this);
728 return m_videoInputNode;
730 NodeRef* NodeManager::audioMixerNode() const {
731 Autolock _l(this);
732 return m_audioMixerNode;
734 NodeRef* NodeManager::audioOutputNode() const {
735 Autolock _l(this);
736 return m_audioOutputNode;
738 NodeRef* NodeManager::videoOutputNode() const {
739 Autolock _l(this);
740 return m_videoOutputNode;
743 // fetch groups by index
744 // - you can write-lock the manager during sets of calls to these methods;
745 // this ensures that the group set won't change. The methods do lock
746 // the group internally, so locking isn't explicitly required.
748 uint32 NodeManager::countGroups() const {
749 Autolock _l(this);
750 D_METHOD((
751 "NodeManager::countGroups()\n"));
753 return m_nodeGroupSet.size();
756 NodeGroup* NodeManager::groupAt(
757 uint32 index) const {
758 Autolock _l(this);
759 D_METHOD((
760 "NodeManager::groupAt()\n"));
762 return (index < m_nodeGroupSet.size()) ?
763 m_nodeGroupSet[index] :
767 // look up a group by unique ID; returns B_BAD_VALUE if no
768 // matching group was found
770 class match_group_by_id :
771 public binary_function<const NodeGroup*, uint32, bool> {
772 public:
773 bool operator()(const NodeGroup* group, uint32 id) const {
774 return group->id() == id;
778 status_t NodeManager::findGroup(
779 uint32 id,
780 NodeGroup** outGroup) const {
781 Autolock _l(this);
782 D_METHOD((
783 "NodeManager::findGroup(id)\n"));
785 node_group_set::const_iterator it =
786 find_if(
787 m_nodeGroupSet.begin(),
788 m_nodeGroupSet.end(),
789 bind2nd(match_group_by_id(), id)
792 if(it == m_nodeGroupSet.end()) {
793 *outGroup = 0;
794 return B_BAD_VALUE;
797 *outGroup = *it;
798 return B_OK;
801 // look up a group by name; returns B_NAME_NOT_FOUND if
802 // no group matching the name was found.
804 class match_group_by_name :
805 public binary_function<const NodeGroup*, const char*, bool> {
806 public:
807 bool operator()(const NodeGroup* group, const char* name) const {
808 return !strcmp(group->name(), name);
812 status_t NodeManager::findGroup(
813 const char* name,
814 NodeGroup** outGroup) const {
815 Autolock _l(this);
816 D_METHOD((
817 "NodeManager::findGroup(name)\n"));
819 node_group_set::const_iterator it =
820 find_if(
821 m_nodeGroupSet.begin(),
822 m_nodeGroupSet.end(),
823 bind2nd(match_group_by_name(), name)
826 if(it == m_nodeGroupSet.end()) {
827 *outGroup = 0;
828 return B_BAD_VALUE;
831 *outGroup = *it;
832 return B_OK;
835 // merge the given source group to the given destination;
836 // empties and releases the source group
838 status_t NodeManager::mergeGroups(
839 NodeGroup* sourceGroup,
840 NodeGroup* destinationGroup) {
841 Autolock _l(this);
842 D_METHOD((
843 "NodeManager::mergeGroups(name)\n"));
845 status_t err;
847 // [5feb00 c.lenz] already merged
848 if(sourceGroup->id() == destinationGroup->id())
849 return B_OK;
851 if(sourceGroup->isReleased() || destinationGroup->isReleased())
852 return B_NOT_ALLOWED;
854 for(uint32 n = sourceGroup->countNodes(); n; --n) {
855 NodeRef* node = sourceGroup->nodeAt(n-1);
856 ASSERT(node);
857 err = sourceGroup->removeNode(n-1);
858 ASSERT(err == B_OK);
859 err = destinationGroup->addNode(node);
860 ASSERT(err == B_OK);
863 // [7nov99 e.moon] delete the source group
864 _removeGroup(sourceGroup);
865 sourceGroup->release();
867 return B_OK;
870 // [e.moon 28sep99]
871 // split group: given two nodes currently in the same group
872 // that are not connected (directly OR indirectly),
873 // this method removes outsideNode, and all nodes connected
874 // to outsideNode, from the common group. These nodes are
875 // then added to a new group, returned in 'outGroup'. The
876 // new group has " split" appended to the end of the original
877 // group's name.
879 // Returns B_NOT_ALLOWED if any of the above conditions aren't
880 // met (ie. the nodes are in different groups or an indirect
881 // route exists from one to the other), or B_OK if the group
882 // was split successfully.
885 class _changeNodeGroupFn :
886 public unary_function<NodeRef*, void> {
887 public:
888 NodeGroup* newGroup;
890 _changeNodeGroupFn(
891 NodeGroup* _newGroup) : newGroup(_newGroup) {
892 ASSERT(newGroup);
895 void operator()(
896 NodeRef* node) {
898 PRINT((
899 "_changeNodeGroupFn(): '%s'\n", node->name()));
901 status_t err;
902 NodeGroup* oldGroup = node->group();
903 if(oldGroup) {
904 err = oldGroup->removeNode(node);
905 ASSERT(err == B_OK);
908 err = newGroup->addNode(node);
909 ASSERT(err == B_OK);
913 status_t NodeManager::splitGroup(
914 NodeRef* insideNode,
915 NodeRef* outsideNode,
916 NodeGroup** outGroup) {
918 ASSERT(insideNode);
919 ASSERT(outsideNode);
921 Autolock _l(this);
923 // ensure that no route exists from insideNode to outsideNode
924 if(findRoute(insideNode->id(), outsideNode->id())) {
925 PRINT((
926 "!!! NodeManager::splitGroup(): route exists from %" B_PRId32
927 " to %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
928 return B_NOT_ALLOWED;
931 // make sure the nodes share a common group
932 NodeGroup* oldGroup = insideNode->group();
933 if(!oldGroup) {
934 PRINT(("!!! NodeManager::splitGroup(): invalid group\n"));
935 return B_NOT_ALLOWED;
937 if(oldGroup != outsideNode->group()) {
938 PRINT((
939 "!!! NodeManager::splitGroup(): mismatched groups for %" B_PRId32
940 " and %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
941 return B_NOT_ALLOWED;
944 Autolock _l_old_group(oldGroup);
946 // create the new group
947 BString nameBuffer = oldGroup->name();
948 nameBuffer << " split";
950 NodeGroup* newGroup = createGroup(
951 nameBuffer.String(),
952 oldGroup->runMode());
953 *outGroup = newGroup;
955 // move nodes connected to outsideNode from old to new group
956 _changeNodeGroupFn fn(newGroup);
957 fn(outsideNode);
959 _for_each_state st;
960 _do_for_each_connected(
961 this,
962 outsideNode,
963 oldGroup,
964 true,
966 &st);
968 // [e.moon 1dec99] a single-node group takes that node's name
969 if(newGroup->countNodes() == 1)
970 newGroup->setName(newGroup->nodeAt(0)->name());
972 if(oldGroup->countNodes() == 1)
973 oldGroup->setName(oldGroup->nodeAt(0)->name());
975 return B_OK;
979 // * INSTANTIATION & CONNECTION
980 // Use these calls rather than the associated BMediaRoster()
981 // methods to assure that the nodes and connections you set up
982 // can be properly serialized & reconstituted.
984 // basic BMediaRoster::InstantiateDormantNode() wrapper
986 status_t NodeManager::instantiate(
987 const dormant_node_info& info,
988 NodeRef** outRef,
989 bigtime_t timeout,
990 uint32 nodeFlags) {
992 Autolock _l(this);
993 status_t err;
994 D_METHOD((
995 "NodeManager::instantiate()\n"));
997 // * instantiate
999 media_node node;
1001 if(m_useAddOnHost) {
1002 err = AddOnHost::InstantiateDormantNode(
1003 info, &node, timeout);
1005 if(err < B_OK) {
1006 node = media_node::null;
1008 // attempt to relaunch
1009 BMessenger mess;
1010 err = AddOnHost::Launch(&mess);
1011 if(err < B_OK) {
1012 PRINT((
1013 "!!! NodeManager::instantiate(): giving up on AddOnHost\n"));
1015 m_useAddOnHost = false;
1017 else {
1018 err = AddOnHost::InstantiateDormantNode(
1019 info, &node, timeout);
1024 if(!m_useAddOnHost || node == media_node::null) {
1025 D_ROSTER((
1026 "# roster->InstantiateDormantNode()\n"));
1027 err = roster->InstantiateDormantNode(info, &node);
1030 if(err < B_OK) {
1031 *outRef = 0;
1032 return err;
1035 if(node == media_node::null) {
1036 // [e.moon 23oct99] +++++
1037 // instantiating a soundcard input/output (emu10k or sonic_vibes)
1038 // produces a node ID of -1 (R4.5.2 x86)
1040 PRINT((
1041 "! InstantiateDormantNode(): invalid media node\n"));
1043 // bail out
1044 *outRef = 0;
1045 return B_BAD_INDEX;
1048 // * create NodeRef
1049 NodeRef* ref = new NodeRef(
1050 node,
1051 this,
1052 nodeFlags, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1053 NodeRef::_INTERNAL);
1055 ref->_setAddonHint(&info);
1056 _addRef(ref);
1058 // * return it
1059 *outRef = ref;
1060 return B_OK;
1063 // SniffRef/Instantiate.../SetRefFor: a one-call interface
1064 // to create a node capable of playing a given media file.
1066 status_t NodeManager::instantiate(
1067 const entry_ref& file,
1068 uint64 requireNodeKinds,
1069 NodeRef** outRef,
1070 bigtime_t timeout,
1071 uint32 nodeFlags,
1072 bigtime_t* outDuration) {
1074 D_METHOD((
1075 "NodeManager::instantiate(ref)\n"));
1077 // [no lock needed; calls the full form of instantiate()]
1079 status_t err;
1081 // * Find matching add-on
1082 dormant_node_info info;
1084 D_ROSTER((
1085 "# roster->SniffRef()\n"));
1086 err = roster->SniffRef(
1087 file,
1088 requireNodeKinds,
1089 &info);
1090 if(err < B_OK) {
1091 *outRef = 0;
1092 return err;
1095 // * Instantiate
1096 err = instantiate(info, outRef, timeout, nodeFlags);
1098 if(err < B_OK)
1099 return err;
1101 ASSERT(*outRef);
1103 // * Set file to play
1104 bigtime_t dur;
1105 D_ROSTER(("# roster->SetRefFor()\n"));
1106 err = roster->SetRefFor(
1107 (*outRef)->node(),
1108 file,
1109 false,
1110 &dur);
1112 if(err < B_OK) {
1113 PRINT((
1114 "* SetRefFor() failed: %s\n", strerror(err)));
1116 else if(outDuration)
1117 *outDuration = dur;
1119 // * update info [e.moon 29sep99]
1120 Autolock _l(*outRef);
1121 (*outRef)->_setAddonHint(&info, &file);
1123 return err;
1126 // use this method to reference nodes internal to your
1127 // application.
1129 status_t NodeManager::reference(
1130 BMediaNode* node,
1131 NodeRef** outRef,
1132 uint32 nodeFlags) {
1134 Autolock _l(this);
1135 D_METHOD((
1136 "NodeManager::reference()\n"));
1138 // should this node be marked _NO_RELEASE?
1139 NodeRef* ref = new NodeRef(node->Node(), this, nodeFlags, 0);
1140 _addRef(ref);
1142 *outRef = ref;
1143 return B_OK;
1146 // the most flexible form of connect(): set the template
1147 // format as you would for BMediaRoster::Connect().
1149 status_t NodeManager::connect(
1150 const media_output& output,
1151 const media_input& input,
1152 const media_format& templateFormat,
1153 Connection* outConnection /*=0*/) {
1155 Autolock _l(this);
1156 status_t err;
1157 D_METHOD((
1158 "NodeManager::connect()\n"));
1160 // * Find (& create if necessary) NodeRefs
1162 NodeRef* outputRef;
1163 if(getNodeRef(output.node.node, &outputRef) < B_OK)
1164 outputRef = _addRefFor(output.node, 0);
1166 NodeRef* inputRef;
1167 if(getNodeRef(input.node.node, &inputRef) < B_OK)
1168 inputRef = _addRefFor(input.node, 0);
1170 // * Connect the nodes
1172 media_output finalOutput;
1173 media_input finalInput;
1174 media_format finalFormat = templateFormat;
1176 D_ROSTER(("# roster->Connect()\n"));
1177 err = roster->Connect(
1178 output.source,
1179 input.destination,
1180 &finalFormat,
1181 &finalOutput,
1182 &finalInput);
1184 if(err < B_OK) {
1185 if(outConnection)
1186 *outConnection = Connection();
1187 connectionFailed(output, input, templateFormat, err);
1188 return err;
1191 // * Create Connection instance; mark it INTERNAL
1192 // to automatically remove it upon shutdown.
1194 D_METHOD((
1195 "! creating connection:\n"
1196 " source id: %" B_PRId32 "\n"
1197 " source port: %" B_PRId32 "\n"
1198 " dest id: %" B_PRId32 "\n"
1199 " dest port: %" B_PRId32 "\n",
1200 finalOutput.source.id, finalOutput.source.port,
1201 finalInput.destination.id, finalInput.destination.port));
1203 uint32 cflags = Connection::INTERNAL;
1204 if(outputRef->m_info.node.kind & B_FILE_INTERFACE) {
1205 // 3aug99:
1206 // workaround for bug 19990802-12798:
1207 // connections involving a file-interface node aren't removed
1208 cflags |= Connection::LOCKED;
1211 Connection* con = new Connection(
1212 m_nextConID++,
1213 output.node,
1214 finalOutput.source,
1215 finalOutput.name,
1216 input.node,
1217 finalInput.destination,
1218 finalInput.name,
1219 finalFormat,
1220 cflags);
1222 con->setOutputHint(
1223 output.name,
1224 output.format);
1226 con->setInputHint(
1227 input.name,
1228 input.format);
1230 con->setRequestedFormat(
1231 templateFormat);
1233 _addConnection(con);
1235 // [e.moon 10aug99]
1236 // fetch updated latencies;
1237 // [e.moon 28sep99]
1238 // scan all nodes connected directly OR indirectly to the
1239 // newly-connected nodes and update their latencies -- this includes
1240 // recalculating the node's 'producer delay' if in B_RECORDING mode.
1242 _updateLatenciesFrom(inputRef, true);
1244 // copy connection
1245 if(outConnection) {
1246 *outConnection = *con;
1248 return B_OK;
1251 // format-guessing form of connect(): tries to find
1252 // a common format between output & input before connection;
1253 // returns B_MEDIA_BAD_FORMAT if no common format appears
1254 // possible.
1256 // NOTE: the specifics of the input and output formats are ignored;
1257 // this method only looks at the format type, and properly
1258 // handles wildcards at that level (B_MEDIA_NO_TYPE).
1260 status_t NodeManager::connect(
1261 const media_output& output,
1262 const media_input& input,
1263 Connection* outConnection /*=0*/) {
1265 D_METHOD((
1266 "NodeManager::connect(guess)\n"));
1268 // [no lock needed; calls the full form of connect()]
1270 // defer to the pickier endpoint
1271 media_format f;
1273 if(output.format.type > B_MEDIA_UNKNOWN_TYPE) {
1274 f = output.format;
1275 if ((input.format.type > B_MEDIA_UNKNOWN_TYPE) &&
1276 (f.type != input.format.type)) {
1277 connectionFailed(output, input, f, B_MEDIA_BAD_FORMAT);
1278 return B_MEDIA_BAD_FORMAT;
1281 else if(input.format.type > B_MEDIA_UNKNOWN_TYPE) {
1282 f = input.format;
1283 // output node doesn't care
1285 else {
1286 // about as non-picky as two nodes can possibly be
1287 f.type = B_MEDIA_UNKNOWN_TYPE;
1290 // +++++ ? revert to wildcard ?
1292 // let the nodes try to work out a common format from here
1293 return connect(
1294 output,
1295 input,
1297 outConnection);
1300 // disconnects the connection represented by the provided
1301 // Connection object. if successful, returns B_OK.
1303 status_t NodeManager::disconnect(
1304 const Connection& connection) {
1306 Autolock _l(this);
1307 status_t err;
1308 D_METHOD((
1309 "NodeManager::disconnect()\n"));
1311 // don't bother trying to disconnect an invalid connection
1312 if(!connection.isValid())
1313 return B_NOT_ALLOWED;
1315 // make sure connection can be released
1316 if(connection.flags() & Connection::LOCKED) {
1317 PRINT((
1318 "NodeManager::disconnect(): connection locked:\n"
1319 " %" B_PRId32 ":%s -> %" B_PRId32 ":%s\n",
1320 connection.sourceNode(),
1321 connection.outputName(),
1322 connection.destinationNode(),
1323 connection.inputName()));
1324 return B_NOT_ALLOWED;
1327 D_METHOD((
1328 "! breaking connection:\n"
1329 " source node: %" B_PRId32 "\n"
1330 " source id: %" B_PRId32 "\n"
1331 " source port: %" B_PRId32 "\n"
1332 " dest node: %" B_PRId32 "\n"
1333 " dest id: %" B_PRId32 "\n"
1334 " dest port: %" B_PRId32 "\n",
1335 connection.sourceNode(),
1336 connection.source().id, connection.source().port,
1337 connection.destinationNode(),
1338 connection.destination().id, connection.destination().port));
1340 // do it
1341 D_ROSTER(("# roster->Disconnect()\n"));
1342 err = roster->Disconnect(
1343 connection.sourceNode(),
1344 connection.source(),
1345 connection.destinationNode(),
1346 connection.destination());
1348 // mark disconnected
1349 if(err == B_OK) {
1350 con_map::iterator it = m_conSourceMap.lower_bound(connection.sourceNode());
1351 con_map::iterator itEnd = m_conSourceMap.upper_bound(connection.sourceNode());
1352 for(; it != itEnd; ++it)
1353 if((*it).second->id() == connection.id()) {
1354 (*it).second->m_disconnected = true;
1355 break;
1357 ASSERT(it != itEnd);
1359 // [e.moon 28sep99]
1360 // fetch updated latencies;
1361 // scan all nodes connected directly OR indirectly to the
1362 // newly-connected nodes and update their latencies -- this includes
1363 // recalculating the node's 'producer delay' if in B_RECORDING mode.
1365 NodeRef* ref;
1366 if(getNodeRef(connection.sourceNode(), &ref) == B_OK)
1367 _updateLatenciesFrom(ref, true);
1368 if(getNodeRef(connection.destinationNode(), &ref) == B_OK)
1369 _updateLatenciesFrom(ref, true);
1371 } else {
1372 // +++++ if this failed, somebody somewhere is mighty confused
1373 PRINT((
1374 "NodeManager::disconnect(): Disconnect() failed:\n %s\n",
1375 strerror(err)));
1378 return err;
1381 // * GROUP CREATION
1383 NodeGroup* NodeManager::createGroup(
1384 const char* name,
1385 BMediaNode::run_mode runMode) {
1387 Autolock _l(this);
1388 D_METHOD((
1389 "NodeManager::createGroup()\n"));
1391 NodeGroup* g = new NodeGroup(name, this, runMode);
1392 _addGroup(g);
1394 return g;
1397 // -------------------------------------------------------- //
1398 // *** node/connection iteration
1399 // *** MUST BE LOCKED for any of these calls
1400 // -------------------------------------------------------- //
1402 // usage:
1403 // For the first call, pass 'cookie' a pointer to a void* set to 0.
1404 // Returns B_BAD_INDEX when the set of nodes has been exhausted (and
1405 // re-zeroes the cookie, cleaning up any unused memory.)
1407 status_t NodeManager::getNextRef(
1408 NodeRef** ref,
1409 void** cookie) {
1410 ASSERT(IsLocked());
1411 ASSERT(cookie);
1413 if(!*cookie)
1414 *cookie = new node_ref_map::iterator(m_nodeRefMap.begin());
1416 node_ref_map::iterator* pit = (node_ref_map::iterator*)*cookie;
1418 // at end of set?
1419 if(*pit == m_nodeRefMap.end()) {
1420 delete pit;
1421 *cookie = 0;
1422 return B_BAD_INDEX;
1425 // return next entry
1426 *ref = (*(*pit)).second;
1427 ++(*pit);
1428 return B_OK;
1431 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1432 void NodeManager::disposeRefCookie(
1433 void** cookie) {
1435 if(!cookie)
1436 return;
1438 node_ref_map::iterator* it =
1439 reinterpret_cast<node_ref_map::iterator*>(*cookie);
1440 ASSERT(it);
1441 if(it)
1442 delete it;
1445 status_t NodeManager::getNextConnection(
1446 Connection* connection,
1447 void** cookie) {
1448 ASSERT(IsLocked());
1449 ASSERT(cookie);
1451 if(!*cookie)
1452 *cookie = new con_map::iterator(m_conSourceMap.begin());
1454 con_map::iterator* pit = (con_map::iterator*)*cookie;
1456 // at end of set?
1457 if(*pit == m_conSourceMap.end()) {
1458 delete pit;
1459 *cookie = 0;
1460 return B_BAD_INDEX;
1463 // return next entry (ewww)
1464 *connection = *((*(*pit)).second);
1465 ++(*pit);
1466 return B_OK;
1469 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1470 void NodeManager::disposeConnectionCookie(
1471 void** cookie) {
1473 if(!cookie)
1474 return;
1476 con_map::iterator* it =
1477 reinterpret_cast<con_map::iterator*>(*cookie);
1478 ASSERT(it);
1479 if(it)
1480 delete it;
1484 // -------------------------------------------------------- //
1485 // *** BHandler impl
1486 // -------------------------------------------------------- //
1488 // +++++ support all Media Roster messages! +++++
1490 // [e.moon 7nov99] implemented observer pattern for NodeGroup
1491 void NodeManager::MessageReceived(BMessage* message) {
1493 D_MESSAGE((
1494 "NodeManager::MessageReceived(): %c%c%c%c\n",
1495 message->what >> 24,
1496 (message->what >> 16) & 0xff,
1497 (message->what >> 8) & 0xff,
1498 (message->what) & 0xff));
1500 switch(message->what) {
1502 // *** Media Roster messages ***
1504 case B_MEDIA_NODE_CREATED:
1505 if(_handleNodesCreated(message) == B_OK)
1506 notify(message);
1507 break;
1509 case B_MEDIA_NODE_DELETED:
1510 _handleNodesDeleted(message);
1511 notify(message);
1512 break;
1514 case B_MEDIA_CONNECTION_MADE:
1515 _handleConnectionMade(message);
1516 notify(message);
1517 break;
1519 case B_MEDIA_CONNECTION_BROKEN:
1520 _handleConnectionBroken(message); // augments message!
1521 notify(message);
1522 break;
1524 case B_MEDIA_FORMAT_CHANGED:
1525 _handleFormatChanged(message);
1526 notify(message);
1527 break;
1529 default:
1530 _inherited::MessageReceived(message);
1531 break;
1535 // -------------------------------------------------------- //
1536 // *** IObservable hooks
1537 // -------------------------------------------------------- //
1539 void NodeManager::observerAdded(
1540 const BMessenger& observer) {
1542 BMessage m(M_OBSERVER_ADDED);
1543 m.AddMessenger("target", BMessenger(this));
1544 observer.SendMessage(&m);
1548 void NodeManager::observerRemoved(
1549 const BMessenger& observer) {
1551 BMessage m(M_OBSERVER_REMOVED);
1552 m.AddMessenger("target", BMessenger(this));
1553 observer.SendMessage(&m);
1556 void NodeManager::notifyRelease() {
1558 BMessage m(M_RELEASED);
1559 m.AddMessenger("target", BMessenger(this));
1560 notify(&m);
1563 void NodeManager::releaseComplete() {
1564 // tear down media roster connection
1565 D_ROSTER(("# roster->StopWatching()\n"));
1566 status_t err = roster->StopWatching(
1567 BMessenger(this));
1568 if(err < B_OK) {
1569 PRINT((
1570 "* roster->StopWatching() failed: %s\n", strerror(err)));
1575 // -------------------------------------------------------- //
1576 // *** ILockable impl.
1577 // -------------------------------------------------------- //
1579 bool NodeManager::lock(
1580 lock_t type,
1581 bigtime_t timeout) {
1583 D_LOCK(("*** NodeManager::lock(): %ld\n", find_thread(0)));
1585 status_t err = LockWithTimeout(timeout);
1588 D_LOCK(("*** NodeManager::lock() ACQUIRED: %ld\n", find_thread(0)));
1590 return err == B_OK;
1593 bool NodeManager::unlock(
1594 lock_t type) {
1596 D_LOCK(("*** NodeManager::unlock(): %ld\n", find_thread(0)));
1598 Unlock();
1600 D_LOCK(("*** NodeManager::unlock() RELEASED: %ld\n", find_thread(0)));
1602 return true;
1605 bool NodeManager::isLocked(
1606 lock_t type) const {
1608 return IsLocked();
1611 // -------------------------------------------------------- //
1612 // *** internal operations (LOCK REQUIRED)
1613 // -------------------------------------------------------- //
1615 void NodeManager::_initCommonNodes() {
1617 ASSERT(IsLocked());
1618 status_t err;
1619 media_node node;
1621 D_METHOD((
1622 "NodeManager::_initCommonNodes()\n"));
1624 uint32 disableTransport =
1625 (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
1627 // video input
1628 D_ROSTER(("# roster->GetVideoInput()\n"));
1629 err = roster->GetVideoInput(&node);
1630 if(err == B_OK)
1631 m_videoInputNode = _addRefFor(
1632 node,
1633 _userFlagsForKind(node.kind),
1634 _implFlagsForKind(node.kind));
1636 // video output
1637 D_ROSTER(("# roster->GetVideoOutput()\n"));
1638 err = roster->GetVideoOutput(&node);
1639 if(err == B_OK) {
1640 if(m_videoInputNode && node.node == m_videoInputNode->id()) {
1641 // input and output nodes identical
1642 // [e.moon 20dec99]
1643 m_videoOutputNode = m_videoInputNode;
1645 else {
1646 m_videoOutputNode = _addRefFor(
1647 node,
1648 _userFlagsForKind(node.kind) & ~NodeRef::NO_START_STOP,
1649 _implFlagsForKind(node.kind));
1653 // audio mixer
1654 D_ROSTER(("# roster->GetAudioMixer()\n"));
1655 err = roster->GetAudioMixer(&node);
1656 if(err == B_OK)
1657 m_audioMixerNode = _addRefFor(
1658 node,
1659 _userFlagsForKind(node.kind) | disableTransport,
1660 _implFlagsForKind(node.kind));
1662 // audio input
1663 D_ROSTER(("# roster->GetAudioInput()\n"));
1664 err = roster->GetAudioInput(&node);
1665 if(err == B_OK)
1666 m_audioInputNode = _addRefFor(
1667 node,
1668 _userFlagsForKind(node.kind),
1669 _implFlagsForKind(node.kind));
1671 // audio output
1672 D_ROSTER(("# roster->GetAudioOutput()\n"));
1673 err = roster->GetAudioOutput(&node);
1674 if(err == B_OK) {
1675 if(m_audioInputNode && node.node == m_audioInputNode->id()) {
1676 // input and output nodes identical
1677 // [e.moon 20dec99]
1678 m_audioOutputNode = m_audioInputNode;
1680 // disable transport controls (the default audio output must always
1681 // be running, and can't be seeked.)
1683 m_audioOutputNode->setFlags(
1684 m_audioOutputNode->flags() | disableTransport);
1686 else {
1687 m_audioOutputNode = _addRefFor(
1688 node,
1689 _userFlagsForKind(node.kind) | disableTransport,
1690 _implFlagsForKind(node.kind));
1695 void NodeManager::_addRef(
1696 NodeRef* ref) {
1698 ASSERT(ref);
1699 ASSERT(IsLocked());
1701 D_METHOD((
1702 "NodeManager::_addRef()\n"));
1704 // precondition: no NodeRef yet exists for this node
1705 // +++++
1706 // [e.moon 21oct99]
1707 // <markjan@xs4all.nl> sez this fails on startup w/ MediaKit 10.5
1708 ASSERT(
1709 m_nodeRefMap.find(ref->id()) == m_nodeRefMap.end());
1711 // add it
1712 // [e.moon 13oct99] PPC-friendly
1713 m_nodeRefMap.insert(node_ref_map::value_type(ref->id(), ref));
1715 // [e.moon 8nov99] call hook
1716 nodeCreated(ref);
1719 void NodeManager::_removeRef(
1720 media_node_id id) {
1721 ASSERT(IsLocked());
1723 D_METHOD((
1724 "NodeManager::_removeRef()\n"));
1726 node_ref_map::iterator it = m_nodeRefMap.find(id);
1728 // precondition: a NodeRef w/ matching ID is in the map
1729 ASSERT(it != m_nodeRefMap.end());
1731 // [e.moon 8nov99] call hook
1732 nodeDeleted((*it).second);
1734 // remove it
1735 m_nodeRefMap.erase(it);
1738 // create, add, return a NodeRef for the given external node;
1739 // must not already exist
1740 NodeRef* NodeManager::_addRefFor(
1741 const media_node& node,
1742 uint32 nodeFlags,
1743 uint32 nodeImplFlags) {
1745 ASSERT(IsLocked());
1747 D_METHOD((
1748 "NodeManager::_addRefFor()\n"));
1750 // precondition: no NodeRef yet exists for this node
1751 ASSERT(
1752 m_nodeRefMap.find(node.node) == m_nodeRefMap.end());
1754 // // precondition: the node actually exists
1755 // live_node_info info;
1756 // D_ROSTER(("# roster->GetLiveNodeInfo()\n"));
1757 // ASSERT(roster->GetLiveNodeInfo(node, &info) == B_OK);
1759 // * create & add ref
1760 NodeRef* ref = new NodeRef(node, this, nodeFlags, nodeImplFlags);
1761 _addRef(ref);
1763 return ref;
1766 void NodeManager::_addConnection(
1767 Connection* connection) {
1769 ASSERT(connection);
1770 ASSERT(IsLocked());
1772 D_METHOD((
1773 "NodeManager::_addConnection()\n"));
1775 // precondition: not already entered in either source or dest map
1776 // +++++ a more rigorous test would be a very good thing
1777 #ifdef DEBUG
1778 for(con_map::iterator it = m_conSourceMap.lower_bound(connection->sourceNode());
1779 it != m_conSourceMap.upper_bound(connection->sourceNode()); ++it) {
1780 ASSERT((*it).second->id() != connection->id());
1782 for(con_map::iterator it = m_conDestinationMap.lower_bound(connection->destinationNode());
1783 it != m_conDestinationMap.upper_bound(connection->destinationNode()); ++it) {
1784 ASSERT((*it).second->id() != connection->id());
1786 #endif
1788 // add to both maps
1789 // [e.moon 13oct99] PPC-friendly
1790 m_conSourceMap.insert(
1791 con_map::value_type(
1792 connection->sourceNode(),
1793 connection));
1794 m_conDestinationMap.insert(
1795 con_map::value_type(
1796 connection->destinationNode(),
1797 connection));
1799 // [e.moon 8nov99] call hook
1800 connectionMade(connection);
1803 void NodeManager::_removeConnection(
1804 const Connection& connection) {
1806 ASSERT(IsLocked());
1807 con_map::iterator itSource, itDestination;
1809 D_METHOD((
1810 "NodeManager::_removeConnection()\n"));
1812 // [e.moon 8nov99] call hook
1813 connectionBroken(&connection);
1815 // precondition: one entry in both source & dest maps
1816 // +++++ a more rigorous test would be a very good thing
1818 for(
1819 itSource = m_conSourceMap.lower_bound(connection.sourceNode());
1820 itSource != m_conSourceMap.upper_bound(connection.sourceNode());
1821 ++itSource)
1822 if((*itSource).second->id() == connection.id())
1823 break;
1825 ASSERT(itSource != m_conSourceMap.end());
1827 for(
1828 itDestination = m_conDestinationMap.lower_bound(connection.destinationNode());
1829 itDestination != m_conDestinationMap.upper_bound(connection.destinationNode());
1830 ++itDestination)
1831 if((*itDestination).second->id() == connection.id())
1832 break;
1834 ASSERT(itDestination != m_conDestinationMap.end());
1836 // delete & remove from both maps
1837 delete (*itSource).second;
1838 m_conSourceMap.erase(itSource);
1839 m_conDestinationMap.erase(itDestination);
1842 void NodeManager::_addGroup(
1843 NodeGroup* group) {
1845 ASSERT(group);
1846 ASSERT(IsLocked());
1848 D_METHOD((
1849 "NodeManager::_addGroup()\n"));
1851 // precondition: group not already in set
1852 ASSERT(
1853 find(
1854 m_nodeGroupSet.begin(),
1855 m_nodeGroupSet.end(),
1856 group) == m_nodeGroupSet.end());
1858 // add
1859 m_nodeGroupSet.push_back(group);
1861 // // [e.moon 7nov99] observe
1862 // add_observer(this, group);
1865 void NodeManager::_removeGroup(
1866 NodeGroup* group) {
1868 ASSERT(group);
1869 ASSERT(IsLocked());
1871 D_METHOD((
1872 "NodeManager::_removeGroup()\n"));
1874 node_group_set::iterator it = find(
1875 m_nodeGroupSet.begin(),
1876 m_nodeGroupSet.end(),
1877 group);
1879 // precondition: group in set
1880 if(it == m_nodeGroupSet.end()) {
1881 PRINT((
1882 "* NodeManager::_removeGroup(%" B_PRId32 "): group not in set.\n",
1883 group->id()));
1884 return;
1887 // remove it
1888 m_nodeGroupSet.erase(it);
1891 // -------------------------------------------------------- //
1892 // *** Message Handlers ***
1893 // -------------------------------------------------------- //
1896 // now returns B_OK iff the message should be relayed to observers
1897 // [e.moon 11oct99]
1899 inline status_t NodeManager::_handleNodesCreated(
1900 BMessage* message) {
1901 ASSERT(IsLocked());
1903 status_t err = B_OK;
1905 // fetch number of new nodes
1906 type_code type;
1907 int32 count;
1908 err = message->GetInfo("media_node_id", &type, &count);
1909 if(err < B_OK) {
1910 PRINT((
1911 "* NodeManager::_handleNodesCreated(): GetInfo() failed:\n"
1912 " %s\n",
1913 strerror(err)));
1914 return err;
1916 if(!count) {
1917 PRINT((
1918 "* NodeManager::_handleNodesCreated(): no node IDs in message.\n"));
1919 return err;
1922 D_METHOD((
1923 "NodeManager::_handleNodesCreated(): %" B_PRId32 " nodes\n",
1924 count));
1926 // * Create NodeRef instances for the listed nodes.
1927 // If this is the first message received from the Media Roster,
1928 // no connection info will be received for these nodes; store them
1929 // for now (indexed by service-thread port) and figure the connections
1930 // afterwards.
1931 // These nodes are mapped by port ID because that's the only criterion
1932 // available for matching a media_source to a node.
1934 typedef map<port_id, NodeRef*> port_ref_map;
1935 port_ref_map* initialNodes = m_existingNodesInit ? 0 : new port_ref_map;
1937 bool refsCreated = false;
1939 for(int32 n = 0; n < count; ++n) {
1940 // fetch ID of next node
1941 int32 id;
1942 err = message->FindInt32("media_node_id", n, &id);
1943 if(err < B_OK) {
1944 PRINT((
1945 "* NodeManager::_handleNodesCreated(): FindInt32() failed:\n"
1946 " %s", strerror(err)));
1947 continue;
1950 // look up the node
1951 media_node node;
1952 err = roster->GetNodeFor(id, &node);
1953 if(err < B_OK) {
1954 PRINT((
1955 "* NodeManager::_handleNodesCreated(): roster->GetNodeFor(%"
1956 B_PRId32 ") failed:\n"
1957 " %s\n",
1958 id, strerror(err)));
1959 continue;
1962 // look for an existing NodeRef; if not found, create one:
1963 NodeRef* ref = 0;
1964 if(getNodeRef(node.node, &ref) < B_OK) {
1965 // create one
1966 ref = _addRefFor(
1967 node,
1968 _userFlagsForKind(node.kind), // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1969 _implFlagsForKind(node.kind) | NodeRef::_CREATE_NOTIFIED);
1971 refsCreated = true;
1973 // // [e.moon 7nov99] call hook
1974 // nodeCreated(ref);
1976 } else {
1977 // PRINT((
1978 // "* NodeManager::_handleNodesCreated():\n"
1979 // " found existing ref for '%s' (%ld)\n",
1980 // ref->name(), id));
1983 // set _CREATE_NOTIFIED to prevent notification from being passed on
1984 // twice [e.moon 11oct99]
1985 if(!(ref->m_implFlags & NodeRef::_CREATE_NOTIFIED)) {
1986 ref->m_implFlags |= NodeRef::_CREATE_NOTIFIED;
1987 refsCreated = true;
1990 // release the (duplicate) media_node reference
1991 err = roster->ReleaseNode(node);
1992 if(err < B_OK) {
1993 PRINT((
1994 "* NodeManager::_handleNodesCreated(): roster->ReleaseNode(%"
1995 B_PRId32 ") failed:\n"
1996 " %s\n",
1997 id, strerror(err)));
2001 // add to the 'initial nodes' set if necessary
2002 // [e.moon 13oct99] PPC-friendly
2003 if(initialNodes)
2004 initialNodes->insert(
2005 port_ref_map::value_type(
2006 node.port, ref));
2009 if(initialNodes) {
2010 // populate current connections from each node in the set
2011 // PRINT((
2012 // "* NodeManager::_handleNodesCreated(): POPULATING CONNECTIONS (%ld)\n",
2013 // initialNodes->size()));
2015 for(port_ref_map::const_iterator itDest = initialNodes->begin();
2016 itDest != initialNodes->end(); ++itDest) {
2018 // walk each connected input for this node; find corresponding
2019 // output & fill in a new Connection instance.
2021 NodeRef* destRef = (*itDest).second;
2022 ASSERT(destRef);
2023 if(!(destRef->kind() & B_BUFFER_CONSUMER))
2024 // no inputs
2025 continue;
2027 vector<media_input> inputs;
2028 err = destRef->getConnectedInputs(inputs);
2030 // +++++ FAILED ON STARTUP [e.moon 28sep99]; haven't reproduced yet
2031 // [21oct99] failed again
2032 //ASSERT(err == B_OK);
2033 if(err < B_OK) {
2034 PRINT((
2035 "!!! NodeManager::_handleNodesCreated():\n"
2036 " NodeRef('%s')::getConnectedInputs() failed:\n"
2037 " %s\n",
2038 destRef->name(), strerror(err)));
2040 continue;
2044 // PRINT((" - %s: %ld inputs\n", destRef->name(), inputs.size()));
2046 for(vector<media_input>::const_iterator itInput = inputs.begin();
2047 itInput != inputs.end(); ++itInput) {
2049 // look for a matching source node by port ID:
2050 const media_input& input = *itInput;
2051 port_ref_map::const_iterator itSource = initialNodes->find(
2052 input.source.port);
2054 if(itSource == initialNodes->end()) {
2055 // source not found!
2056 PRINT((
2057 "* NodeManager::_handleNodesCreated():\n"
2058 " Building initial Connection set: couldn't find source node\n"
2059 " connected to input '%s' of '%s' (source port %" B_PRId32 ").\n",
2060 input.name, destRef->name(), input.source.port));
2061 continue;
2064 // found it; fetch matching output
2065 NodeRef* sourceRef = (*itSource).second;
2066 ASSERT(sourceRef);
2067 media_output output;
2068 err = sourceRef->findOutput(input.source, &output);
2069 if(err < B_OK) {
2070 PRINT((
2071 "* NodeManager::_handleNodesCreated():\n"
2072 " Building initial Connection set: couldn't find output\n"
2073 " in node '%s' connected to input '%s' of '%s'.\n",
2074 sourceRef->name(),
2075 input.name, destRef->name()));
2076 continue;
2079 // sanity check
2080 // ASSERT(input.source == output.source);
2081 // ASSERT(input.destination == output.destination);
2082 // diagnostics [e.moon 11jan00]
2083 if(input.source != output.source ||
2084 input.destination != output.destination) {
2085 PRINT((
2086 "!!! NodeManager::_handleNodesCreated():\n"
2087 " input/output mismatch for connection\n"
2088 " '%s' (%s) -> '%s' (%s)\n"
2089 " input.source: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2090 " output.source: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2091 " input.destination: port %" B_PRId32 ", ID %" B_PRId32 "\n"
2092 " output.destination: port %" B_PRId32 ", ID %" B_PRId32 "\n\n",
2093 sourceRef->name(), output.name,
2094 destRef->name(), input.name,
2095 input.source.port, input.source.id,
2096 output.source.port, output.source.id,
2097 input.destination.port, input.destination.id,
2098 output.destination.port, output.destination.id));
2099 continue;
2102 // instantiate & add connection
2104 Connection* con = new Connection(
2105 m_nextConID++,
2106 output.node,
2107 output.source,
2108 output.name,
2109 input.node,
2110 input.destination,
2111 input.name,
2112 input.format,
2115 _addConnection(con);
2117 // // [e.moon 7nov99] call hook
2118 // connectionMade(con);
2120 // PRINT((
2121 // "* NodeManager::_handleNodesCreated(): Found initial connection:\n"
2122 // " %s:%s -> %s:%s\n",
2123 // sourceRef->name(), con->outputName(),
2124 // destRef->name(), con->inputName()));
2126 } // for(vector<media_input> ...
2128 } // for(port_ref_map ...
2130 // mark the ordeal as over & done with
2131 m_existingNodesInit = true;
2132 // clean up
2133 delete initialNodes;
2136 // don't relay message if no new create notifications were received [e.moon 11oct99]
2137 return refsCreated ? B_OK : B_ERROR;
2140 inline void NodeManager::_handleNodesDeleted(
2141 BMessage* message) {
2142 ASSERT(IsLocked());
2144 D_METHOD((
2145 "NodeManager::_handleNodesDeleted()\n"));
2147 // walk the list of deleted nodes, removing & cleaning up refs
2148 // (and any straggler connections)
2150 type_code type;
2151 int32 count;
2152 status_t err = message->GetInfo("media_node_id", &type, &count);
2153 if(err < B_OK) {
2154 PRINT((
2155 "* NodeManager::_handleNodesDeleted(): GetInfo() failed:\n"
2156 " %s\n",
2157 strerror(err)));
2158 return;
2160 if(!count)
2161 return;
2163 for(int32 n = 0; n < count; n++) {
2165 int32 id;
2166 err = message->FindInt32("media_node_id", n, &id);
2167 if(err < B_OK) {
2168 PRINT((
2169 "* NodeManager::_handleNodesDeleted(): FindInt32() failed\n"
2170 " %s\n",
2171 strerror(err)));
2172 continue;
2175 // fetch ref
2176 NodeRef* ref;
2177 err = getNodeRef(id, &ref);
2178 if(err < B_OK) {
2179 PRINT((
2180 "* NodeManager::_handleNodesDeleted(): getNodeRef(%" B_PRId32
2181 ") failed\n"
2182 " %s\n",
2183 id, strerror(err)));
2184 continue;
2187 // find & remove any 'stuck' connections; notify any observers
2188 // that the connections have been removed
2189 vector<Connection> stuckConnections;
2190 ref->getInputConnections(stuckConnections);
2191 ref->getOutputConnections(stuckConnections);
2193 BMessage message(B_MEDIA_CONNECTION_BROKEN);
2195 for(uint32 n = 0; n < stuckConnections.size(); ++n) {
2196 Connection& c = stuckConnections[n];
2198 // generate a complete B_MEDIA_CONNECTION_BROKEN message
2199 // +++++ the message format may be extended in the future -- ick
2201 message.AddData("source", B_RAW_TYPE, &c.source(), sizeof(media_source));
2202 message.AddData("destination", B_RAW_TYPE, &c.destination(), sizeof(media_destination));
2203 message.AddInt32(_connectionField, c.id());
2204 message.AddInt32(_sourceNodeField, c.sourceNode());
2205 message.AddInt32(_destNodeField, c.destinationNode());
2207 _removeConnection(c);
2210 // +++++ don't notify if no stuck connections were found
2211 notify(&message);
2213 // ungroup if necessary
2214 if(ref->m_group) {
2215 ASSERT(!ref->isReleased());
2216 ref->m_group->removeNode(ref);
2219 // [e.moon 23oct99] mark the node released!
2220 ref->m_nodeReleased = true;
2222 // // [e.moon 7nov99] call hook
2223 // nodeDeleted(ref);
2225 // release it
2226 ref->release();
2228 } // for(int32 n ...
2231 inline void NodeManager::_handleConnectionMade(
2232 BMessage* message) {
2233 ASSERT(IsLocked());
2234 D_METHOD((
2235 "NodeManager::_handleConnectionMade()\n"));
2236 status_t err;
2238 for(int32 n = 0;;++n) {
2239 media_input input;
2240 media_output output;
2241 const void* data;
2242 ssize_t dataSize;
2244 // fetch output
2245 err = message->FindData("output", B_RAW_TYPE, n, &data, &dataSize);
2246 if(err < B_OK) {
2247 if(!n) {
2248 PRINT((
2249 "* NodeManager::_handleConnectionMade(): no entries in message.\n"));
2251 break;
2253 if(dataSize < ssize_t(sizeof(media_output))) {
2254 PRINT((
2255 "* NodeManager::_handleConnectionMade(): not enough data for output.\n"));
2256 break;
2258 output = *(media_output*)data;
2260 // fetch input
2261 err = message->FindData("input", B_RAW_TYPE, n, &data, &dataSize);
2262 if(err < B_OK) {
2263 if(!n) {
2264 PRINT((
2265 "* NodeManager::_handleConnectionMade(): no complete entries in message.\n"));
2267 break;
2269 if(dataSize < ssize_t(sizeof(media_input))) {
2270 PRINT((
2271 "* NodeManager::_handleConnectionMade(): not enough data for input.\n"));
2272 break;
2274 input = *(media_input*)data;
2276 // look for existing Connection instance
2277 Connection found;
2278 err = findConnection(
2279 output.node.node,
2280 output.source,
2281 &found);
2282 if(err == B_OK) {
2283 PRINT((
2284 " - existing connection for %s -> %s found\n",
2285 found.outputName(), found.inputName()));
2286 continue;
2289 // instantiate & add Connection
2290 Connection* con = new Connection(
2291 m_nextConID++,
2292 output.node,
2293 output.source,
2294 output.name,
2295 input.node,
2296 input.destination,
2297 input.name,
2298 input.format,
2301 _addConnection(con);
2305 // augments message with source and destination node ID's
2306 inline void NodeManager::_handleConnectionBroken(
2307 BMessage* message) {
2309 D_METHOD((
2310 "NodeManager::_handleConnectionBroken()\n"));
2311 status_t err;
2313 // walk the listed connections
2314 for(int32 n=0;;n++) {
2315 media_source source;
2317 const void* data;
2318 ssize_t dataSize;
2320 // fetch source
2321 err = message->FindData("source", B_RAW_TYPE, n, &data, &dataSize);
2322 if(err < B_OK) {
2323 if(!n) {
2324 PRINT((
2325 "* NodeManager::_handleConnectionBroken(): incomplete entry in message.\n"));
2327 break;
2329 if(dataSize < ssize_t(sizeof(media_source))) {
2330 PRINT((
2331 "* NodeManager::_handleConnectionBroken(): not enough data for source.\n"));
2332 continue;
2334 source = *(media_source*)data;
2336 // look up the connection +++++ SLOW +++++
2337 Connection con;
2338 err = findConnection(source, &con);
2339 if(err < B_OK) {
2340 PRINT((
2341 "* NodeManager::_handleConnectionBroken(): connection not found:\n"
2342 " %" B_PRId32 ":%" B_PRId32 "\n",
2343 source.port, source.id));
2345 // add empty entry to message
2346 message->AddInt32(_connectionField, 0);
2347 message->AddInt32(_sourceNodeField, 0);
2348 message->AddInt32(_destNodeField, 0);
2349 continue;
2352 // add entry to the message
2353 message->AddInt32(_connectionField, con.id());
2354 message->AddInt32(_sourceNodeField, con.sourceNode());
2355 message->AddInt32(_destNodeField, con.destinationNode());
2357 // // [e.moon 7nov99] call hook
2358 // connectionBroken(&con);
2360 // home free; delete the connection
2361 _removeConnection(con);
2363 } // for(int32 n ...
2366 inline void
2367 NodeManager::_handleFormatChanged(BMessage *message)
2369 D_METHOD((
2370 "NodeManager::_handleFormatChanged()\n"));
2371 status_t err;
2373 ssize_t dataSize;
2375 // fetch source
2376 media_source* source;
2377 err = message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize);
2378 if(err < B_OK) {
2379 PRINT((
2380 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2381 return;
2384 // fetch destination
2385 media_destination* destination;
2386 err = message->FindData("be:destination", B_RAW_TYPE, (const void**)&destination, &dataSize);
2387 if(err < B_OK) {
2388 PRINT((
2389 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2390 return;
2393 // fetch format
2394 media_format* format;
2395 err = message->FindData("be:format", B_RAW_TYPE, (const void**)&format, &dataSize);
2396 if(err < B_OK) {
2397 PRINT((
2398 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2399 return;
2402 // find matching connection
2403 for(con_map::const_iterator it = m_conSourceMap.begin();
2404 it != m_conSourceMap.end(); ++it) {
2405 if((*it).second->source() == *source) {
2406 if((*it).second->destination() != *destination) {
2407 // connection defunct
2408 return;
2411 // found
2412 (*it).second->m_format = *format;
2414 // attach node IDs to message
2415 message->AddInt32(_connectionField, (*it).second->id());
2416 message->AddInt32(_sourceNodeField, (*it).second->sourceNode());
2417 message->AddInt32(_destNodeField, (*it).second->destinationNode());
2419 break;
2425 // return flags appropriate for an external
2426 // node with the given 'kind'
2428 inline uint32 NodeManager::_userFlagsForKind(
2429 uint32 kind) {
2431 uint32 f = 0;
2433 // kind & B_TIME_SOURCE ||
2434 kind & B_PHYSICAL_OUTPUT
2435 // || kind & B_SYSTEM_MIXER [now in initCommonNodes() e.moon 17nov99]
2437 f |= (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
2439 // // [28sep99 e.moon] physical inputs may not be stopped for now; at
2440 // // least one sound input node (for emu10k) stops working when requested
2441 // // to stop.
2442 // // +++++ should this logic be in initCommonNodes()?
2443 // if(
2444 // kind & B_PHYSICAL_INPUT)
2445 // f |= NodeRef::NO_STOP;
2447 return f;
2450 inline uint32 NodeManager::_implFlagsForKind(
2451 uint32 kind) {
2453 return 0;
2456 // [e.moon 28sep99] latency updating
2457 // These methods must set the recording-mode delay for
2458 // any B_RECORDING nodes they handle.
2460 // +++++ abstract to 'for each' and 'for each from'
2461 // methods (template or callback?)
2464 // refresh cached latency for every node in the given group
2465 // (or all nodes if no group given.)
2467 inline void NodeManager::_updateLatencies(
2468 NodeGroup* group) {
2470 ASSERT(IsLocked());
2471 if(group) {
2472 ASSERT(group->isLocked());
2475 if(group) {
2476 for(NodeGroup::node_set::iterator it = group->m_nodes.begin();
2477 it != group->m_nodes.end(); ++it) {
2479 (*it)->_updateLatency();
2482 else {
2483 for(node_ref_map::iterator it = m_nodeRefMap.begin();
2484 it != m_nodeRefMap.end(); ++it) {
2486 (*it).second->_updateLatency();
2491 // refresh cached latency for every node attached to
2492 // AND INCLUDING the given origin node.
2493 // if 'recurse' is true, affects indirectly attached
2494 // nodes as well.
2497 inline void NodeManager::_updateLatenciesFrom(
2498 NodeRef* origin,
2499 bool recurse) {
2501 ASSERT(IsLocked());
2503 // PRINT(("### NodeManager::_updateLatenciesFrom()\n"));
2505 origin->lock();
2506 origin->_updateLatency();
2507 origin->unlock();
2509 _lockAllGroups(); // [e.moon 13oct99]
2511 _for_each_state st;
2512 _do_for_each_connected(
2513 this,
2514 origin,
2515 0, // all groups
2516 recurse,
2517 mem_fun(&NodeRef::_updateLatency),
2518 &st);
2520 _unlockAllGroups(); // [e.moon 13oct99]
2523 // a bit of unpleasantness [e.moon 13oct99]
2524 void NodeManager::_lockAllGroups() {
2526 ASSERT(IsLocked());
2527 for(node_group_set::iterator it = m_nodeGroupSet.begin();
2528 it != m_nodeGroupSet.end(); ++it) {
2529 (*it)->lock();
2533 void NodeManager::_unlockAllGroups() {
2534 ASSERT(IsLocked());
2535 for(node_group_set::iterator it = m_nodeGroupSet.begin();
2536 it != m_nodeGroupSet.end(); ++it) {
2537 (*it)->unlock();
2542 // END -- NodeManager.cpp --