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