Save and Play Different AVAudioRecorder Files - objective-c

I am trying to play around with AVAudioRecorder and what I am trying to do now is to record and play on different views.
Here is how it goes. I have 20 views(or pages because I am preparing for a book app) in each page you can record and automatically saves the file when you stop, then, play it only on that page. When you go to other pages you can record again another, and when you go back to the previous pages your previous recordings are still playable.
How can I do that? I've tried giving the files different names and play it using the AVAudioPlayer but it's not working.

Your use of multiple filenames is one of the easiest way to address this need. I use multiple files to store audio data for one of my apps. In my case I preload the data from the file into memory then alloc a new AVAudioPlayer object and init it with the data:
self.msg = [NSMutableData dataWithContentsOfURL:filePathAsString];
self.player = [[[AVAudioPlayer alloc] initWithData:self.msg error:&err] autorelease];
...
[self.msg release];
To record a given audio clip again simply save the recorded data over any existing data in a file associated with the view in question and your playback automatically gets the new audio when the code above executes.

Related

create a directory to save recorded files on iphone using objective c

I am letting user record audio from mic to .acc file
at the moment they are saved to default app document folder
in plist i enabled "supports opening documents in place"
Now in iPhones File App i can see my apps folder in Documents and also see and listen to the recorded .acc file
great... but...
Now the user can also see and then edit / mess with ini files and other files i dont really want them o see or edit etc...
So now this isnt a good solution.
So where do i save recorded audio so that users can still see them, find them on their phone, listen and share them with friends (without being to see the apps other files)?
For any files that don't need to change, just keep them as resources in your app bundle and load them from there at runtime.
For files that are generated at runtime (not at build-time) or config files that change, which you don't want to be exposed, put them in Application Support instead of in Documents.
In Objective-C:
NSArray * appSupportURLs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
In Swift:
let appSupportURLs = FileManager.default.urls(for: .applicationSupportDirectory,
in: .userDomainMask)
This Apple Developer video pretty much covers it: https://developer.apple.com/videos/play/tech-talks/204/

preload HLS streaming for a list of playerItem

I'm trying to preload the first second of a list of playerItems to prevent delay at beginning.
I'm using preferredForwardBufferDuration to preload.
Here is a snippet for preload setup:
//setup repload in advance
VURLAsset *asset = [AVURLAsset assetWithURL:m3u8URL];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
playerItem.preferredForwardBufferDuration = 1;
AVPlayer *player = [[AVPlayer alloc] init];
_playerLayer.player = player;
player.replaceCurrentItemWithPlayerItem(playerItem)
// as soon as playback begins, reset it to 0
_item.preferredForwardBufferDuration = 0;
I have two questions:
I noticed that it takes about 1-3 seconds (great wifi) for playerItem status change from AVPlayerItemStatusUnknown to AVPlayerItemStatusReadyToPlay after the setup. So if I tap to play within 1 second after the preload setup, it will have to wait until status changes to ready. Why it's taking that much time and what's causing the status change? Prefetching the first 1 second under great wifi shouldn't take that long.
I would like to preload the first second of a list of playerItems. Is it possible to use the above method? Or if I can use AVAssetResourceLoader?
Speeding up playback has several variables to deal with. Take a look on this session https://developer.apple.com/videos/play/wwdc2016/503/ it contains section "Speeding up HTTP Live Streaming" which may be helpful.
Loading time may contains several components e.g. master playlist is too long and it takes time to load it and parse (in this case recommended to setup http compression with gzip on web server) or FairPlay stream encrypted before starts playing. If your stream is video you may also tweak initial quality of video.

Are iCloud images being cached in iOS device after being retrieved by application?

I have a simple UITableView, where each cell has an thumbnail picture that the user may have taken with its iOS device camera.
If iCloud is enabled the image is saved in it. However I was wondering if some sort of caching happens when loading the image, because I have notice a slowness on first loading then, even if the piece of code is called again when cell display on screen, the image show quite fast.
This is the relevant code fragment, I have omitted the logic for building the cell, I think it is not relevant, because the question is about other aspects:
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// logic for retrieve data and build cell
NSURL *ubiquityUrl = [fm URLForUbiquityContainerIdentifier:nil];
NSURL *docURL = [ubiquityUrl
URLByAppendingPathComponent:[NSString stringWithFormat:#"P_%#_%#.jpg",imgId,#"thumbnail"]
isDirectory:NO];
// this a custom object extending UIDocument
IP2DataDocument *dataDocument = [[IP2DataDocument alloc] initWithFileURL:docURL];
[dataDocument openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(#"iCloud document opened");
// logic for filling table cell picture
} else {
NSLog(#"failed opening document from iCloud");
}
}];
// returning cell
}
I can see "iCloud document opened" in Xcode, each time the cell display.
If some sort of caching occurs, can you point out where and how ?
The Document-based App Programming Guide for iOS says:
When you run a metadata query to learn about an application’s iCloud documents, the query results are placeholder items (NSMetadataItem objects) for document files. The items contain metadata about the file, such as its URL and its modification date. The document file is not in the iCloud container directory.
The actual data for a document is not downloaded until one of the following happens:
Your application attempts to open or access the file, such as by calling openWithCompletionHandler:.
Your application calls the NSFileManager method startDownloadingUbiquitousItemAtURL:error: to download the data explicitly.
To sum it up: The first time you open your document, it may not have been downloaded from iCloud yet, which is why it'll take longer. Afterwards, there is a local copy of the file that is obviously faster to read.
It is your docURL or specially
NSURL *ubiquityUrl = [fm URLForUbiquityContainerIdentifier:nil];
You don't actual access directly to iCloud. You access an equivalent local location (ubiquityUrl) that is iCloud enabled. If the file that you try to get has not been downloaded locally yet, then the local iCloud daemon will download it at the time you are accessing. Once this occurs, it is stored in your device locally. So the next time, you try to access it again using the docURL, it is much quicker because of this. Also the iCloud daemon is responsible for syncing version your document. So you don't need to worry about that if someone else has updated a newer version of the same document from another device.

