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:
beveloper
2003-05-25 21:16:53 +00:00
parent 917d37106e
commit 359ac30644
12 changed files with 435 additions and 141 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ virtual status_t GetConfigurationFor(
BMessage * into_message); BMessage * into_message);
virtual bool WantsAutoStart(); virtual bool WantsAutoStart();
virtual status_t AutoStart( virtual status_t AutoStart(
int in_count, int in_index,
BMediaNode ** out_node, BMediaNode ** out_node,
int32 * out_internal_id, int32 * out_internal_id,
bool * out_has_more); bool * out_has_more);
+1
View File
@@ -111,6 +111,7 @@ enum {
NODE_SET_TIMESOURCE, NODE_SET_TIMESOURCE,
NODE_REQUEST_COMPLETED, NODE_REQUEST_COMPLETED,
NODE_FINAL_RELEASE, NODE_FINAL_RELEASE,
NODE_PUBLISH_CONNECTIONS,
NODE_MESSAGE_END, NODE_MESSAGE_END,
CONSUMER_MESSAGE_START = 0x300, CONSUMER_MESSAGE_START = 0x300,
+5 -1
View File
@@ -21,7 +21,11 @@
#define SYSTEM_TIMESOURCE_CONTROL_PORT -666 #define SYSTEM_TIMESOURCE_CONTROL_PORT -666
#define IS_SYSTEM_TIMESOURCE(_node) ((_node).node > 0 && (_node).port == SYSTEM_TIMESOURCE_CONTROL_PORT) #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)) #define ROUND_UP_TO_PAGE(size) (((size) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1))
+52 -8
View File
@@ -1312,7 +1312,7 @@ BMediaRoster::GetFreeOutputsFor(const media_node & node,
if (buf_num_outputs == 0) if (buf_num_outputs == 0)
break; break;
} }
MediaRosterEx(this)->PublishOutputs(node, &list); MediaRosterEx(this)->PublishOutputs(node, &list);
return B_OK; return B_OK;
} }
@@ -1550,21 +1550,38 @@ BMediaRosterEx::RegisterNode(BMediaNode * node, media_addon_id addonid, int32 fl
ts->FinishCreate(); 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 // register existing inputs and outputs with the
// media_server, this allows GetLiveNodes() to work // media_server, this allows GetLiveNodes() to work
// with created, but unconnected nodes. // with created, but unconnected nodes.
if (node->Kinds() & B_BUFFER_PRODUCER) { if (node->Kinds() & B_BUFFER_PRODUCER) {
Stack<media_output> stack; List<media_output> list;
if (B_OK == GetAllOutputs(node->Node(), &stack)) if (B_OK == GetAllOutputs(node->Node(), &list))
PublishOutputs(node->Node(), &stack); PublishOutputs(node->Node(), &list);
} else if (node->Kinds() & B_BUFFER_CONSUMER) { } else if (node->Kinds() & B_BUFFER_CONSUMER) {
Stack<media_input> stack; List<media_input> list;
if (B_OK == GetAllInputs(node->Node(), &stack)) if (B_OK == GetAllInputs(node->Node(), &list))
PublishInputs(node->Node(), &stack); PublishInputs(node->Node(), &list);
} }
*/ */
BPrivate::media::notifications::NodesCreated(&reply.nodeid, 1); 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); 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); message->SendReply(&pong, static_cast<BHandler *>(NULL), 2000000);
return; 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: case NODE_FINAL_RELEASE:
{ {
+1 -4
View File
@@ -10,10 +10,7 @@
#define _TIME_SOURCE_OBJECT_H_ #define _TIME_SOURCE_OBJECT_H_
#include <TimeSource.h> #include <TimeSource.h>
#include "MediaMisc.h"
#define NODE_KIND_USER_MASK 0x00000000FFFFFFFFLL
#define NODE_KIND_SHADOW_TIMESOURCE 0x0000000100000000LL
#define NODE_KIND_SYSTEM_TIMESOURCE 0x0000000200000000LL
namespace BPrivate { namespace media { namespace BPrivate { namespace media {
+10
View File
@@ -105,6 +105,16 @@ status_t AppManager::UnregisterTeam(team_id team)
return is_removed ? B_OK : B_ERROR; 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() void AppManager::RestartAddonServer()
{ {
static bigtime_t restart_period = 0; static bigtime_t restart_period = 0;
+2
View File
@@ -19,6 +19,8 @@ public:
void TerminateAddonServer(); void TerminateAddonServer();
team_id AddonServer(); team_id AddonServer();
status_t SendMessage(team_id team, BMessage *msg);
void Dump(); void Dump();
private: private:
+134 -52
View File
@@ -6,15 +6,18 @@
#include <MediaNode.h> #include <MediaNode.h>
#include <MediaRoster.h> #include <MediaRoster.h>
#include <string.h> #include <string.h>
#include <String.h>
#include "DefaultManager.h" #include "DefaultManager.h"
#include "NodeManager.h"
#include "debug.h" #include "debug.h"
extern NodeManager *gNodeManager;
/* no locking used in this file, we assume that the caller (NodeManager) does it. /* no locking used in this file, we assume that the caller (NodeManager) does it.
*/ */
DefaultManager::DefaultManager() DefaultManager::DefaultManager()
: fPhysicalVideoOut(-1), : fMixerConnected(false),
fPhysicalVideoOut(-1),
fPhysicalVideoIn(-1), fPhysicalVideoIn(-1),
fPhysicalAudioOut(-1), fPhysicalAudioOut(-1),
fPhysicalAudioIn(-1), fPhysicalAudioIn(-1),
@@ -153,11 +156,15 @@ void
DefaultManager::RescanThread() DefaultManager::RescanThread()
{ {
printf("DefaultManager::RescanThread() enter\n"); printf("DefaultManager::RescanThread() enter\n");
// We do not search for the system time source, // We do not search for the system time source,
// it should already exist // it should already exist
ASSERT(fSystemTimeSource != -1); 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) if (fPhysicalVideoOut == -1)
FindPhysicalVideoOut(); FindPhysicalVideoOut();
if (fPhysicalVideoIn == -1) if (fPhysicalVideoIn == -1)
@@ -168,144 +175,218 @@ DefaultManager::RescanThread()
FindPhysicalAudioIn(); FindPhysicalAudioIn();
if (fAudioMixer == -1) if (fAudioMixer == -1)
FindAudioMixer(); FindAudioMixer();
}
// The normal time source is searched for after the // The normal time source is searched for after the
// Physical Audio Out has been created. // Physical Audio Out has been created.
if (fTimeSource == -1) if (fTimeSource == -1)
FindTimeSource(); 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"); printf("DefaultManager::RescanThread() leave\n");
} }
void void
DefaultManager::FindPhysicalVideoOut() DefaultManager::FindPhysicalVideoOut()
{ {
dormant_node_info info; live_node_info info;
media_format input; /* a physical video output has a logical data input */ media_format input; /* a physical video output has a logical data input */
media_node node;
int32 count; int32 count;
status_t rv; status_t rv;
memset(&input, 0, sizeof(input)); memset(&input, 0, sizeof(input));
input.type = B_MEDIA_RAW_VIDEO; input.type = B_MEDIA_RAW_VIDEO;
count = 1; 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) { if (rv != B_OK || count != 1) {
printf("Couldn't find physical video output node\n"); printf("Couldn't find physical video output node\n");
return; return;
} }
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL); printf("Default physical video output created!\n");
if (rv != B_OK) { fPhysicalVideoOut = info.node.node;
printf("Couldn't instantiate physical video output node\n");
} else {
printf("Default physical video output created!\n");
fPhysicalVideoOut = node.node;
}
} }
void void
DefaultManager::FindPhysicalVideoIn() DefaultManager::FindPhysicalVideoIn()
{ {
dormant_node_info info; live_node_info info;
media_format output; /* a physical video input has a logical data output */ media_format output; /* a physical video input has a logical data output */
media_node node;
int32 count; int32 count;
status_t rv; status_t rv;
memset(&output, 0, sizeof(output)); memset(&output, 0, sizeof(output));
output.type = B_MEDIA_RAW_VIDEO; output.type = B_MEDIA_RAW_VIDEO;
count = 1; 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) { if (rv != B_OK || count != 1) {
printf("Couldn't find physical video input node\n"); printf("Couldn't find physical video input node\n");
return; return;
} }
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL); printf("Default physical video input created!\n");
if (rv != B_OK) { fPhysicalVideoIn = info.node.node;
printf("Couldn't instantiate physical video input node\n");
} else {
printf("Default physical video input created!\n");
fPhysicalVideoIn = node.node;
}
} }
void void
DefaultManager::FindPhysicalAudioOut() DefaultManager::FindPhysicalAudioOut()
{ {
dormant_node_info info; live_node_info info[2];
media_format input; /* a physical audio output has a logical data input */ media_format input; /* a physical audio output has a logical data input */
media_node node;
int32 count; int32 count;
status_t rv; status_t rv;
memset(&input, 0, sizeof(input)); memset(&input, 0, sizeof(input));
input.type = B_MEDIA_RAW_AUDIO; input.type = B_MEDIA_RAW_AUDIO;
count = 1; count = 2;
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT); rv = BMediaRoster::Roster()->GetLiveNodes(&info[0], &count, &input, NULL, NULL, B_BUFFER_CONSUMER | B_PHYSICAL_OUTPUT);
if (rv != B_OK || count != 1) { if (rv != B_OK || count < 1) {
printf("Couldn't find physical audio output node\n"); printf("Couldn't find physical audio output node\n");
return; return;
} }
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL); for (int i = 0; i < count; i++)
if (rv != B_OK) { printf("info[%d].name %s\n", i, info[i].name);
printf("Couldn't instantiate physical audio output node\n");
} else { 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"); printf("Default physical audio output created!\n");
fPhysicalAudioOut = node.node; fPhysicalAudioOut = info[i].node.node;
return;
} }
} }
void void
DefaultManager::FindPhysicalAudioIn() DefaultManager::FindPhysicalAudioIn()
{ {
dormant_node_info info; live_node_info info[2];
media_format output; /* a physical audio input has a logical data output */ media_format output; /* a physical audio input has a logical data output */
media_node node;
int32 count; int32 count;
status_t rv; status_t rv;
memset(&output, 0, sizeof(output)); memset(&output, 0, sizeof(output));
output.type = B_MEDIA_RAW_AUDIO; output.type = B_MEDIA_RAW_AUDIO;
count = 1; count = 2;
rv = BMediaRoster::Roster()->GetDormantNodes(&info, &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT); rv = BMediaRoster::Roster()->GetLiveNodes(&info[0], &count, NULL, &output, NULL, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
if (rv != B_OK || count != 1) { if (rv != B_OK || count < 1) {
printf("Couldn't find physical audio input node\n"); printf("Couldn't find physical audio input node\n");
return; return;
} }
rv = BMediaRoster::Roster()->InstantiateDormantNode(info, &node, B_FLAVOR_IS_GLOBAL); for (int i = 0; i < count; i++)
if (rv != B_OK) { printf("info[%d].name %s\n", i, info[i].name);
printf("Couldn't instantiate physical audio input node\n");
} else { 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"); printf("Default physical audio input created!\n");
fPhysicalAudioIn = node.node; fPhysicalAudioIn = info[i].node.node;
return;
} }
} }
void void
DefaultManager::FindTimeSource() 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 void
DefaultManager::FindAudioMixer() DefaultManager::FindAudioMixer()
{ {
dormant_node_info info; live_node_info info;
media_node node;
int32 count; int32 count;
status_t rv; status_t rv;
count = 1; 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) { if (rv != B_OK || count != 1) {
printf("Couldn't find audio mixer node\n"); printf("Couldn't find audio mixer node\n");
return; 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) { if (rv != B_OK) {
printf("Couldn't instantiate audio mixer node\n"); printf("DefaultManager: failed to find soundcard (physical audio output)\n");
} else { return B_ERROR;
printf("Default audio mixer created!\n");
fAudioMixer = node.node;
} }
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 void
@@ -317,3 +398,4 @@ void
DefaultManager::CleanupTeam(team_id team) DefaultManager::CleanupTeam(team_id team)
{ {
} }
+11 -8
View File
@@ -35,14 +35,17 @@ private:
void FindAudioMixer(); void FindAudioMixer();
void FindTimeSource(); void FindTimeSource();
status_t ConnectMixerToOutput();
private: private:
media_node_id fPhysicalVideoOut; volatile bool fMixerConnected;
media_node_id fPhysicalVideoIn; volatile media_node_id fPhysicalVideoOut;
media_node_id fPhysicalAudioOut; volatile media_node_id fPhysicalVideoIn;
media_node_id fPhysicalAudioIn; volatile media_node_id fPhysicalAudioOut;
media_node_id fSystemTimeSource; volatile media_node_id fPhysicalAudioIn;
media_node_id fTimeSource; volatile media_node_id fSystemTimeSource;
media_node_id fAudioMixer; volatile media_node_id fTimeSource;
int32 fPhysicalAudioOutInputID; volatile media_node_id fAudioMixer;
volatile int32 fPhysicalAudioOutInputID;
char fPhysicalAudioOutInputName[B_MEDIA_NAME_LENGTH]; char fPhysicalAudioOutInputName[B_MEDIA_NAME_LENGTH];
}; };
+32 -2
View File
@@ -43,6 +43,7 @@ static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@O
#include "NodeManager.h" #include "NodeManager.h"
#include "DefaultManager.h" #include "DefaultManager.h"
#include "AppManager.h" #include "AppManager.h"
#include "MediaMisc.h"
extern AppManager *gAppManager; extern AppManager *gAppManager;
@@ -411,7 +412,7 @@ NodeManager::GetDormantNodeInfo(dormant_node_info *node_info, const media_node &
return B_ERROR; return B_ERROR;
} }
ASSERT(node.port == rn->port); 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->addon = rn->addon_id;
node_info->flavor_id = rn->addon_flavor_id; node_info->flavor_id = rn->addon_flavor_id;
strcpy(node_info->name, rn->name); 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); ) { for (fRegisteredNodeMap->Rewind(); fRegisteredNodeMap->GetNext(&rn); ) {
if (rn->nodeid == node.node) { if (rn->nodeid == node.node) {
ASSERT(node.port == rn->port); 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->node = node;
live_info->hint_point = BPoint(0, 0); live_info->hint_point = BPoint(0, 0);
strcpy(live_info->name, rn->name); strcpy(live_info->name, rn->name);
@@ -468,6 +469,9 @@ NodeManager::GetLiveNodes(Stack<live_node_info> *livenodes, int32 maxcount, cons
BAutolock lock(fLocker); BAutolock lock(fLocker);
registered_node *rn; registered_node *rn;
int namelen; 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 // determine the count of byte to compare when checking for a name with(out) wildcard
if (name) { if (name) {
@@ -539,6 +543,28 @@ NodeManager::GetLiveNodes(BMessage *msg)
return B_OK; 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 * 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", 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); 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; media_output *output;
for (rn->outputlist.Rewind(); rn->outputlist.GetNext(&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", 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); 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("NodeManager: list end\n");
printf("\n"); printf("\n");
+2
View File
@@ -105,6 +105,8 @@ public:
void CleanupTeam(team_id team); void CleanupTeam(team_id team);
void UpdateNodeConnections();
private: private:
media_addon_id fNextAddOnID; media_addon_id fNextAddOnID;
media_node_id fNextNodeID; media_node_id fNextNodeID;
+184 -65
View File
@@ -55,6 +55,17 @@ static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@O
void DumpFlavorInfo(const flavor_info *info); 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 class MediaAddonServer : BApplication
{ {
public: public:
@@ -68,11 +79,16 @@ public:
void AddOnRemoved(ino_t file_node); void AddOnRemoved(ino_t file_node);
void HandleMessage(int32 code, const void *data, size_t size); void HandleMessage(int32 code, const void *data, size_t size);
static int32 controlthread(void *arg); 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); void ScanAddOnFlavors(BMediaAddOn *addon);
Map<ino_t, media_addon_id> *filemap; Map<ino_t, media_addon_id> *filemap;
Map<media_addon_id, int32> *flavorcountmap; Map<media_addon_id, AddOnInfo> *infomap;
BMediaRoster *mediaroster; BMediaRoster *mediaroster;
ino_t DirNodeSystem; ino_t DirNodeSystem;
@@ -88,9 +104,9 @@ MediaAddonServer::MediaAddonServer(const char *sig) :
{ {
mediaroster = BMediaRoster::Roster(); mediaroster = BMediaRoster::Roster();
filemap = new Map<ino_t, media_addon_id>; filemap = new Map<ino_t, media_addon_id>;
flavorcountmap = new Map<media_addon_id, int32>; infomap = new Map<media_addon_id, AddOnInfo>;
control_port = create_port(64,"media_addon_server port"); control_port = create_port(64, "media_addon_server port");
control_thread = spawn_thread(controlthread,"media_addon_server control",12,this); control_thread = spawn_thread(controlthread, "media_addon_server control", 12, this);
resume_thread(control_thread); resume_thread(control_thread);
} }
@@ -106,7 +122,7 @@ MediaAddonServer::~MediaAddonServer()
_DormantNodeManager->UnregisterAddon(*id); _DormantNodeManager->UnregisterAddon(*id);
delete filemap; delete filemap;
delete flavorcountmap; delete infomap;
} }
void void
@@ -160,6 +176,10 @@ MediaAddonServer::controlthread(void *arg)
void void
MediaAddonServer::ReadyToRun() 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 // register with media_server
server_register_addonserver_request request; server_register_addonserver_request request;
server_register_addonserver_reply reply; server_register_addonserver_reply reply;
@@ -172,7 +192,13 @@ MediaAddonServer::ReadyToRun()
return; 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 // load dormant media nodes
node_ref nref; node_ref nref;
@@ -191,7 +217,21 @@ MediaAddonServer::ReadyToRun()
WatchDir(&e2); WatchDir(&e2);
fStartup = false; 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; server_rescan_defaults_command cmd;
SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd)); SendToServer(SERVER_RESCAN_DEFAULTS, &cmd, sizeof(cmd));
} }
@@ -199,7 +239,7 @@ MediaAddonServer::ReadyToRun()
void void
MediaAddonServer::ScanAddOnFlavors(BMediaAddOn *addon) MediaAddonServer::ScanAddOnFlavors(BMediaAddOn *addon)
{ {
int32 *flavorcount; AddOnInfo *info;
int32 oldflavorcount; int32 oldflavorcount;
int32 newflavorcount; int32 newflavorcount;
media_addon_id addon_id; media_addon_id addon_id;
@@ -223,11 +263,11 @@ MediaAddonServer::ScanAddOnFlavors(BMediaAddOn *addon)
addon_id = addon->AddonID(); addon_id = addon->AddonID();
// update the cached flavor count, get oldflavorcount and newflavorcount // update the cached flavor count, get oldflavorcount and newflavorcount
b = flavorcountmap->Get(addon->AddonID(), &flavorcount); b = infomap->Get(addon_id, &info);
ASSERT(b); ASSERT(b);
oldflavorcount = *flavorcount; oldflavorcount = info->flavor_count;
newflavorcount = addon->CountFlavors(); newflavorcount = addon->CountFlavors();
*flavorcount = newflavorcount; info->flavor_count = newflavorcount;
TRACE("%ld old flavors, %ld new flavors\n", oldflavorcount, 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; return;
} }
TRACE("MediaAddonServer::AddOnAdded: loading addon %d now...\n", id);
addon = _DormantNodeManager->GetAddon(id); addon = _DormantNodeManager->GetAddon(id);
if (addon == NULL) { if (addon == NULL) {
FATAL("MediaAddonServer::AddOnAdded: failed to get add-on %s\n", path); 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); TRACE("MediaAddonServer::AddOnAdded: loading finished, id %ld\n", id);
// put file's inode and addon's id into map
filemap->Insert(file_node, id); 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); FATAL("#### add-on %ld WantsAutoStart!\n", id);
/* // During startup, first all add-ons are loaded, then all
* the mixer (which we can't load because of unresolved symbols) // nodes (flavors) representing physical inputs and outputs
* is the only node that uses autostart (which is not implemented yet) // 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.
/*
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;
}
*/
// After startup is done, we simply do it for each new
// loaded add-on, too.
if (!fStartup) { if (!fStartup) {
InstantiatePhysialInputsAndOutputs(info);
InstantiateAutostartFlavors(info);
PutAddonIfPossible(info);
// since something might have changed
server_rescan_defaults_command cmd; 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 void
MediaAddonServer::AddOnRemoved(ino_t file_node) MediaAddonServer::AddOnRemoved(ino_t file_node)
{ {
media_addon_id *tempid; media_addon_id *tempid;
media_addon_id id; media_addon_id id;
AddOnInfo *info;
int32 *tempflavorcount; int32 *tempflavorcount;
int32 oldflavorcount; int32 oldflavorcount;
// XXX locking? // XXX locking?
@@ -383,14 +494,22 @@ MediaAddonServer::AddOnRemoved(ino_t file_node)
id = *tempid; // tempid pointer is invalid after Removing() it from the map id = *tempid; // tempid pointer is invalid after Removing() it from the map
filemap->Remove(file_node); filemap->Remove(file_node);
if (!flavorcountmap->Get(id, &tempflavorcount)) { if (!infomap->Get(id, &info)) {
FATAL("MediaAddonServer::AddOnRemoved: couldn't get flavor count for add-on %ld\n", id); FATAL("MediaAddonServer::AddOnRemoved: couldn't get addon info for add-on %ld\n", id);
oldflavorcount = 1000; oldflavorcount = 1000;
} else { } else {
oldflavorcount = *tempflavorcount; //same reason as above oldflavorcount = info->flavor_count; //same reason as above
}
flavorcountmap->Remove(id);
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); _DormantNodeManager->UnregisterAddon(id);
BPrivate::media::notifications::FlavorsChanged(id, 0, oldflavorcount); BPrivate::media::notifications::FlavorsChanged(id, 0, oldflavorcount);