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