xref: /haiku/src/kits/midi2/MidiEndpoint.cpp (revision 39241fe22890fb958b6ba32d6ab9526da98be187)
1 /*
2  * Copyright (c) 2002-2003 Matthijs Hollemans
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "debug.h"
24 #include "MidiEndpoint.h"
25 #include "MidiRoster.h"
26 #include "MidiRosterLooper.h"
27 #include "protocol.h"
28 
29 //------------------------------------------------------------------------------
30 
31 const char* BMidiEndpoint::Name() const
32 {
33 	const char* str = NULL;
34 
35 	// It seems reasonable to assume that the pointer returned by
36 	// BString::String() can change when the string is modified,
37 	// e.g. to allocate more space. That's why we lock here too.
38 
39 	if (LockLooper())
40 	{
41 		str = name.String();
42 		UnlockLooper();
43 	}
44 
45 	return str;
46 }
47 
48 //------------------------------------------------------------------------------
49 
50 void BMidiEndpoint::SetName(const char* name_)
51 {
52 	if (name_ == NULL)
53 	{
54 		WARN("SetName() does not accept a NULL name");
55 		return;
56 	}
57 	else if (IsRemote())
58 	{
59 		WARN("SetName() is not allowed on remote endpoints");
60 		return;
61 	}
62 	else if (!IsValid())
63 	{
64 		return;
65 	}
66 	else if (name != name_)
67 	{
68 		BMessage msg;
69 		msg.AddString("midi:name", name_);
70 
71 		if (SendChangeRequest(&msg) == B_OK)
72 		{
73 			if (LockLooper())
74 			{
75 				name.SetTo(name_);
76 				UnlockLooper();
77 			}
78 		}
79 	}
80 }
81 
82 //------------------------------------------------------------------------------
83 
84 int32 BMidiEndpoint::ID() const
85 {
86 	return id;
87 }
88 
89 //------------------------------------------------------------------------------
90 
91 bool BMidiEndpoint::IsProducer() const
92 {
93 	return !isConsumer;
94 }
95 
96 //------------------------------------------------------------------------------
97 
98 bool BMidiEndpoint::IsConsumer() const
99 {
100 	return isConsumer;
101 }
102 
103 //------------------------------------------------------------------------------
104 
105 bool BMidiEndpoint::IsRemote() const
106 {
107 	return !isLocal;
108 }
109 
110 //------------------------------------------------------------------------------
111 
112 bool BMidiEndpoint::IsLocal() const
113 {
114 	return isLocal;
115 }
116 
117 //------------------------------------------------------------------------------
118 
119 bool BMidiEndpoint::IsPersistent() const
120 {
121 	return false;
122 }
123 
124 //------------------------------------------------------------------------------
125 
126 bool BMidiEndpoint::IsValid() const
127 {
128 	if (IsLocal())
129 	{
130 		return (ID() > 0);
131 	}
132 	else  // remote endpoint
133 	{
134 		return IsRegistered();
135 	}
136 }
137 
138 //------------------------------------------------------------------------------
139 
140 status_t BMidiEndpoint::Release()
141 {
142 	int32 old = atomic_add(&refCount, -1);
143 
144 	TRACE(("BMidiEndpoint::Release refCount is now %ld", old - 1))
145 
146 	if (old == 1)
147 	{
148 		// If the reference count of a local endpoint drops to zero,
149 		// we must delete it. The destructor of BMidiLocalXXX calls
150 		// BMidiRoster::DeleteLocal(), which does all the hard work.
151 		// If we are a proxy for a remote endpoint, we must only be
152 		// deleted if that remote endpoint no longer exists.
153 
154 		if (IsLocal() || !isAlive)
155 		{
156 			delete this;
157 		}
158 	}
159 	else if (old <= 0)
160 	{
161 		debugger("too many calls to Release()");
162 	}
163 
164 	return B_OK;
165 }
166 
167 //------------------------------------------------------------------------------
168 
169 status_t BMidiEndpoint::Acquire()
170 {
171 	int32 old = atomic_add(&refCount, 1);
172 
173 	TRACE(("BMidiEndpoint::Acquire refCount is now %ld", old + 1))
174 
175 	return B_OK;
176 }
177 
178 //------------------------------------------------------------------------------
179 
180 status_t BMidiEndpoint::SetProperties(const BMessage* properties_)
181 {
182 	if (properties_ == NULL)
183 	{
184 		WARN("SetProperties() does not accept a NULL message")
185 		return B_BAD_VALUE;
186 	}
187 	else if (IsRemote())
188 	{
189 		WARN("SetProperties() is not allowed on remote endpoints");
190 		return B_ERROR;
191 	}
192 	else if (!IsValid())
193 	{
194 		return B_ERROR;
195 	}
196 	else
197 	{
198 		BMessage msg;
199 		msg.AddMessage("midi:properties", properties_);
200 
201 		status_t err = SendChangeRequest(&msg);
202 		if (err == B_OK)
203 		{
204 			if (LockLooper())
205 			{
206 				*properties = *properties_;
207 				UnlockLooper();
208 			}
209 		}
210 
211 		return err;
212 	}
213 }
214 
215 //------------------------------------------------------------------------------
216 
217 status_t BMidiEndpoint::GetProperties(BMessage* properties_) const
218 {
219 	if (properties_ == NULL)
220 	{
221 		WARN("GetProperties() does not accept NULL properties")
222 		return B_BAD_VALUE;
223 	}
224 
225 	if (LockLooper())
226 	{
227 		*properties_ = *properties;
228 		UnlockLooper();
229 	}
230 
231 	return B_OK;
232 }
233 
234 //------------------------------------------------------------------------------
235 
236 status_t BMidiEndpoint::Register(void)
237 {
238 	if (IsRemote())
239 	{
240 		WARN("You cannot Register() remote endpoints");
241 		return B_ERROR;
242 	}
243 	else if (IsRegistered())
244 	{
245 		WARN("This endpoint is already registered");
246 		return B_OK;
247 	}
248 	else if (!IsValid())
249 	{
250 		return B_ERROR;
251 	}
252 	else
253 	{
254 		return SendRegisterRequest(true);
255 	}
256 }
257 
258 //------------------------------------------------------------------------------
259 
260 status_t BMidiEndpoint::Unregister(void)
261 {
262 	if (IsRemote())
263 	{
264 		WARN("You cannot Unregister() remote endpoints");
265 		return B_ERROR;
266 	}
267 	else if (!IsRegistered())
268 	{
269 		WARN("This endpoint is already unregistered");
270 		return B_OK;
271 	}
272 	else if (!IsValid())
273 	{
274 		return B_ERROR;
275 	}
276 	else
277 	{
278 		return SendRegisterRequest(false);
279 	}
280 }
281 
282 //------------------------------------------------------------------------------
283 
284 BMidiEndpoint::BMidiEndpoint(const char* name_)
285 {
286 	TRACE(("BMidiEndpoint::BMidiEndpoint"))
287 
288 	if (name_ != NULL)
289 	{
290 		name.SetTo(name_);
291 	}
292 
293 	id           = 0;
294 	refCount     = 0;
295 	isLocal      = false;
296 	isRegistered = false;
297 	isAlive      = true;
298 
299 	properties = new BMessage;
300 }
301 
302 //------------------------------------------------------------------------------
303 
304 BMidiEndpoint::~BMidiEndpoint()
305 {
306 	TRACE(("BMidiEndpoint::~BMidiEndpoint (%p)", this))
307 
308 	if (refCount > 0)
309 	{
310 		debugger(
311 			"you should use Release() to dispose of endpoints; "
312 			"do not \"delete\" them or allocate them on the stack!");
313 	}
314 
315 	delete properties;
316 }
317 
318 //------------------------------------------------------------------------------
319 
320 void BMidiEndpoint::_Reserved1() { }
321 void BMidiEndpoint::_Reserved2() { }
322 void BMidiEndpoint::_Reserved3() { }
323 void BMidiEndpoint::_Reserved4() { }
324 void BMidiEndpoint::_Reserved5() { }
325 void BMidiEndpoint::_Reserved6() { }
326 void BMidiEndpoint::_Reserved7() { }
327 void BMidiEndpoint::_Reserved8() { }
328 
329 //------------------------------------------------------------------------------
330 
331 status_t BMidiEndpoint::SendRegisterRequest(bool registered)
332 {
333 	BMessage msg;
334 	msg.AddBool("midi:registered", registered);
335 
336 	status_t err = SendChangeRequest(&msg);
337 	if (err == B_OK)
338 	{
339 		if (LockLooper())
340 		{
341 			isRegistered = registered;
342 			UnlockLooper();
343 		}
344 	}
345 
346 	return err;
347 }
348 
349 //------------------------------------------------------------------------------
350 
351 status_t BMidiEndpoint::SendChangeRequest(BMessage* msg)
352 {
353 	ASSERT(msg != NULL)
354 
355 	msg->what = MSG_CHANGE_ENDPOINT;
356 	msg->AddInt32("midi:id", ID());
357 
358 	BMessage reply;
359 	status_t err = BMidiRoster::MidiRoster()->SendRequest(msg, &reply);
360 	if (err != B_OK) { return err; }
361 
362 	status_t res;
363 	if (reply.FindInt32("midi:result", &res) == B_OK)
364 	{
365 		return res;
366 	}
367 
368 	return B_ERROR;
369 }
370 
371 //------------------------------------------------------------------------------
372 
373 bool BMidiEndpoint::IsRegistered() const
374 {
375 	// No need to protect this with a lock, because reading
376 	// and writing a bool is always an atomic operation.
377 
378 	return isRegistered;
379 }
380 
381 //------------------------------------------------------------------------------
382 
383 bool BMidiEndpoint::LockLooper() const
384 {
385 	return BMidiRoster::MidiRoster()->looper->Lock();
386 }
387 
388 //------------------------------------------------------------------------------
389 
390 void BMidiEndpoint::UnlockLooper() const
391 {
392 	BMidiRoster::MidiRoster()->looper->Unlock();
393 }
394 
395 //------------------------------------------------------------------------------
396