* Copyright 2006, Haiku.
*
* Copyright (c) 2002-2004 Matthijs Hollemans
* Distributed under the terms of the MIT License.
*
* Authors:
* Matthijs Hollemans
*/
#include "debug.h"
#include <MidiConsumer.h>
#include <MidiRoster.h>
#include "MidiRosterLooper.h"
#include "protocol.h"
#include <pthread.h>
using namespace BPrivate;
int32 midi_debug_level = 0;
int32 midi_dispatcher_priority = B_REAL_TIME_PRIORITY;
static BMidiRoster* sRoster = NULL;
static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT;
namespace BPrivate
{
static struct BMidiRosterKiller
{
~BMidiRosterKiller()
{
delete sRoster;
}
static void CreateRoster() {
sRoster = new BMidiRoster();
}
}
midi_roster_killer;
}
BMidiEndpoint*
BMidiRoster::NextEndpoint(int32* id)
{
BMidiEndpoint* endp = NULL;
if (id != NULL) {
BMidiRosterLooper* looper = MidiRoster()->fLooper;
if (looper->Lock()) {
endp = looper->NextEndpoint(id);
if (endp != NULL) {
endp->Acquire();
}
looper->Unlock();
}
}
return endp;
}
BMidiProducer*
BMidiRoster::NextProducer(int32* id)
{
BMidiEndpoint* endp;
while ((endp = NextEndpoint(id)) != NULL) {
if (endp->IsProducer()) {
return (BMidiProducer*) endp;
}
endp->Release();
}
return NULL;
}
BMidiConsumer*
BMidiRoster::NextConsumer(int32* id)
{
BMidiEndpoint* endp;
while ((endp = NextEndpoint(id)) != NULL) {
if (endp->IsConsumer()) {
return (BMidiConsumer*) endp;
}
endp->Release();
}
return NULL;
}
BMidiEndpoint*
BMidiRoster::FindEndpoint(int32 id, bool localOnly)
{
BMidiEndpoint* endp = NULL;
BMidiRosterLooper* looper = MidiRoster()->fLooper;
if (looper->Lock()) {
endp = looper->FindEndpoint(id);
if ((endp != NULL) && endp->IsRemote()) {
if (localOnly || !endp->IsRegistered()) {
endp = NULL;
}
}
if (endp != NULL) {
endp->Acquire();
}
looper->Unlock();
}
return endp;
}
BMidiProducer*
BMidiRoster::FindProducer(int32 id, bool localOnly)
{
BMidiEndpoint* endp = FindEndpoint(id, localOnly);
if ((endp != NULL) && !endp->IsProducer()) {
endp->Release();
endp = NULL;
}
return (BMidiProducer*) endp;
}
BMidiConsumer*
BMidiRoster::FindConsumer(int32 id, bool localOnly)
{
BMidiEndpoint* endp = FindEndpoint(id, localOnly);
if ((endp != NULL) && !endp->IsConsumer()) {
endp->Release();
endp = NULL;
}
return (BMidiConsumer*) endp;
}
void
BMidiRoster::StartWatching(const BMessenger* msngr)
{
if (msngr == NULL) {
WARN("StartWatching does not accept a NULL messenger")
} else {
BMidiRosterLooper* looper = MidiRoster()->fLooper;
if (looper->Lock()) {
looper->StartWatching(msngr);
looper->Unlock();
}
}
}
void
BMidiRoster::StopWatching()
{
BMidiRosterLooper* looper = MidiRoster()->fLooper;
if (looper->Lock()) {
looper->StopWatching();
looper->Unlock();
}
}
status_t
BMidiRoster::Register(BMidiEndpoint* endp)
{
if (endp != NULL) {
return endp->Register();
}
return B_BAD_VALUE;
}
status_t
BMidiRoster::Unregister(BMidiEndpoint* endp)
{
if (endp != NULL) {
return endp->Unregister();
}
return B_BAD_VALUE;
}
BMidiRoster*
BMidiRoster::MidiRoster()
{
pthread_once(&sInitOnce, BPrivate::BMidiRosterKiller::CreateRoster);
return sRoster;
}
BMidiRoster::BMidiRoster()
{
TRACE(("BMidiRoster::BMidiRoster"))
fLooper = new BMidiRosterLooper();
if (!fLooper->Init(this))
return;
BMessage msg;
msg.what = MSG_REGISTER_APP;
msg.AddMessenger("midi:messenger", BMessenger(fLooper));
fServer = new BMessenger(MIDI_SERVER_SIGNATURE);
if (fServer->SendMessage(&msg, fLooper, TIMEOUT) != B_OK) {
WARN("Cannot send request to midi_server");
return;
}
acquire_sem(fLooper->fInitLock);
}
BMidiRoster::~BMidiRoster()
{
TRACE(("BMidiRoster::~BMidiRoster"))
if (fLooper != NULL) {
fLooper->Lock();
fLooper->Quit();
}
delete fServer;
}
void BMidiRoster::_Reserved1() { }
void BMidiRoster::_Reserved2() { }
void BMidiRoster::_Reserved3() { }
void BMidiRoster::_Reserved4() { }
void BMidiRoster::_Reserved5() { }
void BMidiRoster::_Reserved6() { }
void BMidiRoster::_Reserved7() { }
void BMidiRoster::_Reserved8() { }
void
BMidiRoster::CreateLocal(BMidiEndpoint* endp)
{
ASSERT(endp != NULL)
BMessage msg;
msg.what = MSG_CREATE_ENDPOINT;
msg.AddBool("midi:consumer", endp->fIsConsumer);
msg.AddBool("midi:registered", endp->fIsRegistered);
msg.AddString("midi:name", endp->Name());
msg.AddMessage("midi:properties", endp->fProperties);
if (endp->IsConsumer()) {
BMidiConsumer* consumer = (BMidiConsumer*) endp;
msg.AddInt32("midi:port", consumer->fPort);
msg.AddInt64("midi:latency", consumer->fLatency);
}
BMessage reply;
if (SendRequest(&msg, &reply) == B_OK) {
status_t res;
if (reply.FindInt32("midi:result", &res) == B_OK) {
if (res == B_OK) {
int32 id;
if (reply.FindInt32("midi:id", &id) == B_OK) {
endp->fId = id;
if (fLooper->Lock()) {
fLooper->AddEndpoint(endp);
fLooper->Unlock();
}
}
}
}
}
}
void
BMidiRoster::DeleteLocal(BMidiEndpoint* endp)
{
ASSERT(endp != NULL)
BMessage msg;
msg.what = MSG_DELETE_ENDPOINT;
msg.AddInt32("midi:id", endp->ID());
fServer->SendMessage(&msg, (BHandler*) NULL, TIMEOUT);
if (endp->ID() > 0) {
if (fLooper->Lock()) {
fLooper->RemoveEndpoint(endp);
fLooper->Unlock();
}
}
}
status_t
BMidiRoster::SendRequest(BMessage* msg, BMessage* reply)
{
ASSERT(msg != NULL)
ASSERT(reply != NULL)
status_t err = fServer->SendMessage(msg, reply, TIMEOUT, TIMEOUT);
if (err != B_OK) {
WARN("Cannot send request to midi_server");
}
#ifdef DEBUG
if (err == B_OK) {
printf("REPLY "); reply->PrintToStream();
}
#endif
return err;
}