From 7fd432700b5fd02a23af42ee36d1bc780e8bf702 Mon Sep 17 00:00:00 2001 From: beveloper Date: Mon, 20 Jan 2003 01:11:15 +0000 Subject: [PATCH] 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 --- headers/os/media/TimeSource.h | 7 +- headers/private/media/DataExchange.h | 15 ++- src/kits/media/MediaNode.cpp | 13 ++- src/kits/media/TimeSource.cpp | 155 +++++++++++++++++++++++++-- 4 files changed, 171 insertions(+), 19 deletions(-) diff --git a/headers/os/media/TimeSource.h b/headers/os/media/TimeSource.h index aa737d62a4..a2f0eb5157 100644 --- a/headers/os/media/TimeSource.h +++ b/headers/os/media/TimeSource.h @@ -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); }; diff --git a/headers/private/media/DataExchange.h b/headers/private/media/DataExchange.h index 2ab215a5f8..1a0a498380 100644 --- a/headers/private/media/DataExchange.h +++ b/headers/private/media/DataExchange.h @@ -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 diff --git a/src/kits/media/MediaNode.cpp b/src/kits/media/MediaNode.cpp index b968d5b638..bc9239f1a5 100644 --- a/src/kits/media/MediaNode.cpp +++ b/src/kits/media/MediaNode.cpp @@ -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(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, diff --git a/src/kits/media/TimeSource.cpp b/src/kits/media/TimeSource.cpp index f95616fe0e..025568dd90 100644 --- a/src/kits/media/TimeSource.cpp +++ b/src/kits/media/TimeSource.cpp @@ -4,9 +4,12 @@ * DESCR: ***********************************************************************/ #include +#include +#include #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(rawdata); + DirectAddMe(data->node); + return B_OK; + } + + case TIMESOURCE_REMOVE_SLAVE_NODE: + { + const timesource_remove_slave_node_command *data = static_cast(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) {