xref: /haiku/src/apps/cortex/NodeManager/NodeGroup.cpp (revision 7b2f246e6917555f79d43f25ba240c78d45812f2)
1c284bb0fSMatt Madia /*
2c284bb0fSMatt Madia  * Copyright (c) 1999-2000, Eric Moon.
3c284bb0fSMatt Madia  * All rights reserved.
4c284bb0fSMatt Madia  *
5c284bb0fSMatt Madia  * Redistribution and use in source and binary forms, with or without
6c284bb0fSMatt Madia  * modification, are permitted provided that the following conditions
7c284bb0fSMatt Madia  * are met:
8c284bb0fSMatt Madia  *
9c284bb0fSMatt Madia  * 1. Redistributions of source code must retain the above copyright
10c284bb0fSMatt Madia  *    notice, this list of conditions, and the following disclaimer.
11c284bb0fSMatt Madia  *
12c284bb0fSMatt Madia  * 2. Redistributions in binary form must reproduce the above copyright
13c284bb0fSMatt Madia  *    notice, this list of conditions, and the following disclaimer in the
14c284bb0fSMatt Madia  *    documentation and/or other materials provided with the distribution.
15c284bb0fSMatt Madia  *
16c284bb0fSMatt Madia  * 3. The name of the author may not be used to endorse or promote products
17c284bb0fSMatt Madia  *    derived from this software without specific prior written permission.
18c284bb0fSMatt Madia  *
19c284bb0fSMatt Madia  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20c284bb0fSMatt Madia  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21c284bb0fSMatt Madia  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c284bb0fSMatt Madia  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23c284bb0fSMatt Madia  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24c284bb0fSMatt Madia  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25c284bb0fSMatt Madia  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26c284bb0fSMatt Madia  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27c284bb0fSMatt Madia  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28c284bb0fSMatt Madia  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c284bb0fSMatt Madia  */
30c284bb0fSMatt Madia 
31c284bb0fSMatt 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 
release()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
~NodeGroup()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
name() const138a0795c6fSMarcus Overhagen const char* NodeGroup::name() const {
139a0795c6fSMarcus Overhagen 	Autolock _l(this);
140a0795c6fSMarcus Overhagen 	return m_name.String();
141a0795c6fSMarcus Overhagen }
142a0795c6fSMarcus Overhagen 
setName(const char * name)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
countNodes() const150a0795c6fSMarcus Overhagen uint32 NodeGroup::countNodes() const {
151a0795c6fSMarcus Overhagen 	Autolock _l(this);
152a0795c6fSMarcus Overhagen 	return m_nodes.size();
153a0795c6fSMarcus Overhagen }
154a0795c6fSMarcus Overhagen 
nodeAt(uint32 index) const155a0795c6fSMarcus 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 
addNode(NodeRef * node)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 
removeNode(NodeRef * node)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 
removeNode(uint32 index)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 
groupFlags() const359a0795c6fSMarcus Overhagen uint32 NodeGroup::groupFlags() const {
360a0795c6fSMarcus Overhagen 	Autolock _l(this);
361a0795c6fSMarcus Overhagen 	return m_flags;
362a0795c6fSMarcus Overhagen }
363a0795c6fSMarcus Overhagen 
setGroupFlags(uint32 flags)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
canCycle() const374a0795c6fSMarcus 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 
transportState() const388a0795c6fSMarcus 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 
setStartPosition(bigtime_t start)402a0795c6fSMarcus Overhagen status_t NodeGroup::setStartPosition(
403a0795c6fSMarcus Overhagen 	bigtime_t										start) {
404a0795c6fSMarcus Overhagen 	Autolock _l(this);
405a0795c6fSMarcus Overhagen 
406a0795c6fSMarcus Overhagen 	D_METHOD((
407425ac1b6SAlexander von Gluck IV 		"NodeGroup::setStartPosition(%lld)\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 
startPosition() const444a0795c6fSMarcus 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 
setEndPosition(bigtime_t end)464a0795c6fSMarcus Overhagen status_t NodeGroup::setEndPosition(
465a0795c6fSMarcus Overhagen 	bigtime_t										end) {
466a0795c6fSMarcus Overhagen 	Autolock _l(this);
467a0795c6fSMarcus Overhagen 
468a0795c6fSMarcus Overhagen 	D_METHOD((
469425ac1b6SAlexander von Gluck IV 		"NodeGroup::setEndPosition(%lld)\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 
endPosition() const529a0795c6fSMarcus 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 
preroll()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 
start()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 
stop()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 
roll()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 
getTimeSource(media_node * outTimeSource) const603a0795c6fSMarcus 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 
setTimeSource(const media_node & timeSource)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(),
635*7b2f246eSPulkoMandy #if __GNUC__ <= 2
636a0795c6fSMarcus Overhagen 		bind2nd(
637a0795c6fSMarcus Overhagen 			mem_fun(&NodeRef::_setTimeSource),
638a0795c6fSMarcus Overhagen 			m_timeSource.node
639a0795c6fSMarcus Overhagen 		)
640*7b2f246eSPulkoMandy #else
641*7b2f246eSPulkoMandy 		[this](NodeRef* nodeRef) { nodeRef->_setTimeSource(m_timeSource.node); }
642*7b2f246eSPulkoMandy #endif
643a0795c6fSMarcus Overhagen 	);
644a0795c6fSMarcus Overhagen 
645a0795c6fSMarcus Overhagen //	// try to set as sync node
646a0795c6fSMarcus Overhagen //	err = setSyncNode(timeSource);
647a0795c6fSMarcus Overhagen //	if(err < B_OK) {
648a0795c6fSMarcus Overhagen //		PRINT((
649a0795c6fSMarcus Overhagen //			"* NodeGroup::setTimeSource(): setSyncNode() failed: %s\n",
650a0795c6fSMarcus Overhagen //			strerror(err)));
651a0795c6fSMarcus Overhagen //	}
652a0795c6fSMarcus Overhagen 
653a0795c6fSMarcus Overhagen 	// notify
654a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
655a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
656a0795c6fSMarcus Overhagen 	}
657a0795c6fSMarcus Overhagen 	BMessage m(M_TIME_SOURCE_CHANGED);
658a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
659a0795c6fSMarcus Overhagen 	m.AddInt32("timeSourceID", timeSource.node);
660a0795c6fSMarcus Overhagen 	notify(&m);
661a0795c6fSMarcus Overhagen 	UnlockLooper();
662a0795c6fSMarcus Overhagen 
663a0795c6fSMarcus Overhagen 	return B_OK;
664a0795c6fSMarcus Overhagen }
665a0795c6fSMarcus Overhagen 
666a0795c6fSMarcus Overhagen // run mode access:
667a0795c6fSMarcus Overhagen //   Sets the default run mode for the group.  This will be
668a0795c6fSMarcus Overhagen //   applied to every node with a wildcard (0) run mode.
669a0795c6fSMarcus Overhagen //
670a0795c6fSMarcus Overhagen //   Special case: if the run mode is B_OFFLINE, it will be
671a0795c6fSMarcus Overhagen //   applied to all nodes in the group.
672a0795c6fSMarcus Overhagen 
runMode() const673a0795c6fSMarcus Overhagen BMediaNode::run_mode NodeGroup::runMode() const {
674a0795c6fSMarcus Overhagen 	Autolock _l(this);
675a0795c6fSMarcus Overhagen 	return m_runMode;
676a0795c6fSMarcus Overhagen }
677a0795c6fSMarcus Overhagen 
setRunMode(BMediaNode::run_mode mode)678a0795c6fSMarcus Overhagen status_t NodeGroup::setRunMode(BMediaNode::run_mode mode) {
679a0795c6fSMarcus Overhagen 	Autolock _l(this);
680a0795c6fSMarcus Overhagen 
681a0795c6fSMarcus Overhagen 	m_runMode = mode;
682a0795c6fSMarcus Overhagen 
683a0795c6fSMarcus Overhagen 	// apply to all nodes
684a0795c6fSMarcus Overhagen 	for_each(
685a0795c6fSMarcus Overhagen 		m_nodes.begin(),
686a0795c6fSMarcus Overhagen 		m_nodes.end(),
687*7b2f246eSPulkoMandy #if __GNUC__ <= 2
688a0795c6fSMarcus Overhagen 		bind2nd(
689a0795c6fSMarcus Overhagen 			mem_fun(&NodeRef::_setRunModeAuto),
690a0795c6fSMarcus Overhagen 			m_runMode
691a0795c6fSMarcus Overhagen 		)
692*7b2f246eSPulkoMandy #else
693*7b2f246eSPulkoMandy 		[this](NodeRef* ref) { ref->_setRunModeAuto(this->m_runMode); }
694*7b2f246eSPulkoMandy #endif
695a0795c6fSMarcus Overhagen //		bound_method(
696a0795c6fSMarcus Overhagen //			*this,
697a0795c6fSMarcus Overhagen //			&NodeGroup::setRunModeFor)
698a0795c6fSMarcus Overhagen 	);
699a0795c6fSMarcus Overhagen 
700a0795c6fSMarcus Overhagen 
701a0795c6fSMarcus Overhagen 	return B_OK;
702a0795c6fSMarcus Overhagen }
703a0795c6fSMarcus Overhagen 
704a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
705a0795c6fSMarcus Overhagen // *** BHandler
706a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
707a0795c6fSMarcus Overhagen 
MessageReceived(BMessage * message)708a0795c6fSMarcus Overhagen void NodeGroup::MessageReceived(
709a0795c6fSMarcus Overhagen 	BMessage*										message) {
710a0795c6fSMarcus Overhagen 
711a0795c6fSMarcus Overhagen //	PRINT((
712a0795c6fSMarcus Overhagen //		"NodeGroup::MessageReceived():\n"));
713a0795c6fSMarcus Overhagen //	message->PrintToStream();
714a0795c6fSMarcus Overhagen 	status_t err;
715a0795c6fSMarcus Overhagen 
716a0795c6fSMarcus Overhagen 	switch(message->what) {
717a0795c6fSMarcus Overhagen 		case M_SET_TIME_SOURCE:
718a0795c6fSMarcus Overhagen 			{
719a0795c6fSMarcus Overhagen 				media_node timeSource;
720a0795c6fSMarcus Overhagen 				void* data;
721a0795c6fSMarcus Overhagen 				ssize_t dataSize;
722a0795c6fSMarcus Overhagen 				err = message->FindData(
723a0795c6fSMarcus Overhagen 					"timeSourceNode",
724a0795c6fSMarcus Overhagen 					B_RAW_TYPE,
725a0795c6fSMarcus Overhagen 					(const void**)&data,
726a0795c6fSMarcus Overhagen 					&dataSize);
727a0795c6fSMarcus Overhagen 				if(err < B_OK) {
728a0795c6fSMarcus Overhagen 					PRINT((
729a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_TIME_SOURCE):\n"
730a0795c6fSMarcus Overhagen 						"  no timeSourceNode!\n"));
731a0795c6fSMarcus Overhagen 					break;
732a0795c6fSMarcus Overhagen 				}
733a0795c6fSMarcus Overhagen 				timeSource = *(media_node*)data;
734a0795c6fSMarcus Overhagen 
735a0795c6fSMarcus Overhagen 				setTimeSource(timeSource);
736a0795c6fSMarcus Overhagen 			}
737a0795c6fSMarcus Overhagen 			break;
738a0795c6fSMarcus Overhagen 
739a0795c6fSMarcus Overhagen 		case M_SET_RUN_MODE:
740a0795c6fSMarcus Overhagen 			{
741a0795c6fSMarcus Overhagen 				uint32 runMode;
742a0795c6fSMarcus Overhagen 				err = message->FindInt32("runMode", (int32*)&runMode);
743a0795c6fSMarcus Overhagen 				if(err < B_OK) {
744a0795c6fSMarcus Overhagen 					PRINT((
745a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n"
746a0795c6fSMarcus Overhagen 						"  no runMode!\n"));
747a0795c6fSMarcus Overhagen 					break;
748a0795c6fSMarcus Overhagen 				}
749a0795c6fSMarcus Overhagen 
750a0795c6fSMarcus Overhagen 				if(runMode < BMediaNode::B_OFFLINE ||
751a0795c6fSMarcus Overhagen 					runMode > BMediaNode::B_RECORDING) {
752a0795c6fSMarcus Overhagen 					PRINT((
753a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n"
7541a7bcf69SOliver Tappe 						"  invalid run mode (%" B_PRIu32 ")\n", runMode));
755a0795c6fSMarcus Overhagen 					break;
756a0795c6fSMarcus Overhagen 				}
757a0795c6fSMarcus Overhagen 
758a0795c6fSMarcus Overhagen 				setRunMode((BMediaNode::run_mode)runMode);
759a0795c6fSMarcus Overhagen 			}
760a0795c6fSMarcus Overhagen 			break;
761a0795c6fSMarcus Overhagen 
762a0795c6fSMarcus Overhagen 		case M_SET_START_POSITION:
763a0795c6fSMarcus Overhagen 			{
764a0795c6fSMarcus Overhagen 				bigtime_t position;
765a0795c6fSMarcus Overhagen 				err = message->FindInt64("position", (int64*)&position);
766a0795c6fSMarcus Overhagen 				if(err < B_OK) {
767a0795c6fSMarcus Overhagen 					PRINT((
768a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_START_POSITION):\n"
769a0795c6fSMarcus Overhagen 						"  no position!\n"));
770a0795c6fSMarcus Overhagen 					break;
771a0795c6fSMarcus Overhagen 				}
772a0795c6fSMarcus Overhagen 				setStartPosition(position);
773a0795c6fSMarcus Overhagen 			}
774a0795c6fSMarcus Overhagen 			break;
775a0795c6fSMarcus Overhagen 
776a0795c6fSMarcus Overhagen 		case M_SET_END_POSITION:
777a0795c6fSMarcus Overhagen 			{
778a0795c6fSMarcus Overhagen 				bigtime_t position;
779a0795c6fSMarcus Overhagen 				err = message->FindInt64("position", (int64*)&position);
780a0795c6fSMarcus Overhagen 				if(err < B_OK) {
781a0795c6fSMarcus Overhagen 					PRINT((
782a0795c6fSMarcus Overhagen 						"* NodeGroup::MessageReceived(M_SET_END_POSITION):\n"
783a0795c6fSMarcus Overhagen 						"  no position!\n"));
784a0795c6fSMarcus Overhagen 					break;
785a0795c6fSMarcus Overhagen 				}
786a0795c6fSMarcus Overhagen 				setEndPosition(position);
787a0795c6fSMarcus Overhagen 			}
788a0795c6fSMarcus Overhagen 			break;
789a0795c6fSMarcus Overhagen 
790a0795c6fSMarcus Overhagen 		case M_PREROLL:
791a0795c6fSMarcus Overhagen 			preroll();
792a0795c6fSMarcus Overhagen 			break;
793a0795c6fSMarcus Overhagen 
794a0795c6fSMarcus Overhagen 		case M_START:
795a0795c6fSMarcus Overhagen 			start();
796a0795c6fSMarcus Overhagen 			break;
797a0795c6fSMarcus Overhagen 
798a0795c6fSMarcus Overhagen 		case M_STOP:
799a0795c6fSMarcus Overhagen 			stop();
800a0795c6fSMarcus Overhagen 			break;
801a0795c6fSMarcus Overhagen 
802a0795c6fSMarcus Overhagen 		case M_ROLL:
803a0795c6fSMarcus Overhagen 			roll();
804a0795c6fSMarcus Overhagen 			break;
805a0795c6fSMarcus Overhagen 
806a0795c6fSMarcus Overhagen 		default:
807a0795c6fSMarcus Overhagen 			_inherited::MessageReceived(message);
808a0795c6fSMarcus Overhagen 			break;
809a0795c6fSMarcus Overhagen 	}
810a0795c6fSMarcus Overhagen }
811a0795c6fSMarcus Overhagen 
812a0795c6fSMarcus Overhagen 
813a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
814a0795c6fSMarcus Overhagen // *** IPersistent
815a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
816a0795c6fSMarcus Overhagen 
817a0795c6fSMarcus Overhagen // !
818a0795c6fSMarcus Overhagen #if CORTEX_XML
819a0795c6fSMarcus Overhagen // !
820a0795c6fSMarcus Overhagen 
821a0795c6fSMarcus Overhagen // +++++
822a0795c6fSMarcus Overhagen 
823a0795c6fSMarcus Overhagen // Default constructor
NodeGroup()824a0795c6fSMarcus Overhagen NodeGroup::NodeGroup() :
825a0795c6fSMarcus Overhagen 	m_manager(0) {} // +++++ finish initialization
826a0795c6fSMarcus Overhagen 
827a0795c6fSMarcus Overhagen 
828a0795c6fSMarcus Overhagen // !
829a0795c6fSMarcus Overhagen #endif /*CORTEX_XML*/
830a0795c6fSMarcus Overhagen // !
831a0795c6fSMarcus Overhagen 
832a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
833a0795c6fSMarcus Overhagen // *** IObservable:		[19aug99]
834a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
835a0795c6fSMarcus Overhagen 
observerAdded(const BMessenger & observer)836a0795c6fSMarcus Overhagen void NodeGroup::observerAdded(
837a0795c6fSMarcus Overhagen 	const BMessenger&				observer) {
838a0795c6fSMarcus Overhagen 
839a0795c6fSMarcus Overhagen 	BMessage m(M_OBSERVER_ADDED);
840a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
841a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
842a0795c6fSMarcus Overhagen 	observer.SendMessage(&m);
843a0795c6fSMarcus Overhagen }
844a0795c6fSMarcus Overhagen 
observerRemoved(const BMessenger & observer)845a0795c6fSMarcus Overhagen void NodeGroup::observerRemoved(
846a0795c6fSMarcus Overhagen 	const BMessenger&				observer) {
847a0795c6fSMarcus Overhagen 
848a0795c6fSMarcus Overhagen 	BMessage m(M_OBSERVER_REMOVED);
849a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
850a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
851a0795c6fSMarcus Overhagen 	observer.SendMessage(&m);
852a0795c6fSMarcus Overhagen }
853a0795c6fSMarcus Overhagen 
notifyRelease()854a0795c6fSMarcus Overhagen void NodeGroup::notifyRelease() {
855a0795c6fSMarcus Overhagen 
856a0795c6fSMarcus Overhagen 	BMessage m(M_RELEASED);
857a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
858a0795c6fSMarcus Overhagen 	m.AddMessenger("target", BMessenger(this));
859a0795c6fSMarcus Overhagen 	notify(&m);
860a0795c6fSMarcus Overhagen }
861a0795c6fSMarcus Overhagen 
releaseComplete()862a0795c6fSMarcus Overhagen void NodeGroup::releaseComplete() {
863a0795c6fSMarcus Overhagen 	// +++++
864a0795c6fSMarcus Overhagen }
865a0795c6fSMarcus Overhagen 
866a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
867a0795c6fSMarcus Overhagen // *** ILockable: pass lock requests to m_lock
868a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
869a0795c6fSMarcus Overhagen 
lock(lock_t type,bigtime_t timeout)870a0795c6fSMarcus Overhagen bool NodeGroup::lock(
871a0795c6fSMarcus Overhagen 	lock_t type,
872a0795c6fSMarcus Overhagen 	bigtime_t timeout) {
873a0795c6fSMarcus Overhagen 
874a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::lock(): %ld\n", find_thread(0)));
875a0795c6fSMarcus Overhagen 
876a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
877a0795c6fSMarcus Overhagen 	status_t err = m_lock.LockWithTimeout(timeout);
878a0795c6fSMarcus Overhagen 
879a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::lock() ACQUIRED: %ld\n", find_thread(0)));
880a0795c6fSMarcus Overhagen 
881a0795c6fSMarcus Overhagen 	return err == B_OK;
882a0795c6fSMarcus Overhagen }
883a0795c6fSMarcus Overhagen 
unlock(lock_t type)884a0795c6fSMarcus Overhagen bool NodeGroup::unlock(
885a0795c6fSMarcus Overhagen 	lock_t type) {
886a0795c6fSMarcus Overhagen 
887a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::unlock(): %ld\n", find_thread(0)));
888a0795c6fSMarcus Overhagen 
889a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
890a0795c6fSMarcus Overhagen 	m_lock.Unlock();
891a0795c6fSMarcus Overhagen 
892a0795c6fSMarcus Overhagen 	D_LOCK(("*** NodeGroup::unlock() RELEASED: %ld\n", find_thread(0)));
893a0795c6fSMarcus Overhagen 
894a0795c6fSMarcus Overhagen 	return true;
895a0795c6fSMarcus Overhagen }
896a0795c6fSMarcus Overhagen 
isLocked(lock_t type) const897a0795c6fSMarcus Overhagen bool NodeGroup::isLocked(
898a0795c6fSMarcus Overhagen 	lock_t type) const {
899a0795c6fSMarcus Overhagen 
900a0795c6fSMarcus Overhagen 	ASSERT(type == WRITE);
901a0795c6fSMarcus Overhagen 	return m_lock.IsLocked();
902a0795c6fSMarcus Overhagen }
903a0795c6fSMarcus Overhagen 
904a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
905a0795c6fSMarcus Overhagen // *** ctor (accessible to NodeManager)
906a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
907a0795c6fSMarcus Overhagen 
NodeGroup(const char * name,NodeManager * manager,BMediaNode::run_mode runMode)908a0795c6fSMarcus Overhagen NodeGroup::NodeGroup(
909a0795c6fSMarcus Overhagen 	const char*									name,
910a0795c6fSMarcus Overhagen 	NodeManager*								manager,
911a0795c6fSMarcus Overhagen 	BMediaNode::run_mode				runMode) :
912a0795c6fSMarcus Overhagen 
913a0795c6fSMarcus Overhagen 	ObservableHandler(name),
914a0795c6fSMarcus Overhagen 	m_lock("NodeGroup::m_lock"),
915a0795c6fSMarcus Overhagen 	m_manager(manager),
916a0795c6fSMarcus Overhagen 	m_id(NextID()),
917a0795c6fSMarcus Overhagen 	m_name(name),
918a0795c6fSMarcus Overhagen 	m_flags(0),
919a0795c6fSMarcus Overhagen 	m_transportState(TRANSPORT_INVALID),
920a0795c6fSMarcus Overhagen 	m_runMode(runMode),
921a0795c6fSMarcus Overhagen 	m_timeSourceObj(0),
922a0795c6fSMarcus Overhagen 	m_released(false),
923a0795c6fSMarcus Overhagen 	m_cycleThread(0),
924a0795c6fSMarcus Overhagen 	m_cyclePort(0),
925a0795c6fSMarcus Overhagen 	m_startPosition(0LL),
926a0795c6fSMarcus Overhagen 	m_endPosition(0LL),
927a0795c6fSMarcus Overhagen 	m_newStart(false),
928a0795c6fSMarcus Overhagen 	m_newEnd(false) {
929a0795c6fSMarcus Overhagen 
930a0795c6fSMarcus Overhagen 	ASSERT(m_manager);
931a0795c6fSMarcus Overhagen 
932a0795c6fSMarcus Overhagen 	if(!m_manager->Lock()) {
933a0795c6fSMarcus Overhagen 		ASSERT(!"m_manager->Lock() failed");
934a0795c6fSMarcus Overhagen 	}
935a0795c6fSMarcus Overhagen 	m_manager->AddHandler(this);
936a0795c6fSMarcus Overhagen 	m_manager->Unlock();
937a0795c6fSMarcus Overhagen 
938a0795c6fSMarcus Overhagen 	// set default time source
939a0795c6fSMarcus Overhagen 	media_node ts;
940a0795c6fSMarcus Overhagen 	D_ROSTER(("# roster->GetTimeSource()\n"));
941a0795c6fSMarcus Overhagen 	status_t err = m_manager->roster->GetTimeSource(&ts);
942a0795c6fSMarcus Overhagen 	if(err < B_OK) {
943a0795c6fSMarcus Overhagen 		PRINT((
944a0795c6fSMarcus Overhagen 			"*** NodeGroup(): roster->GetTimeSource() failed:\n"
945a0795c6fSMarcus Overhagen 			"    %s\n", strerror(err)));
946a0795c6fSMarcus Overhagen 	}
947a0795c6fSMarcus Overhagen 	setTimeSource(ts);
948a0795c6fSMarcus Overhagen }
949a0795c6fSMarcus Overhagen 
950a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
951a0795c6fSMarcus Overhagen // *** internal operations
952a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
953a0795c6fSMarcus Overhagen 
954a0795c6fSMarcus Overhagen uint32 NodeGroup::s_nextID = 1;
NextID()955a0795c6fSMarcus Overhagen uint32 NodeGroup::NextID() {
956a0795c6fSMarcus Overhagen 	return atomic_add((int32*)&s_nextID, 1);
957a0795c6fSMarcus Overhagen }
958a0795c6fSMarcus Overhagen 
959a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
960a0795c6fSMarcus Overhagen // *** ref->group communication (LOCK REQUIRED)
961a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
962a0795c6fSMarcus Overhagen 
963a0795c6fSMarcus Overhagen // when a NodeRef's cycle state (ie. looping or not looping)
964a0795c6fSMarcus Overhagen // changes, it must pass that information on via this method
965a0795c6fSMarcus Overhagen 
_refCycleChanged(NodeRef * ref)966a0795c6fSMarcus Overhagen void NodeGroup::_refCycleChanged(
967a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
968a0795c6fSMarcus Overhagen 	assert_locked(this);
969a0795c6fSMarcus Overhagen 	D_METHOD((
970a0795c6fSMarcus Overhagen 		"NodeGroup::_refCycleChanged('%s')\n",
971a0795c6fSMarcus Overhagen 		ref->name()));
972a0795c6fSMarcus Overhagen 
973a0795c6fSMarcus Overhagen 	if(ref->m_cycle) {
974a0795c6fSMarcus Overhagen 		_cycleAddRef(ref);
975a0795c6fSMarcus Overhagen 	}	else {
976a0795c6fSMarcus Overhagen 		_cycleRemoveRef(ref);
977a0795c6fSMarcus Overhagen 	}
978a0795c6fSMarcus Overhagen 
979a0795c6fSMarcus Overhagen 	// +++++ if running & cycle valid, the node should be properly
980a0795c6fSMarcus Overhagen 	//       seek'd and start'd
981a0795c6fSMarcus Overhagen }
982a0795c6fSMarcus Overhagen 
983a0795c6fSMarcus Overhagen 
984a0795c6fSMarcus Overhagen // when a cycling node's latency changes, call this method.
985a0795c6fSMarcus Overhagen 
_refLatencyChanged(NodeRef * ref)986a0795c6fSMarcus Overhagen void NodeGroup::_refLatencyChanged(
987a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
988a0795c6fSMarcus Overhagen 	assert_locked(this);
989a0795c6fSMarcus Overhagen 	D_METHOD((
990a0795c6fSMarcus Overhagen 		"NodeGroup::_refLatencyChanged('%s')\n",
991a0795c6fSMarcus Overhagen 		ref->name()));
992a0795c6fSMarcus Overhagen 
993a0795c6fSMarcus Overhagen 	if(!_cycleValid())
994a0795c6fSMarcus Overhagen 		return;
995a0795c6fSMarcus Overhagen 
996a0795c6fSMarcus Overhagen 	// remove & replace ref (positions it properly)
997a0795c6fSMarcus Overhagen 	_cycleRemoveRef(ref);
998a0795c6fSMarcus Overhagen 	_cycleAddRef(ref);
999a0795c6fSMarcus Overhagen 
1000a0795c6fSMarcus Overhagen 	// slap my thread up
1001a0795c6fSMarcus Overhagen 	ASSERT(m_cyclePort);
1002a0795c6fSMarcus Overhagen 	write_port(
1003a0795c6fSMarcus Overhagen 		m_cyclePort,
1004a0795c6fSMarcus Overhagen 		_CYCLE_LATENCY_CHANGED,
1005a0795c6fSMarcus Overhagen 		0,
1006a0795c6fSMarcus Overhagen 		0);
1007a0795c6fSMarcus Overhagen 
1008a0795c6fSMarcus Overhagen 	// +++++ zat it?
1009a0795c6fSMarcus Overhagen }
1010a0795c6fSMarcus Overhagen 
1011a0795c6fSMarcus Overhagen // when a NodeRef receives notification that it has been stopped,
1012a0795c6fSMarcus Overhagen // but is labeled as still running, it must call this method.
1013a0795c6fSMarcus Overhagen // [e.moon 11oct99: roll/B_OFFLINE support]
1014a0795c6fSMarcus Overhagen 
_refStopped(NodeRef * ref)1015a0795c6fSMarcus Overhagen void NodeGroup::_refStopped(
1016a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
1017a0795c6fSMarcus Overhagen 	assert_locked(this);
1018a0795c6fSMarcus Overhagen 	D_METHOD((
1019a0795c6fSMarcus Overhagen 		"NodeGroup::_refStopped('%s')\n",
1020a0795c6fSMarcus Overhagen 		ref->name()));
1021a0795c6fSMarcus Overhagen 
1022a0795c6fSMarcus Overhagen 	// roll/B_OFFLINE support [e.moon 11oct99]
1023a0795c6fSMarcus Overhagen 	// (check to see if any other nodes in the group are still running;
1024a0795c6fSMarcus Overhagen 	//  mark group stopped if not.)
1025a0795c6fSMarcus Overhagen 	if(m_transportState == TRANSPORT_ROLLING) {
1026a0795c6fSMarcus Overhagen 		bool nodesRunning = false;
1027a0795c6fSMarcus Overhagen 		for(node_set::iterator it = m_nodes.begin();
1028a0795c6fSMarcus Overhagen 			it != m_nodes.end(); ++it) {
1029a0795c6fSMarcus Overhagen 			if((*it)->isRunning()) {
1030a0795c6fSMarcus Overhagen 				nodesRunning = true;
1031a0795c6fSMarcus Overhagen 				break;
1032a0795c6fSMarcus Overhagen 			}
1033a0795c6fSMarcus Overhagen 		}
1034a0795c6fSMarcus Overhagen 		if(!nodesRunning)
1035a0795c6fSMarcus Overhagen 			// the group has stopped; update transport state
1036a0795c6fSMarcus Overhagen 			_changeState(TRANSPORT_STOPPED);
1037a0795c6fSMarcus Overhagen 
1038a0795c6fSMarcus Overhagen 	}
1039a0795c6fSMarcus Overhagen 
1040a0795c6fSMarcus Overhagen }
1041a0795c6fSMarcus Overhagen 
1042a0795c6fSMarcus Overhagen 
1043a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1044a0795c6fSMarcus Overhagen // *** transport helpers (LOCK REQUIRED)
1045a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1046a0795c6fSMarcus Overhagen 
1047a0795c6fSMarcus Overhagen 
1048a0795c6fSMarcus Overhagen // Preroll all nodes in the group; this is the implementation
1049a0795c6fSMarcus Overhagen // of preroll().
1050a0795c6fSMarcus Overhagen // *** this method should not be called from the transport thread
1051a0795c6fSMarcus Overhagen // (since preroll operations can block for a relatively long time.)
1052a0795c6fSMarcus Overhagen 
_preroll()1053a0795c6fSMarcus Overhagen status_t NodeGroup::_preroll() {
1054a0795c6fSMarcus Overhagen 	assert_locked(this);
1055a0795c6fSMarcus Overhagen 
1056a0795c6fSMarcus Overhagen 	D_METHOD((
1057a0795c6fSMarcus Overhagen 		"NodeGroup::_preroll()\n"));
1058a0795c6fSMarcus Overhagen 
1059a0795c6fSMarcus Overhagen 	if(
1060a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_RUNNING ||
1061a0795c6fSMarcus Overhagen 		m_transportState == TRANSPORT_ROLLING)
1062a0795c6fSMarcus Overhagen 		// too late
1063a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1064a0795c6fSMarcus Overhagen 
1065a0795c6fSMarcus Overhagen 	// * preroll all nodes to the start position
1066a0795c6fSMarcus Overhagen 
1067a0795c6fSMarcus Overhagen 	// +++++ currently, if an error is encountered it's ignored.
1068a0795c6fSMarcus Overhagen 	//       should the whole operation fail if one node couldn't
1069a0795c6fSMarcus Overhagen 	//       be prerolled?
1070a0795c6fSMarcus Overhagen 	//
1071a0795c6fSMarcus Overhagen 	//       My gut response is 'no', since the preroll step is
1072a0795c6fSMarcus Overhagen 	//       optional, but the caller should have some inkling that
1073a0795c6fSMarcus Overhagen 	//       one of its nodes didn't behave.
1074a0795c6fSMarcus Overhagen 
1075a0795c6fSMarcus Overhagen // [e.moon 13oct99] making PPC compiler happy
1076a0795c6fSMarcus Overhagen //	for_each(
1077a0795c6fSMarcus Overhagen //		m_nodes.begin(),
1078a0795c6fSMarcus Overhagen //		m_nodes.end(),
1079a0795c6fSMarcus Overhagen //		bind2nd(
1080a0795c6fSMarcus Overhagen //			mem_fun(&NodeRef::_preroll),
1081a0795c6fSMarcus Overhagen //			m_startPosition
1082a0795c6fSMarcus Overhagen //		)
1083a0795c6fSMarcus Overhagen //	);
1084a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1085a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1086a0795c6fSMarcus Overhagen 		(*it)->_preroll(m_startPosition);
1087a0795c6fSMarcus Overhagen 	}
1088a0795c6fSMarcus Overhagen 
1089a0795c6fSMarcus Overhagen //    replaces
1090a0795c6fSMarcus Overhagen //		bind2nd(
1091a0795c6fSMarcus Overhagen //			bound_method(*this, &NodeGroup::prerollNode),
1092a0795c6fSMarcus Overhagen //			m_startPosition
1093a0795c6fSMarcus Overhagen //		)
1094a0795c6fSMarcus Overhagen 
1095a0795c6fSMarcus Overhagen 	return B_OK;
1096a0795c6fSMarcus Overhagen }
1097a0795c6fSMarcus Overhagen 
1098a0795c6fSMarcus Overhagen 
1099a0795c6fSMarcus Overhagen //// functor: calculates latency of each node it's handed, caching
1100a0795c6fSMarcus Overhagen //// the largest one found; includes initial latency if nodes report it.
1101a0795c6fSMarcus Overhagen //
1102a0795c6fSMarcus Overhagen //class NodeGroup::calcLatencyFn { public:
1103a0795c6fSMarcus Overhagen //	bigtime_t& maxLatency;
1104a0795c6fSMarcus Overhagen //
1105a0795c6fSMarcus Overhagen //	calcLatencyFn(bigtime_t& _m) : maxLatency(_m) {}
1106a0795c6fSMarcus Overhagen //
1107a0795c6fSMarcus Overhagen //	void operator()(NodeRef* r) {
1108a0795c6fSMarcus Overhagen //		ASSERT(r);
1109a0795c6fSMarcus Overhagen //
1110a0795c6fSMarcus Overhagen ////		PRINT((
1111a0795c6fSMarcus Overhagen ////			"# calcLatencyFn(): '%s'\n",
1112a0795c6fSMarcus Overhagen ////			r->name()));
1113a0795c6fSMarcus Overhagen //
1114a0795c6fSMarcus Overhagen //		if(!(r->node().kind & B_BUFFER_PRODUCER)) {
1115a0795c6fSMarcus Overhagen //			// node can't incur latency
1116a0795c6fSMarcus Overhagen ////			PRINT((
1117a0795c6fSMarcus Overhagen ////				"-   not a producer\n"));
1118a0795c6fSMarcus Overhagen //			return;
1119a0795c6fSMarcus Overhagen //		}
1120a0795c6fSMarcus Overhagen //
1121a0795c6fSMarcus Overhagen //		bigtime_t latency;
1122a0795c6fSMarcus Overhagen //		status_t err =
1123a0795c6fSMarcus Overhagen //			BMediaRoster::Roster()->GetLatencyFor(
1124a0795c6fSMarcus Overhagen //				r->node(),
1125a0795c6fSMarcus Overhagen //				&latency);
1126a0795c6fSMarcus Overhagen //		if(err < B_OK) {
1127a0795c6fSMarcus Overhagen //			PRINT((
1128a0795c6fSMarcus Overhagen //				"* calcLatencyFn: GetLatencyFor() failed: %s\n",
1129a0795c6fSMarcus Overhagen //				strerror(err)));
1130a0795c6fSMarcus Overhagen //			return;
1131a0795c6fSMarcus Overhagen //		}
1132425ac1b6SAlexander von Gluck IV ////		PRINT(("-   %lld\n", latency));
1133a0795c6fSMarcus Overhagen //
1134a0795c6fSMarcus Overhagen //		bigtime_t add;
1135a0795c6fSMarcus Overhagen //		err = BMediaRoster::Roster()->GetInitialLatencyFor(
1136a0795c6fSMarcus Overhagen //			r->node(),
1137a0795c6fSMarcus Overhagen //			&add);
1138425ac1b6SAlexander von Gluck IV ////		PRINT(("-   %lld\n", add));
1139a0795c6fSMarcus Overhagen //		if(err < B_OK) {
1140a0795c6fSMarcus Overhagen //			PRINT((
1141a0795c6fSMarcus Overhagen //				"* calcLatencyFn: GetInitialLatencyFor() failed: %s\n",
1142a0795c6fSMarcus Overhagen //				strerror(err)));
1143a0795c6fSMarcus Overhagen //		}
1144a0795c6fSMarcus Overhagen //		else
1145a0795c6fSMarcus Overhagen //			latency += add;
1146a0795c6fSMarcus Overhagen //
1147a0795c6fSMarcus Overhagen //		if(latency > maxLatency)
1148a0795c6fSMarcus Overhagen //			maxLatency = latency;
1149a0795c6fSMarcus Overhagen //
1150a0795c6fSMarcus Overhagen ////		PRINT((
1151425ac1b6SAlexander von Gluck IV ////			"-   max latency: %lld\n",
1152a0795c6fSMarcus Overhagen ////			maxLatency));
1153a0795c6fSMarcus Overhagen //	}
1154a0795c6fSMarcus Overhagen //};
1155a0795c6fSMarcus Overhagen 
1156a0795c6fSMarcus Overhagen // Start all nodes in the group; this is the implementation of
1157a0795c6fSMarcus Overhagen // start().  Fails if the run mode is B_OFFLINE; use _roll() instead
1158a0795c6fSMarcus Overhagen // in that case.
1159a0795c6fSMarcus Overhagen //
1160a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1161a0795c6fSMarcus Overhagen //  an API-implementation method.)
1162a0795c6fSMarcus Overhagen 
_start()1163a0795c6fSMarcus Overhagen status_t NodeGroup::_start() {
1164a0795c6fSMarcus Overhagen 	assert_locked(this);
1165a0795c6fSMarcus Overhagen 
1166a0795c6fSMarcus Overhagen 	D_METHOD((
1167a0795c6fSMarcus Overhagen 		"NodeGroup::_start()\n"));
1168a0795c6fSMarcus Overhagen 	status_t err;
1169a0795c6fSMarcus Overhagen 
1170a0795c6fSMarcus Overhagen 	if(m_transportState != TRANSPORT_STOPPED)
1171a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1172a0795c6fSMarcus Overhagen 
1173a0795c6fSMarcus Overhagen 	if(m_runMode == BMediaNode::B_OFFLINE)
1174a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1175a0795c6fSMarcus Overhagen 
1176a0795c6fSMarcus Overhagen 	ASSERT(m_nodes.size());
1177a0795c6fSMarcus Overhagen 
1178a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STARTING);
1179a0795c6fSMarcus Overhagen 
1180a0795c6fSMarcus Overhagen 	// * Find the highest latency in the group
1181a0795c6fSMarcus Overhagen 
1182a0795c6fSMarcus Overhagen 	bigtime_t offset = 0LL;
1183a0795c6fSMarcus Overhagen 	calcLatencyFn _f(offset);
1184a0795c6fSMarcus Overhagen 	for_each(
1185a0795c6fSMarcus Overhagen 		m_nodes.begin(),
1186a0795c6fSMarcus Overhagen 		m_nodes.end(),
1187a0795c6fSMarcus Overhagen 		_f);
1188a0795c6fSMarcus Overhagen 
1189a0795c6fSMarcus Overhagen 	offset += s_rosterLatency;
1190a0795c6fSMarcus Overhagen 	PRINT((
11911a7bcf69SOliver Tappe 		"- offset: %" B_PRIdBIGTIME "\n", offset));
1192a0795c6fSMarcus Overhagen 
1193a0795c6fSMarcus Overhagen 	// * Seek all nodes (in case one or more failed to preroll)
1194a0795c6fSMarcus Overhagen 
1195a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1196a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1197a0795c6fSMarcus Overhagen 		err = (*it)->_seekStopped(m_startPosition);
1198a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1199a0795c6fSMarcus Overhagen 			PRINT((
1200a0795c6fSMarcus Overhagen 				"! NodeGroup('%s')::_start():\n"
12011a7bcf69SOliver Tappe 				"  ref('%s')->_seekStopped(%" B_PRIdBIGTIME ") failed:\n"
1202a0795c6fSMarcus Overhagen 				"  %s\n",
1203a0795c6fSMarcus Overhagen 				name(), (*it)->name(), m_startPosition,
1204a0795c6fSMarcus Overhagen 				strerror(err)));
1205a0795c6fSMarcus Overhagen 
1206a0795c6fSMarcus Overhagen 			// +++++ continue?
1207a0795c6fSMarcus Overhagen 		}
1208a0795c6fSMarcus Overhagen 	}
1209a0795c6fSMarcus Overhagen 
1210a0795c6fSMarcus Overhagen 	// * Start all nodes, allowing for the max latency found
1211a0795c6fSMarcus Overhagen 
1212a0795c6fSMarcus Overhagen 	ASSERT(m_timeSourceObj);
1213a0795c6fSMarcus Overhagen 	bigtime_t when = m_timeSourceObj->Now() + offset;
1214a0795c6fSMarcus Overhagen 
1215a0795c6fSMarcus Overhagen 	// 10aug99: initialize cycle (loop) settings
1216a0795c6fSMarcus Overhagen 	if(_cycleValid()) {
1217a0795c6fSMarcus Overhagen 		_initCycleThread();
1218a0795c6fSMarcus Overhagen 		_cycleInit(when);
1219a0795c6fSMarcus Overhagen 	}
1220a0795c6fSMarcus Overhagen 
1221a0795c6fSMarcus Overhagen 	// start the nodes
1222a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_nodes.begin();
1223a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1224a0795c6fSMarcus Overhagen 		err = (*it)->_start(when);
1225a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1226a0795c6fSMarcus Overhagen 			PRINT((
1227a0795c6fSMarcus Overhagen 				"! NodeGroup('%s')::_start():\n"
12281a7bcf69SOliver Tappe 				"  ref('%s')->_start(%" B_PRIdBIGTIME ") failed:\n"
1229a0795c6fSMarcus Overhagen 				"  %s\n",
1230a0795c6fSMarcus Overhagen 				name(), (*it)->name(), when,
1231a0795c6fSMarcus Overhagen 				strerror(err)));
1232a0795c6fSMarcus Overhagen 
1233a0795c6fSMarcus Overhagen 			// +++++ continue?
1234a0795c6fSMarcus Overhagen 		}
1235a0795c6fSMarcus Overhagen 	}
1236a0795c6fSMarcus Overhagen 
1237a0795c6fSMarcus Overhagen 	// notify observers
1238a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_RUNNING);
1239a0795c6fSMarcus Overhagen 	return B_OK;
1240a0795c6fSMarcus Overhagen }
1241a0795c6fSMarcus Overhagen 
1242a0795c6fSMarcus Overhagen // Stop all nodes in the group; this is the implementation of
1243a0795c6fSMarcus Overhagen // stop().
1244a0795c6fSMarcus Overhagen //
1245a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1246a0795c6fSMarcus Overhagen //  an API-implementation method.)
1247a0795c6fSMarcus Overhagen 
_stop()1248a0795c6fSMarcus Overhagen status_t NodeGroup::_stop() {
1249a0795c6fSMarcus Overhagen 
1250a0795c6fSMarcus Overhagen 	D_METHOD((
1251a0795c6fSMarcus Overhagen 		"NodeGroup::_stop()\n"));
1252a0795c6fSMarcus Overhagen 
1253a0795c6fSMarcus Overhagen 	assert_locked(this);
1254a0795c6fSMarcus Overhagen 
1255a0795c6fSMarcus Overhagen 	if(
1256a0795c6fSMarcus Overhagen 		m_transportState != TRANSPORT_RUNNING &&
1257a0795c6fSMarcus Overhagen 		m_transportState != TRANSPORT_ROLLING)
1258a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1259a0795c6fSMarcus Overhagen 
1260a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STOPPING);
1261a0795c6fSMarcus Overhagen 
1262a0795c6fSMarcus Overhagen 	// * stop the cycle thread if need be
1263a0795c6fSMarcus Overhagen 	_destroyCycleThread();
1264a0795c6fSMarcus Overhagen 
1265a0795c6fSMarcus Overhagen 	// * stop all nodes
1266a0795c6fSMarcus Overhagen 	//   +++++ error reports would be nice
1267a0795c6fSMarcus Overhagen 
1268a0795c6fSMarcus Overhagen 	for_each(
1269a0795c6fSMarcus Overhagen 		m_nodes.begin(),
1270a0795c6fSMarcus Overhagen 		m_nodes.end(),
1271*7b2f246eSPulkoMandy #if __GNUC__ <= 2
1272a0795c6fSMarcus Overhagen 		mem_fun(&NodeRef::_stop)
1273*7b2f246eSPulkoMandy #else
1274*7b2f246eSPulkoMandy 		[](NodeRef* ref) { ref->_stop(); }
1275*7b2f246eSPulkoMandy #endif
1276a0795c6fSMarcus Overhagen 	);
1277a0795c6fSMarcus Overhagen 
1278a0795c6fSMarcus Overhagen 	// update transport state
1279a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STOPPED);
1280a0795c6fSMarcus Overhagen 
1281a0795c6fSMarcus Overhagen 	return B_OK;
1282a0795c6fSMarcus Overhagen }
1283a0795c6fSMarcus Overhagen 
1284a0795c6fSMarcus Overhagen // Roll all nodes in the group; this is the implementation of
1285a0795c6fSMarcus Overhagen // roll().
1286a0795c6fSMarcus Overhagen //
1287a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from
1288a0795c6fSMarcus Overhagen //  an API-implementation method.)
1289a0795c6fSMarcus Overhagen 
_roll()1290a0795c6fSMarcus Overhagen status_t NodeGroup::_roll() {
1291a0795c6fSMarcus Overhagen 
1292a0795c6fSMarcus Overhagen 	D_METHOD((
1293a0795c6fSMarcus Overhagen 		"NodeGroup::_roll()\n"));
1294a0795c6fSMarcus Overhagen 	assert_locked(this);
1295a0795c6fSMarcus Overhagen 	status_t err;
1296a0795c6fSMarcus Overhagen 
1297a0795c6fSMarcus Overhagen 	if(m_transportState != TRANSPORT_STOPPED)
1298a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1299a0795c6fSMarcus Overhagen 
1300a0795c6fSMarcus Overhagen 	bigtime_t period = m_endPosition - m_startPosition;
1301a0795c6fSMarcus Overhagen 	if(period <= 0LL)
1302a0795c6fSMarcus Overhagen 		return B_NOT_ALLOWED;
1303a0795c6fSMarcus Overhagen 
1304a0795c6fSMarcus Overhagen 	_changeState(TRANSPORT_STARTING);
1305a0795c6fSMarcus Overhagen 
1306a0795c6fSMarcus Overhagen 	bigtime_t tpStart = 0LL;
1307a0795c6fSMarcus Overhagen 	bigtime_t tpStop = period;
1308a0795c6fSMarcus Overhagen 
1309a0795c6fSMarcus Overhagen 	if(m_runMode != BMediaNode::B_OFFLINE) {
1310a0795c6fSMarcus Overhagen 
1311a0795c6fSMarcus Overhagen 		// * Find the highest latency in the group
1312a0795c6fSMarcus Overhagen 		bigtime_t offset = 0LL;
1313a0795c6fSMarcus Overhagen 		calcLatencyFn _f(offset);
1314a0795c6fSMarcus Overhagen 		for_each(
1315a0795c6fSMarcus Overhagen 			m_nodes.begin(),
1316a0795c6fSMarcus Overhagen 			m_nodes.end(),
1317a0795c6fSMarcus Overhagen 			_f);
1318a0795c6fSMarcus Overhagen 
1319a0795c6fSMarcus Overhagen 		offset += s_rosterLatency;
1320a0795c6fSMarcus Overhagen 		PRINT((
13211a7bcf69SOliver Tappe 			"- offset: %" B_PRIdBIGTIME "\n", offset));
1322a0795c6fSMarcus Overhagen 
1323a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
1324a0795c6fSMarcus Overhagen 		tpStart = m_timeSourceObj->Now() + offset;
1325a0795c6fSMarcus Overhagen 		tpStop += tpStart;
1326a0795c6fSMarcus Overhagen 	}
1327a0795c6fSMarcus Overhagen 
1328a0795c6fSMarcus Overhagen 	// * Roll all nodes; watch for errors
1329a0795c6fSMarcus Overhagen 	bool allFailed = true;
1330a0795c6fSMarcus Overhagen 	err = B_OK;
1331a0795c6fSMarcus Overhagen 	for(
1332a0795c6fSMarcus Overhagen 		node_set::iterator it = m_nodes.begin();
1333a0795c6fSMarcus Overhagen 		it != m_nodes.end(); ++it) {
1334a0795c6fSMarcus Overhagen 
1335a0795c6fSMarcus Overhagen 		status_t e = (*it)->_roll(
1336a0795c6fSMarcus Overhagen 			tpStart,
1337a0795c6fSMarcus Overhagen 			tpStop,
1338a0795c6fSMarcus Overhagen 			m_startPosition);
1339a0795c6fSMarcus Overhagen 		if(e < B_OK)
1340a0795c6fSMarcus Overhagen 			err = e;
1341a0795c6fSMarcus Overhagen 		else
1342a0795c6fSMarcus Overhagen 			allFailed = false;
1343a0795c6fSMarcus Overhagen 	}
1344a0795c6fSMarcus Overhagen 
1345a0795c6fSMarcus Overhagen 	if(!allFailed)
1346a0795c6fSMarcus Overhagen 		// notify observers
1347a0795c6fSMarcus Overhagen 		_changeState(TRANSPORT_ROLLING);
1348a0795c6fSMarcus Overhagen 
1349a0795c6fSMarcus Overhagen 	return err;
1350a0795c6fSMarcus Overhagen }
1351a0795c6fSMarcus Overhagen 
1352a0795c6fSMarcus Overhagen 
1353a0795c6fSMarcus Overhagen // State transition; notify listeners
1354a0795c6fSMarcus Overhagen // +++++ [18aug99] DANGER: should notification happen in the middle
1355a0795c6fSMarcus Overhagen //                         of such an operation?
_changeState(transport_state_t to)1356a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState(
1357a0795c6fSMarcus Overhagen 	transport_state_t			to) {
1358a0795c6fSMarcus Overhagen 
1359a0795c6fSMarcus Overhagen 	assert_locked(this);
1360a0795c6fSMarcus Overhagen 
1361a0795c6fSMarcus Overhagen 	m_transportState = to;
1362a0795c6fSMarcus Overhagen 
1363a0795c6fSMarcus Overhagen 	if(!LockLooper()) {
1364a0795c6fSMarcus Overhagen 		ASSERT(!"LockLooper() failed.");
1365a0795c6fSMarcus Overhagen 	}
1366a0795c6fSMarcus Overhagen 	BMessage m(M_TRANSPORT_STATE_CHANGED);
1367a0795c6fSMarcus Overhagen 	m.AddInt32("groupID", id());
1368a0795c6fSMarcus Overhagen 	m.AddInt32("transportState", m_transportState);
1369a0795c6fSMarcus Overhagen 	notify(&m);
1370a0795c6fSMarcus Overhagen 	UnlockLooper();
1371a0795c6fSMarcus Overhagen }
1372a0795c6fSMarcus Overhagen 
1373a0795c6fSMarcus Overhagen // Enforce a state transition, and notify listeners
_changeState(transport_state_t from,transport_state_t to)1374a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState(
1375a0795c6fSMarcus Overhagen 	transport_state_t			from,
1376a0795c6fSMarcus Overhagen 	transport_state_t			to) {
1377a0795c6fSMarcus Overhagen 
1378a0795c6fSMarcus Overhagen 	assert_locked(this);
1379a0795c6fSMarcus Overhagen 	ASSERT(m_transportState == from);
1380a0795c6fSMarcus Overhagen 
1381a0795c6fSMarcus Overhagen 	_changeState(to);
1382a0795c6fSMarcus Overhagen }
1383a0795c6fSMarcus Overhagen 
1384a0795c6fSMarcus Overhagen 
1385a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1386a0795c6fSMarcus Overhagen // *** cycle thread & helpers (LOCK REQUIRED)
1387a0795c6fSMarcus Overhagen // -------------------------------------------------------- //
1388a0795c6fSMarcus Overhagen 
1389a0795c6fSMarcus Overhagen // *** cycle port definitions
1390a0795c6fSMarcus Overhagen 
1391a0795c6fSMarcus Overhagen const int32					_portLength			= 32;
1392a0795c6fSMarcus Overhagen const char* const		_portName				= "NodeGroup::m_cyclePort";
1393a0795c6fSMarcus Overhagen const size_t				_portMsgMaxSize	= 256;
1394a0795c6fSMarcus Overhagen 
1395a0795c6fSMarcus Overhagen 
1396a0795c6fSMarcus Overhagen // set up the cycle thread (including its kernel port)
_initCycleThread()1397a0795c6fSMarcus Overhagen status_t NodeGroup::_initCycleThread() {
1398a0795c6fSMarcus Overhagen 	assert_locked(this);
1399a0795c6fSMarcus Overhagen 	status_t err;
1400a0795c6fSMarcus Overhagen 	D_METHOD((
1401a0795c6fSMarcus Overhagen 		"NodeGroup::_initCycleThread()\n"));
1402a0795c6fSMarcus Overhagen 
1403a0795c6fSMarcus Overhagen 	if(m_cycleThread) {
1404a0795c6fSMarcus Overhagen 		// thread is still alive
1405a0795c6fSMarcus Overhagen 		err = _destroyCycleThread();
1406a0795c6fSMarcus Overhagen 		if(err < B_OK)
1407a0795c6fSMarcus Overhagen 			return err;
1408a0795c6fSMarcus Overhagen 	}
1409a0795c6fSMarcus Overhagen 
1410a0795c6fSMarcus Overhagen 	// create
1411a0795c6fSMarcus Overhagen 	m_cycleThreadDone = false;
1412a0795c6fSMarcus Overhagen 	m_cycleThread = spawn_thread(
1413a0795c6fSMarcus Overhagen 		&_CycleThread,
1414a0795c6fSMarcus Overhagen 		"NodeGroup[cycleThread]",
1415a0795c6fSMarcus Overhagen 		B_NORMAL_PRIORITY,
1416a0795c6fSMarcus Overhagen 		(void*)this);
1417a0795c6fSMarcus Overhagen 	if(m_cycleThread < B_OK) {
1418a0795c6fSMarcus Overhagen 		PRINT((
1419a0795c6fSMarcus Overhagen 			"* NodeGroup::_initCycleThread(): spawn_thread() failed:\n"
1420a0795c6fSMarcus Overhagen 			"  %s\n",
1421a0795c6fSMarcus Overhagen 			strerror(m_cycleThread)));
1422a0795c6fSMarcus Overhagen 		return m_cycleThread;
1423a0795c6fSMarcus Overhagen 	}
1424a0795c6fSMarcus Overhagen 
1425a0795c6fSMarcus Overhagen 	// launch
1426a0795c6fSMarcus Overhagen 	return resume_thread(m_cycleThread);
1427a0795c6fSMarcus Overhagen }
1428a0795c6fSMarcus Overhagen 
1429a0795c6fSMarcus Overhagen // shut down the cycle thread/port
_destroyCycleThread()1430a0795c6fSMarcus Overhagen status_t NodeGroup::_destroyCycleThread() {
1431a0795c6fSMarcus Overhagen 	assert_locked(this);
1432a0795c6fSMarcus Overhagen 	status_t err;
1433a0795c6fSMarcus Overhagen 	D_METHOD((
1434a0795c6fSMarcus Overhagen 		"NodeGroup::_destroyCycleThread()\n"));
1435a0795c6fSMarcus Overhagen 
1436a0795c6fSMarcus Overhagen 	if(!m_cycleThread)
1437a0795c6fSMarcus Overhagen 		return B_OK;
1438a0795c6fSMarcus Overhagen 
1439a0795c6fSMarcus Overhagen 	if(!m_cycleThreadDone) {
1440a0795c6fSMarcus Overhagen 		// kill the thread
1441a0795c6fSMarcus Overhagen 		ASSERT(m_cyclePort);
1442a0795c6fSMarcus Overhagen 		err = write_port_etc(
1443a0795c6fSMarcus Overhagen 			m_cyclePort,
1444a0795c6fSMarcus Overhagen 			_CYCLE_STOP,
1445a0795c6fSMarcus Overhagen 			0,
1446a0795c6fSMarcus Overhagen 			0,
1447a0795c6fSMarcus Overhagen 			B_TIMEOUT,
1448a0795c6fSMarcus Overhagen 			10000LL);
1449a0795c6fSMarcus Overhagen 
1450a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1451a0795c6fSMarcus Overhagen 			// bad thread.  die, thread, die.
1452a0795c6fSMarcus Overhagen 			PRINT((
1453a0795c6fSMarcus Overhagen 				"* NodeGroup::_destroyCycleThread(): port write failed; killing.\n"));
1454a0795c6fSMarcus Overhagen 			delete_port(m_cyclePort);
1455a0795c6fSMarcus Overhagen 			m_cyclePort = 0;
1456a0795c6fSMarcus Overhagen 			kill_thread(m_cycleThread);
1457a0795c6fSMarcus Overhagen 			m_cycleThread = 0;
1458a0795c6fSMarcus Overhagen 			return B_OK;
1459a0795c6fSMarcus Overhagen 		}
1460a0795c6fSMarcus Overhagen 
1461a0795c6fSMarcus Overhagen 		// the thread got the message; wait for it to quit
1462a0795c6fSMarcus Overhagen 		unlock();
1463a0795c6fSMarcus Overhagen 		while(wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED) {
1464a0795c6fSMarcus Overhagen 			PRINT((
1465a0795c6fSMarcus Overhagen 				"! wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED\n"));
1466a0795c6fSMarcus Overhagen 		}
1467a0795c6fSMarcus Overhagen 		lock();
1468a0795c6fSMarcus Overhagen 	}
1469a0795c6fSMarcus Overhagen 
1470a0795c6fSMarcus Overhagen 	// it's up to the thread to close its port
1471a0795c6fSMarcus Overhagen 	ASSERT(!m_cyclePort);
1472a0795c6fSMarcus Overhagen 
1473a0795c6fSMarcus Overhagen 	m_cycleThread = 0;
1474a0795c6fSMarcus Overhagen 
1475a0795c6fSMarcus Overhagen 	return B_OK;
1476a0795c6fSMarcus Overhagen }
1477a0795c6fSMarcus Overhagen 
1478a0795c6fSMarcus Overhagen 
1479a0795c6fSMarcus Overhagen // 1) do the current positions specify a valid cycle region?
1480a0795c6fSMarcus Overhagen // 2) are any nodes in the group cycle-enabled?
1481a0795c6fSMarcus Overhagen 
_cycleValid()1482a0795c6fSMarcus Overhagen bool NodeGroup::_cycleValid() {
1483a0795c6fSMarcus Overhagen 	assert_locked(this);
1484a0795c6fSMarcus Overhagen 	return
1485a0795c6fSMarcus Overhagen 		(m_transportState == TRANSPORT_RUNNING ||
1486a0795c6fSMarcus Overhagen 		 m_transportState == TRANSPORT_STARTING) &&
1487a0795c6fSMarcus Overhagen 		 canCycle();
1488a0795c6fSMarcus Overhagen }
1489a0795c6fSMarcus Overhagen 
1490a0795c6fSMarcus Overhagen // initialize the cycle members (call when starting)
1491a0795c6fSMarcus Overhagen 
_cycleInit(bigtime_t startTime)1492a0795c6fSMarcus Overhagen void NodeGroup::_cycleInit(
1493a0795c6fSMarcus Overhagen 	bigtime_t										startTime) {
1494a0795c6fSMarcus Overhagen 	assert_locked(this);
1495a0795c6fSMarcus Overhagen 	ASSERT(m_cycleNodes.size() > 0);
1496a0795c6fSMarcus Overhagen 	D_METHOD((
1497425ac1b6SAlexander von Gluck IV 		"NodeGroup::_cycleInit(%lld)\n",
1498a0795c6fSMarcus Overhagen 		startTime));
1499a0795c6fSMarcus Overhagen 
1500a0795c6fSMarcus Overhagen 	// +++++ rescan latencies?
1501a0795c6fSMarcus Overhagen 
1502a0795c6fSMarcus Overhagen 	// figure new boundary & deadline from region length
1503a0795c6fSMarcus Overhagen 	bigtime_t cyclePeriod = m_endPosition - m_startPosition;
1504a0795c6fSMarcus Overhagen 
1505a0795c6fSMarcus Overhagen 	if(cyclePeriod <= 0) {
1506a0795c6fSMarcus Overhagen 		// cycle region is no longer valid
1507a0795c6fSMarcus Overhagen 		m_cycleBoundary = 0LL;
1508a0795c6fSMarcus Overhagen 		m_cycleDeadline = 0LL;
1509a0795c6fSMarcus Overhagen 
1510a0795c6fSMarcus Overhagen //		no no no -- deadlocks when the thread calls this method
1511a0795c6fSMarcus Overhagen //		// stop the thread
1512a0795c6fSMarcus Overhagen //		_destroyCycleThread();
1513a0795c6fSMarcus Overhagen 		return;
1514a0795c6fSMarcus Overhagen 	}
1515a0795c6fSMarcus Overhagen 
1516a0795c6fSMarcus Overhagen 	m_cycleStart = startTime;
1517a0795c6fSMarcus Overhagen 	m_cycleBoundary = startTime + cyclePeriod;
1518a0795c6fSMarcus Overhagen 	m_cycleDeadline = m_cycleBoundary - (m_cycleMaxLatency + s_rosterLatency);
1519a0795c6fSMarcus Overhagen }
1520a0795c6fSMarcus Overhagen 
1521a0795c6fSMarcus Overhagen 
1522a0795c6fSMarcus Overhagen // add a ref to the cycle set (in proper order, based on latency)
_cycleAddRef(NodeRef * ref)1523a0795c6fSMarcus Overhagen void NodeGroup::_cycleAddRef(
1524a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
1525a0795c6fSMarcus Overhagen 	assert_locked(this);
1526a0795c6fSMarcus Overhagen 
1527a0795c6fSMarcus Overhagen 	// make sure it's not already there
1528a0795c6fSMarcus Overhagen 	ASSERT(find(
1529a0795c6fSMarcus Overhagen 		m_cycleNodes.begin(),
1530a0795c6fSMarcus Overhagen 		m_cycleNodes.end(),
1531a0795c6fSMarcus Overhagen 		ref) == m_cycleNodes.end());
1532a0795c6fSMarcus Overhagen 
1533a0795c6fSMarcus Overhagen 	// [re]calc latency if 0
1534a0795c6fSMarcus Overhagen 	if(!ref->m_latency)
1535a0795c6fSMarcus Overhagen 		ref->_updateLatency();
1536a0795c6fSMarcus Overhagen 
1537a0795c6fSMarcus Overhagen 	node_set::iterator it;
1538a0795c6fSMarcus Overhagen 	for(it = m_cycleNodes.begin();
1539a0795c6fSMarcus Overhagen 		it != m_cycleNodes.end(); ++it) {
1540a0795c6fSMarcus Overhagen 		if(ref->m_latency > (*it)->m_latency) {
1541a0795c6fSMarcus Overhagen 			m_cycleNodes.insert(it, ref);
1542a0795c6fSMarcus Overhagen 			break;
1543a0795c6fSMarcus Overhagen 		}
1544a0795c6fSMarcus Overhagen 	}
1545a0795c6fSMarcus Overhagen 
1546a0795c6fSMarcus Overhagen 	// not inserted? new ref belongs at the end
1547a0795c6fSMarcus Overhagen 	if(it == m_cycleNodes.end())
1548a0795c6fSMarcus Overhagen 		m_cycleNodes.insert(it, ref);
1549a0795c6fSMarcus Overhagen }
1550a0795c6fSMarcus Overhagen 
1551a0795c6fSMarcus Overhagen // remove a ref from the cycle set
_cycleRemoveRef(NodeRef * ref)1552a0795c6fSMarcus Overhagen void NodeGroup::_cycleRemoveRef(
1553a0795c6fSMarcus Overhagen 	NodeRef*										ref) {
1554a0795c6fSMarcus Overhagen 	assert_locked(this);
1555a0795c6fSMarcus Overhagen 
1556a0795c6fSMarcus Overhagen 	node_set::iterator it = find(
1557a0795c6fSMarcus Overhagen 		m_cycleNodes.begin(),
1558a0795c6fSMarcus Overhagen 		m_cycleNodes.end(),
1559a0795c6fSMarcus Overhagen 		ref);
1560a0795c6fSMarcus Overhagen 	ASSERT(it != m_cycleNodes.end());
1561a0795c6fSMarcus Overhagen 	m_cycleNodes.erase(it);
1562a0795c6fSMarcus Overhagen }
1563a0795c6fSMarcus Overhagen 
_cycleBoundary() const1564a0795c6fSMarcus Overhagen bigtime_t NodeGroup::_cycleBoundary() const {
1565a0795c6fSMarcus Overhagen 	Autolock _l(this);
1566a0795c6fSMarcus Overhagen 	return m_cycleBoundary;
1567a0795c6fSMarcus Overhagen }
1568a0795c6fSMarcus Overhagen 
1569a0795c6fSMarcus Overhagen // cycle thread impl.
1570a0795c6fSMarcus Overhagen /*static*/
_CycleThread(void * user)1571a0795c6fSMarcus Overhagen status_t NodeGroup::_CycleThread(void* user) {
1572a0795c6fSMarcus Overhagen 	((NodeGroup*)user)->_cycleThread();
1573a0795c6fSMarcus Overhagen 	return B_OK;
1574a0795c6fSMarcus Overhagen }
1575a0795c6fSMarcus Overhagen 
_cycleThread()1576a0795c6fSMarcus Overhagen void NodeGroup::_cycleThread() {
1577a0795c6fSMarcus Overhagen 
1578a0795c6fSMarcus Overhagen 	status_t err;
1579a0795c6fSMarcus Overhagen 	int32 code;
1580a0795c6fSMarcus Overhagen 	int32 errorCount = 0;
1581a0795c6fSMarcus Overhagen 
1582a0795c6fSMarcus Overhagen 	// +++++ liability -- if the thread has to be killed, this buffer
1583a0795c6fSMarcus Overhagen 	//       won't be reclaimed
1584a0795c6fSMarcus Overhagen 	char* msgBuffer = new char[_portMsgMaxSize];
1585a0795c6fSMarcus Overhagen 	array_delete<char> _d(msgBuffer);
1586a0795c6fSMarcus Overhagen 
1587a0795c6fSMarcus Overhagen 	// create port
1588a0795c6fSMarcus Overhagen 	ASSERT(!m_cyclePort);
1589a0795c6fSMarcus Overhagen 	m_cyclePort = create_port(
1590a0795c6fSMarcus Overhagen 		_portLength,
1591a0795c6fSMarcus Overhagen 		_portName);
1592a0795c6fSMarcus Overhagen 	ASSERT(m_cyclePort >= B_OK);
1593a0795c6fSMarcus Overhagen 
1594a0795c6fSMarcus Overhagen 	// the message-handling loop
1595a0795c6fSMarcus Overhagen 	bool done = false;
1596a0795c6fSMarcus Overhagen 	while(!done) {
1597a0795c6fSMarcus Overhagen 
1598a0795c6fSMarcus Overhagen 		// *** wait until it's time to queue the next cycle, or until
1599a0795c6fSMarcus Overhagen 		// *** a message arrives
1600a0795c6fSMarcus Overhagen 
1601a0795c6fSMarcus Overhagen 		lock();				// **** BEGIN LOCKED SECTION ****
1602a0795c6fSMarcus Overhagen 		if(!_cycleValid()) {
1603a0795c6fSMarcus Overhagen 			unlock();
1604a0795c6fSMarcus Overhagen 			break;
1605a0795c6fSMarcus Overhagen 		}
1606a0795c6fSMarcus Overhagen 
1607a0795c6fSMarcus Overhagen 		ASSERT(m_cycleNodes.size() > 0);
1608a0795c6fSMarcus Overhagen 		ASSERT(m_timeSourceObj);
1609a0795c6fSMarcus Overhagen 
1610a0795c6fSMarcus Overhagen 		bigtime_t maxLatency = m_cycleNodes.front()->m_latency;
1611a0795c6fSMarcus Overhagen 		bigtime_t wakeUpAt = m_timeSourceObj->RealTimeFor(
1612a0795c6fSMarcus Overhagen 			m_cycleBoundary, maxLatency + s_rosterLatency);
1613a0795c6fSMarcus Overhagen 		bigtime_t timeout = wakeUpAt - m_timeSourceObj->RealTime();
1614a0795c6fSMarcus Overhagen 
1615a0795c6fSMarcus Overhagen 		if(timeout <= 0) {
1616a0795c6fSMarcus Overhagen 			// +++++ whoops, I'm late.
1617a0795c6fSMarcus Overhagen 			// +++++ adjust to compensate !!!
1618a0795c6fSMarcus Overhagen 			PRINT((
1619a0795c6fSMarcus Overhagen 				"*** NodeGroup::_cycleThread(): LATE\n"
16201a7bcf69SOliver Tappe 				"    by %" B_PRIdBIGTIME "\n", -timeout));
1621a0795c6fSMarcus Overhagen 		}
1622a0795c6fSMarcus Overhagen 
1623a0795c6fSMarcus Overhagen 		// +++++ if timeout is very short, spin until the target time arrives
1624a0795c6fSMarcus Overhagen 
1625a0795c6fSMarcus Overhagen 		unlock();			// **** END LOCKED SECTION ****
1626a0795c6fSMarcus Overhagen 
1627a0795c6fSMarcus Overhagen 		// block until message arrives or it's time to wake up
1628a0795c6fSMarcus Overhagen 		err = read_port_etc(
1629a0795c6fSMarcus Overhagen 			m_cyclePort,
1630a0795c6fSMarcus Overhagen 			&code,
1631a0795c6fSMarcus Overhagen 			msgBuffer,
1632a0795c6fSMarcus Overhagen 			_portMsgMaxSize,
1633a0795c6fSMarcus Overhagen 			B_TIMEOUT,
1634a0795c6fSMarcus Overhagen 			timeout);
1635a0795c6fSMarcus Overhagen 
1636a0795c6fSMarcus Overhagen 		if(err == B_TIMED_OUT) {
1637a0795c6fSMarcus Overhagen 			// the time has come to seek my nodes
1638a0795c6fSMarcus Overhagen 			_handleCycleService();
1639a0795c6fSMarcus Overhagen 			continue;
1640a0795c6fSMarcus Overhagen 		}
1641a0795c6fSMarcus Overhagen 		else if(err < B_OK) {
1642a0795c6fSMarcus Overhagen 			// any other error is bad news
1643a0795c6fSMarcus Overhagen 			PRINT((
1644a0795c6fSMarcus Overhagen 				"* NodeGroup::_cycleThread(): read_port error:\n"
1645a0795c6fSMarcus Overhagen 				"  %s\n"
1646a0795c6fSMarcus Overhagen 				"  ABORTING\n\n", strerror(err)));
1647a0795c6fSMarcus Overhagen 			if(++errorCount > 10) {
1648a0795c6fSMarcus Overhagen 				PRINT((
1649a0795c6fSMarcus Overhagen 					"*** Too many errors; aborting.\n"));
1650a0795c6fSMarcus Overhagen 				break;
1651a0795c6fSMarcus Overhagen 			}
1652a0795c6fSMarcus Overhagen 			continue;
1653a0795c6fSMarcus Overhagen 		}
1654a0795c6fSMarcus Overhagen 
1655a0795c6fSMarcus Overhagen 		errorCount = 0;
1656a0795c6fSMarcus Overhagen 
1657a0795c6fSMarcus Overhagen 		// process the message
1658a0795c6fSMarcus Overhagen 		switch(code) {
1659a0795c6fSMarcus Overhagen 			case _CYCLE_STOP:
1660a0795c6fSMarcus Overhagen 				// bail
1661a0795c6fSMarcus Overhagen 				done = true;
1662a0795c6fSMarcus Overhagen 				break;
1663a0795c6fSMarcus Overhagen 
1664a0795c6fSMarcus Overhagen 			case _CYCLE_END_CHANGED:
1665a0795c6fSMarcus Overhagen 			case _CYCLE_LATENCY_CHANGED:
1666a0795c6fSMarcus Overhagen 				// fall through to next loop; for now, these messages
1667a0795c6fSMarcus Overhagen 				// serve only to slap me out of my stupor and reassess
1668a0795c6fSMarcus Overhagen 				// the timing situation...
1669a0795c6fSMarcus Overhagen 				break;
1670a0795c6fSMarcus Overhagen 
1671a0795c6fSMarcus Overhagen 			default:
1672a0795c6fSMarcus Overhagen 				PRINT((
16731a7bcf69SOliver Tappe 					"* NodeGroup::_cycleThread(): unknown message code '%"
16741a7bcf69SOliver Tappe 						B_PRId32 "'\n", code));
1675a0795c6fSMarcus Overhagen 				break;
1676a0795c6fSMarcus Overhagen 		}
1677a0795c6fSMarcus Overhagen 	} // while(!done)
1678a0795c6fSMarcus Overhagen 
1679a0795c6fSMarcus Overhagen 
1680a0795c6fSMarcus Overhagen 	// delete port
1681a0795c6fSMarcus Overhagen 	delete_port(m_cyclePort);
1682a0795c6fSMarcus Overhagen 	m_cyclePort = 0;
1683a0795c6fSMarcus Overhagen 
1684a0795c6fSMarcus Overhagen 	// done
1685a0795c6fSMarcus Overhagen 	m_cycleThreadDone = true;
1686a0795c6fSMarcus Overhagen }
1687a0795c6fSMarcus Overhagen 
1688a0795c6fSMarcus Overhagen // cycle service: seek all nodes & initiate next cycle
_handleCycleService()1689a0795c6fSMarcus Overhagen void NodeGroup::_handleCycleService() {
1690a0795c6fSMarcus Overhagen 	Autolock _l(this);
1691a0795c6fSMarcus Overhagen //	D_METHOD((
1692a0795c6fSMarcus Overhagen //		"NodeGroup::_handleCycleService()\n"));
1693a0795c6fSMarcus Overhagen 	status_t err;
1694a0795c6fSMarcus Overhagen 
1695a0795c6fSMarcus Overhagen 	if(!_cycleValid()) {
1696a0795c6fSMarcus Overhagen //		PRINT((
1697a0795c6fSMarcus Overhagen //			"- _handleCycleService(): cycle not valid; quitting.\n"));
1698a0795c6fSMarcus Overhagen 		return;
1699a0795c6fSMarcus Overhagen 	}
1700a0795c6fSMarcus Overhagen 
1701a0795c6fSMarcus Overhagen 	// seek
1702a0795c6fSMarcus Overhagen 	for(node_set::iterator it = m_cycleNodes.begin();
1703a0795c6fSMarcus Overhagen 		it != m_cycleNodes.end(); ++it) {
1704a0795c6fSMarcus Overhagen 		err = (*it)->_seek(
1705a0795c6fSMarcus Overhagen 			m_startPosition,
1706a0795c6fSMarcus Overhagen 			m_cycleBoundary);
1707a0795c6fSMarcus Overhagen 		if(err < B_OK) {
1708a0795c6fSMarcus Overhagen 			PRINT((
1709a0795c6fSMarcus Overhagen 				"- _handleCycleService(): node('%s')::_seek() failed:\n"
1710a0795c6fSMarcus Overhagen 				"  %s\n",
1711a0795c6fSMarcus Overhagen 				(*it)->name(), strerror(err)));
1712a0795c6fSMarcus Overhagen 		}
1713a0795c6fSMarcus Overhagen 	}
1714a0795c6fSMarcus Overhagen 
1715a0795c6fSMarcus Overhagen 	// update cycle settings
1716a0795c6fSMarcus Overhagen 	if(m_newStart) {
1717a0795c6fSMarcus Overhagen 		m_newStart = false;
1718a0795c6fSMarcus Overhagen 		m_startPosition = m_newStartPosition;
1719a0795c6fSMarcus Overhagen 	}
1720a0795c6fSMarcus Overhagen 	if(m_newEnd) {
1721a0795c6fSMarcus Overhagen 		m_newEnd = false;
1722a0795c6fSMarcus Overhagen 		m_endPosition = m_newEndPosition;
1723a0795c6fSMarcus Overhagen 	}
1724a0795c6fSMarcus Overhagen 
1725a0795c6fSMarcus Overhagen 	// prepare next cycle
1726a0795c6fSMarcus Overhagen 	_cycleInit(m_cycleBoundary);
1727a0795c6fSMarcus Overhagen }
1728a0795c6fSMarcus Overhagen 
1729a0795c6fSMarcus Overhagen // END -- NodeGroup.cpp --
1730