SysEx event not received - audiokit

I have a small app receiving MIDI from Bluetooth channel.
It works well using Core APIs, so I tried to use AudioKit to simplify my code.
Problem is : I can't see the SysEx events in the listener (although I see them in my basic code). Other midi events are received.
AKMidi = AudioKit.midi
AKMidi?.addListener(AVKMIDIControl())
...
AKMidi?.openInput(index: i)
...
class AVKMIDIControl:AKMIDIListener {
...
// copy paste from audiokit.io example
func receivedMIDISystemCommand(_ data: [MIDIByte]) {
if let command = AKMIDISystemCommand(rawValue: data[0]) {
var newString = "MIDI System Command: \(command) \n"
for i in 0 ..< data.count {
newString.append("\(data[i]) ")
}
print(newString)
}
}
...
I should be receiving SysEx events in the listener (btw,I implemented all other functions to be sure I am catching everything), but I only get log messages like
AKMIDI.swift:startReceivingSysex(with:):102:Starting to receive Sysex
AKMIDI.swift:stopReceivingSysex():107:Done receiving Sysex
but nothing through the listener...
How can I get the Sysex message data ?

I can confirm this behavior in the current version (4.7.2), however: in version 4.5.6 sysex (and other MIDI messages) are received by your midilistener. So my app is still using that version. for some reason receiving MIDI just seems broken in later versions.
But version 4.5.6 is not perfect too. It cuts large sysex messages into multiple small messages. I have some code to deal with that, let me know if you need it.

Related

receivedMIDIController not calling from sequencer

Current State:
I'm playing a midi file using AppleSequencer.
VirtualPorts and Listener are implemented, "receivedMIDINoteOn/Off" working great.
My Problem
"receivedMIDIController" not calling from my sequencer.
Message send from Logic Pro X's MIDI Out Port is calling "receivedMIDIController". (Same MIDI File)
I want to know what is happening, anyone can help me please?
Ok, new track with "replaceMIDINoteData" have only "modiNoteDataEvent"
var sequencer:AppleSequencer = AppleSequencer()
let t = sequencer.newTrack("track")
t?.replaceMIDINoteData(with: seqSty.tracks[0].getMIDINoteData())
//sequencer has Note Evnet Only.
a sequencer from MIDI Data has all kind of events, and then replace data with "MIDINoteData"
sequencer = AppleSequencer(fromData: data)
sequencer.tracks[0].replaceMIDINoteData(with: seqSty.tracks[0].getMIDINoteData())
//sequencer has all events from MIDI

Error when sending data between connected devices in Game Center

I am working on a local multiplayer, real time game in swift 5. In order to achieve the real time gameplay, I am sending data back and forth between two devices with the function GKMatch.sendData(data:, to:, withDataSendingMethod:). It works fairly inconsistently, regardless of if I use .reliable or .unreliable, however the error it gives me when it is unable to send data is consistent. It is as follow:
2020-07-27 21:07:22.433631-0400 Teacher Brawl[19336:5244039] [ViceroyTrace] [ERROR] AGPSessionRecvFrom:1954 0x103f11600 sack: SEARCH FAILURE SERIAL NUMBER (0000000B) FROM (5682ABEE)...
Where Teacher Brawl is the name of the project.
I was wondering if anyone is able to provide insight as to why I am getting the error, as I do not fully understand it being relatively new to swift and newer to GameKit. The code I am using to send the data is shown below, and it is being called anytime there is a tap on the screen, which in the context of this game is fairly minimal. If you need any further details please let me know, I would be happy to provide them. All help is greatly appreciated as the inconsistency of data sending has stopped any progress I can make for this game. :)
func sendButtons(button: String) {
let sendableString: Data? = button.data(using: .utf8)
do {
try localMatch.send(sendableString!, to: localMatch.players, dataMode: .unreliable)
}
catch {
print("")
}
}
For reference, the variable localMatch is my variable for the GKMatch that was returned when both players joined the game.
This error message is common and shouldn't interfere with your game sending data. My app gets this error but still sends data fine.
If you are sending data to all players, you should use the built in function func sendData(toAllPlayers data: Data, with mode: GKMatch.SendDataMode) throws. You should also send data reliably if it is not being sent very often. For debugging reasons, you might want to print when data is sent and print errors. Here is the full code you can try.
func sendButtons(button: String) {
let sendableString: Data? = button.data(using: .utf8)
do {
try localMatch.sendData(toAllPlayers: sendableString!, with: .reliable)
print("Data sent")
}
catch {
print("Data not sent")
print(error)
}
}
If the data is not sent, check if "Data sent" is printed and check for errors

Are WebSocket messages cached on iOS?

