1409 lines
38 KiB
C++
1409 lines
38 KiB
C++
/*
|
|
* Copyright (c) 2015 Dario Casalinuovo
|
|
* Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files or portions
|
|
* thereof (the "Software"), to deal in the Software without restriction,
|
|
* including without limitation the rights to use, copy, modify, merge,
|
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
* and to permit persons to whom the Software is furnished to do so, subject
|
|
* to the following conditions:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright notice
|
|
* in the binary, as well as this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided with
|
|
* the distribution.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "NodeManager.h"
|
|
|
|
#include <Application.h>
|
|
#include <Autolock.h>
|
|
#include <Entry.h>
|
|
#include <MediaAddOn.h>
|
|
#include <MediaDefs.h>
|
|
#include <Message.h>
|
|
#include <Messenger.h>
|
|
#include <OS.h>
|
|
#include <Path.h>
|
|
|
|
#include <MediaDebug.h>
|
|
#include <MediaMisc.h>
|
|
#include <Notifications.h>
|
|
|
|
#include "AppManager.h"
|
|
#include "DefaultManager.h"
|
|
#include "media_server.h"
|
|
|
|
|
|
const char*
|
|
get_node_type(node_type type)
|
|
{
|
|
#define CASE(c) case c: return #c;
|
|
switch (type) {
|
|
CASE(VIDEO_INPUT)
|
|
CASE(AUDIO_INPUT)
|
|
CASE(VIDEO_OUTPUT)
|
|
CASE(AUDIO_MIXER)
|
|
CASE(AUDIO_OUTPUT)
|
|
CASE(AUDIO_OUTPUT_EX)
|
|
CASE(TIME_SOURCE)
|
|
CASE(SYSTEM_TIME_SOURCE)
|
|
|
|
default:
|
|
return "unknown";
|
|
}
|
|
#undef CASE
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
NodeManager::NodeManager()
|
|
:
|
|
BLocker("node manager"),
|
|
fNextAddOnID(1),
|
|
fNextNodeID(1),
|
|
fDefaultManager(new DefaultManager)
|
|
{
|
|
}
|
|
|
|
|
|
NodeManager::~NodeManager()
|
|
{
|
|
delete fDefaultManager;
|
|
}
|
|
|
|
|
|
// #pragma mark - Default node management
|
|
|
|
|
|
status_t
|
|
NodeManager::SetDefaultNode(node_type type, const media_node* node,
|
|
const dormant_node_info* info, const media_input* input)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
status_t status = B_BAD_VALUE;
|
|
if (node != NULL)
|
|
status = fDefaultManager->Set(node->node, NULL, 0, type);
|
|
else if (input != NULL) {
|
|
status = fDefaultManager->Set(input->node.node, input->name,
|
|
input->destination.id, type);
|
|
} else if (info != NULL) {
|
|
media_node_id nodeID;
|
|
int32 count = 1;
|
|
status = GetInstances(info->addon, info->flavor_id, &nodeID, &count,
|
|
count);
|
|
if (status == B_OK)
|
|
status = fDefaultManager->Set(nodeID, NULL, 0, type);
|
|
}
|
|
|
|
if (status == B_OK && (type == VIDEO_INPUT || type == VIDEO_OUTPUT
|
|
|| type == AUDIO_OUTPUT || type == AUDIO_INPUT)) {
|
|
fDefaultManager->SaveState(this);
|
|
Dump();
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetDefaultNode(node_type type, media_node_id* _nodeID,
|
|
char* inputName, int32* _inputID)
|
|
{
|
|
BAutolock _(this);
|
|
return fDefaultManager->Get(_nodeID, inputName, _inputID, type);
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::RescanDefaultNodes()
|
|
{
|
|
BAutolock _(this);
|
|
return fDefaultManager->Rescan();
|
|
}
|
|
|
|
|
|
// #pragma mark - Live node management
|
|
|
|
|
|
status_t
|
|
NodeManager::RegisterNode(media_addon_id addOnID, int32 flavorID,
|
|
const char* name, uint64 kinds, port_id port, team_id team,
|
|
media_node_id timesource, media_node_id* _nodeID)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
registered_node node;
|
|
node.timesource_id = timesource;
|
|
node.add_on_id = addOnID;
|
|
node.flavor_id = flavorID;
|
|
strlcpy(node.name, name, sizeof(node.name));
|
|
node.kinds = kinds;
|
|
node.port = port;
|
|
node.containing_team = team;
|
|
node.creator = -1; // will be set later
|
|
node.ref_count = 1;
|
|
|
|
if ((node.kinds & B_TIME_SOURCE) != 0
|
|
&& strcmp(node.name, "System clock") == 0) {
|
|
// This may happen when media_addon_server crash,
|
|
// we will replace the old timesource.
|
|
node.node_id = NODE_SYSTEM_TIMESOURCE_ID;
|
|
|
|
NodeMap::iterator found = fNodeMap.find(node.node_id);
|
|
if (found != fNodeMap.end())
|
|
fNodeMap.erase(node.node_id);
|
|
|
|
*_nodeID = node.node_id;
|
|
} else {
|
|
node.node_id = fNextNodeID;
|
|
*_nodeID = node.node_id;
|
|
}
|
|
|
|
try {
|
|
node.team_ref_count.insert(std::make_pair(team, 1));
|
|
fNodeMap.insert(std::make_pair(node.node_id, node));
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
fNextNodeID++;
|
|
|
|
TRACE("NodeManager::RegisterNode: node %" B_PRId32 ", addon_id %" B_PRId32
|
|
", flavor_id %" B_PRId32 ", name \"%s\", kinds %#" B_PRIx64", port %"
|
|
B_PRId32 ", team %" B_PRId32 "\n", *_nodeID, addOnID, flavorID, name,
|
|
kinds, port, team);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::UnregisterNode(media_node_id id, team_id team,
|
|
media_addon_id* _addOnID, int32* _flavorID)
|
|
{
|
|
TRACE("NodeManager::UnregisterNode enter: node %" B_PRId32 ", team %"
|
|
B_PRId32 "\n", id, team);
|
|
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::UnregisterNode: couldn't find node %" B_PRId32
|
|
" (team %" B_PRId32 ")\n", id, team);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& node = found->second;
|
|
|
|
if (node.containing_team != team) {
|
|
ERROR("NodeManager::UnregisterNode: team %" B_PRId32 " tried to "
|
|
"unregister node %" B_PRId32 ", but it was instantiated by team %"
|
|
B_PRId32 "\n", team, id, node.containing_team);
|
|
return B_ERROR;
|
|
}
|
|
if (node.ref_count != 1) {
|
|
ERROR("NodeManager::UnregisterNode: node %" B_PRId32 ", team %"
|
|
B_PRId32 " has ref count %" B_PRId32 " (should be 1)\n", id, team,
|
|
node.ref_count);
|
|
//return B_ERROR;
|
|
}
|
|
|
|
if (_addOnID != NULL)
|
|
*_addOnID = node.add_on_id;
|
|
|
|
if (_flavorID != NULL)
|
|
*_flavorID = node.flavor_id;
|
|
|
|
fNodeMap.erase(found);
|
|
|
|
TRACE("NodeManager::UnregisterNode leave: node %" B_PRId32 ", addon_id %"
|
|
B_PRId32 ", flavor_id %" B_PRId32 " team %" B_PRId32 "\n", id,
|
|
*_addOnID, *_flavorID, team);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::ReleaseNodeReference(media_node_id id, team_id team)
|
|
{
|
|
TRACE("NodeManager::ReleaseNodeReference enter: node %" B_PRId32 ", team %"
|
|
B_PRId32 "\n", id, team);
|
|
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " not "
|
|
"found\n", id);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& node = found->second;
|
|
|
|
TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
|
|
if (teamRef == node.team_ref_count.end()) {
|
|
// Normally it is an error to release a node in another team. But we
|
|
// make one exception: if the node is global, and the creator team
|
|
// tries to release it, we will release it in the the
|
|
// media_addon_server.
|
|
team_id addOnServer = gAppManager->AddOnServerTeam();
|
|
teamRef = node.team_ref_count.find(addOnServer);
|
|
|
|
if (node.creator == team && teamRef != node.team_ref_count.end()) {
|
|
PRINT(1, "!!! NodeManager::ReleaseNodeReference doing global "
|
|
"release!\n");
|
|
node.creator = -1; // invalidate!
|
|
team = addOnServer;
|
|
} else {
|
|
ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " has "
|
|
"no team %" B_PRId32 " references\n", id, team);
|
|
return B_ERROR;
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
int32 teamCount = teamRef->second - 1;
|
|
(void)teamCount;
|
|
#endif
|
|
|
|
if (--teamRef->second == 0)
|
|
node.team_ref_count.erase(teamRef);
|
|
|
|
if (--node.ref_count == 0) {
|
|
PRINT(1, "NodeManager::ReleaseNodeReference: detected released node is"
|
|
" now unused, node %" B_PRId32 "\n", id);
|
|
|
|
// TODO: remove!
|
|
node_final_release_command command;
|
|
status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
|
|
sizeof(command));
|
|
if (status != B_OK) {
|
|
ERROR("NodeManager::ReleaseNodeReference: can't send command to "
|
|
"node %" B_PRId32 "\n", id);
|
|
// ignore error
|
|
}
|
|
}
|
|
|
|
TRACE("NodeManager::ReleaseNodeReference leave: node %" B_PRId32 ", team %"
|
|
B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
|
|
node.ref_count, teamCount);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::ReleaseNodeAll(media_node_id id)
|
|
{
|
|
TRACE("NodeManager::ReleaseNodeAll enter: node %" B_PRId32 "\n", id);
|
|
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::ReleaseNodeAll: node %" B_PRId32 " not found\n",
|
|
id);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& node = found->second;
|
|
node.team_ref_count.clear();
|
|
node.ref_count = 0;
|
|
|
|
node_final_release_command command;
|
|
status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
|
|
sizeof(command));
|
|
if (status != B_OK) {
|
|
ERROR("NodeManager::ReleaseNodeAll: can't send command to "
|
|
"node %" B_PRId32 "\n", id);
|
|
// ignore error
|
|
}
|
|
|
|
TRACE("NodeManager::ReleaseNodeAll leave: node %" B_PRId32 "\n", id);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::SetNodeCreator(media_node_id id, team_id creator)
|
|
{
|
|
TRACE("NodeManager::SetNodeCreator node %" B_PRId32 ", creator %" B_PRId32
|
|
"\n", id, creator);
|
|
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " not found\n",
|
|
id);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& node = found->second;
|
|
|
|
if (node.creator != -1) {
|
|
ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " is already"
|
|
" assigned creator %" B_PRId32 "\n", id, node.creator);
|
|
return B_ERROR;
|
|
}
|
|
|
|
node.creator = creator;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetCloneForID(media_node_id id, team_id team, media_node* node)
|
|
{
|
|
TRACE("NodeManager::GetCloneForID enter: node %" B_PRId32 " team %"
|
|
B_PRId32 "\n", id, team);
|
|
|
|
BAutolock _(this);
|
|
|
|
status_t status = _AcquireNodeReference(id, team);
|
|
if (status != B_OK) {
|
|
ERROR("NodeManager::GetCloneForID: couldn't increment ref count, "
|
|
"node %" B_PRId32 " team %" B_PRId32 "\n", id, team);
|
|
return status;
|
|
}
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::GetCloneForID: node %" B_PRId32 " not found\n",
|
|
id);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& registeredNode = found->second;
|
|
|
|
node->node = registeredNode.node_id;
|
|
node->port = registeredNode.port;
|
|
node->kind = registeredNode.kinds;
|
|
|
|
TRACE("NodeManager::GetCloneForID leave: node %" B_PRId32 " team %"
|
|
B_PRId32 "\n", id, team);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
/*! This function locates the default "node" for the requested "type" and
|
|
returns a clone.
|
|
If the requested type is AUDIO_OUTPUT_EX, also "input_name" and "input_id"
|
|
need to be set and returned, as this is required by
|
|
BMediaRoster::GetAudioOutput(media_node *out_node, int32 *out_input_id,
|
|
BString *out_input_name).
|
|
*/
|
|
status_t
|
|
NodeManager::GetClone(node_type type, team_id team, media_node* node,
|
|
char* inputName, int32* _inputID)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
TRACE("NodeManager::GetClone enter: team %" B_PRId32 ", type %d (%s)\n",
|
|
team, type, get_node_type(type));
|
|
|
|
media_node_id id;
|
|
status_t status = GetDefaultNode(type, &id, inputName, _inputID);
|
|
if (status != B_OK) {
|
|
ERROR("NodeManager::GetClone: couldn't GetDefaultNode, team %" B_PRId32
|
|
", type %d (%s)\n", team, type, get_node_type(type));
|
|
*node = media_node::null;
|
|
return status;
|
|
}
|
|
ASSERT(id > 0);
|
|
|
|
status = GetCloneForID(id, team, node);
|
|
if (status != B_OK) {
|
|
ERROR("NodeManager::GetClone: couldn't GetCloneForID, id %" B_PRId32
|
|
", team %" B_PRId32 ", type %d (%s)\n", id, team, type,
|
|
get_node_type(type));
|
|
*node = media_node::null;
|
|
return status;
|
|
}
|
|
ASSERT(id == node->node);
|
|
|
|
TRACE("NodeManager::GetClone leave: node id %" B_PRId32 ", node port %"
|
|
B_PRId32 ", node kind %#" B_PRIx64 "\n", node->node, node->port,
|
|
node->kind);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::ReleaseNode(const media_node& node, team_id team)
|
|
{
|
|
TRACE("NodeManager::ReleaseNode enter: node %" B_PRId32 " team %" B_PRId32
|
|
"\n", node.node, team);
|
|
|
|
if (ReleaseNodeReference(node.node, team) != B_OK) {
|
|
ERROR("NodeManager::ReleaseNode: couldn't decrement node %" B_PRId32
|
|
" team %" B_PRId32 " ref count\n", node.node, team);
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::PublishInputs(const media_node& node, const media_input* inputs,
|
|
int32 count)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(node.node);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::PublishInputs: node %" B_PRId32 " not found\n",
|
|
node.node);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& registeredNode = found->second;
|
|
|
|
registeredNode.input_list.clear();
|
|
|
|
try {
|
|
for (int32 i = 0; i < count; i++)
|
|
registeredNode.input_list.push_back(inputs[i]);
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::PublishOutputs(const media_node &node, const media_output* outputs,
|
|
int32 count)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(node.node);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::PublishOutputs: node %" B_PRId32 " not found\n",
|
|
node.node);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& registeredNode = found->second;
|
|
|
|
registeredNode.output_list.clear();
|
|
|
|
try {
|
|
for (int32 i = 0; i < count; i++)
|
|
registeredNode.output_list.push_back(outputs[i]);
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::FindNodeID(port_id port, media_node_id* _id)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator iterator = fNodeMap.begin();
|
|
for (; iterator != fNodeMap.end(); iterator++) {
|
|
registered_node& node = iterator->second;
|
|
|
|
if (node.port == port) {
|
|
*_id = node.node_id;
|
|
TRACE("NodeManager::FindNodeID found port %" B_PRId32 ", node %"
|
|
B_PRId32 "\n", port, node.node_id);
|
|
return B_OK;
|
|
}
|
|
|
|
OutputList::iterator outIterator = node.output_list.begin();
|
|
for (; outIterator != node.output_list.end(); outIterator++) {
|
|
if (outIterator->source.port == port) {
|
|
*_id = node.node_id;
|
|
TRACE("NodeManager::FindNodeID found output port %" B_PRId32
|
|
", node %" B_PRId32 "\n", port, node.node_id);
|
|
return B_OK;
|
|
}
|
|
}
|
|
|
|
InputList::iterator inIterator = node.input_list.begin();
|
|
for (; inIterator != node.input_list.end(); inIterator++) {
|
|
if (inIterator->destination.port == port) {
|
|
*_id = node.node_id;
|
|
TRACE("NodeManager::FindNodeID found input port %" B_PRId32
|
|
", node %" B_PRId32 "\n", port, node.node_id);
|
|
return B_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
ERROR("NodeManager::FindNodeID failed, port %" B_PRId32 "\n", port);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetDormantNodeInfo(const media_node& node,
|
|
dormant_node_info* nodeInfo)
|
|
{
|
|
// TODO: not sure if this is correct
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(node.node);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::GetDormantNodeInfo: node %" B_PRId32 " not found"
|
|
"\n", node.node);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& registeredNode = found->second;
|
|
|
|
if (registeredNode.add_on_id == -1
|
|
&& node.node != NODE_SYSTEM_TIMESOURCE_ID) {
|
|
// This function must return an error if the node is application owned
|
|
TRACE("NodeManager::GetDormantNodeInfo NODE IS APPLICATION OWNED! "
|
|
"node %" B_PRId32 ", add_on_id %" B_PRId32 ", flavor_id %" B_PRId32
|
|
", name \"%s\"\n", node.node, registeredNode.add_on_id,
|
|
registeredNode.flavor_id, registeredNode.name);
|
|
return B_ERROR;
|
|
}
|
|
|
|
ASSERT(node.port == registeredNode.port);
|
|
ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
|
|
== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
|
|
|
|
nodeInfo->addon = registeredNode.add_on_id;
|
|
nodeInfo->flavor_id = registeredNode.flavor_id;
|
|
strlcpy(nodeInfo->name, registeredNode.name, sizeof(nodeInfo->name));
|
|
|
|
TRACE("NodeManager::GetDormantNodeInfo node %" B_PRId32 ", add_on_id %"
|
|
B_PRId32 ", flavor_id %" B_PRId32 ", name \"%s\"\n", node.node,
|
|
registeredNode.add_on_id, registeredNode.flavor_id,
|
|
registeredNode.name);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetLiveNodeInfo(const media_node& node, live_node_info* liveInfo)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(node.node);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::GetLiveNodeInfo: node %" B_PRId32 " not found\n",
|
|
node.node);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& registeredNode = found->second;
|
|
|
|
ASSERT(node.port == registeredNode.port);
|
|
ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
|
|
== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
|
|
|
|
liveInfo->node = node;
|
|
liveInfo->hint_point = BPoint(0, 0);
|
|
strlcpy(liveInfo->name, registeredNode.name, sizeof(liveInfo->name));
|
|
|
|
TRACE("NodeManager::GetLiveNodeInfo node %" B_PRId32 ", name = \"%s\"\n",
|
|
node.node, registeredNode.name);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetInstances(media_addon_id addOnID, int32 flavorID,
|
|
media_node_id* ids, int32* _count, int32 maxCount)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator iterator = fNodeMap.begin();
|
|
int32 count = 0;
|
|
for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
|
|
registered_node& node = iterator->second;
|
|
|
|
if (node.add_on_id == addOnID && node.flavor_id == flavorID)
|
|
ids[count++] = node.node_id;
|
|
}
|
|
|
|
TRACE("NodeManager::GetInstances found %" B_PRId32 " instances for "
|
|
"addon_id %" B_PRId32 ", flavor_id %" B_PRId32 "\n", count, addOnID,
|
|
flavorID);
|
|
*_count = count;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetLiveNodes(LiveNodeList& liveNodes, int32 maxCount,
|
|
const media_format* inputFormat, const media_format* outputFormat,
|
|
const char* name, uint64 requireKinds)
|
|
{
|
|
TRACE("NodeManager::GetLiveNodes: maxCount %" B_PRId32 ", in-format %p, "
|
|
"out-format %p, name %s, require kinds 0x%" B_PRIx64 "\n", maxCount,
|
|
inputFormat, outputFormat, name != NULL ? name : "NULL", requireKinds);
|
|
|
|
BAutolock _(this);
|
|
|
|
// Determine the count of byte to compare when checking for a name with
|
|
// or without wildcard
|
|
size_t nameLength = 0;
|
|
if (name != NULL) {
|
|
nameLength = strlen(name);
|
|
if (nameLength > 0 && name[nameLength - 1] == '*')
|
|
nameLength--;
|
|
}
|
|
|
|
NodeMap::iterator iterator = fNodeMap.begin();
|
|
int32 count = 0;
|
|
for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
|
|
registered_node& node = iterator->second;
|
|
|
|
if ((node.kinds & requireKinds) != requireKinds)
|
|
continue;
|
|
|
|
if (nameLength != 0) {
|
|
if (strncmp(name, node.name, nameLength) != 0)
|
|
continue;
|
|
}
|
|
|
|
if (inputFormat != NULL) {
|
|
bool found = false;
|
|
|
|
for (InputList::iterator inIterator = node.input_list.begin();
|
|
inIterator != node.input_list.end(); inIterator++) {
|
|
media_input& input = *inIterator;
|
|
|
|
if (format_is_compatible(*inputFormat, input.format)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
}
|
|
|
|
if (outputFormat != NULL) {
|
|
bool found = false;
|
|
|
|
for (OutputList::iterator outIterator = node.output_list.begin();
|
|
outIterator != node.output_list.end(); outIterator++) {
|
|
media_output& output = *outIterator;
|
|
|
|
if (format_is_compatible(*outputFormat, output.format)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
}
|
|
|
|
live_node_info info;
|
|
info.node.node = node.node_id;
|
|
info.node.port = node.port;
|
|
info.node.kind = node.kinds;
|
|
info.hint_point = BPoint(0, 0);
|
|
strlcpy(info.name, node.name, sizeof(info.name));
|
|
|
|
try {
|
|
liveNodes.push_back(info);
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
TRACE("NodeManager::GetLiveNodes found %" B_PRId32 "\n", count);
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
/*! Add media_node_id of all live nodes to the message
|
|
int32 "media_node_id" (multiple items)
|
|
*/
|
|
status_t
|
|
NodeManager::GetLiveNodes(BMessage* message)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator iterator = fNodeMap.begin();
|
|
for (; iterator != fNodeMap.end(); iterator++) {
|
|
registered_node& node = iterator->second;
|
|
|
|
if (message->AddInt32("media_node_id", node.node_id) != B_OK)
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// #pragma mark - Registration of BMediaAddOns
|
|
|
|
|
|
void
|
|
NodeManager::RegisterAddOn(const entry_ref& ref, media_addon_id* _newID)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
media_addon_id id = fNextAddOnID++;
|
|
|
|
// printf("NodeManager::RegisterAddOn: ref-name \"%s\", assigning id %"
|
|
// B_PRId32 "\n", ref.name, id);
|
|
|
|
try {
|
|
fPathMap.insert(std::make_pair(id, ref));
|
|
*_newID = id;
|
|
} catch (std::bad_alloc& exception) {
|
|
*_newID = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
NodeManager::UnregisterAddOn(media_addon_id addOnID)
|
|
{
|
|
PRINT(1, "NodeManager::UnregisterAddOn: id %" B_PRId32 "\n", addOnID);
|
|
|
|
BAutolock _(this);
|
|
|
|
RemoveDormantFlavorInfo(addOnID);
|
|
fPathMap.erase(addOnID);
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetAddOnRef(media_addon_id addOnID, entry_ref* ref)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
PathMap::iterator found = fPathMap.find(addOnID);
|
|
if (found == fPathMap.end())
|
|
return B_ERROR;
|
|
|
|
*ref = found->second;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// #pragma mark - Registration of node flavors, published by BMediaAddOns
|
|
|
|
|
|
//! This function is only used (indirectly) by the media_addon_server.
|
|
status_t
|
|
NodeManager::AddDormantFlavorInfo(const dormant_flavor_info& flavorInfo)
|
|
{
|
|
PRINT(1, "NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
|
|
"flavor-id %" B_PRId32 ", name \"%s\", flavor-name \"%s\", flavor-info"
|
|
" \"%s\"\n", flavorInfo.node_info.addon,
|
|
flavorInfo.node_info.flavor_id, flavorInfo.node_info.name,
|
|
flavorInfo.name, flavorInfo.info);
|
|
|
|
BAutolock _(this);
|
|
|
|
// Try to find the addon-id/flavor-id in the list.
|
|
// If it already exists, update the info, but don't change its instance
|
|
// count.
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (info.add_on_id != flavorInfo.node_info.addon
|
|
|| info.flavor_id != flavorInfo.node_info.flavor_id)
|
|
continue;
|
|
|
|
if (info.info_valid) {
|
|
ERROR("NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
|
|
"flavor-id %" B_PRId32 " does already exist\n",
|
|
info.info.node_info.addon, info.info.node_info.flavor_id);
|
|
}
|
|
|
|
TRACE("NodeManager::AddDormantFlavorInfo, updating addon-id %" B_PRId32
|
|
", flavor-id %" B_PRId32 "\n", info.info.node_info.addon,
|
|
info.info.node_info.flavor_id);
|
|
|
|
info.max_instances_count = flavorInfo.possible_count > 0
|
|
? flavorInfo.possible_count : INT32_MAX;
|
|
info.info_valid = true;
|
|
info.info = flavorInfo;
|
|
return B_OK;
|
|
}
|
|
|
|
// Insert information into the list
|
|
|
|
dormant_add_on_flavor_info info;
|
|
info.add_on_id = flavorInfo.node_info.addon;
|
|
info.flavor_id = flavorInfo.node_info.flavor_id;
|
|
info.max_instances_count = flavorInfo.possible_count > 0
|
|
? flavorInfo.possible_count : INT32_MAX;
|
|
info.instances_count = 0;
|
|
info.info_valid = true;
|
|
info.info = flavorInfo;
|
|
|
|
try {
|
|
fDormantFlavors.push_back(info);
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
//! This function is only used (indirectly) by the media_addon_server
|
|
void
|
|
NodeManager::InvalidateDormantFlavorInfo(media_addon_id addOnID)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (info.add_on_id == addOnID && info.info_valid) {
|
|
PRINT(1, "NodeManager::InvalidateDormantFlavorInfo, addon-id %"
|
|
B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
|
|
"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
|
|
info.info.node_info.flavor_id, info.info.node_info.name,
|
|
info.info.name, info.info.info);
|
|
|
|
info.info_valid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//! This function is only used (indirectly) by the media_addon_server
|
|
void
|
|
NodeManager::RemoveDormantFlavorInfo(media_addon_id addOnID)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
for (size_t index = 0; index < fDormantFlavors.size(); index++) {
|
|
dormant_add_on_flavor_info& info = fDormantFlavors[index];
|
|
|
|
if (info.add_on_id == addOnID) {
|
|
PRINT(1, "NodeManager::RemoveDormantFlavorInfo, addon-id %"
|
|
B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
|
|
"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
|
|
info.info.node_info.flavor_id, info.info.node_info.name,
|
|
info.info.name, info.info.info);
|
|
fDormantFlavors.erase(fDormantFlavors.begin() + index--);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::IncrementFlavorInstancesCount(media_addon_id addOnID,
|
|
int32 flavorID, team_id team)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (info.add_on_id != addOnID || info.flavor_id != flavorID)
|
|
continue;
|
|
|
|
if (info.instances_count >= info.max_instances_count) {
|
|
// maximum (or more) instances already exist
|
|
ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %"
|
|
B_PRId32 ", flavor-id %" B_PRId32 " maximum (or more) "
|
|
"instances already exist\n", addOnID, flavorID);
|
|
return B_ERROR;
|
|
}
|
|
|
|
TeamCountMap::iterator teamInstance
|
|
= info.team_instances_count.find(team);
|
|
if (teamInstance == info.team_instances_count.end()) {
|
|
// This is the team's first instance
|
|
try {
|
|
info.team_instances_count.insert(std::make_pair(team, 1));
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
} else {
|
|
// Just increase its ref count
|
|
teamInstance->second++;
|
|
}
|
|
|
|
info.instances_count++;
|
|
return B_OK;
|
|
}
|
|
|
|
ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %" B_PRId32 ", "
|
|
"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::DecrementFlavorInstancesCount(media_addon_id addOnID,
|
|
int32 flavorID, team_id team)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (info.add_on_id != addOnID || info.flavor_id != flavorID)
|
|
continue;
|
|
|
|
TeamCountMap::iterator teamInstance
|
|
= info.team_instances_count.find(team);
|
|
if (teamInstance == info.team_instances_count.end()) {
|
|
ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %"
|
|
B_PRId32 ", flavor-id %" B_PRId32 " team %" B_PRId32 " has no "
|
|
"references\n", addOnID, flavorID, team);
|
|
return B_ERROR;
|
|
}
|
|
if (--teamInstance->second == 0)
|
|
info.team_instances_count.erase(teamInstance);
|
|
|
|
info.instances_count--;
|
|
return B_OK;
|
|
}
|
|
|
|
ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %" B_PRId32 ", "
|
|
"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
//! This function is called when the media_addon_server has crashed
|
|
void
|
|
NodeManager::CleanupDormantFlavorInfos()
|
|
{
|
|
PRINT(1, "NodeManager::CleanupDormantFlavorInfos\n");
|
|
|
|
BAutolock _(this);
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
// Current instance count is zero since the media_addon_server crashed.
|
|
BPrivate::media::notifications::FlavorsChanged(info.add_on_id,
|
|
0, info.instances_count);
|
|
}
|
|
|
|
fDormantFlavors.clear();
|
|
|
|
PRINT(1, "NodeManager::CleanupDormantFlavorInfos done\n");
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetDormantNodes(dormant_node_info* infos, int32* _count,
|
|
const media_format* input, const media_format* output, const char* name,
|
|
uint64 requireKinds, uint64 denyKinds)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
// Determine the count of byte to compare when checking for a name with
|
|
// or without wildcard
|
|
size_t nameLength = 0;
|
|
if (name != NULL) {
|
|
nameLength = strlen(name);
|
|
if (nameLength > 0 && name[nameLength - 1] == '*')
|
|
nameLength--;
|
|
}
|
|
|
|
int32 maxCount = *_count;
|
|
int32 count = 0;
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end() && count < maxCount; iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (!info.info_valid)
|
|
continue;
|
|
|
|
if ((info.info.kinds & requireKinds) != requireKinds
|
|
|| (info.info.kinds & denyKinds) != 0)
|
|
continue;
|
|
|
|
if (nameLength != 0) {
|
|
if (strncmp(name, info.info.name, nameLength) != 0)
|
|
continue;
|
|
}
|
|
|
|
if (input != NULL) {
|
|
bool found = false;
|
|
|
|
for (int32 i = 0; i < info.info.in_format_count; i++) {
|
|
if (format_is_compatible(*input, info.info.in_formats[i])) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
}
|
|
|
|
if (output != NULL) {
|
|
bool found = false;
|
|
|
|
for (int32 i = 0; i < info.info.out_format_count; i++) {
|
|
if (format_is_compatible(*output, info.info.out_formats[i])) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
}
|
|
|
|
infos[count++] = info.info.node_info;
|
|
}
|
|
|
|
*_count = count;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::GetDormantFlavorInfoFor(media_addon_id addOnID, int32 flavorID,
|
|
dormant_flavor_info* flavorInfo)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& info = *iterator;
|
|
|
|
if (info.add_on_id == addOnID && info.flavor_id == flavorID
|
|
&& info.info_valid) {
|
|
*flavorInfo = info.info;
|
|
return B_OK;
|
|
}
|
|
}
|
|
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
// #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
|
|
NodeManager::CleanupTeam(team_id team)
|
|
{
|
|
BAutolock _(this);
|
|
|
|
fDefaultManager->CleanupTeam(team);
|
|
|
|
PRINT(1, "NodeManager::CleanupTeam: team %" B_PRId32 "\n", team);
|
|
|
|
// Cleanup node references
|
|
|
|
for (NodeMap::iterator iterator = fNodeMap.begin();
|
|
iterator != fNodeMap.end();) {
|
|
registered_node& node = iterator->second;
|
|
NodeMap::iterator remove = iterator++;
|
|
|
|
// If the gone team was the creator of some global dormant node
|
|
// instance, we now invalidate that we may want to remove that
|
|
// global node, but I'm not sure
|
|
if (node.creator == team) {
|
|
node.creator = -1;
|
|
// fall through
|
|
}
|
|
|
|
// If the team hosting this node is gone, remove node from database
|
|
if (node.containing_team == team) {
|
|
PRINT(1, "NodeManager::CleanupTeam: removing node id %" B_PRId32
|
|
", team %" B_PRId32 "\n", node.node_id, team);
|
|
// Ensure the slave node is removed from it's timesource
|
|
_NotifyTimeSource(node);
|
|
fNodeMap.erase(remove);
|
|
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
|
continue;
|
|
}
|
|
|
|
// Check the list of teams that have references to this node, and
|
|
// remove the team
|
|
TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
|
|
if (teamRef != node.team_ref_count.end()) {
|
|
PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " refs "
|
|
"from node id %" B_PRId32 ", team %" B_PRId32 "\n",
|
|
teamRef->second, node.node_id, team);
|
|
node.ref_count -= teamRef->second;
|
|
if (node.ref_count == 0) {
|
|
PRINT(1, "NodeManager::CleanupTeam: removing 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);
|
|
BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
|
|
} else
|
|
node.team_ref_count.erase(teamRef);
|
|
}
|
|
}
|
|
|
|
// Cleanup add-on references
|
|
|
|
for (size_t index = 0; index < fDormantFlavors.size(); index++) {
|
|
dormant_add_on_flavor_info& flavorInfo = fDormantFlavors[index];
|
|
|
|
TeamCountMap::iterator instanceCount
|
|
= flavorInfo.team_instances_count.find(team);
|
|
if (instanceCount != flavorInfo.team_instances_count.end()) {
|
|
PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " "
|
|
"instances from addon %" B_PRId32 ", flavor %" B_PRId32 "\n",
|
|
instanceCount->second, flavorInfo.add_on_id,
|
|
flavorInfo.flavor_id);
|
|
|
|
int32 count = flavorInfo.instances_count;
|
|
flavorInfo.instances_count -= instanceCount->second;
|
|
if (flavorInfo.instances_count <= 0) {
|
|
fDormantFlavors.erase(fDormantFlavors.begin() + index--);
|
|
BPrivate::media::notifications::FlavorsChanged(
|
|
flavorInfo.add_on_id, 0, count);
|
|
} else
|
|
flavorInfo.team_instances_count.erase(team);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
NodeManager::LoadState()
|
|
{
|
|
BAutolock _(this);
|
|
return fDefaultManager->LoadState();
|
|
}
|
|
|
|
status_t
|
|
NodeManager::SaveState()
|
|
{
|
|
BAutolock _(this);
|
|
return fDefaultManager->SaveState(this);
|
|
}
|
|
|
|
|
|
void
|
|
NodeManager::Dump()
|
|
{
|
|
BAutolock _(this);
|
|
|
|
// for each addon-id, the add-on path map contains an entry_ref
|
|
|
|
printf("\nNodeManager: addon path map follows:\n");
|
|
|
|
for (PathMap::iterator iterator = fPathMap.begin();
|
|
iterator != fPathMap.end(); iterator++) {
|
|
BPath path(&iterator->second);
|
|
printf(" addon-id %" B_PRId32 ", path \"%s\"\n", iterator->first,
|
|
path.InitCheck() == B_OK ? path.Path() : "INVALID");
|
|
}
|
|
|
|
printf("NodeManager: list end\n\n");
|
|
|
|
// for each node-id, the registered node map contians information about
|
|
// source of the node, users, etc.
|
|
|
|
printf("NodeManager: registered nodes map follows:\n");
|
|
for (NodeMap::iterator iterator = fNodeMap.begin();
|
|
iterator != fNodeMap.end(); iterator++) {
|
|
registered_node& node = iterator->second;
|
|
|
|
printf(" node-id %" B_PRId32 ", addon-id %" B_PRId32 ", addon-flavor-"
|
|
"id %" B_PRId32 ", port %" B_PRId32 ", creator %" B_PRId32 ", "
|
|
"team %" B_PRId32 ", kinds %#08" B_PRIx64 ", name \"%s\", "
|
|
"ref_count %" B_PRId32 "\n", node.node_id, node.add_on_id,
|
|
node.flavor_id, node.port, node.creator, node.containing_team,
|
|
node.kinds, node.name, node.ref_count);
|
|
|
|
printf(" teams (refcount): ");
|
|
for (TeamCountMap::iterator refsIterator = node.team_ref_count.begin();
|
|
refsIterator != node.team_ref_count.end(); refsIterator++) {
|
|
printf("%" B_PRId32 " (%" B_PRId32 "), ", refsIterator->first,
|
|
refsIterator->second);
|
|
}
|
|
printf("\n");
|
|
|
|
for (InputList::iterator inIterator = node.input_list.begin();
|
|
inIterator != node.input_list.end(); inIterator++) {
|
|
media_input& input = *inIterator;
|
|
printf(" media_input: node-id %" B_PRId32 ", node-port %"
|
|
B_PRId32 ", source-port %" B_PRId32 ", source-id %" B_PRId32
|
|
", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
|
|
"\"%s\"\n", input.node.node, input.node.port, input.source.port,
|
|
input.source.id, input.destination.port, input.destination.id,
|
|
input.name);
|
|
}
|
|
if (node.input_list.empty())
|
|
printf(" media_input: none\n");
|
|
|
|
for (OutputList::iterator outIterator = node.output_list.begin();
|
|
outIterator != node.output_list.end(); outIterator++) {
|
|
media_output& output = *outIterator;
|
|
printf(" media_output: node-id %" B_PRId32 ", node-port %"
|
|
B_PRId32 ", source-port %" B_PRId32 ", source-id %" B_PRId32
|
|
", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
|
|
"\"%s\"\n", output.node.node, output.node.port,
|
|
output.source.port, output.source.id, output.destination.port,
|
|
output.destination.id, output.name);
|
|
}
|
|
if (node.output_list.empty())
|
|
printf(" media_output: none\n");
|
|
}
|
|
|
|
printf("NodeManager: list end\n");
|
|
printf("\n");
|
|
|
|
// Dormant add-on flavors
|
|
|
|
printf("NodeManager: dormant flavor list follows:\n");
|
|
|
|
for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
|
|
iterator != fDormantFlavors.end(); iterator++) {
|
|
dormant_add_on_flavor_info& flavorInfo = *iterator;
|
|
|
|
printf(" addon-id %" B_PRId32 ", flavor-id %" B_PRId32 ", max "
|
|
"instances count %" B_PRId32 ", instances count %" B_PRId32 ", "
|
|
"info valid %s\n", flavorInfo.add_on_id, flavorInfo.flavor_id,
|
|
flavorInfo.max_instances_count, flavorInfo.instances_count,
|
|
flavorInfo.info_valid ? "yes" : "no");
|
|
printf(" teams (instances): ");
|
|
for (TeamCountMap::iterator countIterator
|
|
= flavorInfo.team_instances_count.begin();
|
|
countIterator != flavorInfo.team_instances_count.end();
|
|
countIterator++) {
|
|
printf("%" B_PRId32 " (%" B_PRId32 "), ", countIterator->first,
|
|
countIterator->second);
|
|
}
|
|
printf("\n");
|
|
if (!flavorInfo.info_valid)
|
|
continue;
|
|
|
|
printf(" addon-id %" B_PRId32 ", addon-flavor-id %" B_PRId32 ", "
|
|
"addon-name \"%s\"\n", flavorInfo.info.node_info.addon,
|
|
flavorInfo.info.node_info.flavor_id,
|
|
flavorInfo.info.node_info.name);
|
|
printf(" flavor-kinds %#08" B_PRIx64 ", flavor_flags %#08" B_PRIx32
|
|
", internal_id %" B_PRId32 ", possible_count %" B_PRId32 ", "
|
|
"in_format_count %" B_PRId32 ", out_format_count %" B_PRId32 "\n",
|
|
flavorInfo.info.kinds, flavorInfo.info.flavor_flags,
|
|
flavorInfo.info.internal_id, flavorInfo.info.possible_count,
|
|
flavorInfo.info.in_format_count, flavorInfo.info.out_format_count);
|
|
printf(" flavor-name \"%s\"\n", flavorInfo.info.name);
|
|
printf(" flavor-info \"%s\"\n", flavorInfo.info.info);
|
|
}
|
|
printf("NodeManager: list end\n");
|
|
|
|
fDefaultManager->Dump();
|
|
}
|
|
|
|
|
|
// #pragma mark - private methods
|
|
|
|
|
|
status_t
|
|
NodeManager::_AcquireNodeReference(media_node_id id, team_id team)
|
|
{
|
|
TRACE("NodeManager::_AcquireNodeReference enter: node %" B_PRId32 ", team "
|
|
"%" B_PRId32 "\n", id, team);
|
|
|
|
BAutolock _(this);
|
|
|
|
NodeMap::iterator found = fNodeMap.find(id);
|
|
if (found == fNodeMap.end()) {
|
|
ERROR("NodeManager::_AcquireNodeReference: node %" B_PRId32 " not "
|
|
"found\n", id);
|
|
return B_ERROR;
|
|
}
|
|
|
|
registered_node& node = found->second;
|
|
|
|
TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
|
|
if (teamRef == node.team_ref_count.end()) {
|
|
// This is the team's first reference
|
|
try {
|
|
node.team_ref_count.insert(std::make_pair(team, 1));
|
|
} catch (std::bad_alloc& exception) {
|
|
return B_NO_MEMORY;
|
|
}
|
|
} else {
|
|
// Just increase its ref count
|
|
teamRef->second++;
|
|
}
|
|
|
|
node.ref_count++;
|
|
|
|
TRACE("NodeManager::_AcquireNodeReference leave: node %" B_PRId32 ", team "
|
|
"%" B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
|
|
node.ref_count, node.team_ref_count.find(team)->second);
|
|
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);
|
|
}
|