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* 19 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 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 65 BMidiEndpoint::ID() const 66 { 67 return fId; 68 } 69 70 71 bool 72 BMidiEndpoint::IsProducer() const 73 { 74 return !fIsConsumer; 75 } 76 77 78 bool 79 BMidiEndpoint::IsConsumer() const 80 { 81 return fIsConsumer; 82 } 83 84 85 bool 86 BMidiEndpoint::IsRemote() const 87 { 88 return !fIsLocal; 89 } 90 91 92 bool 93 BMidiEndpoint::IsLocal() const 94 { 95 return fIsLocal; 96 } 97 98 99 bool 100 BMidiEndpoint::IsPersistent() const 101 { 102 return false; 103 } 104 105 106 bool 107 BMidiEndpoint::IsValid() const 108 { 109 if (IsLocal()) 110 return (ID() > 0); 111 112 // remote endpoint 113 return IsRegistered(); 114 } 115 116 117 status_t 118 BMidiEndpoint::Release() 119 { 120 int32 old = atomic_add(&fRefCount, -1); 121 122 TRACE(("BMidiEndpoint::Release refCount is now %ld", 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 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 %ld", old + 1)) 150 151 return B_OK; 152 } 153 154 155 status_t 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 184 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 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 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 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 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 267 void BMidiEndpoint::_Reserved1() { } 268 void BMidiEndpoint::_Reserved2() { } 269 void BMidiEndpoint::_Reserved3() { } 270 void BMidiEndpoint::_Reserved4() { } 271 void BMidiEndpoint::_Reserved5() { } 272 void BMidiEndpoint::_Reserved6() { } 273 void BMidiEndpoint::_Reserved7() { } 274 void BMidiEndpoint::_Reserved8() { } 275 276 //------------------------------------------------------------------------------ 277 278 status_t 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 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 318 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 328 BMidiEndpoint::LockLooper() const 329 { 330 return BMidiRoster::MidiRoster()->fLooper->Lock(); 331 } 332 333 334 void 335 BMidiEndpoint::UnlockLooper() const 336 { 337 BMidiRoster::MidiRoster()->fLooper->Unlock(); 338 } 339 340