#include "DormantNodeManager.h"
#include <stdio.h>
#include <string.h>
#include <Autolock.h>
#include <Entry.h>
#include <Path.h>
#include <MediaDebug.h>
#include <MediaMisc.h>
#include <ServerInterface.h>
#include <DataExchange.h>
namespace BPrivate {
namespace media {
DormantNodeManager* gDormantNodeManager;
DormantNodeManager::DormantNodeManager()
:
fLock("dormant node manager locker")
{
}
DormantNodeManager::~DormantNodeManager()
{
AddOnMap::iterator iterator = fAddOnMap.begin();
for (; iterator != fAddOnMap.end(); iterator++) {
loaded_add_on_info& info = iterator->second;
ERROR("Forcing unload of add-on id %" B_PRId32 " with usecount %"
B_PRId32 "\n", info.add_on->AddonID(), info.use_count);
_UnloadAddOn(info.add_on, info.image);
}
}
BMediaAddOn*
DormantNodeManager::GetAddOn(media_addon_id id)
{
TRACE("DormantNodeManager::GetAddon, id %" B_PRId32 "\n", id);
BMediaAddOn* addOn = _LookupAddOn(id);
if (addOn != NULL)
return addOn;
BPath path;
if (FindAddOnPath(&path, id) != B_OK) {
ERROR("DormantNodeManager::GetAddon: can't find path for add-on %"
B_PRId32 "\n", id);
return NULL;
}
BMediaAddOn* newAddOn;
image_id image;
if (_LoadAddOn(path.Path(), id, &newAddOn, &image) != B_OK) {
ERROR("DormantNodeManager::GetAddon: can't load add-on %" B_PRId32
" from path %s\n",id, path.Path());
return NULL;
}
BAutolock _(fLock);
addOn = _LookupAddOn(id);
if (addOn == NULL) {
addOn = newAddOn;
loaded_add_on_info info;
info.add_on = newAddOn;
info.image = image;
info.use_count = 1;
try {
fAddOnMap.insert(std::make_pair(id, info));
} catch (std::bad_alloc& exception) {
_UnloadAddOn(newAddOn, image);
return NULL;
}
} else
_UnloadAddOn(newAddOn, image);
ASSERT(addOn->AddonID() == id);
return addOn;
}
void
DormantNodeManager::PutAddOn(media_addon_id id)
{
TRACE("DormantNodeManager::PutAddon, id %" B_PRId32 "\n", id);
BAutolock locker(fLock);
AddOnMap::iterator found = fAddOnMap.find(id);
if (found == fAddOnMap.end()) {
ERROR("DormantNodeManager::PutAddon: failed to find add-on %" B_PRId32
"\n", id);
return;
}
loaded_add_on_info& info = found->second;
if (--info.use_count == 0) {
BMediaAddOn* addOn = info.add_on;
image_id image = info.image;
fAddOnMap.erase(found);
locker.Unlock();
_UnloadAddOn(addOn, image);
}
}
void
DormantNodeManager::PutAddOnDelayed(media_addon_id id)
{
UNIMPLEMENTED();
}
media_addon_id
DormantNodeManager::RegisterAddOn(const char* path)
{
TRACE("DormantNodeManager::RegisterAddon, path %s\n", path);
entry_ref ref;
status_t status = get_ref_for_path(path, &ref);
if (status != B_OK) {
ERROR("DormantNodeManager::RegisterAddon failed, couldn't get ref "
"for path %s: %s\n", path, strerror(status));
return 0;
}
server_register_add_on_request request;
request.ref = ref;
server_register_add_on_reply reply;
status = QueryServer(SERVER_REGISTER_ADD_ON, &request, sizeof(request),
&reply, sizeof(reply));
if (status != B_OK) {
ERROR("DormantNodeManager::RegisterAddon failed, couldn't talk to "
"media server: %s\n", strerror(status));
return 0;
}
TRACE("DormantNodeManager::RegisterAddon finished with id %" B_PRId32 "\n",
reply.add_on_id);
return reply.add_on_id;
}
void
DormantNodeManager::UnregisterAddOn(media_addon_id id)
{
TRACE("DormantNodeManager::UnregisterAddon id %" B_PRId32 "\n", id);
ASSERT(id > 0);
port_id port = find_port(MEDIA_SERVER_PORT_NAME);
if (port < 0)
return;
server_unregister_add_on_command msg;
msg.add_on_id = id;
write_port(port, SERVER_UNREGISTER_ADD_ON, &msg, sizeof(msg));
}
status_t
DormantNodeManager::FindAddOnPath(BPath* path, media_addon_id id)
{
server_get_add_on_ref_request request;
request.add_on_id = id;
server_get_add_on_ref_reply reply;
status_t status = QueryServer(SERVER_GET_ADD_ON_REF, &request,
sizeof(request), &reply, sizeof(reply));
if (status != B_OK)
return status;
entry_ref ref = reply.ref;
return path->SetTo(&ref);
}
BMediaAddOn*
DormantNodeManager::_LookupAddOn(media_addon_id id)
{
BAutolock _(fLock);
AddOnMap::iterator found = fAddOnMap.find(id);
if (found == fAddOnMap.end())
return NULL;
loaded_add_on_info& info = found->second;
ASSERT(id == info.add_on->AddonID());
info.use_count++;
return info.add_on;
}
status_t
DormantNodeManager::_LoadAddOn(const char* path, media_addon_id id,
BMediaAddOn** _newAddOn, image_id* _newImage)
{
image_id image = load_add_on(path);
if (image < 0) {
ERROR("DormantNodeManager::LoadAddon: loading \"%s\" failed: %s\n",
path, strerror(image));
return image;
}
BMediaAddOn* (*makeAddOn)(image_id);
status_t status = get_image_symbol(image, "make_media_addon",
B_SYMBOL_TYPE_TEXT, (void**)&makeAddOn);
if (status != B_OK) {
ERROR("DormantNodeManager::LoadAddon: loading failed, function not "
"found: %s\n", strerror(status));
unload_add_on(image);
return status;
}
BMediaAddOn* addOn = makeAddOn(image);
if (addOn == NULL) {
ERROR("DormantNodeManager::LoadAddon: creating BMediaAddOn failed\n");
unload_add_on(image);
return B_ERROR;
}
ASSERT(addOn->ImageID() == image);
addOn->fAddon = id;
addOn->fImage = image;
*_newAddOn = addOn;
*_newImage = image;
return B_OK;
}
void
DormantNodeManager::_UnloadAddOn(BMediaAddOn* addOn, image_id image)
{
ASSERT(addOn != NULL);
ASSERT(addOn->ImageID() == image);
delete addOn;
unload_add_on(image);
}
}
}