1/*
2 * Copyright 2006, Haiku.
3 *
4 * Copyright (c) 2002-2003 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
6 *
7 * Authors:
8 *		Matthijs Hollemans
9 */
10
11#include "debug.h"
12#include <MidiConsumer.h>
13#include <MidiProducer.h>
14#include <MidiRoster.h>
15#include "MidiRosterLooper.h"
16#include "protocol.h"
17
18
19status_t
20BMidiProducer::Connect(BMidiConsumer* cons)
21{
22	if (cons == NULL) {
23		WARN("Connect() does not accept a NULL consumer")
24		return B_BAD_VALUE;
25	}
26	if (!IsValid() || !cons->IsValid()) {
27		return B_ERROR;
28	}
29	return SendConnectRequest(cons, true);
30}
31
32
33status_t
34BMidiProducer::Disconnect(BMidiConsumer* cons)
35{
36	if (cons == NULL) {
37		WARN("Disconnect() does not accept a NULL consumer")
38		return B_BAD_VALUE;
39	}
40	if (!IsValid() || !cons->IsValid()) {
41		return B_ERROR;
42	}
43	return SendConnectRequest(cons, false);
44}
45
46
47bool
48BMidiProducer::IsConnected(BMidiConsumer* cons) const
49{
50	bool isConnected = false;
51
52	if (cons != NULL) {
53		if (LockProducer()) {
54			isConnected = fConnections->HasItem(cons);
55			UnlockProducer();
56		}
57	}
58
59	return isConnected;
60}
61
62
63BList*
64BMidiProducer::Connections() const
65{
66	BList* list = new BList();
67
68	if (LockProducer()) {
69		for (int32 t = 0; t < CountConsumers(); ++t) {
70			BMidiConsumer* cons = ConsumerAt(t);
71			cons->Acquire();
72			list->AddItem(cons);
73		}
74
75		UnlockProducer();
76	}
77
78	return list;
79}
80
81
82BMidiProducer::BMidiProducer(const char* name)
83	: BMidiEndpoint(name),
84	fLocker("MidiProducerLock")
85{
86	fIsConsumer = false;
87	fConnections = new BList();
88}
89
90
91BMidiProducer::~BMidiProducer()
92{
93	delete fConnections;
94}
95
96
97void BMidiProducer::_Reserved1() { }
98void BMidiProducer::_Reserved2() { }
99void BMidiProducer::_Reserved3() { }
100void BMidiProducer::_Reserved4() { }
101void BMidiProducer::_Reserved5() { }
102void BMidiProducer::_Reserved6() { }
103void BMidiProducer::_Reserved7() { }
104void BMidiProducer::_Reserved8() { }
105
106
107status_t
108BMidiProducer::SendConnectRequest(
109	BMidiConsumer* cons, bool mustConnect)
110{
111	ASSERT(cons != NULL)
112
113	BMessage msg, reply;
114
115	if (mustConnect) {
116		msg.what = MSG_CONNECT_ENDPOINTS;
117	} else {
118		msg.what = MSG_DISCONNECT_ENDPOINTS;
119	}
120
121	msg.AddInt32("midi:producer", ID());
122	msg.AddInt32("midi:consumer", cons->ID());
123
124	status_t err = BMidiRoster::MidiRoster()->SendRequest(&msg, &reply);
125	if (err != B_OK)
126		return err;
127
128	status_t res;
129	if (reply.FindInt32("midi:result", &res) == B_OK) {
130		if (res == B_OK) {
131			if (mustConnect) {
132				ConnectionMade(cons);
133			} else {
134				ConnectionBroken(cons);
135			}
136
137			#ifdef DEBUG
138			BMidiRoster::MidiRoster()->fLooper->DumpEndpoints();
139			#endif
140		}
141
142		return res;
143	}
144
145	return B_ERROR;
146}
147
148
149void
150BMidiProducer::ConnectionMade(BMidiConsumer* consumer)
151{
152	if (consumer == NULL)
153		return;
154
155	if (LockProducer()) {
156		ASSERT(!fConnections->HasItem(consumer))
157
158		fConnections->AddItem(consumer);
159		UnlockProducer();
160	}
161
162	if (IsLocal()) {
163		((BMidiLocalProducer*) this)->Connected(consumer);
164	}
165}
166
167
168bool
169BMidiProducer::ConnectionBroken(BMidiConsumer* consumer)
170{
171	if (consumer == NULL)
172		return false;
173
174	bool wasConnected = false;
175
176	if (LockProducer()) {
177		wasConnected = fConnections->RemoveItem(consumer);
178		UnlockProducer();
179	}
180
181	if (wasConnected && IsLocal()) {
182		((BMidiLocalProducer*) this)->Disconnected(consumer);
183	}
184
185	return wasConnected;
186}
187
188
189int32
190BMidiProducer::CountConsumers() const
191{
192	return fConnections->CountItems();
193}
194
195
196BMidiConsumer*
197BMidiProducer::ConsumerAt(int32 index) const
198{
199	ASSERT(index >= 0 && index < CountConsumers())
200
201	return (BMidiConsumer*) fConnections->ItemAt(index);
202}
203
204
205bool
206BMidiProducer::LockProducer() const
207{
208	return fLocker.Lock();
209}
210
211
212void
213BMidiProducer::UnlockProducer() const
214{
215	fLocker.Unlock();
216}
217
218