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) {