iPhone: Error uploading audio wav bytes data to server - ios

I am developing an iOS application. I have to send an audio file to our server programmatically. I am using the following code to send an sample wav audio file to server. Our server accepts only audio file in signed bytes array format for receiving.
NSURL *urlPath = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"Crash" ofType:#"wav"]];
NSString *wavbundlepath = [urlPath absoluteString];
NSLog(#"wavbundlepath: %#",wavbundlepath);
NSData *bytes = [wavbundlepath dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"bytes: %#",bytes);
NSString *recordPostLength = [NSString stringWithFormat:#"%d", [bytes length]];
NSMutableString *urlstr = [NSMutableString stringWithFormat:#"%#", #"http://www.mywebserver/api/UploadFile?Name="];
[urlstr appendString:#"crash"];
[urlstr appendFormat:#"&MemberID=%d", 0];
[urlstr appendFormat:#"&Type=%#",#"Recording"];
[urlstr appendFormat:#"&client=%#",#"ios"];
NSLog(#"urlstr.......%#",urlstr);
NSMutableURLRequest *recordRequest = [[NSMutableURLRequest alloc] init] ;
[recordRequest setURL:[NSURL URLWithString:urlstr]];
[recordRequest setHTTPMethod:#"POST"];
[recordRequest setValue:recordPostLength forHTTPHeaderField:#"Content-Length"];
[recordRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[recordRequest setHTTPBody:bytes];
NSURLResponse *recordResponse;
NSError *recordError;
NSData *recordResponseData = [NSURLConnection sendSynchronousRequest:recordRequest returningResponse:&recordResponse error:&recordError];
NSString *recordResp = [[NSString alloc]initWithData:recordResponseData encoding:NSUTF8StringEncoding];
NSLog(#"recordResp:%#", recordResp);
But the problem is, always receving "Input string is not correct." response error.
I am not very much aware of uploading audio bytes to server. Could someone please check this code and tell me this is valid code or not for uploading a wav audio bytes array to server?
Thank you.
UPDATED CODE
I tried below code as my server side engineer said not to have any other things post body, and it works fine and getting positive response. But, the server is not able to work with format NSData bytes (32 bit elements) what i'm sending, because server side its implemented to receive only array of bytes or signed bytes data format only.
NSURL *urlPath = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"Temp" ofType:#"wav"]];
NSString *wavbundlepath = [urlPath absoluteString];
NSLog(#"wavbundlepath: %#",wavbundlepath);
NSData *bytes=[NSData dataWithContentsOfURL:urlPath];
NSLog(#"bytes: %#",bytes);
NSString *recordPostLength = [NSString stringWithFormat:#"%d", [bytes length]];
NSMutableString *urlstr = [NSMutableString stringWithFormat:#"%#", #"http://www.myserver.com/api/UploadFile?Name="];
[urlstr appendString:#"Temp"];
[urlstr appendFormat:#"&MemberID=%d", 0];
[urlstr appendFormat:#"&Type=%#",#"Recording"];
[urlstr appendFormat:#"&client=%#",#"ios"];
NSLog(#"urlstr.......%#",urlstr);
NSMutableURLRequest *recordRequest = [[NSMutableURLRequest alloc] init] ;
[recordRequest setURL:[NSURL URLWithString:urlstr]];
NSInputStream *dataStream = [NSInputStream inputStreamWithData:bytes];
[recordRequest setHTTPBodyStream:dataStream];
[recordRequest setHTTPMethod:#"POST"];
NSURLResponse *recordResponse;
NSError *recordError;
NSData *recordResponseData = [NSURLConnection sendSynchronousRequest:recordRequest returningResponse:&recordResponse error:&recordError];
NSString *recordResp = [[NSString alloc]initWithData:recordResponseData encoding:NSUTF8StringEncoding];
NSLog(#"recordResp:%#", recordResp);
recordResponceJson = [recordResp JSONValue];
NSLog(#"recordResponceJson = %#",recordResponceJson);
recId = [recordResponceJson valueForKey:#"ID"];
NSLog(#"recId....%#", recId);
Could someone please guide me, how i can send array of bytes in this http post?

There are a couple problems:
First how you're reading the file will not return a valid WAV file:
You should use [NSData dataWithContentsOfURL:] to read the bytes. The way you're reading them it will try to convert the bytes into characters. This will corrupt your wav file.
Second, the content-type of the POST body is probably incorrect. See the line:
[recordRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
The audio bytes would not be encoded in x-www-form-urlencoded format. It is more likely that the server would accept a audio/wav or application/octet-stream content type. Check with your server developers to see exactly what the server is expecting.
Also, you may want to check out the NSMutableURLRequest method called setHTTPBodyStream: that lets you send a file without having to load the entire thing into memory.

Related

Zip file not created properly in iOS

I am writing all the NSLOG's to a text file and post it to the server on click of a table view cell . I convert the text file to zip file before I post it using NSURLConnection . However , There is Some garbage data present inside the Zip file posted , But the text file has the correct content. I am using SSZipArchive, The code that I use to post the file is
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"Logger.txt"]];
NSString* zipfile = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"Logger.zip"]];
//create zip file, return true on success
BOOL isZipCreated=[SSZipArchive createZipFileAtPath:zipfile withContentsOfDirectory:logFilePath];
if (isZipCreated) {
NSLog(#"Zip file Created at Path : %#",zipfile);
NSString *contentOfZipFile = [NSString stringWithContentsOfFile:zipfile encoding:NSUTF8StringEncoding error:NULL];
NSData *zipData = [contentOfZipFile dataUsingEncoding:NSUTF8StringEncoding];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[zipData length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:finalURL]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/zip" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:zipData ];
NSURLConnection *conn = [[NSURLConnection alloc]initWithRequest:request delegate:self];
}
else {
NSLog(#"Zip create error");
}
Any assistance would be of great help.
You can use this library Objective-Zip, actually I have used this and its working fine for me.
Creating a Zip File:
ZipFile *zipFile= [[ZipFile alloc] initWithFileName:#"Logger.zip" mode:ZipFileModeCreate];
Adding a file to a zip file
ZipWriteStream *stream= [zipFile writeFileInZipWithName:#"Logger.txt" compressionLevel:ZipCompressionLevelBest];
[stream writeData:abcData];
[stream finishedWriting];
Reading a file from a zip file:
ZipFile *unzipFile= [[ZipFile alloc] initWithFileName:#"Logger.zip" mode:ZipFileModeUnzip];
[unzipFile goToFirstFileInZip];
ZipReadStream *read= [unzipFile readCurrentFileInZip];
NSMutableData *data= [[NSMutableData alloc] initWithLength:256];
int bytesRead= [read readDataWithBuffer:data];
[read finishedReading];
Hope this code will help you :)
Happy Coding!! ;)

Using base64 string with NSURLConnection

I am using a NSURLConnect call and I get unsupported URL when I have a space in my query string. To fix this I converted the string to base64 and I am still getting errors. How do I send a base64 string though NSUrlConnect successfully? If this isn't possible, how do I safely send a string with a space in it?
NSData *convertData = [queryWS dataUsingEncoding: NSUnicodeStringEncoding];
queryWS = [convertData base64EncodedStringWithOptions:kNilOptions];
NSURLRequest *urlRequest =
[NSURLRequest requestWithURL:[NSURL URLWithString:queryWS]];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
if (!error) {
responseDictionary =
[NSJSONSerialization JSONObjectWithData:data
options:0
error:&parseError];
You do not want to convert the URL string to base64 encoding. What you want is to properly escape any special characters in the URL. Please see the NSString stringByAddingPercentEscapesUsingEncoding: method or NSString stringByAddingPercentEncodingWithAllowedCharacters: if you only need to support iOS 9 or later.
NSString *queryString = #"SOME_QUERY_STRING";
NSString *encodedQueryString = [queryString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSURL returning nil When Calling an API

I'm trying to call an API and bring back menu items. My string seems to contain data because when I put it into a browser, I'm getting JSON.
NSString *urlString = [NSString stringWithFormat:#"https://api.nutritionix.com/v1_1/search/subway?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=MY_APP_ID&appKey=MY_APP_KEY"];
NSURL *url = [NSURL URLWithString:urlString];
My "urlString" contains a lot of information, but when I put a breakpoint on the NSURL object, it says it returns "nil".
EDIT: Removed spaces however the error persists.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"GET"];
[request setURL:[NSURL URLWithString:urlString]];
NSHTTPURLResponse *responseCode = nil;
NSError *error = [[NSError alloc] init];
NSData *ResponseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&responseCode error:&error];
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:ResponseData options:kNilOptions error:nil];
itemName = dataDictionary[#"item_name"];
NSLog(#"%#", itemName);
EDIT: Added request code
Ok, I have found something interesting about your url
You just forgot about string format. Every percent sign cry to you: 'I want to be replaced with something you gain to me!'
So, to prevent such behavior, you need to hide every percent with another percent: %%
-(void)doNSURLTestOne{
NSString *urlString = [NSString stringWithFormat:#"https://api.nutritionix.com/v1_1/search/subway?results=0%%3A20&cal_min=0&cal_max=50000&fields=item_name%%2Cbrand_name%%2Citem_id%%2Cbrand_id&appId=MY_APP_ID&appKey=MY_APP_KEY"];
NSURL *url = [NSURL URLWithString:urlString];
NSLog(#"is url nil? %#", url);
NSLog(#"is urlString ok? %#", urlString);
}
But I prefer to use AFNetworking library for net part
UPD: better choice to use another clean NSString ( thanks #rmaddy )
-(void)doNSURLTestTwo{
NSString *urlString = #"https://api.nutritionix.com/v1_1/search/subway?results=0%3A20&cal_min=0&cal_max=50000&fields=item_name%2Cbrand_name%2Citem_id%2Cbrand_id&appId=MY_APP_ID&appKey=MY_APP_KEY";
NSURL *url = [NSURL URLWithString:urlString];
NSLog(#"is url nil? %#", url);
NSLog(#"is urlString ok? %#", urlString);
}

Post Request to alchemy API in iOS8

Im trying to use the API call TextGetRankedNamedEntities http://www.alchemyapi.com/api/entity/textc.html#rtext
Here is my relevant code:
NSString *data = #"Data I want analyzed";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"result.txt"];
[data writeToFile:appFile atomically:YES encoding:NSUTF8StringEncoding error:NULL];
//I have verified the data is in the file
NSString *queryString = [NSString stringWithFormat:#"http://access.alchemyapi.com/calls/text/TextGetRankedNamedEntities?apikey=MY_API_KEY&showSourceText=1"];
NSMutableURLRequest *theRequest=[NSMutableURLRequest
requestWithURL:[
NSURL URLWithString: queryString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
//Set request method to post
[theRequest setHTTPMethod:#"POST"];
NSString *post = [NSString stringWithFormat:#"&text=%#", appFile];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
[theRequest setHTTPBody:postData];
my result for this request is:
<?xml version="1.0" encoding="UTF-8"?>
<results>
<status>OK</status>
<usage>By accessing AlchemyAPI or using information generated by AlchemyAPI, you are agreeing to be bound by the AlchemyAPI Terms of Use: http://www.alchemyapi.com/company/terms.html</usage>
<url></url>
<language>english</language>
<text>/var/mobile/Containers/Data/Application/6C00A4F8-4DEE-44F2-9DBF-7568CEF72054/Documents/result.txt</text>
<entities>
</entities>
</results>
It appears that the data that is being send is the file path and not that actual contents of the file.
EDIT: Solved, Leaving the question for possible feedback and best practices for using HTTTP requests in iOS as I am new to both.
Change:
NSString *post = [NSString stringWithFormat:#"&text=%#", appFile];
To:
NSString *post = [NSString stringWithFormat:#"&text=%#", data];
It didn't occur to me to try this before posting the question because I had previous tried to do this but at that point I was sending the request with the GET method not the POST method.

Need to detect when app is unable to connect to server when uploading JSON document in iOS

I am uploading a JSON document from my app to a server on the web, and I am able to do this successfully. However, what I need to do now is detect when there is no WiFi or 3G connectivity and prompt the user with an alert that informs the user that the app is unable to connect, and then give them the option to save the JSON document as a .plist file locally.
Here is the code that I have thus far:
This is my method that uploads my JSON document to the server:
- (void) sendJsonDoc:(NSString *)jDoc {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://myWebsite.php"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request setValue:[NSString stringWithFormat:#"%d", [jDoc length]] forHTTPHeaderField:#"Content-length"];
[request setHTTPBody:[jDoc dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
int code = [httpResponse statusCode];
NSLog(#"%d", code);
}
Here is the code that I have in order to save the JSON document locally as a plist file:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
path = [path stringByAppendingPathComponent:#"jsonDoc.plist"];
// If the file doesn't exist in the Documents Folder, copy it.
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"jsonDoc" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:path error:nil];
}
// Load the Property List.
NSString *loadJSON = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
How do I detect in my sendJsonDoc method when there is no connection and issue an alert to the user that prompts them that there is no connection, and if they want to save the document locally?
Check out the Reachability framework/library.
tonymillion made a nice version of the Apple supplied one that has been adapted to use ARC and adds support for blocks as well. The readme on github also explains how you can subscribe to notifications for the change of connection :)
Check out the project here

Resources