Updated time source code to allow automatic starting and stopping of time sources.

Sending run mode changes and broadcasting of time changes is also implemented.
For one reason or another, all this doesn't work right now.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2520 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2003-01-20 01:11:15 +00:00
parent ffa7234e82
commit 7fd432700b
4 changed files with 171 additions and 19 deletions

View File

@ -22,6 +22,7 @@ namespace BPrivate { namespace media {
class TimeSourceObject;
class SystemTimeSourceObject;
struct TimeSourceTransmit;
struct SlaveNodes;
} }
@ -124,9 +125,9 @@ virtual status_t _Reserved_TimeSource_5(void *);
bool fStarted;
area_id fArea;
volatile BPrivate::media::TimeSourceTransmit *fBuf;
_BSlaveNodeStorageP * _mSlaveNodes;
BPrivate::media::SlaveNodes *fSlaveNodes;
area_id _mOrigArea;
area_id _reserved_area;
bool fIsRealtime;
bool _reserved_bool_[3];
uint32 _reserved_time_source_[10];
@ -142,6 +143,8 @@ virtual status_t AddMe(BMediaNode * node);
void DirectStop(bigtime_t at, bool immediate);
void DirectSeek(bigtime_t to, bigtime_t at);
void DirectSetRunMode(run_mode mode);
void DirectAddMe(const media_node &node);
void DirectRemoveMe(const media_node &node);
};

View File

@ -149,11 +149,13 @@ enum {
FILEINTERFACE_MESSAGE_END,
CONTROLLABLE_MESSAGE_START = 0x600,
CONTROLLABLE_MESSAGE_END,
TIMESOURECE_MESSAGE_START = 0x700,
TIMESOURCE_MESSAGE_START = 0x700,
TIMESOURCE_OP, // datablock is a struct time_source_op_info
TIMESOURCE_ADD_SLAVE_NODE,
TIMESOURCE_REMOVE_SLAVE_NODE,
TIMESOURECE_MESSAGE_END,
TIMESOURCE_MESSAGE_END,
};
@ -875,7 +877,14 @@ struct node_set_timesource_command : public command_data
media_node_id timesource_id;
};
struct timesource_add_slave_node_command : public command_data
{
media_node node;
};
struct timesource_remove_slave_node_command : public command_data
{
media_node node;
};
#endif // _DATA_EXCHANGE_H

View File