Strange but I cannot find any information on that: if I write a [large] message to the WebSocket stream on iOS and the execution gets back to my code, is the message already sent or somehow buffered?
I'm using Starscream library but it just uses CFStream-s.
Looking at the source code for the Starscream library mentioned, the library appends the send operation to a NSOperation queue:
private func dequeueWrite(..) {
...
writeQueue.addOperation(operation)
}
and then immediately returns.
So when the one of the send methods returns, for example:
open func write(data: Data, completion: (() -> ())? = nil)
The message will not yet have been sent.
But as you can see you can pass a completion block to this method, that will be called when the whole message has been written to the underlying output stream. Note that this doesn't tell you anything about whether the message has actually been sent on the network, or if the sender has received it successfully.
To know if the sender has received and processed the message successfully, you need to wait for a response message - that is something you need to define in your application protocol.
Before using the Starscream library in production, you might want to report/fix some issues in it. While reviewing the send mechanism I noticed that if the OutputStream buffer is full on WebSocket.swift line 1254 the library tries sending the rest of the buffer in a busy loop rather than waiting for a hasSpaceAvailable event. This may waste a lot of CPU cycle if you send a large message.
Also, it looks like the case when stream.write returns 0, indicating that the output buffer is full, is incorrectly handled as an error.
Probably it use
func CFWriteStreamWrite(_ stream: CFWriteStream!,
_ buffer: UnsafePointer<UInt8>!,
_ bufferLength: CFIndex) -> CFIndex
the write call return "The number of bytes successfully written, 0 if the stream has been filled to capacity (for fixed-length streams), or -1 if either the stream is not open or an error occurs."
So yes, they are buffered. But I think that is the only option, a write function need to have the buffer because every socket have a max buffer zsize

Bidirectional gRPC stream sometimes stops processing responses after stopping and starting

