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

View File

@ -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);

View File

@ -111,6 +111,7 @@ enum {
NODE_SET_TIMESOURCE,
NODE_REQUEST_COMPLETED,
NODE_FINAL_RELEASE,
NODE_PUBLISH_CONNECTIONS,
NODE_MESSAGE_END,
CONSUMER_MESSAGE_START = 0x300,

View File

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

View File

@ -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:
{

View File

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

View File

@ -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;

View File

@ -19,6 +19,8 @@ public:
void TerminateAddonServer();
team_id AddonServer();
status_t SendMessage(team_id team, BMessage *msg);
void Dump();
private:

View File

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

View File

@ -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];
};

View File

@ -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");

View File

@ -105,6 +105,8 @@ public:
void CleanupTeam(team_id team);
void UpdateNodeConnections();
private:
media_addon_id fNextAddOnID;
media_node_id fNextNodeID;

View File

@ -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);