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