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