xref: /haiku/src/apps/cortex/NodeManager/NodeGroup.cpp (revision a0795c6fe30e25338049a952326c61deb7a343b6)
1*a0795c6fSMarcus Overhagen // NodeGroup.cpp
2*a0795c6fSMarcus Overhagen 
3*a0795c6fSMarcus Overhagen #include "NodeGroup.h"
4*a0795c6fSMarcus Overhagen //#include "NodeGroup_transport_thread.h"
5*a0795c6fSMarcus Overhagen 
6*a0795c6fSMarcus Overhagen #include "NodeManager.h"
7*a0795c6fSMarcus Overhagen #include "NodeRef.h"
8*a0795c6fSMarcus Overhagen 
9*a0795c6fSMarcus Overhagen #include <MediaRoster.h>
10*a0795c6fSMarcus Overhagen #include <OS.h>
11*a0795c6fSMarcus Overhagen #include <TimeSource.h>
12*a0795c6fSMarcus Overhagen 
13*a0795c6fSMarcus Overhagen #include <algorithm>
14*a0795c6fSMarcus Overhagen #include <functional>
15*a0795c6fSMarcus Overhagen 
16*a0795c6fSMarcus Overhagen #include "array_delete.h"
17*a0795c6fSMarcus Overhagen #include "BasicThread.h"
18*a0795c6fSMarcus Overhagen #include "node_manager_impl.h"
19*a0795c6fSMarcus Overhagen #include "functional_tools.h"
20*a0795c6fSMarcus Overhagen 
21*a0795c6fSMarcus Overhagen __USE_CORTEX_NAMESPACE
22*a0795c6fSMarcus Overhagen #define D_METHOD(x) //PRINT (x)
23*a0795c6fSMarcus Overhagen #define D_ROSTER(x) //PRINT (x)
24*a0795c6fSMarcus Overhagen #define D_LOCK(x) //PRINT (x)
25*a0795c6fSMarcus Overhagen 
26*a0795c6fSMarcus Overhagen 
27*a0795c6fSMarcus Overhagen 
28*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
29*a0795c6fSMarcus Overhagen // *** ctor/dtor
30*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
31*a0795c6fSMarcus Overhagen 
32*a0795c6fSMarcus Overhagen // free the group, including all nodes within it
33*a0795c6fSMarcus Overhagen // (this call will result in the eventual deletion of the object.)
34*a0795c6fSMarcus Overhagen // returns B_OK on success; B_NOT_ALLOWED if release() has
35*a0795c6fSMarcus Overhagen // already been called; other error codes if the Media Roster
36*a0795c6fSMarcus Overhagen // call fails.
37*a0795c6fSMarcus Overhagen // * THE MANAGER MUST BE LOCKED
38*a0795c6fSMarcus Overhagen 
39*a0795c6fSMarcus Overhagen status_t NodeGroup::release() {
40*a0795c6fSMarcus Overhagen 
41*a0795c6fSMarcus Overhagen 	D_METHOD((
42*a0795c6fSMarcus Overhagen 		"NodeGroup::release()\n"));
43*a0795c6fSMarcus Overhagen 
44*a0795c6fSMarcus Overhagen 	if(isReleased())
45*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
46*a0795c6fSMarcus Overhagen 
47*a0795c6fSMarcus Overhagen 	// clean up
48*a0795c6fSMarcus Overhagen 	lock();
49*a0795c6fSMarcus Overhagen 
50*a0795c6fSMarcus Overhagen 	// halt all nodes
51*a0795c6fSMarcus Overhagen 	_stop();
52*a0795c6fSMarcus Overhagen 
53*a0795c6fSMarcus Overhagen 	// remove & release all nodes
54*a0795c6fSMarcus Overhagen 	// +++++ causes triply-nested lock: eww!
55*a0795c6fSMarcus Overhagen 	while(m_nodes.size()) {
56*a0795c6fSMarcus Overhagen 		NodeRef* last = m_nodes.back();
57*a0795c6fSMarcus Overhagen 		removeNode(m_nodes.size()-1);
58*a0795c6fSMarcus Overhagen 		last->release();
59*a0795c6fSMarcus Overhagen 	}
60*a0795c6fSMarcus Overhagen 
61*a0795c6fSMarcus Overhagen 	unlock();
62*a0795c6fSMarcus Overhagen 
63*a0795c6fSMarcus Overhagen // [e.moon 7nov99]
64*a0795c6fSMarcus Overhagen // removing the released group is now NodeManager's responsibility
65*a0795c6fSMarcus Overhagen //
66*a0795c6fSMarcus Overhagen 	// remove from NodeManager
67*a0795c6fSMarcus Overhagen 	if(!m_manager->lock()) {
68*a0795c6fSMarcus Overhagen 		ASSERT(!"* m_manager->lock() failed.\n");
69*a0795c6fSMarcus Overhagen 	}
70*a0795c6fSMarcus Overhagen 	m_manager->_removeGroup(this);
71*a0795c6fSMarcus Overhagen 	m_manager->unlock();
72*a0795c6fSMarcus Overhagen 
73*a0795c6fSMarcus Overhagen 	// hand off to IObservable
74*a0795c6fSMarcus Overhagen 	return _inherited::release();
75*a0795c6fSMarcus Overhagen }
76*a0795c6fSMarcus Overhagen 
77*a0795c6fSMarcus Overhagen // call release() rather than deleting NodeGroup objects
78*a0795c6fSMarcus Overhagen NodeGroup::~NodeGroup() {
79*a0795c6fSMarcus Overhagen 
80*a0795c6fSMarcus Overhagen 	Autolock _l(this);
81*a0795c6fSMarcus Overhagen 	D_METHOD((
82*a0795c6fSMarcus Overhagen 		"~NodeGroup()\n"));
83*a0795c6fSMarcus Overhagen 
84*a0795c6fSMarcus Overhagen 	ASSERT(!m_nodes.size());
85*a0795c6fSMarcus Overhagen 
86*a0795c6fSMarcus Overhagen 	if(m_timeSourceObj) {
87*a0795c6fSMarcus Overhagen 		m_timeSourceObj->Release();
88*a0795c6fSMarcus Overhagen 		m_timeSourceObj = 0;
89*a0795c6fSMarcus Overhagen 	}
90*a0795c6fSMarcus Overhagen }
91*a0795c6fSMarcus Overhagen 
92*a0795c6fSMarcus Overhagen 
93*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
94*a0795c6fSMarcus Overhagen // *** accessors
95*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
96*a0795c6fSMarcus Overhagen 
97*a0795c6fSMarcus Overhagen // [e.moon 13oct99] moved to header
98*a0795c6fSMarcus Overhagen //inline uint32 NodeGroup::id() const { return m_id; }
99*a0795c6fSMarcus Overhagen 
100*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
101*a0795c6fSMarcus Overhagen // *** operations
102*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
103*a0795c6fSMarcus Overhagen 
104*a0795c6fSMarcus Overhagen // name access
105*a0795c6fSMarcus Overhagen const char* NodeGroup::name() const {
106*a0795c6fSMarcus Overhagen 	Autolock _l(this);
107*a0795c6fSMarcus Overhagen 	return m_name.String();
108*a0795c6fSMarcus Overhagen }
109*a0795c6fSMarcus Overhagen 
110*a0795c6fSMarcus Overhagen status_t NodeGroup::setName(const char* name) {
111*a0795c6fSMarcus Overhagen 	Autolock _l(this);
112*a0795c6fSMarcus Overhagen 	m_name = name;
113*a0795c6fSMarcus Overhagen 	return B_OK;
114*a0795c6fSMarcus Overhagen }
115*a0795c6fSMarcus Overhagen 
116*a0795c6fSMarcus Overhagen // content access
117*a0795c6fSMarcus Overhagen uint32 NodeGroup::countNodes() const {
118*a0795c6fSMarcus Overhagen 	Autolock _l(this);
119*a0795c6fSMarcus Overhagen 	return m_nodes.size();
120*a0795c6fSMarcus Overhagen }
121*a0795c6fSMarcus Overhagen 
122*a0795c6fSMarcus Overhagen NodeRef* NodeGroup::nodeAt(
123*a0795c6fSMarcus Overhagen 	uint32											index) const {
124*a0795c6fSMarcus Overhagen 	Autolock _l(this);
125*a0795c6fSMarcus Overhagen 	return (index < m_nodes.size()) ?
126*a0795c6fSMarcus Overhagen 		m_nodes[index] :
127*a0795c6fSMarcus Overhagen 		0;
128*a0795c6fSMarcus Overhagen }
129*a0795c6fSMarcus Overhagen 
130*a0795c6fSMarcus Overhagen // add/remove nodes:
131*a0795c6fSMarcus Overhagen // - you may only add a node with no current group.
132*a0795c6fSMarcus Overhagen // - nodes added during playback will be started;
133*a0795c6fSMarcus Overhagen //   nodes removed during playback will be stopped (unless
134*a0795c6fSMarcus Overhagen //   the NO_START_STOP transport restriction flag is set
135*a0795c6fSMarcus Overhagen //   for a given node.)
136*a0795c6fSMarcus Overhagen 
137*a0795c6fSMarcus Overhagen status_t NodeGroup::addNode(
138*a0795c6fSMarcus Overhagen 	NodeRef*										node) {
139*a0795c6fSMarcus Overhagen 
140*a0795c6fSMarcus Overhagen 	D_METHOD((
141*a0795c6fSMarcus Overhagen 		"NodeGroup::addNode()\n"));
142*a0795c6fSMarcus Overhagen 
143*a0795c6fSMarcus Overhagen 	// lock the manager first; if the node has no current group,
144*a0795c6fSMarcus Overhagen 	// this locks the node.
145*a0795c6fSMarcus Overhagen 	m_manager->lock();
146*a0795c6fSMarcus Overhagen 
147*a0795c6fSMarcus Overhagen 	Autolock _l(this);
148*a0795c6fSMarcus Overhagen 
149*a0795c6fSMarcus Overhagen 	// precondition: GROUP_LOCKED not set
150*a0795c6fSMarcus Overhagen 	if(m_flags & GROUP_LOCKED)
151*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
152*a0795c6fSMarcus Overhagen 
153*a0795c6fSMarcus Overhagen 	// precondition: no current group
154*a0795c6fSMarcus Overhagen 	if(node->m_group) {
155*a0795c6fSMarcus Overhagen 		// [e.moon 28sep99] whoops, forgot one
156*a0795c6fSMarcus Overhagen 		PRINT((
157*a0795c6fSMarcus Overhagen 			"!!! node already in group '%s'\n", node->m_group->name()));
158*a0795c6fSMarcus Overhagen 
159*a0795c6fSMarcus Overhagen 		m_manager->unlock();
160*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
161*a0795c6fSMarcus Overhagen 	}
162*a0795c6fSMarcus Overhagen 
163*a0795c6fSMarcus Overhagen 	// add it
164*a0795c6fSMarcus Overhagen 	m_nodes.push_back(node);
165*a0795c6fSMarcus Overhagen 	node->_setGroup(this);
166*a0795c6fSMarcus Overhagen 
167*a0795c6fSMarcus Overhagen 	// release the manager
168*a0795c6fSMarcus Overhagen 	m_manager->unlock();
169*a0795c6fSMarcus Overhagen 
170*a0795c6fSMarcus Overhagen 	// first node? the transport is now ready to start
171*a0795c6fSMarcus Overhagen 	if(m_nodes.size() == 1) {
172*a0795c6fSMarcus Overhagen 		_changeState(TRANSPORT_INVALID, TRANSPORT_STOPPED);
173*a0795c6fSMarcus Overhagen 	}
174*a0795c6fSMarcus Overhagen //
175*a0795c6fSMarcus Overhagen //	if(m_syncNode == media_node::null) {
176*a0795c6fSMarcus Overhagen //		// assign as sync node
177*a0795c6fSMarcus Overhagen //		setSyncNode(node->node());
178*a0795c6fSMarcus Overhagen //	}
179*a0795c6fSMarcus Overhagen //
180*a0795c6fSMarcus Overhagen 	// initialize the new node
181*a0795c6fSMarcus Overhagen 	status_t err = node->_initTransportState();
182*a0795c6fSMarcus Overhagen 	if(err < B_OK)
183*a0795c6fSMarcus Overhagen 		return err;
184*a0795c6fSMarcus Overhagen 
185*a0795c6fSMarcus Overhagen 	// set time source
186*a0795c6fSMarcus Overhagen 	node->_setTimeSource(m_timeSource.node);
187*a0795c6fSMarcus Overhagen 
188*a0795c6fSMarcus Overhagen 	// set run mode
189*a0795c6fSMarcus Overhagen 	node->_setRunMode(m_runMode);
190*a0795c6fSMarcus Overhagen 
191*a0795c6fSMarcus Overhagen 	// add to cycle set if need be
192*a0795c6fSMarcus Overhagen 	// +++++ should I call _cycleAddRef() instead?
193*a0795c6fSMarcus Overhagen 	if(node->m_cycle)
194*a0795c6fSMarcus Overhagen 		_refCycleChanged(node);
195*a0795c6fSMarcus Overhagen 
196*a0795c6fSMarcus Overhagen 	if(m_transportState == TRANSPORT_RUNNING) {
197*a0795c6fSMarcus Overhagen 		// +++++ start if necessary!
198*a0795c6fSMarcus Overhagen 	}
199*a0795c6fSMarcus Overhagen 	// +++++ not started if TRANSPORT_ROLLING: is that proper? [e.moon 11oct99]
200*a0795c6fSMarcus Overhagen 
201*a0795c6fSMarcus Overhagen 	// send notification
202*a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
203*a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
204*a0795c6fSMarcus Overhagen 	}
205*a0795c6fSMarcus Overhagen 	BMessage m(M_NODE_ADDED);
206*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
207*a0795c6fSMarcus Overhagen 	m.AddInt32("nodeID", node->id());
208*a0795c6fSMarcus Overhagen 	notify(&m);
209*a0795c6fSMarcus Overhagen 	UnlockLooper();
210*a0795c6fSMarcus Overhagen 
211*a0795c6fSMarcus Overhagen 	// success
212*a0795c6fSMarcus Overhagen 	return B_OK;
213*a0795c6fSMarcus Overhagen }
214*a0795c6fSMarcus Overhagen 
215*a0795c6fSMarcus Overhagen 
216*a0795c6fSMarcus Overhagen status_t NodeGroup::removeNode(
217*a0795c6fSMarcus Overhagen 	NodeRef*										node) {
218*a0795c6fSMarcus Overhagen 
219*a0795c6fSMarcus Overhagen 	D_METHOD((
220*a0795c6fSMarcus Overhagen 		"NodeGroup::removeNode()\n"));
221*a0795c6fSMarcus Overhagen 
222*a0795c6fSMarcus Overhagen 	// lock the manager first; once the node is ungrouped,
223*a0795c6fSMarcus Overhagen 	// the manager lock applies to it
224*a0795c6fSMarcus Overhagen 	m_manager->lock();
225*a0795c6fSMarcus Overhagen 
226*a0795c6fSMarcus Overhagen 	Autolock _l(this);
227*a0795c6fSMarcus Overhagen 
228*a0795c6fSMarcus Overhagen 	// precondition: this must be the node's group
229*a0795c6fSMarcus Overhagen 	if(node->m_group != this) {
230*a0795c6fSMarcus Overhagen 		// [e.moon 28sep99] whoops, forgot one
231*a0795c6fSMarcus Overhagen 		PRINT((
232*a0795c6fSMarcus Overhagen 			"!!! node not in group '%s'\n", node->m_group->name()));
233*a0795c6fSMarcus Overhagen 
234*a0795c6fSMarcus Overhagen 		m_manager->unlock();
235*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
236*a0795c6fSMarcus Overhagen 	}
237*a0795c6fSMarcus Overhagen 
238*a0795c6fSMarcus Overhagen 	// remove from the cycle set
239*a0795c6fSMarcus Overhagen 	if(node->m_cycle)
240*a0795c6fSMarcus Overhagen 		_cycleRemoveRef(node);
241*a0795c6fSMarcus Overhagen 
242*a0795c6fSMarcus Overhagen 	// remove it
243*a0795c6fSMarcus Overhagen 	ASSERT(m_nodes.size());
244*a0795c6fSMarcus Overhagen 	remove(
245*a0795c6fSMarcus Overhagen 		m_nodes.begin(),
246*a0795c6fSMarcus Overhagen 		m_nodes.end(),
247*a0795c6fSMarcus Overhagen 		node);
248*a0795c6fSMarcus Overhagen 
249*a0795c6fSMarcus Overhagen 	// should have removed one and only one entry
250*a0795c6fSMarcus Overhagen 	m_nodes.resize(m_nodes.size()-1);
251*a0795c6fSMarcus Overhagen 
252*a0795c6fSMarcus Overhagen //	// 6aug99: the timesource is now the sync node...
253*a0795c6fSMarcus Overhagen //	// is this the sync node? reassign if so
254*a0795c6fSMarcus Overhagen //
255*a0795c6fSMarcus Overhagen //	if(node->node() == m_syncNode) {
256*a0795c6fSMarcus Overhagen //
257*a0795c6fSMarcus Overhagen //		// look for another sync-capable node
258*a0795c6fSMarcus Overhagen //		bool found = false;
259*a0795c6fSMarcus Overhagen //		for(int n = 0; !found && n < m_nodes.size(); ++n)
260*a0795c6fSMarcus Overhagen //			if(setSyncNode(m_nodes[n]->node()) == B_OK)
261*a0795c6fSMarcus Overhagen //				found = true;
262*a0795c6fSMarcus Overhagen //
263*a0795c6fSMarcus Overhagen //		// no luck? admit defeat:
264*a0795c6fSMarcus Overhagen //		if(!found) {
265*a0795c6fSMarcus Overhagen //			PRINT((
266*a0795c6fSMarcus Overhagen //				"* NodeGroup::removeNode(): no sync-capable nodes left!\n"));
267*a0795c6fSMarcus Overhagen //
268*a0795c6fSMarcus Overhagen //			// +++++ stop & set to invalid state?
269*a0795c6fSMarcus Overhagen //
270*a0795c6fSMarcus Overhagen //			setSyncNode(media_node::null);
271*a0795c6fSMarcus Overhagen //		}
272*a0795c6fSMarcus Overhagen //	}
273*a0795c6fSMarcus Overhagen 
274*a0795c6fSMarcus Overhagen 	// stop the node if necessary
275*a0795c6fSMarcus Overhagen 	status_t err = node->_stop();
276*a0795c6fSMarcus Overhagen 	if(err < B_OK) {
277*a0795c6fSMarcus Overhagen 		PRINT((
278*a0795c6fSMarcus Overhagen 			"*** NodeGroup::removeNode('%s'): error from node->_stop():\n"
279*a0795c6fSMarcus Overhagen 			"    %s\n",
280*a0795c6fSMarcus Overhagen 			node->name(),
281*a0795c6fSMarcus Overhagen 			strerror(err)));
282*a0795c6fSMarcus Overhagen 	}
283*a0795c6fSMarcus Overhagen 
284*a0795c6fSMarcus Overhagen 	// clear the node's group pointer
285*a0795c6fSMarcus Overhagen 	node->_setGroup(0);
286*a0795c6fSMarcus Overhagen 
287*a0795c6fSMarcus Overhagen 	// release the manager lock; the node is now ungrouped and
288*a0795c6fSMarcus Overhagen 	// unlocked
289*a0795c6fSMarcus Overhagen 	m_manager->unlock();
290*a0795c6fSMarcus Overhagen 
291*a0795c6fSMarcus Overhagen 	// was that the last node? stop/disable the transport if so
292*a0795c6fSMarcus Overhagen 	if(!m_nodes.size()) {
293*a0795c6fSMarcus Overhagen 
294*a0795c6fSMarcus Overhagen 		// +++++ kill sync thread(s)
295*a0795c6fSMarcus Overhagen 
296*a0795c6fSMarcus Overhagen 		_changeState(TRANSPORT_INVALID);
297*a0795c6fSMarcus Overhagen 	}
298*a0795c6fSMarcus Overhagen 
299*a0795c6fSMarcus Overhagen 	// send notification
300*a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
301*a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
302*a0795c6fSMarcus Overhagen 	}
303*a0795c6fSMarcus Overhagen 	BMessage m(M_NODE_REMOVED);
304*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
305*a0795c6fSMarcus Overhagen 	m.AddInt32("nodeID", node->id());
306*a0795c6fSMarcus Overhagen 	notify(&m);
307*a0795c6fSMarcus Overhagen 	UnlockLooper();
308*a0795c6fSMarcus Overhagen 
309*a0795c6fSMarcus Overhagen 	// success
310*a0795c6fSMarcus Overhagen 	return B_OK;
311*a0795c6fSMarcus Overhagen }
312*a0795c6fSMarcus Overhagen 
313*a0795c6fSMarcus Overhagen status_t NodeGroup::removeNode(
314*a0795c6fSMarcus Overhagen 	uint32											index) {
315*a0795c6fSMarcus Overhagen 
316*a0795c6fSMarcus Overhagen 	D_METHOD((
317*a0795c6fSMarcus Overhagen 		"NodeGroup::removeNode(by index)\n"));
318*a0795c6fSMarcus Overhagen 
319*a0795c6fSMarcus Overhagen 	// +++++ icky nested lock
320*a0795c6fSMarcus Overhagen 	Autolock _l(this);
321*a0795c6fSMarcus Overhagen 
322*a0795c6fSMarcus Overhagen 	ASSERT(m_nodes.size() > index);
323*a0795c6fSMarcus Overhagen 	return removeNode(m_nodes[index]);
324*a0795c6fSMarcus Overhagen }
325*a0795c6fSMarcus Overhagen 
326*a0795c6fSMarcus Overhagen uint32 NodeGroup::groupFlags() const {
327*a0795c6fSMarcus Overhagen 	Autolock _l(this);
328*a0795c6fSMarcus Overhagen 	return m_flags;
329*a0795c6fSMarcus Overhagen }
330*a0795c6fSMarcus Overhagen 
331*a0795c6fSMarcus Overhagen status_t NodeGroup::setGroupFlags(
332*a0795c6fSMarcus Overhagen 	uint32											flags) {
333*a0795c6fSMarcus Overhagen 	Autolock _l(this);
334*a0795c6fSMarcus Overhagen 	m_flags = flags;
335*a0795c6fSMarcus Overhagen 	return B_OK;
336*a0795c6fSMarcus Overhagen }
337*a0795c6fSMarcus Overhagen 
338*a0795c6fSMarcus Overhagen 
339*a0795c6fSMarcus Overhagen // returns true if one or more nodes in the group have cycling
340*a0795c6fSMarcus Overhagen // enabled, and the start- and end-positions are valid
341*a0795c6fSMarcus Overhagen bool NodeGroup::canCycle() const {
342*a0795c6fSMarcus Overhagen 	Autolock _l(this);
343*a0795c6fSMarcus Overhagen 
344*a0795c6fSMarcus Overhagen 	return
345*a0795c6fSMarcus Overhagen 		m_cycleNodes.size() > 0 &&
346*a0795c6fSMarcus Overhagen 		m_endPosition - m_startPosition > s_minCyclePeriod;
347*a0795c6fSMarcus Overhagen }
348*a0795c6fSMarcus Overhagen 
349*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
350*a0795c6fSMarcus Overhagen // *** TRANSPORT POSITIONING (LOCK REQUIRED)
351*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
352*a0795c6fSMarcus Overhagen 
353*a0795c6fSMarcus Overhagen // Fetch the current transport state
354*a0795c6fSMarcus Overhagen 
355*a0795c6fSMarcus Overhagen NodeGroup::transport_state_t NodeGroup::transportState() const {
356*a0795c6fSMarcus Overhagen 	Autolock _l(this);
357*a0795c6fSMarcus Overhagen 	return m_transportState;
358*a0795c6fSMarcus Overhagen }
359*a0795c6fSMarcus Overhagen 
360*a0795c6fSMarcus Overhagen // Set the starting media time:
361*a0795c6fSMarcus Overhagen //   This is the point at which playback will begin in any media
362*a0795c6fSMarcus Overhagen //   files/documents being played by the nodes in this group.
363*a0795c6fSMarcus Overhagen //   When cycle mode is enabled, this is the point to which each
364*a0795c6fSMarcus Overhagen //   node will be seek'd at the end of each cycle (loop).
365*a0795c6fSMarcus Overhagen //
366*a0795c6fSMarcus Overhagen //   The starting time can't be changed in the B_OFFLINE run mode
367*a0795c6fSMarcus Overhagen //   (this call will return an error.)
368*a0795c6fSMarcus Overhagen 
369*a0795c6fSMarcus Overhagen status_t NodeGroup::setStartPosition(
370*a0795c6fSMarcus Overhagen 	bigtime_t										start) {
371*a0795c6fSMarcus Overhagen 	Autolock _l(this);
372*a0795c6fSMarcus Overhagen 
373*a0795c6fSMarcus Overhagen 	D_METHOD((
374*a0795c6fSMarcus Overhagen 		"NodeGroup::setStartPosition(%Ld)\n", start));
375*a0795c6fSMarcus Overhagen 
376*a0795c6fSMarcus Overhagen 	if(
377*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_RUNNING ||
378*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_ROLLING ||
379*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_STARTING) {
380*a0795c6fSMarcus Overhagen 
381*a0795c6fSMarcus Overhagen 		if(m_runMode == BMediaNode::B_OFFLINE)
382*a0795c6fSMarcus Overhagen 			return B_NOT_ALLOWED;
383*a0795c6fSMarcus Overhagen 
384*a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
385*a0795c6fSMarcus Overhagen 
386*a0795c6fSMarcus Overhagen 		if(_cycleValid()) {
387*a0795c6fSMarcus Overhagen 			if(m_timeSourceObj->Now() >= m_cycleDeadline) {
388*a0795c6fSMarcus Overhagen 				// too late to change start position; defer
389*a0795c6fSMarcus Overhagen //				PRINT((" - deferred\n"));
390*a0795c6fSMarcus Overhagen 				m_newStartPosition = start;
391*a0795c6fSMarcus Overhagen 				m_newStart = true;
392*a0795c6fSMarcus Overhagen 				return B_OK;
393*a0795c6fSMarcus Overhagen 			}
394*a0795c6fSMarcus Overhagen 
395*a0795c6fSMarcus Overhagen 			// not at deadline yet; fall through to set start position
396*a0795c6fSMarcus Overhagen 		}
397*a0795c6fSMarcus Overhagen 	}
398*a0795c6fSMarcus Overhagen 
399*a0795c6fSMarcus Overhagen 	m_startPosition = start;
400*a0795c6fSMarcus Overhagen 
401*a0795c6fSMarcus Overhagen 	// +++++ notify [e.moon 11oct99]
402*a0795c6fSMarcus Overhagen 
403*a0795c6fSMarcus Overhagen 	return B_OK;
404*a0795c6fSMarcus Overhagen }
405*a0795c6fSMarcus Overhagen 
406*a0795c6fSMarcus Overhagen // Fetch the starting position:
407*a0795c6fSMarcus Overhagen 
408*a0795c6fSMarcus Overhagen // +++++ if a previously-set start position was deferred, it won't be
409*a0795c6fSMarcus Overhagen //       returned yet
410*a0795c6fSMarcus Overhagen 
411*a0795c6fSMarcus Overhagen bigtime_t NodeGroup::startPosition() const {
412*a0795c6fSMarcus Overhagen 	Autolock _l(this);
413*a0795c6fSMarcus Overhagen 
414*a0795c6fSMarcus Overhagen 	return m_startPosition;
415*a0795c6fSMarcus Overhagen }
416*a0795c6fSMarcus Overhagen 
417*a0795c6fSMarcus Overhagen // Set the ending media time:
418*a0795c6fSMarcus Overhagen //   This is the point at which playback will end relative to
419*a0795c6fSMarcus Overhagen //   media documents begin played by the nodes in this group;
420*a0795c6fSMarcus Overhagen //   in cycle mode, this specifies the loop point.  If the
421*a0795c6fSMarcus Overhagen //   ending time is less than or equal to the starting time,
422*a0795c6fSMarcus Overhagen //   the transport will continue until stopped manually.
423*a0795c6fSMarcus Overhagen //   If the end position is changed while the transport is playing,
424*a0795c6fSMarcus Overhagen //   it must take effect retroactively (if it's before the current
425*a0795c6fSMarcus Overhagen //   position and looping is enabled, all nodes must 'warp' to
426*a0795c6fSMarcus Overhagen //   the proper post-loop position.)
427*a0795c6fSMarcus Overhagen //
428*a0795c6fSMarcus Overhagen //   The ending time can't be changed if run mode is B_OFFLINE and
429*a0795c6fSMarcus Overhagen //   the transport is running (this call will return an error.)
430*a0795c6fSMarcus Overhagen 
431*a0795c6fSMarcus Overhagen status_t NodeGroup::setEndPosition(
432*a0795c6fSMarcus Overhagen 	bigtime_t										end) {
433*a0795c6fSMarcus Overhagen 	Autolock _l(this);
434*a0795c6fSMarcus Overhagen 
435*a0795c6fSMarcus Overhagen 	D_METHOD((
436*a0795c6fSMarcus Overhagen 		"NodeGroup::setEndPosition(%Ld)\n", end));
437*a0795c6fSMarcus Overhagen 
438*a0795c6fSMarcus Overhagen 	if(
439*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_RUNNING ||
440*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_ROLLING ||
441*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_STARTING) {
442*a0795c6fSMarcus Overhagen 
443*a0795c6fSMarcus Overhagen 		if(m_runMode == BMediaNode::B_OFFLINE)
444*a0795c6fSMarcus Overhagen 			return B_NOT_ALLOWED;
445*a0795c6fSMarcus Overhagen 
446*a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
447*a0795c6fSMarcus Overhagen 
448*a0795c6fSMarcus Overhagen 		bigtime_t endDelta = end - m_endPosition;
449*a0795c6fSMarcus Overhagen 
450*a0795c6fSMarcus Overhagen 		if(_cycleValid()) {
451*a0795c6fSMarcus Overhagen 			if(m_timeSourceObj->Now() >= m_cycleDeadline + endDelta) {
452*a0795c6fSMarcus Overhagen 				// too late to change end position; defer
453*a0795c6fSMarcus Overhagen //				PRINT((" - deferred\n"));
454*a0795c6fSMarcus Overhagen 				m_newEndPosition = end;
455*a0795c6fSMarcus Overhagen 				m_newEnd = true;
456*a0795c6fSMarcus Overhagen 				return B_OK;
457*a0795c6fSMarcus Overhagen 			}
458*a0795c6fSMarcus Overhagen 			else {
459*a0795c6fSMarcus Overhagen 				// set new end position
460*a0795c6fSMarcus Overhagen 				m_endPosition = end;
461*a0795c6fSMarcus Overhagen 
462*a0795c6fSMarcus Overhagen 				// inform thread
463*a0795c6fSMarcus Overhagen 				ASSERT(m_cyclePort);
464*a0795c6fSMarcus Overhagen 				write_port(
465*a0795c6fSMarcus Overhagen 					m_cyclePort,
466*a0795c6fSMarcus Overhagen 					_CYCLE_END_CHANGED,
467*a0795c6fSMarcus Overhagen 					0,
468*a0795c6fSMarcus Overhagen 					0);
469*a0795c6fSMarcus Overhagen //
470*a0795c6fSMarcus Overhagen //				// restart nodes' cycle threads with new end position
471*a0795c6fSMarcus Overhagen //				_cycleInit(m_cycleStart);
472*a0795c6fSMarcus Overhagen //				for(node_set::iterator it = m_cycleNodes.begin();
473*a0795c6fSMarcus Overhagen //					it != m_cycleNodes.end(); ++it) {
474*a0795c6fSMarcus Overhagen //					(*it)->_scheduleCycle(m_cycleBoundary);
475*a0795c6fSMarcus Overhagen //				}
476*a0795c6fSMarcus Overhagen //				return B_OK;
477*a0795c6fSMarcus Overhagen 			}
478*a0795c6fSMarcus Overhagen 		}
479*a0795c6fSMarcus Overhagen 	}
480*a0795c6fSMarcus Overhagen 
481*a0795c6fSMarcus Overhagen 	m_endPosition = end;
482*a0795c6fSMarcus Overhagen 
483*a0795c6fSMarcus Overhagen 	// +++++ notify [e.moon 11oct99]
484*a0795c6fSMarcus Overhagen 
485*a0795c6fSMarcus Overhagen 	return B_OK;
486*a0795c6fSMarcus Overhagen }
487*a0795c6fSMarcus Overhagen 
488*a0795c6fSMarcus Overhagen 
489*a0795c6fSMarcus Overhagen // Fetch the end position:
490*a0795c6fSMarcus Overhagen //   Note that if the end position is less than or equal to the start
491*a0795c6fSMarcus Overhagen //   position, it's ignored.
492*a0795c6fSMarcus Overhagen 
493*a0795c6fSMarcus Overhagen // +++++ if a previously-set end position was deferred, it won't be
494*a0795c6fSMarcus Overhagen //       returned yet
495*a0795c6fSMarcus Overhagen 
496*a0795c6fSMarcus Overhagen bigtime_t NodeGroup::endPosition() const {
497*a0795c6fSMarcus Overhagen 	Autolock _l(this);
498*a0795c6fSMarcus Overhagen 	return m_endPosition;
499*a0795c6fSMarcus Overhagen }
500*a0795c6fSMarcus Overhagen 
501*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
502*a0795c6fSMarcus Overhagen // *** TRANSPORT OPERATIONS (LOCK REQUIRED)
503*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
504*a0795c6fSMarcus Overhagen 
505*a0795c6fSMarcus Overhagen // Preroll the group:
506*a0795c6fSMarcus Overhagen //   Seeks, then prerolls, each node in the group (honoring the
507*a0795c6fSMarcus Overhagen //   NO_SEEK and NO_PREROLL flags.)  This ensures that the group
508*a0795c6fSMarcus Overhagen //   can start as quickly as possible.
509*a0795c6fSMarcus Overhagen //
510*a0795c6fSMarcus Overhagen //   Does not return until all nodes in the group have been
511*a0795c6fSMarcus Overhagen //   prepared.
512*a0795c6fSMarcus Overhagen 
513*a0795c6fSMarcus Overhagen status_t NodeGroup::preroll() {
514*a0795c6fSMarcus Overhagen 	D_METHOD((
515*a0795c6fSMarcus Overhagen 		"NodeGroup::preroll()\n"));
516*a0795c6fSMarcus Overhagen 
517*a0795c6fSMarcus Overhagen 	Autolock _l(this);
518*a0795c6fSMarcus Overhagen 	return _preroll();
519*a0795c6fSMarcus Overhagen }
520*a0795c6fSMarcus Overhagen 
521*a0795c6fSMarcus Overhagen // Start all nodes in the group:
522*a0795c6fSMarcus Overhagen //   Nodes with the NO_START_STOP flag aren't molested.
523*a0795c6fSMarcus Overhagen 
524*a0795c6fSMarcus Overhagen status_t NodeGroup::start() {
525*a0795c6fSMarcus Overhagen 	D_METHOD((
526*a0795c6fSMarcus Overhagen 		"NodeGroup::start()\n"));
527*a0795c6fSMarcus Overhagen 
528*a0795c6fSMarcus Overhagen 	Autolock _l(this);
529*a0795c6fSMarcus Overhagen 	return _start();
530*a0795c6fSMarcus Overhagen }
531*a0795c6fSMarcus Overhagen 
532*a0795c6fSMarcus Overhagen // Stop all nodes in the group:
533*a0795c6fSMarcus Overhagen //   Nodes with the NO_START_STOP flag aren't molested.
534*a0795c6fSMarcus Overhagen 
535*a0795c6fSMarcus Overhagen status_t NodeGroup::stop() {
536*a0795c6fSMarcus Overhagen 	D_METHOD((
537*a0795c6fSMarcus Overhagen 		"NodeGroup::stop()\n"));
538*a0795c6fSMarcus Overhagen 
539*a0795c6fSMarcus Overhagen 	Autolock _l(this);
540*a0795c6fSMarcus Overhagen 	return _stop();
541*a0795c6fSMarcus Overhagen }
542*a0795c6fSMarcus Overhagen 
543*a0795c6fSMarcus Overhagen // Roll all nodes in the group:
544*a0795c6fSMarcus Overhagen //   Queues a start and stop atomically (via BMediaRoster::RollNode()).
545*a0795c6fSMarcus Overhagen //   Returns B_NOT_ALLOWED if endPosition <= startPosition;
546*a0795c6fSMarcus Overhagen 
547*a0795c6fSMarcus Overhagen status_t NodeGroup::roll() {
548*a0795c6fSMarcus Overhagen 	D_METHOD((
549*a0795c6fSMarcus Overhagen 		"NodeGroup::roll()\n"));
550*a0795c6fSMarcus Overhagen 
551*a0795c6fSMarcus Overhagen 	Autolock _l(this);
552*a0795c6fSMarcus Overhagen 	return _roll();
553*a0795c6fSMarcus Overhagen }
554*a0795c6fSMarcus Overhagen 
555*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
556*a0795c6fSMarcus Overhagen // *** TIME SOURCE & RUN-MODE OPERATIONS (LOCK REQUIRED)
557*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
558*a0795c6fSMarcus Overhagen 
559*a0795c6fSMarcus Overhagen // time source control:
560*a0795c6fSMarcus Overhagen //   getTimeSource():
561*a0795c6fSMarcus Overhagen //   returns B_ERROR if no time source has been set; otherwise,
562*a0795c6fSMarcus Overhagen //   returns the node ID of the current time source for all
563*a0795c6fSMarcus Overhagen //   nodes in the group.
564*a0795c6fSMarcus Overhagen //
565*a0795c6fSMarcus Overhagen //   setTimeSource():
566*a0795c6fSMarcus Overhagen //   Calls SetTimeSourceFor() on every node in the group.
567*a0795c6fSMarcus Overhagen //   The group must be stopped; B_NOT_ALLOWED will be returned
568*a0795c6fSMarcus Overhagen //   if the state is TRANSPORT_RUNNING or TRANSPORT_ROLLING.
569*a0795c6fSMarcus Overhagen 
570*a0795c6fSMarcus Overhagen status_t NodeGroup::getTimeSource(
571*a0795c6fSMarcus Overhagen 	media_node*									outTimeSource) const {
572*a0795c6fSMarcus Overhagen 	Autolock _l(this);
573*a0795c6fSMarcus Overhagen 
574*a0795c6fSMarcus Overhagen 	if(m_timeSource != media_node::null) {
575*a0795c6fSMarcus Overhagen 		*outTimeSource = m_timeSource;
576*a0795c6fSMarcus Overhagen 		return B_OK;
577*a0795c6fSMarcus Overhagen 	}
578*a0795c6fSMarcus Overhagen 	return B_ERROR;
579*a0795c6fSMarcus Overhagen }
580*a0795c6fSMarcus Overhagen 
581*a0795c6fSMarcus Overhagen status_t NodeGroup::setTimeSource(
582*a0795c6fSMarcus Overhagen 	const media_node&						timeSource) {
583*a0795c6fSMarcus Overhagen 
584*a0795c6fSMarcus Overhagen 	Autolock _l(this);
585*a0795c6fSMarcus Overhagen 
586*a0795c6fSMarcus Overhagen 	if(m_transportState == TRANSPORT_RUNNING || m_transportState == TRANSPORT_ROLLING)
587*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
588*a0795c6fSMarcus Overhagen 
589*a0795c6fSMarcus Overhagen 	if(m_timeSourceObj)
590*a0795c6fSMarcus Overhagen 		m_timeSourceObj->Release();
591*a0795c6fSMarcus Overhagen 
592*a0795c6fSMarcus Overhagen 	m_timeSource = timeSource;
593*a0795c6fSMarcus Overhagen 
594*a0795c6fSMarcus Overhagen 	// cache a BTimeSource*
595*a0795c6fSMarcus Overhagen 	m_timeSourceObj = m_manager->roster->MakeTimeSourceFor(timeSource);
596*a0795c6fSMarcus Overhagen 	ASSERT(m_timeSourceObj);
597*a0795c6fSMarcus Overhagen 
598*a0795c6fSMarcus Overhagen 	// apply new time source to all nodes
599*a0795c6fSMarcus Overhagen 	for_each(
600*a0795c6fSMarcus Overhagen 		m_nodes.begin(),
601*a0795c6fSMarcus Overhagen 		m_nodes.end(),
602*a0795c6fSMarcus Overhagen 		bind2nd(
603*a0795c6fSMarcus Overhagen 			mem_fun(&NodeRef::_setTimeSource),
604*a0795c6fSMarcus Overhagen 			m_timeSource.node
605*a0795c6fSMarcus Overhagen 		)
606*a0795c6fSMarcus Overhagen 	);
607*a0795c6fSMarcus Overhagen 
608*a0795c6fSMarcus Overhagen //	// try to set as sync node
609*a0795c6fSMarcus Overhagen //	err = setSyncNode(timeSource);
610*a0795c6fSMarcus Overhagen //	if(err < B_OK) {
611*a0795c6fSMarcus Overhagen //		PRINT((
612*a0795c6fSMarcus Overhagen //			"* NodeGroup::setTimeSource(): setSyncNode() failed: %s\n",
613*a0795c6fSMarcus Overhagen //			strerror(err)));
614*a0795c6fSMarcus Overhagen //	}
615*a0795c6fSMarcus Overhagen 
616*a0795c6fSMarcus Overhagen 	// notify
617*a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
618*a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
619*a0795c6fSMarcus Overhagen 	}
620*a0795c6fSMarcus Overhagen 	BMessage m(M_TIME_SOURCE_CHANGED);
621*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
622*a0795c6fSMarcus Overhagen 	m.AddInt32("timeSourceID", timeSource.node);
623*a0795c6fSMarcus Overhagen 	notify(&m);
624*a0795c6fSMarcus Overhagen 	UnlockLooper();
625*a0795c6fSMarcus Overhagen 
626*a0795c6fSMarcus Overhagen 	return B_OK;
627*a0795c6fSMarcus Overhagen }
628*a0795c6fSMarcus Overhagen 
629*a0795c6fSMarcus Overhagen // run mode access:
630*a0795c6fSMarcus Overhagen //   Sets the default run mode for the group.  This will be
631*a0795c6fSMarcus Overhagen //   applied to every node with a wildcard (0) run mode.
632*a0795c6fSMarcus Overhagen //
633*a0795c6fSMarcus Overhagen //   Special case: if the run mode is B_OFFLINE, it will be
634*a0795c6fSMarcus Overhagen //   applied to all nodes in the group.
635*a0795c6fSMarcus Overhagen 
636*a0795c6fSMarcus Overhagen BMediaNode::run_mode NodeGroup::runMode() const {
637*a0795c6fSMarcus Overhagen 	Autolock _l(this);
638*a0795c6fSMarcus Overhagen 	return m_runMode;
639*a0795c6fSMarcus Overhagen }
640*a0795c6fSMarcus Overhagen 
641*a0795c6fSMarcus Overhagen status_t NodeGroup::setRunMode(BMediaNode::run_mode mode) {
642*a0795c6fSMarcus Overhagen 	Autolock _l(this);
643*a0795c6fSMarcus Overhagen 
644*a0795c6fSMarcus Overhagen 	m_runMode = mode;
645*a0795c6fSMarcus Overhagen 
646*a0795c6fSMarcus Overhagen 	// apply to all nodes
647*a0795c6fSMarcus Overhagen 	for_each(
648*a0795c6fSMarcus Overhagen 		m_nodes.begin(),
649*a0795c6fSMarcus Overhagen 		m_nodes.end(),
650*a0795c6fSMarcus Overhagen 		bind2nd(
651*a0795c6fSMarcus Overhagen 			mem_fun(&NodeRef::_setRunModeAuto),
652*a0795c6fSMarcus Overhagen 			m_runMode
653*a0795c6fSMarcus Overhagen 		)
654*a0795c6fSMarcus Overhagen //		bound_method(
655*a0795c6fSMarcus Overhagen //			*this,
656*a0795c6fSMarcus Overhagen //			&NodeGroup::setRunModeFor)
657*a0795c6fSMarcus Overhagen 	);
658*a0795c6fSMarcus Overhagen 
659*a0795c6fSMarcus Overhagen 
660*a0795c6fSMarcus Overhagen 	return B_OK;
661*a0795c6fSMarcus Overhagen }
662*a0795c6fSMarcus Overhagen 
663*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
664*a0795c6fSMarcus Overhagen // *** BHandler
665*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
666*a0795c6fSMarcus Overhagen 
667*a0795c6fSMarcus Overhagen void NodeGroup::MessageReceived(
668*a0795c6fSMarcus Overhagen 	BMessage*										message) {
669*a0795c6fSMarcus Overhagen 
670*a0795c6fSMarcus Overhagen //	PRINT((
671*a0795c6fSMarcus Overhagen //		"NodeGroup::MessageReceived():\n"));
672*a0795c6fSMarcus Overhagen //	message->PrintToStream();
673*a0795c6fSMarcus Overhagen 	status_t err;
674*a0795c6fSMarcus Overhagen 
675*a0795c6fSMarcus Overhagen 	switch(message->what) {
676*a0795c6fSMarcus Overhagen 		case M_SET_TIME_SOURCE:
677*a0795c6fSMarcus Overhagen 			{
678*a0795c6fSMarcus Overhagen 				media_node timeSource;
679*a0795c6fSMarcus Overhagen 				void* data;
680*a0795c6fSMarcus Overhagen 				ssize_t dataSize;
681*a0795c6fSMarcus Overhagen 				err = message->FindData(
682*a0795c6fSMarcus Overhagen 					"timeSourceNode",
683*a0795c6fSMarcus Overhagen 					B_RAW_TYPE,
684*a0795c6fSMarcus Overhagen 					(const void**)&data,
685*a0795c6fSMarcus Overhagen 					&dataSize);
686*a0795c6fSMarcus Overhagen 				if(err < B_OK) {
687*a0795c6fSMarcus Overhagen 					PRINT((
688*a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_TIME_SOURCE):\n"
689*a0795c6fSMarcus Overhagen 						"  no timeSourceNode!\n"));
690*a0795c6fSMarcus Overhagen 					break;
691*a0795c6fSMarcus Overhagen 				}
692*a0795c6fSMarcus Overhagen 				timeSource = *(media_node*)data;
693*a0795c6fSMarcus Overhagen 
694*a0795c6fSMarcus Overhagen 				setTimeSource(timeSource);
695*a0795c6fSMarcus Overhagen 			}
696*a0795c6fSMarcus Overhagen 			break;
697*a0795c6fSMarcus Overhagen 
698*a0795c6fSMarcus Overhagen 		case M_SET_RUN_MODE:
699*a0795c6fSMarcus Overhagen 			{
700*a0795c6fSMarcus Overhagen 				uint32 runMode;
701*a0795c6fSMarcus Overhagen 				err = message->FindInt32("runMode", (int32*)&runMode);
702*a0795c6fSMarcus Overhagen 				if(err < B_OK) {
703*a0795c6fSMarcus Overhagen 					PRINT((
704*a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n"
705*a0795c6fSMarcus Overhagen 						"  no runMode!\n"));
706*a0795c6fSMarcus Overhagen 					break;
707*a0795c6fSMarcus Overhagen 				}
708*a0795c6fSMarcus Overhagen 
709*a0795c6fSMarcus Overhagen 				if(runMode < BMediaNode::B_OFFLINE ||
710*a0795c6fSMarcus Overhagen 					runMode > BMediaNode::B_RECORDING) {
711*a0795c6fSMarcus Overhagen 					PRINT((
712*a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n"
713*a0795c6fSMarcus Overhagen 						"  invalid run mode (%ld)\n", runMode));
714*a0795c6fSMarcus Overhagen 					break;
715*a0795c6fSMarcus Overhagen 				}
716*a0795c6fSMarcus Overhagen 
717*a0795c6fSMarcus Overhagen 				setRunMode((BMediaNode::run_mode)runMode);
718*a0795c6fSMarcus Overhagen 			}
719*a0795c6fSMarcus Overhagen 			break;
720*a0795c6fSMarcus Overhagen 
721*a0795c6fSMarcus Overhagen 		case M_SET_START_POSITION:
722*a0795c6fSMarcus Overhagen 			{
723*a0795c6fSMarcus Overhagen 				bigtime_t position;
724*a0795c6fSMarcus Overhagen 				err = message->FindInt64("position", (int64*)&position);
725*a0795c6fSMarcus Overhagen 				if(err < B_OK) {
726*a0795c6fSMarcus Overhagen 					PRINT((
727*a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_START_POSITION):\n"
728*a0795c6fSMarcus Overhagen 						"  no position!\n"));
729*a0795c6fSMarcus Overhagen 					break;
730*a0795c6fSMarcus Overhagen 				}
731*a0795c6fSMarcus Overhagen 				setStartPosition(position);
732*a0795c6fSMarcus Overhagen 			}
733*a0795c6fSMarcus Overhagen 			break;
734*a0795c6fSMarcus Overhagen 
735*a0795c6fSMarcus Overhagen 		case M_SET_END_POSITION:
736*a0795c6fSMarcus Overhagen 			{
737*a0795c6fSMarcus Overhagen 				bigtime_t position;
738*a0795c6fSMarcus Overhagen 				err = message->FindInt64("position", (int64*)&position);
739*a0795c6fSMarcus Overhagen 				if(err < B_OK) {
740*a0795c6fSMarcus Overhagen 					PRINT((
741*a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_END_POSITION):\n"
742*a0795c6fSMarcus Overhagen 						"  no position!\n"));
743*a0795c6fSMarcus Overhagen 					break;
744*a0795c6fSMarcus Overhagen 				}
745*a0795c6fSMarcus Overhagen 				setEndPosition(position);
746*a0795c6fSMarcus Overhagen 			}
747*a0795c6fSMarcus Overhagen 			break;
748*a0795c6fSMarcus Overhagen 
749*a0795c6fSMarcus Overhagen 		case M_PREROLL:
750*a0795c6fSMarcus Overhagen 			preroll();
751*a0795c6fSMarcus Overhagen 			break;
752*a0795c6fSMarcus Overhagen 
753*a0795c6fSMarcus Overhagen 		case M_START:
754*a0795c6fSMarcus Overhagen 			start();
755*a0795c6fSMarcus Overhagen 			break;
756*a0795c6fSMarcus Overhagen 
757*a0795c6fSMarcus Overhagen 		case M_STOP:
758*a0795c6fSMarcus Overhagen 			stop();
759*a0795c6fSMarcus Overhagen 			break;
760*a0795c6fSMarcus Overhagen 
761*a0795c6fSMarcus Overhagen 		case M_ROLL:
762*a0795c6fSMarcus Overhagen 			roll();
763*a0795c6fSMarcus Overhagen 			break;
764*a0795c6fSMarcus Overhagen 
765*a0795c6fSMarcus Overhagen 		default:
766*a0795c6fSMarcus Overhagen 			_inherited::MessageReceived(message);
767*a0795c6fSMarcus Overhagen 			break;
768*a0795c6fSMarcus Overhagen 	}
769*a0795c6fSMarcus Overhagen }
770*a0795c6fSMarcus Overhagen 
771*a0795c6fSMarcus Overhagen 
772*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
773*a0795c6fSMarcus Overhagen // *** IPersistent
774*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
775*a0795c6fSMarcus Overhagen 
776*a0795c6fSMarcus Overhagen // !
777*a0795c6fSMarcus Overhagen #if CORTEX_XML
778*a0795c6fSMarcus Overhagen // !
779*a0795c6fSMarcus Overhagen 
780*a0795c6fSMarcus Overhagen // +++++
781*a0795c6fSMarcus Overhagen 
782*a0795c6fSMarcus Overhagen // Default constructor
783*a0795c6fSMarcus Overhagen NodeGroup::NodeGroup() :
784*a0795c6fSMarcus Overhagen 	m_manager(0) {} // +++++ finish initialization
785*a0795c6fSMarcus Overhagen 
786*a0795c6fSMarcus Overhagen 
787*a0795c6fSMarcus Overhagen // !
788*a0795c6fSMarcus Overhagen #endif /*CORTEX_XML*/
789*a0795c6fSMarcus Overhagen // !
790*a0795c6fSMarcus Overhagen 
791*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
792*a0795c6fSMarcus Overhagen // *** IObservable:		[19aug99]
793*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
794*a0795c6fSMarcus Overhagen 
795*a0795c6fSMarcus Overhagen void NodeGroup::observerAdded(
796*a0795c6fSMarcus Overhagen 	const BMessenger&				observer) {
797*a0795c6fSMarcus Overhagen 
798*a0795c6fSMarcus Overhagen 	BMessage m(M_OBSERVER_ADDED);
799*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
800*a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
801*a0795c6fSMarcus Overhagen 	observer.SendMessage(&m);
802*a0795c6fSMarcus Overhagen }
803*a0795c6fSMarcus Overhagen 
804*a0795c6fSMarcus Overhagen void NodeGroup::observerRemoved(
805*a0795c6fSMarcus Overhagen 	const BMessenger&				observer) {
806*a0795c6fSMarcus Overhagen 
807*a0795c6fSMarcus Overhagen 	BMessage m(M_OBSERVER_REMOVED);
808*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
809*a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
810*a0795c6fSMarcus Overhagen 	observer.SendMessage(&m);
811*a0795c6fSMarcus Overhagen }
812*a0795c6fSMarcus Overhagen 
813*a0795c6fSMarcus Overhagen void NodeGroup::notifyRelease() {
814*a0795c6fSMarcus Overhagen 
815*a0795c6fSMarcus Overhagen 	BMessage m(M_RELEASED);
816*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
817*a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
818*a0795c6fSMarcus Overhagen 	notify(&m);
819*a0795c6fSMarcus Overhagen }
820*a0795c6fSMarcus Overhagen 
821*a0795c6fSMarcus Overhagen void NodeGroup::releaseComplete() {
822*a0795c6fSMarcus Overhagen 	// +++++
823*a0795c6fSMarcus Overhagen }
824*a0795c6fSMarcus Overhagen 
825*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
826*a0795c6fSMarcus Overhagen // *** ILockable: pass lock requests to m_lock
827*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
828*a0795c6fSMarcus Overhagen 
829*a0795c6fSMarcus Overhagen bool NodeGroup::lock(
830*a0795c6fSMarcus Overhagen 	lock_t type,
831*a0795c6fSMarcus Overhagen 	bigtime_t timeout) {
832*a0795c6fSMarcus Overhagen 
833*a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::lock(): %ld\n", find_thread(0)));
834*a0795c6fSMarcus Overhagen 
835*a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
836*a0795c6fSMarcus Overhagen 	status_t err = m_lock.LockWithTimeout(timeout);
837*a0795c6fSMarcus Overhagen 
838*a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::lock() ACQUIRED: %ld\n", find_thread(0)));
839*a0795c6fSMarcus Overhagen 
840*a0795c6fSMarcus Overhagen 	return err == B_OK;
841*a0795c6fSMarcus Overhagen }
842*a0795c6fSMarcus Overhagen 
843*a0795c6fSMarcus Overhagen bool NodeGroup::unlock(
844*a0795c6fSMarcus Overhagen 	lock_t type) {
845*a0795c6fSMarcus Overhagen 
846*a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::unlock(): %ld\n", find_thread(0)));
847*a0795c6fSMarcus Overhagen 
848*a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
849*a0795c6fSMarcus Overhagen 	m_lock.Unlock();
850*a0795c6fSMarcus Overhagen 
851*a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::unlock() RELEASED: %ld\n", find_thread(0)));
852*a0795c6fSMarcus Overhagen 
853*a0795c6fSMarcus Overhagen 	return true;
854*a0795c6fSMarcus Overhagen }
855*a0795c6fSMarcus Overhagen 
856*a0795c6fSMarcus Overhagen bool NodeGroup::isLocked(
857*a0795c6fSMarcus Overhagen 	lock_t type) const {
858*a0795c6fSMarcus Overhagen 
859*a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
860*a0795c6fSMarcus Overhagen 	return m_lock.IsLocked();
861*a0795c6fSMarcus Overhagen }
862*a0795c6fSMarcus Overhagen 
863*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
864*a0795c6fSMarcus Overhagen // *** ctor (accessible to NodeManager)
865*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
866*a0795c6fSMarcus Overhagen 
867*a0795c6fSMarcus Overhagen NodeGroup::NodeGroup(
868*a0795c6fSMarcus Overhagen 	const char*									name,
869*a0795c6fSMarcus Overhagen 	NodeManager*								manager,
870*a0795c6fSMarcus Overhagen 	BMediaNode::run_mode				runMode) :
871*a0795c6fSMarcus Overhagen 
872*a0795c6fSMarcus Overhagen 	ObservableHandler(name),
873*a0795c6fSMarcus Overhagen 	m_lock("NodeGroup::m_lock"),
874*a0795c6fSMarcus Overhagen 	m_manager(manager),
875*a0795c6fSMarcus Overhagen 	m_id(NextID()),
876*a0795c6fSMarcus Overhagen 	m_name(name),
877*a0795c6fSMarcus Overhagen 	m_flags(0),
878*a0795c6fSMarcus Overhagen 	m_transportState(TRANSPORT_INVALID),
879*a0795c6fSMarcus Overhagen 	m_runMode(runMode),
880*a0795c6fSMarcus Overhagen 	m_timeSourceObj(0),
881*a0795c6fSMarcus Overhagen 	m_released(false),
882*a0795c6fSMarcus Overhagen 	m_cycleThread(0),
883*a0795c6fSMarcus Overhagen 	m_cyclePort(0),
884*a0795c6fSMarcus Overhagen 	m_startPosition(0LL),
885*a0795c6fSMarcus Overhagen 	m_endPosition(0LL),
886*a0795c6fSMarcus Overhagen 	m_newStart(false),
887*a0795c6fSMarcus Overhagen 	m_newEnd(false) {
888*a0795c6fSMarcus Overhagen 
889*a0795c6fSMarcus Overhagen 	ASSERT(m_manager);
890*a0795c6fSMarcus Overhagen 
891*a0795c6fSMarcus Overhagen 	if(!m_manager->Lock()) {
892*a0795c6fSMarcus Overhagen 		ASSERT(!"m_manager->Lock() failed");
893*a0795c6fSMarcus Overhagen 	}
894*a0795c6fSMarcus Overhagen 	m_manager->AddHandler(this);
895*a0795c6fSMarcus Overhagen 	m_manager->Unlock();
896*a0795c6fSMarcus Overhagen 
897*a0795c6fSMarcus Overhagen 	// set default time source
898*a0795c6fSMarcus Overhagen 	media_node ts;
899*a0795c6fSMarcus Overhagen 	D_ROSTER(("# roster->GetTimeSource()\n"));
900*a0795c6fSMarcus Overhagen 	status_t err = m_manager->roster->GetTimeSource(&ts);
901*a0795c6fSMarcus Overhagen 	if(err < B_OK) {
902*a0795c6fSMarcus Overhagen 		PRINT((
903*a0795c6fSMarcus Overhagen 			"*** NodeGroup(): roster->GetTimeSource() failed:\n"
904*a0795c6fSMarcus Overhagen 			"    %s\n", strerror(err)));
905*a0795c6fSMarcus Overhagen 	}
906*a0795c6fSMarcus Overhagen 	setTimeSource(ts);
907*a0795c6fSMarcus Overhagen }
908*a0795c6fSMarcus Overhagen 
909*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
910*a0795c6fSMarcus Overhagen // *** internal operations
911*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
912*a0795c6fSMarcus Overhagen 
913*a0795c6fSMarcus Overhagen uint32 NodeGroup::s_nextID = 1;
914*a0795c6fSMarcus Overhagen uint32 NodeGroup::NextID() {
915*a0795c6fSMarcus Overhagen 	return atomic_add((int32*)&s_nextID, 1);
916*a0795c6fSMarcus Overhagen }
917*a0795c6fSMarcus Overhagen 
918*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
919*a0795c6fSMarcus Overhagen // *** ref->group communication (LOCK REQUIRED)
920*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
921*a0795c6fSMarcus Overhagen 
922*a0795c6fSMarcus Overhagen // when a NodeRef's cycle state (ie. looping or not looping)
923*a0795c6fSMarcus Overhagen // changes, it must pass that information on via this method
924*a0795c6fSMarcus Overhagen 
925*a0795c6fSMarcus Overhagen void NodeGroup::_refCycleChanged(
926*a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
927*a0795c6fSMarcus Overhagen 	assert_locked(this);
928*a0795c6fSMarcus Overhagen 	D_METHOD((
929*a0795c6fSMarcus Overhagen 		"NodeGroup::_refCycleChanged('%s')\n",
930*a0795c6fSMarcus Overhagen 		ref->name()));
931*a0795c6fSMarcus Overhagen 
932*a0795c6fSMarcus Overhagen 	if(ref->m_cycle) {
933*a0795c6fSMarcus Overhagen 		_cycleAddRef(ref);
934*a0795c6fSMarcus Overhagen 	}	else {
935*a0795c6fSMarcus Overhagen 		_cycleRemoveRef(ref);
936*a0795c6fSMarcus Overhagen 	}
937*a0795c6fSMarcus Overhagen 
938*a0795c6fSMarcus Overhagen 	// +++++ if running & cycle valid, the node should be properly
939*a0795c6fSMarcus Overhagen 	//       seek'd and start'd
940*a0795c6fSMarcus Overhagen }
941*a0795c6fSMarcus Overhagen 
942*a0795c6fSMarcus Overhagen 
943*a0795c6fSMarcus Overhagen // when a cycling node's latency changes, call this method.
944*a0795c6fSMarcus Overhagen 
945*a0795c6fSMarcus Overhagen void NodeGroup::_refLatencyChanged(
946*a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
947*a0795c6fSMarcus Overhagen 	assert_locked(this);
948*a0795c6fSMarcus Overhagen 	D_METHOD((
949*a0795c6fSMarcus Overhagen 		"NodeGroup::_refLatencyChanged('%s')\n",
950*a0795c6fSMarcus Overhagen 		ref->name()));
951*a0795c6fSMarcus Overhagen 
952*a0795c6fSMarcus Overhagen 	if(!_cycleValid())
953*a0795c6fSMarcus Overhagen 		return;
954*a0795c6fSMarcus Overhagen 
955*a0795c6fSMarcus Overhagen 	// remove & replace ref (positions it properly)
956*a0795c6fSMarcus Overhagen 	_cycleRemoveRef(ref);
957*a0795c6fSMarcus Overhagen 	_cycleAddRef(ref);
958*a0795c6fSMarcus Overhagen 
959*a0795c6fSMarcus Overhagen 	// slap my thread up
960*a0795c6fSMarcus Overhagen 	ASSERT(m_cyclePort);
961*a0795c6fSMarcus Overhagen 	write_port(
962*a0795c6fSMarcus Overhagen 		m_cyclePort,
963*a0795c6fSMarcus Overhagen 		_CYCLE_LATENCY_CHANGED,
964*a0795c6fSMarcus Overhagen 		0,
965*a0795c6fSMarcus Overhagen 		0);
966*a0795c6fSMarcus Overhagen 
967*a0795c6fSMarcus Overhagen 	// +++++ zat it?
968*a0795c6fSMarcus Overhagen }
969*a0795c6fSMarcus Overhagen 
970*a0795c6fSMarcus Overhagen // when a NodeRef receives notification that it has been stopped,
971*a0795c6fSMarcus Overhagen // but is labeled as still running, it must call this method.
972*a0795c6fSMarcus Overhagen // [e.moon 11oct99: roll/B_OFFLINE support]
973*a0795c6fSMarcus Overhagen 
974*a0795c6fSMarcus Overhagen void NodeGroup::_refStopped(
975*a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
976*a0795c6fSMarcus Overhagen 	assert_locked(this);
977*a0795c6fSMarcus Overhagen 	D_METHOD((
978*a0795c6fSMarcus Overhagen 		"NodeGroup::_refStopped('%s')\n",
979*a0795c6fSMarcus Overhagen 		ref->name()));
980*a0795c6fSMarcus Overhagen 
981*a0795c6fSMarcus Overhagen 	// roll/B_OFFLINE support [e.moon 11oct99]
982*a0795c6fSMarcus Overhagen 	// (check to see if any other nodes in the group are still running;
983*a0795c6fSMarcus Overhagen 	//  mark group stopped if not.)
984*a0795c6fSMarcus Overhagen 	if(m_transportState == TRANSPORT_ROLLING) {
985*a0795c6fSMarcus Overhagen 		bool nodesRunning = false;
986*a0795c6fSMarcus Overhagen 		for(node_set::iterator it = m_nodes.begin();
987*a0795c6fSMarcus Overhagen 			it != m_nodes.end(); ++it) {
988*a0795c6fSMarcus Overhagen 			if((*it)->isRunning()) {
989*a0795c6fSMarcus Overhagen 				nodesRunning = true;
990*a0795c6fSMarcus Overhagen 				break;
991*a0795c6fSMarcus Overhagen 			}
992*a0795c6fSMarcus Overhagen 		}
993*a0795c6fSMarcus Overhagen 		if(!nodesRunning)
994*a0795c6fSMarcus Overhagen 			// the group has stopped; update transport state
995*a0795c6fSMarcus Overhagen 			_changeState(TRANSPORT_STOPPED);
996*a0795c6fSMarcus Overhagen 
997*a0795c6fSMarcus Overhagen 	}
998*a0795c6fSMarcus Overhagen 
999*a0795c6fSMarcus Overhagen }
1000*a0795c6fSMarcus Overhagen 
1001*a0795c6fSMarcus Overhagen 
1002*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1003*a0795c6fSMarcus Overhagen // *** transport helpers (LOCK REQUIRED)
1004*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1005*a0795c6fSMarcus Overhagen 
1006*a0795c6fSMarcus Overhagen 
1007*a0795c6fSMarcus Overhagen // Preroll all nodes in the group; this is the implementation
1008*a0795c6fSMarcus Overhagen // of preroll().
1009*a0795c6fSMarcus Overhagen // *** this method should not be called from the transport thread
1010*a0795c6fSMarcus Overhagen // (since preroll operations can block for a relatively long time.)
1011*a0795c6fSMarcus Overhagen 
1012*a0795c6fSMarcus Overhagen status_t NodeGroup::_preroll() {
1013*a0795c6fSMarcus Overhagen 	assert_locked(this);
1014*a0795c6fSMarcus Overhagen 
1015*a0795c6fSMarcus Overhagen 	D_METHOD((
1016*a0795c6fSMarcus Overhagen 		"NodeGroup::_preroll()\n"));
1017*a0795c6fSMarcus Overhagen 
1018*a0795c6fSMarcus Overhagen 	if(
1019*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_RUNNING ||
1020*a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_ROLLING)
1021*a0795c6fSMarcus Overhagen 		// too late
1022*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1023*a0795c6fSMarcus Overhagen 
1024*a0795c6fSMarcus Overhagen 	// * preroll all nodes to the start position
1025*a0795c6fSMarcus Overhagen 
1026*a0795c6fSMarcus Overhagen 	// +++++ currently, if an error is encountered it's ignored.
1027*a0795c6fSMarcus Overhagen 	//       should the whole operation fail if one node couldn't
1028*a0795c6fSMarcus Overhagen 	//       be prerolled?
1029*a0795c6fSMarcus Overhagen 	//
1030*a0795c6fSMarcus Overhagen 	//       My gut response is 'no', since the preroll step is
1031*a0795c6fSMarcus Overhagen 	//       optional, but the caller should have some inkling that
1032*a0795c6fSMarcus Overhagen 	//       one of its nodes didn't behave.
1033*a0795c6fSMarcus Overhagen 
1034*a0795c6fSMarcus Overhagen // [e.moon 13oct99] making PPC compiler happy
1035*a0795c6fSMarcus Overhagen //	for_each(
1036*a0795c6fSMarcus Overhagen //		m_nodes.begin(),
1037*a0795c6fSMarcus Overhagen //		m_nodes.end(),
1038*a0795c6fSMarcus Overhagen //		bind2nd(
1039*a0795c6fSMarcus Overhagen //			mem_fun(&NodeRef::_preroll),
1040*a0795c6fSMarcus Overhagen //			m_startPosition
1041*a0795c6fSMarcus Overhagen //		)
1042*a0795c6fSMarcus Overhagen //	);
1043*a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1044*a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1045*a0795c6fSMarcus Overhagen 		(*it)->_preroll(m_startPosition);
1046*a0795c6fSMarcus Overhagen 	}
1047*a0795c6fSMarcus Overhagen 
1048*a0795c6fSMarcus Overhagen //    replaces
1049*a0795c6fSMarcus Overhagen //		bind2nd(
1050*a0795c6fSMarcus Overhagen //			bound_method(*this, &NodeGroup::prerollNode),
1051*a0795c6fSMarcus Overhagen //			m_startPosition
1052*a0795c6fSMarcus Overhagen //		)
1053*a0795c6fSMarcus Overhagen 
1054*a0795c6fSMarcus Overhagen 	return B_OK;
1055*a0795c6fSMarcus Overhagen }
1056*a0795c6fSMarcus Overhagen 
1057*a0795c6fSMarcus Overhagen 
1058*a0795c6fSMarcus Overhagen //// functor: calculates latency of each node it's handed, caching
1059*a0795c6fSMarcus Overhagen //// the largest one found; includes initial latency if nodes report it.
1060*a0795c6fSMarcus Overhagen //
1061*a0795c6fSMarcus Overhagen //class NodeGroup::calcLatencyFn { public:
1062*a0795c6fSMarcus Overhagen //	bigtime_t& maxLatency;
1063*a0795c6fSMarcus Overhagen //
1064*a0795c6fSMarcus Overhagen //	calcLatencyFn(bigtime_t& _m) : maxLatency(_m) {}
1065*a0795c6fSMarcus Overhagen //
1066*a0795c6fSMarcus Overhagen //	void operator()(NodeRef* r) {
1067*a0795c6fSMarcus Overhagen //		ASSERT(r);
1068*a0795c6fSMarcus Overhagen //
1069*a0795c6fSMarcus Overhagen ////		PRINT((
1070*a0795c6fSMarcus Overhagen ////			"# calcLatencyFn(): '%s'\n",
1071*a0795c6fSMarcus Overhagen ////			r->name()));
1072*a0795c6fSMarcus Overhagen //
1073*a0795c6fSMarcus Overhagen //		if(!(r->node().kind & B_BUFFER_PRODUCER)) {
1074*a0795c6fSMarcus Overhagen //			// node can't incur latency
1075*a0795c6fSMarcus Overhagen ////			PRINT((
1076*a0795c6fSMarcus Overhagen ////				"-   not a producer\n"));
1077*a0795c6fSMarcus Overhagen //			return;
1078*a0795c6fSMarcus Overhagen //		}
1079*a0795c6fSMarcus Overhagen //
1080*a0795c6fSMarcus Overhagen //		bigtime_t latency;
1081*a0795c6fSMarcus Overhagen //		status_t err =
1082*a0795c6fSMarcus Overhagen //			BMediaRoster::Roster()->GetLatencyFor(
1083*a0795c6fSMarcus Overhagen //				r->node(),
1084*a0795c6fSMarcus Overhagen //				&latency);
1085*a0795c6fSMarcus Overhagen //		if(err < B_OK) {
1086*a0795c6fSMarcus Overhagen //			PRINT((
1087*a0795c6fSMarcus Overhagen //				"* calcLatencyFn: GetLatencyFor() failed: %s\n",
1088*a0795c6fSMarcus Overhagen //				strerror(err)));
1089*a0795c6fSMarcus Overhagen //			return;
1090*a0795c6fSMarcus Overhagen //		}
1091*a0795c6fSMarcus Overhagen ////		PRINT(("-   %Ld\n", latency));
1092*a0795c6fSMarcus Overhagen //
1093*a0795c6fSMarcus Overhagen //		bigtime_t add;
1094*a0795c6fSMarcus Overhagen //		err = BMediaRoster::Roster()->GetInitialLatencyFor(
1095*a0795c6fSMarcus Overhagen //			r->node(),
1096*a0795c6fSMarcus Overhagen //			&add);
1097*a0795c6fSMarcus Overhagen ////		PRINT(("-   %Ld\n", add));
1098*a0795c6fSMarcus Overhagen //		if(err < B_OK) {
1099*a0795c6fSMarcus Overhagen //			PRINT((
1100*a0795c6fSMarcus Overhagen //				"* calcLatencyFn: GetInitialLatencyFor() failed: %s\n",
1101*a0795c6fSMarcus Overhagen //				strerror(err)));
1102*a0795c6fSMarcus Overhagen //		}
1103*a0795c6fSMarcus Overhagen //		else
1104*a0795c6fSMarcus Overhagen //			latency += add;
1105*a0795c6fSMarcus Overhagen //
1106*a0795c6fSMarcus Overhagen //		if(latency > maxLatency)
1107*a0795c6fSMarcus Overhagen //			maxLatency = latency;
1108*a0795c6fSMarcus Overhagen //
1109*a0795c6fSMarcus Overhagen ////		PRINT((
1110*a0795c6fSMarcus Overhagen ////			"-   max latency: %Ld\n",
1111*a0795c6fSMarcus Overhagen ////			maxLatency));
1112*a0795c6fSMarcus Overhagen //	}
1113*a0795c6fSMarcus Overhagen //};
1114*a0795c6fSMarcus Overhagen 
1115*a0795c6fSMarcus Overhagen // Start all nodes in the group; this is the implementation of
1116*a0795c6fSMarcus Overhagen // start().  Fails if the run mode is B_OFFLINE; use _roll() instead
1117*a0795c6fSMarcus Overhagen // in that case.
1118*a0795c6fSMarcus Overhagen //
1119*a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1120*a0795c6fSMarcus Overhagen //  an API-implementation method.)
1121*a0795c6fSMarcus Overhagen 
1122*a0795c6fSMarcus Overhagen status_t NodeGroup::_start() {
1123*a0795c6fSMarcus Overhagen 	assert_locked(this);
1124*a0795c6fSMarcus Overhagen 
1125*a0795c6fSMarcus Overhagen 	D_METHOD((
1126*a0795c6fSMarcus Overhagen 		"NodeGroup::_start()\n"));
1127*a0795c6fSMarcus Overhagen 	status_t err;
1128*a0795c6fSMarcus Overhagen 
1129*a0795c6fSMarcus Overhagen 	if(m_transportState != TRANSPORT_STOPPED)
1130*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1131*a0795c6fSMarcus Overhagen 
1132*a0795c6fSMarcus Overhagen 	if(m_runMode == BMediaNode::B_OFFLINE)
1133*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1134*a0795c6fSMarcus Overhagen 
1135*a0795c6fSMarcus Overhagen 	ASSERT(m_nodes.size());
1136*a0795c6fSMarcus Overhagen 
1137*a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STARTING);
1138*a0795c6fSMarcus Overhagen 
1139*a0795c6fSMarcus Overhagen 	// * Find the highest latency in the group
1140*a0795c6fSMarcus Overhagen 
1141*a0795c6fSMarcus Overhagen 	bigtime_t offset = 0LL;
1142*a0795c6fSMarcus Overhagen 	calcLatencyFn _f(offset);
1143*a0795c6fSMarcus Overhagen 	for_each(
1144*a0795c6fSMarcus Overhagen 		m_nodes.begin(),
1145*a0795c6fSMarcus Overhagen 		m_nodes.end(),
1146*a0795c6fSMarcus Overhagen 		_f);
1147*a0795c6fSMarcus Overhagen 
1148*a0795c6fSMarcus Overhagen 	offset += s_rosterLatency;
1149*a0795c6fSMarcus Overhagen 	PRINT((
1150*a0795c6fSMarcus Overhagen 		"- offset: %Ld\n", offset));
1151*a0795c6fSMarcus Overhagen 
1152*a0795c6fSMarcus Overhagen 	// * Seek all nodes (in case one or more failed to preroll)
1153*a0795c6fSMarcus Overhagen 
1154*a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1155*a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1156*a0795c6fSMarcus Overhagen 		err = (*it)->_seekStopped(m_startPosition);
1157*a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1158*a0795c6fSMarcus Overhagen 			PRINT((
1159*a0795c6fSMarcus Overhagen 				"! NodeGroup('%s')::_start():\n"
1160*a0795c6fSMarcus Overhagen 				"  ref('%s')->_seekStopped(%Ld) failed:\n"
1161*a0795c6fSMarcus Overhagen 				"  %s\n",
1162*a0795c6fSMarcus Overhagen 				name(), (*it)->name(), m_startPosition,
1163*a0795c6fSMarcus Overhagen 				strerror(err)));
1164*a0795c6fSMarcus Overhagen 
1165*a0795c6fSMarcus Overhagen 			// +++++ continue?
1166*a0795c6fSMarcus Overhagen 		}
1167*a0795c6fSMarcus Overhagen 	}
1168*a0795c6fSMarcus Overhagen 
1169*a0795c6fSMarcus Overhagen 	// * Start all nodes, allowing for the max latency found
1170*a0795c6fSMarcus Overhagen 
1171*a0795c6fSMarcus Overhagen 	ASSERT(m_timeSourceObj);
1172*a0795c6fSMarcus Overhagen 	bigtime_t when = m_timeSourceObj->Now() + offset;
1173*a0795c6fSMarcus Overhagen 
1174*a0795c6fSMarcus Overhagen 	// 10aug99: initialize cycle (loop) settings
1175*a0795c6fSMarcus Overhagen 	if(_cycleValid()) {
1176*a0795c6fSMarcus Overhagen 		_initCycleThread();
1177*a0795c6fSMarcus Overhagen 		_cycleInit(when);
1178*a0795c6fSMarcus Overhagen 	}
1179*a0795c6fSMarcus Overhagen 
1180*a0795c6fSMarcus Overhagen 	// start the nodes
1181*a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1182*a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1183*a0795c6fSMarcus Overhagen 		err = (*it)->_start(when);
1184*a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1185*a0795c6fSMarcus Overhagen 			PRINT((
1186*a0795c6fSMarcus Overhagen 				"! NodeGroup('%s')::_start():\n"
1187*a0795c6fSMarcus Overhagen 				"  ref('%s')->_start(%Ld) failed:\n"
1188*a0795c6fSMarcus Overhagen 				"  %s\n",
1189*a0795c6fSMarcus Overhagen 				name(), (*it)->name(), when,
1190*a0795c6fSMarcus Overhagen 				strerror(err)));
1191*a0795c6fSMarcus Overhagen 
1192*a0795c6fSMarcus Overhagen 			// +++++ continue?
1193*a0795c6fSMarcus Overhagen 		}
1194*a0795c6fSMarcus Overhagen 	}
1195*a0795c6fSMarcus Overhagen 
1196*a0795c6fSMarcus Overhagen 	// notify observers
1197*a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_RUNNING);
1198*a0795c6fSMarcus Overhagen 	return B_OK;
1199*a0795c6fSMarcus Overhagen }
1200*a0795c6fSMarcus Overhagen 
1201*a0795c6fSMarcus Overhagen // Stop all nodes in the group; this is the implementation of
1202*a0795c6fSMarcus Overhagen // stop().
1203*a0795c6fSMarcus Overhagen //
1204*a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1205*a0795c6fSMarcus Overhagen //  an API-implementation method.)
1206*a0795c6fSMarcus Overhagen 
1207*a0795c6fSMarcus Overhagen status_t NodeGroup::_stop() {
1208*a0795c6fSMarcus Overhagen 
1209*a0795c6fSMarcus Overhagen 	D_METHOD((
1210*a0795c6fSMarcus Overhagen 		"NodeGroup::_stop()\n"));
1211*a0795c6fSMarcus Overhagen 
1212*a0795c6fSMarcus Overhagen 	assert_locked(this);
1213*a0795c6fSMarcus Overhagen 
1214*a0795c6fSMarcus Overhagen 	if(
1215*a0795c6fSMarcus Overhagen 		m_transportState != TRANSPORT_RUNNING &&
1216*a0795c6fSMarcus Overhagen 		m_transportState != TRANSPORT_ROLLING)
1217*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1218*a0795c6fSMarcus Overhagen 
1219*a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STOPPING);
1220*a0795c6fSMarcus Overhagen 
1221*a0795c6fSMarcus Overhagen 	// * stop the cycle thread if need be
1222*a0795c6fSMarcus Overhagen 	_destroyCycleThread();
1223*a0795c6fSMarcus Overhagen 
1224*a0795c6fSMarcus Overhagen 	// * stop all nodes
1225*a0795c6fSMarcus Overhagen 	//   +++++ error reports would be nice
1226*a0795c6fSMarcus Overhagen 
1227*a0795c6fSMarcus Overhagen 	for_each(
1228*a0795c6fSMarcus Overhagen 		m_nodes.begin(),
1229*a0795c6fSMarcus Overhagen 		m_nodes.end(),
1230*a0795c6fSMarcus Overhagen 		mem_fun(&NodeRef::_stop)
1231*a0795c6fSMarcus Overhagen 	);
1232*a0795c6fSMarcus Overhagen 
1233*a0795c6fSMarcus Overhagen 	// update transport state
1234*a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STOPPED);
1235*a0795c6fSMarcus Overhagen 
1236*a0795c6fSMarcus Overhagen 	return B_OK;
1237*a0795c6fSMarcus Overhagen }
1238*a0795c6fSMarcus Overhagen 
1239*a0795c6fSMarcus Overhagen // Roll all nodes in the group; this is the implementation of
1240*a0795c6fSMarcus Overhagen // roll().
1241*a0795c6fSMarcus Overhagen //
1242*a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1243*a0795c6fSMarcus Overhagen //  an API-implementation method.)
1244*a0795c6fSMarcus Overhagen 
1245*a0795c6fSMarcus Overhagen status_t NodeGroup::_roll() {
1246*a0795c6fSMarcus Overhagen 
1247*a0795c6fSMarcus Overhagen 	D_METHOD((
1248*a0795c6fSMarcus Overhagen 		"NodeGroup::_roll()\n"));
1249*a0795c6fSMarcus Overhagen 	assert_locked(this);
1250*a0795c6fSMarcus Overhagen 	status_t err;
1251*a0795c6fSMarcus Overhagen 
1252*a0795c6fSMarcus Overhagen 	if(m_transportState != TRANSPORT_STOPPED)
1253*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1254*a0795c6fSMarcus Overhagen 
1255*a0795c6fSMarcus Overhagen 	bigtime_t period = m_endPosition - m_startPosition;
1256*a0795c6fSMarcus Overhagen 	if(period <= 0LL)
1257*a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1258*a0795c6fSMarcus Overhagen 
1259*a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STARTING);
1260*a0795c6fSMarcus Overhagen 
1261*a0795c6fSMarcus Overhagen 	bigtime_t tpStart = 0LL;
1262*a0795c6fSMarcus Overhagen 	bigtime_t tpStop = period;
1263*a0795c6fSMarcus Overhagen 
1264*a0795c6fSMarcus Overhagen 	if(m_runMode != BMediaNode::B_OFFLINE) {
1265*a0795c6fSMarcus Overhagen 
1266*a0795c6fSMarcus Overhagen 		// * Find the highest latency in the group
1267*a0795c6fSMarcus Overhagen 		bigtime_t offset = 0LL;
1268*a0795c6fSMarcus Overhagen 		calcLatencyFn _f(offset);
1269*a0795c6fSMarcus Overhagen 		for_each(
1270*a0795c6fSMarcus Overhagen 			m_nodes.begin(),
1271*a0795c6fSMarcus Overhagen 			m_nodes.end(),
1272*a0795c6fSMarcus Overhagen 			_f);
1273*a0795c6fSMarcus Overhagen 
1274*a0795c6fSMarcus Overhagen 		offset += s_rosterLatency;
1275*a0795c6fSMarcus Overhagen 		PRINT((
1276*a0795c6fSMarcus Overhagen 			"- offset: %Ld\n", offset));
1277*a0795c6fSMarcus Overhagen 
1278*a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
1279*a0795c6fSMarcus Overhagen 		tpStart = m_timeSourceObj->Now() + offset;
1280*a0795c6fSMarcus Overhagen 		tpStop += tpStart;
1281*a0795c6fSMarcus Overhagen 	}
1282*a0795c6fSMarcus Overhagen 
1283*a0795c6fSMarcus Overhagen 	// * Roll all nodes; watch for errors
1284*a0795c6fSMarcus Overhagen 	bool allFailed = true;
1285*a0795c6fSMarcus Overhagen 	err = B_OK;
1286*a0795c6fSMarcus Overhagen 	for(
1287*a0795c6fSMarcus Overhagen 		node_set::iterator it = m_nodes.begin();
1288*a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1289*a0795c6fSMarcus Overhagen 
1290*a0795c6fSMarcus Overhagen 		status_t e = (*it)->_roll(
1291*a0795c6fSMarcus Overhagen 			tpStart,
1292*a0795c6fSMarcus Overhagen 			tpStop,
1293*a0795c6fSMarcus Overhagen 			m_startPosition);
1294*a0795c6fSMarcus Overhagen 		if(e < B_OK)
1295*a0795c6fSMarcus Overhagen 			err = e;
1296*a0795c6fSMarcus Overhagen 		else
1297*a0795c6fSMarcus Overhagen 			allFailed = false;
1298*a0795c6fSMarcus Overhagen 	}
1299*a0795c6fSMarcus Overhagen 
1300*a0795c6fSMarcus Overhagen 	if(!allFailed)
1301*a0795c6fSMarcus Overhagen 		// notify observers
1302*a0795c6fSMarcus Overhagen 		_changeState(TRANSPORT_ROLLING);
1303*a0795c6fSMarcus Overhagen 
1304*a0795c6fSMarcus Overhagen 	return err;
1305*a0795c6fSMarcus Overhagen }
1306*a0795c6fSMarcus Overhagen 
1307*a0795c6fSMarcus Overhagen 
1308*a0795c6fSMarcus Overhagen // State transition; notify listeners
1309*a0795c6fSMarcus Overhagen // +++++ [18aug99] DANGER: should notification happen in the middle
1310*a0795c6fSMarcus Overhagen //                         of such an operation?
1311*a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState(
1312*a0795c6fSMarcus Overhagen 	transport_state_t			to) {
1313*a0795c6fSMarcus Overhagen 
1314*a0795c6fSMarcus Overhagen 	assert_locked(this);
1315*a0795c6fSMarcus Overhagen 
1316*a0795c6fSMarcus Overhagen 	m_transportState = to;
1317*a0795c6fSMarcus Overhagen 
1318*a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
1319*a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
1320*a0795c6fSMarcus Overhagen 	}
1321*a0795c6fSMarcus Overhagen 	BMessage m(M_TRANSPORT_STATE_CHANGED);
1322*a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
1323*a0795c6fSMarcus Overhagen 	m.AddInt32("transportState", m_transportState);
1324*a0795c6fSMarcus Overhagen 	notify(&m);
1325*a0795c6fSMarcus Overhagen 	UnlockLooper();
1326*a0795c6fSMarcus Overhagen }
1327*a0795c6fSMarcus Overhagen 
1328*a0795c6fSMarcus Overhagen // Enforce a state transition, and notify listeners
1329*a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState(
1330*a0795c6fSMarcus Overhagen 	transport_state_t			from,
1331*a0795c6fSMarcus Overhagen 	transport_state_t			to) {
1332*a0795c6fSMarcus Overhagen 
1333*a0795c6fSMarcus Overhagen 	assert_locked(this);
1334*a0795c6fSMarcus Overhagen 	ASSERT(m_transportState == from);
1335*a0795c6fSMarcus Overhagen 
1336*a0795c6fSMarcus Overhagen 	_changeState(to);
1337*a0795c6fSMarcus Overhagen }
1338*a0795c6fSMarcus Overhagen 
1339*a0795c6fSMarcus Overhagen 
1340*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1341*a0795c6fSMarcus Overhagen // *** cycle thread & helpers (LOCK REQUIRED)
1342*a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1343*a0795c6fSMarcus Overhagen 
1344*a0795c6fSMarcus Overhagen // *** cycle port definitions
1345*a0795c6fSMarcus Overhagen 
1346*a0795c6fSMarcus Overhagen const int32					_portLength			= 32;
1347*a0795c6fSMarcus Overhagen const char* const		_portName				= "NodeGroup::m_cyclePort";
1348*a0795c6fSMarcus Overhagen const size_t				_portMsgMaxSize	= 256;
1349*a0795c6fSMarcus Overhagen 
1350*a0795c6fSMarcus Overhagen 
1351*a0795c6fSMarcus Overhagen // set up the cycle thread (including its kernel port)
1352*a0795c6fSMarcus Overhagen status_t NodeGroup::_initCycleThread() {
1353*a0795c6fSMarcus Overhagen 	assert_locked(this);
1354*a0795c6fSMarcus Overhagen 	status_t err;
1355*a0795c6fSMarcus Overhagen 	D_METHOD((
1356*a0795c6fSMarcus Overhagen 		"NodeGroup::_initCycleThread()\n"));
1357*a0795c6fSMarcus Overhagen 
1358*a0795c6fSMarcus Overhagen 	if(m_cycleThread) {
1359*a0795c6fSMarcus Overhagen 		// thread is still alive
1360*a0795c6fSMarcus Overhagen 		err = _destroyCycleThread();
1361*a0795c6fSMarcus Overhagen 		if(err < B_OK)
1362*a0795c6fSMarcus Overhagen 			return err;
1363*a0795c6fSMarcus Overhagen 	}
1364*a0795c6fSMarcus Overhagen 
1365*a0795c6fSMarcus Overhagen 	// create
1366*a0795c6fSMarcus Overhagen 	m_cycleThreadDone = false;
1367*a0795c6fSMarcus Overhagen 	m_cycleThread = spawn_thread(
1368*a0795c6fSMarcus Overhagen 		&_CycleThread,
1369*a0795c6fSMarcus Overhagen 		"NodeGroup[cycleThread]",
1370*a0795c6fSMarcus Overhagen 		B_NORMAL_PRIORITY,
1371*a0795c6fSMarcus Overhagen 		(void*)this);
1372*a0795c6fSMarcus Overhagen 	if(m_cycleThread < B_OK) {
1373*a0795c6fSMarcus Overhagen 		PRINT((
1374*a0795c6fSMarcus Overhagen 			"* NodeGroup::_initCycleThread(): spawn_thread() failed:\n"
1375*a0795c6fSMarcus Overhagen 			"  %s\n",
1376*a0795c6fSMarcus Overhagen 			strerror(m_cycleThread)));
1377*a0795c6fSMarcus Overhagen 		return m_cycleThread;
1378*a0795c6fSMarcus Overhagen 	}
1379*a0795c6fSMarcus Overhagen 
1380*a0795c6fSMarcus Overhagen 	// launch
1381*a0795c6fSMarcus Overhagen 	return resume_thread(m_cycleThread);
1382*a0795c6fSMarcus Overhagen }
1383*a0795c6fSMarcus Overhagen 
1384*a0795c6fSMarcus Overhagen // shut down the cycle thread/port
1385*a0795c6fSMarcus Overhagen status_t NodeGroup::_destroyCycleThread() {
1386*a0795c6fSMarcus Overhagen 	assert_locked(this);
1387*a0795c6fSMarcus Overhagen 	status_t err;
1388*a0795c6fSMarcus Overhagen 	D_METHOD((
1389*a0795c6fSMarcus Overhagen 		"NodeGroup::_destroyCycleThread()\n"));
1390*a0795c6fSMarcus Overhagen 
1391*a0795c6fSMarcus Overhagen 	if(!m_cycleThread)
1392*a0795c6fSMarcus Overhagen 		return B_OK;
1393*a0795c6fSMarcus Overhagen 
1394*a0795c6fSMarcus Overhagen 	if(!m_cycleThreadDone) {
1395*a0795c6fSMarcus Overhagen 		// kill the thread
1396*a0795c6fSMarcus Overhagen 		ASSERT(m_cyclePort);
1397*a0795c6fSMarcus Overhagen 		err = write_port_etc(
1398*a0795c6fSMarcus Overhagen 			m_cyclePort,
1399*a0795c6fSMarcus Overhagen 			_CYCLE_STOP,
1400*a0795c6fSMarcus Overhagen 			0,
1401*a0795c6fSMarcus Overhagen 			0,
1402*a0795c6fSMarcus Overhagen 			B_TIMEOUT,
1403*a0795c6fSMarcus Overhagen 			10000LL);
1404*a0795c6fSMarcus Overhagen 
1405*a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1406*a0795c6fSMarcus Overhagen 			// bad thread.  die, thread, die.
1407*a0795c6fSMarcus Overhagen 			PRINT((
1408*a0795c6fSMarcus Overhagen 				"* NodeGroup::_destroyCycleThread(): port write failed; killing.\n"));
1409*a0795c6fSMarcus Overhagen 			delete_port(m_cyclePort);
1410*a0795c6fSMarcus Overhagen 			m_cyclePort = 0;
1411*a0795c6fSMarcus Overhagen 			kill_thread(m_cycleThread);
1412*a0795c6fSMarcus Overhagen 			m_cycleThread = 0;
1413*a0795c6fSMarcus Overhagen 			return B_OK;
1414*a0795c6fSMarcus Overhagen 		}
1415*a0795c6fSMarcus Overhagen 
1416*a0795c6fSMarcus Overhagen 		// the thread got the message; wait for it to quit
1417*a0795c6fSMarcus Overhagen 		unlock();
1418*a0795c6fSMarcus Overhagen 		while(wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED) {
1419*a0795c6fSMarcus Overhagen 			PRINT((
1420*a0795c6fSMarcus Overhagen 				"! wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED\n"));
1421*a0795c6fSMarcus Overhagen 		}
1422*a0795c6fSMarcus Overhagen 		lock();
1423*a0795c6fSMarcus Overhagen 	}
1424*a0795c6fSMarcus Overhagen 
1425*a0795c6fSMarcus Overhagen 	// it's up to the thread to close its port
1426*a0795c6fSMarcus Overhagen 	ASSERT(!m_cyclePort);
1427*a0795c6fSMarcus Overhagen 
1428*a0795c6fSMarcus Overhagen 	m_cycleThread = 0;
1429*a0795c6fSMarcus Overhagen 
1430*a0795c6fSMarcus Overhagen 	return B_OK;
1431*a0795c6fSMarcus Overhagen }
1432*a0795c6fSMarcus Overhagen 
1433*a0795c6fSMarcus Overhagen 
1434*a0795c6fSMarcus Overhagen // 1) do the current positions specify a valid cycle region?
1435*a0795c6fSMarcus Overhagen // 2) are any nodes in the group cycle-enabled?
1436*a0795c6fSMarcus Overhagen 
1437*a0795c6fSMarcus Overhagen bool NodeGroup::_cycleValid() {
1438*a0795c6fSMarcus Overhagen 	assert_locked(this);
1439*a0795c6fSMarcus Overhagen 	return
1440*a0795c6fSMarcus Overhagen 		(m_transportState == TRANSPORT_RUNNING ||
1441*a0795c6fSMarcus Overhagen 		 m_transportState == TRANSPORT_STARTING) &&
1442*a0795c6fSMarcus Overhagen 		 canCycle();
1443*a0795c6fSMarcus Overhagen }
1444*a0795c6fSMarcus Overhagen 
1445*a0795c6fSMarcus Overhagen // initialize the cycle members (call when starting)
1446*a0795c6fSMarcus Overhagen 
1447*a0795c6fSMarcus Overhagen void NodeGroup::_cycleInit(
1448*a0795c6fSMarcus Overhagen 	bigtime_t										startTime) {
1449*a0795c6fSMarcus Overhagen 	assert_locked(this);
1450*a0795c6fSMarcus Overhagen 	ASSERT(m_cycleNodes.size() > 0);
1451*a0795c6fSMarcus Overhagen 	D_METHOD((
1452*a0795c6fSMarcus Overhagen 		"NodeGroup::_cycleInit(%Ld)\n",
1453*a0795c6fSMarcus Overhagen 		startTime));
1454*a0795c6fSMarcus Overhagen 
1455*a0795c6fSMarcus Overhagen 	// +++++ rescan latencies?
1456*a0795c6fSMarcus Overhagen 
1457*a0795c6fSMarcus Overhagen 	// figure new boundary & deadline from region length
1458*a0795c6fSMarcus Overhagen 	bigtime_t cyclePeriod = m_endPosition - m_startPosition;
1459*a0795c6fSMarcus Overhagen 
1460*a0795c6fSMarcus Overhagen 	if(cyclePeriod <= 0) {
1461*a0795c6fSMarcus Overhagen 		// cycle region is no longer valid
1462*a0795c6fSMarcus Overhagen 		m_cycleBoundary = 0LL;
1463*a0795c6fSMarcus Overhagen 		m_cycleDeadline = 0LL;
1464*a0795c6fSMarcus Overhagen 
1465*a0795c6fSMarcus Overhagen //		no no no -- deadlocks when the thread calls this method
1466*a0795c6fSMarcus Overhagen //		// stop the thread
1467*a0795c6fSMarcus Overhagen //		_destroyCycleThread();
1468*a0795c6fSMarcus Overhagen 		return;
1469*a0795c6fSMarcus Overhagen 	}
1470*a0795c6fSMarcus Overhagen 
1471*a0795c6fSMarcus Overhagen 	m_cycleStart = startTime;
1472*a0795c6fSMarcus Overhagen 	m_cycleBoundary = startTime + cyclePeriod;
1473*a0795c6fSMarcus Overhagen 	m_cycleDeadline = m_cycleBoundary - (m_cycleMaxLatency + s_rosterLatency);
1474*a0795c6fSMarcus Overhagen }
1475*a0795c6fSMarcus Overhagen 
1476*a0795c6fSMarcus Overhagen 
1477*a0795c6fSMarcus Overhagen // add a ref to the cycle set (in proper order, based on latency)
1478*a0795c6fSMarcus Overhagen void NodeGroup::_cycleAddRef(
1479*a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
1480*a0795c6fSMarcus Overhagen 	assert_locked(this);
1481*a0795c6fSMarcus Overhagen 
1482*a0795c6fSMarcus Overhagen 	// make sure it's not already there
1483*a0795c6fSMarcus Overhagen 	ASSERT(find(
1484*a0795c6fSMarcus Overhagen 		m_cycleNodes.begin(),
1485*a0795c6fSMarcus Overhagen 		m_cycleNodes.end(),
1486*a0795c6fSMarcus Overhagen 		ref) == m_cycleNodes.end());
1487*a0795c6fSMarcus Overhagen 
1488*a0795c6fSMarcus Overhagen 	// [re]calc latency if 0
1489*a0795c6fSMarcus Overhagen 	if(!ref->m_latency)
1490*a0795c6fSMarcus Overhagen 		ref->_updateLatency();
1491*a0795c6fSMarcus Overhagen 
1492*a0795c6fSMarcus Overhagen 	node_set::iterator it;
1493*a0795c6fSMarcus Overhagen 	for(it = m_cycleNodes.begin();
1494*a0795c6fSMarcus Overhagen 		it != m_cycleNodes.end(); ++it) {
1495*a0795c6fSMarcus Overhagen 		if(ref->m_latency > (*it)->m_latency) {
1496*a0795c6fSMarcus Overhagen 			m_cycleNodes.insert(it, ref);
1497*a0795c6fSMarcus Overhagen 			break;
1498*a0795c6fSMarcus Overhagen 		}
1499*a0795c6fSMarcus Overhagen 	}
1500*a0795c6fSMarcus Overhagen 
1501*a0795c6fSMarcus Overhagen 	// not inserted? new ref belongs at the end
1502*a0795c6fSMarcus Overhagen 	if(it == m_cycleNodes.end())
1503*a0795c6fSMarcus Overhagen 		m_cycleNodes.insert(it, ref);
1504*a0795c6fSMarcus Overhagen }
1505*a0795c6fSMarcus Overhagen 
1506*a0795c6fSMarcus Overhagen // remove a ref from the cycle set
1507*a0795c6fSMarcus Overhagen void NodeGroup::_cycleRemoveRef(
1508*a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
1509*a0795c6fSMarcus Overhagen 	assert_locked(this);
1510*a0795c6fSMarcus Overhagen 
1511*a0795c6fSMarcus Overhagen 	node_set::iterator it = find(
1512*a0795c6fSMarcus Overhagen 		m_cycleNodes.begin(),
1513*a0795c6fSMarcus Overhagen 		m_cycleNodes.end(),
1514*a0795c6fSMarcus Overhagen 		ref);
1515*a0795c6fSMarcus Overhagen 	ASSERT(it != m_cycleNodes.end());
1516*a0795c6fSMarcus Overhagen 	m_cycleNodes.erase(it);
1517*a0795c6fSMarcus Overhagen }
1518*a0795c6fSMarcus Overhagen 
1519*a0795c6fSMarcus Overhagen bigtime_t NodeGroup::_cycleBoundary() const {
1520*a0795c6fSMarcus Overhagen 	Autolock _l(this);
1521*a0795c6fSMarcus Overhagen 	return m_cycleBoundary;
1522*a0795c6fSMarcus Overhagen }
1523*a0795c6fSMarcus Overhagen 
1524*a0795c6fSMarcus Overhagen // cycle thread impl.
1525*a0795c6fSMarcus Overhagen /*static*/
1526*a0795c6fSMarcus Overhagen status_t NodeGroup::_CycleThread(void* user) {
1527*a0795c6fSMarcus Overhagen 	((NodeGroup*)user)->_cycleThread();
1528*a0795c6fSMarcus Overhagen 	return B_OK;
1529*a0795c6fSMarcus Overhagen }
1530*a0795c6fSMarcus Overhagen 
1531*a0795c6fSMarcus Overhagen void NodeGroup::_cycleThread() {
1532*a0795c6fSMarcus Overhagen 
1533*a0795c6fSMarcus Overhagen 	status_t err;
1534*a0795c6fSMarcus Overhagen 	int32 code;
1535*a0795c6fSMarcus Overhagen 	int32 errorCount = 0;
1536*a0795c6fSMarcus Overhagen 
1537*a0795c6fSMarcus Overhagen 	// +++++ liability -- if the thread has to be killed, this buffer
1538*a0795c6fSMarcus Overhagen 	//       won't be reclaimed
1539*a0795c6fSMarcus Overhagen 	char* msgBuffer = new char[_portMsgMaxSize];
1540*a0795c6fSMarcus Overhagen 	array_delete<char> _d(msgBuffer);
1541*a0795c6fSMarcus Overhagen 
1542*a0795c6fSMarcus Overhagen 	// create port
1543*a0795c6fSMarcus Overhagen 	ASSERT(!m_cyclePort);
1544*a0795c6fSMarcus Overhagen 	m_cyclePort = create_port(
1545*a0795c6fSMarcus Overhagen 		_portLength,
1546*a0795c6fSMarcus Overhagen 		_portName);
1547*a0795c6fSMarcus Overhagen 	ASSERT(m_cyclePort >= B_OK);
1548*a0795c6fSMarcus Overhagen 
1549*a0795c6fSMarcus Overhagen 	// the message-handling loop
1550*a0795c6fSMarcus Overhagen 	bool done = false;
1551*a0795c6fSMarcus Overhagen 	while(!done) {
1552*a0795c6fSMarcus Overhagen 
1553*a0795c6fSMarcus Overhagen 		// *** wait until it's time to queue the next cycle, or until
1554*a0795c6fSMarcus Overhagen 		// *** a message arrives
1555*a0795c6fSMarcus Overhagen 
1556*a0795c6fSMarcus Overhagen 		lock();				// **** BEGIN LOCKED SECTION ****
1557*a0795c6fSMarcus Overhagen 		if(!_cycleValid()) {
1558*a0795c6fSMarcus Overhagen 			unlock();
1559*a0795c6fSMarcus Overhagen 			break;
1560*a0795c6fSMarcus Overhagen 		}
1561*a0795c6fSMarcus Overhagen 
1562*a0795c6fSMarcus Overhagen 		ASSERT(m_cycleNodes.size() > 0);
1563*a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
1564*a0795c6fSMarcus Overhagen 
1565*a0795c6fSMarcus Overhagen 		bigtime_t maxLatency = m_cycleNodes.front()->m_latency;
1566*a0795c6fSMarcus Overhagen 		bigtime_t wakeUpAt = m_timeSourceObj->RealTimeFor(
1567*a0795c6fSMarcus Overhagen 			m_cycleBoundary, maxLatency + s_rosterLatency);
1568*a0795c6fSMarcus Overhagen 		bigtime_t timeout = wakeUpAt - m_timeSourceObj->RealTime();
1569*a0795c6fSMarcus Overhagen 
1570*a0795c6fSMarcus Overhagen 		if(timeout <= 0) {
1571*a0795c6fSMarcus Overhagen 			// +++++ whoops, I'm late.
1572*a0795c6fSMarcus Overhagen 			// +++++ adjust to compensate !!!
1573*a0795c6fSMarcus Overhagen 			PRINT((
1574*a0795c6fSMarcus Overhagen 				"*** NodeGroup::_cycleThread(): LATE\n"
1575*a0795c6fSMarcus Overhagen 				"    by %Ld\n", -timeout));
1576*a0795c6fSMarcus Overhagen 		}
1577*a0795c6fSMarcus Overhagen 
1578*a0795c6fSMarcus Overhagen 		// +++++ if timeout is very short, spin until the target time arrives
1579*a0795c6fSMarcus Overhagen 
1580*a0795c6fSMarcus Overhagen 		unlock();			// **** END LOCKED SECTION ****
1581*a0795c6fSMarcus Overhagen 
1582*a0795c6fSMarcus Overhagen 		// block until message arrives or it's time to wake up
1583*a0795c6fSMarcus Overhagen 		err = read_port_etc(
1584*a0795c6fSMarcus Overhagen 			m_cyclePort,
1585*a0795c6fSMarcus Overhagen 			&code,
1586*a0795c6fSMarcus Overhagen 			msgBuffer,
1587*a0795c6fSMarcus Overhagen 			_portMsgMaxSize,
1588*a0795c6fSMarcus Overhagen 			B_TIMEOUT,
1589*a0795c6fSMarcus Overhagen 			timeout);
1590*a0795c6fSMarcus Overhagen 
1591*a0795c6fSMarcus Overhagen 		if(err == B_TIMED_OUT) {
1592*a0795c6fSMarcus Overhagen 			// the time has come to seek my nodes
1593*a0795c6fSMarcus Overhagen 			_handleCycleService();
1594*a0795c6fSMarcus Overhagen 			continue;
1595*a0795c6fSMarcus Overhagen 		}
1596*a0795c6fSMarcus Overhagen 		else if(err < B_OK) {
1597*a0795c6fSMarcus Overhagen 			// any other error is bad news
1598*a0795c6fSMarcus Overhagen 			PRINT((
1599*a0795c6fSMarcus Overhagen 				"* NodeGroup::_cycleThread(): read_port error:\n"
1600*a0795c6fSMarcus Overhagen 				"  %s\n"
1601*a0795c6fSMarcus Overhagen 				"  ABORTING\n\n", strerror(err)));
1602*a0795c6fSMarcus Overhagen 			if(++errorCount > 10) {
1603*a0795c6fSMarcus Overhagen 				PRINT((
1604*a0795c6fSMarcus Overhagen 					"*** Too many errors; aborting.\n"));
1605*a0795c6fSMarcus Overhagen 				break;
1606*a0795c6fSMarcus Overhagen 			}
1607*a0795c6fSMarcus Overhagen 			continue;
1608*a0795c6fSMarcus Overhagen 		}
1609*a0795c6fSMarcus Overhagen 
1610*a0795c6fSMarcus Overhagen 		errorCount = 0;
1611*a0795c6fSMarcus Overhagen 
1612*a0795c6fSMarcus Overhagen 		// process the message
1613*a0795c6fSMarcus Overhagen 		switch(code) {
1614*a0795c6fSMarcus Overhagen 			case _CYCLE_STOP:
1615*a0795c6fSMarcus Overhagen 				// bail
1616*a0795c6fSMarcus Overhagen 				done = true;
1617*a0795c6fSMarcus Overhagen 				break;
1618*a0795c6fSMarcus Overhagen 
1619*a0795c6fSMarcus Overhagen 			case _CYCLE_END_CHANGED:
1620*a0795c6fSMarcus Overhagen 			case _CYCLE_LATENCY_CHANGED:
1621*a0795c6fSMarcus Overhagen 				// fall through to next loop; for now, these messages
1622*a0795c6fSMarcus Overhagen 				// serve only to slap me out of my stupor and reassess
1623*a0795c6fSMarcus Overhagen 				// the timing situation...
1624*a0795c6fSMarcus Overhagen 				break;
1625*a0795c6fSMarcus Overhagen 
1626*a0795c6fSMarcus Overhagen 			default:
1627*a0795c6fSMarcus Overhagen 				PRINT((
1628*a0795c6fSMarcus Overhagen 					"* NodeGroup::_cycleThread(): unknown message code '%ld'\n", code));
1629*a0795c6fSMarcus Overhagen 				break;
1630*a0795c6fSMarcus Overhagen 		}
1631*a0795c6fSMarcus Overhagen 	} // while(!done)
1632*a0795c6fSMarcus Overhagen 
1633*a0795c6fSMarcus Overhagen 
1634*a0795c6fSMarcus Overhagen 	// delete port
1635*a0795c6fSMarcus Overhagen 	delete_port(m_cyclePort);
1636*a0795c6fSMarcus Overhagen 	m_cyclePort = 0;
1637*a0795c6fSMarcus Overhagen 
1638*a0795c6fSMarcus Overhagen 	// done
1639*a0795c6fSMarcus Overhagen 	m_cycleThreadDone = true;
1640*a0795c6fSMarcus Overhagen }
1641*a0795c6fSMarcus Overhagen 
1642*a0795c6fSMarcus Overhagen // cycle service: seek all nodes & initiate next cycle
1643*a0795c6fSMarcus Overhagen void NodeGroup::_handleCycleService() {
1644*a0795c6fSMarcus Overhagen 	Autolock _l(this);
1645*a0795c6fSMarcus Overhagen //	D_METHOD((
1646*a0795c6fSMarcus Overhagen //		"NodeGroup::_handleCycleService()\n"));
1647*a0795c6fSMarcus Overhagen 	status_t err;
1648*a0795c6fSMarcus Overhagen 
1649*a0795c6fSMarcus Overhagen 	if(!_cycleValid()) {
1650*a0795c6fSMarcus Overhagen //		PRINT((
1651*a0795c6fSMarcus Overhagen //			"- _handleCycleService(): cycle not valid; quitting.\n"));
1652*a0795c6fSMarcus Overhagen 		return;
1653*a0795c6fSMarcus Overhagen 	}
1654*a0795c6fSMarcus Overhagen 
1655*a0795c6fSMarcus Overhagen 	// seek
1656*a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_cycleNodes.begin();
1657*a0795c6fSMarcus Overhagen 		it != m_cycleNodes.end(); ++it) {
1658*a0795c6fSMarcus Overhagen 		err = (*it)->_seek(
1659*a0795c6fSMarcus Overhagen 			m_startPosition,
1660*a0795c6fSMarcus Overhagen 			m_cycleBoundary);
1661*a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1662*a0795c6fSMarcus Overhagen 			PRINT((
1663*a0795c6fSMarcus Overhagen 				"- _handleCycleService(): node('%s')::_seek() failed:\n"
1664*a0795c6fSMarcus Overhagen 				"  %s\n",
1665*a0795c6fSMarcus Overhagen 				(*it)->name(), strerror(err)));
1666*a0795c6fSMarcus Overhagen 		}
1667*a0795c6fSMarcus Overhagen 	}
1668*a0795c6fSMarcus Overhagen 
1669*a0795c6fSMarcus Overhagen 	// update cycle settings
1670*a0795c6fSMarcus Overhagen 	if(m_newStart) {
1671*a0795c6fSMarcus Overhagen 		m_newStart = false;
1672*a0795c6fSMarcus Overhagen 		m_startPosition = m_newStartPosition;
1673*a0795c6fSMarcus Overhagen 	}
1674*a0795c6fSMarcus Overhagen 	if(m_newEnd) {
1675*a0795c6fSMarcus Overhagen 		m_newEnd = false;
1676*a0795c6fSMarcus Overhagen 		m_endPosition = m_newEndPosition;
1677*a0795c6fSMarcus Overhagen 	}
1678*a0795c6fSMarcus Overhagen 
1679*a0795c6fSMarcus Overhagen 	// prepare next cycle
1680*a0795c6fSMarcus Overhagen 	_cycleInit(m_cycleBoundary);
1681*a0795c6fSMarcus Overhagen }
1682*a0795c6fSMarcus Overhagen 
1683*a0795c6fSMarcus Overhagen // END -- NodeGroup.cpp --
1684