git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8154 a95241bf-73f2-0310-859d-f6bbb57e9c96
851 lines
19 KiB
C++
851 lines
19 KiB
C++
/*
|
|
* Copyright (c) 2002-2004 Matthijs Hollemans
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <Alert.h>
|
|
|
|
#include "debug.h"
|
|
#include "MidiServerApp.h"
|
|
#include "PortDrivers.h"
|
|
#include "ServerDefs.h"
|
|
#include "protocol.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
MidiServerApp::MidiServerApp()
|
|
: BApplication(MIDI_SERVER_SIGNATURE)
|
|
{
|
|
TRACE(("Running Haiku MIDI server"))
|
|
|
|
nextId = 1;
|
|
devWatcher.Start();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
MidiServerApp::~MidiServerApp()
|
|
{
|
|
for (int32 t = 0; t < CountApps(); ++t)
|
|
{
|
|
delete AppAt(t);
|
|
}
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
delete EndpointAt(t);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::AboutRequested()
|
|
{
|
|
(new BAlert(0,
|
|
"Haiku midi_server 1.0.0 alpha\n\n"
|
|
"notes disguised as bytes\n"
|
|
"propagating to endpoints,\n"
|
|
"an aural delight",
|
|
"Okay", 0, 0, B_WIDTH_AS_USUAL,
|
|
B_INFO_ALERT))->Go();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::MessageReceived(BMessage* msg)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("IN "); msg->PrintToStream();
|
|
#endif
|
|
|
|
// About thread safety inside the midi_server: even though
|
|
// multiple apps may be sending requests to the server at
|
|
// the same time, the BLooper's thread handles passes them
|
|
// to our MessageReceived() one after the other, so there
|
|
// is no need to synchronize anything.
|
|
|
|
switch (msg->what)
|
|
{
|
|
case MSG_REGISTER_APP: OnRegisterApp(msg); break;
|
|
case MSG_CREATE_ENDPOINT: OnCreateEndpoint(msg); break;
|
|
case MSG_DELETE_ENDPOINT: OnDeleteEndpoint(msg); break;
|
|
case MSG_PURGE_ENDPOINT: OnPurgeEndpoint(msg); break;
|
|
case MSG_CHANGE_ENDPOINT: OnChangeEndpoint(msg); break;
|
|
case MSG_CONNECT_ENDPOINTS: OnConnectDisconnect(msg); break;
|
|
case MSG_DISCONNECT_ENDPOINTS: OnConnectDisconnect(msg); break;
|
|
|
|
default: super::MessageReceived(msg); break;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnRegisterApp(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnRegisterApp"))
|
|
|
|
// We only send the "app registered" message upon success,
|
|
// so if anything goes wrong here, we do not let the app
|
|
// know about it, and we consider it unregistered. (Most
|
|
// likely, the app is dead. If not, it freezes forever
|
|
// in anticipation of a message that will never arrive.)
|
|
|
|
app_t* app = new app_t;
|
|
|
|
if (msg->FindMessenger("midi:messenger", &app->messenger) == B_OK)
|
|
{
|
|
if (SendAllEndpoints(app))
|
|
{
|
|
if (SendAllConnections(app))
|
|
{
|
|
BMessage reply;
|
|
reply.what = MSG_APP_REGISTERED;
|
|
|
|
if (SendNotification(app, &reply))
|
|
{
|
|
apps.AddItem(app);
|
|
|
|
#ifdef DEBUG
|
|
DumpApps();
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete app;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnCreateEndpoint(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnCreateEndpoint"))
|
|
|
|
status_t err;
|
|
|
|
endpoint_t* endp = new endpoint_t;
|
|
|
|
endp->app = WhichApp(msg);
|
|
if (endp->app == NULL)
|
|
{
|
|
err = B_ERROR;
|
|
}
|
|
else
|
|
{
|
|
err = B_BAD_VALUE;
|
|
|
|
if ((msg->FindBool("midi:consumer", &endp->consumer) == B_OK)
|
|
&& (msg->FindBool("midi:registered", &endp->registered) == B_OK)
|
|
&& (msg->FindString("midi:name", &endp->name) == B_OK)
|
|
&& (msg->FindMessage("midi:properties", &endp->properties) == B_OK))
|
|
{
|
|
if (endp->consumer)
|
|
{
|
|
if ((msg->FindInt32("midi:port", &endp->port) == B_OK)
|
|
&& (msg->FindInt64("midi:latency", &endp->latency) == B_OK))
|
|
{
|
|
err = B_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = B_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
BMessage reply;
|
|
|
|
if (err == B_OK)
|
|
{
|
|
endp->id = nextId++;
|
|
reply.AddInt32("midi:id", endp->id);
|
|
}
|
|
|
|
reply.AddInt32("midi:result", err);
|
|
|
|
if (SendReply(endp->app, msg, &reply) && (err == B_OK))
|
|
{
|
|
AddEndpoint(msg, endp);
|
|
}
|
|
else
|
|
{
|
|
delete endp;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnDeleteEndpoint(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnDeleteEndpoint"))
|
|
|
|
// Clients send the "delete endpoint" message from
|
|
// the BMidiEndpoint destructor, so there is no point
|
|
// sending a reply, because the endpoint object will
|
|
// be destroyed no matter what.
|
|
|
|
app_t* app = WhichApp(msg);
|
|
if (app != NULL)
|
|
{
|
|
endpoint_t* endp = WhichEndpoint(msg, app);
|
|
if (endp != NULL)
|
|
{
|
|
RemoveEndpoint(app, endp);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnPurgeEndpoint(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnPurgeEndpoint"))
|
|
|
|
// This performs the same task as OnDeleteEndpoint(),
|
|
// except that this message was send by the midi_server
|
|
// itself, so we don't check that the app that made the
|
|
// request really is the owner of the endpoint. (But we
|
|
// _do_ check that the message came from the server.)
|
|
|
|
if (!msg->IsSourceRemote())
|
|
{
|
|
int32 id;
|
|
if (msg->FindInt32("midi:id", &id) == B_OK)
|
|
{
|
|
endpoint_t* endp = FindEndpoint(id);
|
|
if (endp != NULL)
|
|
{
|
|
RemoveEndpoint(NULL, endp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnChangeEndpoint(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnChangeEndpoint"))
|
|
|
|
endpoint_t* endp = NULL;
|
|
status_t err;
|
|
|
|
app_t* app = WhichApp(msg);
|
|
if (app == NULL)
|
|
{
|
|
err = B_ERROR;
|
|
}
|
|
else
|
|
{
|
|
endp = WhichEndpoint(msg, app);
|
|
if (endp == NULL)
|
|
{
|
|
err = B_BAD_VALUE;
|
|
}
|
|
else
|
|
{
|
|
err = B_OK;
|
|
}
|
|
}
|
|
|
|
BMessage reply;
|
|
reply.AddInt32("midi:result", err);
|
|
|
|
if (SendReply(app, msg, &reply) && (err == B_OK))
|
|
{
|
|
TRACE(("Endpoint %ld (%p) changed", endp->id, endp))
|
|
|
|
BMessage notify;
|
|
notify.what = MSG_ENDPOINT_CHANGED;
|
|
notify.AddInt32("midi:id", endp->id);
|
|
|
|
bool registered;
|
|
if (msg->FindBool("midi:registered", ®istered) == B_OK)
|
|
{
|
|
notify.AddBool("midi:registered", registered);
|
|
endp->registered = registered;
|
|
}
|
|
|
|
BString name;
|
|
if (msg->FindString("midi:name", &name) == B_OK)
|
|
{
|
|
notify.AddString("midi:name", name);
|
|
endp->name = name;
|
|
}
|
|
|
|
BMessage properties;
|
|
if (msg->FindMessage("midi:properties", &properties) == B_OK)
|
|
{
|
|
notify.AddMessage("midi:properties", &properties);
|
|
endp->properties = properties;
|
|
}
|
|
|
|
bigtime_t latency;
|
|
if (msg->FindInt64("midi:latency", &latency) == B_OK)
|
|
{
|
|
notify.AddInt64("midi:latency", latency);
|
|
endp->latency = latency;
|
|
}
|
|
|
|
NotifyAll(¬ify, app);
|
|
|
|
#ifdef DEBUG
|
|
DumpEndpoints();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::OnConnectDisconnect(BMessage* msg)
|
|
{
|
|
TRACE(("MidiServerApp::OnConnectDisconnect"))
|
|
|
|
bool mustConnect = (msg->what == MSG_CONNECT_ENDPOINTS);
|
|
|
|
status_t err;
|
|
endpoint_t* prod = NULL;
|
|
endpoint_t* cons = NULL;
|
|
|
|
app_t* app = WhichApp(msg);
|
|
if (app == NULL)
|
|
{
|
|
err = B_ERROR;
|
|
}
|
|
else
|
|
{
|
|
err = B_BAD_VALUE;
|
|
|
|
int32 prodId, consId;
|
|
if ((msg->FindInt32("midi:producer", &prodId) == B_OK)
|
|
&& (msg->FindInt32("midi:consumer", &consId) == B_OK))
|
|
{
|
|
prod = FindEndpoint(prodId);
|
|
cons = FindEndpoint(consId);
|
|
|
|
if ((prod != NULL) && !prod->consumer)
|
|
{
|
|
if ((cons != NULL) && cons->consumer)
|
|
{
|
|
// It is an error to connect two endpoints that
|
|
// are already connected, or to disconnect two
|
|
// endpoints that are not connected at all.
|
|
|
|
if (mustConnect == prod->connections.HasItem(cons))
|
|
{
|
|
err = B_ERROR;
|
|
}
|
|
else
|
|
{
|
|
err = B_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BMessage reply;
|
|
reply.AddInt32("midi:result", err);
|
|
|
|
if (SendReply(app, msg, &reply) && (err == B_OK))
|
|
{
|
|
if (mustConnect)
|
|
{
|
|
TRACE(("Connection made: %ld ---> %ld", prod->id, cons->id))
|
|
|
|
prod->connections.AddItem(cons);
|
|
}
|
|
else
|
|
{
|
|
TRACE(("Connection broken: %ld -X-> %ld", prod->id, cons->id))
|
|
|
|
prod->connections.RemoveItem(cons);
|
|
}
|
|
|
|
BMessage notify;
|
|
MakeConnectedNotification(¬ify, prod, cons, mustConnect);
|
|
NotifyAll(¬ify, app);
|
|
|
|
#ifdef DEBUG
|
|
DumpEndpoints();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool MidiServerApp::SendAllEndpoints(app_t* app)
|
|
{
|
|
ASSERT(app != NULL)
|
|
|
|
BMessage notify;
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* endp = EndpointAt(t);
|
|
|
|
MakeCreatedNotification(¬ify, endp);
|
|
|
|
if (!SendNotification(app, ¬ify)) { return false; }
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool MidiServerApp::SendAllConnections(app_t* app)
|
|
{
|
|
ASSERT(app != NULL)
|
|
|
|
BMessage notify;
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* prod = EndpointAt(t);
|
|
if (!prod->consumer)
|
|
{
|
|
for (int32 k = 0; k < CountConnections(prod); ++k)
|
|
{
|
|
endpoint_t* cons = ConnectionAt(prod, k);
|
|
|
|
MakeConnectedNotification(¬ify, prod, cons, true);
|
|
|
|
if (!SendNotification(app, ¬ify)) { return false; }
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::AddEndpoint(BMessage* msg, endpoint_t* endp)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
ASSERT(endp != NULL)
|
|
ASSERT(!endpoints.HasItem(endp))
|
|
|
|
TRACE(("Endpoint %ld (%p) added", endp->id, endp))
|
|
|
|
endpoints.AddItem(endp);
|
|
|
|
BMessage notify;
|
|
MakeCreatedNotification(¬ify, endp);
|
|
NotifyAll(¬ify, endp->app);
|
|
|
|
#ifdef DEBUG
|
|
DumpEndpoints();
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::RemoveEndpoint(app_t* app, endpoint_t* endp)
|
|
{
|
|
ASSERT(endp != NULL)
|
|
ASSERT(endpoints.HasItem(endp))
|
|
|
|
TRACE(("Endpoint %ld (%p) removed", endp->id, endp))
|
|
|
|
endpoints.RemoveItem(endp);
|
|
|
|
if (endp->consumer)
|
|
{
|
|
DisconnectDeadConsumer(endp);
|
|
}
|
|
|
|
BMessage notify;
|
|
notify.what = MSG_ENDPOINT_DELETED;
|
|
notify.AddInt32("midi:id", endp->id);
|
|
NotifyAll(¬ify, app);
|
|
|
|
delete endp;
|
|
|
|
#ifdef DEBUG
|
|
DumpEndpoints();
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::DisconnectDeadConsumer(endpoint_t* cons)
|
|
{
|
|
ASSERT(cons != NULL)
|
|
ASSERT(cons->consumer)
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* prod = EndpointAt(t);
|
|
if (!prod->consumer)
|
|
{
|
|
prod->connections.RemoveItem(cons);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::MakeCreatedNotification(BMessage* msg, endpoint_t* endp)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
ASSERT(endp != NULL)
|
|
|
|
msg->MakeEmpty();
|
|
msg->what = MSG_ENDPOINT_CREATED;
|
|
msg->AddInt32("midi:id", endp->id);
|
|
msg->AddBool("midi:consumer", endp->consumer);
|
|
msg->AddBool("midi:registered", endp->registered);
|
|
msg->AddString("midi:name", endp->name);
|
|
msg->AddMessage("midi:properties", &endp->properties);
|
|
|
|
if (endp->consumer)
|
|
{
|
|
msg->AddInt32("midi:port", endp->port);
|
|
msg->AddInt64("midi:latency", endp->latency);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::MakeConnectedNotification(
|
|
BMessage* msg, endpoint_t* prod, endpoint_t* cons, bool mustConnect)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
ASSERT(prod != NULL)
|
|
ASSERT(cons != NULL)
|
|
ASSERT(!prod->consumer)
|
|
ASSERT(cons->consumer)
|
|
|
|
msg->MakeEmpty();
|
|
|
|
if (mustConnect)
|
|
{
|
|
msg->what = MSG_ENDPOINTS_CONNECTED;
|
|
}
|
|
else
|
|
{
|
|
msg->what = MSG_ENDPOINTS_DISCONNECTED;
|
|
}
|
|
|
|
msg->AddInt32("midi:producer", prod->id);
|
|
msg->AddInt32("midi:consumer", cons->id);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
app_t* MidiServerApp::WhichApp(BMessage* msg)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
|
|
BMessenger retadr = msg->ReturnAddress();
|
|
|
|
for (int32 t = 0; t < CountApps(); ++t)
|
|
{
|
|
app_t* app = AppAt(t);
|
|
if (app->messenger.Team() == retadr.Team())
|
|
{
|
|
return app;
|
|
}
|
|
}
|
|
|
|
TRACE(("Application %ld is not registered", retadr.Team()))
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
endpoint_t* MidiServerApp::WhichEndpoint(BMessage* msg, app_t* app)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
ASSERT(app != NULL)
|
|
|
|
int32 id;
|
|
if (msg->FindInt32("midi:id", &id) == B_OK)
|
|
{
|
|
endpoint_t* endp = FindEndpoint(id);
|
|
if ((endp != NULL) && (endp->app == app))
|
|
{
|
|
return endp;
|
|
}
|
|
}
|
|
|
|
TRACE(("Endpoint not found or wrong app"))
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
endpoint_t* MidiServerApp::FindEndpoint(int32 id)
|
|
{
|
|
if (id > 0)
|
|
{
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* endp = EndpointAt(t);
|
|
if (endp->id == id)
|
|
{
|
|
return endp;
|
|
}
|
|
}
|
|
}
|
|
|
|
TRACE(("Endpoint %ld not found", id))
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::NotifyAll(BMessage* msg, app_t* except)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
|
|
for (int32 t = CountApps() - 1; t >= 0; --t)
|
|
{
|
|
app_t* app = AppAt(t);
|
|
if (app != except)
|
|
{
|
|
if (!SendNotification(app, msg))
|
|
{
|
|
delete (app_t*) apps.RemoveItem(t);
|
|
|
|
#ifdef DEBUG
|
|
DumpApps();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool MidiServerApp::SendNotification(app_t* app, BMessage* msg)
|
|
{
|
|
ASSERT(app != NULL)
|
|
ASSERT(msg != NULL)
|
|
|
|
status_t err = app->messenger.SendMessage(msg, (BHandler*) NULL, TIMEOUT);
|
|
|
|
if (err != B_OK)
|
|
{
|
|
DeliveryError(app);
|
|
}
|
|
|
|
return (err == B_OK);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool MidiServerApp::SendReply(app_t* app, BMessage* msg, BMessage* reply)
|
|
{
|
|
ASSERT(msg != NULL)
|
|
ASSERT(reply != NULL)
|
|
|
|
status_t err = msg->SendReply(reply, (BHandler*) NULL, TIMEOUT);
|
|
|
|
if ((err != B_OK) && (app != NULL))
|
|
{
|
|
DeliveryError(app);
|
|
apps.RemoveItem(app);
|
|
delete app;
|
|
|
|
#ifdef DEBUG
|
|
DumpApps();
|
|
#endif
|
|
}
|
|
|
|
return (err == B_OK);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void MidiServerApp::DeliveryError(app_t* app)
|
|
{
|
|
ASSERT(app != NULL)
|
|
|
|
// We cannot communicate with the app, so we assume it's
|
|
// dead. We need to remove its endpoints from the roster,
|
|
// but we cannot do that right away; removing endpoints
|
|
// triggers a bunch of new notifications and we don't want
|
|
// those to get in the way of the notifications we are
|
|
// currently sending out. Instead, we consider the death
|
|
// of an app as a separate event, and pretend that the
|
|
// now-dead app sent us delete requests for its endpoints.
|
|
|
|
TRACE(("Delivery error; unregistering app (%p)", app))
|
|
|
|
BMessage msg;
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* endp = EndpointAt(t);
|
|
if (endp->app == app)
|
|
{
|
|
msg.MakeEmpty();
|
|
msg.what = MSG_PURGE_ENDPOINT;
|
|
msg.AddInt32("midi:id", endp->id);
|
|
|
|
// It is not safe to post a message to your own
|
|
// looper's message queue, because you risk a
|
|
// deadlock if the queue is full. The chance of
|
|
// that happening is fairly small, but just in
|
|
// case, we catch it with a timeout. Because this
|
|
// situation is so unlikely, I decided to simply
|
|
// forget about the whole "purge" message then.
|
|
|
|
if (be_app_messenger.SendMessage(
|
|
&msg, (BHandler*) NULL, TIMEOUT) != B_OK)
|
|
{
|
|
WARN("Could not deliver purge message")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int32 MidiServerApp::CountApps()
|
|
{
|
|
return apps.CountItems();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
app_t* MidiServerApp::AppAt(int32 index)
|
|
{
|
|
ASSERT(index >= 0 && index < CountApps())
|
|
|
|
return (app_t*) apps.ItemAt(index);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int32 MidiServerApp::CountEndpoints()
|
|
{
|
|
return endpoints.CountItems();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
endpoint_t* MidiServerApp::EndpointAt(int32 index)
|
|
{
|
|
ASSERT(index >= 0 && index < CountEndpoints())
|
|
|
|
return (endpoint_t*) endpoints.ItemAt(index);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int32 MidiServerApp::CountConnections(endpoint_t* prod)
|
|
{
|
|
ASSERT(prod != NULL)
|
|
ASSERT(!prod->consumer)
|
|
|
|
return prod->connections.CountItems();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
endpoint_t* MidiServerApp::ConnectionAt(endpoint_t* prod, int32 index)
|
|
{
|
|
ASSERT(prod != NULL)
|
|
ASSERT(!prod->consumer)
|
|
ASSERT(index >= 0 && index < CountConnections(prod))
|
|
|
|
return (endpoint_t*) prod->connections.ItemAt(index);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifdef DEBUG
|
|
void MidiServerApp::DumpApps()
|
|
{
|
|
printf("*** START DumpApps\n");
|
|
|
|
for (int32 t = 0; t < CountApps(); ++t)
|
|
{
|
|
app_t* app = AppAt(t);
|
|
|
|
printf("\tapp %ld (%p): team %ld\n", t, app, app->messenger.Team());
|
|
}
|
|
|
|
printf("*** END DumpApps\n");
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifdef DEBUG
|
|
void MidiServerApp::DumpEndpoints()
|
|
{
|
|
printf("*** START DumpEndpoints\n");
|
|
|
|
for (int32 t = 0; t < CountEndpoints(); ++t)
|
|
{
|
|
endpoint_t* endp = EndpointAt(t);
|
|
|
|
printf("\tendpoint %ld (%p):\n", t, endp);
|
|
|
|
printf("\t\tid %ld, name '%s', %s, %s, app %p\n",
|
|
endp->id, endp->name.String(),
|
|
endp->consumer ? "consumer" : "producer",
|
|
endp->registered ? "registered" : "unregistered",
|
|
endp->app);
|
|
|
|
printf("\t\tproperties: "); endp->properties.PrintToStream();
|
|
|
|
if (endp->consumer)
|
|
{
|
|
printf("\t\tport %ld, latency %Ld\n", endp->port, endp->latency);
|
|
}
|
|
else
|
|
{
|
|
printf("\t\tconnections:\n");
|
|
for (int32 k = 0; k < CountConnections(endp); ++k)
|
|
{
|
|
endpoint_t* cons = ConnectionAt(endp, k);
|
|
printf("\t\t\tid %ld (%p)\n", cons->id, cons);
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("*** END DumpEndpoints\n");
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int main()
|
|
{
|
|
MidiServerApp app;
|
|
app.Run();
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|