xref: /haiku/docs/develop/midi/oldprotocol.rst (revision a5061ecec55353a5f394759473f1fd6df04890da)
1*a5061eceSAdrien DestuguesThe BeOS R5 Midi Kit protocol
2*a5061eceSAdrien Destugues=============================
3*a5061eceSAdrien Destugues
4*a5061eceSAdrien DestuguesIn the course of writing the OpenBeOS Midi Kit, I spent some time
5*a5061eceSAdrien Destugueslooking at how BeOS R5's libmidi2.so and midi_server communicate. Not
6*a5061eceSAdrien Destuguesout of a compulsion to clone this protocol, but to learn from it. After
7*a5061eceSAdrien Destuguesall, the Be engineers spent a lot of time thinking about this already,
8*a5061eceSAdrien Destuguesand it would be foolish not to build on their experience. Here is what I
9*a5061eceSAdrien Destugueshave found out.
10*a5061eceSAdrien Destugues
11*a5061eceSAdrien DestuguesTwo kinds of communication happen: administrative tasks and MIDI events.
12*a5061eceSAdrien DestuguesThe housekeeping stuff is done by sending BMessages between the
13*a5061eceSAdrien DestuguesBMidiRoster and the midi_server. MIDI events are sent between producers
14*a5061eceSAdrien Destuguesand consumers using ports, without intervention from the server.
15*a5061eceSAdrien Destugues
16*a5061eceSAdrien DestuguesThis document describes the BMessage protocol. The protocol appears to
17*a5061eceSAdrien Destuguesbe asynchronous, which means that when BMidiRoster sends a message to
18*a5061eceSAdrien Destuguesthe midi_server, it does not wait around for a reply, even though the
19*a5061eceSAdrien Destuguesmidi_server replies to all messages. The libmidi2 functions *do* block
20*a5061eceSAdrien Destuguesuntil the reply is received, though, so client code does not have to
21*a5061eceSAdrien Destuguesworry about any of this.
22*a5061eceSAdrien Destugues
23*a5061eceSAdrien DestuguesBoth BMidiRoster and the midi_server can initiate messages. BMidiRoster
24*a5061eceSAdrien Destuguestypically sends a message when client code calls one of the functions
25*a5061eceSAdrien Destuguesfrom a libmidi2 class. When the midi_server sends messages, it is to
26*a5061eceSAdrien Destugueskeep BMidiRoster up-to-date about changes in the roster. BMidiRoster
27*a5061eceSAdrien Destuguesnever replies to messages from the server. The encoding of the BMessage
28*a5061eceSAdrien Destugues'what' codes indicates their direction. The 'Mxxx' messages are sent
29*a5061eceSAdrien Destuguesfrom libmidi2 to the midi_server. The 'mXXX' messages go the other way
30*a5061eceSAdrien Destuguesaround: from the server to a client.
31*a5061eceSAdrien Destugues
32*a5061eceSAdrien Destugues--------------
33*a5061eceSAdrien Destugues
34*a5061eceSAdrien DestuguesWho does what?
35*a5061eceSAdrien Destugues--------------
36*a5061eceSAdrien Destugues
37*a5061eceSAdrien DestuguesThe players here are the midi_server, which is a normal BApplication,
38*a5061eceSAdrien Destuguesand all the client apps, also BApplications. The client apps have loaded
39*a5061eceSAdrien Destuguesa copy of libmidi2 into their own address space. The main class from
40*a5061eceSAdrien Destugueslibmidi2 is BMidiRoster. The BMidiRoster has a BLooper that communicates
41*a5061eceSAdrien Destugueswith the midi_server's BLooper.
42*a5061eceSAdrien Destugues
43*a5061eceSAdrien DestuguesThe midi_server keeps a list of *all* endpoints in the system, even
44*a5061eceSAdrien Destugueslocal, nonpublished, ones. Each BMidiRoster instance keeps its own list
45*a5061eceSAdrien Destuguesof remote published endpoints, and all endpoints local to this
46*a5061eceSAdrien Destuguesapplication. It does not know about remote endpoints that are not
47*a5061eceSAdrien Destuguespublished yet.
48*a5061eceSAdrien Destugues
49*a5061eceSAdrien DestuguesWhenever you make a change to one of your own endpoints, your
50*a5061eceSAdrien DestuguesBMidiRoster notifies the midi_server. If your endpoint is published, the
51*a5061eceSAdrien Destuguesmidi_server then notifies all of the other BMidiRosters, so they can
52*a5061eceSAdrien Destuguesupdate their local rosters. It does *not* notify your own app!
53*a5061eceSAdrien Destugues(Sometimes, however, the midi_server also notifies everyone else even if
54*a5061eceSAdrien Destuguesyour local endpoint is *not* published. The reason for this escapes me,
55*a5061eceSAdrien Destuguesbecause the other BMidiRosters have no access to those endpoints
56*a5061eceSAdrien Destuguesanyway.)
57*a5061eceSAdrien Destugues
58*a5061eceSAdrien DestuguesBy the way, "notification" here means the internal communications
59*a5061eceSAdrien Destuguesbetween server and libmidi, not the B_MIDI_EVENT messages you receive
60*a5061eceSAdrien Destugueswhen you call BMidiRoster::StartWatching().
61*a5061eceSAdrien Destugues
62*a5061eceSAdrien Destugues--------------
63*a5061eceSAdrien Destugues
64*a5061eceSAdrien DestuguesBMidiRoster::MidiRoster()
65*a5061eceSAdrien Destugues-------------------------
66*a5061eceSAdrien Destugues
67*a5061eceSAdrien DestuguesThe first time it is called, this function creates the one-and-only
68*a5061eceSAdrien Destuguesinstance of BMidiRoster. Even if you don't explicitly call it yourself,
69*a5061eceSAdrien Destuguesit is used behind-the-scenes anyway by any of the other BMidiRoster
70*a5061eceSAdrien Destuguesfunctions. MidiRoster() constructs a BLooper and gets it running. Then
71*a5061eceSAdrien Destuguesit sends a BMessenger with the looper's address to the midi_server:
72*a5061eceSAdrien Destugues
73*a5061eceSAdrien Destugues::
74*a5061eceSAdrien Destugues
75*a5061eceSAdrien Destugues   OUT BMessage: what = Mapp (0x4d617070, or 1298231408)
76*a5061eceSAdrien Destugues       entry       be:msngr, type='MSNG', c=1, size=24,
77*a5061eceSAdrien Destugues
78*a5061eceSAdrien DestuguesThe server now responds with mOBJ messages for all *remote* *published*
79*a5061eceSAdrien Destuguesproducers and consumers. (Obviously, this list only contains remote
80*a5061eceSAdrien Destuguesobjects because by now you can't have created any local endpoints yet.)
81*a5061eceSAdrien Destugues
82*a5061eceSAdrien DestuguesFor a consumer this message looks like:
83*a5061eceSAdrien Destugues
84*a5061eceSAdrien Destugues::
85*a5061eceSAdrien Destugues
86*a5061eceSAdrien Destugues   IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
87*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x1 (1, '')
88*a5061eceSAdrien Destugues       entry     be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
89*a5061eceSAdrien Destugues       entry        be:port, type='LONG', c=1, size= 4, data[0]: 0x1dab (7595, '')
90*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0"
91*a5061eceSAdrien Destugues
92*a5061eceSAdrien Destugues(Oddness: why is be:latency a LONG and not a LLNG? Since latency is
93*a5061eceSAdrien Destuguesexpressed in microseconds using a 64-bit bigtime_t, you'd expect the
94*a5061eceSAdrien Destuguesmidi_server to send all 64 of those bits... In the 'Mnew' message, on
95*a5061eceSAdrien Destuguesthe other hand, be:latency *is* a LLGN.)
96*a5061eceSAdrien Destugues
97*a5061eceSAdrien DestuguesAnd for a producer:
98*a5061eceSAdrien Destugues
99*a5061eceSAdrien Destugues::
100*a5061eceSAdrien Destugues
101*a5061eceSAdrien Destugues   IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
102*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x2 (2, '')
103*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=16, data[0]: "/dev/midi/vbus0"
104*a5061eceSAdrien Destugues
105*a5061eceSAdrien DestuguesNote that the be:name field is not present if the endpoint has no name.
106*a5061eceSAdrien DestuguesThat is, if the endpoint was constructed by passing a NULL name into the
107*a5061eceSAdrien DestuguesBMidiLocalConsumer() or BMidiLocalProducer() constructor.
108*a5061eceSAdrien Destugues
109*a5061eceSAdrien DestuguesNext up are notifications for *all* connections, even those between
110*a5061eceSAdrien Destuguesendpoints that are not registered:
111*a5061eceSAdrien Destugues
112*a5061eceSAdrien Destugues::
113*a5061eceSAdrien Destugues
114*a5061eceSAdrien Destugues   IN  BMessage: what = mCON (0x6d434f4e, or 1833127758)
115*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
116*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
117*a5061eceSAdrien Destugues
118*a5061eceSAdrien DestuguesThese messages are followed by an Msyn message:
119*a5061eceSAdrien Destugues
120*a5061eceSAdrien Destugues::
121*a5061eceSAdrien Destugues
122*a5061eceSAdrien Destugues   IN  BMessage: what = Msyn (0x4d73796e, or 1299413358)
123*a5061eceSAdrien Destugues
124*a5061eceSAdrien DestuguesAnd finally the (asynchronous) reply:
125*a5061eceSAdrien Destugues
126*a5061eceSAdrien Destugues::
127*a5061eceSAdrien Destugues
128*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
129*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
130*a5061eceSAdrien Destugues       entry     _previous_, ...
131*a5061eceSAdrien Destugues
132*a5061eceSAdrien DestuguesOnly after this reply is received, MidiRoster() returns.
133*a5061eceSAdrien Destugues
134*a5061eceSAdrien DestuguesThe purpose of the Msyn message is not entirely clear. (Without it, Be's
135*a5061eceSAdrien Destugueslibmidi2 blocks in the MidiRoster() call.) Does it signify the end of
136*a5061eceSAdrien Destuguesthe list of endpoints? Why doesn't libmidi2 simply wait for the final
137*a5061eceSAdrien Destuguesreply?
138*a5061eceSAdrien Destugues
139*a5061eceSAdrien Destugues--------------
140*a5061eceSAdrien Destugues
141*a5061eceSAdrien DestuguesBMidiLocalProducer constructor
142*a5061eceSAdrien Destugues------------------------------
143*a5061eceSAdrien Destugues
144*a5061eceSAdrien DestuguesBMidiRoster, on behalf of the constructor, sends the following to the
145*a5061eceSAdrien Destuguesmidi_server:
146*a5061eceSAdrien Destugues
147*a5061eceSAdrien Destugues::
148*a5061eceSAdrien Destugues
149*a5061eceSAdrien Destugues   OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567)
150*a5061eceSAdrien Destugues       entry        be:type, type='CSTR', c=1, size=9, data[0]: "producer"
151*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=21, data[0]: "MIDI Keyboard output"
152*a5061eceSAdrien Destugues
153*a5061eceSAdrien DestuguesThe be:name field is optional.
154*a5061eceSAdrien Destugues
155*a5061eceSAdrien DestuguesThe reply includes the ID for the new endpoint. This means that the
156*a5061eceSAdrien Destuguesmidi_server assigns the IDs, and any endpoint gets an ID whether it is
157*a5061eceSAdrien Destuguespublished or not.
158*a5061eceSAdrien Destugues
159*a5061eceSAdrien Destugues::
160*a5061eceSAdrien Destugues
161*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
162*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '')
163*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
164*a5061eceSAdrien Destugues       entry     _previous_, ...
165*a5061eceSAdrien Destugues
166*a5061eceSAdrien DestuguesUnlike many other Be API classes, BMidiLocalProducer and
167*a5061eceSAdrien DestuguesBMidiLocalConsumer don't have an InitCheck() method. But under certain
168*a5061eceSAdrien Destuguesodd circumstances (such as the midi_server not running), creating the
169*a5061eceSAdrien Destuguesendpoint might fail. How does client code check for that? Well, it turns
170*a5061eceSAdrien Destuguesout that upon failure, the endpoint is assigned ID 0, so you can check
171*a5061eceSAdrien Destuguesfor that. In that case, the endpoint's refcount is 0 and you should not
172*a5061eceSAdrien DestuguesRelease() it. (That is stupid, actually, because Release() is the only
173*a5061eceSAdrien Destuguesway that you can destroy the object. Our implementation should bump the
174*a5061eceSAdrien Destuguesendpoint to 1 even on failure!)
175*a5061eceSAdrien Destugues
176*a5061eceSAdrien DestuguesIf another app creates a new endpoint, your BMidiRoster is not notified.
177*a5061eceSAdrien DestuguesThe remote endpoint is not published yet, so your app is not supposed to
178*a5061eceSAdrien Destuguessee it.
179*a5061eceSAdrien Destugues
180*a5061eceSAdrien Destugues--------------
181*a5061eceSAdrien Destugues
182*a5061eceSAdrien DestuguesBMidiLocalConsumer constructor
183*a5061eceSAdrien Destugues------------------------------
184*a5061eceSAdrien Destugues
185*a5061eceSAdrien DestuguesThis is similar to the BMidiLocalProducer constructor, although the
186*a5061eceSAdrien Destuguescontents of the message differ slightly. Again, be:name is optional.
187*a5061eceSAdrien Destugues
188*a5061eceSAdrien Destugues::
189*a5061eceSAdrien Destugues
190*a5061eceSAdrien Destugues   OUT BMessage: what = Mnew (0x4d6e6577, or 1299080567)
191*a5061eceSAdrien Destugues       entry        be:type, type='CSTR', c=1, size=9, data[0]: "consumer"
192*a5061eceSAdrien Destugues       entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x0 (0, '')
193*a5061eceSAdrien Destugues       entry        be:port, type='LONG', c=1, size= 4, data[0]: 0x4c0 (1216, '')
194*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=13, data[0]: "InternalMIDI"
195*a5061eceSAdrien Destugues
196*a5061eceSAdrien DestuguesAnd the reply:
197*a5061eceSAdrien Destugues
198*a5061eceSAdrien Destugues::
199*a5061eceSAdrien Destugues
200*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
201*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x11 (17, '')
202*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
203*a5061eceSAdrien Destugues       entry     _previous_, ...
204*a5061eceSAdrien Destugues
205*a5061eceSAdrien DestuguesBefore it sends the message to the server, the constructor creates a new
206*a5061eceSAdrien Destuguesport with the name "MidiEventPort" and a queue length (capacity) of 1.
207*a5061eceSAdrien Destugues
208*a5061eceSAdrien Destugues--------------
209*a5061eceSAdrien Destugues
210*a5061eceSAdrien DestuguesBMidiEndpoint::Register()
211*a5061eceSAdrien DestuguesBMidiRoster::Register()
212*a5061eceSAdrien Destugues-------------------------
213*a5061eceSAdrien Destugues
214*a5061eceSAdrien DestuguesSends the same message for producers and consumers:
215*a5061eceSAdrien Destugues
216*a5061eceSAdrien Destugues::
217*a5061eceSAdrien Destugues
218*a5061eceSAdrien Destugues   OUT BMessage: what = Mreg (0x4d726567, or 1299342695)
219*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
220*a5061eceSAdrien Destugues
221*a5061eceSAdrien DestuguesThe reply:
222*a5061eceSAdrien Destugues
223*a5061eceSAdrien Destugues::
224*a5061eceSAdrien Destugues
225*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
226*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
227*a5061eceSAdrien Destugues       entry     _previous_, ...
228*a5061eceSAdrien Destugues
229*a5061eceSAdrien DestuguesIf you try to Register() an endpoint that is already registered,
230*a5061eceSAdrien Destugueslibmidi2 still sends the message. (Which could mean that BMidiRoster
231*a5061eceSAdrien Destuguesdoes not keep track of this registered state.) The midi_server simply
232*a5061eceSAdrien Destuguesignores that request, and sends back error code 0 (B_OK). So the API
233*a5061eceSAdrien Destuguesdoes not flag this as an error.
234*a5061eceSAdrien Destugues
235*a5061eceSAdrien DestuguesIf you send an invalid be:id, the midi_server returns error code -1
236*a5061eceSAdrien Destugues(General OS Error, B_ERROR). If you try to Register() a remote endpoint,
237*a5061eceSAdrien Destugueslibmidi2 immediately returns error code -1, and does not send a message
238*a5061eceSAdrien Destuguesto the server.
239*a5061eceSAdrien Destugues
240*a5061eceSAdrien DestuguesIf another app Register()'s a producer, your BMidiRoster receives:
241*a5061eceSAdrien Destugues
242*a5061eceSAdrien Destugues::
243*a5061eceSAdrien Destugues
244*a5061eceSAdrien Destugues   IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
245*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '')
246*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=7, data[0]: "a name"
247*a5061eceSAdrien Destugues
248*a5061eceSAdrien DestuguesIf the other app registers a consumer, your BMidiRoster receives:
249*a5061eceSAdrien Destugues
250*a5061eceSAdrien Destugues::
251*a5061eceSAdrien Destugues
252*a5061eceSAdrien Destugues   IN  BMessage: what = mOBJ (0x6d4f424a, or 1833910858)
253*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x19 (25, '')
254*a5061eceSAdrien Destugues       entry     be:latency, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
255*a5061eceSAdrien Destugues       entry        be:port, type='LONG', c=1, size= 4, data[0]: 0xde9 (3561, '')
256*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=7, data[0]: "a name"
257*a5061eceSAdrien Destugues
258*a5061eceSAdrien DestuguesThese are the same messages you get when your BMidiRoster instance is
259*a5061eceSAdrien Destuguesconstructed. In both messages, the be:name field is optional again.
260*a5061eceSAdrien Destugues
261*a5061eceSAdrien DestuguesIf the other app Register()'s the endpoint more than once, you still get
262*a5061eceSAdrien Destuguesonly one notification. So the midi_server simply ignores that second
263*a5061eceSAdrien Destuguespublish request.
264*a5061eceSAdrien Destugues
265*a5061eceSAdrien Destugues--------------
266*a5061eceSAdrien Destugues
267*a5061eceSAdrien DestuguesBMidiEndpoint::Unregister()
268*a5061eceSAdrien DestuguesBMidiRoster::Unregister()
269*a5061eceSAdrien Destugues---------------------------
270*a5061eceSAdrien Destugues
271*a5061eceSAdrien DestuguesSends the same message for producers and consumers:
272*a5061eceSAdrien Destugues
273*a5061eceSAdrien Destugues::
274*a5061eceSAdrien Destugues
275*a5061eceSAdrien Destugues   OUT BMessage: what = Munr (0x4d756e72, or 1299541618)
276*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
277*a5061eceSAdrien Destugues
278*a5061eceSAdrien DestuguesThe reply:
279*a5061eceSAdrien Destugues
280*a5061eceSAdrien Destugues::
281*a5061eceSAdrien Destugues
282*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
283*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
284*a5061eceSAdrien Destugues       entry     _previous_, ...
285*a5061eceSAdrien Destugues
286*a5061eceSAdrien DestuguesIf you try to Unregister() and endpoint that is already unregistered,
287*a5061eceSAdrien Destugueslibmidi2 still sends the message. The midi_server simply ignores that
288*a5061eceSAdrien Destuguesrequest, and sends back error code 0 (B_OK). So the API does not flag
289*a5061eceSAdrien Destuguesthis as an error. If you try to Unregister() a remote endpoint, libmidi2
290*a5061eceSAdrien Destuguesimmediately returns error code -1, and does not send a message to the
291*a5061eceSAdrien Destuguesserver.
292*a5061eceSAdrien Destugues
293*a5061eceSAdrien DestuguesWhen another app Unregister()'s one of its own endpoints, your
294*a5061eceSAdrien DestuguesBMidiRoster receives:
295*a5061eceSAdrien Destugues
296*a5061eceSAdrien Destugues::
297*a5061eceSAdrien Destugues
298*a5061eceSAdrien Destugues   IN  BMessage: what = mDEL (0x6d44454c, or 1833190732)
299*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17 (23, '')
300*a5061eceSAdrien Destugues
301*a5061eceSAdrien DestuguesWhen the other app deletes that endpoint (refcount is now 0) and it is
302*a5061eceSAdrien Destuguesnot unregistered yet, your BMidiRoster also receives that mDEL message.
303*a5061eceSAdrien DestuguesMultiple Unregisters() are ignored again by the midi_server.
304*a5061eceSAdrien Destugues
305*a5061eceSAdrien DestuguesIf an app quits without properly cleaning up, i.e. it does not
306*a5061eceSAdrien DestuguesUnregister() and Release() its endpoints, then the midi_server's roster
307*a5061eceSAdrien Destuguescontains a stale endpoint. As soon as the midi_server recognizes this
308*a5061eceSAdrien Destugues(for example, when an application tries to connect that endpoint), it
309*a5061eceSAdrien Destuguessends all BMidiRosters an mDEL message for this endpoint. (This message
310*a5061eceSAdrien Destuguesis sent whenever the midi_server feels like it, so libmidi2 can receive
311*a5061eceSAdrien Destuguesthis message while it is still waiting for a reply to some other
312*a5061eceSAdrien Destuguesmessage.) If the stale endpoint is still on the roster and you (re)start
313*a5061eceSAdrien Destuguesyour app, then you receive an mOBJ message for this endpoint during the
314*a5061eceSAdrien Destuguesstartup handshake. A little later you will receive the mDEL.
315*a5061eceSAdrien Destugues
316*a5061eceSAdrien Destugues--------------
317*a5061eceSAdrien Destugues
318*a5061eceSAdrien DestuguesBMidiEndpoint::Release()
319*a5061eceSAdrien Destugues------------------------
320*a5061eceSAdrien Destugues
321*a5061eceSAdrien DestuguesOnly sends a message if the refcount of local objects (published or not)
322*a5061eceSAdrien Destuguesbecomes 0:
323*a5061eceSAdrien Destugues
324*a5061eceSAdrien Destugues::
325*a5061eceSAdrien Destugues
326*a5061eceSAdrien Destugues   OUT BMessage: what = Mdel (0x4d64656c, or 1298425196)
327*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
328*a5061eceSAdrien Destugues
329*a5061eceSAdrien DestuguesThe corresponding reply:
330*a5061eceSAdrien Destugues
331*a5061eceSAdrien Destugues::
332*a5061eceSAdrien Destugues
333*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
334*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
335*a5061eceSAdrien Destugues       entry     _previous_, ...
336*a5061eceSAdrien Destugues
337*a5061eceSAdrien DestuguesIf you did not Unregister() a published endpoint before you Release()'d
338*a5061eceSAdrien Destuguesit, no 'Munr' message is sent. Of course, the midi_server is smart
339*a5061eceSAdrien Destuguesenough to realize that this endpoint should be wiped from the roster
340*a5061eceSAdrien Destuguesnow. Likewise, if this endpoint is connected to another endpoint,
341*a5061eceSAdrien DestuguesRelease() will not send a separate 'Mdis' message, but the server *will*
342*a5061eceSAdrien Destuguesdisconnect them. (This, of course, only happens when you Release() local
343*a5061eceSAdrien Destuguesobjects. Releasing a proxy has no impact on the connection with the real
344*a5061eceSAdrien Destuguesendpoint.)
345*a5061eceSAdrien Destugues
346*a5061eceSAdrien DestuguesWhen you Release() a proxy (a remote endpoint) and its refcount becomes
347*a5061eceSAdrien Destugues0, libmidi2 does not send an 'Mdel' message to the server. After all,
348*a5061eceSAdrien Destuguesthe object is not deleted, just your proxy. If the remote endpoint still
349*a5061eceSAdrien Destuguesexists (i.e. IsValid() returns true), the BMidiRoster actually keeps a
350*a5061eceSAdrien Destuguescached copy of the proxy object around, just in case you need it again.
351*a5061eceSAdrien DestuguesThis means you can do this: endp = NextEndpoint(); endp->Release(); (now
352*a5061eceSAdrien Destuguesrefcount is 0) endp- >Acquire(); (now refcount is 1 again). But I advice
353*a5061eceSAdrien Destuguesagainst that since it doesn't work for all objects; local and dead
354*a5061eceSAdrien Destuguesremote endpoints *will* be deleted when their refcount reaches zero.
355*a5061eceSAdrien Destugues
356*a5061eceSAdrien DestuguesIn Be's implementation, if you Release() a local endpoint that already
357*a5061eceSAdrien Destugueshas a zero refcount, libmidi still sends out the 'Mdel' message. It also
358*a5061eceSAdrien Destuguesdrops you into the debugger. (I think it should return an error code
359*a5061eceSAdrien Destuguesinstead, it already has a status_t.) However, if you Release() proxies a
360*a5061eceSAdrien Destuguesfew times too many, your app does not jump into the debugger. (Again, I
361*a5061eceSAdrien Destuguesthink the return result should be an error code here -- for OpenBeOS R1
362*a5061eceSAdrien DestuguesI think we should jump into the debugger just like with local objects).
363*a5061eceSAdrien DestuguesHmm, actually, whether you end up in the debugger depends on the
364*a5061eceSAdrien Destuguescontents of memory after the object is deleted, because you perform the
365*a5061eceSAdrien Destuguesextra Release() on a dead object. Don't do that.
366*a5061eceSAdrien Destugues
367*a5061eceSAdrien Destugues--------------
368*a5061eceSAdrien Destugues
369*a5061eceSAdrien DestuguesBMidiEndpoint::SetName()
370*a5061eceSAdrien Destugues------------------------
371*a5061eceSAdrien Destugues
372*a5061eceSAdrien DestuguesFor local endpoints, both unpublished and published, libmidi2 sends:
373*a5061eceSAdrien Destugues
374*a5061eceSAdrien Destugues::
375*a5061eceSAdrien Destugues
376*a5061eceSAdrien Destugues   OUT BMessage: what = Mnam (0x4d6e616d, or 1299079533)
377*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
378*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=7, data[0]: "b name"
379*a5061eceSAdrien Destugues
380*a5061eceSAdrien DestuguesAnd receives:
381*a5061eceSAdrien Destugues
382*a5061eceSAdrien Destugues::
383*a5061eceSAdrien Destugues
384*a5061eceSAdrien Destugues   IN BMessage: what =  (0x0, or 0)
385*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
386*a5061eceSAdrien Destugues       entry     _previous_, ...
387*a5061eceSAdrien Destugues
388*a5061eceSAdrien DestuguesYou cannot rename remote endpoints. If you try, libmidi2 will simply
389*a5061eceSAdrien Destuguesignore your request. It does not send a message to the midi_server.
390*a5061eceSAdrien Destugues
391*a5061eceSAdrien DestuguesIf another application renames one of its own endpoints, all other
392*a5061eceSAdrien DestuguesBMidiRosters receive:
393*a5061eceSAdrien Destugues
394*a5061eceSAdrien Destugues::
395*a5061eceSAdrien Destugues
396*a5061eceSAdrien Destugues   IN  BMessage: what = mREN (0x6d52454e, or 1834108238)
397*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x5 (5, '')
398*a5061eceSAdrien Destugues       entry        be:name, type='CSTR', c=1, size=7, data[0]: "b name"
399*a5061eceSAdrien Destugues
400*a5061eceSAdrien DestuguesYou receive this message even if the other app did not publish its
401*a5061eceSAdrien Destuguesendpoint. This seems rather strange, because your BMidiRoster has no
402*a5061eceSAdrien Destuguesknowledge of this particular endpoint yet, so what is it to do with this
403*a5061eceSAdrien Destuguesmessage? Ignore it, I guess.
404*a5061eceSAdrien Destugues
405*a5061eceSAdrien Destugues--------------
406*a5061eceSAdrien Destugues
407*a5061eceSAdrien DestuguesBMidiEndpoint::GetProperties()
408*a5061eceSAdrien Destugues------------------------------
409*a5061eceSAdrien Destugues
410*a5061eceSAdrien DestuguesFor *any* kind of endpoint (local non-published, local published,
411*a5061eceSAdrien Destuguesremote) libmidi2 sends the following message to the server:
412*a5061eceSAdrien Destugues
413*a5061eceSAdrien Destugues::
414*a5061eceSAdrien Destugues
415*a5061eceSAdrien Destugues   OUT BMessage: what = Mgpr (0x4d677072, or 1298624626)
416*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x2b2 (690, '')
417*a5061eceSAdrien Destugues       entry       be:props, type='MSGG', c=1, size= 0,
418*a5061eceSAdrien Destugues
419*a5061eceSAdrien Destugues(Why this "get properties" request includes a BMessage is a mistery to
420*a5061eceSAdrien Destuguesme. The midi_server does not appear to copy its contents into the reply,
421*a5061eceSAdrien Destugueswhich would have made at least some sense. The BMessage from the client
422*a5061eceSAdrien Destuguesis completely overwritten with the endpoint's properties.)
423*a5061eceSAdrien Destugues
424*a5061eceSAdrien Destugues::
425*a5061eceSAdrien Destugues
426*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
427*a5061eceSAdrien Destugues       entry       be:props, type='MSGG', c=1, size= 0,
428*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
429*a5061eceSAdrien Destugues       entry     _previous_, ...
430*a5061eceSAdrien Destugues
431*a5061eceSAdrien DestuguesThis means that endpoint properties are stored in the server only, not
432*a5061eceSAdrien Destuguesinside the BMidiEndpoints, and not by the local BMidiRosters.
433*a5061eceSAdrien Destugues
434*a5061eceSAdrien Destugues--------------
435*a5061eceSAdrien Destugues
436*a5061eceSAdrien DestuguesBMidiEndpoint::SetProperties()
437*a5061eceSAdrien Destugues------------------------------
438*a5061eceSAdrien Destugues
439*a5061eceSAdrien DestuguesFor local endpoints, published or not, libmidi2 sends the following
440*a5061eceSAdrien Destuguesmessage to the server:
441*a5061eceSAdrien Destugues
442*a5061eceSAdrien Destugues::
443*a5061eceSAdrien Destugues
444*a5061eceSAdrien Destugues   OUT BMessage: what = Mspr (0x4d737072, or 1299411058)
445*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
446*a5061eceSAdrien Destugues       entry       be:props, type='MSGG', c=1, size= 0,
447*a5061eceSAdrien Destugues
448*a5061eceSAdrien DestuguesAnd expects this back:
449*a5061eceSAdrien Destugues
450*a5061eceSAdrien Destugues::
451*a5061eceSAdrien Destugues
452*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
453*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
454*a5061eceSAdrien Destugues       entry     _previous_, ...
455*a5061eceSAdrien Destugues
456*a5061eceSAdrien DestuguesYou cannot change the properties of remote endpoints. If you try,
457*a5061eceSAdrien Destugueslibmidi2 will ignore your request. It does not send a message to the
458*a5061eceSAdrien Destuguesmidi_server, and it returns the -1 error code (B_ERROR).
459*a5061eceSAdrien Destugues
460*a5061eceSAdrien DestuguesIf another application changes the properties of one of its own
461*a5061eceSAdrien Destuguesendpoints, all other BMidiRosters receive:
462*a5061eceSAdrien Destugues
463*a5061eceSAdrien Destugues::
464*a5061eceSAdrien Destugues
465*a5061eceSAdrien Destugues   IN  BMessage: what = mPRP (0x6d505250, or 1833980496)
466*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
467*a5061eceSAdrien Destugues       entry  be:properties, type='MSGG', c=1, size= 0,
468*a5061eceSAdrien Destugues
469*a5061eceSAdrien DestuguesYou receive this message even if the other app did not publish its
470*a5061eceSAdrien Destuguesendpoint.
471*a5061eceSAdrien Destugues
472*a5061eceSAdrien Destugues--------------
473*a5061eceSAdrien Destugues
474*a5061eceSAdrien DestuguesBMidiLocalConsumer::SetLatency()
475*a5061eceSAdrien Destugues--------------------------------
476*a5061eceSAdrien Destugues
477*a5061eceSAdrien DestuguesFor local endpoints, published or not, libmidi2 sends the following
478*a5061eceSAdrien Destuguesmessage to the server:
479*a5061eceSAdrien Destugues
480*a5061eceSAdrien Destugues::
481*a5061eceSAdrien Destugues
482*a5061eceSAdrien Destugues   OUT BMessage: what = Mlat (0x4d6c6174, or 1298948468)
483*a5061eceSAdrien Destugues       entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '')
484*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x14f (335, '')
485*a5061eceSAdrien Destugues
486*a5061eceSAdrien DestuguesAnd receives:
487*a5061eceSAdrien Destugues
488*a5061eceSAdrien Destugues::
489*a5061eceSAdrien Destugues
490*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
491*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
492*a5061eceSAdrien Destugues       entry     _previous_, ...
493*a5061eceSAdrien Destugues
494*a5061eceSAdrien DestuguesIf another application changes the latency of one of its own consumers,
495*a5061eceSAdrien Destuguesall other BMidiRosters receive:
496*a5061eceSAdrien Destugues
497*a5061eceSAdrien Destugues::
498*a5061eceSAdrien Destugues
499*a5061eceSAdrien Destugues   IN  BMessage: what = mLAT (0x6d4c4154, or 1833714004)
500*a5061eceSAdrien Destugues       entry          be:id, type='LONG', c=1, size= 4, data[0]: 0x15 (21, '')
501*a5061eceSAdrien Destugues       entry     be:latency, type='LLNG', c=1, size= 8, data[0]: 0x3e8 (1000, '')
502*a5061eceSAdrien Destugues
503*a5061eceSAdrien DestuguesYou receive this message even if the other app did not publish its
504*a5061eceSAdrien Destuguesendpoint.
505*a5061eceSAdrien Destugues
506*a5061eceSAdrien Destugues--------------
507*a5061eceSAdrien Destugues
508*a5061eceSAdrien DestuguesBMidiProducer::Connect()
509*a5061eceSAdrien Destugues------------------------
510*a5061eceSAdrien Destugues
511*a5061eceSAdrien DestuguesThe message:
512*a5061eceSAdrien Destugues
513*a5061eceSAdrien Destugues::
514*a5061eceSAdrien Destugues
515*a5061eceSAdrien Destugues   OUT BMessage: what = Mcon (0x4d636f6e, or 1298362222)
516*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x17f (383, '')
517*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x376 (886, '')
518*a5061eceSAdrien Destugues
519*a5061eceSAdrien DestuguesThe answer:
520*a5061eceSAdrien Destugues
521*a5061eceSAdrien Destugues::
522*a5061eceSAdrien Destugues
523*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
524*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
525*a5061eceSAdrien Destugues       entry     _previous_, ...
526*a5061eceSAdrien Destugues
527*a5061eceSAdrien DestuguesThe server sends back a B_ERROR result if you specify wrong ID's. When
528*a5061eceSAdrien Destuguesyou try to connect a producer and consumer that are already connected to
529*a5061eceSAdrien Destugueseach other, libmidi2 still sends the 'Mcon' message to the server (even
530*a5061eceSAdrien Destuguesthough it could have known these endpoints are already connected). In
531*a5061eceSAdrien Destuguesthat case, the server responds with a B_ERROR code as well.
532*a5061eceSAdrien Destugues
533*a5061eceSAdrien DestuguesWhen another app makes the connection, your BMidiRoster receives:
534*a5061eceSAdrien Destugues
535*a5061eceSAdrien Destugues::
536*a5061eceSAdrien Destugues
537*a5061eceSAdrien Destugues   IN  BMessage: what = mCON (0x6d434f4e, or 1833127758)
538*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
539*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
540*a5061eceSAdrien Destugues
541*a5061eceSAdrien DestuguesNote: your BMidiRoster receives this notification even if the producer
542*a5061eceSAdrien Destuguesor the consumer (or both) are not registered endpoints.
543*a5061eceSAdrien Destugues
544*a5061eceSAdrien Destugues--------------
545*a5061eceSAdrien Destugues
546*a5061eceSAdrien DestuguesBMidiProducer::Disconnect()
547*a5061eceSAdrien Destugues---------------------------
548*a5061eceSAdrien Destugues
549*a5061eceSAdrien DestuguesThe message:
550*a5061eceSAdrien Destugues
551*a5061eceSAdrien Destugues::
552*a5061eceSAdrien Destugues
553*a5061eceSAdrien Destugues   OUT BMessage: what = Mdis (0x4d646973, or 1298426227)
554*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x309 (777, '')
555*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x393 (915, '')
556*a5061eceSAdrien Destugues
557*a5061eceSAdrien DestuguesThe answer:
558*a5061eceSAdrien Destugues
559*a5061eceSAdrien Destugues::
560*a5061eceSAdrien Destugues
561*a5061eceSAdrien Destugues   IN  BMessage: what =  (0x0, or 0)
562*a5061eceSAdrien Destugues       entry      be:result, type='LONG', c=1, size= 4, data[0]: 0x0 (0, '')
563*a5061eceSAdrien Destugues       entry     _previous_, ...
564*a5061eceSAdrien Destugues
565*a5061eceSAdrien DestuguesThe server sends back a B_ERROR result if you specify wrong ID's. When
566*a5061eceSAdrien Destuguesyou try to disconnect a producer and consumer that are not connected to
567*a5061eceSAdrien Destugueseach other, libmidi2 still sends the 'Mdis' message to the server (even
568*a5061eceSAdrien Destuguesthough it could have known these endpoints are not connected). In that
569*a5061eceSAdrien Destuguescase, the server responds with a B_ERROR code as well.
570*a5061eceSAdrien Destugues
571*a5061eceSAdrien DestuguesWhen another app breaks the connection, your BMidiRoster receives:
572*a5061eceSAdrien Destugues
573*a5061eceSAdrien Destugues::
574*a5061eceSAdrien Destugues
575*a5061eceSAdrien Destugues   IN  BMessage: what = mDIS (0x6d444953, or 1833191763)
576*a5061eceSAdrien Destugues       entry    be:producer, type='LONG', c=1, size= 4, data[0]: 0x13 (19, '')
577*a5061eceSAdrien Destugues       entry    be:consumer, type='LONG', c=1, size= 4, data[0]: 0x14 (20, '')
578*a5061eceSAdrien Destugues
579*a5061eceSAdrien DestuguesNote: your BMidiRoster receives this notification even if the producer
580*a5061eceSAdrien Destuguesor the consumer (or both) are not registered endpoints.
581*a5061eceSAdrien Destugues
582*a5061eceSAdrien Destugues--------------
583*a5061eceSAdrien Destugues
584*a5061eceSAdrien DestuguesWatchin'
585*a5061eceSAdrien Destugues--------
586*a5061eceSAdrien Destugues
587*a5061eceSAdrien DestuguesBMidiRoster::StartWatching() and StopWatching() do not send messages to
588*a5061eceSAdrien Destuguesthe midi_server. This means that the BMidiRoster itself, and not the
589*a5061eceSAdrien Destuguesmidi_server, sends the notifications to the messenger. It does this
590*a5061eceSAdrien Destugueswhenever it receives a message from the midi_server.
591*a5061eceSAdrien Destugues
592*a5061eceSAdrien DestuguesThe relationship between midi_server messages and B_MIDI_EVENT
593*a5061eceSAdrien Destuguesnotifications is as follows:
594*a5061eceSAdrien Destugues
595*a5061eceSAdrien Destugues   +---------+---------------------------+
596*a5061eceSAdrien Destugues   | message | notification              |
597*a5061eceSAdrien Destugues   +=========+===========================+
598*a5061eceSAdrien Destugues   | mOBJ    | B_MIDI_REGISTERED         |
599*a5061eceSAdrien Destugues   +---------+---------------------------+
600*a5061eceSAdrien Destugues   | mDEL    | B_MIDI_UNREGISTERED       |
601*a5061eceSAdrien Destugues   +---------+---------------------------+
602*a5061eceSAdrien Destugues   | mCON    | B_MIDI_CONNECTED          |
603*a5061eceSAdrien Destugues   +---------+---------------------------+
604*a5061eceSAdrien Destugues   | mDIS    | B_MIDI_DISCONNECTED       |
605*a5061eceSAdrien Destugues   +---------+---------------------------+
606*a5061eceSAdrien Destugues   | mREN    | B_MIDI_CHANGED_NAME       |
607*a5061eceSAdrien Destugues   +---------+---------------------------+
608*a5061eceSAdrien Destugues   | mLAT    | B_MIDI_CHANGED_LATENCY    |
609*a5061eceSAdrien Destugues   +---------+---------------------------+
610*a5061eceSAdrien Destugues   | mPRP    | B_MIDI_CHANGED_PROPERTIES |
611*a5061eceSAdrien Destugues   +---------+---------------------------+
612*a5061eceSAdrien Destugues
613*a5061eceSAdrien DestuguesFor each message on the left, the watcher will receive the corresponding
614*a5061eceSAdrien Destuguesnotification on the right.
615*a5061eceSAdrien Destugues
616*a5061eceSAdrien Destugues--------------
617*a5061eceSAdrien Destugues
618*a5061eceSAdrien DestuguesOther observations
619*a5061eceSAdrien Destugues------------------
620*a5061eceSAdrien Destugues
621*a5061eceSAdrien DestuguesOperations that do not send messages to the midi_server:
622*a5061eceSAdrien Destugues
623*a5061eceSAdrien Destugues-  BMidiEndpoint::Acquire(). This means reference counting is done
624*a5061eceSAdrien Destugues   locally by BMidiRoster. Release() doesn't send a message either,
625*a5061eceSAdrien Destugues   unless the refcount becomes 0 and the object is deleted. (Which
626*a5061eceSAdrien Destugues   suggests that it is actually the destructor and not Release() that
627*a5061eceSAdrien Destugues   sends the message.)
628*a5061eceSAdrien Destugues
629*a5061eceSAdrien Destugues-  BMidiRoster::NextEndpoint(), NextProducer(), NextConsumer(),
630*a5061eceSAdrien Destugues   FindEndpoint(), FindProducer(), FindConsumer(). None of these
631*a5061eceSAdrien Destugues   functions send messages to the midi_server. This means that each
632*a5061eceSAdrien Destugues   BMidiRoster instance keeps its own list of available endpoints. This
633*a5061eceSAdrien Destugues   is why it receives 'mOBJ' messages during the startup handshake, and
634*a5061eceSAdrien Destugues   whenever a new remote endpoint is registered, and 'mDEL' messages for
635*a5061eceSAdrien Destugues   every endpoint that disappears. Even though the NextXXX() functions
636*a5061eceSAdrien Destugues   do not return locally created objects, this "local roster" *does*
637*a5061eceSAdrien Destugues   keep track of them, since FindXXX() *do* return local endpoints.
638*a5061eceSAdrien Destugues
639*a5061eceSAdrien Destugues-  BMidiEndpoint::Name(), ID(), IsProducer(), IsConsumer(), IsRemote(),
640*a5061eceSAdrien Destugues   IsLocal() IsPersistent(). BMidiConsumer::Latency().
641*a5061eceSAdrien Destugues   BMidiLocalConsumer::GetProducerID(), SetTimeout(). These all appear
642*a5061eceSAdrien Destugues   to consult BMidiRoster's local roster.
643*a5061eceSAdrien Destugues
644*a5061eceSAdrien Destugues-  BMidiEndpoint::IsValid(). This function simply looks at BMidiRoster's
645*a5061eceSAdrien Destugues   local roster to see whether the remote endpoint is still visible,
646*a5061eceSAdrien Destugues   i.e. not unregistered. It does not determine whether the endpoint's
647*a5061eceSAdrien Destugues   application is still alive, or "ping" the endpoint or anything fancy
648*a5061eceSAdrien Destugues   like that.
649*a5061eceSAdrien Destugues
650*a5061eceSAdrien Destugues-  BMidiProducer::IsConnected(), Connections(). This means that
651*a5061eceSAdrien Destugues   BMidiRoster's local roster, or maybe the BMidiProducers themselves
652*a5061eceSAdrien Destugues   (including the proxies) keep track of the various connections.
653*a5061eceSAdrien Destugues
654*a5061eceSAdrien Destugues-  BMidiLocalProducer::Connected(), Disconnected(). These methods are
655*a5061eceSAdrien Destugues   invoked when any app (including your own) makes or breaks a
656*a5061eceSAdrien Destugues   connection on one of your local producers. These hooks are invoked
657*a5061eceSAdrien Destugues   before the B_MIDI_EVENT messages are sent to any watchers.
658*a5061eceSAdrien Destugues
659*a5061eceSAdrien Destugues-  Quitting your app. Even though the BMidiRoster instance is deleted
660*a5061eceSAdrien Destugues   when the app quits, it does not let the midi_server know that the
661*a5061eceSAdrien Destugues   application in question is now gone. Any endpoints you have
662*a5061eceSAdrien Destugues   registered are not automatically unregistered. This means that the
663*a5061eceSAdrien Destugues   midi_server is left with some stale information. Undoubtedly, there
664*a5061eceSAdrien Destugues   is a mechanism in place to clean this up. The same mechanism would be
665*a5061eceSAdrien Destugues   used to clean up apps that did not exit cleanly, or that crashed.
666*a5061eceSAdrien Destugues
667*a5061eceSAdrien DestuguesOther stuff:
668*a5061eceSAdrien Destugues
669*a5061eceSAdrien Destugues-  libmidi2.so exports an int32 symbol called "midi_debug_level". If you
670*a5061eceSAdrien Destugues   set it to a non-zero value, libmidi2 will dump a lot of interesting
671*a5061eceSAdrien Destugues   debug info on stdout. To do this, declare the variable in your app
672*a5061eceSAdrien Destugues   with "extern int32 midi_debug_level;", and then set it to some high
673*a5061eceSAdrien Destugues   value later: "midi_debug_level = 0x7FFFFFFF;" Now run your app from a
674*a5061eceSAdrien Destugues   Terminal and watch libmidi2 do its thing.
675*a5061eceSAdrien Destugues
676*a5061eceSAdrien Destugues-  libmidi2.so also exports an int32 symbol called
677*a5061eceSAdrien Destugues   "midi_dispatcher_priority". This is the runtime priority of the
678*a5061eceSAdrien Destugues   thread that fields MIDI events to consumers.
679