2 * Copyright 2006, Haiku.
4 * Copyright (c) 2002-2004 Matthijs Hollemans
5 * Distributed under the terms of the MIT License.
12 #include <MidiConsumer.h>
13 #include <MidiRoster.h>
14 #include "MidiRosterLooper.h"
20 using namespace BPrivate
;
22 // The midi_debug_level and midi_dispatcher_priority symbols
23 // were exported by Be's libmidi2, and even though they do not
24 // appear in the headers, some apps may still be using them.
25 // For backwards compatibility's sake, we export those symbols
26 // as well, even though we do not use them for anything.
28 // Not used. For backwards compatibility only.
29 int32 midi_debug_level
= 0;
31 // Not used. For backwards compatibility only.
32 int32 midi_dispatcher_priority
= B_REAL_TIME_PRIORITY
;
34 //------------------------------------------------------------------------------
36 // The one and only BMidiRoster instance, which is created
37 // the first time the client app calls MidiRoster(). It is
38 // destroyed by the BMidiRosterKiller when the app quits.
39 static BMidiRoster
* sRoster
= NULL
;
41 static pthread_once_t sInitOnce
= PTHREAD_ONCE_INIT
;
44 // Destroys the BMidiRoster instance when the app quits.
47 static struct BMidiRosterKiller
54 static void CreateRoster() {
55 sRoster
= new BMidiRoster();
63 BMidiRoster::NextEndpoint(int32
* id
)
65 BMidiEndpoint
* endp
= NULL
;
68 BMidiRosterLooper
* looper
= MidiRoster()->fLooper
;
70 endp
= looper
->NextEndpoint(id
);
83 BMidiRoster::NextProducer(int32
* id
)
87 while ((endp
= NextEndpoint(id
)) != NULL
) {
88 if (endp
->IsProducer()) {
89 return (BMidiProducer
*) endp
;
99 BMidiRoster::NextConsumer(int32
* id
)
103 while ((endp
= NextEndpoint(id
)) != NULL
) {
104 if (endp
->IsConsumer()) {
105 return (BMidiConsumer
*) endp
;
115 BMidiRoster::FindEndpoint(int32 id
, bool localOnly
)
117 BMidiEndpoint
* endp
= NULL
;
119 BMidiRosterLooper
* looper
= MidiRoster()->fLooper
;
120 if (looper
->Lock()) {
121 endp
= looper
->FindEndpoint(id
);
123 if ((endp
!= NULL
) && endp
->IsRemote()) {
124 if (localOnly
|| !endp
->IsRegistered()) {
141 BMidiRoster::FindProducer(int32 id
, bool localOnly
)
143 BMidiEndpoint
* endp
= FindEndpoint(id
, localOnly
);
145 if ((endp
!= NULL
) && !endp
->IsProducer()) {
150 return (BMidiProducer
*) endp
;
155 BMidiRoster::FindConsumer(int32 id
, bool localOnly
)
157 BMidiEndpoint
* endp
= FindEndpoint(id
, localOnly
);
159 if ((endp
!= NULL
) && !endp
->IsConsumer()) {
164 return (BMidiConsumer
*) endp
;
169 BMidiRoster::StartWatching(const BMessenger
* msngr
)
172 WARN("StartWatching does not accept a NULL messenger")
174 BMidiRosterLooper
* looper
= MidiRoster()->fLooper
;
175 if (looper
->Lock()) {
176 looper
->StartWatching(msngr
);
184 BMidiRoster::StopWatching()
186 BMidiRosterLooper
* looper
= MidiRoster()->fLooper
;
187 if (looper
->Lock()) {
188 looper
->StopWatching();
195 BMidiRoster::Register(BMidiEndpoint
* endp
)
198 return endp
->Register();
206 BMidiRoster::Unregister(BMidiEndpoint
* endp
)
209 return endp
->Unregister();
217 BMidiRoster::MidiRoster()
219 pthread_once(&sInitOnce
, BPrivate::BMidiRosterKiller::CreateRoster
);
225 BMidiRoster::BMidiRoster()
227 TRACE(("BMidiRoster::BMidiRoster"))
229 fLooper
= new BMidiRosterLooper();
231 if (!fLooper
->Init(this))
235 msg
.what
= MSG_REGISTER_APP
;
236 msg
.AddMessenger("midi:messenger", BMessenger(fLooper
));
237 fServer
= new BMessenger(MIDI_SERVER_SIGNATURE
);
239 if (fServer
->SendMessage(&msg
, fLooper
, TIMEOUT
) != B_OK
) {
240 WARN("Cannot send request to midi_server");
244 // Although unlikely, we may receive the midi_server's
245 // "app registered" reply before we lock the semaphore.
246 // In that case, BMidiRosterLooper's MessageReceived()
247 // will bump the semaphore count, and our acquire_sem()
248 // can grab the semaphore safely (without blocking).
250 acquire_sem(fLooper
->fInitLock
);
254 BMidiRoster::~BMidiRoster()
256 TRACE(("BMidiRoster::~BMidiRoster"))
258 if (fLooper
!= NULL
) {
266 void BMidiRoster::_Reserved1() { }
267 void BMidiRoster::_Reserved2() { }
268 void BMidiRoster::_Reserved3() { }
269 void BMidiRoster::_Reserved4() { }
270 void BMidiRoster::_Reserved5() { }
271 void BMidiRoster::_Reserved6() { }
272 void BMidiRoster::_Reserved7() { }
273 void BMidiRoster::_Reserved8() { }
277 BMidiRoster::CreateLocal(BMidiEndpoint
* endp
)
281 // We are being called from the BMidiLocalConsumer or
282 // BMidiLocalProducer constructor, so there is no need
283 // to lock anything, because at this point there cannot
284 // be multiple threads accessing the endpoint's data.
287 msg
.what
= MSG_CREATE_ENDPOINT
;
288 msg
.AddBool("midi:consumer", endp
->fIsConsumer
);
289 msg
.AddBool("midi:registered", endp
->fIsRegistered
);
290 msg
.AddString("midi:name", endp
->Name());
291 msg
.AddMessage("midi:properties", endp
->fProperties
);
293 if (endp
->IsConsumer()) {
294 BMidiConsumer
* consumer
= (BMidiConsumer
*) endp
;
295 msg
.AddInt32("midi:port", consumer
->fPort
);
296 msg
.AddInt64("midi:latency", consumer
->fLatency
);
300 if (SendRequest(&msg
, &reply
) == B_OK
) {
302 if (reply
.FindInt32("midi:result", &res
) == B_OK
) {
305 if (reply
.FindInt32("midi:id", &id
) == B_OK
) {
308 if (fLooper
->Lock()) {
309 fLooper
->AddEndpoint(endp
);
317 // There are many things that can go wrong when creating
318 // a new endpoint, but BMidiEndpoint has no InitCheck()
319 // method to check for this. (You can, however, see if the
320 // endpoint's ID is 0 after the constructor returns, or
321 // call IsValid().) In any case, you should still Release()
322 // the endpoint to delete the object. (This is different
323 // from Be's implementation, which bumps the refcount only
324 // when creation succeeded. If you call Release(), you'll
325 // trip an assertion, so you can't delete these endpoints.)
330 BMidiRoster::DeleteLocal(BMidiEndpoint
* endp
)
335 msg
.what
= MSG_DELETE_ENDPOINT
;
336 msg
.AddInt32("midi:id", endp
->ID());
338 // Note: this is always called from BMidiLocalConsumer's
339 // or BMidiLocalProducer's destructor, so we don't expect
340 // a reply from the server. If something went wrong, the
341 // object will be destroyed regardless.
343 fServer
->SendMessage(&msg
, (BHandler
*) NULL
, TIMEOUT
);
345 // If the endpoint was successfully created, we must remove
346 // it from the list of endpoints. If creation failed, then
347 // we didn't put the endpoint on that list. If the endpoint
348 // was connected to anything, we must also disconnect it.
350 if (endp
->ID() > 0) {
351 if (fLooper
->Lock()) {
352 fLooper
->RemoveEndpoint(endp
);
360 BMidiRoster::SendRequest(BMessage
* msg
, BMessage
* reply
)
363 ASSERT(reply
!= NULL
)
365 status_t err
= fServer
->SendMessage(msg
, reply
, TIMEOUT
, TIMEOUT
);
368 WARN("Cannot send request to midi_server");
373 printf("REPLY "); reply
->PrintToStream();