I am getting a warning in my GTMHTTPUploadFetcher.m file that says "-fetcherWithRequest:fetcherClass" not found (return type defaults to "id")
for this code
+ (GTMHTTPUploadFetcher *)uploadFetcherWithRequest:(NSURLRequest *)request
fetcherService:(GTMHTTPFetcherService *)fetcherService {
// Internal utility method for instantiating fetchers
GTMHTTPUploadFetcher *fetcher;
if (fetcherService) {
fetcher = [fetcherService fetcherWithRequest:request
fetcherClass:self];
} else {
fetcher = (GTMHTTPUploadFetcher *) [self fetcherWithRequest:request];
}
return fetcher;
}
and then I get an error involving the Foundation Framework
Parse Issue
expected expression
//this is where the expected expression is
- (void)uploadNextChunkWithOffset:(NSUInteger)offset
fetcherProperties:(NSMutableDictionary *)props {
// upload another chunk
NSUInteger chunkSize = [self chunkSize];
NSString *rangeStr, *lengthStr;
NSData *chunkData;
NSUInteger dataLen = [self fullUploadLength];
if (offset == kQueryServerForOffset) {
// resuming, so we'll initially send an empty data block and wait for the
// server to tell us where the current offset really is
chunkData = [NSData data];
rangeStr = [NSString stringWithFormat:#"bytes */%lu", (unsigned long)dataLen];
lengthStr = #"0";
offset = 0;
} else {
// uploading the next data chunk
#if DEBUG
**//this is the exact line of code causing the problem//**
(unsigned long)NSAssert2(offset < dataLen, #"offset %lu exceeds data length %lu",
offset, dataLen);
#endif
NSUInteger thisChunkSize = chunkSize;
// if the chunk size is bigger than the remaining data, or else
// it's close enough in size to the remaining data that we'd rather
// avoid having a whole extra http fetch for the leftover bit, then make
// this chunk size exactly match the remaining data size
BOOL isChunkTooBig = (thisChunkSize + offset > dataLen);
BOOL isChunkAlmostBigEnough = (dataLen - offset < thisChunkSize + 2500);
if (isChunkTooBig || isChunkAlmostBigEnough) {
thisChunkSize = dataLen - offset;
}
chunkData = [self uploadSubdataWithOffset:offset
length:thisChunkSize];
rangeStr = [NSString stringWithFormat:#"bytes %lu-%u/%lu",
(unsigned long)offset, offset + thisChunkSize - 1, (unsigned long)dataLen];
lengthStr = [NSString stringWithFormat:#"%lu", (unsigned long)thisChunkSize];
}
//related to this
! expanded from macro 'NSAssert2'
#define NSAssert2(condition, desc, arg1, arg2) NSAssert((condition), (desc), (arg1), (arg2))
! expanded from macro 'NSAssert'
#if !defined(_NSAssertBody)
#define NSAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
#endif
Only started getting the error after I updated Xcode (not to new version just update)
anyone have any suggestions not sure these two are related or not so will post this second part separately.
Solved this by going into time machine and resurrecting the old .m file and replacing it. It no doesn't give me an error, however I can't upload video because of MIME type problem, but that's another post.
Solved this by going into time machine and resurrecting the old .m file and replacing it.
Related
I am having a bit of an issue passing a reference to a primitive type through chaining, and having the value represented by the pointer change correctly. The weird part is, if I call getBytes directly from main function, byteLocation is properly adjusted, but if I chain it through a convenience function, it seems get a junk value. Actually, even weirder, it at first gets the correct value when stepping through the debugger, but executes the return clause twice. The first return clause gets the correct value, the second loads byteLocation with a junk value. Any ideas?
EDIT (Actual Code):
#property (strong, nonatomic, nonnull) NSData* data;
#property (assign, nonatomic) CFByteOrder byteOrder;
- (void)convertBytesToHostOrder:(nonnull void*)buffer length:(NSUInteger)length {
if(length > 1 && self.byteOrder != CFByteOrderGetCurrent()) {
// Swap bytes if the packet endiness differs from the host
char* fromBytes = buffer;
for(NSUInteger i=0; i < length/2; i++) {
NSUInteger indexes[2] = {i, length-i-0};
char byte = fromBytes[indexes[0]];
fromBytes[indexes[0]] = fromBytes[indexes[1]];
fromBytes[indexes[1]] = byte;
}
}
}
- (nonnull void*)getBytes:(nonnull void*)buffer startingFrom:(nonnull NSUInteger*)location length:(NSUInteger)length {
NSRange range = NSMakeRange(*location, length);
[self.data getBytes:buffer range:range]; // self.data is an instance of NSData
[self convertBytesToHostOrder:buffer length:length];
NSUInteger update = range.location + range.length;
*location = update;
return buffer;
}
- (NSTimeInterval)readTimeIntervalStartingFrom:(nonnull NSUInteger*)byteLocation {
uint32_t seconds;
uint16_t milliseconds;
// This line of code screws up the byteLocation pointer for some reason
[self getBytes:&seconds startingFrom:byteLocation length:sizeof(seconds)];
[self getBytes:&milliseconds startingFrom:byteLocation length:sizeof(milliseconds)];
NSTimeInterval ti = seconds + milliseconds / ((double) 1000 * (1 << 6));
return ti;
}
- (void)readData {
NSUInteger byteLocation = 0;
self.sequenceNumber = *(uint8_t*) [self getBytes:&_sequenceNumber startingFrom:&byteLocation length:sizeof(_sequenceNumber)];
self.flags = *(uint8_t*) [self getBytes:&_flags startingFrom:&byteLocation length:sizeof(_flags)];
// Continue to process packet data if we didn't get a goodbye message
if(!(self.flags & LBRadarPongFlagGoodbye)) {
// Parse accelerations
int16_t int16;
self.accelerationX = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
self.accelerationY = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
self.accelerationZ = (*(int16_t*) [self getBytes:&int16 startingFrom:&byteLocation length:sizeof(int16)]) / kGToRaw;
// Parse peripheral states
self.batteryVoltage = [self readFloat16From:&byteLocation];
self.chargeCurrent = [self readFloat16From:&byteLocation];
self.systemCurrent = [self readFloat16From:&byteLocation];
// All previous lines of code work properly and as expected.
// Buffers are read properly, and byteLocation properly reflects 14, which is the number of bytes read up to this point.
self.pongReceivedTimeIntervalSince1970 = [self readTimeIntervalStartingFrom:&byteLocation];
}
}
The problem seems to be with incrementing the location. In both cases you should copy from position zero, up to the size of the variable. In the following code:
[self readBytes:&seconds location:byteLocation length:sizeof(seconds)]
[self readBytes:&milliseconds location:byteLocation length:sizeof(milliseconds)]
The first call starts at position zero and reads 32 bits. The second one starts at position 32, which doesn't even fit in the variable's 16 bits. This is overflowing the buffer. Try this instead:
- (void*)readBytes:(void*)buffer location:(NSUInteger*)location length:(NSUInteger)length {
// The difference is in the next line. Zero instead of *location
[NSData getBytes:&buffer range:NSMakeRange(0, length)];
*location = *location + length;
return buffer; // Seems to be called twice, first time location* has the correct byteLocation inside it, second time location* has a junk value
}
At a guess[*] your error is on the line:
[self.data getBytes:&buffer range:NSMakeRange(*location, length)];
You are passing a void * value by taking the address of buffer - which is already a void *. Changing this to:
[self.data getBytes:buffer range:NSMakeRange(*location, length)];
will at least produce non-garabge results.
[*] I can only guess as the code you posted did not even compile, I edited your question to correct some of the more obvious errors - but even that involved some guessing! You should post real code.
I should have just posted the actual code, sorry guys. Turns out the error was in a helper function (convertBytesToHostOrder). This was reading out of bounds of buffer. Since buffer was the parameter right before byteLocation, it seems that writing at a location 1 spot beyond buffer was the byteLocation location. Fixed now and everything is working.
- (void)convertBytesToHostOrder:(nonnull void*)buffer length:(NSUInteger)length {
if(length > 1 && self.byteOrder != CFByteOrderGetCurrent()) {
// Swap bytes if the packet endiness differs from the host
char* fromBytes = buffer;
for(NSUInteger i=0; i < length/2; i++) {
NSUInteger indexes[2] = {i, length-i-0};
char byte = fromBytes[indexes[0]];
fromBytes[indexes[0]] = fromBytes[indexes[1]];
fromBytes[indexes[1]] = byte;
}
}
}
Should be:
NSUInteger indexes[2] = {i, length-i-1};
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!!!!)
I am trying to store an array based on audio input and then play animation frames corresponding to the input while the recording is played back.
The code is working up to now except after a while it crashes in the simulator and highlights
"CCLOG(#"adding image: %#", characterImageString);";
with this:
EXC_BAD_ACCESS (code=1, address=0xd686be8)
which is memory management I know but I am absolutely stumped.
if(isRecording){
int myInt;
NSString * characterImageString;
//get a number based on the volume input
float f = audioMonitorResults * 200; //convert max(0.06) to 12
f=((f/12)*10);
NSNumber *myNumber = [NSNumber numberWithDouble:(f+0.5)];
myInt = [myNumber intValue] + 1;
//create the image file name from the intiger we
//created from the audiomonitor results
if(myInt < 10){
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
} else if (myInt == 10){
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
CCLOG(#"adding image: %#", characterImageString);
//add each frame
[animationSequence addObject:characterImageString];
// print array contents
NSLog(#"animationSequence Array: %#", animationSequence);
// print array size
NSLog(#"animationSequence Number of Objects in Array: %u", [animationSequence count]); }
This is the code that plays as the audio is playing back:
-(void) updateAnimation:(ccTime) delta{
myFrame ++;
NSString *imageToDisplay;
imageToDisplay = animationSequence[myFrame];
CCTexture2D *currentTextureToDisplay = [[CCTextureCache sharedTextureCache] addImage:imageToDisplay];
[character setTexture:currentTextureToDisplay];
CCLOG(#"current texture to display: %#", currentTextureToDisplay);
if (myFrame >= [animationSequence count]) {
[self unschedule:#selector(updateAnimation:)];
}
Your characterImageString is nil if myInt > 10
The exception is thrown, because you're trying to print a variable, which hasn't been initialized.
You could try changing your code to something like this:
if(myInt < 10)
{
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
}
else if (myInt >= 10 && myInt < 100)
{
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
else if (myInt >= 100 && myInt < 1000)
{
characterImageString = [NSString stringWithFormat:#"fungus0%i.png",myInt];
}
else
{
characterImageString = [NSString stringWithFormat:#"fungus%i.png",myInt];
}
Obviously small debugging goes a long way. Could you add control printout for myInt before the line
if(myInt < 10){
to see the value of myInt before the crash?
if myInt is <= 0 your program has no protection for such case so resulting picture will not exist.
And for myInt > 10 the program will crash since NSString * characterImageString; is an automatic uninitialized variable of the random value.
hmmm ... some motherhood and apple pie , hard with the info available. Not certain what the initial float value is, so declare somewhere your min and max image numbers (say, kMinFrameNumber and kMaxFrameNumber). Since the float value could be anything at the start of your algorithm, add the following 'defensive' lines after computing myInt:
myInt=MAX(kMinFrameNumber,myInt);
myInt=MIN(kMaxFrameNumber,myInt);
then formatting :
characterImageString = [NSString stringWithFormat:#"fungus%04i.png",myInt];
finally, i doubt the exception is thrown at the highlighted line (that is where it is detected).
a. How did you declare the array animationSequence (is it retained?). If not, it could get autoreleased under your feet at some random interval, and you would be trying to send a message to a deallocated instance.
b. You should also check for bounds before addressing animationSequence
if(myFrame<[animationSequence count]-1) {
imageToDisplay = animationSequence[myFrame];
} else {
CCLOGERROR(#"Yelp ! addressing out of bounds!");
// terminate neatly here ! as in unschedule and return
}
c. check if your texture is nil before setting a sprite (it will accept a nil texture in cocos2d version 2.0) but, you are in the dark about the state of your code.
Previously I read audio samples from a complete audio file using CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer. Right now I would like to do the same using ranges (ie i specify the range in time.. read a small chunk of audio as per the time, and then go back and read again). The reason why I want to use time range is b/c I want to control the size of each read (to fit in a packet with a max size).
for some reason, there is always a bump between each read. In my code you'll notice that I start the AVAssetReader and end it every time I set a time range, and that's b/c I cannot dynamically adjust the time range after the reader has started (see here for more details).
Could it be that starting and ending a reader is just too expensive to produce a continuous real time experience? Or are there other ways of doing this that I'm not aware of?
Also note that this jitter or lag happens at whatever point I set the time interval to be.. which makes me believe that starting and ending a reader the way I am is too expensive for real time audio playback.
- (void) setupReader
{
NSURL *assetURL = [NSURL URLWithString:#"ipod-library://item/item.m4a?id=1053020204400037178"];
songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
track = [songAsset.tracks objectAtIndex:0];
nativeTrackASBD = [self getTrackNativeSettings:track];
// set CM time parameters
assetCMTime = songAsset.duration;
CMTimeReadDurationInSeconds = CMTimeMakeWithSeconds(1, assetCMTime.timescale);
currentCMTime = CMTimeMake(0,assetCMTime.timescale);
}
-(void)readVBRPackets
{
// make sure assetCMTime is greater than currentCMTime
while (CMTimeCompare(assetCMTime,currentCMTime) == 1 )
{
NSError * error = nil;
reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error];
readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track
outputSettings:nil];
[reader addOutput:readerOutput];
reader.timeRange = CMTimeRangeMake(currentCMTime, CMTimeReadDurationInSeconds);
[reader startReading];
while ((sample = [readerOutput copyNextSampleBuffer])) {
CMItemCount numSamples = CMSampleBufferGetNumSamples(sample);
if (numSamples == 0) {
continue;
}
NSLog(#"reading sample");
CMBlockBufferRef CMBuffer = CMSampleBufferGetDataBuffer( sample );
AudioBufferList audioBufferList;
OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
sample,
NULL,
&audioBufferList,
sizeof(audioBufferList),
NULL,
NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
&CMBuffer
);
const AudioStreamPacketDescription * inPacketDescriptions;
size_t packetDescriptionsSizeOut;
size_t inNumberPackets;
CheckError(CMSampleBufferGetAudioStreamPacketDescriptionsPtr(sample,
&inPacketDescriptions,
&packetDescriptionsSizeOut),
"could not read sample packet descriptions");
inNumberPackets = packetDescriptionsSizeOut/sizeof(AudioStreamPacketDescription);
AudioBuffer audioBuffer = audioBufferList.mBuffers[0];
for (int i = 0; i < inNumberPackets; ++i)
{
SInt64 dataOffset = inPacketDescriptions[i].mStartOffset;
UInt32 packetSize = inPacketDescriptions[i].mDataByteSize;
size_t packetSpaceRemaining;
packetSpaceRemaining = bufferByteSize - bytesFilled;
// if the space remaining in the buffer is not
// enough for the data contained in this packet
// then just write it
if (packetSpaceRemaining < packetSize)
{
[self enqueueBuffer];
}
// copy data to the audio queue buffer
AudioQueueBufferRef fillBuf = audioQueueBuffers[fillBufferIndex];
memcpy((char*)fillBuf->mAudioData + bytesFilled,
(const char*)(audioBuffer.mData + dataOffset), packetSize);
// fill out packet description
packetDescs[packetsFilled] = inPacketDescriptions[i];
packetDescs[packetsFilled].mStartOffset = bytesFilled;
bytesFilled += packetSize;
packetsFilled += 1;
// if this is the last packet, then ship it
size_t packetsDescsRemaining = kAQMaxPacketDescs - packetsFilled;
if (packetsDescsRemaining == 0) {
[self enqueueBuffer];
}
}
CFRelease(CMBuffer);
CMSampleBufferInvalidate(sample);
CFRelease(sample);
}
[reader cancelReading];
reader = NULL;
readerOutput = NULL;
currentCMTime = CMTimeAdd(currentCMTime, CMTimeReadDurationInSeconds);
}
}
I know what happens :-D It took me near a whole day to figure it out.
In fact AVAssetReader fades the first 1024 samples (maybe a little more) in. That's why you hear the jitter effect.
I fixed it by reading 1024 samples before the position I really want to read, then skip that 1024 samples.
I hope it'll work for you also.
Below code runs just fine on GCC 4.2 but fails with EXC_BAD_ACCESS in LLVM GCC 4.2
- (double_t)readDouble {
double_t *dt = (double_t *)(buffer+offset);
double_t ret = *dt; // Program received signal: EXC_BAD_ACCESS
offset += 8;
return ret;
}
That's how I allocate
int dataLength = [data length];
buffer = malloc(dataLength + 1);
buffer[dataLength] = 0; // null terminate to log
[data getBytes:(void *)buffer length:[data length]];
//NSLog(#"%s", buffer);
Offset and buffer is like
#interface PRDataSet : NSObject {
NSMutableArray *tables;
NSMutableDictionary *tablesByName;
NSMutableDictionary *tablesById;
#private
NSURLConnection *conn;
int offset;
char *buffer;
}
Yes offset is within range.
I do not free the buffer before I use it.
Any ideas?
This could be an aligment problem. The ARM processors (and many other processors) have restrictions regarding the data alignment, e.g. they can only read and write floating-point numbers from addresses that are a multiple of 4 or 8.
From the way the buffer is allocated in your code, it might not be allocated properly, or your double_t data elements aren't aligned within the buffer.
In order to avoid the problem, you should try to first copy the data into an aligned buffer and read it from there.
LLVM just doesn't read float directly.
Here's the solution:
- (uint32_t)readUInt32 {
uint32_t ret = *(uint32_t *)(buffer+offset);
offset += 4;
return ret;
}
- (uint16_t)readUInt16 {
uint16_t ret = *(uint16_t *)(buffer+offset);
offset += 2;
return ret;
}
- (uint64_t)readUInt64 {
uint64_t ret = *(uint64_t *)(buffer+offset);
offset += 8;
return ret;
}
- (float_t)readSingle {
uint32_t t = [self readUInt32];
float_t ret = *((float_t *)(&t));
return ret;
}
- (double_t)readDouble {
uint64_t t = [self readUInt64];
double_t ret = *((double_t *)(&t));
return ret;
}