xref: /haiku/src/kits/midi2/MidiEndpoint.cpp (revision 1a7bcf6962e1c99906cce0fe602e08c3fcda46f6)
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 
18 const char*
Name() const19 BMidiEndpoint::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 
36 void
SetName(const char * newName)37 BMidiEndpoint::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 
64 int32
ID() const65 BMidiEndpoint::ID() const
66 {
67 	return fId;
68 }
69 
70 
71 bool
IsProducer() const72 BMidiEndpoint::IsProducer() const
73 {
74 	return !fIsConsumer;
75 }
76 
77 
78 bool
IsConsumer() const79 BMidiEndpoint::IsConsumer() const
80 {
81 	return fIsConsumer;
82 }
83 
84 
85 bool
IsRemote() const86 BMidiEndpoint::IsRemote() const
87 {
88 	return !fIsLocal;
89 }
90 
91 
92 bool
IsLocal() const93 BMidiEndpoint::IsLocal() const
94 {
95 	return fIsLocal;
96 }
97 
98 
99 bool
IsPersistent() const100 BMidiEndpoint::IsPersistent() const
101 {
102 	return false;
103 }
104 
105 
106 bool
IsValid() const107 BMidiEndpoint::IsValid() const
108 {
109 	if (IsLocal())
110 		return (ID() > 0);
111 
112 	// remote endpoint
113 	return IsRegistered();
114 }
115 
116 
117 status_t
Release()118 BMidiEndpoint::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 
141 status_t
Acquire()142 BMidiEndpoint::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 
155 status_t
SetProperties(const BMessage * properties_)156 BMidiEndpoint::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 
183 status_t
GetProperties(BMessage * _properties) const184 BMidiEndpoint::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 
200 status_t
Register()201 BMidiEndpoint::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 
218 status_t
Unregister()219 BMidiEndpoint::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 
BMidiEndpoint(const char * name_)236 BMidiEndpoint::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 
~BMidiEndpoint()253 BMidiEndpoint::~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 
_Reserved1()267 void BMidiEndpoint::_Reserved1() { }
_Reserved2()268 void BMidiEndpoint::_Reserved2() { }
_Reserved3()269 void BMidiEndpoint::_Reserved3() { }
_Reserved4()270 void BMidiEndpoint::_Reserved4() { }
_Reserved5()271 void BMidiEndpoint::_Reserved5() { }
_Reserved6()272 void BMidiEndpoint::_Reserved6() { }
_Reserved7()273 void BMidiEndpoint::_Reserved7() { }
_Reserved8()274 void BMidiEndpoint::_Reserved8() { }
275 
276 //------------------------------------------------------------------------------
277 
278 status_t
SendRegisterRequest(bool registered)279 BMidiEndpoint::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 
296 status_t
SendChangeRequest(BMessage * msg)297 BMidiEndpoint::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 
317 bool
IsRegistered() const318 BMidiEndpoint::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 
327 bool
LockLooper() const328 BMidiEndpoint::LockLooper() const
329 {
330 	return BMidiRoster::MidiRoster()->fLooper->Lock();
331 }
332 
333 
334 void
UnlockLooper() const335 BMidiEndpoint::UnlockLooper() const
336 {
337 	BMidiRoster::MidiRoster()->fLooper->Unlock();
338 }
339 
340