1332cc6bcSAxel Dörfler/*
2332cc6bcSAxel Dörfler * Copyright 2002-2012, Haiku. All Rights Reserved.
3332cc6bcSAxel Dörfler * This file may be used under the terms of the MIT License.
4332cc6bcSAxel Dörfler *
5faa2d10cSDario Casalinuovo * Authors:
6faa2d10cSDario Casalinuovo *    Dario Casalinuovo
7faa2d10cSDario Casalinuovo *    Marcus Overhagen
8332cc6bcSAxel Dörfler */
9332cc6bcSAxel Dörfler
10332cc6bcSAxel Dörfler
1152a38012Sejakowatz#include <TimeSource.h>
127f01171fSDario Casalinuovo
137fd43270Sbeveloper#include <Autolock.h>
147f01171fSDario Casalinuovo
157fd43270Sbeveloper#include <string.h>
167f01171fSDario Casalinuovo
17b84955d4SBarrett#include "MediaDebug.h"
18570f7d04Sbeveloper#include "DataExchange.h"
190a483e72SIngo Weinhold#include "ServerInterface.h"
207fd43270Sbeveloper#include "TimeSourceObject.h"
21faa2d10cSDario Casalinuovo#include "TMap.h"
2252a38012Sejakowatz
235c080a95Sbeveloper#define DEBUG_TIMESOURCE 0
245c080a95Sbeveloper
255c080a95Sbeveloper#if DEBUG_TIMESOURCE
265c080a95Sbeveloper	#define TRACE_TIMESOURCE printf
275c080a95Sbeveloper#else
285c080a95Sbeveloper	#define TRACE_TIMESOURCE if (1) {} else printf
295c080a95Sbeveloper#endif
305c080a95Sbeveloper
310e21b167Sbevelopernamespace BPrivate { namespace media {
320e21b167Sbeveloper
3323d4209dSbeveloper#define _atomic_read(p) 	atomic_or((p), 0)
3423d4209dSbeveloper
357f01171fSDario Casalinuovo// must be multiple of page size
367f01171fSDario Casalinuovo#define TS_AREA_SIZE		B_PAGE_SIZE
377f01171fSDario Casalinuovo// must be power of two
387f01171fSDario Casalinuovo#define TS_INDEX_COUNT		128
3923d4209dSbeveloper
407f01171fSDario Casalinuovo// sizeof(TimeSourceTransmit) must be <= TS_AREA_SIZE
417f01171fSDario Casalinuovostruct TimeSourceTransmit
420e21b167Sbeveloper{
430e21b167Sbeveloper	int32 readindex;
440e21b167Sbeveloper	int32 writeindex;
45d6379053Sbeveloper	int32 isrunning;
4623d4209dSbeveloper	bigtime_t realtime[TS_INDEX_COUNT];
4723d4209dSbeveloper	bigtime_t perftime[TS_INDEX_COUNT];
4823d4209dSbeveloper	float drift[TS_INDEX_COUNT];
490e21b167Sbeveloper};
500e21b167Sbeveloper
51faa2d10cSDario Casalinuovo#define MAX_SLAVE_NODES 300
5223f34657SMarcus Overhagen
5323f34657SMarcus Overhagen
54faa2d10cSDario Casalinuovoclass SlaveNodes : public BLocker
557fd43270Sbeveloper{
56332cc6bcSAxel Dörflerpublic:
57faa2d10cSDario Casalinuovo								SlaveNodes();
58faa2d10cSDario Casalinuovo								~SlaveNodes();
59faa2d10cSDario Casalinuovo
60faa2d10cSDario Casalinuovo	int32						CountSlaves() const;
61faa2d10cSDario Casalinuovo	bool						GetNextSlave(port_id** id);
62faa2d10cSDario Casalinuovo	void						Rewind();
63faa2d10cSDario Casalinuovo
64faa2d10cSDario Casalinuovo	bool						InsertSlave(const media_node& node);
65faa2d10cSDario Casalinuovo	bool						RemoveSlave(const media_node& node);
66faa2d10cSDario Casalinuovoprivate:
67faa2d10cSDario Casalinuovo	Map<media_node_id, port_id>	fSlaveList;
687fd43270Sbeveloper};
697fd43270Sbeveloper
7023f34657SMarcus Overhagen
7123f34657SMarcus OverhagenSlaveNodes::SlaveNodes()
72faa2d10cSDario Casalinuovo	:
73faa2d10cSDario Casalinuovo	BLocker("BTimeSource slavenodes")
7423f34657SMarcus Overhagen{
7523f34657SMarcus Overhagen}
7623f34657SMarcus Overhagen
7723f34657SMarcus Overhagen
7823f34657SMarcus OverhagenSlaveNodes::~SlaveNodes()
7923f34657SMarcus Overhagen{
80faa2d10cSDario Casalinuovo	fSlaveList.MakeEmpty();
81faa2d10cSDario Casalinuovo}
82faa2d10cSDario Casalinuovo
83faa2d10cSDario Casalinuovo
84faa2d10cSDario Casalinuovoint32
85faa2d10cSDario CasalinuovoSlaveNodes::CountSlaves() const
86faa2d10cSDario Casalinuovo{
87faa2d10cSDario Casalinuovo	return fSlaveList.CountItems();
88faa2d10cSDario Casalinuovo}
89faa2d10cSDario Casalinuovo
90faa2d10cSDario Casalinuovo
91faa2d10cSDario Casalinuovobool
92faa2d10cSDario CasalinuovoSlaveNodes::GetNextSlave(port_id** id)
93faa2d10cSDario Casalinuovo{
94faa2d10cSDario Casalinuovo	return fSlaveList.GetNext(id);
9523f34657SMarcus Overhagen}
9623f34657SMarcus Overhagen
9723f34657SMarcus Overhagen
98faa2d10cSDario Casalinuovovoid
99faa2d10cSDario CasalinuovoSlaveNodes::Rewind()
100faa2d10cSDario Casalinuovo{
101faa2d10cSDario Casalinuovo	fSlaveList.Rewind();
102faa2d10cSDario Casalinuovo}
103faa2d10cSDario Casalinuovo
104faa2d10cSDario Casalinuovo
105faa2d10cSDario Casalinuovobool
106faa2d10cSDario CasalinuovoSlaveNodes::InsertSlave(const media_node& node)
107faa2d10cSDario Casalinuovo{
108faa2d10cSDario Casalinuovo	return fSlaveList.Insert(node.node, node.port);
109faa2d10cSDario Casalinuovo}
110faa2d10cSDario Casalinuovo
111faa2d10cSDario Casalinuovo
112faa2d10cSDario Casalinuovobool
113faa2d10cSDario CasalinuovoSlaveNodes::RemoveSlave(const media_node& node)
114faa2d10cSDario Casalinuovo{
115faa2d10cSDario Casalinuovo	return fSlaveList.Remove(node.node);
116faa2d10cSDario Casalinuovo}
117faa2d10cSDario Casalinuovo
118faa2d10cSDario Casalinuovo
119faa2d10cSDario Casalinuovo} } // namespace BPrivate::media
12052a38012Sejakowatz
12152a38012Sejakowatz
12252a38012Sejakowatz/*************************************************************
12352a38012Sejakowatz * protected BTimeSource
12452a38012Sejakowatz *************************************************************/
12552a38012Sejakowatz
12652a38012SejakowatzBTimeSource::~BTimeSource()
12752a38012Sejakowatz{
12852a38012Sejakowatz	CALLED();
1290e21b167Sbeveloper	if (fArea > 0)
1300e21b167Sbeveloper		delete_area(fArea);
13123f34657SMarcus Overhagen	delete fSlaveNodes;
13252a38012Sejakowatz}
13352a38012Sejakowatz
13452a38012Sejakowatz/*************************************************************
13552a38012Sejakowatz * public BTimeSource
13652a38012Sejakowatz *************************************************************/
13752a38012Sejakowatz
13852a38012Sejakowatzstatus_t
13952a38012SejakowatzBTimeSource::SnoozeUntil(bigtime_t performance_time,
1407f01171fSDario Casalinuovo	bigtime_t with_latency, bool retry_signals)
14152a38012Sejakowatz{
14252a38012Sejakowatz	CALLED();
1430e21b167Sbeveloper	bigtime_t time;
1440e21b167Sbeveloper	status_t err;
1450e21b167Sbeveloper	do {
1460e21b167Sbeveloper		time = RealTimeFor(performance_time, with_latency);
1470e21b167Sbeveloper		err = snooze_until(time, B_SYSTEM_TIMEBASE);
1480e21b167Sbeveloper	} while (err == B_INTERRUPTED && retry_signals);
1490e21b167Sbeveloper	return err;
15052a38012Sejakowatz}
15152a38012Sejakowatz
15252a38012Sejakowatz
15352a38012Sejakowatzbigtime_t
15452a38012SejakowatzBTimeSource::Now()
15552a38012Sejakowatz{
1565ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::Now()\n");
15752a38012Sejakowatz	return PerformanceTimeFor(RealTime());
15852a38012Sejakowatz}
15952a38012Sejakowatz
16052a38012Sejakowatz
16152a38012Sejakowatzbigtime_t
16252a38012SejakowatzBTimeSource::PerformanceTimeFor(bigtime_t real_time)
16352a38012Sejakowatz{
1645ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::PerformanceTimeFor()\n");
165332cc6bcSAxel Dörfler	bigtime_t last_perf_time;
166332cc6bcSAxel Dörfler	bigtime_t last_real_time;
167332cc6bcSAxel Dörfler	float last_drift;
16852a38012Sejakowatz
169b5714936SMarcus Overhagen	if (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK)
170b5714936SMarcus Overhagen		debugger("BTimeSource::PerformanceTimeFor: GetTime failed");
171332cc6bcSAxel Dörfler
1727f01171fSDario Casalinuovo	return last_perf_time
1737f01171fSDario Casalinuovo		+ (bigtime_t)((real_time - last_real_time) * last_drift);
17452a38012Sejakowatz}
17552a38012Sejakowatz
17652a38012Sejakowatz
17752a38012Sejakowatzbigtime_t
17852a38012SejakowatzBTimeSource::RealTimeFor(bigtime_t performance_time,
1797f01171fSDario Casalinuovo	bigtime_t with_latency)
18052a38012Sejakowatz{
1815ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::RealTimeFor()\n");
18252a38012Sejakowatz
1830e21b167Sbeveloper	if (fIsRealtime) {
1840e21b167Sbeveloper		return performance_time - with_latency;
1850e21b167Sbeveloper	}
1860e21b167Sbeveloper
187332cc6bcSAxel Dörfler	bigtime_t last_perf_time;
188332cc6bcSAxel Dörfler	bigtime_t last_real_time;
189332cc6bcSAxel Dörfler	float last_drift;
1900e21b167Sbeveloper
191b5714936SMarcus Overhagen	if (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK)
192b5714936SMarcus Overhagen		debugger("BTimeSource::RealTimeFor: GetTime failed");
1930e21b167Sbeveloper
1947f01171fSDario Casalinuovo	return last_real_time - with_latency
1957f01171fSDario Casalinuovo		+ (bigtime_t)((performance_time - last_perf_time) / last_drift);
19652a38012Sejakowatz}
19752a38012Sejakowatz
19852a38012Sejakowatz
19952a38012Sejakowatzbool
20052a38012SejakowatzBTimeSource::IsRunning()
20152a38012Sejakowatz{
2025ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::IsRunning()\n");
2035c080a95Sbeveloper
204d6379053Sbeveloper	bool isrunning;
205332cc6bcSAxel Dörfler
2067f01171fSDario Casalinuovo	// The system time source is always running
2075c080a95Sbeveloper	if (fIsRealtime)
2087f01171fSDario Casalinuovo		isrunning = true;
2095c080a95Sbeveloper	else
2105c080a95Sbeveloper		isrunning = fBuf ? atomic_add(&fBuf->isrunning, 0) : fStarted;
211332cc6bcSAxel Dörfler
212332cc6bcSAxel Dörfler	TRACE_TIMESOURCE("BTimeSource::IsRunning() node %" B_PRId32 ", port %"
213332cc6bcSAxel Dörfler		B_PRId32 ", %s\n", fNodeID, fControlPort, isrunning ? "yes" : "no");
214d6379053Sbeveloper	return isrunning;
21552a38012Sejakowatz}
21652a38012Sejakowatz
21752a38012Sejakowatz
21852a38012Sejakowatzstatus_t
2197f01171fSDario CasalinuovoBTimeSource::GetTime(bigtime_t* performance_time,
2207f01171fSDario Casalinuovo	bigtime_t* real_time, float* drift)
22152a38012Sejakowatz{
2225ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::GetTime()\n");
22352a38012Sejakowatz
2240e21b167Sbeveloper	if (fIsRealtime) {
2250e21b167Sbeveloper		*performance_time = *real_time = system_time();
2260e21b167Sbeveloper		*drift = 1.0f;
2270e21b167Sbeveloper		return B_OK;
2280e21b167Sbeveloper	}
2290e21b167Sbeveloper
23011ed4f9fSDario Casalinuovo	if (fBuf == NULL)
23111ed4f9fSDario Casalinuovo		debugger("BTimeSource::GetTime: fBuf == NULL");
23211ed4f9fSDario Casalinuovo
23311ed4f9fSDario Casalinuovo	int32 index = _atomic_read(&fBuf->readindex);
23423d4209dSbeveloper	index &= (TS_INDEX_COUNT - 1);
2350e21b167Sbeveloper	*real_time = fBuf->realtime[index];
2360e21b167Sbeveloper	*performance_time = fBuf->perftime[index];
2370e21b167Sbeveloper	*drift = fBuf->drift[index];
2380e21b167Sbeveloper
239332cc6bcSAxel Dörfler	TRACE_TIMESOURCE("BTimeSource::GetTime     timesource %" B_PRId32
240332cc6bcSAxel Dörfler		", perf %16" B_PRId64 ", real %16" B_PRId64 ", drift %2.2f\n", ID(),
241332cc6bcSAxel Dörfler		*performance_time, *real_time, *drift);
24252a38012Sejakowatz	return B_OK;
24352a38012Sejakowatz}
24452a38012Sejakowatz
24552a38012Sejakowatz
24652a38012Sejakowatzbigtime_t
24752a38012SejakowatzBTimeSource::RealTime()
24852a38012Sejakowatz{
2495ac4fbd7Sbeveloper	PRINT(8, "CALLED BTimeSource::RealTime()\n");
25052a38012Sejakowatz	return system_time();
25152a38012Sejakowatz}
25252a38012Sejakowatz
25352a38012Sejakowatz
25452a38012Sejakowatzstatus_t
2557f01171fSDario CasalinuovoBTimeSource::GetStartLatency(bigtime_t* out_latency)
25652a38012Sejakowatz{
25752a38012Sejakowatz	CALLED();
25852a38012Sejakowatz	*out_latency = 0;
25952a38012Sejakowatz	return B_OK;
26052a38012Sejakowatz}
26152a38012Sejakowatz
26252a38012Sejakowatz/*************************************************************
26352a38012Sejakowatz * protected BTimeSource
26452a38012Sejakowatz *************************************************************/
26552a38012Sejakowatz
26652a38012Sejakowatz
2677f01171fSDario CasalinuovoBTimeSource::BTimeSource()
2687f01171fSDario Casalinuovo	:
2690e21b167Sbeveloper	BMediaNode("This one is never called"),
270d6379053Sbeveloper	fStarted(false),
2710e21b167Sbeveloper	fArea(-1),
2720e21b167Sbeveloper	fBuf(NULL),
27323f34657SMarcus Overhagen	fSlaveNodes(new BPrivate::media::SlaveNodes),
2740e21b167Sbeveloper	fIsRealtime(false)
27552a38012Sejakowatz{
27652a38012Sejakowatz	CALLED();
27752a38012Sejakowatz	AddNodeKind(B_TIME_SOURCE);
2780e21b167Sbeveloper	// This constructor is only called by real time sources that inherit
2790e21b167Sbeveloper	// BTimeSource. We create the communication area in FinishCreate(),
2800e21b167Sbeveloper	// since we don't have a correct ID() until this node is registered.
28152a38012Sejakowatz}
28252a38012Sejakowatz
28352a38012Sejakowatz
28452a38012Sejakowatzstatus_t
2857f01171fSDario CasalinuovoBTimeSource::HandleMessage(int32 message, const void* rawdata,
2867f01171fSDario Casalinuovo	size_t size)
28752a38012Sejakowatz{
288332cc6bcSAxel Dörfler	PRINT(4, "BTimeSource::HandleMessage %#" B_PRIx32 ", node %" B_PRId32 "\n",
289332cc6bcSAxel Dörfler		message, fNodeID);
290fc8b28b6SJérôme Duval	status_t rv;
29152a38012Sejakowatz	switch (message) {
29252a38012Sejakowatz		case TIMESOURCE_OP:
29352a38012Sejakowatz		{
2947f01171fSDario Casalinuovo			const time_source_op_info* data
2957f01171fSDario Casalinuovo				= static_cast<const time_source_op_info*>(rawdata);
29669cb3c10SAxel Dörfler
29769cb3c10SAxel Dörfler			status_t result;
29869cb3c10SAxel Dörfler			result = TimeSourceOp(*data, NULL);
29969cb3c10SAxel Dörfler			if (result != B_OK) {
30069cb3c10SAxel Dörfler				ERROR("BTimeSource::HandleMessage: TimeSourceOp failed\n");
30169cb3c10SAxel Dörfler			}
30269cb3c10SAxel Dörfler
3030e21b167Sbeveloper			switch (data->op) {
3040e21b167Sbeveloper				case B_TIMESOURCE_START:
3050e21b167Sbeveloper					DirectStart(data->real_time);
3060e21b167Sbeveloper					break;
3070e21b167Sbeveloper				case B_TIMESOURCE_STOP:
3080e21b167Sbeveloper					DirectStop(data->real_time, false);
3090e21b167Sbeveloper					break;
3100e21b167Sbeveloper				case B_TIMESOURCE_STOP_IMMEDIATELY:
3110e21b167Sbeveloper					DirectStop(data->real_time, true);
3120e21b167Sbeveloper					break;
3130e21b167Sbeveloper				case B_TIMESOURCE_SEEK:
3140e21b167Sbeveloper					DirectSeek(data->performance_time, data->real_time);
3150e21b167Sbeveloper					break;
3160e21b167Sbeveloper			}
31752a38012Sejakowatz			return B_OK;
31852a38012Sejakowatz		}
319332cc6bcSAxel Dörfler
3207fd43270Sbeveloper		case TIMESOURCE_ADD_SLAVE_NODE:
3217fd43270Sbeveloper		{
3227f01171fSDario Casalinuovo			const timesource_add_slave_node_command* data
3237f01171fSDario Casalinuovo				= static_cast<const timesource_add_slave_node_command*>(rawdata);
3247fd43270Sbeveloper			DirectAddMe(data->node);
3257fd43270Sbeveloper			return B_OK;
3267fd43270Sbeveloper		}
3277fd43270Sbeveloper
3287fd43270Sbeveloper		case TIMESOURCE_REMOVE_SLAVE_NODE:
3297fd43270Sbeveloper		{
3307f01171fSDario Casalinuovo			const timesource_remove_slave_node_command* data
3317f01171fSDario Casalinuovo				= static_cast<const timesource_remove_slave_node_command*>(rawdata);
3327fd43270Sbeveloper			DirectRemoveMe(data->node);
3337fd43270Sbeveloper			return B_OK;
3347fd43270Sbeveloper		}
335332cc6bcSAxel Dörfler
336fc8b28b6SJérôme Duval		case TIMESOURCE_GET_START_LATENCY:
337fc8b28b6SJérôme Duval		{
3387f01171fSDario Casalinuovo			const timesource_get_start_latency_request* request
3397f01171fSDario Casalinuovo				= static_cast<const timesource_get_start_latency_request*>(rawdata);
340fc8b28b6SJérôme Duval			timesource_get_start_latency_reply reply;
341fc8b28b6SJérôme Duval			rv = GetStartLatency(&reply.start_latency);
342fc8b28b6SJérôme Duval			request->SendReply(rv, &reply, sizeof(reply));
343fc8b28b6SJérôme Duval			return B_OK;
344fc8b28b6SJérôme Duval		}
3450e21b167Sbeveloper	}
34652a38012Sejakowatz	return B_ERROR;
34752a38012Sejakowatz}
34852a38012Sejakowatz
34952a38012Sejakowatz
35052a38012Sejakowatzvoid
35152a38012SejakowatzBTimeSource::PublishTime(bigtime_t performance_time,
3527f01171fSDario Casalinuovo	bigtime_t real_time, float drift)
35352a38012Sejakowatz{
354332cc6bcSAxel Dörfler	TRACE_TIMESOURCE("BTimeSource::PublishTime timesource %" B_PRId32
355332cc6bcSAxel Dörfler		", perf %16" B_PRId64 ", real %16" B_PRId64 ", drift %2.2f\n", ID(),
356332cc6bcSAxel Dörfler		performance_time, real_time, drift);
357d6379053Sbeveloper	if (0 == fBuf) {
358332cc6bcSAxel Dörfler		ERROR("BTimeSource::PublishTime timesource %" B_PRId32
359332cc6bcSAxel Dörfler			", fBuf = NULL\n", ID());
360d6379053Sbeveloper		fStarted = true;
3610e21b167Sbeveloper		return;
362d6379053Sbeveloper	}
3630e21b167Sbeveloper
36411ed4f9fSDario Casalinuovo	int32 index = atomic_add(&fBuf->writeindex, 1);
36523d4209dSbeveloper	index &= (TS_INDEX_COUNT - 1);
3660e21b167Sbeveloper	fBuf->realtime[index] = real_time;
3670e21b167Sbeveloper	fBuf->perftime[index] = performance_time;
3680e21b167Sbeveloper	fBuf->drift[index] = drift;
3690e21b167Sbeveloper	atomic_add(&fBuf->readindex, 1);
37052a38012Sejakowatz}
37152a38012Sejakowatz
37252a38012Sejakowatz
37352a38012Sejakowatzvoid
37452a38012SejakowatzBTimeSource::BroadcastTimeWarp(bigtime_t at_real_time,
3757f01171fSDario Casalinuovo	bigtime_t new_performance_time)
37652a38012Sejakowatz{
3777fd43270Sbeveloper	CALLED();
37823f34657SMarcus Overhagen	ASSERT(fSlaveNodes != NULL);
37923f34657SMarcus Overhagen
3807fd43270Sbeveloper	// calls BMediaNode::TimeWarp() of all slaved nodes
381332cc6bcSAxel Dörfler
382332cc6bcSAxel Dörfler	TRACE("BTimeSource::BroadcastTimeWarp: at_real_time %" B_PRId64
383332cc6bcSAxel Dörfler		", new_performance_time %" B_PRId64 "\n", at_real_time,
384332cc6bcSAxel Dörfler		new_performance_time);
385332cc6bcSAxel Dörfler
386faa2d10cSDario Casalinuovo	BAutolock lock(fSlaveNodes);
3877fd43270Sbeveloper
388faa2d10cSDario Casalinuovo	port_id* port = NULL;
389faa2d10cSDario Casalinuovo	while (fSlaveNodes->GetNextSlave(&port) == true) {
390faa2d10cSDario Casalinuovo		node_time_warp_command cmd;
391faa2d10cSDario Casalinuovo		cmd.at_real_time = at_real_time;
392faa2d10cSDario Casalinuovo		cmd.to_performance_time = new_performance_time;
393faa2d10cSDario Casalinuovo		SendToPort(*port, NODE_TIME_WARP,
394faa2d10cSDario Casalinuovo			&cmd, sizeof(cmd));
3957fd43270Sbeveloper	}
396faa2d10cSDario Casalinuovo	fSlaveNodes->Rewind();
39752a38012Sejakowatz}
39852a38012Sejakowatz
39952a38012Sejakowatz
40052a38012Sejakowatzvoid
40152a38012SejakowatzBTimeSource::SendRunMode(run_mode mode)
40252a38012Sejakowatz{
4037fd43270Sbeveloper	CALLED();
40423f34657SMarcus Overhagen	ASSERT(fSlaveNodes != NULL);
40523f34657SMarcus Overhagen
4060e21b167Sbeveloper	// send the run mode change to all slaved nodes
4077fd43270Sbeveloper
408faa2d10cSDario Casalinuovo	BAutolock lock(fSlaveNodes);
4097fd43270Sbeveloper
410faa2d10cSDario Casalinuovo	port_id* port = NULL;
411faa2d10cSDario Casalinuovo	while (fSlaveNodes->GetNextSlave(&port) == true) {
412faa2d10cSDario Casalinuovo		node_set_run_mode_command cmd;
413faa2d10cSDario Casalinuovo		cmd.mode = mode;
414faa2d10cSDario Casalinuovo		SendToPort(*port, NODE_SET_RUN_MODE,
415faa2d10cSDario Casalinuovo			&cmd, sizeof(cmd));
4167fd43270Sbeveloper	}
417faa2d10cSDario Casalinuovo	fSlaveNodes->Rewind();
41852a38012Sejakowatz}
41952a38012Sejakowatz
42052a38012Sejakowatz
42152a38012Sejakowatzvoid
42252a38012SejakowatzBTimeSource::SetRunMode(run_mode mode)
42352a38012Sejakowatz{
42452a38012Sejakowatz	CALLED();
42552a38012Sejakowatz	BMediaNode::SetRunMode(mode);
4260e21b167Sbeveloper	SendRunMode(mode);
42752a38012Sejakowatz}
42852a38012Sejakowatz/*************************************************************
42952a38012Sejakowatz * private BTimeSource
43052a38012Sejakowatz *************************************************************/
43152a38012Sejakowatz
43252a38012Sejakowatz/*
43352a38012Sejakowatz//unimplemented
43452a38012SejakowatzBTimeSource::BTimeSource(const BTimeSource &clone)
43552a38012SejakowatzBTimeSource &BTimeSource::operator=(const BTimeSource &clone)
43652a38012Sejakowatz*/
43752a38012Sejakowatz
43852a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_0(void *) { return B_ERROR; }
43952a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_1(void *) { return B_ERROR; }
44052a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_2(void *) { return B_ERROR; }
44152a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_3(void *) { return B_ERROR; }
44252a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_4(void *) { return B_ERROR; }
44352a38012Sejakowatzstatus_t BTimeSource::_Reserved_TimeSource_5(void *) { return B_ERROR; }
44452a38012Sejakowatz
44552a38012Sejakowatz/* explicit */
4467f01171fSDario CasalinuovoBTimeSource::BTimeSource(media_node_id id)
4477f01171fSDario Casalinuovo	:
4480e21b167Sbeveloper	BMediaNode("This one is never called"),
449d6379053Sbeveloper	fStarted(false),
4500e21b167Sbeveloper	fArea(-1),
4510e21b167Sbeveloper	fBuf(NULL),
4527fd43270Sbeveloper	fSlaveNodes(NULL),
4530e21b167Sbeveloper	fIsRealtime(false)
45452a38012Sejakowatz{
45552a38012Sejakowatz	CALLED();
45652a38012Sejakowatz	AddNodeKind(B_TIME_SOURCE);
4570e21b167Sbeveloper	ASSERT(id > 0);
4580e21b167Sbeveloper
4597f01171fSDario Casalinuovo	// This constructor is only called by the derived
4607f01171fSDario Casalinuovo	// BPrivate::media::TimeSourceObject objects
4617f01171fSDario Casalinuovo	// We create a clone of the communication area.
4620e21b167Sbeveloper	char name[32];
463332cc6bcSAxel Dörfler	sprintf(name, "__timesource_buf_%" B_PRId32, id);
464faa2d10cSDario Casalinuovo	area_id area = find_area(name);
4650e21b167Sbeveloper	if (area <= 0) {
466332cc6bcSAxel Dörfler		ERROR("BTimeSource::BTimeSource couldn't find area, node %" B_PRId32
467332cc6bcSAxel Dörfler			"\n", id);
4680e21b167Sbeveloper		return;
4690e21b167Sbeveloper	}
470332cc6bcSAxel Dörfler	sprintf(name, "__cloned_timesource_buf_%" B_PRId32, id);
4717f01171fSDario Casalinuovo
4727f01171fSDario Casalinuovo	void** buf = reinterpret_cast<void**>
4737f01171fSDario Casalinuovo		(const_cast<BPrivate::media::TimeSourceTransmit**>(&fBuf));
4747f01171fSDario Casalinuovo
4757f01171fSDario Casalinuovo	fArea = clone_area(name, buf, B_ANY_ADDRESS,
4767f01171fSDario Casalinuovo		B_READ_AREA | B_WRITE_AREA, area);
4777f01171fSDario Casalinuovo
4780e21b167Sbeveloper	if (fArea <= 0) {
479332cc6bcSAxel Dörfler		ERROR("BTimeSource::BTimeSource couldn't clone area, node %" B_PRId32
480332cc6bcSAxel Dörfler			"\n", id);
4810e21b167Sbeveloper		return;
4820e21b167Sbeveloper	}
48352a38012Sejakowatz}
48452a38012Sejakowatz
48552a38012Sejakowatz
48652a38012Sejakowatzvoid
48752a38012SejakowatzBTimeSource::FinishCreate()
48852a38012Sejakowatz{
4890e21b167Sbeveloper	CALLED();
490332cc6bcSAxel Dörfler
4910e21b167Sbeveloper	char name[32];
492332cc6bcSAxel Dörfler	sprintf(name, "__timesource_buf_%" B_PRId32, ID());
4937f01171fSDario Casalinuovo
4947f01171fSDario Casalinuovo	void** buf = reinterpret_cast<void**>
4957f01171fSDario Casalinuovo		(const_cast<BPrivate::media::TimeSourceTransmit**>(&fBuf));
4967f01171fSDario Casalinuovo
4977f01171fSDario Casalinuovo	fArea = create_area(name, buf, B_ANY_ADDRESS, TS_AREA_SIZE,
4987f01171fSDario Casalinuovo		B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
4997f01171fSDario Casalinuovo
5000e21b167Sbeveloper	if (fArea <= 0) {
501332cc6bcSAxel Dörfler		ERROR("BTimeSource::BTimeSource couldn't create area, node %" B_PRId32
502332cc6bcSAxel Dörfler			"\n", ID());
5030e21b167Sbeveloper		fBuf = NULL;
5040e21b167Sbeveloper		return;
5050e21b167Sbeveloper	}
5060e21b167Sbeveloper	fBuf->readindex = 0;
5070e21b167Sbeveloper	fBuf->writeindex = 1;
5080e21b167Sbeveloper	fBuf->realtime[0] = 0;
5090e21b167Sbeveloper	fBuf->perftime[0] = 0;
5100e21b167Sbeveloper	fBuf->drift[0] = 1.0f;
511d6379053Sbeveloper	fBuf->isrunning = fStarted;
51252a38012Sejakowatz}
51352a38012Sejakowatz
51452a38012Sejakowatz
51552a38012Sejakowatzstatus_t
5167f01171fSDario CasalinuovoBTimeSource::RemoveMe(BMediaNode* node)
51752a38012Sejakowatz{
5187fd43270Sbeveloper	CALLED();
5197fd43270Sbeveloper	if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
5207fd43270Sbeveloper		timesource_remove_slave_node_command cmd;
5217fd43270Sbeveloper		cmd.node = node->Node();
5227f01171fSDario Casalinuovo		SendToPort(fControlPort, TIMESOURCE_REMOVE_SLAVE_NODE,
5237f01171fSDario Casalinuovo			&cmd, sizeof(cmd));
5247fd43270Sbeveloper	} else {
5257fd43270Sbeveloper		DirectRemoveMe(node->Node());
5267fd43270Sbeveloper	}
5277fd43270Sbeveloper	return B_OK;
52852a38012Sejakowatz}
52952a38012Sejakowatz
53052a38012Sejakowatz
53152a38012Sejakowatzstatus_t
5327f01171fSDario CasalinuovoBTimeSource::AddMe(BMediaNode* node)
53352a38012Sejakowatz{
5347fd43270Sbeveloper	CALLED();
5357fd43270Sbeveloper	if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
5367fd43270Sbeveloper		timesource_add_slave_node_command cmd;
5377fd43270Sbeveloper		cmd.node = node->Node();
5387fd43270Sbeveloper		SendToPort(fControlPort, TIMESOURCE_ADD_SLAVE_NODE, &cmd, sizeof(cmd));
5397fd43270Sbeveloper	} else {
5407fd43270Sbeveloper		DirectAddMe(node->Node());
5417fd43270Sbeveloper	}
5427fd43270Sbeveloper	return B_OK;
5437fd43270Sbeveloper}
54452a38012Sejakowatz
5457fd43270Sbeveloper
5467fd43270Sbevelopervoid
5477f01171fSDario CasalinuovoBTimeSource::DirectAddMe(const media_node& node)
5487fd43270Sbeveloper{
54923f34657SMarcus Overhagen	CALLED();
55023f34657SMarcus Overhagen	ASSERT(fSlaveNodes != NULL);
551faa2d10cSDario Casalinuovo	BAutolock lock(fSlaveNodes);
5527fd43270Sbeveloper
553faa2d10cSDario Casalinuovo	if (fSlaveNodes->CountSlaves() == MAX_SLAVE_NODES) {
554faa2d10cSDario Casalinuovo		ERROR("BTimeSource::DirectAddMe reached maximum number of slaves\n");
5557fd43270Sbeveloper		return;
5567fd43270Sbeveloper	}
557034e2b7fSStephan Aßmus	if (fNodeID == node.node) {
558034e2b7fSStephan Aßmus		ERROR("BTimeSource::DirectAddMe should not add itself to slave nodes\n");
559034e2b7fSStephan Aßmus		return;
560034e2b7fSStephan Aßmus	}
561faa2d10cSDario Casalinuovo
562faa2d10cSDario Casalinuovo	if (fSlaveNodes->InsertSlave(node) != true) {
563faa2d10cSDario Casalinuovo		ERROR("BTimeSource::DirectAddMe failed\n");
564faa2d10cSDario Casalinuovo		return;
5657fd43270Sbeveloper	}
566faa2d10cSDario Casalinuovo
567faa2d10cSDario Casalinuovo	if (fSlaveNodes->CountSlaves() == 1) {
568faa2d10cSDario Casalinuovo		// start the time source
569faa2d10cSDario Casalinuovo		time_source_op_info msg;
570faa2d10cSDario Casalinuovo		msg.op = B_TIMESOURCE_START;
571faa2d10cSDario Casalinuovo		msg.real_time = RealTime();
572faa2d10cSDario Casalinuovo
573faa2d10cSDario Casalinuovo		TRACE_TIMESOURCE("starting time source %" B_PRId32 "\n", ID());
574faa2d10cSDario Casalinuovo
575faa2d10cSDario Casalinuovo		write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
576faa2d10cSDario Casalinuovo	}
577faa2d10cSDario Casalinuovo }
578faa2d10cSDario Casalinuovo
57952a38012Sejakowatz
5807fd43270Sbevelopervoid
5817f01171fSDario CasalinuovoBTimeSource::DirectRemoveMe(const media_node& node)
5827fd43270Sbeveloper{
5837fd43270Sbeveloper	CALLED();
58423f34657SMarcus Overhagen	ASSERT(fSlaveNodes != NULL);
585faa2d10cSDario Casalinuovo	BAutolock lock(fSlaveNodes);
5867fd43270Sbeveloper
587faa2d10cSDario Casalinuovo	if (fSlaveNodes->CountSlaves() == 0) {
5885ac4fbd7Sbeveloper		ERROR("BTimeSource::DirectRemoveMe no slots used\n");
5897fd43270Sbeveloper		return;
5907fd43270Sbeveloper	}
591faa2d10cSDario Casalinuovo
592faa2d10cSDario Casalinuovo	if (fSlaveNodes->RemoveSlave(node) != true) {
593faa2d10cSDario Casalinuovo		ERROR("BTimeSource::DirectRemoveMe failed\n");
594faa2d10cSDario Casalinuovo		return;
595faa2d10cSDario Casalinuovo	}
596faa2d10cSDario Casalinuovo
597faa2d10cSDario Casalinuovo	if (fSlaveNodes->CountSlaves() == 0) {
598faa2d10cSDario Casalinuovo		// stop the time source
599faa2d10cSDario Casalinuovo		time_source_op_info msg;
600faa2d10cSDario Casalinuovo		msg.op = B_TIMESOURCE_STOP_IMMEDIATELY;
601faa2d10cSDario Casalinuovo		msg.real_time = RealTime();
602faa2d10cSDario Casalinuovo
603faa2d10cSDario Casalinuovo		TRACE_TIMESOURCE("stopping time source %" B_PRId32 "\n", ID());
604faa2d10cSDario Casalinuovo
605faa2d10cSDario Casalinuovo		write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
6067fd43270Sbeveloper	}
6077fd43270Sbeveloper}
60852a38012Sejakowatz
609faa2d10cSDario Casalinuovo
61052a38012Sejakowatzvoid
61152a38012SejakowatzBTimeSource::DirectStart(bigtime_t at)
61252a38012Sejakowatz{
61365799d5bSMarcus Overhagen	CALLED();
614d6379053Sbeveloper	if (fBuf)
615d6379053Sbeveloper		atomic_or(&fBuf->isrunning, 1);
616d6379053Sbeveloper	else
617d6379053Sbeveloper		fStarted = true;
61852a38012Sejakowatz}
61952a38012Sejakowatz
62052a38012Sejakowatz
62152a38012Sejakowatzvoid
6227f01171fSDario CasalinuovoBTimeSource::DirectStop(bigtime_t at, bool immediate)
62352a38012Sejakowatz{
62465799d5bSMarcus Overhagen	CALLED();
625d6379053Sbeveloper	if (fBuf)
626d6379053Sbeveloper		atomic_and(&fBuf->isrunning, 0);
627d6379053Sbeveloper	else
628d6379053Sbeveloper		fStarted = false;
62952a38012Sejakowatz}
63052a38012Sejakowatz
63152a38012Sejakowatz
63252a38012Sejakowatzvoid
6337f01171fSDario CasalinuovoBTimeSource::DirectSeek(bigtime_t to, bigtime_t at)
63452a38012Sejakowatz{
63552a38012Sejakowatz	UNIMPLEMENTED();
63652a38012Sejakowatz}
63752a38012Sejakowatz
63852a38012Sejakowatz
63952a38012Sejakowatzvoid
64052a38012SejakowatzBTimeSource::DirectSetRunMode(run_mode mode)
64152a38012Sejakowatz{
64252a38012Sejakowatz	UNIMPLEMENTED();
64352a38012Sejakowatz}
644