I'm baffled. I have an open NSInputStream which thinks it has bytes available. When I read the bytes, the operation always returns 0. I've searched everywhere and my code looks like most everyone else's doing the same thing. This is such a low level operation that I can't figure out how it could go wrong.
I've tried this by connecting to a number of different hosts. I've also watched with Wireshark and I can see the host receiving the bytes I write, but the read:maxBytes operation still always returns 0???
case NSStreamEventHasBytesAvailable:
{
//Check stream status
NSString *returnedStatus;
commandLength = [commandString length];
[commandString deleteCharactersInRange:NSMakeRange(0, commandLength)];
returnedStatus = [NSString stringWithString:[self decodeStatus:[stream streamStatus]]];
[commandString appendFormat:#"inputStream %# status=%#\n",stream, returnedStatus];
[self writeCommand:commandString];
uint8_t *buf[buffLength];
NSUInteger len = 0;
len = [(NSInputStream *)stream read:(uint8_t *)buf maxLength:buffLength];
if (len == 0) {
//len = buffLength;
[self writeCommand:#"No bytes read!\n"];
}
I also run into this issue and i found an answer in the documentation:
- (BOOL)hasBytesAvailable
Return Value:
YES if the receiver has bytes available to read, otherwise NO. May also return YES if a read must be attempted in order to determine the availability of bytes.
Related
I'm dealing with the garmin GDL90 protocol which sends across various types of messages in binary to my IOS device. I'm going through and trying to process all these messages but have been running into an issue. Specifically the messages are byte packed so that if you ever see an occurrence of
0x7d 0x5e or 0x7d 0x5d you have to convert them to 0x7d or 0x7e
I've set my code up so that I detect the message type I'm parsing and then call a function:
- (void) parseMessage:(NSMutableData *)message
to do my data parsing. My individual message parsing functions call the parent function [super parseMessage:message]; which handles both the parsing of common elements as well as dealing with my byte-stuffing. Each of these function calls takes an NSData * so shouldn't a modification made in my super function return back out the same data?
My top level class gets a parse message call and the NSMutableData pointer's address is: 0x170048f10
Once I step into the parent's parseData call my address is still 0x170048f10
After I make modifications to the data I'm now pointing at the memory address 0x17805e840
Once I return from this function, however, I'm back pointing at 0x170048f10 again with the wrong data.
Should I be using pass by reference or something? Any suggestions?
I have two variations of my function - unstuff1 throws an error and unstuff2 doesn't work.
- (NSMutableData *)unstuff1:(NSMutableData *)mutableData {
int dataLength = [mutableData length];
char *bytes = [mutableData bytes];
// Scan bytes ignoring 1st and last byte because they will be 7e's
for (int i = dataLength - 1; i > 0; i--) {
bytes[i + 1] ^= 0x20;
if (i + 1 == dataLength) {
NSLog(#"Terminal character padding detected on character %d with length %d", i, dataLength);
} else {
/* Replace 2 bytes with a single byte should remove the flag when you do this */
[mutableData replaceBytesInRange:NSMakeRange(i, 2) withBytes:&bytes[i + 1] length:1];
dataLength--;
}
}
return mutableData;
}
- (NSMutableData *)unstuff2:(NSMutableData *)data {
NSMutableData *mutableData = [[NSMutableData alloc] initWithData:data];
int dataLength = [mutableData length];
char *bytes = [mutableData bytes];
// Scan bytes ignoring 1st and last byte because they will be 7e's
for (int i = dataLength - 1; i > 0; i--) {
bytes[i + 1] ^= 0x20;
if (i + 1 == dataLength) {
NSLog(#"Terminal character padding detected on character %d with length %d", i, dataLength);
} else {
/* Replace 2 bytes with a single byte should remove the flag when you do this */
[mutableData replaceBytesInRange:NSMakeRange(i, 2) withBytes:&bytes[i + 1] length:1];
dataLength--;
}
}
return mutableData;
}
In unstuff2 obviously i'm making a new MutableData so I guess that accounts for the memory address change (that is the function i was using that gave me the error specified).
unstuff1 throws the following exception:
-[_NSInlineData replaceBytesInRange:withBytes:length:]: unrecognized selector sent to instance 0x178250d40
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSInlineData replaceBytesInRange:withBytes:length:]: unrecognized selector sent to instance
Unlike languages like C++ and C# (just to name two), Objective C has no concept of "pass by reference". However, passing a copy of a pointer to your NSMutableData is functionally equivalent to passing the object by reference. That is, if you pass in an NSMutableData (or NSMutableAnything for that matter) to a function and that function modifies it, the calling function will see the changes reflected in the object that it passed in.
Ok looks like I tracked down the problem. I realized the compiler was sending out warnings:
incompatible pointer types initializing 'NSMutableData *' with an expression of type 'NSData *'
It turns out I had some code
NSMutableData *message = [data subdataWithRange:NSMakeRange(5, len - 5)];
Which i needed to convert into:
NSMutableData *message = [NSMutableData dataWithData:[data subdataWithRange:NSMakeRange(5, len - 5)]];
And then things all work out. Moral of the story (read your warnings!!!!)
Sometimes when trying to get a path to a keychain returned by SecKeychainCopySearchList I get error with code -25301 which from the list of errors stands for errSecBufferTooSmall. The SecCopyErrorMessageString states:
There is not enough memory available to use the specified item.
Weird thing is that it doesn't always return the error on the very same keychain reference.
Here's how I try to get the path to the keychain:
- (NSString *)getKeychainPath:(SecKeychainRef)keychain {
char *pathName = malloc(sizeof(*pathName) * 1024);
UInt32 pathLength;
OSStatus errCode = SecKeychainGetPath(keychain, &pathLength, pathName);
if (errCode != errSecSuccess) {
NSString *errString = (NSString *)SecCopyErrorMessageString(errCode, NULL);
DLog(#"%d: %#", errCode, errString);
}
NSData *d = [NSData dataWithBytes:pathName length:pathLength];
return [[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding] autorelease];
}
I'm interested in what buffer does the function use? I've tried outputting the pathLength variable but it's way bellow the 1K bytes. What am I doing wrong? What should I do to avoid these errors? Can they be bypassed by any way at all?
From the SecKeychainGetPath documentation:
ioPathLength
On entry, a pointer to a variable containing the length (in bytes) of the buffer specified by pathName.
On return, the string length of pathName, not including the null termination.
You're not doing the "on input" part. You need to initialize pathLength to the size of the pathName buffer. For example:
UInt32 pathLength = 1024;
char *pathName = malloc(pathLength);
I have been working on reading in an audio asset using AVAssetReader so that I can later play back the audio with an AUGraph with an AudioUnit callback. I have the AUGraph and AudioUnit callback working but it reads files from disk and if the file is too big it would take up too much memory and crash the app. So I am instead reading the asset directly and only a limited size. I will then manage it as a double buffer and get the AUGraph what it needs when it needs it.
(Note: I would love know if I can use Audio Queue Services and still use an AUGraph with AudioUnit callback so memory is managed for me by the iOS frameworks.)
My problem is that I do not have a good understanding of arrays, structs and pointers in C. The part where I need help is taking the individual AudioBufferList which holds onto a single AudioBuffer and add that data to another AudioBufferList which holds onto all of the data to be used later. I believe I need to use memcpy but it is not clear how to use it or even initialize an AudioBufferList for my purposes. I am using MixerHost for reference which is the sample project from Apple which reads in the file from disk.
I have uploaded my work in progress if you would like to load it up in Xcode. I've figured out most of what I need to get this done and once I have the data being collected all in one place I should be good to go.
Sample Project: MyAssetReader.zip
In the header you can see I declare the bufferList as a pointer to the struct.
#interface MyAssetReader : NSObject {
BOOL reading;
signed long sampleTotal;
Float64 totalDuration;
AudioBufferList *bufferList; // How should this be handled?
}
Then I allocate bufferList this way, largely borrowing from MixerHost...
UInt32 channelCount = [asset.tracks count];
if (channelCount > 1) {
NSLog(#"We have more than 1 channel!");
}
bufferList = (AudioBufferList *) malloc (
sizeof (AudioBufferList) + sizeof (AudioBuffer) * (channelCount - 1)
);
if (NULL == bufferList) {NSLog (#"*** malloc failure for allocating bufferList memory"); return;}
// initialize the mNumberBuffers member
bufferList->mNumberBuffers = channelCount;
// initialize the mBuffers member to 0
AudioBuffer emptyBuffer = {0};
size_t arrayIndex;
for (arrayIndex = 0; arrayIndex < channelCount; arrayIndex++) {
// set up the AudioBuffer structs in the buffer list
bufferList->mBuffers[arrayIndex] = emptyBuffer;
bufferList->mBuffers[arrayIndex].mNumberChannels = 1;
// How should mData be initialized???
bufferList->mBuffers[arrayIndex].mData = malloc(sizeof(AudioUnitSampleType));
}
Finally I loop through the reads.
int frameCount = 0;
CMSampleBufferRef nextBuffer;
while (assetReader.status == AVAssetReaderStatusReading) {
nextBuffer = [assetReaderOutput copyNextSampleBuffer];
AudioBufferList localBufferList;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &localBufferList, sizeof(localBufferList), NULL, NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
// increase the number of total bites
bufferList->mBuffers[0].mDataByteSize += localBufferList.mBuffers[0].mDataByteSize;
// carefully copy the data into the buffer list
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
// get information about duration and position
//CMSampleBufferGet
CMItemCount sampleCount = CMSampleBufferGetNumSamples(nextBuffer);
Float64 duration = CMTimeGetSeconds(CMSampleBufferGetDuration(nextBuffer));
Float64 presTime = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(nextBuffer));
if (isnan(duration)) duration = 0.0;
if (isnan(presTime)) presTime = 0.0;
//NSLog(#"sampleCount: %ld", sampleCount);
//NSLog(#"duration: %f", duration);
//NSLog(#"presTime: %f", presTime);
self.sampleTotal += sampleCount;
self.totalDuration += duration;
frameCount++;
free(nextBuffer);
}
I am unsure about the what that I handle mDataByteSize and mData, especially with memcpy. Since mData is a void pointer this is an extra tricky area.
memcpy(bufferList->mBuffers[0].mData + frameCount, localBufferList.mBuffers[0].mData, sizeof(AudioUnitSampleType));
In this line I think it should be copying the value from the data in localBufferList to the position in the bufferList plus the number of frames to position the pointer where it should write the data. I have a couple of ideas on what I need to change to get this to work.
Since a void pointer is just 1 and not the size of the pointer for an AudioUnitSampleType I may need to multiply it also by sizeof(AudioUnitSampleType) to get the memcpy into the right position
I may not be using malloc properly to prepare mData but since I am not sure how many frames there will be I am not sure what to do to initialize it
Currently when I run this app it ends this function with an invalid pointer for bufferList.
I appreciate your help with making me better understand how to manage an AudioBufferList.
I've come up with my own answer. I decided to use an NSMutableData object which allows me to appendBytes from the CMSampleBufferRef after calling CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer to get an AudioBufferList.
[data appendBytes:localBufferList.mBuffers[0].mData length:localBufferList.mBuffers[0].mDataByteSize];
Once the read loop is done I have all of the data in my NSMutableData object. I then create and populate the AudioBufferList this way.
audioBufferList = (AudioBufferList *)malloc(sizeof(AudioBufferList));
if (NULL == audioBufferList) {
NSLog (#"*** malloc failure for allocating audioBufferList memory");
[data release];
return;
}
audioBufferList->mNumberBuffers = 1;
audioBufferList->mBuffers[0].mNumberChannels = channelCount;
audioBufferList->mBuffers[0].mDataByteSize = [data length];
audioBufferList->mBuffers[0].mData = (AudioUnitSampleType *)malloc([data length]);
if (NULL == audioBufferList->mBuffers[0].mData) {
NSLog (#"*** malloc failure for allocating mData memory");
[data release];
return;
}
memcpy(audioBufferList->mBuffers[0].mData, [data mutableBytes], [data length]);
[data release];
I'd appreciate a little code review on how I use malloc to create the struct and populate it. I am getting a EXC_BAD_ACCESS error sporadically but I cannot pinpoint where the error is just yet. Since I am using malloc on the struct I should not have to retain it anywhere. I do call "free" to release child elements within the struct and finally the struct itself everywhere that I use malloc.
I really would like to use the getBuffer:length: method of an NSInputStream.
After a lot of research i couldn't find a valid example that uses this method, because most people really needed read: maxLength:.
So now some facts on the surroundings:
* I'm developing an app for the iPhone, iOS 3.1.3
* I've established a network communication via sockets
* That network connection actually works; so i didn't forget to add a a stream to the runloop or a valid delegate or such things - it already works
* I'm only sending and receiving Strings over the network.
* I've set a valid delegate that implements stream: handleEvent: correctly (differentiates between the received events and takes proper actions).
I'm not sure if the receiving code is 100% correct as i sometimes receive a message twice.
This could also be caused be a faulty implementation on the device i'm communicating with.
To figure out which of the last to points it is, i'm trying to find out how many bytes are really on the receiving buffer when i receive a "NSStreamEventHasBytesAvailable" event.
As i don't know for sure that my implementation is correct, but i wanted to know the actual number of bytes i received, i wanted to use getBuffer: length: and take a look at the length afterwards.
Strange thing is: the length is never printed on the console, as
[((NSInputStream *) stream) getBuffer: &buf length: &numBytes] always evaluates to FALSE.
Anyway, the part of code afterwards works correctly, receives the message in the buffer and forwards it correctly - works good.
Question remains: Why doesn't getBuffer: length: work?
The code of interest is here:
`
case NSStreamEventHasBytesAvailable: {
uint8_t *buf;
unsigned int numBytes;
if ([((NSInputStream *) stream) getBuffer: &buf length: &numBytes]) {
NSLog(#"\t\tBytes in the buffer: %i", &numBytes);
}
uint8_t buffer[BUFFER_SIZE];
int len = [((NSInputStream *) stream) read: buffer
maxLength: BUFFER_SIZE];
NSLog(#"\tread: %i bytes", len);
/*
if len > 0: len is equal to the filled byte elements
if len == 0: end of buffer was reached while reading
if len < 0: something terrible happened...
*/
if (len > 0) {
/* 1. create string from received byte buffer */
NSString *msg = [[NSString alloc] initWithBytes: buffer length: len encoding: NSASCIIStringEncoding];
NSLog(#"\tcontained message: %#", msg);
/* 2. inform communicator about received message */
[communicator received: msg];
[msg release];
}
if (len < 0) {
[communicator received: #"Error!"];
}
break;
}
`
Would be nice if someone could help me!
Darwin is open source, so "the truth is out there". The source for NSStream shows that GSInetInputStream is the class that implements a NSInputStream for a socket, and the implementation of getBuffer:length: for that class answers the question succinctly:
- (BOOL) getBuffer: (uint8_t **)buffer length: (unsigned int *)len
{
return NO;
}
Found here.
I think that getBuffer isn't working because there isn't a buffer yet, you are reading into the buffer afterwards, so it cant get the pointer to the buffer yet...
ah, i think i get what you mean. but i suppose the following code should then evaluate to TRUE at least after reading into the buffer?
i'm just asking, because it doesn't, getBuffer:length: still seems not to work.
the communication using the available bytes works well, but the question remains...
uint8_t *buf1;
unsigned int numBytes1;
if ([((NSInputStream *) stream) getBuffer: &buf length: &numBytes]) {
NSLog(#"\t\tBytes are in the buffer before Op.");
}
uint8_t buffer[BUFFER_SIZE];
int len = [((NSInputStream *) stream) read: buffer
maxLength: BUFFER_SIZE];
uint8_t *buf2;
unsigned int numBytes2;
if ([((NSInputStream *) stream) getBuffer: &buf2 length: &numBytes2]) {
NSLog(#"\t\tBytes in the buffer after Op.");
}
sorry for creating an answer to my own question; but the comment was able to handle so much code...
I am interfacing with a hardware device that streams data to my app over Wifi. The data is streaming in just fine. The data contains a character header (DATA:) that indicates a new record has begun. The issues is that the data I receive doesn't necessarily fall on the header boundary, so I have to capture the data until what I've captured contains the header. Then, everything that precedes the header goes into the previous record and everything that comes after it goes into a new record. I have this working, but wondered if anyone has done this before and has a good computer-sciencey way to solve the problem.
Here's what I do:
Convert the NSData of the current read to an NSString
Append the NSString to a placeholder string
Check placeholder string for the header (DATA:). If the header is not there, just wait for the next read.
If the header exists, append whatever precedes it to a previous record placeholder and hand that placeholder off to an array as a complete record that I can further parse into fields.
Take whatever shows up after the header and place it in the record placeholder so that it can be appended to in the next read. Repeat steps 3 - 5.
Let me know if you see any flaws with this or have a suggestion for a better way.
Seems there should be some design pattern for this, but I can't think of one.
Thanks.
UPDATE: Here is a little bit of code:
uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {
[data appendBytes:(const void *)buf length:len];
int bytesRead;
bytesRead += len;
} else {
NSLog(#"No data.");
}
How would this code be changed then to implement a finite state machine?
That seems pretty much how I'd do it. The only thing I might do differently is write an NSData category that does the linear search of DATA: for me, just to save the overhead of converting it to a string. It wouldn't be that hard to do, either. Something like:
#interface NSData (Search)
- (NSRange) rangeOfData:(NSData *)aData;
#end
#implementation NSData (Search)
- (NSRange) rangeOfData:(NSData *)aData {
const void * bytes = [self bytes];
NSUInteger length = [self length];
const void * searchBytes = [aData bytes];
NSUInteger searchLength = [aData length];
NSUInteger searchIndex = 0;
NSRange foundRange = {NSNotFound, searchLength};
for (NSUInteger index = 0; index < length; index++) {
if (bytes[index] == searchBytes[searchIndex]) {
//the current character matches
if (foundRange.location == NSNotFound) {
foundRange.location = index;
}
searchIndex++;
if (searchIndex >= searchLength) { return foundRange; }
} else {
searchIndex = 0;
foundRange.location = NSNotFound;
}
}
return foundRange;
}
#end
Then you can just use:
NSData * searchData = [#"DATA:" dataUsingEncoding:NSUTF8StringEncoding];
while(receivingData) {
if ([receivedData rangeOfData:searchData].location != NSNotFound) {
//WOOO!
}
}
(warning: typed in a browser)
This is a classic finite state machine problem. A lot of data protocols that are stream based can be described with a finite state machine.
Basically you have a state, and transition. Boost has a finite state machine library, but it could be overkill. You can implement it as a switch.
while(stream.hasData) {
char nextInput = stream.get();
switch(currentState) {
case D: {
if(nextInput == A)
currentState = A;
else
currentState = D; //die
} case A: {
//Same for A
}
}
}
Requested elaboration:
Basically look at the diagram below...it's a finite state machine. At any given time the machine is in exactly one state. Every time a character is input into the state machine a transition is taken, and the current state moves. (possibly back into the same state). So all you have to do is model your networked data as a finite state machine then implement that machine. There are libraries that lay it out for you, then all you have to do is implement exactly what happens on each transition. For you that you probably mean interpreting or saving the byte of data. The interpretation depends on what transition. The transition depends on the current state and the current input. Here is an example FSM.
alt text http://www.freeimagehosting.net/uploads/b1706f2a8d.png
Note that if the characters DATA: are entered the state moves to the last circle. Any other sequence will keep the state in one of first 5 states. (top row) You can also have splits. So the FSM can make decisions, so if you get a sequence like DATA2: then you can branch off of that machine into the data2: part and interpret differently in a totally different part of the machine.