Added automatic loading of physical input and output nodes.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3320 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
917d37106e
commit
359ac30644
@ -109,7 +109,7 @@ virtual status_t GetConfigurationFor(
|
||||
BMessage * into_message);
|
||||
virtual bool WantsAutoStart();
|
||||
virtual status_t AutoStart(
|
||||
int in_count,
|
||||
int in_index,
|
||||
BMediaNode ** out_node,
|
||||
int32 * out_internal_id,
|
||||
bool * out_has_more);
|
||||
|
@ -111,6 +111,7 @@ enum {
|
||||
NODE_SET_TIMESOURCE,
|
||||
NODE_REQUEST_COMPLETED,
|
||||
NODE_FINAL_RELEASE,
|
||||
NODE_PUBLISH_CONNECTIONS,
|
||||
|
||||
NODE_MESSAGE_END,
|
||||
CONSUMER_MESSAGE_START = 0x300,
|
||||
|
@ -21,7 +21,11 @@
|
||||
#define SYSTEM_TIMESOURCE_CONTROL_PORT -666
|
||||
#define IS_SYSTEM_TIMESOURCE(_node) ((_node).node > 0 && (_node).port == SYSTEM_TIMESOURCE_CONTROL_PORT)
|
||||
|
||||
#define NODE_KIND_NO_REFCOUNTING 0x80000000
|
||||
#define NODE_KIND_USER_MASK 0x00000000FFFFFFFFLL
|
||||
#define NODE_KIND_COMPARE_MASK 0x000000007FFFFFFFLL
|
||||
#define NODE_KIND_NO_REFCOUNTING 0x0000000080000000LL
|
||||
#define NODE_KIND_SHADOW_TIMESOURCE 0x0000000100000000LL
|
||||
#define NODE_KIND_SYSTEM_TIMESOURCE 0x0000000200000000LL
|
||||
|
||||
#define ROUND_UP_TO_PAGE(size) (((size) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1))
|
||||
|
||||
|
@ -1312,7 +1312,7 @@ BMediaRoster::GetFreeOutputsFor(const media_node & node,
|
||||
if (buf_num_outputs == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
MediaRosterEx(this)->PublishOutputs(node, &list);
|
||||
return B_OK;
|
||||
}
|
||||
@ -1550,21 +1550,38 @@ BMediaRosterEx::RegisterNode(BMediaNode * node, media_addon_id addonid, int32 fl
|
||||
ts->FinishCreate();
|
||||
}
|
||||
|
||||
// XXX XXX XXX
|
||||
// Calling GetAllOutputs and GetAllInputs here,
|
||||
// followed by PublishOutputs and PublishInputs,
|
||||
// does not work, it is too early, and in some
|
||||
// cases it will deadlock the node control thread.
|
||||
|
||||
// Posting a message to the roster thread here
|
||||
// is also to early, the multi_audio add-on will
|
||||
// no list any inputs
|
||||
// XXX XXX XXX
|
||||
|
||||
/*
|
||||
BMessage msg(NODE_PUBLISH_CONNECTIONS);
|
||||
media_node tempnode;
|
||||
tempnode = node->Node();
|
||||
msg.AddData("node", B_RAW_TYPE, &tempnode, sizeof(tempnode));
|
||||
PostMessage(&msg);
|
||||
*/
|
||||
/*
|
||||
// register existing inputs and outputs with the
|
||||
// media_server, this allows GetLiveNodes() to work
|
||||
// with created, but unconnected nodes.
|
||||
if (node->Kinds() & B_BUFFER_PRODUCER) {
|
||||
Stack<media_output> stack;
|
||||
if (B_OK == GetAllOutputs(node->Node(), &stack))
|
||||
PublishOutputs(node->Node(), &stack);
|
||||
List<media_output> list;
|
||||
if (B_OK == GetAllOutputs(node->Node(), &list))
|
||||
PublishOutputs(node->Node(), &list);
|
||||
} else if (node->Kinds() & B_BUFFER_CONSUMER) {
|
||||
Stack<media_input> stack;
|
||||
if (B_OK == GetAllInputs(node->Node(), &stack))
|
||||
PublishInputs(node->Node(), &stack);
|
||||
List<media_input> list;
|
||||
if (B_OK == GetAllInputs(node->Node(), &list))
|
||||
PublishInputs(node->Node(), &list);
|
||||
}
|
||||
*/
|
||||
|
||||
BPrivate::media::notifications::NodesCreated(&reply.nodeid, 1);
|
||||
/*
|
||||
TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id);
|
||||
@ -2441,6 +2458,33 @@ BMediaRoster::MessageReceived(BMessage * message)
|
||||
message->SendReply(&pong, static_cast<BHandler *>(NULL), 2000000);
|
||||
return;
|
||||
}
|
||||
|
||||
case NODE_PUBLISH_CONNECTIONS:
|
||||
{
|
||||
const void *data;
|
||||
ssize_t numBytes;
|
||||
media_node node;
|
||||
|
||||
printf("NODE_PUBLISH_CONNECTIONS enter\n");
|
||||
|
||||
message->FindData("node", B_RAW_TYPE, &data, &numBytes);
|
||||
node = *(const media_node *)data;
|
||||
|
||||
// register existing inputs and outputs with the
|
||||
// media_server, this allows GetLiveNodes() to work
|
||||
// with created, but unconnected nodes.
|
||||
if (node.kind & B_BUFFER_PRODUCER) {
|
||||
List<media_output> outputlist;
|
||||
if (B_OK == MediaRosterEx(this)->GetAllOutputs(node, &outputlist))
|
||||
MediaRosterEx(this)->PublishOutputs(node, &outputlist);
|
||||
} else if (node.kind & B_BUFFER_CONSUMER) {
|
||||
List<media_input> inputlist;
|
||||
if (B_OK == MediaRosterEx(this)->GetAllInputs(node, &inputlist))
|
||||
MediaRosterEx(this)->PublishInputs(node, &inputlist);
|
||||
}
|
||||
printf("NODE_PUBLISH_CONNECTIONS leave\n");
|
||||
return;
|
||||
}
|
||||
|
||||
case NODE_FINAL_RELEASE:
|
||||
{
|
||||
|
@ -10,10 +10,7 @@
|
||||
#define _TIME_SOURCE_OBJECT_H_
|
||||
|
||||
#include <TimeSource.h>
|
||||
|
||||
#define NODE_KIND_USER_MASK 0x00000000FFFFFFFFLL
|
||||
#define NODE_KIND_SHADOW_TIMESOURCE 0x0000000100000000LL
|
||||
#define NODE_KIND_SYSTEM_TIMESOURCE 0x0000000200000000LL
|
||||
#include "MediaMisc.h"
|
||||
|
||||
namespace BPrivate { namespace media {
|
||||
|
||||
|
@ -105,6 +105,16 @@ status_t AppManager::UnregisterTeam(team_id team)
|
||||
return is_removed ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
status_t
|
||||
AppManager::SendMessage(team_id team, BMessage *msg)
|
||||
{
|
||||
BAutolock lock(fLocker);
|
||||
App *app;
|
||||
if (!fAppMap->Get(team, &app))
|
||||
return B_ERROR;
|
||||
return app->messenger.SendMessage(msg);
|
||||
}
|
||||
|
||||
void AppManager::RestartAddonServer()
|
||||
{
|
||||
static bigtime_t restart_period = 0;
|
||||
|
@ -19,6 +19,8 @@ public:
|
||||
void TerminateAddonServer();
|
||||
team_id AddonServer();
|
||||
|
||||
status_t SendMessage(team_id team, BMessage *msg);
|
||||
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
|
@ -6,15 +6,18 @@
|
||||
#include <MediaNode.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <string.h>
|
||||
#include <String.h>
|
||||
#include "DefaultManager.h"
|
||||
#include "NodeManager.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern NodeManager *gNodeManager;
|
||||
|
||||
/* no locking used in this file, we assume that the caller (NodeManager) does it.
|
||||
*/
|
||||
|
||||
DefaultManager::DefaultManager()
|
||||
: fPhysicalVideoOut(-1),
|
||||
: fMixerConnected(false),
|
||||
fPhysicalVideoOut(-1),
|
||||
fPhysicalVideoIn(-1),
|
||||
fPhysicalAudioOut(-1),
|
||||
fPhysicalAudioIn(-1),
|
||||
@ -153,11 +156,15 @@ void
|
||||
DefaultManager::RescanThread()
|
||||
{
|
||||
printf("DefaultManager::RescanThread() enter\n");
|
||||
|
||||
|
||||
// We do not search for the system time source,
|
||||
// it should already exist
|
||||
ASSERT(fSystemTimeSource != -1);
|
||||
|
||||
|
||||
for (int i = 0; i < 10; i++) { // XXX ugly workaround
|
||||
gNodeManager->UpdateNodeConnections(); // XXX ugly workaround
|
||||
snooze(1000000); // XXX ugly workaround
|
||||
|
||||
if (fPhysicalVideoOut == -1)
|
||||
FindPhysicalVideoOut();
|
||||
if (fPhysicalVideoIn == -1)
|
||||
@ -168,144 +175,218 @@ DefaultManager::RescanThread()
|
||||
FindPhysicalAudioIn();
|
||||
if (fAudioMixer == -1)
|
||||
FindAudioMixer();
|
||||
}
|
||||
|
||||
// The normal time source is searched for after the
|
||||
// Physical Audio Out has been created.
|
||||
if (fTimeSource == -1)
|
||||
FindTimeSource();
|
||||
|
||||
// Connect the mixer and physical audio out (soundcard)
|
||||
if (!fMixerConnected && fAudioMixer != -1 && fPhysicalAudioOut != -1) {
|
||||
fMixerConnected = B_OK == ConnectMixerToOutput();
|
||||
if (!fMixerConnected)
|
||||
FATAL("DefaultManager: failed to connect mixer and soundcard\n");
|
||||
}
|
||||
|
||||
printf("DefaultManager::RescanThread() leave\n");
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindPhysicalVideoOut()
|
||||
{
|
||||
dormant_node_info info;
|
||||
live_node_info info;
|
||||
media_format input; /* a physical video output has a logical data input */
|
||||
media_node node;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
memset(&input, 0, sizeof(input));
|
||||
input.type = B_MEDIA_RAW_VIDEO;
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info, &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("Couldn't find physical video output node\n");
|
||||
return;
|
||||
}
|
||||
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate physical video output node\n");
|
||||
} else {
|
||||
printf("Default physical video output created!\n");
|
||||
fPhysicalVideoOut = node.node;
|
||||
}
|
||||
printf("Default physical video output created!\n");
|
||||
fPhysicalVideoOut = info.node.node;
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindPhysicalVideoIn()
|
||||
{
|
||||
dormant_node_info info;
|
||||
live_node_info info;
|
||||
media_format output; /* a physical video input has a logical data output */
|
||||
media_node node;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
memset(&output, 0, sizeof(output));
|
||||
output.type = B_MEDIA_RAW_VIDEO;
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info, &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("Couldn't find physical video input node\n");
|
||||
return;
|
||||
}
|
||||
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate physical video input node\n");
|
||||
} else {
|
||||
printf("Default physical video input created!\n");
|
||||
fPhysicalVideoIn = node.node;
|
||||
}
|
||||
printf("Default physical video input created!\n");
|
||||
fPhysicalVideoIn = info.node.node;
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindPhysicalAudioOut()
|
||||
{
|
||||
dormant_node_info info;
|
||||
live_node_info info[2];
|
||||
media_format input; /* a physical audio output has a logical data input */
|
||||
media_node node;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
memset(&input, 0, sizeof(input));
|
||||
input.type = B_MEDIA_RAW_AUDIO;
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
|
||||
if (rv != B_OK || count != 1) {
|
||||
count = 2;
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info[0], &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
|
||||
if (rv != B_OK || count < 1) {
|
||||
printf("Couldn't find physical audio output node\n");
|
||||
return;
|
||||
}
|
||||
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate physical audio output node\n");
|
||||
} else {
|
||||
for (int i = 0; i < count; i++)
|
||||
printf("info[%d].name %s\n", i, info[i].name);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (0 == strcmp(info[i].name, "None Out")) // skip the Null audio driver
|
||||
continue;
|
||||
printf("Default physical audio output created!\n");
|
||||
fPhysicalAudioOut = node.node;
|
||||
fPhysicalAudioOut = info[i].node.node;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindPhysicalAudioIn()
|
||||
{
|
||||
dormant_node_info info;
|
||||
live_node_info info[2];
|
||||
media_format output; /* a physical audio input has a logical data output */
|
||||
media_node node;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
memset(&output, 0, sizeof(output));
|
||||
output.type = B_MEDIA_RAW_AUDIO;
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
|
||||
if (rv != B_OK || count != 1) {
|
||||
count = 2;
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info[0], &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
|
||||
if (rv != B_OK || count < 1) {
|
||||
printf("Couldn't find physical audio input node\n");
|
||||
return;
|
||||
}
|
||||
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate physical audio input node\n");
|
||||
} else {
|
||||
for (int i = 0; i < count; i++)
|
||||
printf("info[%d].name %s\n", i, info[i].name);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (0 == strcmp(info[i].name, "None In")) // skip the Null audio driver
|
||||
continue;
|
||||
printf("Default physical audio input created!\n");
|
||||
fPhysicalAudioIn = node.node;
|
||||
fPhysicalAudioIn = info[i].node.node;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindTimeSource()
|
||||
{
|
||||
live_node_info info;
|
||||
media_format input; /* a physical audio output has a logical data input (DAC)*/
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
/* We try to use the default physical audio out node,
|
||||
* as it most likely is a timesource.
|
||||
* XXX if that fails, we might use other audio or video clock timesources
|
||||
*/
|
||||
|
||||
memset(&input, 0, sizeof(input));
|
||||
input.type = B_MEDIA_RAW_AUDIO;
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info, &count, &input, NULL, NULL, B_TIME_SOURCE | B_PHYSICAL_OUTPUT);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("Couldn't find DAC timesource node\n");
|
||||
return;
|
||||
}
|
||||
fTimeSource = info.node.node;
|
||||
printf("Default DAC timesource created!\n");
|
||||
}
|
||||
|
||||
void
|
||||
DefaultManager::FindAudioMixer()
|
||||
{
|
||||
dormant_node_info info;
|
||||
media_node node;
|
||||
live_node_info info;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
count = 1;
|
||||
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, NULL, NULL, NULL, B_BUFFER_PRODUCER | B_BUFFER_CONSUMER | B_SYSTEM_MIXER);
|
||||
rv = BMediaRoster::Roster()->GetLiveNodes(&info, &count, NULL, NULL, NULL, B_BUFFER_PRODUCER | B_BUFFER_CONSUMER | B_SYSTEM_MIXER);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("Couldn't find audio mixer node\n");
|
||||
return;
|
||||
}
|
||||
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL);
|
||||
fAudioMixer = info.node.node;
|
||||
printf("Default audio mixer node created\n");
|
||||
}
|
||||
|
||||
status_t
|
||||
DefaultManager::ConnectMixerToOutput()
|
||||
{
|
||||
BMediaRoster *roster;
|
||||
media_node mixer;
|
||||
media_node soundcard;
|
||||
media_input input;
|
||||
media_output output;
|
||||
media_format format;
|
||||
int32 count;
|
||||
status_t rv;
|
||||
|
||||
roster = BMediaRoster::Roster();
|
||||
|
||||
// XXX this connects to *any* physical output, but not it's default logical input
|
||||
rv = roster->GetNodeFor(fPhysicalAudioOut, &soundcard);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate audio mixer node\n");
|
||||
} else {
|
||||
printf("Default audio mixer created!\n");
|
||||
fAudioMixer = node.node;
|
||||
printf("DefaultManager: failed to find soundcard (physical audio output)\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
rv = roster->GetNodeFor(fAudioMixer, &mixer);
|
||||
if (rv != B_OK) {
|
||||
roster->ReleaseNode(soundcard);
|
||||
printf("DefaultManager: failed to find mixer\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// we now have the mixer and soundcard nodes,
|
||||
// find a free input/output and connect them
|
||||
|
||||
rv = roster->GetFreeOutputsFor(mixer, &output, 1, &count, B_MEDIA_RAW_AUDIO);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("DefaultManager: can't find free mixer output\n");
|
||||
rv = B_ERROR;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
rv = roster->GetFreeInputsFor(soundcard, &input, 1, &count, B_MEDIA_RAW_AUDIO);
|
||||
if (rv != B_OK || count != 1) {
|
||||
printf("DefaultManager: can't find free soundcard input\n");
|
||||
rv = B_ERROR;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
memset(&format, 0, sizeof(format));
|
||||
format.type = B_MEDIA_RAW_AUDIO;
|
||||
|
||||
rv = roster->Connect(output.source, input.destination, &format, &output, &input);
|
||||
if (rv != B_OK) {
|
||||
printf("DefaultManager: connect failed\n");
|
||||
}
|
||||
|
||||
finish:
|
||||
roster->ReleaseNode(mixer);
|
||||
roster->ReleaseNode(soundcard);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
@ -317,3 +398,4 @@ void
|
||||
DefaultManager::CleanupTeam(team_id team)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,14 +35,17 @@ private:
|
||||
void FindAudioMixer();
|
||||
void FindTimeSource();
|
||||
|
||||
status_t ConnectMixerToOutput();
|
||||
|
||||
private:
|
||||
media_node_id fPhysicalVideoOut;
|
||||
media_node_id fPhysicalVideoIn;
|
||||
media_node_id fPhysicalAudioOut;
|
||||
media_node_id fPhysicalAudioIn;
|
||||
media_node_id fSystemTimeSource;
|
||||
media_node_id fTimeSource;
|
||||
media_node_id fAudioMixer;
|
||||
int32 fPhysicalAudioOutInputID;
|
||||
volatile bool fMixerConnected;
|
||||
volatile media_node_id fPhysicalVideoOut;
|
||||
volatile media_node_id fPhysicalVideoIn;
|
||||
volatile media_node_id fPhysicalAudioOut;
|
||||
volatile media_node_id fPhysicalAudioIn;
|
||||
volatile media_node_id fSystemTimeSource;
|
||||
volatile media_node_id fTimeSource;
|
||||
volatile media_node_id fAudioMixer;
|
||||
volatile int32 fPhysicalAudioOutInputID;
|
||||
char fPhysicalAudioOutInputName[B_MEDIA_NAME_LENGTH];
|
||||
};
|
||||
|
@ -43,6 +43,7 @@ static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@O
|
||||
#include "NodeManager.h"
|
||||
#include "DefaultManager.h"
|
||||
#include "AppManager.h"
|
||||
#include "MediaMisc.h"
|
||||
|
||||
extern AppManager *gAppManager;
|
||||
|
||||
@ -411,7 +412,7 @@ NodeManager::GetDormantNodeInfo(dormant_node_info *node_info, const media_node &
|
||||
return B_ERROR;
|
||||
}
|
||||
ASSERT(node.port == rn->port);
|
||||
ASSERT(node.kind == rn->kinds);
|
||||
ASSERT((node.kind & NODE_KIND_COMPARE_MASK) == (rn->kinds & NODE_KIND_COMPARE_MASK));
|
||||
node_info->addon = rn->addon_id;
|
||||
node_info->flavor_id = rn->addon_flavor_id;
|
||||
strcpy(node_info->name, rn->name);
|
||||
@ -431,7 +432,7 @@ NodeManager::GetLiveNodeInfo(live_node_info *live_info, const media_node &node)
|
||||
for (fRegisteredNodeMap->Rewind(); fRegisteredNodeMap->GetNext(&rn); ) {
|
||||
if (rn->nodeid == node.node) {
|
||||
ASSERT(node.port == rn->port);
|
||||
ASSERT(node.kind == rn->kinds);
|
||||
ASSERT((node.kind & NODE_KIND_COMPARE_MASK) == (rn->kinds & NODE_KIND_COMPARE_MASK));
|
||||
live_info->node = node;
|
||||
live_info->hint_point = BPoint(0, 0);
|
||||
strcpy(live_info->name, rn->name);
|
||||
@ -468,6 +469,9 @@ NodeManager::GetLiveNodes(Stack<live_node_info> *livenodes, int32 maxcount, cons
|
||||
BAutolock lock(fLocker);
|
||||
registered_node *rn;
|
||||
int namelen;
|
||||
|
||||
TRACE("NodeManager::GetLiveNodes: maxcount %d, in-format %p, out-format %p, name %s, require_kinds 0x%x\n",
|
||||
maxcount, inputformat, outputformat, (name ? name : "NULL"), require_kinds);
|
||||
|
||||
// determine the count of byte to compare when checking for a name with(out) wildcard
|
||||
if (name) {
|
||||
@ -539,6 +543,28 @@ NodeManager::GetLiveNodes(BMessage *msg)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void
|
||||
NodeManager::UpdateNodeConnections()
|
||||
{
|
||||
// XXX this is only a workaround because the multi_audio
|
||||
// XXX addon does not publish inputs right after creation :(
|
||||
BAutolock lock(fLocker);
|
||||
|
||||
registered_node *rn;
|
||||
for (fRegisteredNodeMap->Rewind(); fRegisteredNodeMap->GetNext(&rn); ) {
|
||||
|
||||
BMessage msg(NODE_PUBLISH_CONNECTIONS);
|
||||
media_node tempnode;
|
||||
tempnode.node = rn->nodeid;
|
||||
tempnode.port = rn->port;
|
||||
tempnode.kind = rn->kinds;
|
||||
msg.AddData("node", B_RAW_TYPE, &tempnode, sizeof(tempnode));
|
||||
|
||||
gAppManager->SendMessage(rn->team, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Registration of BMediaAddOns
|
||||
**********************************************************************/
|
||||
@ -964,11 +990,15 @@ NodeManager::Dump()
|
||||
printf(" media_input: node-id %ld, node-port %ld, source-port %ld, source-id %ld, dest-port %ld, dest-id %ld, name \"%s\"\n",
|
||||
input->node.node, input->node.port, input->source.port, input->source.id, input->destination.port, input->destination.id, input->name);
|
||||
}
|
||||
if (rn->inputlist.IsEmpty())
|
||||
printf(" media_input: none\n");
|
||||
media_output *output;
|
||||
for (rn->outputlist.Rewind(); rn->outputlist.GetNext(&output); ) {
|
||||
printf(" media_output: node-id %ld, node-port %ld, source-port %ld, source-id %ld, dest-port %ld, dest-id %ld, name \"%s\"\n",
|
||||
output->node.node, output->node.port, output->source.port, output->source.id, output->destination.port, output->destination.id, output->name);
|
||||
}
|
||||
if (rn->outputlist.IsEmpty())
|
||||
printf(" media_input: none\n");
|
||||
}
|
||||
printf("NodeManager: list end\n");
|
||||
printf("\n");
|
||||
|
@ -105,6 +105,8 @@ public:
|
||||
|
||||
void CleanupTeam(team_id team);
|
||||
|
||||
void UpdateNodeConnections();
|
||||
|
||||
private:
|
||||
media_addon_id fNextAddOnID;
|
||||
media_node_id fNextNodeID;
|
||||
|
@ -55,6 +55,17 @@ static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@O
|
||||
|
||||
void DumpFlavorInfo(const flavor_info *info);
|
||||
|
||||
struct AddOnInfo
|
||||
{
|
||||
media_addon_id id;
|
||||
bool wants_autostart;
|
||||
int32 flavor_count;
|
||||
|
||||
List<media_node> active_flavors;
|
||||
|
||||
BMediaAddOn *addon; // if != NULL, need to call _DormantNodeManager->PutAddon(id)
|
||||
};
|
||||
|
||||
class MediaAddonServer : BApplication
|
||||
{
|
||||
public:
|
||||
@ -68,11 +79,16 @@ public:
|
||||
void AddOnRemoved(ino_t file_node);
|
||||
void HandleMessage(int32 code, const void *data, size_t size);
|
||||
static int32 controlthread(void *arg);
|
||||
|
||||
void PutAddonIfPossible(AddOnInfo *info);
|
||||
void InstantiatePhysialInputsAndOutputs(AddOnInfo *info);
|
||||
void InstantiateAutostartFlavors(AddOnInfo *info);
|
||||
void DestroyInstantiatedFlavors(AddOnInfo *info);
|
||||
|
||||
void ScanAddOnFlavors(BMediaAddOn *addon);
|
||||
|
||||
Map<ino_t, media_addon_id> *filemap;
|
||||
Map<media_addon_id, int32> *flavorcountmap;
|
||||
Map<media_addon_id, AddOnInfo> *infomap;
|
||||
|
||||
BMediaRoster *mediaroster;
|
||||
ino_t DirNodeSystem;
|
||||
@ -88,9 +104,9 @@ MediaAddonServer::MediaAddonServer(const char *sig) :
|
||||
{
|
||||
mediaroster = BMediaRoster::Roster();
|
||||
filemap = new Map<ino_t, media_addon_id>;
|
||||
flavorcountmap = new Map<media_addon_id, int32>;
|
||||
control_port = create_port(64,"media_addon_server port");
|
||||
control_thread = spawn_thread(controlthread,"media_addon_server control",12,this);
|
||||
infomap = new Map<media_addon_id, AddOnInfo>;
|
||||
control_port = create_port(64, "media_addon_server port");
|
||||
control_thread = spawn_thread(controlthread, "media_addon_server control", 12, this);
|
||||
resume_thread(control_thread);
|
||||
}
|
||||
|
||||
@ -106,7 +122,7 @@ MediaAddonServer::~MediaAddonServer()
|
||||
_DormantNodeManager->UnregisterAddon(*id);
|
||||
|
||||
delete filemap;
|
||||
delete flavorcountmap;
|
||||
delete infomap;
|
||||
}
|
||||
|
||||
void
|
||||
@ -160,6 +176,10 @@ MediaAddonServer::controlthread(void *arg)
|
||||
void
|
||||
MediaAddonServer::ReadyToRun()
|
||||
{
|
||||
// the control thread is already running at this point,
|
||||
// so we can talk to the media server and also receive
|
||||
// commands for instantiation
|
||||
|
||||
// register with media_server
|
||||
server_register_addonserver_request request;
|
||||
server_register_addonserver_reply reply;
|
||||
@ -172,7 +192,13 @@ MediaAddonServer::ReadyToRun()
|
||||
return;
|
||||
}
|
||||
|
||||
fStartup = true;
|
||||
ASSERT(fStartup == true);
|
||||
|
||||
// During startup, first all add-ons are loaded, then all
|
||||
// nodes (flavors) representing physical inputs and outputs
|
||||
// are instantiated. Next, all add-ons that need autostart
|
||||
// will be autostarted. Finally, add-ons that don't have
|
||||
// any active nodes (flavors) will be unloaded.
|
||||
|
||||
// load dormant media nodes
|
||||
node_ref nref;
|
||||
@ -191,7 +217,21 @@ MediaAddonServer::ReadyToRun()
|
||||
WatchDir(&e2);
|
||||
|
||||
fStartup = false;
|
||||
|
||||
AddOnInfo *info;
|
||||
|
||||
infomap->Rewind();
|
||||
while (infomap->GetNext(&info))
|
||||
InstantiatePhysialInputsAndOutputs(info);
|
||||
|
||||
infomap->Rewind();
|
||||
while (infomap->GetNext(&info))
|
||||
InstantiateAutostartFlavors(info);
|
||||
|
||||
infomap->Rewind();
|
||||
while (infomap->GetNext(&info))
|
||||
PutAddonIfPossible(info);
|
||||
|
||||
server_rescan_defaults_command cmd;
|
||||
SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd));
|
||||
}
|
||||
@ -199,7 +239,7 @@ MediaAddonServer::ReadyToRun()
|
||||
void
|
||||
MediaAddonServer::ScanAddOnFlavors(BMediaAddOn *addon)
|
||||
{
|
||||
int32 *flavorcount;
|
||||
AddOnInfo *info;
|
||||
int32 oldflavorcount;
|
||||
int32 newflavorcount;
|
||||
media_addon_id addon_id;
|
||||
@ -223,11 +263,11 @@ MediaAddonServer::ScanAddOnFlavors(BMediaAddOn *addon)
|
||||
addon_id = addon->AddonID();
|
||||
|
||||
// update the cached flavor count, get oldflavorcount and newflavorcount
|
||||
b = flavorcountmap->Get(addon->AddonID(), &flavorcount);
|
||||
b = infomap->Get(addon_id, &info);
|
||||
ASSERT(b);
|
||||
oldflavorcount = *flavorcount;
|
||||
oldflavorcount = info->flavor_count;
|
||||
newflavorcount = addon->CountFlavors();
|
||||
*flavorcount = newflavorcount;
|
||||
info->flavor_count = newflavorcount;
|
||||
|
||||
TRACE("%ld old flavors, %ld new flavors\n", oldflavorcount, newflavorcount);
|
||||
|
||||
@ -296,6 +336,8 @@ MediaAddonServer::AddOnAdded(const char *path, ino_t file_node)
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("MediaAddonServer::AddOnAdded: loading addon %d now...\n", id);
|
||||
|
||||
addon = _DormantNodeManager->GetAddon(id);
|
||||
if (addon == NULL) {
|
||||
FATAL("MediaAddonServer::AddOnAdded: failed to get add-on %s\n", path);
|
||||
@ -305,73 +347,142 @@ MediaAddonServer::AddOnAdded(const char *path, ino_t file_node)
|
||||
|
||||
TRACE("MediaAddonServer::AddOnAdded: loading finished, id %ld\n", id);
|
||||
|
||||
// put file's inode and addon's id into map
|
||||
filemap->Insert(file_node, id);
|
||||
flavorcountmap->Insert(id, 0);
|
||||
|
||||
ScanAddOnFlavors(addon);
|
||||
|
||||
if (addon->WantsAutoStart())
|
||||
// also create AddOnInfo struct and get a pointer so
|
||||
// we can modify it
|
||||
AddOnInfo tempinfo;
|
||||
infomap->Insert(id, tempinfo);
|
||||
AddOnInfo *info;
|
||||
infomap->Get(id, &info);
|
||||
|
||||
// setup
|
||||
info->id = id;
|
||||
info->wants_autostart = false; // temporary default
|
||||
info->flavor_count = 0;
|
||||
info->addon = addon;
|
||||
|
||||
// scan the flavors
|
||||
ScanAddOnFlavors(addon);
|
||||
|
||||
// need to call BMediaNode::WantsAutoStart()
|
||||
// after the flavors have been scanned
|
||||
info->wants_autostart = addon->WantsAutoStart();
|
||||
|
||||
if (info->wants_autostart)
|
||||
FATAL("#### add-on %ld WantsAutoStart!\n", id);
|
||||
|
||||
/*
|
||||
* the mixer (which we can't load because of unresolved symbols)
|
||||
* is the only node that uses autostart (which is not implemented yet)
|
||||
*/
|
||||
|
||||
/*
|
||||
loading BMediaAddOn from /boot/beos/system/add-ons/media/mixer.media_addon
|
||||
adding media add-on -1
|
||||
1 flavors:
|
||||
flavor 0:
|
||||
internal_id = 0
|
||||
name = Be Audio Mixer
|
||||
info = The system-wide sound mixer of the future.
|
||||
flavor_flags = 0x0
|
||||
kinds = 0x40003 B_BUFFER_PRODUCER B_BUFFER_CONSUMER B_SYSTEM_MIXER
|
||||
in_format_count = 1
|
||||
out_format_count = 1
|
||||
#### WantsAutoStart!
|
||||
*/
|
||||
|
||||
/*
|
||||
if (addon->WantsAutoStart()) {
|
||||
for (int32 index = 0; ;index++) {
|
||||
BMediaNode *outNode;
|
||||
int32 outInternalID;
|
||||
bool outHasMore;
|
||||
rv = addon->AutoStart(index, &outNode, &outInternalID, &outHasMore);
|
||||
if (rv == B_OK) {
|
||||
printf("started node %ld\n",index);
|
||||
rv = mediaroster->RegisterNode(outNode);
|
||||
if (rv != B_OK)
|
||||
printf("failed to register node %ld\n",index);
|
||||
if (!outHasMore)
|
||||
// break;
|
||||
return;
|
||||
} else if (rv == B_MEDIA_ADDON_FAILED && outHasMore) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
// During startup, first all add-ons are loaded, then all
|
||||
// nodes (flavors) representing physical inputs and outputs
|
||||
// are instantiated. Next, all add-ons that need autostart
|
||||
// will be autostarted. Finally, add-ons that don't have
|
||||
// any active nodes (flavors) will be unloaded.
|
||||
|
||||
// After startup is done, we simply do it for each new
|
||||
// loaded add-on, too.
|
||||
if (!fStartup) {
|
||||
InstantiatePhysialInputsAndOutputs(info);
|
||||
InstantiateAutostartFlavors(info);
|
||||
PutAddonIfPossible(info);
|
||||
|
||||
// since something might have changed
|
||||
server_rescan_defaults_command cmd;
|
||||
SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd));
|
||||
SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
_DormantNodeManager->PutAddon(id);
|
||||
// we do not call _DormantNodeManager->PutAddon(id)
|
||||
// since it is done by PutAddonIfPossible()
|
||||
}
|
||||
|
||||
void
|
||||
MediaAddonServer::DestroyInstantiatedFlavors(AddOnInfo *info)
|
||||
{
|
||||
printf("MediaAddonServer::DestroyInstantiatedFlavors");
|
||||
}
|
||||
|
||||
void
|
||||
MediaAddonServer::PutAddonIfPossible(AddOnInfo *info)
|
||||
{
|
||||
if (info->addon && info->active_flavors.IsEmpty()) {
|
||||
_DormantNodeManager->PutAddon(info->id);
|
||||
info->addon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaAddonServer::InstantiatePhysialInputsAndOutputs(AddOnInfo *info)
|
||||
{
|
||||
int count = info->addon->CountFlavors();
|
||||
for (int i = 0; i < count; i++) {
|
||||
const flavor_info *flavorinfo;
|
||||
if (B_OK != info->addon->GetFlavorAt(i, &flavorinfo)) {
|
||||
FATAL("MediaAddonServer::InstantiatePhysialInputsAndOutputs GetFlavorAt failed for index %d!\n", i);
|
||||
continue;
|
||||
}
|
||||
if (flavorinfo->kinds & (B_PHYSICAL_INPUT | B_PHYSICAL_OUTPUT)) {
|
||||
media_node node;
|
||||
status_t rv;
|
||||
|
||||
dormant_node_info dni;
|
||||
dni.addon = info->id;
|
||||
dni.flavor_id = flavorinfo->internal_id;
|
||||
strcpy(dni.name, flavorinfo->name);
|
||||
|
||||
printf("MediaAddonServer::InstantiatePhysialInputsAndOutputs: \"%s\" is a physical input/output\n", flavorinfo->name);
|
||||
rv = mediaroster->InstantiateDormantNode(dni, &node);
|
||||
if (rv != B_OK) {
|
||||
printf("Couldn't instantiate node\n");
|
||||
} else {
|
||||
printf("Node created!\n");
|
||||
info->active_flavors.Insert(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaAddonServer::InstantiateAutostartFlavors(AddOnInfo *info)
|
||||
{
|
||||
if (!info->wants_autostart)
|
||||
return;
|
||||
|
||||
for (int32 index = 0; ;index++) {
|
||||
BMediaNode *outNode;
|
||||
int32 outInternalID;
|
||||
bool outHasMore;
|
||||
status_t rv;
|
||||
printf("trying autostart of node %ld, index %ld\n", info->id, index);
|
||||
rv = info->addon->AutoStart(index, &outNode, &outInternalID, &outHasMore);
|
||||
if (rv == B_OK) {
|
||||
printf("started node\n",index);
|
||||
|
||||
// XXX IncrementAddonFlavorInstancesCount
|
||||
|
||||
rv = MediaRosterEx(mediaroster)->RegisterNode(outNode, info->id, outInternalID);
|
||||
if (rv != B_OK) {
|
||||
printf("failed to register node %ld\n",index);
|
||||
// XXX DecrementAddonFlavorInstancesCount
|
||||
}
|
||||
|
||||
info->active_flavors.Insert(outNode->Node());
|
||||
|
||||
if (!outHasMore)
|
||||
return;
|
||||
} else if (rv == B_MEDIA_ADDON_FAILED && outHasMore) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaAddonServer::AddOnRemoved(ino_t file_node)
|
||||
{
|
||||
media_addon_id *tempid;
|
||||
media_addon_id id;
|
||||
AddOnInfo *info;
|
||||
int32 *tempflavorcount;
|
||||
int32 oldflavorcount;
|
||||
// XXX locking?
|
||||
@ -383,14 +494,22 @@ MediaAddonServer::AddOnRemoved(ino_t file_node)
|
||||
id = *tempid; // tempid pointer is invalid after Removing() it from the map
|
||||
filemap->Remove(file_node);
|
||||
|
||||
if (!flavorcountmap->Get(id, &tempflavorcount)) {
|
||||
FATAL("MediaAddonServer::AddOnRemoved: couldn't get flavor count for add-on %ld\n", id);
|
||||
if (!infomap->Get(id, &info)) {
|
||||
FATAL("MediaAddonServer::AddOnRemoved: couldn't get addon info for add-on %ld\n", id);
|
||||
oldflavorcount = 1000;
|
||||
} else {
|
||||
oldflavorcount = *tempflavorcount; //same reason as above
|
||||
}
|
||||
flavorcountmap->Remove(id);
|
||||
oldflavorcount = info->flavor_count; //same reason as above
|
||||
|
||||
DestroyInstantiatedFlavors(info);
|
||||
PutAddonIfPossible(info);
|
||||
|
||||
if (info->addon) {
|
||||
FATAL("MediaAddonServer::AddOnRemoved: couldn't unload addon %ld since flavors are in use\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
infomap->Remove(id);
|
||||
_DormantNodeManager->UnregisterAddon(id);
|
||||
|
||||
BPrivate::media::notifications::FlavorsChanged(id, 0, oldflavorcount);
|
||||
|
Loading…
Reference in New Issue
Block a user