Progressive download using Matt Gallagher's audio streamer - iphone

I'm a completely n00b when talking about audio. I'm using Matt Gallagher's audio streamer on my radio app. How may I use progressive download? Also, ExtAudioFile is a good idea too :)
Edit:
Used this:
length = CFReadStreamRead(stream, bytes, kAQDefaultBufSize);
if(!data)
data =[[NSMutableData alloc] initWithLength:0];
[data appendData:[NSData dataWithBytes:bytes length:kAQDefaultBufSize]];
Now I can save the audio data using writeToFile:atomically: NSData method, but the audio won't play. Also, if I try to load it on a AVAudioPlayer, I get an error.

I'm trying to do something similar. I ended up doing it like this:
length = CFReadStreamRead(stream, bytes, kAQDefaultBufSize);
// Save data
if (saveLocation){
NSFileHandle *mp3 = [NSFileHandle fileHandleForWritingAtPath:saveLocation];
[mp3 seekToEndOfFile];
[mp3 writeData:[NSData dataWithBytes:bytes length:length]];
[mp3 closeFile];
}
Some problems to be aware of. You should make sure that the file at saveLocation exists. I made a new initializer with the mp3 url and saveLocation path, and put the check there. Also, be aware that if the user performs a seek in the mp3 this will not realize that. Basically, it will record exactly what gets played back. It is not smart enough to realize that the playback position moved. However, if you just start the stream, and allow it to finish the whole mp3 (assuming that it has an end) it should save just fine.

Related

ASIHTTPRequest - Uploading files from the camera roll

