Files
haiku-beta6/src/servers/media/media_server.cpp
T
beveloper 353b9f6bce changed map and list templates to be more useable, however, they will
be rewritten soon. Changed debugging macros and use of them, too.
Also replaced the linked lists in the BufferManager (which were complicated,
but working ok) with template based ones.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2133 a95241bf-73f2-0310-859d-f6bbb57e9c96
2002-12-03 00:59:42 +00:00

583 lines
20 KiB
C++

#include <Application.h>
#include <stdio.h>
#include <Messenger.h>
#include <MediaDefs.h>
#include <MediaFormats.h>
#include <Autolock.h>
#include "NotificationManager.h"
#include "ServerInterface.h"
#include "DataExchange.h"
#include "BufferManager.h"
#include "NodeManager.h"
#include "AppManager.h"
#include "media_server.h"
#include "debug.h"
/*
*
* An implementation of a new media_server for the OpenBeOS MediaKit
* Started by Marcus Overhagen <[email protected]> on 2001-10-25
*
* Communication with the OpenBeOS libmedia.so is done using BMessages
* sent to the server application, handled in XXX()
* functions. A simple BMessage reply is beeing send back.
*
*
* function names and class structure is loosely
* based on information acquired using:
* nm --demangle /boot/beos/system/servers/media_server | grep Server | sort
* nm --demangle /boot/beos/system/servers/media_server | grep Manager | sort
*
*/
NotificationManager *gNotificationManager;
BufferManager *gBufferManager;
AppManager *gAppManager;
NodeManager *gNodeManager;
#define REPLY_TIMEOUT ((bigtime_t)500000)
class ServerApp : BApplication
{
public:
ServerApp();
~ServerApp();
bool QuitRequested();
void HandleMessage(int32 code, void *data, size_t size);
static int32 controlthread(void *arg);
void GetSharedBufferArea(BMessage *msg);
void RegisterBuffer(BMessage *msg);
void UnregisterBuffer(BMessage *msg);
/* functionality not yet implemented
00014a00 T _ServerApp::_ServerApp(void)
00014e1c T _ServerApp::~_ServerApp(void)
00014ff4 T _ServerApp::MessageReceived(BMessage *);
00015840 T _ServerApp::QuitRequested(void)
00015b50 T _ServerApp::_DoNotify(command_data *)
00015d18 T _ServerApp::_UnregisterApp(long, bool)
00018e90 T _ServerApp::AddOnHost(void)
00019530 T _ServerApp::AboutRequested(void)
00019d04 T _ServerApp::AddPurgableBufferGroup(long, long, long, void *)
00019db8 T _ServerApp::CancelPurgableBufferGroupCleanup(long)
00019e50 T _ServerApp::DirtyWork(void)
0001a4bc T _ServerApp::ArgvReceived(long, char **)
0001a508 T _ServerApp::CleanupPurgedBufferGroup(_ServerApp::purgable_buffer_group const &, bool)
0001a5dc T _ServerApp::DirtyWorkLaunch(void *)
0001a634 T _ServerApp::SetQuitMode(bool)
0001a648 T _ServerApp::IsQuitMode(void) const
0001a658 T _ServerApp::BroadcastCurrentStateTo(BMessenger &)
0001adcc T _ServerApp::ReadyToRun(void)
*/
private:
port_id control_port;
thread_id control_thread;
BLocker *fLocker;
void MessageReceived(BMessage *msg);
typedef BApplication inherited;
};
ServerApp::ServerApp()
: BApplication(NEW_MEDIA_SERVER_SIGNATURE),
fLocker(new BLocker("media server locker"))
{
//load volume settings from config file
//mVolumeLeft = ???;
//mVolumeRight = ???;
gNotificationManager = new NotificationManager;
gBufferManager = new BufferManager;
gAppManager = new AppManager;
gNodeManager = new NodeManager;
control_port = create_port(64,"media_server port");
control_thread = spawn_thread(controlthread, "media_server control", 105, this);
resume_thread(control_thread);
gAppManager->StartAddonServer();
}
ServerApp::~ServerApp()
{
TRACE("ServerApp::~ServerApp()\n");
delete gNotificationManager;
delete gBufferManager;
delete gAppManager;
delete gNodeManager;
delete fLocker;
delete_port(control_port);
status_t err;
wait_for_thread(control_thread,&err);
}
bool
ServerApp::QuitRequested()
{
TRACE("ServerApp::QuitRequested()\n");
gAppManager->TerminateAddonServer();
return true;
}
void
ServerApp::HandleMessage(int32 code, void *data, size_t size)
{
status_t rv;
INFO("ServerApp::HandleMessage %#lx\n", code);
switch (code) {
case SERVER_REGISTER_ADDONSERVER:
{
const server_register_addonserver_request *request = reinterpret_cast<const server_register_addonserver_request *>(data);
server_register_addonserver_reply reply;
rv = gAppManager->RegisterAddonServer(request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_REGISTER_APP:
{
const server_register_app_request *request = reinterpret_cast<const server_register_app_request *>(data);
server_register_app_reply reply;
rv = gAppManager->RegisterTeam(request->team, request->messenger);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_UNREGISTER_APP:
{
const server_unregister_app_request *request = reinterpret_cast<const server_unregister_app_request *>(data);
server_unregister_app_reply reply;
rv = gAppManager->UnregisterTeam(request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_GET_MEDIAADDON_REF:
{
server_get_mediaaddon_ref_request *msg = (server_get_mediaaddon_ref_request *)data;
server_get_mediaaddon_ref_reply reply;
entry_ref tempref;
reply.result = gNodeManager->GetAddonRef(&tempref, msg->addonid);
reply.ref = tempref;
write_port(msg->reply_port, 0, &reply, sizeof(reply));
break;
}
case SERVER_NODE_ID_FOR:
{
const server_node_id_for_request *request = reinterpret_cast<const server_node_id_for_request *>(data);
server_node_id_for_reply reply;
rv = gNodeManager->FindNodeId(&reply.nodeid, request->port);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_GET_LIVE_NODE_INFO:
{
const server_get_live_node_info_request *request = reinterpret_cast<const server_get_live_node_info_request *>(data);
server_get_live_node_info_reply reply;
rv = gNodeManager->GetLiveNodeInfo(&reply.live_info, request->node);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_GET_LIVE_NODES:
{
const server_get_live_nodes_request *request = reinterpret_cast<const server_get_live_nodes_request *>(data);
server_get_live_nodes_reply reply;
Stack<live_node_info> livenodes;
rv = gNodeManager->GetLiveNodes(
&livenodes,
request->maxcount,
request->has_input ? &request->inputformat : NULL,
request->has_output ? &request->outputformat : NULL,
request->has_name ? request->name : NULL,
request->require_kinds);
reply.count = livenodes.CountItems();
if (reply.count <= MAX_LIVE_INFO) {
for (int32 index = 0; index < reply.count; index++)
livenodes.Pop(&reply.live_info[index]);
reply.area = -1;
} else {
// we create an area here, and pass it to the library, where it will be deleted.
live_node_info *start_addr;
size_t size;
size = ((reply.count * sizeof(live_node_info)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
reply.area = create_area("get live nodes", reinterpret_cast<void **>(&start_addr), B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (reply.area < B_OK) {
FATAL("SERVER_GET_LIVE_NODES: failed to create area, %#lx\n", reply.area);
reply.count = 0;
rv = B_ERROR;
} else {
for (int32 index = 0; index < reply.count; index++)
livenodes.Pop(&start_addr[index]);
}
}
rv = request->SendReply(rv, &reply, sizeof(reply));
if (rv != B_OK)
delete_area(reply.area); // if we couldn't send the message, delete the area
break;
}
case SERVER_GET_NODE_FOR:
{
const server_get_node_for_request *request = reinterpret_cast<const server_get_node_for_request *>(data);
server_get_node_for_reply reply;
rv = gNodeManager->GetCloneForId(&reply.clone, request->nodeid, request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_RELEASE_NODE:
{
const server_release_node_request *request = reinterpret_cast<const server_release_node_request *>(data);
server_release_node_reply reply;
rv = gNodeManager->ReleaseNode(request->node, request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_REGISTER_NODE:
{
const server_register_node_request *request = reinterpret_cast<const server_register_node_request *>(data);
server_register_node_reply reply;
rv = gNodeManager->RegisterNode(&reply.nodeid, request->addon_id, request->addon_flavor_id, request->name, request->kinds, request->port, request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_UNREGISTER_NODE:
{
const server_unregister_node_request *request = reinterpret_cast<const server_unregister_node_request *>(data);
server_unregister_node_reply reply;
rv = gNodeManager->UnregisterNode(&reply.addon_id, request->nodeid, request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_PUBLISH_INPUTS:
{
const server_publish_inputs_request *request = reinterpret_cast<const server_publish_inputs_request *>(data);
server_publish_inputs_reply reply;
if (request->count <= MAX_INPUTS) {
rv = gNodeManager->PublishInputs(request->node, request->inputs, request->count);
} else {
media_input *inputs;
area_id clone;
clone = clone_area("media_inputs clone", reinterpret_cast<void **>(&inputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
if (clone < B_OK) {
FATAL("SERVER_PUBLISH_INPUTS: failed to clone area, %#lx\n", clone);
rv = B_ERROR;
} else {
rv = gNodeManager->PublishInputs(request->node, inputs, request->count);
delete_area(clone);
}
}
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_PUBLISH_OUTPUTS:
{
const server_publish_outputs_request *request = reinterpret_cast<const server_publish_outputs_request *>(data);
server_publish_outputs_reply reply;
if (request->count <= MAX_OUTPUTS) {
rv = gNodeManager->PublishOutputs(request->node, request->outputs, request->count);
} else {
media_output *outputs;
area_id clone;
clone = clone_area("media_outputs clone", reinterpret_cast<void **>(&outputs), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, request->area);
if (clone < B_OK) {
FATAL("SERVER_PUBLISH_OUTPUTS: failed to clone area, %#lx\n", clone);
rv = B_ERROR;
} else {
rv = gNodeManager->PublishOutputs(request->node, outputs, request->count);
delete_area(clone);
}
}
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_GET_NODE:
{
const server_get_node_request *request = reinterpret_cast<const server_get_node_request *>(data);
server_get_node_reply reply;
rv = gNodeManager->GetClone(&reply.node, reply.input_name, &reply.input_id, request->type, request->team);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_SET_NODE:
{
const server_set_node_request *request = reinterpret_cast<const server_set_node_request *>(data);
server_set_node_reply reply;
// XXX do something here
debugger("SERVER_SET_NODE seems to be needed\n");
request->SendReply(B_OK, &reply, sizeof(reply));
break;
}
case SERVER_GET_DORMANT_NODE_FOR:
{
const server_get_dormant_node_for_request *request = reinterpret_cast<const server_get_dormant_node_for_request *>(data);
server_get_dormant_node_for_reply reply;
rv = gNodeManager->GetDormantNodeInfo(&reply.node_info, request->node);
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_GET_INSTANCES_FOR:
{
const server_get_instances_for_request *request = reinterpret_cast<const server_get_instances_for_request *>(data);
server_get_instances_for_reply reply;
rv = gNodeManager->GetInstances(reply.node_id, &reply.count, min_c(request->maxcount, MAX_NODE_ID), request->addon_id, request->addon_flavor_id);
if (reply.count == MAX_NODE_ID && request->maxcount > MAX_NODE_ID) { // XXX might be fixed by using an area
FATAL("SERVER_GET_INSTANCES_FOR: WARNING! returning possibly truncated list of node id's\n");
}
request->SendReply(rv, &reply, sizeof(reply));
break;
}
case SERVER_REGISTER_MEDIAADDON:
{
server_register_mediaaddon_request *msg = (server_register_mediaaddon_request *)data;
server_register_mediaaddon_reply reply;
gNodeManager->RegisterAddon(msg->ref, &reply.addonid);
write_port(msg->reply_port, 0, &reply, sizeof(reply));
break;
}
case SERVER_UNREGISTER_MEDIAADDON:
{
server_unregister_mediaaddon_command *msg = (server_unregister_mediaaddon_command *)data;
gNodeManager->UnregisterAddon(msg->addonid);
break;
}
case SERVER_REGISTER_DORMANT_NODE:
{
xfer_server_register_dormant_node *msg = (xfer_server_register_dormant_node *)data;
dormant_flavor_info dfi;
if (msg->purge_id > 0)
gNodeManager->RemoveDormantFlavorInfo(msg->purge_id);
rv = dfi.Unflatten(msg->dfi_type, &(msg->dfi), msg->dfi_size);
ASSERT(rv == B_OK);
gNodeManager->AddDormantFlavorInfo(dfi);
break;
}
case SERVER_GET_DORMANT_NODES:
{
xfer_server_get_dormant_nodes *msg = (xfer_server_get_dormant_nodes *)data;
xfer_server_get_dormant_nodes_reply reply;
dormant_node_info * infos = new dormant_node_info[msg->maxcount];
reply.count = msg->maxcount;
reply.result = gNodeManager->GetDormantNodes(
infos,
&reply.count,
msg->has_input ? &msg->inputformat : NULL,
msg->has_output ? &msg->outputformat : NULL,
msg->has_name ? msg->name : NULL,
msg->require_kinds,
msg->deny_kinds);
if (reply.result != B_OK)
reply.count = 0;
write_port(msg->reply_port, 0, &reply, sizeof(reply));
if (reply.count > 0)
write_port(msg->reply_port, 0, infos, reply.count * sizeof(dormant_node_info));
delete [] infos;
break;
}
case SERVER_GET_DORMANT_FLAVOR_INFO:
{
xfer_server_get_dormant_flavor_info *msg = (xfer_server_get_dormant_flavor_info *)data;
dormant_flavor_info dfi;
status_t rv;
rv = gNodeManager->GetDormantFlavorInfoFor(msg->addon, msg->flavor_id, &dfi);
if (rv != B_OK) {
xfer_server_get_dormant_flavor_info_reply reply;
reply.result = rv;
write_port(msg->reply_port, 0, &reply, sizeof(reply));
} else {
xfer_server_get_dormant_flavor_info_reply *reply;
int replysize;
replysize = sizeof(xfer_server_get_dormant_flavor_info_reply) + dfi.FlattenedSize();
reply = (xfer_server_get_dormant_flavor_info_reply *)malloc(replysize);
reply->dfi_size = dfi.FlattenedSize();
reply->dfi_type = dfi.TypeCode();
reply->result = dfi.Flatten(reply->dfi, reply->dfi_size);
write_port(msg->reply_port, 0, reply, replysize);
free(reply);
}
break;
}
default:
printf("media_server: received unknown message code %#08lx\n",code);
}
}
int32
ServerApp::controlthread(void *arg)
{
char data[B_MEDIA_MESSAGE_SIZE];
ServerApp *app;
ssize_t size;
int32 code;
app = (ServerApp *)arg;
while ((size = read_port_etc(app->control_port, &code, data, sizeof(data), 0, 0)) > 0)
app->HandleMessage(code, data, size);
return 0;
}
void
ServerApp::GetSharedBufferArea(BMessage *msg)
{
BMessage reply(B_OK);
reply.AddInt32("area",gBufferManager->SharedBufferListID());
msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT);
}
void
ServerApp::RegisterBuffer(BMessage *msg)
{
team_id teamid;
media_buffer_id bufferid;
size_t size;
int32 flags;
size_t offset;
area_id area;
status_t status;
//msg->PrintToStream();
teamid = msg->FindInt32("team");
area = msg->FindInt32("area");
offset = msg->FindInt32("offset");
size = msg->FindInt32("size");
flags = msg->FindInt32("flags");
bufferid = msg->FindInt32("buffer");
//TRACE("ServerApp::RegisterBuffer team = 0x%08x, areaid = 0x%08x, offset = 0x%08x, size = 0x%08x, flags = 0x%08x, buffer = 0x%08x\n",(int)teamid,(int)area,(int)offset,(int)size,(int)flags,(int)bufferid);
if (bufferid == 0)
status = gBufferManager->RegisterBuffer(teamid, size, flags, offset, area, &bufferid);
else
status = gBufferManager->RegisterBuffer(teamid, bufferid, &size, &flags, &offset, &area);
BMessage reply(status);
reply.AddInt32("buffer",bufferid);
reply.AddInt32("size",size);
reply.AddInt32("flags",flags);
reply.AddInt32("offset",offset);
reply.AddInt32("area",area);
msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT);
}
void
ServerApp::UnregisterBuffer(BMessage *msg)
{
team_id teamid;
media_buffer_id bufferid;
status_t status;
teamid = msg->FindInt32("team");
bufferid = msg->FindInt32("buffer");
status = gBufferManager->UnregisterBuffer(teamid, bufferid);
BMessage reply(status);
msg->SendReply(&reply,(BHandler*)NULL,REPLY_TIMEOUT);
}
void ServerApp::MessageReceived(BMessage *msg)
{
switch (msg->what) {
case MEDIA_SERVER_GET_SHARED_BUFFER_AREA: GetSharedBufferArea(msg); break;
case MEDIA_SERVER_REGISTER_BUFFER: RegisterBuffer(msg); break;
case MEDIA_SERVER_UNREGISTER_BUFFER: UnregisterBuffer(msg); break;
case MEDIA_SERVER_REQUEST_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break;
case MEDIA_SERVER_CANCEL_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break;
case MEDIA_SERVER_SEND_NOTIFICATIONS: gNotificationManager->EnqueueMessage(msg); break;
default:
printf("\nnew media server: unknown message received\n");
msg->PrintToStream();
}
}
int main()
{
new ServerApp;
be_app->Run();
delete be_app;
return 0;
}
/*
0001e260 T MBufferManager::MBufferManager(void)
0001e47c T MBufferManager::~MBufferManager(void)
0001e540 T MBufferManager::PrintToStream(void)
0001e6fc T MBufferManager::RecycleBuffersWithOwner(long, long)
0001ea00 T MBufferManager::RegisterBuffer(long, buffer_clone_info const *, long *, media_source const &)
0001f090 T MBufferManager::AcquireBuffer(long, long, media_source)
0001f28c T MBufferManager::ReleaseBuffer(long, long, bool, BMessage *, char const *)
0001fd0c T MBufferManager::PurgeTeamBufferGroups(long)
0001fdf0 T MBufferManager::RegisterBufferGroup(BMessage *, char const *, long)
0002007c T MBufferManager::_RemoveGroupFromClaimants(long, long, void *)
00020158 T MBufferManager::UnregisterBufferGroup(BMessage *, char const *, long)
0002028c T MBufferManager::_UnregisterBufferGroup(long, long)
000206f4 T MBufferManager::AddBuffersTo(BMessage *, char const *)
00020cd0 T MBufferManager::ReclaimBuffers(long const *, long, long, long)
00020f7c T MBufferManager::CleanupPurgedBufferGroup(long, long, long, void *, bool, BMessage &)
00021080 T MBufferManager::LoadState(void)
0002108c T MBufferManager::SaveState(void)
000210a0 T MDefaultManager::MDefaultManager(void)
0002123c T MDefaultManager::~MDefaultManager(void)
000212f4 T MDefaultManager::SaveState(void)
0002172c T MDefaultManager::LoadState(void)
00021de0 T MDefaultManager::SetDefault(long, BMessage &)
00022058 T MDefaultManager::SetRunningDefault(long, media_node const &)
000221a8 T MDefaultManager::RemoveRunningDefault(media_node const &)
000226ec T MDefaultManager::SetRealtimeFlags(unsigned long)
00022720 T MDefaultManager::GetRealtimeFlags(void)
00022730 T MDefaultManager::GetRunningDefault(long, media_node &)
000227d0 T MDefaultManager::RemoveDefault(long)
00022830 T MDefaultManager::GetDefault(long, BMessage &)
00022890 T MNotifierManager::MNotifierManager(void)
00022a5c T MNotifierManager::~MNotifierManager(void)
00022b20 T MNotifierManager::RegisterNotifier(long, BMessenger, media_node const *)
00022f50 T MNotifierManager::UnregisterNotifier(long, BMessenger, media_node const *)
00023f00 T MNotifierManager::BroadcastMessage(BMessage *, long long)
0002426c T MNotifierManager::regen_node_list(media_node const &)
000249b4 T MNotifierManager::get_node_messenger(media_node const &, get_messenger_a *)
00024a90 T MNotifierManager::HandleBroadcastError(BMessage *, BMessenger &, long, long long)
00024b34 T MNotifierManager::LoadState(void)
00024b40 T MNotifierManager::SaveState(void)
00024c5c T MMediaFilesManager::MMediaFilesManager(void)
00024dec T MMediaFilesManager::~MMediaFilesManager(void)
00024ea4 T MMediaFilesManager::SaveState(void)
00025b70 T MMediaFilesManager::LoadState(void)
00026668 T MMediaFilesManager::create_default_settings(void)
00027130 T MMediaFilesManager::GetTypes(BMessage &, BMessage &)
000271f8 T MMediaFilesManager::GetItems(BMessage &, BMessage &)
000274f0 T MMediaFilesManager::SetItem(BMessage &, BMessage &)
00027bc0 T MMediaFilesManager::ClearItem(BMessage &, BMessage &)
000288f4 T MMediaFilesManager::RemoveItem(BMessage &, BMessage &)
00028f0c T MMediaFilesManager::AddType(BMessage &, BMessage &)
*/