How to signal an NSStreamEventEndEncountered on an NSInputStream reading from NSMutableData - objective-c

In Cocoa, I've setup two NSThreads, one producer and one consumer.
The producer appends data to an NSMutableData, and the receiver opens an NSInputStream from that data and reads in chunks.
The producer thread writes a lot faster than the consumer processes, which is OK. But the producer only produces a finite amount of work, then exits. I'd like for the consumer thread to handle the NSStreamEventEndEncountered event. How can I signal this when the NSInputStream comes from an NSMutableData?
Should I just make the producer send a series of bytes with a magical number signifying an end of stream?

The producer appends data to an NSMutableData, and the receiver opens an NSInputStream from that data and reads in chunks.
That won't work. From the -initWithData: documentation:
The contents of data are copied.
Meaning, it will copy out whatever's in the data object at that time, not follow the contents of the data object as you add more data to it.
(The same goes for +inputStreamWithData:.)
Try a pipe instead.

Related

What does the hasSpaceAvailable property on NSOutputStream mean?

I'm trying to wrap my head around the logic behind hasSpaceAvailable on NSOutputStream.
In my app, I'm sending large amounts of data (100MB) broken up into 4080byte chunks (hard limit) over a CFSocket managed by NSInput/output streams.
When I start writing the data, about a quarter way through hasSpaceAvailable suddenly becomes NO, and so I add the data to a queue. However, if I ignore that and try to write the data anyways, the write seems to work as the return value of write:maxLength: matches the maxLength parameter (4080).
What does the output stream have space for? As far as I can tell, when using UNIX/Berkley sockets there is no logic available to determine if the socket can be written to, you just write and determine if all of the data was written.
The documentation for the property states:
A boolean value that indicates whether the receiver can be written to. (read-only)
YES if the receiver can be written to or if a write must be attempted in order to determine if space is available, NO otherwise.
In my example where I'm seeing a NO, what factor is causing this result when I can still write to that socket.
I think the hasSpaceAvailable property just returns YES if the stream has sent a "space available" stream event since the last time you called the write method. You shouldn't poll that property, and it arguably shouldn't even exist. Instead, you should wait for a stream event on the output stream that says that there's space available for writing instead.
When that stream event occurs, it means that the outgoing packet queue has at least one byte fewer than the maximum number of bytes that the socket is configured to allow you to queue up. In other words, a send() or write() system call on the socket is guaranteed to write at least one byte without blocking, and the socket is guaranteed to be in a nonblocking mode.
Note that after you write data, the stream will send another space available event immediately if the stream's buffer can take more data (or after it has sent some data if the buffer is full).

AudioQueueOutputCallback buffer data (during playback and recording)

I have trouble with understanding what exactly is in buffer containing incoming data.
Is AudioQueueBufferRef refers to piece of data (from last callback call) or it is whole past data (since AudioQueue start) ?
Have you taken a look at the Apple developer documentation for this?
An audio queue buffer, newly available to fill because the playback audio queue has acquired its contents.
It also provides the queue that triggered the callback.

CFStreamCreateBoundPair streams lose data with small buffer size

I am attempting to create a streaming html parser with libxml2 in Objective-C. I have a NSURLConnection that downloads the data, and I have created in NSInputStream and NSOutputstream with CFStreamCreateBoundPairwith a small buffer size of 10 bytes. As data is received from the NSURLConnection I write it to the output stream. It appears when the amount of data received is larger than the buffer size the left over data is lost. Is this supposed to happen? From my understanding I thought the data would be queued and written in chunks the size of the buffer to the input stream.
CFStreamCreateBoundPair Reference
You need to ensure that all data from the received chunk is eventually written into the stream.
You might do this with a simple loop in the delegate method where you continuously write a portion of the received chunk until it is completely written into the stream. However, this may cause the thread where the delegate is running to block undeterminably: if the consumer is not ready to consume more bytes, the output stream will block when attempting to write more data.
Alternatively, you might dispatch the NSData object asynchronously to a queue where a block is doing the loop and writes all the data before it completes. However, this may cause your system to run out of memory if the consumer is slow and the data is large - since all NSData live on the dispatch queue until the block finished.
Both approaches have pros and cons. I tend to prefer the first, since there is no memory issue and the connection will buffer the incoming bytes up to a certain upper limit anyway - before it stops acknowledging more bytes.

How many events does multiple writes to NSOutputStream result in?

Do two writes to the NSOutputStream result in two NSStreamEventHasBytesAvailable (where I handle the data read) in stream:handleEvent:?
Have you checked out the "Stream Programming Guide" on output streams? https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/WritingOutputStreams.html
On output streams, the sequence is:
alloc/init
set delegate
schedule in run loop
open
wait for NSStreamEventOpenCompleted
wait for NSStreamEventHasSpaceAvailable
When NSStreamEventHasSpaceAvailable is received (this will only be received once in response to each write operation), you have the option of performing a write. If you perform a write, you then need to wait to receive NSStreamEventHasSpaceAvailable before writing again. When performing a write, you must also confirm that everything that you attempted to write was actually written. It may be necessary to handle partial writes if the write attempt only partially completes.

Recording Audio on iPhone and Sending Over Network with NSOutputStream

I am writing an iPhone application that needs to record audio from the built-in microphone and then send that audio data to a server for processing.
The application uses a socket connection to connect to the server and Audio Queue Services to do the recording. What I am unsure of is when to actually send the data. Audio Queue Services fires a callback each time it has filled a buffer with some audio data. NSOutputStream fires an event each time it has space available.
My first thought was to send the data to the server on the Audio Queue callback. But it seems like this would run into a problem if the NSOutputStream does not have space available at that time.
Then I thought about buffering the data as it comes back from the Audio Queue and sending some each time the NSOutputStream fires a space available event. But this would seem to have a problem if the sending to the server gets ahead of the audio recording then there will be a situation where there is nothing to write on the space available event, so the event will not be fired again and the data transfer will effectivly be stalled.
So what is the best way to handle this? Should I have a timer that fires repeatedly and see if there is space available and there is data that needs to be sent? Also, I think I will need to do some thread synchronization so that I can take chunks of data out of my buffer to send across the network but also add chunks of data to the buffer as the recording proceeds without risking mangling my buffer.
You could use a ring buffer to hold a certain number of audio frames and drop frames if the buffer exceeds a certain size. When your stream-has-space-available callback gets called, pull a frame off the ring buffer and send it.
CHDataStructures provides a few ring-buffer (which it calls “circular buffer”) classes.