Posts

Post marked as solved
1 Replies
DTS has confirmed to me that there really is no API path which allows the audio unit to coordinate with the host in such a way to only process a given number of frames (or multiple of) at a time. Their solution was to just insert latency into the stream by buffering the incoming audio and spitting out silence until enough audio has come in that we can always process the internally-required number of frames (10ms / 480 in my example above) and send that to the output. Introducing latency is not a great solution, but it'll work.
Post not yet marked as solved
1 Replies
Rereading your question a few times I thiiiink what you may be missing is that the audio unit works with the format and sample rates of its busses, which are known to it. So the audio unit never needs to know what the AVAudioEngine's input node's sample rate is, or have an external object set a custom property on the unit to hold "the format that you expect the audio to come in at". Instead, you just look at the relevant bus's format. Like you said, you can simpy save the sample rate of your bus in the allocateRenderResources method, and the value does not change, so it does not need to be passed into the block. The block parameters are the minimum changing values needed to actually render the audio. While perhaps a trivial convenience saving you two lines of code, there are other values you also want to use in the block and need to save in the same way, so there's no reason the sample rate is special.
Post marked as solved
4 Replies
Contrary to @Polyphonic's answer, I don't believe this is related to the flags at all. I also wonder if @bradhowes is mistaken that the block is called before allocateRenderResources is called. In my experience, that has not occurred. However, internalRenderBlock is called every time renderBlock is called, which can be multiple times during an audio graph setup, and will happen before the alloc method. It seems odd, but It Just Is. Consequently, general advice for everyone is that you should make sure your block doesn't capture any variable values which are not immutable after the audio unit's initialization, otherwise those captured values can be different in different calls to internalRenderBlock and cause subtle bugs. (Been there.) If you look at Apple's example code ("Creating Custom Audio Effects" / AUv3Filter), this is (part of) why all the state that is referred to by internalRenderBlock is stored in a separate struct/C++ class instance; The pointer to that struct/instance never changes, as that pointer is the only thing the block captures. Any time internalRenderBlock is called, therefore, returns the same exact block and captures and has identical behavior.
Post not yet marked as solved
10 Replies
I am using the same approach as in the TicTacToe example https://developer.apple.com/documentation/network/building_a_custom_peer-to-peer_protocol connection.stateUpdateHandler = { [weak self] (newState) in guard let self = self else { return } switch newState { case .ready: ... self.receiveNextMessage() case .failed(let err): print("Device TCP connection failed: \(err)") ... case .cancelled: print("Device TCP connection cancelled") ... default: break } } private func receiveNextMessage() { guard let connection = connection else { return } connection.receiveMessage { [weak self] (content, context, isComplete, error) in guard let self = self else { return } if let content = content { ... } else if let error = error { switch error { ... case NWError.posix(.ENODATA): // Without forceCancel, the connection state does not change until I later try to send data self.connection?.forceCancel() break default: print("Receive error: \(error)") } } if error == nil { self.receiveNextMessage() } } }
Post not yet marked as solved
10 Replies
I'm going to dig this back up because it's directly related to my own questions. The context: == @SuperBidi: [When the connection is gracefully closed by the other side....] I don't receive State changes, but I receive errors on my receive function. I was listening to State changes to handle my connection state but I also have to consider that an error in the receive function means that the connection may be down. @eskimo: Right. You also have to pay attention to EOF in your receive callback, because most TCP connections close cleanly, and that’s how a clean close is indicated. So with that in mind, here's what I'm doing and seeing: I open a connection to a remote, the NWConnection state is .ready (misc things may happen) I then receive() to wait for any incoming data. The remote side gracefully closes the connection (FIN/FIN-ACK) The receive() callback comes back with an error NWError.posix(.ENODATA) (I assume this is the exact "EOF" @eskimo mentioned) The NWConnection does not change states. It is still .ready. What's not clear to me is why it's still considered "ready". It seems like conceptually the concept of "ready" doesn't necessarily mean "connected". And The key question at this moment is, should the local side do anything, or just sit and wait for the local side to send before ever doing anything with the connection. Now let's say, my local side wants to send data to the remote. The connection is "ready" so: I call send(), the callback is called with no error Simultaneously the NWConnection internally recognizes the connection has been reset ([connection] nw_socket_handle_socket_event [C4:2] Socket SO_ERROR [54: Connection reset by peer]) The NWConnection's state now transitions to .failed. What I'm left with here is a message that says it got through to the remote before the connection failed, but it didn't. It seems as if when the ENODATA error is passed into the receive() callback, then the connection should be explicitly cancelled, so the local side knows the connection is not established anymore? But then why doesn't the framework itself do this? How is this supposed to handled correctly? Thanks.
Post not yet marked as solved
12 Replies
I fixed this by agreeing to the new contracts on both the developer account website and App Store Connect. 🙄🙄