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