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