2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
34 #include "NodeManager.h"
36 #include "AddOnHost.h"
37 #include "Connection.h"
38 #include "NodeGroup.h"
42 #include <MediaRoster.h>
50 #include "set_tools.h"
51 #include "functional_tools.h"
53 #include "node_manager_impl.h"
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 // -------------------------------------------------------- //
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(
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
,
104 // -------------------------------------------------------- //
106 // -------------------------------------------------------- //
108 class _for_each_state
{
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.)
122 void _do_for_each_connected(
123 NodeManager
* manager
,
128 _for_each_state
* state
) {
130 // PRINT(("### _do_for_each_connected()\n"));
132 ASSERT(manager
->IsLocked());
138 if(state
->visited
.find(origin
->id()) != state
->visited
.end()) {
139 // PRINT(("### already visited\n"));
144 // used to walk connections
145 vector
<Connection
> connections
;
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())
157 // PRINT(("# source: %ld\n", connections[n].sourceNode()));
160 err
= manager
->getNodeRef(
161 connections
[n
].sourceNode(),
166 if(inGroup
&& targetRef
->group() != inGroup
) {
167 // PRINT(("# .group mismatch\n"));
168 // don't need to visit
174 // targetRef->lock();
175 operation(targetRef
);
177 // targetRef->unlock();
181 _do_for_each_connected(
190 // walk output connections
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())
200 err
= manager
->getNodeRef(
201 connections
[n
].destinationNode(),
206 if(inGroup
&& targetRef
->group() != inGroup
) {
207 // PRINT(("# .group mismatch\n"));
208 // don't need to visit
214 // targetRef->lock();
215 operation(targetRef
);
217 // targetRef->unlock();
221 _do_for_each_connected(
232 inline void NodeManager::_clearGroup(
236 "NodeManager::_clearGroup()\n"));
238 // stop group before clearing [10aug99]
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);
249 // // spew diagnostics
251 // "!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n"
258 inline void NodeManager::_freeConnection(
259 Connection
* connection
) {
263 "NodeManager::_freeConnection(%ld)\n", connection
->id()));
266 // break if internal & still valid
268 connection
->isValid() &&
269 connection
->flags() & Connection::INTERNAL
&&
270 !(connection
->flags() & Connection::LOCKED
)) {
273 "! breaking connection:\n"
274 " source node: %ld\n"
276 " source port: %ld\n"
280 connection
->sourceNode(),
281 connection
->source().id
, connection
->source().port
,
282 connection
->destinationNode(),
283 connection
->destination().id
, connection
->destination().port
));
286 D_ROSTER(("# roster->Disconnect()\n"));
287 err
= roster
->Disconnect(
288 connection
->sourceNode(),
289 connection
->source(),
290 connection
->destinationNode(),
291 connection
->destination());
295 "!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n"
297 connection
->outputName(), connection
->inputName(),
306 // -------------------------------------------------------- //
308 // -------------------------------------------------------- //
311 NodeManager::~NodeManager() {
313 "~NodeManager()\n"));
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
);
326 // [e.moon 13oct99] making PPC compiler happy
328 // m_nodeGroupSet.begin(),
329 // m_nodeGroupSet.end(),
332 // &NodeManager::_clearGroup
335 for(node_group_set::iterator it
= m_nodeGroupSet
.begin();
336 it
!= m_nodeGroupSet
.end(); ++it
) {
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
350 // m_conSourceMap.begin(),
351 // m_conSourceMap.end(),
352 // unary_map_function(
356 // &NodeManager::_freeConnection
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();
368 for(list
<NodeRef
*>::const_iterator it
= deadNodes
.begin();
369 it
!= deadNodes
.end(); ++it
) {
373 if(m_nodeRefMap
.size()) {
374 // +++++ nodes will only remain if they have observers; cope!
375 PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap
.size()));
378 for(node_ref_map::const_iterator it
= m_nodeRefMap
.begin();
379 it
!= m_nodeRefMap
.end(); ++it
)
380 deadNodes
.push_back((*it
).second
);
388 // m_nodeRefMap.begin(),
389 // m_nodeRefMap.end(),
390 // unary_map_function(
398 // // delete all nodes
400 // m_nodeRefMap.begin(),
401 // m_nodeRefMap.end());
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(
419 ObservableLooper("NodeManager"),
420 roster(BMediaRoster::Roster()),
424 m_audioOutputNode(0),
425 m_videoOutputNode(0),
427 m_existingNodesInit(false),
428 m_useAddOnHost(useAddOnHost
) {
435 // create refs for common nodes
441 // initialize connection to the media roster
442 D_ROSTER(("# roster->StartWatching(%p)\n", this));
443 roster
->StartWatching(BMessenger(this));
446 // -------------------------------------------------------- //
448 // -------------------------------------------------------- //
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(
458 NodeRef
** outRef
) const {
462 "NodeManager::getNodeRef(%ld)\n", id
));
464 node_ref_map::const_iterator it
= m_nodeRefMap
.find(id
);
465 if(it
== m_nodeRefMap
.end()) {
470 *outRef
= (*it
).second
;
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(
481 const media_source
& source
,
482 Connection
* outConnection
) const {
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
) {
494 *outConnection
= *((*it
).second
);
498 *outConnection
= Connection();
502 status_t
NodeManager::findConnection(
504 const media_destination
& destination
,
505 Connection
* outConnection
) const {
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
) {
517 *outConnection
= *((*it
).second
);
521 *outConnection
= Connection();
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 {
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
);
548 *outConnection
= Connection();
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
{
558 set
<media_node_id
> visited
;
561 bool NodeManager::findRoute(
563 media_node_id nodeB
) {
567 "NodeManager::findRoute(%ld, %ld)\n", nodeA
, nodeB
));
571 err
= getNodeRef(nodeA
, &ref
);
574 "!!! NodeManager::findRoute(%" B_PRId32
", %" B_PRId32
575 "): no ref for node %" B_PRId32
"\n", nodeA
, nodeB
, nodeA
));
579 _find_route_state st
;
580 return _find_route_recurse(ref
, nodeB
, &st
);
583 // implementation of above
585 bool NodeManager::_find_route_recurse(
587 media_node_id target
,
588 _find_route_state
* state
) {
595 // node already visited?
596 if(state
->visited
.find(origin
->id()) != state
->visited
.end()) {
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())
612 // test against target
613 if(connections
[n
].sourceNode() == target
)
614 return true; // SUCCESS
619 connections
[n
].sourceNode(),
624 if(_find_route_recurse(
628 return true; // SUCCESS
631 // walk output connections
633 origin
->getOutputConnections(connections
);
634 for(uint32 n
= 0; n
< connections
.size(); ++n
) {
636 if(!connections
[n
].isValid())
639 // test against target
640 if(connections
[n
].destinationNode() == target
)
641 return true; // SUCCESS
646 connections
[n
].destinationNode(),
651 if(_find_route_recurse(
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
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 {
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
) {
687 *outConnection
= *((*it
).second
);
692 *outConnection
= Connection();
696 status_t
NodeManager::findConnection(
697 const media_destination
& destination
,
698 Connection
* outConnection
) const {
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
) {
709 *outConnection
= *((*it
).second
);
714 *outConnection
= Connection();
719 // fetch NodeRefs for system nodes (if a particular node doesn't
720 // exist, these methods return 0)
722 NodeRef
* NodeManager::audioInputNode() const {
724 return m_audioInputNode
;
726 NodeRef
* NodeManager::videoInputNode() const {
728 return m_videoInputNode
;
730 NodeRef
* NodeManager::audioMixerNode() const {
732 return m_audioMixerNode
;
734 NodeRef
* NodeManager::audioOutputNode() const {
736 return m_audioOutputNode
;
738 NodeRef
* NodeManager::videoOutputNode() const {
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 {
751 "NodeManager::countGroups()\n"));
753 return m_nodeGroupSet
.size();
756 NodeGroup
* NodeManager::groupAt(
757 uint32 index
) const {
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> {
773 bool operator()(const NodeGroup
* group
, uint32 id
) const {
774 return group
->id() == id
;
778 status_t
NodeManager::findGroup(
780 NodeGroup
** outGroup
) const {
783 "NodeManager::findGroup(id)\n"));
785 node_group_set::const_iterator it
=
787 m_nodeGroupSet
.begin(),
788 m_nodeGroupSet
.end(),
789 bind2nd(match_group_by_id(), id
)
792 if(it
== m_nodeGroupSet
.end()) {
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> {
807 bool operator()(const NodeGroup
* group
, const char* name
) const {
808 return !strcmp(group
->name(), name
);
812 status_t
NodeManager::findGroup(
814 NodeGroup
** outGroup
) const {
817 "NodeManager::findGroup(name)\n"));
819 node_group_set::const_iterator it
=
821 m_nodeGroupSet
.begin(),
822 m_nodeGroupSet
.end(),
823 bind2nd(match_group_by_name(), name
)
826 if(it
== m_nodeGroupSet
.end()) {
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
) {
843 "NodeManager::mergeGroups(name)\n"));
847 // [5feb00 c.lenz] already merged
848 if(sourceGroup
->id() == destinationGroup
->id())
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);
857 err
= sourceGroup
->removeNode(n
-1);
859 err
= destinationGroup
->addNode(node
);
863 // [7nov99 e.moon] delete the source group
864 _removeGroup(sourceGroup
);
865 sourceGroup
->release();
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
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> {
891 NodeGroup
* _newGroup
) : newGroup(_newGroup
) {
899 "_changeNodeGroupFn(): '%s'\n", node
->name()));
902 NodeGroup
* oldGroup
= node
->group();
904 err
= oldGroup
->removeNode(node
);
908 err
= newGroup
->addNode(node
);
913 status_t
NodeManager::splitGroup(
915 NodeRef
* outsideNode
,
916 NodeGroup
** outGroup
) {
923 // ensure that no route exists from insideNode to outsideNode
924 if(findRoute(insideNode
->id(), outsideNode
->id())) {
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();
934 PRINT(("!!! NodeManager::splitGroup(): invalid group\n"));
935 return B_NOT_ALLOWED
;
937 if(oldGroup
!= outsideNode
->group()) {
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(
952 oldGroup
->runMode());
953 *outGroup
= newGroup
;
955 // move nodes connected to outsideNode from old to new group
956 _changeNodeGroupFn
fn(newGroup
);
960 _do_for_each_connected(
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());
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
,
995 "NodeManager::instantiate()\n"));
1001 if(m_useAddOnHost
) {
1002 err
= AddOnHost::InstantiateDormantNode(
1003 info
, &node
, timeout
);
1006 node
= media_node::null
;
1008 // attempt to relaunch
1010 err
= AddOnHost::Launch(&mess
);
1013 "!!! NodeManager::instantiate(): giving up on AddOnHost\n"));
1015 m_useAddOnHost
= false;
1018 err
= AddOnHost::InstantiateDormantNode(
1019 info
, &node
, timeout
);
1024 if(!m_useAddOnHost
|| node
== media_node::null
) {
1026 "# roster->InstantiateDormantNode()\n"));
1027 err
= roster
->InstantiateDormantNode(info
, &node
);
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)
1041 "! InstantiateDormantNode(): invalid media node\n"));
1049 NodeRef
* ref
= new NodeRef(
1052 nodeFlags
, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1053 NodeRef::_INTERNAL
);
1055 ref
->_setAddonHint(&info
);
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
,
1072 bigtime_t
* outDuration
) {
1075 "NodeManager::instantiate(ref)\n"));
1077 // [no lock needed; calls the full form of instantiate()]
1081 // * Find matching add-on
1082 dormant_node_info info
;
1085 "# roster->SniffRef()\n"));
1086 err
= roster
->SniffRef(
1096 err
= instantiate(info
, outRef
, timeout
, nodeFlags
);
1103 // * Set file to play
1105 D_ROSTER(("# roster->SetRefFor()\n"));
1106 err
= roster
->SetRefFor(
1114 "* SetRefFor() failed: %s\n", strerror(err
)));
1116 else if(outDuration
)
1119 // * update info [e.moon 29sep99]
1120 Autolock
_l(*outRef
);
1121 (*outRef
)->_setAddonHint(&info
, &file
);
1126 // use this method to reference nodes internal to your
1129 status_t
NodeManager::reference(
1136 "NodeManager::reference()\n"));
1138 // should this node be marked _NO_RELEASE?
1139 NodeRef
* ref
= new NodeRef(node
->Node(), this, nodeFlags
, 0);
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*/) {
1158 "NodeManager::connect()\n"));
1160 // * Find (& create if necessary) NodeRefs
1163 if(getNodeRef(output
.node
.node
, &outputRef
) < B_OK
)
1164 outputRef
= _addRefFor(output
.node
, 0);
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(
1186 *outConnection
= Connection();
1187 connectionFailed(output
, input
, templateFormat
, err
);
1191 // * Create Connection instance; mark it INTERNAL
1192 // to automatically remove it upon shutdown.
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
) {
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(
1217 finalInput
.destination
,
1230 con
->setRequestedFormat(
1233 _addConnection(con
);
1236 // fetch updated latencies;
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);
1246 *outConnection
= *con
;
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
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*/) {
1266 "NodeManager::connect(guess)\n"));
1268 // [no lock needed; calls the full form of connect()]
1270 // defer to the pickier endpoint
1273 if(output
.format
.type
> B_MEDIA_UNKNOWN_TYPE
) {
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
) {
1283 // output node doesn't care
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
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
) {
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
) {
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
;
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
));
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
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;
1357 ASSERT(it
!= itEnd
);
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.
1366 if(getNodeRef(connection
.sourceNode(), &ref
) == B_OK
)
1367 _updateLatenciesFrom(ref
, true);
1368 if(getNodeRef(connection
.destinationNode(), &ref
) == B_OK
)
1369 _updateLatenciesFrom(ref
, true);
1372 // +++++ if this failed, somebody somewhere is mighty confused
1374 "NodeManager::disconnect(): Disconnect() failed:\n %s\n",
1383 NodeGroup
* NodeManager::createGroup(
1385 BMediaNode::run_mode runMode
) {
1389 "NodeManager::createGroup()\n"));
1391 NodeGroup
* g
= new NodeGroup(name
, this, runMode
);
1397 // -------------------------------------------------------- //
1398 // *** node/connection iteration
1399 // *** MUST BE LOCKED for any of these calls
1400 // -------------------------------------------------------- //
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(
1414 *cookie
= new node_ref_map::iterator(m_nodeRefMap
.begin());
1416 node_ref_map::iterator
* pit
= (node_ref_map::iterator
*)*cookie
;
1419 if(*pit
== m_nodeRefMap
.end()) {
1425 // return next entry
1426 *ref
= (*(*pit
)).second
;
1431 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1432 void NodeManager::disposeRefCookie(
1438 node_ref_map::iterator
* it
=
1439 reinterpret_cast<node_ref_map::iterator
*>(*cookie
);
1445 status_t
NodeManager::getNextConnection(
1446 Connection
* connection
,
1452 *cookie
= new con_map::iterator(m_conSourceMap
.begin());
1454 con_map::iterator
* pit
= (con_map::iterator
*)*cookie
;
1457 if(*pit
== m_conSourceMap
.end()) {
1463 // return next entry (ewww)
1464 *connection
= *((*(*pit
)).second
);
1469 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1470 void NodeManager::disposeConnectionCookie(
1476 con_map::iterator
* it
=
1477 reinterpret_cast<con_map::iterator
*>(*cookie
);
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
) {
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
)
1509 case B_MEDIA_NODE_DELETED
:
1510 _handleNodesDeleted(message
);
1514 case B_MEDIA_CONNECTION_MADE
:
1515 _handleConnectionMade(message
);
1519 case B_MEDIA_CONNECTION_BROKEN
:
1520 _handleConnectionBroken(message
); // augments message!
1524 case B_MEDIA_FORMAT_CHANGED
:
1525 _handleFormatChanged(message
);
1530 _inherited::MessageReceived(message
);
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));
1563 void NodeManager::releaseComplete() {
1564 // tear down media roster connection
1565 D_ROSTER(("# roster->StopWatching()\n"));
1566 status_t err
= roster
->StopWatching(
1570 "* roster->StopWatching() failed: %s\n", strerror(err
)));
1575 // -------------------------------------------------------- //
1576 // *** ILockable impl.
1577 // -------------------------------------------------------- //
1579 bool NodeManager::lock(
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)));
1593 bool NodeManager::unlock(
1596 D_LOCK(("*** NodeManager::unlock(): %ld\n", find_thread(0)));
1600 D_LOCK(("*** NodeManager::unlock() RELEASED: %ld\n", find_thread(0)));
1605 bool NodeManager::isLocked(
1606 lock_t type
) const {
1611 // -------------------------------------------------------- //
1612 // *** internal operations (LOCK REQUIRED)
1613 // -------------------------------------------------------- //
1615 void NodeManager::_initCommonNodes() {
1622 "NodeManager::_initCommonNodes()\n"));
1624 uint32 disableTransport
=
1625 (NodeRef::NO_START_STOP
| NodeRef::NO_SEEK
| NodeRef::NO_PREROLL
);
1628 D_ROSTER(("# roster->GetVideoInput()\n"));
1629 err
= roster
->GetVideoInput(&node
);
1631 m_videoInputNode
= _addRefFor(
1633 _userFlagsForKind(node
.kind
),
1634 _implFlagsForKind(node
.kind
));
1637 D_ROSTER(("# roster->GetVideoOutput()\n"));
1638 err
= roster
->GetVideoOutput(&node
);
1640 if(m_videoInputNode
&& node
.node
== m_videoInputNode
->id()) {
1641 // input and output nodes identical
1643 m_videoOutputNode
= m_videoInputNode
;
1646 m_videoOutputNode
= _addRefFor(
1648 _userFlagsForKind(node
.kind
) & ~NodeRef::NO_START_STOP
,
1649 _implFlagsForKind(node
.kind
));
1654 D_ROSTER(("# roster->GetAudioMixer()\n"));
1655 err
= roster
->GetAudioMixer(&node
);
1657 m_audioMixerNode
= _addRefFor(
1659 _userFlagsForKind(node
.kind
) | disableTransport
,
1660 _implFlagsForKind(node
.kind
));
1663 D_ROSTER(("# roster->GetAudioInput()\n"));
1664 err
= roster
->GetAudioInput(&node
);
1666 m_audioInputNode
= _addRefFor(
1668 _userFlagsForKind(node
.kind
),
1669 _implFlagsForKind(node
.kind
));
1672 D_ROSTER(("# roster->GetAudioOutput()\n"));
1673 err
= roster
->GetAudioOutput(&node
);
1675 if(m_audioInputNode
&& node
.node
== m_audioInputNode
->id()) {
1676 // input and output nodes identical
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
);
1687 m_audioOutputNode
= _addRefFor(
1689 _userFlagsForKind(node
.kind
) | disableTransport
,
1690 _implFlagsForKind(node
.kind
));
1695 void NodeManager::_addRef(
1702 "NodeManager::_addRef()\n"));
1704 // precondition: no NodeRef yet exists for this node
1707 // <markjan@xs4all.nl> sez this fails on startup w/ MediaKit 10.5
1709 m_nodeRefMap
.find(ref
->id()) == m_nodeRefMap
.end());
1712 // [e.moon 13oct99] PPC-friendly
1713 m_nodeRefMap
.insert(node_ref_map::value_type(ref
->id(), ref
));
1715 // [e.moon 8nov99] call hook
1719 void NodeManager::_removeRef(
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
);
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
,
1743 uint32 nodeImplFlags
) {
1748 "NodeManager::_addRefFor()\n"));
1750 // precondition: no NodeRef yet exists for this node
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
);
1766 void NodeManager::_addConnection(
1767 Connection
* connection
) {
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
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());
1789 // [e.moon 13oct99] PPC-friendly
1790 m_conSourceMap
.insert(
1791 con_map::value_type(
1792 connection
->sourceNode(),
1794 m_conDestinationMap
.insert(
1795 con_map::value_type(
1796 connection
->destinationNode(),
1799 // [e.moon 8nov99] call hook
1800 connectionMade(connection
);
1803 void NodeManager::_removeConnection(
1804 const Connection
& connection
) {
1807 con_map::iterator itSource
, itDestination
;
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
1819 itSource
= m_conSourceMap
.lower_bound(connection
.sourceNode());
1820 itSource
!= m_conSourceMap
.upper_bound(connection
.sourceNode());
1822 if((*itSource
).second
->id() == connection
.id())
1825 ASSERT(itSource
!= m_conSourceMap
.end());
1828 itDestination
= m_conDestinationMap
.lower_bound(connection
.destinationNode());
1829 itDestination
!= m_conDestinationMap
.upper_bound(connection
.destinationNode());
1831 if((*itDestination
).second
->id() == connection
.id())
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(
1849 "NodeManager::_addGroup()\n"));
1851 // precondition: group not already in set
1854 m_nodeGroupSet
.begin(),
1855 m_nodeGroupSet
.end(),
1856 group
) == m_nodeGroupSet
.end());
1859 m_nodeGroupSet
.push_back(group
);
1861 // // [e.moon 7nov99] observe
1862 // add_observer(this, group);
1865 void NodeManager::_removeGroup(
1872 "NodeManager::_removeGroup()\n"));
1874 node_group_set::iterator it
= find(
1875 m_nodeGroupSet
.begin(),
1876 m_nodeGroupSet
.end(),
1879 // precondition: group in set
1880 if(it
== m_nodeGroupSet
.end()) {
1882 "* NodeManager::_removeGroup(%" B_PRId32
"): group not in set.\n",
1888 m_nodeGroupSet
.erase(it
);
1891 // -------------------------------------------------------- //
1892 // *** Message Handlers ***
1893 // -------------------------------------------------------- //
1896 // now returns B_OK iff the message should be relayed to observers
1899 inline status_t
NodeManager::_handleNodesCreated(
1900 BMessage
* message
) {
1903 status_t err
= B_OK
;
1905 // fetch number of new nodes
1908 err
= message
->GetInfo("media_node_id", &type
, &count
);
1911 "* NodeManager::_handleNodesCreated(): GetInfo() failed:\n"
1918 "* NodeManager::_handleNodesCreated(): no node IDs in message.\n"));
1923 "NodeManager::_handleNodesCreated(): %" B_PRId32
" nodes\n",
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
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
1942 err
= message
->FindInt32("media_node_id", n
, &id
);
1945 "* NodeManager::_handleNodesCreated(): FindInt32() failed:\n"
1946 " %s", strerror(err
)));
1952 err
= roster
->GetNodeFor(id
, &node
);
1955 "* NodeManager::_handleNodesCreated(): roster->GetNodeFor(%"
1956 B_PRId32
") failed:\n"
1958 id
, strerror(err
)));
1962 // look for an existing NodeRef; if not found, create one:
1964 if(getNodeRef(node
.node
, &ref
) < B_OK
) {
1968 _userFlagsForKind(node
.kind
), // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1969 _implFlagsForKind(node
.kind
) | NodeRef::_CREATE_NOTIFIED
);
1973 // // [e.moon 7nov99] call hook
1974 // nodeCreated(ref);
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
;
1990 // release the (duplicate) media_node reference
1991 err
= roster
->ReleaseNode(node
);
1994 "* NodeManager::_handleNodesCreated(): roster->ReleaseNode(%"
1995 B_PRId32
") failed:\n"
1997 id
, strerror(err
)));
2001 // add to the 'initial nodes' set if necessary
2002 // [e.moon 13oct99] PPC-friendly
2004 initialNodes
->insert(
2005 port_ref_map::value_type(
2010 // populate current connections from each node in the set
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
;
2023 if(!(destRef
->kind() & B_BUFFER_CONSUMER
))
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);
2035 "!!! NodeManager::_handleNodesCreated():\n"
2036 " NodeRef('%s')::getConnectedInputs() failed:\n"
2038 destRef
->name(), strerror(err
)));
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(
2054 if(itSource
== initialNodes
->end()) {
2055 // source not found!
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
));
2064 // found it; fetch matching output
2065 NodeRef
* sourceRef
= (*itSource
).second
;
2067 media_output output
;
2068 err
= sourceRef
->findOutput(input
.source
, &output
);
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",
2075 input
.name
, destRef
->name()));
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
) {
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
));
2102 // instantiate & add connection
2104 Connection
* con
= new Connection(
2115 _addConnection(con
);
2117 // // [e.moon 7nov99] call hook
2118 // connectionMade(con);
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;
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
) {
2145 "NodeManager::_handleNodesDeleted()\n"));
2147 // walk the list of deleted nodes, removing & cleaning up refs
2148 // (and any straggler connections)
2152 status_t err
= message
->GetInfo("media_node_id", &type
, &count
);
2155 "* NodeManager::_handleNodesDeleted(): GetInfo() failed:\n"
2163 for(int32 n
= 0; n
< count
; n
++) {
2166 err
= message
->FindInt32("media_node_id", n
, &id
);
2169 "* NodeManager::_handleNodesDeleted(): FindInt32() failed\n"
2177 err
= getNodeRef(id
, &ref
);
2180 "* NodeManager::_handleNodesDeleted(): getNodeRef(%" B_PRId32
2183 id
, strerror(err
)));
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
2213 // ungroup if necessary
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);
2228 } // for(int32 n ...
2231 inline void NodeManager::_handleConnectionMade(
2232 BMessage
* message
) {
2235 "NodeManager::_handleConnectionMade()\n"));
2238 for(int32 n
= 0;;++n
) {
2240 media_output output
;
2245 err
= message
->FindData("output", B_RAW_TYPE
, n
, &data
, &dataSize
);
2249 "* NodeManager::_handleConnectionMade(): no entries in message.\n"));
2253 if(dataSize
< ssize_t(sizeof(media_output
))) {
2255 "* NodeManager::_handleConnectionMade(): not enough data for output.\n"));
2258 output
= *(media_output
*)data
;
2261 err
= message
->FindData("input", B_RAW_TYPE
, n
, &data
, &dataSize
);
2265 "* NodeManager::_handleConnectionMade(): no complete entries in message.\n"));
2269 if(dataSize
< ssize_t(sizeof(media_input
))) {
2271 "* NodeManager::_handleConnectionMade(): not enough data for input.\n"));
2274 input
= *(media_input
*)data
;
2276 // look for existing Connection instance
2278 err
= findConnection(
2284 " - existing connection for %s -> %s found\n",
2285 found
.outputName(), found
.inputName()));
2289 // instantiate & add Connection
2290 Connection
* con
= new Connection(
2301 _addConnection(con
);
2305 // augments message with source and destination node ID's
2306 inline void NodeManager::_handleConnectionBroken(
2307 BMessage
* message
) {
2310 "NodeManager::_handleConnectionBroken()\n"));
2313 // walk the listed connections
2314 for(int32 n
=0;;n
++) {
2315 media_source source
;
2321 err
= message
->FindData("source", B_RAW_TYPE
, n
, &data
, &dataSize
);
2325 "* NodeManager::_handleConnectionBroken(): incomplete entry in message.\n"));
2329 if(dataSize
< ssize_t(sizeof(media_source
))) {
2331 "* NodeManager::_handleConnectionBroken(): not enough data for source.\n"));
2334 source
= *(media_source
*)data
;
2336 // look up the connection +++++ SLOW +++++
2338 err
= findConnection(source
, &con
);
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);
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 ...
2367 NodeManager::_handleFormatChanged(BMessage
*message
)
2370 "NodeManager::_handleFormatChanged()\n"));
2376 media_source
* source
;
2377 err
= message
->FindData("be:source", B_RAW_TYPE
, (const void**)&source
, &dataSize
);
2380 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2384 // fetch destination
2385 media_destination
* destination
;
2386 err
= message
->FindData("be:destination", B_RAW_TYPE
, (const void**)&destination
, &dataSize
);
2389 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2394 media_format
* format
;
2395 err
= message
->FindData("be:format", B_RAW_TYPE
, (const void**)&format
, &dataSize
);
2398 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
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
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());
2425 // return flags appropriate for an external
2426 // node with the given 'kind'
2428 inline uint32
NodeManager::_userFlagsForKind(
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
2442 // // +++++ should this logic be in initCommonNodes()?
2444 // kind & B_PHYSICAL_INPUT)
2445 // f |= NodeRef::NO_STOP;
2450 inline uint32
NodeManager::_implFlagsForKind(
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(
2472 ASSERT(group
->isLocked());
2476 for(NodeGroup::node_set::iterator it
= group
->m_nodes
.begin();
2477 it
!= group
->m_nodes
.end(); ++it
) {
2479 (*it
)->_updateLatency();
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
2497 inline void NodeManager::_updateLatenciesFrom(
2503 // PRINT(("### NodeManager::_updateLatenciesFrom()\n"));
2506 origin
->_updateLatency();
2509 _lockAllGroups(); // [e.moon 13oct99]
2512 _do_for_each_connected(
2517 mem_fun(&NodeRef::_updateLatency
),
2520 _unlockAllGroups(); // [e.moon 13oct99]
2523 // a bit of unpleasantness [e.moon 13oct99]
2524 void NodeManager::_lockAllGroups() {
2527 for(node_group_set::iterator it
= m_nodeGroupSet
.begin();
2528 it
!= m_nodeGroupSet
.end(); ++it
) {
2533 void NodeManager::_unlockAllGroups() {
2535 for(node_group_set::iterator it
= m_nodeGroupSet
.begin();
2536 it
!= m_nodeGroupSet
.end(); ++it
) {
2542 // END -- NodeManager.cpp --