(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.
Related
I am working on an existing project where UIWebview is used to load html string to load js files for loading contents downloaded from our server.Currently UIWebview is not able to load the contents in IOS which is perfectly loading in Android.
I have tried to switch to WKWebView but still no luck.
self.webContentView.delegate = self;
NSString* html = [player getHTMLString];
NSString* baseURL = [player getBaseURLPath];
[self.pageLoadingActivity startAnimating];
[self.webContentView loadHTMLString:html baseURL: [NSURL URLWithString: baseURL]];
EDIT------
After debugging sometime I found I was getting two 1100 error.
It seemed like two file were missing or app was not able to read them.
Now whenever I am hitting shouldStartLoadWithRequest with
request
URL:
file:///Users/ealpha4tech/Library/Developer/CoreSimulator/Devices/2CA71983-9996-44D6-944F-34E3EAFAE96D/data/Containers/Data/Application/6A19ABBA-CB68-4EE4-AC02-6AD3CB8A5A68/Documents/icplayer/icplayer/D2D6AFFF93CB2CFCB1640484F5429D89.cache.html
I am getting 1100 error.(the above file is present though)
So as a guess, I would say [player getHTMLString] is the problem.
NSURLErrorFileDoesNotExist: The specified file doesn’t exist.
This is a local file error.
I'm guessing that -getHTMLString is trying to load a file out of the app, but that file is not being included in the app.
I could help more if you provide 2 things.
Provide the source for -getHTMLString
Use NSLog() to print value of [player getBaseURLPath].
UPDATE
In looking at your output, I noticed …ments/icplayer/icplayer/D2D6A…. I think the proper path should only have one icplayer not two. Look to see if it's getting repeated somehow.
I am using the following code to populate a webView in my Mac app...
NSURL *url = [NSURL URLWithString:#"https://joeworkman.net"];
[self setMainFrameURL:[url absoluteString]];
I would like to be able to capture when there are errors loading this URL and then instead load a local HTML file stored within my app. This way the users gets presented with a presentable error instead of an ugly 500 server error (if that was the case). Not to mention that most users would not know what that meant anyhow.
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.
For a given MPMediaItem representing a track in an iOS5 user's music library, how can we determine if a track is:
an iTunes Match track that has not been downloaded from iCloud
vs.
a DRMed track
?
In both cases the NSURL returned by MPMediaItemPropertyAssetURL is nil. Therefore instantiating an AVAsset to check the exportable flag is not a viable solution.
It's my understanding that it depends on the version of iOS you use. I think prior to maybe 4.3, an asset returning nil meant simply that the item was DRMed and you didn't have access to it. However, in current versions (5), nil means it's iCloud only. Maybe you have tracks that you think are just DRMed but are in fact iCloud stored songs. On the current app I'm working on, I originally didn't account for iCloud tracks at all (as I was targeting the app for prior versions of iOS) and so I was getting crashes depending on who's device I used. To solve the issue and test for iCloud/DRM I use:
AVURLAsset* asset;
NSURL* realAssetUrl = [item valueForProperty:MPMediaItemPropertyAssetURL];
if(!realAssetUrl){
//track is iCloud
}
asset = [[AVURLAsset alloc]initWithURL:realAssetUrl options:nil];
if(asset == nil || asset.hasProtectedContent){
//asset is DRMed such that it cannot be played back.
//most apps can stop here but I need to be able to export the song
}
if (!asset.exportable || !asset.readable){
//the asset cannot be exported and thus cannot be cached to a file
//the current app directory and cannot be transferred over network
//if asset passed earlier check, can still be used for local playback
}
[asset release];
That seems to work fine for me, but you also imply you were headed down the same path, already, so I'm not sure how much help that'll be to you. However, good luck with your project and I hope you find the answer you're looking for!
I have a Cocoa/Objective-C application which embeds a WebKit WebView. I need to turn on database support and local storage. I know it can be done--I have it working in Safari--but I can't find an example of how to set this up in my own application.
I found this (unanswered) SO question which provides an example but, as the original poster mentions, doesn't work. And in fact, the methods he uses (setDatabasesEnabled, setLocalStorageEnabled) aren't defined in my WebKit.framework (Xcode 3.2.5), although they appear to exist if I define them myself.
Can anyone provide an example of how to enable local database storage for a WebKit-based Cocoa application? Many thanks if so!
Update: I've got something working...I was confused by "databases" vs. "local storage", which are apparently quite different things. Here's the code that works:
WebPreferences* prefs = [webView preferences];
[prefs _setLocalStorageDatabasePath:#"~/Library/Application Support/MyApp"];
[prefs setLocalStorageEnabled:YES];
So that works, but it requires the private method _setLocalStorageDatabasePath, which means no App Store for me. So my amended questions is now: is there a way to make this work without using a private method? I found the WebDatabaseDirectory preference key in this answer, which controls where databases go. But I couldn't find a corresponding key for local storage anywhere in the sources. Or is there a way for me to force local storage to use the database, and so the WebDatabaseDirectory key? Any ideas?
I submitted an app using this code to the Mac App Store, and Apple approved it:
Objective-C
WebPreferences* prefs = [webView preferences];
[prefs _setLocalStorageDatabasePath:#"~/Library/Application Support/MyApp"];
[prefs setLocalStorageEnabled:YES];
Swift 3
var prefs: WebPreferences? = webView.preferences
prefs?._setLocalStorageDatabasePath("~/Library/Application Support/MyApp")
prefs?.localStorageEnabled = true
Whether they will continue to approve that, I don't know, but they allowed it for my application as of 2011-01-29. Update: They also approved a version update to the same app, so it has gone through twice.
I'm going to take the Javascript to Objective-C bridge approach and store everything in core data. Set localStorage to false, then build a JS object and an instance named "localStorage" with the same methods. My javascript devs won't know the difference, and I already had to do the same thing with Air (basically). There's another way to leave the localStorage intact even though it doesn't actually store them in a persistent db. The elements can be iterated through in javascript and manipulated from there, but I think it will be better to simply replace the object with my own.
After a lot of pain and frustration I found a way to enable local storage and have it persist across application runs properly. This solution is specifically for OSX, but it may be applicable to iOS as well.
Download and add this header file into your project. It's not included in the XCode Webkit distribution.
click to download WebStorageManagerPrivate.h
Add to it, the following lines:
static NSString* _storageDirectoryPath();
+ (NSString *)_storageDirectoryPath;
These allow you to retrieve the directory location of the WebKit local storage tracker database. This is important because due to a bug in WebKit, if you don't store your LocalStorage WebView files in the same directory as the tracker database, they are deleted every other time you run your application. I didn't see a way in the WebStorageManager code to change this location for an individual application. It is always read from the user preferences.
Include the WebStorageManagerPrivate.h in your appDelegate.
#include "WebStorageManagerPrivate.h"
You need to download and include in your project another header not included in XCode distribution. Save it as WebPreferencesPrivate.h
click to download WebPreferencesPrivate.h
Include the WebPreferencesPrivate.h in your appDelegate.
#include "WebPreferencesPrivate.h"
Now use the code below in your applicationDidFinishLaunching handler to initialize and enable LocalStorage. The code assumes you have an IBOutlet named 'webView' for the WebView you are using.
NSString* dbPath = [WebStorageManager _storageDirectoryPath];
WebPreferences* prefs = [self.webView preferences];
NSString* localDBPath = [prefs _localStorageDatabasePath];
// PATHS MUST MATCH!!!! otherwise localstorage file is erased when starting program
if( [localDBPath isEqualToString:dbPath] == NO) {
[prefs setAutosaves:YES]; //SET PREFS AUTOSAVE FIRST otherwise settings aren't saved.
// Define application cache quota
static const unsigned long long defaultTotalQuota = 10 * 1024 * 1024; // 10MB
static const unsigned long long defaultOriginQuota = 5 * 1024 * 1024; // 5MB
[prefs setApplicationCacheTotalQuota:defaultTotalQuota];
[prefs setApplicationCacheDefaultOriginQuota:defaultOriginQuota];
[prefs setWebGLEnabled:YES];
[prefs setOfflineWebApplicationCacheEnabled:YES];
[prefs setDatabasesEnabled:YES];
[prefs setDeveloperExtrasEnabled:[[NSUserDefaults standardUserDefaults] boolForKey: #"developer"]];
#ifdef DEBUG
[prefs setDeveloperExtrasEnabled:YES];
#endif
[prefs _setLocalStorageDatabasePath:dbPath];
[prefs setLocalStorageEnabled:YES];
[self.webView setPreferences:prefs];
}
I hope this helps others have struggled or are still struggling with this issue, until it is fixed properly within WebKit.