I currently need to upload large files from an iDevice to a server API. For this I'm attempting to use the ASIHTTPRequest library as it automatically supports uploading large files in queued chunks (before this I simply created an NSData instance with the bytes for the entire file at once and attached this to the POST message, but this causes the application to crash on larger files due to an excessive amount of RAM usage).
The problem is that when you need to upload files and add a file to the HTTP Post message, this is the syntax you need to use:
[theUploadRequest setFile:#"" forKey:#"videoupload"];
setFile requires a file path in a string format. The problem I'm currently having is that it does not seem like you are allowed to simply take the file path from a file which is not in your applications sandbox? Since I need to upload a file which is not in my application, but outside of it in the standard cameraroll.
I tried to make this quick test to see if I could create an NSData object and fill it with data from a file in the cameraroll, providing a path to it like this:
NSData *testData = [NSData dataWithContentsOfURL:theContent.defaultRepresentation.url];
NSLog(#"THE SIZE OF THE TEST DATA: %i", testData.length);
Note that "theContent" is an instance of an ALAsset, and is a file retrieved from the cameraroll. The result of this is simply a length of 0, which I suppose means you can't simply do that.
Is there any way around this? Or would I have to somehow import the video file into the application's sandbox?
So if I understand correctly, you want to upload stuff straight from the camera roll? Based on the docs I'd say the important piece of code you need is:
NSString *filePath = [[info objectForKey:
UIImagePickerControllerMediaURL] path];
The info dictionary is passed to your media picker's delegate:
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info;
You should then be able to use that filePath in your call to setFile.
Take a look here probably you'll find something useful.
Hope this helps.
EDIT:
For something simpler you can use the bit of code posted in this answer
Implying that you need to copy the file somewhere before uploading it, especially if it is a big one.

Get mp3 as NSData

I want to play a mp3 from my server with AVAudioPlayer. I am trying to do it by using
initWithData:(NSData *) error:(NSError **)
To do this I need to convert the mp3 to NSData then pass the NSData into my player.
How do I convert the mp3 to NSData.
NSData has an -initWithContentsOfURL: (or +dataWithContentsOfURL:) method you could use.
Or, you could use NSURLConnection to download your MP3 as NSData.
I'd advise the second method, because it can be used asynchronously and doesn't block the main thread, unlike NSData's -initWithContentsOfURL:
When you download it from the server, conveniently, you already have an NSData object. Did you try starting the player with that?

Streaming with an AVAudioplayer

In order to load a sound file, I have the following code in my application :
- (id) init:(NSString*)a_filename ext:(NSString*)a_ext
{
...
NSString *t_soundFilePath = [CFileLoader getPathForResource:filename WithExtension:ext];
NSURL *t_fileURL = [[[NSURL alloc] initFileURLWithPath: t_soundFilePath] autorelease];
player = [[AVAudioPlayer alloc] initWithContentsOfURL: t_fileURL error: nil];
[player prepareToPlay];
...
}
All the sounds that I load are in my bundle, so I would like to know if the method "initwithcontentsofurl" stream the sound file or if all the file is cached.
I have a lot of sprites in my app so I want to minimize memory space used for sounds.
thx for your help
I used AVPlayer (not AVAudioPlayer) to stream background audio.
Sounds that are played using the AVAudioPlayer are streamed real time from storage. The drawback being that you can occasionally notice a small lag when it is due to start up. If you use OpenAL the sounds are loaded entirely into memory.
There's a good discussion of this sort of thing in the ObjectAL documentation - a library that is meant to simplify the playing of sounds and effects on the iPhone.
If you want to stream audio in your app you can use the following player instead of using AVAudioPlayer
https://github.com/mattgallagher/AudioStreamer
For this player you don't need to put sound files in your bundle, you can put them at server and use url to stream audio.
Hope, this wil help you.
" The AVAudioPlayer class does not provide support for streaming audio
based on HTTP URL's. The URL used with initWithContentsOfURL: must be
a File URL (file://). That is, a local path".
https://developer.apple.com/library/ios/qa/qa1634/_index.html
But you can work around - for example write asynchronously to local file, and init AVAudioPlayer with this file URL, it will work.

Save Youtube video to iPhone in the app

Playing Youtube video in the app is easy and well documented around.
There are two problems with that:
after closing Youtube player, if user wants to play it again it has to wait for online streaming again
can't play offline (load video at home to watch on the road)
Does anyone have code to:
download Youtube video to documents folder and show progress of download
play downloaded video by loading file from documents folder (meaning even when not connected to the internet)
To download the video from YouTube:
Get the URL to download from, via the YouTube API or whatever other method.
Create an NSOutputStream or NSFileHandle opened on a temporary file (in NSTemporaryDirectory() or a temp-named file in your Documents directory).
Set up your progress bar and whatever else you need to do.
Allocate and start an NSURLConnection to fetch the file from the URL. Do not use sendSynchronousRequest:returningResponse:error:, of course.
In the connection:didReceiveResponse: delegate method, read out the length of data to be downloaded for proper updating of the progress bar.
In the connection:didReceiveData: delegate method, write the data to the output stream/file handle and update the progress bar as necessary.
In connectionDidFinishLoading: or connection:didFailWithError:, close the output stream/file handle and rename or delete the temporary file as appropriate.
To play it back, just use NSURL's fileURLWithPath: to create a URL pointing to the local file in the Documents directory and play it as you would any remote video.
Ive used classes from this project: https://github.com/larcus94/LBYouTubeView
It works fine for me.
I can download youtube videos.
I used this code:
LBYouTubeExtractor *extractor = [[[LBYouTubeExtractor alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:(#"http://www.youtube.com/watch?v=%#"), self.videoID ]] quality:LBYouTubeVideoQualityLarge] autorelease];
[extractor extractVideoURLWithCompletionBlock:^(NSURL *videoURL, NSError *error) {
if(!error) {
NSLog(#"Did extract video URL using completion block: %#", videoURL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL: videoURL];
NSString *pathToDocs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [NSString stringWithFormat:(#"video_%#.mp4"), self.videoID ];
[data writeToFile:[pathTODocs stringByAppendingPathComponent:filename] atomically:YES];
NSLog(#"File %# successfully saved", filename);
});
} else {
NSLog(#"Failed extracting video URL using block due to error:%#", error);
}
}];
You can show progress of downloading using technique described in the posts above.
Here is my example: https://github.com/comonitos/youtube_video
I used PSYouTubeExtractor.h class by Peter Steinberger It can get youtube mp4 video url and than downloading and viewing is not a problem
NSURLConnection
+
NSNotificationCenter
+
PSYouTubeExtractor
+
NSMutableData
check these projects -
https://github.com/iosdeveloper/MyTube
https://github.com/pvinis/mytube
these will definitely help you!!
I don't personally know how to download youtube videos (and the code is too big to put in an answer here).
However, here's a complete youtube downloading example here.
It's an open source youtube downloader called LoadTube: here's the a link to the source code.
I would play the video and figure out where the temp file is being stored. If you can get access to it, copy it into some document folder for offline viewing.

Multiple audio sounds in iPhone app?

I've gotten to play a single sound in the iPhone app I've started, but I now desire to play multiple sounds based on a button. To create a separate set of .m and .h files for each audio sounds, and then including them all, doesn't seem the most efficient way to tackle this in terms of coding...then again, I'm just starting out with Cocoa and only just completed my first app ever.
Any help is appreciated. The key here is multiple sounds, each triggered by its own button or image. Thanks.
If the files are MP3 or AAC format, then you can only play one at a time. This is a limitation of core audio on the iPhone.
In terms of playing multiple sounds at once, that's easy, just create a new player instance for every one that you want to play (and remember to release them when you're done)
NSString *path = [[NSBundle mainBundle] pathForResource:#"dream" ofType:#"m4a"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
To convert an MP3 into something like IMA4 (which you can play more than one at once) you would run the following (in terminal, in leopard):
/usr/bin/afconvert -f caff -d ima4 sound.mp3 sound.caf
The above code is firmware 2.2 only, but you can do the same with the AudioQueue files if you want to support older firmwares (it's just a lot more complex, so I haven't listed the code here).
If you have access to the iPhone developer network, then there are a bunch of code samples that show you how to play audio.
All you need to do is make one class that has a function called
-(void)Play:(NSString*)sSoundFile {
// play sound file here
}
I don't have any direct experience with iPhone development, but in theory could you create a single large sound file with all your sounds in it? Each sound could be separated by just enough silence to be individually accessed by a time index. Of course, the downside is that you'd have to load the entire file into memory, unless you could figure out a way to load chunks in a random-access fashion...
#rustyshelf - does this work in the simulator? I'm using that code, and using #import but neither audioPlayerDidFinishPlaying nor audioPlayerDecodeErrorDidOccur ever get called. Very annoying to try to debug.
http://www.icodeblog.com/2009/05/04/iphone-game-programming-tutorial-part-4-basic-game-audio/
in this example in ios5 you have to put
CFURLRef soundurl=(__bridge CFURLRef)[NSURL fileURLWithPath:objstring];
in place of
CFURLRef soundurl=(CFURLRef)[NSURL fileURLWithPath:objstring];
Hardik Mamtora