In short
We have a mobile app that streams fairly high volumes of data to and from a server through various bidirectional streams. The streams need to be closed on occasion (for example when the app is backgrounded). They are then reopened as needed. Sometimes when this happens, something goes wrong:
From what I can tell, the stream is up and running on the device's side (the status of both the GRPCProtocall and the GRXWriter involved is either started or paused)
The device sends data on the stream fine (the server receives the data)
The server seems to send data back to the device fine (the server's Stream.Send calls return as successful)
On the device, the result handler for data received on the stream is never called
More detail
Our code is heavily simplified below, but this should hopefully provide enough detail to indicate what we're doing. A bidirection stream is managed by a Switch class:
class Switch {
/** The protocall over which we send and receive data */
var protocall: GRPCProtoCall?
/** The writer object that writes data to the protocall. */
var writer: GRXBufferedPipe?
/** A static GRPCProtoService as per the .proto */
static let service = APPDataService(host: Settings.grpcHost)
/** A response handler. APPData is the datatype defined by the .proto. */
func rpcResponse(done: Bool, response: APPData?, error: Error?) {
NSLog("Response received")
// Handle response...
}
func start() {
// Create a (new) instance of the writer
// (A writer cannot be used on multiple protocalls)
self.writer = GRXBufferedPipe()
// Setup the protocall
self.protocall = Switch.service.rpcToStream(withRequestWriter: self.writer!, eventHandler: self.rpcRespose(done:response:error:))
// Start the stream
self.protocall.start()
}
func stop() {
// Stop the writer if it is started.
if self.writer.state == .started || self.writer.state == .paused {
self.writer.finishWithError(nil)
}
// Stop the proto call if it is started
if self.protocall?.state == .started || self.protocall?.state == .paused {
protocall?.cancel()
}
self.protocall = nil
}
private var needsRestart: Bool {
if let protocall = self.protocall {
if protocall.state == .notStarted || protocall.state == .finished {
// protocall exists, but isn't running.
return true
} else if writer.state == .notStarted || writer.state == .finished {
// writer isn't running
return true
} else {
// protocall and writer are running
return false
}
} else {
// protocall doesn't exist.
return true
}
}
func restartIfNeeded() {
guard self.needsRestart else { return }
self.stop()
self.start()
}
func write(data: APPData) {
self.writer.writeValue(data)
}
}
Like I said, heavily simplified, but it shows how we start, stop, and restart streams, and how we check whether a stream is healthy.
When the app is backgrounded, we call stop(). When it is foregrounded and we need the stream again, we call start(). And we periodically call restartIfNeeded(), eg. when screens that use the stream come into view.
As I mentioned above, what happens occasionally is that our response handler (rpcResponse) stops getting called when server writes data to the stream. The stream appears to be healthy (server receives the data we write to it, and protocall.state is neither .notStarted nor .finished). But not even the log on the first line of the response handler is executed.
First question: Are we managing the streams correctly, or is our way of stopping and restarting streams prone to errors? If so, what is the correct way of doing something like this?
Second question: How do we debug this? Everything we could think of that we can query for a status tells us that the stream is up and running, but it feels like the objc gRPC library keeps a lot of its mechanics hidden from us. Is there a way to see whether responses from server may do reach us, but fail to trigger our response handler?
Third question: As per the code above, we use the GRXBufferedPipe provided by the library. Its documentation advises against using it in production because it doesn't have a push-back mechanism. To our understanding, the writer is only used to feed data to the gRPC core in a synchronised, one-at-a-time fashion, and since server receives data from us fine, we don't think this is an issue. Are we wrong though? Is the writer also involved in feeding data received from server to our response handler? I.e. if the writer broke due to overload, could that manifest as a problem reading data from the stream, rather than writing to it?
UPDATE: Over a year after asking this, we have finally found a deadlock bug in our server-side code that was causing this behaviour on client-side. The streams appeared to hang because no communication sent by the client was handled by server, and vice-versa, but the streams were actually alive and well. The accepted answer provides good advice for how to manage these bi-directional streams, which I believe is still valuable (it helped us a lot!). But the issue was actually due to a programming error.
Also, for anyone running into this type of issue, it might be worth investigating whether you're experiencing this known issue where a channel gets silently dropped when iOS changes its network. This readme provides instructions for using Apple's CFStream API rather than TCP sockets as a possible fix for that issue.
First question: Are we managing the streams correctly, or is our way of stopping and restarting streams prone to errors? If so, what is the correct way of doing something like this?
From what I can tell by looking at your code, the start() function seems to be right. In the stop() function, you do not need to call cancel() of self.protocall; the call will be finished with the previous self.writer.finishWithError(nil).
needsrestart() is where it gets a bit messy. First, you are not supposed to poll/set the state of protocall yourself. That state is altered by itself. Second, setting those state does not close your stream. It only pause a writer, and if app is in background, pausing a writer is like a no-op. If you want to close a stream, you should use finishWithError to terminate this call, and maybe start a new call later when needed.
Second question: How do we debug this?
One way is to turn on gRPC log (GRPC_TRACE and GRPC_VERBOSITY). Another way is to set breakpoint at here where gRPC objc library receives a gRPC message from the server.
Third question: Is the writer also involved in feeding data received from server to our response handler?
No. If you create a buffered pipe and feed that as request of your call, it only feed data to be sent to server. The receiving path is handled by another writer (which is in fact your protocall object).
I don't see where the usage of GRXBufferedPipe in production is discouraged. The known drawback about this utility is that if you pause the writer but keep writing data to it with writeWithValue, you end up buffering a lot of data without being able to flush them, which may cause memory issue.

How to know when scan is finished

I trigger the scan with following code
struct nl_msg *msg = nlmsg_alloc();
struct nlmsghdr *hdr;
struct genlmsghdr cmd = { .cmd = NL80211_CMD_TRIGGER_SCAN };
struct nl_sock *sock = nl_socket_alloc();
int dev = if_nametoindex("wlan0");
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev);
hdr = nlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, NLMSG_NOOP, 0, 0);
memcpy(nlmsg_data(hdr), &cmd, sizeof(cmd));
nl_send_auto(sock, msg);
Now, how should i know when scan is finished, and how can i get it? In all places i have been searching so far, there is "You will receive NL80211_CMD_NEW_SCANS notification on "scan" multicast group", How should i subscribe to it? i registered my callback, tried
nl_socket_add_memberships(sock, RTN_MULTICAST);
and after that listen for messages in while with
while (1)
nl_recvmsgs_default(sock);
but nothing happened, so: if you had enough patience to read up to this point, please help me with 2 questions
1) How do i know when scan is finished(how to subscribe on this notifications, or read them etc.)
2) How can i read messages after notifications received(method as i understand it below)
To read scanned data i need to send message similar to one that triggers scan, but with message NL80211_CMD_GET_SCAN, and after that data will be stored in nl_socket's payload, am i right?
send a NL80211_CMD_TRIGGER_SCAN to start a scan off. (one after another will fail)
After sending, then listen out for the scan to complete when you get a NL80211_CMD_NEW_SCAN_RESULTS.
a NL80211_CMD_GET_SCAN command to ask for the results.
You will get one message back for every station found, so be ready to handle multiple messages.
NL80211_CMD_TRIGGER_SCAN to scan off
listen to NL80211_CMD_NEW_SCAN_RESULTS
NL80211_CMD_GET_SCAN command to ask for the results
should get one message back for every station found

Resources