Local file plays with AVAudioPlayer but not with AVPlayer?

(Note: The code here is Monotouch/C#, however Objective-C Answers are welcome!)
Im using AVPlayer as my app plays iPod library files as well as local mp3/m4a files. The playback of iPod library files is fine, however I cannot seem to get the AVPlayer to play local mp3 files.
For example, this code works:
NSUrl url;
AVAudioPlayer player2;
url = NSUrl.FromFilename(Path.Combine(Constants.TrackCacheLocation , songPath));
/* The url variable has the value file://localhost/private/var/mobile/Applications/B1ED2576-4398-43F3-8573-2FA3A0342265/Documents/Cache/Remote/dcaad4ff-452e-4d91-8788-c018e6b286f2.mp3 */
player2 = AVAudioPlayer.FromUrl(url);
player2.Play();
The above works fine, note that it's using AVAudioPlayer.
This doesn't (using AVPlayer):
NSUrl url;
AVPlayer player2;
url = NSUrl.FromFilename(Path.Combine(Constants.TrackCacheLocation , songPath));
/* The url variable has the value file://localhost/private/var/mobile/Applications/B1ED2576-4398-43F3-8573-2FA3A0342265/Documents/Cache/Remote/dcaad4ff-452e-4d91-8788-c018e6b286f2.mp3 */
player2 = AVPlayer.FromUrl(url);
player2.Play();
Creating an NSUrl from a local or remote web server also works (with AVPlayer), eg: http://10.0.0.1/testing/test.mp3 delays about a second or two while loading, then starts to play fine. I have a feeling im not creating my NSUrl correctly (even though it works fine for AVAudioPlayer). Any one any have ideas what could be going wrong?
Also, if I check the CurrentItem.Status of the AVPlayer it remains Unknown, it never changes to ReadyToPlay
Many API that uses NSUrl or NSUrlRequest parameters are async by design and will have issues (or even crash) if defined as a local variable (e.g. that will be collected when your method returns when still needed by the native code).
You code above does not supply enough information about where they are created. If you're using local variables then try to promote them as fields and ensure they will exists (e.g. don't re-assign them) until you don't need the AVPlayer anymore.

Download mutiple files in background thread

I am making an iPad app where you can download files (like PDF, doc, etc) and view them offline.
I already have the view part and you can download a file to the document directory.
As it is now you need to wait for the download to be finished to move on.
This can be solved by putting it in a thread, but what happens when the user downloads multiple files or even download the same file multiple times?
My idea is to make a download queue, with a view for the progress.
Workflow:
The user opens a document and press download, the user gets a message that the download is started and can be viewed in the offline documents view.
The user downloads 3 more documents.
When the user goes to the offline document view the user sees a table view with 4 filled cells. 2 documents are done loading and 2 other are still downloading because there is a download/status bar shown in the table view cell.
The downloaded documents can be viewed or deleted.
The downloads in progress can not be watched (yet) but can be cancelled.
I want to make a threaded download class where you can add urls to be downloaded. the class has methods to cancel and delete document-downloads, but also has methods to return the progress.
If possible the class can handle simultaneous downloads.
The problem is, I don't know where to start?
NSURLConnection is already asynchronous. All you need to do is to create NSURLConnection instances, associate them with your data structures, and have at it.
Here's an example where I assume you have one UIView per item. If you use a table view you can't count on view instances, but instead associate a download with an NSIndexPath, or something else.
#implementation MyDownloadView
- (void)startDownload {
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
[req setHTTPMethod:#"GET"];
// Set headers etc. if you need
[[[NSURLConnection alloc] initWithRequest:req delegate:self] autorelease];
[req release];
self.responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Alternatively, store to a file so you don't run out of memory
[self.responseData appendData:data];
}
#end
Then implement the other NSURLConnection delegate methods to do what you need.
I've written an open source example that has pretty much all features you want, canceling a download is currently only available in code, but it's pretty easy to add a button for that.
I'm using asi-http-request for managing the downloads, and they are displayed in a grid view (AQGridView) instead of a UITableView, but i think you get the idea.
Download progress is managed via KVO.
See PSPDFDownload.m for a start. Download the full demo here
Full disclosure: This demo uses PSPDFKit for faster pdf display. But the Kiosk example is exactly what you need, and you don't need to use PSPDFKit for pdf display. There's even an example code path that uses Apple's QuickLook.