media_server: Improve BTimeSource slave nodes management
The media_server is now able to remember the timesource associated to a certain registered_node and always remove it when the owner application crash, Fixes Ticket #11852
This commit is contained in:
@@ -79,6 +79,7 @@ enum {
|
|||||||
SERVER_REGISTER_DORMANT_NODE,
|
SERVER_REGISTER_DORMANT_NODE,
|
||||||
SERVER_GET_DORMANT_NODES,
|
SERVER_GET_DORMANT_NODES,
|
||||||
SERVER_GET_DORMANT_FLAVOR_INFO,
|
SERVER_GET_DORMANT_FLAVOR_INFO,
|
||||||
|
SERVER_SET_NODE_TIMESOURCE,
|
||||||
SERVER_MESSAGE_END,
|
SERVER_MESSAGE_END,
|
||||||
|
|
||||||
NODE_MESSAGE_START = 0x200,
|
NODE_MESSAGE_START = 0x200,
|
||||||
@@ -390,6 +391,7 @@ struct server_change_flavor_instances_count_reply : reply_data {
|
|||||||
struct server_register_node_request : request_data {
|
struct server_register_node_request : request_data {
|
||||||
media_addon_id add_on_id;
|
media_addon_id add_on_id;
|
||||||
int32 flavor_id;
|
int32 flavor_id;
|
||||||
|
media_node_id timesource_id;
|
||||||
char name[B_MEDIA_NAME_LENGTH];
|
char name[B_MEDIA_NAME_LENGTH];
|
||||||
uint64 kinds;
|
uint64 kinds;
|
||||||
port_id port;
|
port_id port;
|
||||||
@@ -634,6 +636,14 @@ struct server_register_dormant_node_command : command_data {
|
|||||||
// a flattened dormant_flavor_info, flattened_size large
|
// a flattened dormant_flavor_info, flattened_size large
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct server_set_node_timesource_request : request_data {
|
||||||
|
media_node_id node_id;
|
||||||
|
media_node_id timesource_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct server_set_node_timesource_reply : reply_data {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - buffer producer commands
|
// #pragma mark - buffer producer commands
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Maurice Kalinowski, [email protected]
|
* Copyright 2015 Dario Casalinuovo
|
||||||
* Copyright 2009-2012, Axel Dörfler, [email protected].
|
* Copyright 2009-2012, Axel Dörfler, [email protected].
|
||||||
|
* Copyright 2008 Maurice Kalinowski, [email protected]
|
||||||
*
|
*
|
||||||
* All rights reserved. Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -1972,6 +1973,7 @@ BMediaRosterEx::RegisterNode(BMediaNode* node, media_addon_id addOnID,
|
|||||||
request.kinds = node->Kinds();
|
request.kinds = node->Kinds();
|
||||||
request.port = node->ControlPort();
|
request.port = node->ControlPort();
|
||||||
request.team = BPrivate::current_team();
|
request.team = BPrivate::current_team();
|
||||||
|
request.timesource_id = node->fTimeSourceID;
|
||||||
|
|
||||||
TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port "
|
TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port "
|
||||||
"%" B_PRId32 ", kinds 0x%" B_PRIx64 ", team %" B_PRId32 ", name '%s'\n",
|
"%" B_PRId32 ", kinds 0x%" B_PRIx64 ", team %" B_PRId32 ", name '%s'\n",
|
||||||
@@ -2176,44 +2178,51 @@ BMediaRoster::SetTimeSourceFor(media_node_id node, media_node_id time_source)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
media_node clone;
|
media_node clone;
|
||||||
status_t rv, result;
|
// We need to get a clone of the node to have a port id
|
||||||
|
status_t result = GetNodeFor(node, &clone);
|
||||||
TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " will be assigned "
|
if (result == B_OK) {
|
||||||
"time source %" B_PRId32 "\n", node, time_source);
|
// We just send the request to set time_source-id as
|
||||||
TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %"
|
// timesource to the node, the NODE_SET_TIMESOURCE handler
|
||||||
B_PRId32 " enter\n", node, time_source);
|
// code will do the real assignment.
|
||||||
|
result = B_OK;
|
||||||
// we need to get a clone of the node to have a port id
|
node_set_timesource_command cmd;
|
||||||
rv = GetNodeFor(node, &clone);
|
cmd.timesource_id = time_source;
|
||||||
if (rv != B_OK) {
|
result = SendToPort(clone.port, NODE_SET_TIMESOURCE,
|
||||||
ERROR("BMediaRoster::SetTimeSourceFor, GetNodeFor failed, node id %"
|
&cmd, sizeof(cmd));
|
||||||
B_PRId32 "\n", node);
|
if (result != B_OK) {
|
||||||
return B_ERROR;
|
ERROR("BMediaRoster::SetTimeSourceFor"
|
||||||
|
"sending NODE_SET_TIMESOURCE failed, node id %"
|
||||||
|
B_PRId32 "\n", clone.node);
|
||||||
|
}
|
||||||
|
// We release the clone
|
||||||
|
result = ReleaseNode(clone);
|
||||||
|
if (result != B_OK) {
|
||||||
|
ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed,"
|
||||||
|
" node id %" B_PRId32 "\n", clone.node);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ERROR("BMediaRoster::SetTimeSourceFor GetCloneForID failed, "
|
||||||
|
"node id %" B_PRId32 "\n", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we just send the request to set time_source-id as timesource to the node,
|
if (result == B_OK) {
|
||||||
// the NODE_SET_TIMESOURCE handler code will do the real assignment
|
// Notify the server
|
||||||
result = B_OK;
|
server_set_node_timesource_request request;
|
||||||
node_set_timesource_command cmd;
|
server_set_node_timesource_reply reply;
|
||||||
cmd.timesource_id = time_source;
|
|
||||||
rv = SendToPort(clone.port, NODE_SET_TIMESOURCE, &cmd, sizeof(cmd));
|
request.node_id = node;
|
||||||
if (rv != B_OK) {
|
request.timesource_id = time_source;
|
||||||
ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE "
|
|
||||||
"failed, node id %" B_PRId32 "\n", node);
|
result = QueryServer(SERVER_SET_NODE_TIMESOURCE, &request,
|
||||||
result = B_ERROR;
|
sizeof(request), &reply, sizeof(reply));
|
||||||
|
if (result != B_OK) {
|
||||||
|
ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE "
|
||||||
|
"failed, node id %" B_PRId32 "\n", node);
|
||||||
|
} else {
|
||||||
|
TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %"
|
||||||
|
B_PRId32 " OK\n", node, time_source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we release the clone
|
|
||||||
rv = ReleaseNode(clone);
|
|
||||||
if (rv != B_OK) {
|
|
||||||
ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed, node id %"
|
|
||||||
B_PRId32 "\n", node);
|
|
||||||
result = B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %"
|
|
||||||
B_PRId32 " leave\n", node, time_source);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -545,9 +545,6 @@ BTimeSource::AddMe(BMediaNode* node)
|
|||||||
void
|
void
|
||||||
BTimeSource::DirectAddMe(const media_node& node)
|
BTimeSource::DirectAddMe(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();
|
CALLED();
|
||||||
ASSERT(fSlaveNodes != NULL);
|
ASSERT(fSlaveNodes != NULL);
|
||||||
BAutolock lock(fSlaveNodes);
|
BAutolock lock(fSlaveNodes);
|
||||||
@@ -582,9 +579,6 @@ BTimeSource::DirectAddMe(const media_node& node)
|
|||||||
void
|
void
|
||||||
BTimeSource::DirectRemoveMe(const media_node& node)
|
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();
|
CALLED();
|
||||||
ASSERT(fSlaveNodes != NULL);
|
ASSERT(fSlaveNodes != NULL);
|
||||||
BAutolock lock(fSlaveNodes);
|
BAutolock lock(fSlaveNodes);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2015 Dario Casalinuovo
|
||||||
* Copyright (c) 2002, 2003 Marcus Overhagen <[email protected]>
|
* Copyright (c) 2002, 2003 Marcus Overhagen <[email protected]>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
|
|
||||||
#include "NodeManager.h"
|
#include "NodeManager.h"
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <MediaAddOn.h>
|
#include <MediaAddOn.h>
|
||||||
@@ -144,12 +146,13 @@ NodeManager::RescanDefaultNodes()
|
|||||||
status_t
|
status_t
|
||||||
NodeManager::RegisterNode(media_addon_id addOnID, int32 flavorID,
|
NodeManager::RegisterNode(media_addon_id addOnID, int32 flavorID,
|
||||||
const char* name, uint64 kinds, port_id port, team_id team,
|
const char* name, uint64 kinds, port_id port, team_id team,
|
||||||
media_node_id* _nodeID)
|
media_node_id timesource, media_node_id* _nodeID)
|
||||||
{
|
{
|
||||||
BAutolock _(this);
|
BAutolock _(this);
|
||||||
|
|
||||||
registered_node node;
|
registered_node node;
|
||||||
node.node_id = fNextNodeID;
|
node.node_id = fNextNodeID;
|
||||||
|
node.timesource_id = timesource;
|
||||||
node.add_on_id = addOnID;
|
node.add_on_id = addOnID;
|
||||||
node.flavor_id = flavorID;
|
node.flavor_id = flavorID;
|
||||||
strlcpy(node.name, name, sizeof(node.name));
|
strlcpy(node.name, name, sizeof(node.name));
|
||||||
@@ -1092,6 +1095,24 @@ NodeManager::GetDormantFlavorInfoFor(media_addon_id addOnID, int32 flavorID,
|
|||||||
// #pragma mark - Misc.
|
// #pragma mark - Misc.
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NodeManager::SetNodeTimeSource(media_node_id node,
|
||||||
|
media_node_id timesource)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
NodeMap::iterator found = fNodeMap.find(node);
|
||||||
|
if (found == fNodeMap.end()) {
|
||||||
|
ERROR("NodeManager::SetNodeTimeSource: node %"
|
||||||
|
B_PRId32 " not found\n", node);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
registered_node& registeredNode = found->second;
|
||||||
|
registeredNode.timesource_id = timesource;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
NodeManager::CleanupTeam(team_id team)
|
NodeManager::CleanupTeam(team_id team)
|
||||||
{
|
{
|
||||||
@@ -1120,6 +1141,8 @@ NodeManager::CleanupTeam(team_id team)
|
|||||||
if (node.containing_team == team) {
|
if (node.containing_team == team) {
|
||||||
PRINT(1, "NodeManager::CleanupTeam: removing node id %" B_PRId32
|
PRINT(1, "NodeManager::CleanupTeam: removing node id %" B_PRId32
|
||||||
", team %" B_PRId32 "\n", node.node_id, team);
|
", team %" B_PRId32 "\n", node.node_id, team);
|
||||||
|
// Ensure the slave node is removed from it's timesource
|
||||||
|
_NotifyTimeSource(node);
|
||||||
fNodeMap.erase(remove);
|
fNodeMap.erase(remove);
|
||||||
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
||||||
continue;
|
continue;
|
||||||
@@ -1137,6 +1160,8 @@ NodeManager::CleanupTeam(team_id team)
|
|||||||
PRINT(1, "NodeManager::CleanupTeam: removing node id %"
|
PRINT(1, "NodeManager::CleanupTeam: removing node id %"
|
||||||
B_PRId32 " that has no teams\n", node.node_id);
|
B_PRId32 " that has no teams\n", node.node_id);
|
||||||
|
|
||||||
|
// Ensure the slave node is removed from it's timesource
|
||||||
|
_NotifyTimeSource(node);
|
||||||
fNodeMap.erase(remove);
|
fNodeMap.erase(remove);
|
||||||
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
||||||
} else
|
} else
|
||||||
@@ -1340,3 +1365,26 @@ NodeManager::_AcquireNodeReference(media_node_id id, team_id team)
|
|||||||
node.ref_count, node.team_ref_count.find(team)->second);
|
node.ref_count, node.team_ref_count.find(team)->second);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NodeManager::_NotifyTimeSource(registered_node& node)
|
||||||
|
{
|
||||||
|
team_id team = be_app->Team();
|
||||||
|
media_node timeSource;
|
||||||
|
// Ensure the timesource ensure still exists
|
||||||
|
if (GetCloneForID(node.timesource_id, team, &timeSource) != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
media_node currentNode;
|
||||||
|
if (GetCloneForID(node.node_id, team,
|
||||||
|
¤tNode) == B_OK) {
|
||||||
|
timesource_remove_slave_node_command cmd;
|
||||||
|
cmd.node = currentNode;
|
||||||
|
// Notify slave node removal to owner timesource
|
||||||
|
SendToPort(timeSource.port, TIMESOURCE_REMOVE_SLAVE_NODE,
|
||||||
|
&cmd, sizeof(cmd));
|
||||||
|
ReleaseNode(timeSource, team);
|
||||||
|
}
|
||||||
|
ReleaseNode(currentNode, team);
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ typedef std::vector<live_node_info> LiveNodeList;
|
|||||||
|
|
||||||
struct registered_node {
|
struct registered_node {
|
||||||
media_node_id node_id;
|
media_node_id node_id;
|
||||||
|
media_node_id timesource_id;
|
||||||
media_addon_id add_on_id;
|
media_addon_id add_on_id;
|
||||||
int32 flavor_id;
|
int32 flavor_id;
|
||||||
char name[B_MEDIA_NAME_LENGTH];
|
char name[B_MEDIA_NAME_LENGTH];
|
||||||
@@ -73,6 +74,7 @@ public:
|
|||||||
status_t RegisterNode(media_addon_id addOnID,
|
status_t RegisterNode(media_addon_id addOnID,
|
||||||
int32 flavorID, const char* name,
|
int32 flavorID, const char* name,
|
||||||
uint64 kinds, port_id port, team_id team,
|
uint64 kinds, port_id port, team_id team,
|
||||||
|
media_node_id timesource,
|
||||||
media_node_id* _nodeID);
|
media_node_id* _nodeID);
|
||||||
status_t UnregisterNode(media_node_id nodeID,
|
status_t UnregisterNode(media_node_id nodeID,
|
||||||
team_id team, media_addon_id* addOnID,
|
team_id team, media_addon_id* addOnID,
|
||||||
@@ -141,6 +143,9 @@ public:
|
|||||||
int32 flavorID,
|
int32 flavorID,
|
||||||
dormant_flavor_info* flavorInfo);
|
dormant_flavor_info* flavorInfo);
|
||||||
|
|
||||||
|
status_t SetNodeTimeSource(media_node_id node,
|
||||||
|
media_node_id timesource);
|
||||||
|
|
||||||
void CleanupTeam(team_id team);
|
void CleanupTeam(team_id team);
|
||||||
|
|
||||||
status_t LoadState();
|
status_t LoadState();
|
||||||
@@ -151,6 +156,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
status_t _AcquireNodeReference(media_node_id id,
|
status_t _AcquireNodeReference(media_node_id id,
|
||||||
team_id team);
|
team_id team);
|
||||||
|
void _NotifyTimeSource(registered_node& node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<media_addon_id, registered_node> NodeMap;
|
typedef std::map<media_addon_id, registered_node> NodeMap;
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ ServerApp::_HandleMessage(int32 code, const void* data, size_t size)
|
|||||||
|
|
||||||
status_t status = gNodeManager->RegisterNode(request.add_on_id,
|
status_t status = gNodeManager->RegisterNode(request.add_on_id,
|
||||||
request.flavor_id, request.name, request.kinds, request.port,
|
request.flavor_id, request.name, request.kinds, request.port,
|
||||||
request.team, &reply.node_id);
|
request.team, request.timesource_id, &reply.node_id);
|
||||||
request.SendReply(status, &reply, sizeof(reply));
|
request.SendReply(status, &reply, sizeof(reply));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -580,6 +580,17 @@ ServerApp::_HandleMessage(int32 code, const void* data, size_t size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SERVER_SET_NODE_TIMESOURCE:
|
||||||
|
{
|
||||||
|
const server_set_node_timesource_request& request
|
||||||
|
= *static_cast<const server_set_node_timesource_request*>(data);
|
||||||
|
server_set_node_timesource_reply reply;
|
||||||
|
status_t result = gNodeManager->SetNodeTimeSource(request.node_id,
|
||||||
|
request.timesource_id);
|
||||||
|
request.SendReply(result, &reply, sizeof(reply));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SERVER_REGISTER_ADD_ON:
|
case SERVER_REGISTER_ADD_ON:
|
||||||
{
|
{
|
||||||
const server_register_add_on_request& request = *static_cast<
|
const server_register_add_on_request& request = *static_cast<
|
||||||
|
|||||||
Reference in New Issue
Block a user