@ -103,6 +103,12 @@ BMediaNode::~BMediaNode()
// BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before
// BeBook: you delete your node instance, depending on your implementation and circumstances.
// first we remove the time source
if (fTimeSource) {
fTimeSource->RemoveMe(this);
fTimeSource->Release();
}
// Attention! We do not unregister TimeSourceObject nodes,
// or delete their control ports, since they are only a
// shadow object, and the real one still exists
@ -112,9 +118,6 @@ BMediaNode::~BMediaNode()
if (fControlPort > 0)
delete_port(fControlPort);
}
if (fTimeSource)
fTimeSource->Release();
}
/*************************************************************
@ -362,7 +365,7 @@ BMediaNode::WaitForMessage(bigtime_t waitUntil,
return B_OK;
}
if (message > TIMESOURECE_MESSAGE_START && message < TIMESOURECE_MESSAGE_END) {
if (message > TIMESOURCE_MESSAGE_START && message < TIMESOURCE_MESSAGE_END) {
if (!fTimeSourceThis)
fTimeSourceThis = dynamic_cast<BTimeSource *>(this);
INFO("BMediaNode::WaitForMessage calling BTimeSource %p\n", fTimeSourceThis);
@ -599,7 +602,7 @@ BMediaNode::HandleBadMessage(int32 code,
CALLED();
TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size);
if (code < NODE_MESSAGE_START || code > TIMESOURECE_MESSAGE_END) {
if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) {
FATAL("BMediaNode::HandleBadMessage: unknown code!\n");
} else {
/* All messages targeted to nodes should be handled here,

View File

@ -4,9 +4,12 @@
* DESCR:
***********************************************************************/
#include <TimeSource.h>
#include <Autolock.h>
#include <string.h>
#include "debug.h"
#include "DataExchange.h"
#include "ServerInterface.h"
#include "TimeSourceObject.h"
namespace BPrivate { namespace media {
@ -21,6 +24,15 @@ struct TimeSourceTransmit // sizeof() must be <= 4096
float drift[INDEX_COUNT];
};
struct SlaveNodes
{
#define SLAVE_NODES_COUNT 300
BLocker locker;
int32 count;
media_node_id node_id[SLAVE_NODES_COUNT];
port_id node_port[SLAVE_NODES_COUNT];
};
} }
@ -33,6 +45,8 @@ BTimeSource::~BTimeSource()
CALLED();
if (fArea > 0)
delete_area(fArea);
if (fSlaveNodes)
free(fSlaveNodes);
}
/*************************************************************
@ -173,12 +187,23 @@ BTimeSource::BTimeSource() :
fStarted(false),
fArea(-1),
fBuf(NULL),
fSlaveNodes((BPrivate::media::SlaveNodes*)malloc(sizeof(BPrivate::media::SlaveNodes))),
fIsRealtime(false)
{
CALLED();
AddNodeKind(B_TIME_SOURCE);
// printf("##### BTimeSource::BTimeSource() name %s, id %ld\n", Name(), ID());
if (fSlaveNodes == NULL) {
FATAL("Error: BTimeSource::BTimeSource() fSlaveNodes == NULL\n");
return;
}
// initialize the slave node storage
fSlaveNodes->count = 0;
memset(&fSlaveNodes->node_id, 0, SLAVE_NODES_COUNT * sizeof(media_node_id));
memset(&fSlaveNodes->node_port, 0, SLAVE_NODES_COUNT * sizeof(port_id));
// This constructor is only called by real time sources that inherit
// BTimeSource. We create the communication area in FinishCreate(),
// since we don't have a correct ID() until this node is registered.
@ -217,6 +242,20 @@ BTimeSource::HandleMessage(int32 message,
}
return B_OK;
}
case TIMESOURCE_ADD_SLAVE_NODE:
{
const timesource_add_slave_node_command *data = static_cast<const timesource_add_slave_node_command *>(rawdata);
DirectAddMe(data->node);
return B_OK;
}
case TIMESOURCE_REMOVE_SLAVE_NODE:
{
const timesource_remove_slave_node_command *data = static_cast<const timesource_remove_slave_node_command *>(rawdata);
DirectRemoveMe(data->node);
return B_OK;
}
}
return B_ERROR;
}
@ -247,16 +286,39 @@ void
BTimeSource::BroadcastTimeWarp(bigtime_t at_real_time,
bigtime_t new_performance_time)
{
UNIMPLEMENTED();
// call BMediaNode::TimeWarp() of all slaved nodes
CALLED();
// calls BMediaNode::TimeWarp() of all slaved nodes
BAutolock lock(fSlaveNodes->locker);
for (int i = 0, n = 0; i < SLAVE_NODES_COUNT && n != fSlaveNodes->count; i++) {
if (fSlaveNodes->node_id[i] != 0) {
node_time_warp_command cmd;
cmd.at_real_time = at_real_time;
cmd.to_performance_time = new_performance_time;
SendToPort(fSlaveNodes->node_port[i], NODE_TIME_WARP, &cmd, sizeof(cmd));
n++;
}
}
}
void
BTimeSource::SendRunMode(run_mode mode)
{
UNIMPLEMENTED();
CALLED();
// send the run mode change to all slaved nodes
BAutolock lock(fSlaveNodes->locker);
for (int i = 0, n = 0; i < SLAVE_NODES_COUNT && n != fSlaveNodes->count; i++) {
if (fSlaveNodes->node_id[i] != 0) {
node_set_run_mode_command cmd;
cmd.mode = mode;
SendToPort(fSlaveNodes->node_port[i], NODE_SET_RUN_MODE, &cmd, sizeof(cmd));
n++;
}
}
}
@ -290,6 +352,7 @@ BTimeSource::BTimeSource(media_node_id id) :
fStarted(false),
fArea(-1),
fBuf(NULL),
fSlaveNodes(NULL),
fIsRealtime(false)
{
CALLED();
@ -342,21 +405,95 @@ BTimeSource::FinishCreate()
status_t
BTimeSource::RemoveMe(BMediaNode *node)
{
UNIMPLEMENTED();
return B_ERROR;
CALLED();
if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
timesource_remove_slave_node_command cmd;
cmd.node = node->Node();
SendToPort(fControlPort, TIMESOURCE_REMOVE_SLAVE_NODE, &cmd, sizeof(cmd));
} else {
DirectRemoveMe(node->Node());
}
return B_OK;
}
status_t
BTimeSource::AddMe(BMediaNode *node)
{
UNIMPLEMENTED();
return B_ERROR;
CALLED();
if (fKinds & NODE_KIND_SHADOW_TIMESOURCE) {
timesource_add_slave_node_command cmd;
cmd.node = node->Node();
SendToPort(fControlPort, TIMESOURCE_ADD_SLAVE_NODE, &cmd, sizeof(cmd));
} else {
DirectAddMe(node->Node());
}
return B_OK;
}
void
BTimeSource::DirectAddMe(const media_node &node)
{
CALLED();
// XXX this code has race conditions and is pretty dumb, and it
// XXX won't detect nodes that crash and don't remove themself.
BAutolock lock(fSlaveNodes->locker);
if (fSlaveNodes->count == SLAVE_NODES_COUNT) {
FATAL("BTimeSource::DirectAddMe out of slave node slots\n");
return;
}
for (int i = 0; i < SLAVE_NODES_COUNT; i++) {
if (fSlaveNodes->node_id[i] == 0) {
fSlaveNodes->node_id[i] = node.node;
fSlaveNodes->node_port[i] = node.port;
fSlaveNodes->count += 1;
if (fSlaveNodes->count == 1) {
// start the time source
time_source_op_info msg;
msg.op = B_TIMESOURCE_START;
msg.real_time = RealTime();
printf("starting time source\n");
write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
}
return;
}
}
FATAL("BTimeSource::DirectAddMe failed\n");
}
void
BTimeSource::DirectRemoveMe(const media_node &node)
{
// XXX this code has race conditions and is pretty dumb, and it
// XXX won't detect nodes that crash and don't remove themself.
CALLED();
BAutolock lock(fSlaveNodes->locker);
if (fSlaveNodes->count == 0) {
FATAL("BTimeSource::DirectRemoveMe no slots used\n");
return;
}
for (int i = 0; i < SLAVE_NODES_COUNT; i++) {
if (fSlaveNodes->node_id[i] == node.node && fSlaveNodes->node_port[i] == node.port) {
fSlaveNodes->node_id[i] = 0;
fSlaveNodes->node_port[i] = 0;
fSlaveNodes->count -= 1;
if (fSlaveNodes->count == 0) {
// stop the time source
time_source_op_info msg;
msg.op = B_TIMESOURCE_STOP_IMMEDIATELY;
msg.real_time = RealTime();
printf("stopping time source\n");
write_port(fControlPort, TIMESOURCE_OP, &msg, sizeof(msg));
}
return;
}
}
FATAL("BTimeSource::DirectRemoveMe failed\n");
}
void
BTimeSource::DirectStart(bigtime_t at)
{