midi_server: cleanup.

* Style cleanup.
* Moved documentation to source file.
* Improved variable/member naming, added '_' prefix for private methods.
This commit is contained in:
Axel Dörfler
2015-10-14 22:23:28 +02:00
parent 8a3ae7a49d
commit 83f803c6ff
2 changed files with 423 additions and 399 deletions
+328 -267
View File
@@ -20,24 +20,29 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include "debug.h"
#include "MidiServerApp.h"
#include "PortDrivers.h"
#include "ServerDefs.h"
#include "protocol.h"
#include <Alert.h> #include "MidiServerApp.h"
#include <new> #include <new>
#include <Alert.h>
#include "debug.h"
#include "protocol.h"
#include "PortDrivers.h"
#include "ServerDefs.h"
using std::nothrow; using std::nothrow;
MidiServerApp::MidiServerApp() MidiServerApp::MidiServerApp()
: BApplication(MIDI_SERVER_SIGNATURE) :
BApplication(MIDI_SERVER_SIGNATURE)
{ {
TRACE(("Running Haiku MIDI server")) TRACE(("Running Haiku MIDI server"))
nextId = 1; fNextID = 1;
fDeviceWatcher = new(std::nothrow) DeviceWatcher(); fDeviceWatcher = new(std::nothrow) DeviceWatcher();
if (fDeviceWatcher != NULL) if (fDeviceWatcher != NULL)
fDeviceWatcher->Run(); fDeviceWatcher->Run();
@@ -49,12 +54,12 @@ MidiServerApp::~MidiServerApp()
if (fDeviceWatcher && fDeviceWatcher->Lock()) if (fDeviceWatcher && fDeviceWatcher->Lock())
fDeviceWatcher->Quit(); fDeviceWatcher->Quit();
for (int32 t = 0; t < CountApps(); ++t) { for (int32 t = 0; t < _CountApps(); ++t) {
delete AppAt(t); delete _AppAt(t);
} }
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
delete EndpointAt(t); delete _EndpointAt(t);
} }
} }
@@ -77,28 +82,44 @@ MidiServerApp::AboutRequested()
void void
MidiServerApp::MessageReceived(BMessage* msg) MidiServerApp::MessageReceived(BMessage* msg)
{ {
#ifdef DEBUG #ifdef DEBUG
printf("IN "); msg->PrintToStream(); printf("IN "); msg->PrintToStream();
#endif #endif
switch (msg->what) { switch (msg->what) {
case MSG_REGISTER_APP: OnRegisterApp(msg); break; case MSG_REGISTER_APP:
case MSG_CREATE_ENDPOINT: OnCreateEndpoint(msg); break; _OnRegisterApp(msg);
case MSG_DELETE_ENDPOINT: OnDeleteEndpoint(msg); break; break;
case MSG_PURGE_ENDPOINT: OnPurgeEndpoint(msg); break; case MSG_CREATE_ENDPOINT:
case MSG_CHANGE_ENDPOINT: OnChangeEndpoint(msg); break; _OnCreateEndpoint(msg);
case MSG_CONNECT_ENDPOINTS: OnConnectDisconnect(msg); break; break;
case MSG_DISCONNECT_ENDPOINTS: OnConnectDisconnect(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; default:
super::MessageReceived(msg);
break;
} }
} }
void void
MidiServerApp::OnRegisterApp(BMessage* msg) MidiServerApp::_OnRegisterApp(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnRegisterApp")) TRACE(("MidiServerApp::_OnRegisterApp"))
// We only send the "app registered" message upon success, // We only send the "app registered" message upon success,
// so if anything goes wrong here, we do not let the app // so if anything goes wrong here, we do not let the app
@@ -108,95 +129,93 @@ MidiServerApp::OnRegisterApp(BMessage* msg)
app_t* app = new app_t; app_t* app = new app_t;
if (msg->FindMessenger("midi:messenger", &app->messenger) == B_OK) { if (msg->FindMessenger("midi:messenger", &app->messenger) == B_OK
if (SendAllEndpoints(app)) { && _SendAllEndpoints(app)
if (SendAllConnections(app)) { && _SendAllConnections(app)) {
BMessage reply; BMessage reply;
reply.what = MSG_APP_REGISTERED; reply.what = MSG_APP_REGISTERED;
if (SendNotification(app, &reply)) { if (_SendNotification(app, &reply)) {
apps.AddItem(app); fApps.AddItem(app);
#ifdef DEBUG
#ifdef DEBUG _DumpApps();
DumpApps(); #endif
#endif
return; return;
} }
} }
}
}
delete app; delete app;
} }
void void
MidiServerApp::OnCreateEndpoint(BMessage* msg) MidiServerApp::_OnCreateEndpoint(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnCreateEndpoint")) TRACE(("MidiServerApp::_OnCreateEndpoint"))
status_t err; status_t status;
endpoint_t* endp = new endpoint_t; endpoint_t* endpoint = new endpoint_t;
endp->app = WhichApp(msg); endpoint->app = _WhichApp(msg);
if (endp->app == NULL) { if (endpoint->app == NULL) {
err = B_ERROR; status = B_ERROR;
} else { } else {
err = B_BAD_VALUE; status = B_BAD_VALUE;
if (msg->FindBool("midi:consumer", &endp->consumer) == B_OK if (msg->FindBool("midi:consumer", &endpoint->consumer) == B_OK
&& msg->FindBool("midi:registered", &endp->registered) == B_OK && msg->FindBool("midi:registered", &endpoint->registered) == B_OK
&& msg->FindString("midi:name", &endp->name) == B_OK && msg->FindString("midi:name", &endpoint->name) == B_OK
&& msg->FindMessage("midi:properties", &endp->properties) == B_OK) { && msg->FindMessage("midi:properties", &endpoint->properties)
if (endp->consumer) { == B_OK) {
if (msg->FindInt32("midi:port", &endp->port) == B_OK if (endpoint->consumer) {
&& msg->FindInt64("midi:latency", &endp->latency) == B_OK) if (msg->FindInt32("midi:port", &endpoint->port) == B_OK
err = B_OK; && msg->FindInt64("midi:latency", &endpoint->latency)
== B_OK)
status = B_OK;
} else } else
err = B_OK; status = B_OK;
} }
} }
BMessage reply; BMessage reply;
if (err == B_OK) { if (status == B_OK) {
endp->id = nextId++; endpoint->id = fNextID++;
reply.AddInt32("midi:id", endp->id); reply.AddInt32("midi:id", endpoint->id);
} }
reply.AddInt32("midi:result", err); reply.AddInt32("midi:result", status);
if (SendReply(endp->app, msg, &reply) && err == B_OK) if (_SendReply(endpoint->app, msg, &reply) && status == B_OK)
AddEndpoint(msg, endp); _AddEndpoint(msg, endpoint);
else else
delete endp; delete endpoint;
} }
void void
MidiServerApp::OnDeleteEndpoint(BMessage* msg) MidiServerApp::_OnDeleteEndpoint(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnDeleteEndpoint")) TRACE(("MidiServerApp::_OnDeleteEndpoint"))
// Clients send the "delete endpoint" message from // Clients send the "delete endpoint" message from
// the BMidiEndpoint destructor, so there is no point // the BMidiEndpoint destructor, so there is no point
// sending a reply, because the endpoint object will // sending a reply, because the endpoint object will
// be destroyed no matter what. // be destroyed no matter what.
app_t* app = WhichApp(msg); app_t* app = _WhichApp(msg);
if (app != NULL) { if (app != NULL) {
endpoint_t* endp = WhichEndpoint(msg, app); endpoint_t* endpoint = _WhichEndpoint(msg, app);
if (endp != NULL) if (endpoint != NULL)
RemoveEndpoint(app, endp); _RemoveEndpoint(app, endpoint);
} }
} }
void void
MidiServerApp::OnPurgeEndpoint(BMessage* msg) MidiServerApp::_OnPurgeEndpoint(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnPurgeEndpoint")) TRACE(("MidiServerApp::_OnPurgeEndpoint"))
// This performs the same task as OnDeleteEndpoint(), // This performs the same task as OnDeleteEndpoint(),
// except that this message was send by the midi_server // except that this message was send by the midi_server
@@ -207,154 +226,158 @@ MidiServerApp::OnPurgeEndpoint(BMessage* msg)
if (!msg->IsSourceRemote()) { if (!msg->IsSourceRemote()) {
int32 id; int32 id;
if (msg->FindInt32("midi:id", &id) == B_OK) { if (msg->FindInt32("midi:id", &id) == B_OK) {
endpoint_t* endp = FindEndpoint(id); endpoint_t* endpoint = _FindEndpoint(id);
if (endp != NULL) if (endpoint != NULL)
RemoveEndpoint(NULL, endp); _RemoveEndpoint(NULL, endpoint);
} }
} }
} }
void void
MidiServerApp::OnChangeEndpoint(BMessage* msg) MidiServerApp::_OnChangeEndpoint(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnChangeEndpoint")) TRACE(("MidiServerApp::_OnChangeEndpoint"))
endpoint_t* endp = NULL; endpoint_t* endpoint = NULL;
status_t err; status_t status;
app_t* app = WhichApp(msg); app_t* app = _WhichApp(msg);
if (app == NULL) if (app == NULL)
err = B_ERROR; status = B_ERROR;
else { else {
endp = WhichEndpoint(msg, app); endpoint = _WhichEndpoint(msg, app);
if (endp == NULL) if (endpoint == NULL)
err = B_BAD_VALUE; status = B_BAD_VALUE;
else else
err = B_OK; status = B_OK;
} }
BMessage reply; BMessage reply;
reply.AddInt32("midi:result", err); reply.AddInt32("midi:result", status);
if (SendReply(app, msg, &reply) && err == B_OK) { if (_SendReply(app, msg, &reply) && status == B_OK) {
TRACE(("Endpoint %" B_PRId32 " (%p) changed", endp->id, endp)) TRACE(("Endpoint %" B_PRId32 " (%p) changed", endpoint->id, endpoint))
BMessage notify; BMessage notify;
notify.what = MSG_ENDPOINT_CHANGED; notify.what = MSG_ENDPOINT_CHANGED;
notify.AddInt32("midi:id", endp->id); notify.AddInt32("midi:id", endpoint->id);
bool registered; bool registered;
if (msg->FindBool("midi:registered", &registered) == B_OK) { if (msg->FindBool("midi:registered", &registered) == B_OK) {
notify.AddBool("midi:registered", registered); notify.AddBool("midi:registered", registered);
endp->registered = registered; endpoint->registered = registered;
} }
BString name; BString name;
if (msg->FindString("midi:name", &name) == B_OK) { if (msg->FindString("midi:name", &name) == B_OK) {
notify.AddString("midi:name", name); notify.AddString("midi:name", name);
endp->name = name; endpoint->name = name;
} }
BMessage properties; BMessage properties;
if (msg->FindMessage("midi:properties", &properties) == B_OK) { if (msg->FindMessage("midi:properties", &properties) == B_OK) {
notify.AddMessage("midi:properties", &properties); notify.AddMessage("midi:properties", &properties);
endp->properties = properties; endpoint->properties = properties;
} }
bigtime_t latency; bigtime_t latency;
if (msg->FindInt64("midi:latency", &latency) == B_OK) { if (msg->FindInt64("midi:latency", &latency) == B_OK) {
notify.AddInt64("midi:latency", latency); notify.AddInt64("midi:latency", latency);
endp->latency = latency; endpoint->latency = latency;
} }
NotifyAll(&notify, app); _NotifyAll(&notify, app);
#ifdef DEBUG #ifdef DEBUG
DumpEndpoints(); _DumpEndpoints();
#endif #endif
} }
} }
void void
MidiServerApp::OnConnectDisconnect(BMessage* msg) MidiServerApp::_OnConnectDisconnect(BMessage* msg)
{ {
TRACE(("MidiServerApp::OnConnectDisconnect")) TRACE(("MidiServerApp::_OnConnectDisconnect"))
bool mustConnect = (msg->what == MSG_CONNECT_ENDPOINTS); bool mustConnect = msg->what == MSG_CONNECT_ENDPOINTS;
status_t err; status_t status;
endpoint_t* prod = NULL; endpoint_t* producer = NULL;
endpoint_t* cons = NULL; endpoint_t* consumer = NULL;
app_t* app = WhichApp(msg); app_t* app = _WhichApp(msg);
if (app == NULL) if (app == NULL)
err = B_ERROR; status = B_ERROR;
else { else {
err = B_BAD_VALUE; status = B_BAD_VALUE;
int32 prodId, consId; int32 producerID;
if (msg->FindInt32("midi:producer", &prodId) == B_OK int32 consumerID;
&& msg->FindInt32("midi:consumer", &consId) == B_OK) { if (msg->FindInt32("midi:producer", &producerID) == B_OK
prod = FindEndpoint(prodId); && msg->FindInt32("midi:consumer", &consumerID) == B_OK) {
cons = FindEndpoint(consId); producer = _FindEndpoint(producerID);
consumer = _FindEndpoint(consumerID);
if (prod != NULL && !prod->consumer) { if (producer != NULL && !producer->consumer) {
if (cons != NULL && cons->consumer) { if (consumer != NULL && consumer->consumer) {
// It is an error to connect two endpoints that // It is an error to connect two endpoints that
// are already connected, or to disconnect two // are already connected, or to disconnect two
// endpoints that are not connected at all. // endpoints that are not connected at all.
if (mustConnect == prod->connections.HasItem(cons)) if (mustConnect == producer->connections.HasItem(consumer))
err = B_ERROR; status = B_ERROR;
else else
err = B_OK; status = B_OK;
} }
} }
} }
} }
BMessage reply; BMessage reply;
reply.AddInt32("midi:result", err); reply.AddInt32("midi:result", status);
if (SendReply(app, msg, &reply) && err == B_OK) { if (_SendReply(app, msg, &reply) && status == B_OK) {
if (mustConnect) { if (mustConnect) {
TRACE(("Connection made: %" B_PRId32 " ---> %" B_PRId32, prod->id, TRACE(("Connection made: %" B_PRId32 " ---> %" B_PRId32,
cons->id)) producer->id, consumer->id))
prod->connections.AddItem(cons); producer->connections.AddItem(consumer);
} else { } else {
TRACE(("Connection broken: %" B_PRId32 " -X-> %" B_PRId32, prod->id, TRACE(("Connection broken: %" B_PRId32 " -X-> %" B_PRId32,
cons->id)) producer->id, consumer->id))
prod->connections.RemoveItem(cons); producer->connections.RemoveItem(consumer);
} }
BMessage notify; BMessage notify;
MakeConnectedNotification(&notify, prod, cons, mustConnect); _MakeConnectedNotification(&notify, producer, consumer, mustConnect);
NotifyAll(&notify, app); _NotifyAll(&notify, app);
#ifdef DEBUG #ifdef DEBUG
DumpEndpoints(); _DumpEndpoints();
#endif #endif
} }
} }
/*! Sends an app MSG_ENDPOINT_CREATED notifications for
all current endpoints. Used when the app registers.
*/
bool bool
MidiServerApp::SendAllEndpoints(app_t* app) MidiServerApp::_SendAllEndpoints(app_t* app)
{ {
ASSERT(app != NULL) ASSERT(app != NULL)
BMessage notify; BMessage notify;
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* endp = EndpointAt(t); endpoint_t* endpoint = _EndpointAt(t);
MakeCreatedNotification(&notify, endp); _MakeCreatedNotification(&notify, endpoint);
if (!SendNotification(app, &notify)) if (!_SendNotification(app, &notify))
return false; return false;
} }
@@ -362,22 +385,25 @@ MidiServerApp::SendAllEndpoints(app_t* app)
} }
/*! Sends an app MSG_ENDPOINTS_CONNECTED notifications for
all current connections. Used when the app registers.
*/
bool bool
MidiServerApp::SendAllConnections(app_t* app) MidiServerApp::_SendAllConnections(app_t* app)
{ {
ASSERT(app != NULL) ASSERT(app != NULL)
BMessage notify; BMessage notify;
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* prod = EndpointAt(t); endpoint_t* producer = _EndpointAt(t);
if (!prod->consumer) { if (!producer->consumer) {
for (int32 k = 0; k < CountConnections(prod); ++k) { for (int32 k = 0; k < _CountConnections(producer); ++k) {
endpoint_t* cons = ConnectionAt(prod, k); endpoint_t* consumer = _ConnectionAt(producer, k);
MakeConnectedNotification(&notify, prod, cons, true); _MakeConnectedNotification(&notify, producer, consumer, true);
if (!SendNotification(app, &notify)) if (!_SendNotification(app, &notify))
return false; return false;
} }
} }
@@ -387,97 +413,111 @@ MidiServerApp::SendAllConnections(app_t* app)
} }
/*! Adds the specified endpoint to the roster, and notifies
all other applications about this event.
*/
void void
MidiServerApp::AddEndpoint(BMessage* msg, endpoint_t* endp) MidiServerApp::_AddEndpoint(BMessage* msg, endpoint_t* endpoint)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
ASSERT(endp != NULL) ASSERT(endpoint != NULL)
ASSERT(!endpoints.HasItem(endp)) ASSERT(!fEndpoints.HasItem(endpoint))
TRACE(("Endpoint %" B_PRId32 " (%p) added", endp->id, endp)) TRACE(("Endpoint %" B_PRId32 " (%p) added", endpoint->id, endpoint))
endpoints.AddItem(endp); fEndpoints.AddItem(endpoint);
BMessage notify; BMessage notify;
MakeCreatedNotification(&notify, endp); _MakeCreatedNotification(&notify, endpoint);
NotifyAll(&notify, endp->app); _NotifyAll(&notify, endpoint->app);
#ifdef DEBUG #ifdef DEBUG
DumpEndpoints(); _DumpEndpoints();
#endif #endif
} }
/*! Removes an endpoint from the roster, and notifies all
other apps about this event. "app" is the application
that the endpoint belongs to; if it is NULL, the app
no longer exists and we're purging the endpoint.
*/
void void
MidiServerApp::RemoveEndpoint(app_t* app, endpoint_t* endp) MidiServerApp::_RemoveEndpoint(app_t* app, endpoint_t* endpoint)
{ {
ASSERT(endp != NULL) ASSERT(endpoint != NULL)
ASSERT(endpoints.HasItem(endp)) ASSERT(fEndpoints.HasItem(endpoint))
TRACE(("Endpoint %" B_PRId32 " (%p) removed", endp->id, endp)) TRACE(("Endpoint %" B_PRId32 " (%p) removed", endpoint->id, endpoint))
endpoints.RemoveItem(endp); fEndpoints.RemoveItem(endpoint);
if (endp->consumer) if (endpoint->consumer)
DisconnectDeadConsumer(endp); _DisconnectDeadConsumer(endpoint);
BMessage notify; BMessage notify;
notify.what = MSG_ENDPOINT_DELETED; notify.what = MSG_ENDPOINT_DELETED;
notify.AddInt32("midi:id", endp->id); notify.AddInt32("midi:id", endpoint->id);
NotifyAll(&notify, app); _NotifyAll(&notify, app);
delete endp; delete endpoint;
#ifdef DEBUG #ifdef DEBUG
DumpEndpoints(); _DumpEndpoints();
#endif #endif
} }
/*! Removes a consumer from the list of connections of
all the producers it is connected to, just before
we remove it from the roster.
*/
void void
MidiServerApp::DisconnectDeadConsumer(endpoint_t* cons) MidiServerApp::_DisconnectDeadConsumer(endpoint_t* consumer)
{ {
ASSERT(cons != NULL) ASSERT(consumer != NULL)
ASSERT(cons->consumer) ASSERT(consumer->consumer)
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* prod = EndpointAt(t); endpoint_t* producer = _EndpointAt(t);
if (!prod->consumer) if (!producer->consumer)
prod->connections.RemoveItem(cons); producer->connections.RemoveItem(consumer);
} }
} }
//! Fills up a MSG_ENDPOINT_CREATED message.
void void
MidiServerApp::MakeCreatedNotification(BMessage* msg, endpoint_t* endp) MidiServerApp::_MakeCreatedNotification(BMessage* msg, endpoint_t* endpoint)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
ASSERT(endp != NULL) ASSERT(endpoint != NULL)
msg->MakeEmpty(); msg->MakeEmpty();
msg->what = MSG_ENDPOINT_CREATED; msg->what = MSG_ENDPOINT_CREATED;
msg->AddInt32("midi:id", endp->id); msg->AddInt32("midi:id", endpoint->id);
msg->AddBool("midi:consumer", endp->consumer); msg->AddBool("midi:consumer", endpoint->consumer);
msg->AddBool("midi:registered", endp->registered); msg->AddBool("midi:registered", endpoint->registered);
msg->AddString("midi:name", endp->name); msg->AddString("midi:name", endpoint->name);
msg->AddMessage("midi:properties", &endp->properties); msg->AddMessage("midi:properties", &endpoint->properties);
if (endp->consumer) { if (endpoint->consumer) {
msg->AddInt32("midi:port", endp->port); msg->AddInt32("midi:port", endpoint->port);
msg->AddInt64("midi:latency", endp->latency); msg->AddInt64("midi:latency", endpoint->latency);
} }
} }
//! Fills up a MSG_ENDPOINTS_(DIS)CONNECTED message.
void void
MidiServerApp::MakeConnectedNotification(BMessage* msg, endpoint_t* prod, MidiServerApp::_MakeConnectedNotification(BMessage* msg, endpoint_t* producer,
endpoint_t* cons, bool mustConnect) endpoint_t* consumer, bool mustConnect)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
ASSERT(prod != NULL) ASSERT(producer != NULL)
ASSERT(cons != NULL) ASSERT(consumer != NULL)
ASSERT(!prod->consumer) ASSERT(!producer->consumer)
ASSERT(cons->consumer) ASSERT(consumer->consumer)
msg->MakeEmpty(); msg->MakeEmpty();
@@ -486,20 +526,23 @@ MidiServerApp::MakeConnectedNotification(BMessage* msg, endpoint_t* prod,
else else
msg->what = MSG_ENDPOINTS_DISCONNECTED; msg->what = MSG_ENDPOINTS_DISCONNECTED;
msg->AddInt32("midi:producer", prod->id); msg->AddInt32("midi:producer", producer->id);
msg->AddInt32("midi:consumer", cons->id); msg->AddInt32("midi:consumer", consumer->id);
} }
/*! Figures out which application a message came from.
Returns NULL if the application is not registered.
*/
app_t* app_t*
MidiServerApp::WhichApp(BMessage* msg) MidiServerApp::_WhichApp(BMessage* msg)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
BMessenger retadr = msg->ReturnAddress(); BMessenger retadr = msg->ReturnAddress();
for (int32 t = 0; t < CountApps(); ++t) { for (int32 t = 0; t < _CountApps(); ++t) {
app_t* app = AppAt(t); app_t* app = _AppAt(t);
if (app->messenger.Team() == retadr.Team()) if (app->messenger.Team() == retadr.Team())
return app; return app;
} }
@@ -510,17 +553,22 @@ MidiServerApp::WhichApp(BMessage* msg)
} }
/*! Looks at the "midi:id" field from a message, and returns
the endpoint object that corresponds to that ID. It also
checks whether the application specified by "app" really
owns the endpoint. Returns NULL on error.
*/
endpoint_t* endpoint_t*
MidiServerApp::WhichEndpoint(BMessage* msg, app_t* app) MidiServerApp::_WhichEndpoint(BMessage* msg, app_t* app)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
ASSERT(app != NULL) ASSERT(app != NULL)
int32 id; int32 id;
if (msg->FindInt32("midi:id", &id) == B_OK) { if (msg->FindInt32("midi:id", &id) == B_OK) {
endpoint_t* endp = FindEndpoint(id); endpoint_t* endpoint = _FindEndpoint(id);
if (endp != NULL && endp->app == app) if (endpoint != NULL && endpoint->app == app)
return endp; return endpoint;
} }
TRACE(("Endpoint not found or wrong app")) TRACE(("Endpoint not found or wrong app"))
@@ -528,14 +576,17 @@ MidiServerApp::WhichEndpoint(BMessage* msg, app_t* app)
} }
/*! Returns the endpoint with the specified ID, or
\c NULL if no such endpoint exists on the roster.
*/
endpoint_t* endpoint_t*
MidiServerApp::FindEndpoint(int32 id) MidiServerApp::_FindEndpoint(int32 id)
{ {
if (id > 0) { if (id > 0) {
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* endp = EndpointAt(t); endpoint_t* endpoint = _EndpointAt(t);
if (endp->id == id) if (endpoint->id == id)
return endp; return endpoint;
} }
} }
@@ -544,65 +595,78 @@ MidiServerApp::FindEndpoint(int32 id)
} }
/*! Sends notification messages to all registered apps,
except to the application that triggered the event.
The "except" app is allowed to be NULL.
*/
void void
MidiServerApp::NotifyAll(BMessage* msg, app_t* except) MidiServerApp::_NotifyAll(BMessage* msg, app_t* except)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
for (int32 t = CountApps() - 1; t >= 0; --t) { for (int32 t = _CountApps() - 1; t >= 0; --t) {
app_t* app = AppAt(t); app_t* app = _AppAt(t);
if (app != except) { if (app != except && !_SendNotification(app, msg)) {
if (!SendNotification(app, msg)) { delete (app_t*)fApps.RemoveItem(t);
delete (app_t*)apps.RemoveItem(t); #ifdef DEBUG
_DumpApps();
#ifdef DEBUG #endif
DumpApps();
#endif
}
} }
} }
} }
/*! Sends a notification message to an application, which is
not necessarily registered yet. Applications never reply
to such notification messages.
*/
bool bool
MidiServerApp::SendNotification(app_t* app, BMessage* msg) MidiServerApp::_SendNotification(app_t* app, BMessage* msg)
{ {
ASSERT(app != NULL) ASSERT(app != NULL)
ASSERT(msg != NULL) ASSERT(msg != NULL)
status_t err = app->messenger.SendMessage(msg, (BHandler*) NULL, TIMEOUT); status_t status = app->messenger.SendMessage(msg, (BHandler*) NULL,
TIMEOUT);
if (status != B_OK)
_DeliveryError(app);
if (err != B_OK) return status == B_OK;
DeliveryError(app);
return err == B_OK;
} }
/*! Sends a reply to a request made by an application.
If "app" is NULL, the application is not registered
(and the reply should contain an error code).
*/
bool bool
MidiServerApp::SendReply(app_t* app, BMessage* msg, BMessage* reply) MidiServerApp::_SendReply(app_t* app, BMessage* msg, BMessage* reply)
{ {
ASSERT(msg != NULL) ASSERT(msg != NULL)
ASSERT(reply != NULL) ASSERT(reply != NULL)
status_t err = msg->SendReply(reply, (BHandler*) NULL, TIMEOUT); status_t status = msg->SendReply(reply, (BHandler*) NULL, TIMEOUT);
if (status != B_OK && app != NULL) {
if (err != B_OK && app != NULL) { _DeliveryError(app);
DeliveryError(app); fApps.RemoveItem(app);
apps.RemoveItem(app);
delete app; delete app;
#ifdef DEBUG #ifdef DEBUG
DumpApps(); _DumpApps();
#endif #endif
} }
return err == B_OK; return status == B_OK;
} }
/*! Removes an app and all of its endpoints from the roster
if a reply or notification message cannot be delivered.
(Waiting for communications to fail is actually our only
way to get rid of stale endpoints.)
*/
void void
MidiServerApp::DeliveryError(app_t* app) MidiServerApp::_DeliveryError(app_t* app)
{ {
ASSERT(app != NULL) ASSERT(app != NULL)
@@ -619,12 +683,12 @@ MidiServerApp::DeliveryError(app_t* app)
BMessage msg; BMessage msg;
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* endp = EndpointAt(t); endpoint_t* endpoint = _EndpointAt(t);
if (endp->app == app) { if (endpoint->app == app) {
msg.MakeEmpty(); msg.MakeEmpty();
msg.what = MSG_PURGE_ENDPOINT; msg.what = MSG_PURGE_ENDPOINT;
msg.AddInt32("midi:id", endp->id); msg.AddInt32("midi:id", endpoint->id);
// It is not safe to post a message to your own // It is not safe to post a message to your own
// looper's message queue, because you risk a // looper's message queue, because you risk a
@@ -644,65 +708,65 @@ MidiServerApp::DeliveryError(app_t* app)
int32 int32
MidiServerApp::CountApps() MidiServerApp::_CountApps()
{ {
return apps.CountItems(); return fApps.CountItems();
} }
app_t* app_t*
MidiServerApp::AppAt(int32 index) MidiServerApp::_AppAt(int32 index)
{ {
ASSERT(index >= 0 && index < CountApps()) ASSERT(index >= 0 && index < CountApps())
return (app_t*)apps.ItemAt(index); return (app_t*)fApps.ItemAt(index);
} }
int32 int32
MidiServerApp::CountEndpoints() MidiServerApp::_CountEndpoints()
{ {
return endpoints.CountItems(); return fEndpoints.CountItems();
} }
endpoint_t* endpoint_t*
MidiServerApp::EndpointAt(int32 index) MidiServerApp::_EndpointAt(int32 index)
{ {
ASSERT(index >= 0 && index < CountEndpoints()) ASSERT(index >= 0 && index < CountEndpoints())
return (endpoint_t*)endpoints.ItemAt(index); return (endpoint_t*)fEndpoints.ItemAt(index);
} }
int32 int32
MidiServerApp::CountConnections(endpoint_t* prod) MidiServerApp::_CountConnections(endpoint_t* producer)
{ {
ASSERT(prod != NULL) ASSERT(producer != NULL)
ASSERT(!prod->consumer) ASSERT(!producer->consumer)
return prod->connections.CountItems(); return producer->connections.CountItems();
} }
endpoint_t* endpoint_t*
MidiServerApp::ConnectionAt(endpoint_t* prod, int32 index) MidiServerApp::_ConnectionAt(endpoint_t* producer, int32 index)
{ {
ASSERT(prod != NULL) ASSERT(producer != NULL)
ASSERT(!prod->consumer) ASSERT(!producer->consumer)
ASSERT(index >= 0 && index < CountConnections(prod)) ASSERT(index >= 0 && index < _CountConnections(producer))
return (endpoint_t*)prod->connections.ItemAt(index); return (endpoint_t*)producer->connections.ItemAt(index);
} }
#ifdef DEBUG #ifdef DEBUG
void void
MidiServerApp::DumpApps() MidiServerApp::_DumpApps()
{ {
printf("*** START DumpApps\n"); printf("*** START DumpApps\n");
for (int32 t = 0; t < CountApps(); ++t) { for (int32 t = 0; t < _CountApps(); ++t) {
app_t* app = AppAt(t); app_t* app = AppAt(t);
printf("\tapp %" B_PRId32 " (%p): team %" B_PRId32 "\n", t, app, printf("\tapp %" B_PRId32 " (%p): team %" B_PRId32 "\n", t, app,
@@ -711,41 +775,39 @@ MidiServerApp::DumpApps()
printf("*** END DumpApps\n"); printf("*** END DumpApps\n");
} }
#endif
#ifdef DEBUG
void void
MidiServerApp::DumpEndpoints() MidiServerApp::_DumpEndpoints()
{ {
printf("*** START DumpEndpoints\n"); printf("*** START DumpEndpoints\n");
for (int32 t = 0; t < CountEndpoints(); ++t) { for (int32 t = 0; t < _CountEndpoints(); ++t) {
endpoint_t* endp = EndpointAt(t); endpoint_t* endpoint = _EndpointAt(t);
printf("\tendpoint %" B_PRId32 " (%p):\n", t, endp); printf("\tendpoint %" B_PRId32 " (%p):\n", t, endpoint);
printf("\t\tid %" B_PRId32 ", name '%s', %s, %s, app %p\n", printf("\t\tid %" B_PRId32 ", name '%s', %s, %s, app %p\n",
endp->id, endp->name.String(), endpoint->id, endpoint->name.String(),
endp->consumer ? "consumer" : "producer", endpoint->consumer ? "consumer" : "producer",
endp->registered ? "registered" : "unregistered", endpoint->registered ? "registered" : "unregistered",
endp->app); endpoint->app);
printf("\t\tproperties: "); endp->properties.PrintToStream(); printf("\t\tproperties: "); endpoint->properties.PrintToStream();
if (endp->consumer) if (endpoint->consumer)
printf("\t\tport %" B_PRId32 ", latency %" B_PRIdBIGTIME "\n", printf("\t\tport %" B_PRId32 ", latency %" B_PRIdBIGTIME "\n",
endp->port, endp->latency); endpoint->port, endpoint->latency);
else { else {
printf("\t\tconnections:\n"); printf("\t\tconnections:\n");
for (int32 k = 0; k < CountConnections(endp); ++k) { for (int32 k = 0; k < CountConnections(endpoint); ++k) {
endpoint_t* cons = ConnectionAt(endp, k); endpoint_t* consumer = ConnectionAt(endpoint, k);
printf("\t\t\tid %" B_PRId32 " (%p)\n", cons->id, cons); printf("\t\t\tid %" B_PRId32 " (%p)\n", consumer->id, consumer);
} }
} }
} }
printf("*** END DumpEndpoints\n"); printf("*** END DumpEndpoints\n");
} }
#endif #endif // DEBUG
// #pragma mark - // #pragma mark -
@@ -758,4 +820,3 @@ main()
app.Run(); app.Run();
return 0; return 0;
} }
+53 -90
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009, Haiku, Inc. All rights reserved. * Copyright 2002-2015, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -8,22 +8,24 @@
#ifndef MIDI_SERVER_APP_H #ifndef MIDI_SERVER_APP_H
#define MIDI_SERVER_APP_H #define MIDI_SERVER_APP_H
#include <Application.h> #include <Application.h>
#include <List.h> #include <List.h>
#include "DeviceWatcher.h" #include "DeviceWatcher.h"
struct app_t; struct app_t;
struct endpoint_t; struct endpoint_t;
// The heart of the midi_server. This BApplication subclass
// keeps the roster of endpoints and applications, processes
// incoming messages from libmidi2.so, and notifies the apps
// when something interesting happens.
class MidiServerApp : public BApplication
{
public:
/*! The heart of the midi_server. This BApplication subclass
keeps the roster of endpoints and applications, processes
incoming messages from libmidi2.so, and notifies the apps
when something interesting happens.
*/
class MidiServerApp : public BApplication {
public:
MidiServerApp(); MidiServerApp();
virtual ~MidiServerApp(); virtual ~MidiServerApp();
@@ -31,106 +33,67 @@ public:
virtual void MessageReceived(BMessage* msg); virtual void MessageReceived(BMessage* msg);
private: private:
typedef BApplication super; typedef BApplication super;
void OnRegisterApp(BMessage* msg); void _OnRegisterApp(BMessage* msg);
void OnCreateEndpoint(BMessage* msg); void _OnCreateEndpoint(BMessage* msg);
void OnDeleteEndpoint(BMessage* msg); void _OnDeleteEndpoint(BMessage* msg);
void OnPurgeEndpoint(BMessage* msg); void _OnPurgeEndpoint(BMessage* msg);
void OnChangeEndpoint(BMessage* msg); void _OnChangeEndpoint(BMessage* msg);
void OnConnectDisconnect(BMessage* msg); void _OnConnectDisconnect(BMessage* msg);
// Sends an app MSG_ENDPOINT_CREATED notifications for bool _SendAllEndpoints(app_t* app);
// all current endpoints. Used when the app registers. bool _SendAllConnections(app_t* app);
bool SendAllEndpoints(app_t* app);
// Sends an app MSG_ENDPOINTS_CONNECTED notifications for void _AddEndpoint(BMessage* msg, endpoint_t* endp);
// all current connections. Used when the app registers. void _RemoveEndpoint(app_t* app, endpoint_t* endp);
bool SendAllConnections(app_t* app);
// Adds the specified endpoint to the roster, and notifies void _DisconnectDeadConsumer(endpoint_t* cons);
// all other applications about this event.
void AddEndpoint(BMessage* msg, endpoint_t* endp);
// Removes an endpoint from the roster, and notifies all void _MakeCreatedNotification(BMessage* msg,
// other apps about this event. "app" is the application endpoint_t* endp);
// that the endpoint belongs to; if it is NULL, the app void _MakeConnectedNotification(BMessage* msg,
// no longer exists and we're purging the endpoint. endpoint_t* prod, endpoint_t* cons,
void RemoveEndpoint(app_t* app, endpoint_t* endp); bool mustConnect);
// Removes a consumer from the list of connections of app_t* _WhichApp(BMessage* msg);
// all the producers it is connected to, just before endpoint_t* _WhichEndpoint(BMessage* msg, app_t* app);
// we remove it from the roster. endpoint_t* _FindEndpoint(int32 id);
void DisconnectDeadConsumer(endpoint_t* cons);
// Fills up a MSG_ENDPOINT_CREATED message. void _NotifyAll(BMessage* msg, app_t* except);
void MakeCreatedNotification(BMessage* msg, endpoint_t* endp); bool _SendNotification(app_t* app, BMessage* msg);
bool _SendReply(app_t* app, BMessage* msg,
BMessage* reply);
// Fills up a MSG_ENDPOINTS_(DIS)CONNECTED message. void _DeliveryError(app_t* app);
void MakeConnectedNotification(
BMessage* msg, endpoint_t* prod, endpoint_t* cons, bool mustConnect);
// Figures out which application a message came from. int32 _CountApps();
// Returns NULL if the application is not registered. app_t* _AppAt(int32 index);
app_t* WhichApp(BMessage* msg);
// Looks at the "midi:id" field from a message, and returns int32 _CountEndpoints();
// the endpoint object that corresponds to that ID. It also endpoint_t* _EndpointAt(int32 index);
// checks whether the application specified by "app" really
// owns the endpoint. Returns NULL on error.
endpoint_t* WhichEndpoint(BMessage* msg, app_t* app);
// Returns the endpoint with the specified ID, or int32 _CountConnections(endpoint_t* prod);
// NULL if no such endpoint exists on the roster. endpoint_t* _ConnectionAt(endpoint_t* prod, int32 index);
endpoint_t* FindEndpoint(int32 id);
// Sends notification messages to all registered apps, #ifdef DEBUG
// except to the application that triggered the event. void _DumpApps();
// The "except" app is allowed to be NULL. void _DumpEndpoints();
void NotifyAll(BMessage* msg, app_t* except); #endif
// Sends a notification message to an application, which is private:
// not necessarily registered yet. Applications never reply //! The registered applications.
// to such notification messages. BList fApps;
bool SendNotification(app_t* app, BMessage* msg);
// Sends a reply to a request made by an application. //! All the endpoints in the system.
// If "app" is NULL, the application is not registered BList fEndpoints;
// (and the reply should contain an error code).
bool SendReply(app_t* app, BMessage* msg, BMessage* reply);
// Removes an app and all of its endpoints from the roster //! The ID we will assign to the next new endpoint.
// if a reply or notification message cannot be delivered. int32 fNextID;
// (Waiting for communications to fail is actually our only
// way to get rid of stale endpoints.)
void DeliveryError(app_t* app);
int32 CountApps(); //! Watch endpoints from /dev/midi drivers.
app_t* AppAt(int32 index);
int32 CountEndpoints();
endpoint_t* EndpointAt(int32 index);
int32 CountConnections(endpoint_t* prod);
endpoint_t* ConnectionAt(endpoint_t* prod, int32 index);
// The registered applications.
BList apps;
// All the endpoints in the system.
BList endpoints;
// The ID we will assign to the next new endpoint.
int32 nextId;
// Watch endpoints from /dev/midi drivers.
DeviceWatcher* fDeviceWatcher; DeviceWatcher* fDeviceWatcher;
#ifdef DEBUG
void DumpApps();
void DumpEndpoints();
#endif
}; };
#endif // MIDI_SERVER_APP_H #endif // MIDI_SERVER_APP_H