⛏️ index : haiku.git

/*
 * Copyright 2006, Haiku.
 * 
 * Copyright (c) 2002-2003 Matthijs Hollemans
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Matthijs Hollemans
 */

#include "debug.h"
#include <MidiConsumer.h>
#include <MidiProducer.h>
#include <MidiRoster.h>
#include "MidiRosterLooper.h"
#include "protocol.h"


status_t 
BMidiProducer::Connect(BMidiConsumer* cons)
{
	if (cons == NULL) {
		WARN("Connect() does not accept a NULL consumer")
		return B_BAD_VALUE;
	}
	if (!IsValid() || !cons->IsValid()) {
		return B_ERROR;
	}
	return SendConnectRequest(cons, true);
}


status_t 
BMidiProducer::Disconnect(BMidiConsumer* cons)
{
	if (cons == NULL) {
		WARN("Disconnect() does not accept a NULL consumer")
		return B_BAD_VALUE;
	} 
	if (!IsValid() || !cons->IsValid()) {
		return B_ERROR;
	}
	return SendConnectRequest(cons, false);
}


bool 
BMidiProducer::IsConnected(BMidiConsumer* cons) const
{
	bool isConnected = false;

	if (cons != NULL) {
		if (LockProducer()) {
			isConnected = fConnections->HasItem(cons);
			UnlockProducer();
		}
	}
	
	return isConnected;
}


BList* 
BMidiProducer::Connections() const
{
	BList* list = new BList();

	if (LockProducer()) {
		for (int32 t = 0; t < CountConsumers(); ++t) {
			BMidiConsumer* cons = ConsumerAt(t);
			cons->Acquire();
			list->AddItem(cons);
		}

		UnlockProducer();
	}

	return list;
}


BMidiProducer::BMidiProducer(const char* name)
	: BMidiEndpoint(name),
	fLocker("MidiProducerLock")
{
	fIsConsumer = false;
	fConnections = new BList();
}


BMidiProducer::~BMidiProducer()
{
	delete fConnections;
}


void BMidiProducer::_Reserved1() { }
void BMidiProducer::_Reserved2() { }
void BMidiProducer::_Reserved3() { } 
void BMidiProducer::_Reserved4() { } 
void BMidiProducer::_Reserved5() { } 
void BMidiProducer::_Reserved6() { }
void BMidiProducer::_Reserved7() { }
void BMidiProducer::_Reserved8() { }


status_t 
BMidiProducer::SendConnectRequest(
	BMidiConsumer* cons, bool mustConnect)
{
	ASSERT(cons != NULL)

	BMessage msg, reply;

	if (mustConnect) {
		msg.what = MSG_CONNECT_ENDPOINTS;
	} else {
		msg.what = MSG_DISCONNECT_ENDPOINTS;
	}

	msg.AddInt32("midi:producer", ID());
	msg.AddInt32("midi:consumer", cons->ID());

	status_t err = BMidiRoster::MidiRoster()->SendRequest(&msg, &reply);
	if (err != B_OK) 
		return err;

	status_t res;
	if (reply.FindInt32("midi:result", &res) == B_OK) {
		if (res == B_OK) {
			if (mustConnect) {
				ConnectionMade(cons);
			} else {
				ConnectionBroken(cons);
			}

			#ifdef DEBUG
			BMidiRoster::MidiRoster()->fLooper->DumpEndpoints();
			#endif
		}

		return res;
	}

	return B_ERROR;
}


void 
BMidiProducer::ConnectionMade(BMidiConsumer* consumer)
{
	if (consumer == NULL)
		return;

	if (LockProducer()) {
		ASSERT(!fConnections->HasItem(consumer))

		fConnections->AddItem(consumer);
		UnlockProducer();
	}

	if (IsLocal()) {
		((BMidiLocalProducer*) this)->Connected(consumer);
	}
}


bool 
BMidiProducer::ConnectionBroken(BMidiConsumer* consumer)
{
	if (consumer == NULL)
		return false;
	
	bool wasConnected = false;

	if (LockProducer()) {
		wasConnected = fConnections->RemoveItem(consumer);
		UnlockProducer();
	}

	if (wasConnected && IsLocal()) {
		((BMidiLocalProducer*) this)->Disconnected(consumer);
	}

	return wasConnected;
}


int32 
BMidiProducer::CountConsumers() const
{
	return fConnections->CountItems();
}


BMidiConsumer* 
BMidiProducer::ConsumerAt(int32 index) const
{
	ASSERT(index >= 0 && index < CountConsumers())

	return (BMidiConsumer*) fConnections->ItemAt(index);
}


bool 
BMidiProducer::LockProducer() const
{
	return fLocker.Lock();
}


void 
BMidiProducer::UnlockProducer() const
{
	fLocker.Unlock();
}