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 <MidiEndpoint.h>
13#include <MidiRoster.h>
14#include "MidiRosterLooper.h"
15#include "protocol.h"
16
17
18const char*
19BMidiEndpoint::Name() const
20{
21	const char* str = NULL;
22
23	// It seems reasonable to assume that the pointer returned by
24	// BString::String() can change when the string is modified,
25	// e.g. to allocate more space. That's why we lock here too.
26
27	if (LockLooper()) {
28		str = fName.String();
29		UnlockLooper();
30	}
31
32	return str;
33}
34
35
36void
37BMidiEndpoint::SetName(const char* newName)
38{
39	if (newName == NULL) {
40		WARN("SetName() does not accept a NULL name");
41		return;
42	}
43	if (IsRemote()) {
44		WARN("SetName() is not allowed on remote endpoints");
45		return;
46	}
47	if (!IsValid())
48		return;
49
50	if (fName != newName) {
51		BMessage msg;
52		msg.AddString("midi:name", newName);
53
54		if (SendChangeRequest(&msg) == B_OK) {
55			if (LockLooper()) {
56				fName.SetTo(newName);
57				UnlockLooper();
58			}
59		}
60	}
61}
62
63
64int32
65BMidiEndpoint::ID() const
66{
67	return fId;
68}
69
70
71bool
72BMidiEndpoint::IsProducer() const
73{
74	return !fIsConsumer;
75}
76
77
78bool
79BMidiEndpoint::IsConsumer() const
80{
81	return fIsConsumer;
82}
83
84
85bool
86BMidiEndpoint::IsRemote() const
87{
88	return !fIsLocal;
89}
90
91
92bool
93BMidiEndpoint::IsLocal() const
94{
95	return fIsLocal;
96}
97
98
99bool
100BMidiEndpoint::IsPersistent() const
101{
102	return false;
103}
104
105
106bool
107BMidiEndpoint::IsValid() const
108{
109	if (IsLocal())
110		return (ID() > 0);
111
112	// remote endpoint
113	return IsRegistered();
114}
115
116
117status_t
118BMidiEndpoint::Release()
119{
120	int32 old = atomic_add(&fRefCount, -1);
121
122	TRACE(("BMidiEndpoint::Release refCount is now %" B_PRId32, old - 1))
123
124	if (old == 1) {
125		// If the reference count of a local endpoint drops to zero,
126		// we must delete it. The destructor of BMidiLocalXXX calls
127		// BMidiRoster::DeleteLocal(), which does all the hard work.
128		// If we are a proxy for a remote endpoint, we must only be
129		// deleted if that remote endpoint no longer exists.
130
131		if (IsLocal() || !fIsAlive)
132			delete this;
133	} else if (old <= 0) {
134		debugger("too many calls to Release()");
135	}
136
137	return B_OK;
138}
139
140
141status_t
142BMidiEndpoint::Acquire()
143{
144#ifdef DEBUG
145	int32 old =
146#endif
147	atomic_add(&fRefCount, 1);
148
149	TRACE(("BMidiEndpoint::Acquire refCount is now %" B_PRId32, old + 1))
150
151	return B_OK;
152}
153
154
155status_t
156BMidiEndpoint::SetProperties(const BMessage* properties_)
157{
158	if (properties_ == NULL) {
159		WARN("SetProperties() does not accept a NULL message")
160		return B_BAD_VALUE;
161	} else if (IsRemote()) {
162		WARN("SetProperties() is not allowed on remote endpoints");
163		return B_ERROR;
164	} else if (!IsValid())  {
165		return B_ERROR;
166	} else {
167		BMessage msg;
168		msg.AddMessage("midi:properties", properties_);
169
170		status_t err = SendChangeRequest(&msg);
171		if (err == B_OK) {
172			if (LockLooper()) {
173				*fProperties = *properties_;
174				UnlockLooper();
175			}
176		}
177
178		return err;
179	}
180}
181
182
183status_t
184BMidiEndpoint::GetProperties(BMessage* _properties) const
185{
186	if (_properties == NULL) {
187		WARN("GetProperties() does not accept NULL properties")
188		return B_BAD_VALUE;
189	}
190
191	if (LockLooper()) {
192		*_properties = *fProperties;
193		UnlockLooper();
194	}
195
196	return B_OK;
197}
198
199
200status_t
201BMidiEndpoint::Register()
202{
203	if (IsRemote()) {
204		WARN("You cannot Register() remote endpoints");
205		return B_ERROR;
206	}
207	if (IsRegistered()) {
208		WARN("This endpoint is already registered");
209		return B_OK;
210	}
211	if (!IsValid())
212		return B_ERROR;
213
214	return SendRegisterRequest(true);
215}
216
217
218status_t
219BMidiEndpoint::Unregister()
220{
221	if (IsRemote()) {
222		WARN("You cannot Unregister() remote endpoints");
223		return B_ERROR;
224	}
225	if (!IsRegistered()) {
226		WARN("This endpoint is already unregistered");
227		return B_OK;
228	}
229	if (!IsValid())
230		return B_ERROR;
231
232	return SendRegisterRequest(false);
233}
234
235
236BMidiEndpoint::BMidiEndpoint(const char* name_)
237{
238	TRACE(("BMidiEndpoint::BMidiEndpoint"))
239
240	if (name_ != NULL)
241		fName.SetTo(name_);
242
243	fId           = 0;
244	fRefCount     = 0;
245	fIsLocal      = false;
246	fIsRegistered = false;
247	fIsAlive      = true;
248
249	fProperties	= new BMessage();
250}
251
252
253BMidiEndpoint::~BMidiEndpoint()
254{
255	TRACE(("BMidiEndpoint::~BMidiEndpoint (%p)", this))
256
257	if (fRefCount > 0) {
258		debugger(
259			"you should use Release() to dispose of endpoints; "
260			"do not \"delete\" them or allocate them on the stack!");
261	}
262	delete fProperties;
263}
264
265//------------------------------------------------------------------------------
266
267void BMidiEndpoint::_Reserved1() { }
268void BMidiEndpoint::_Reserved2() { }
269void BMidiEndpoint::_Reserved3() { }
270void BMidiEndpoint::_Reserved4() { }
271void BMidiEndpoint::_Reserved5() { }
272void BMidiEndpoint::_Reserved6() { }
273void BMidiEndpoint::_Reserved7() { }
274void BMidiEndpoint::_Reserved8() { }
275
276//------------------------------------------------------------------------------
277
278status_t
279BMidiEndpoint::SendRegisterRequest(bool registered)
280{
281	BMessage msg;
282	msg.AddBool("midi:registered", registered);
283
284	status_t err = SendChangeRequest(&msg);
285	if (err == B_OK)  {
286		if (LockLooper()) {
287			fIsRegistered = registered;
288			UnlockLooper();
289		}
290	}
291
292	return err;
293}
294
295
296status_t
297BMidiEndpoint::SendChangeRequest(BMessage* msg)
298{
299	ASSERT(msg != NULL)
300
301	msg->what = MSG_CHANGE_ENDPOINT;
302	msg->AddInt32("midi:id", ID());
303
304	BMessage reply;
305	status_t err = BMidiRoster::MidiRoster()->SendRequest(msg, &reply);
306	if (err != B_OK)
307		return err;
308
309	status_t res;
310	if (reply.FindInt32("midi:result", &res) == B_OK)
311		return res;
312
313	return B_ERROR;
314}
315
316
317bool
318BMidiEndpoint::IsRegistered() const
319{
320	// No need to protect this with a lock, because reading
321	// and writing a bool is always an atomic operation.
322
323	return fIsRegistered;
324}
325
326
327bool
328BMidiEndpoint::LockLooper() const
329{
330	return BMidiRoster::MidiRoster()->fLooper->Lock();
331}
332
333
334void
335BMidiEndpoint::UnlockLooper() const
336{
337	BMidiRoster::MidiRoster()->fLooper->Unlock();
338}
339
340