just simple peace of code (file 1.mp3 clicked and playing as well in iTunes) :
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSError *outError = nil;
QTMovie *newMovie = [QTMovie movieWithURL:[NSURL URLWithString:#"/Users/Alex/1.mp3"] error:&outError];
if (newMovie) {
//[newMovie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
[self setMovie:newMovie];
}
[movie play];
give me error
Error Domain=NSOSStatusErrorDomain
Code=-2000 UserInfo=0x2004a6de0 "A
necessary data reference could not be
resolved."
Changing
[movie play];
to
[movie autoplay];
might help you. QTMovie loads the data in the background, so asking it to play right after it's created might be too quick for the QTMovie to really play the file.
You need to create a file:-based NSURL using fileURLWithPath:, not URLWithString:. URLWithString: is meant for URLs like http:, etc.
Try:
QTMovie *newMovie = [QTMovie movieWithURL:
[NSURL fileURLWithPath:#"/Users/Alex/1.mp3"] error:&outError];
Related
I have a very simple app that I have built to test out AVAudioPlayer. I have a 16s aif file that plays just fine on my Mac. Put it in a simple app and ran on my iPhone but no sound. Sending 'play' to the object returns success and audioPlayerDidFinishPlaying comes back with success after 16 seconds. Still no sound. Have checked the sound volume on the iPhone, just fine. Have checked to make sure my AVAudioPlayer object has volume set at 1.0 - it does. Can anybody help?
Here's my code
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"Soothing" ofType:#"aif"];
NSURL *playURL = [NSURL fileURLWithPath:soundPath];
NSError *error;
self.myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:playURL error:&error];
NSLog(#"About to play sound");
self.myAudioPlayer.delegate = self;
[self.myAudioPlayer prepareToPlay];
bool success = [self.myAudioPlayer play];
if (!success) {
NSLog(#"Failed to play file");
} else NSLog(#"Looks like it succeded");
OK - got it figured out. I had not configured the AVAudioSession for my app. Did something very simple as follows (copied from Apple's example code):
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError)
NSLog(#"Error setting category! %#", setCategoryError);
Sound now plays - plus learned a lot about how to control playback through screen locks, etc., which will be valuable.
Did you check if you get anything from the error?
if(error) {
NSLog( #"%#", [error localizedDescription] );
}
I've tried to overcome this for a while. I'm trying to record sound, but the AVAudioRecorder doesn't record while screen is locked. It does continue to record once screen is unlocked, but the audio recorded when screen was locked is lost forever. I can't find anything wrong with what I'm doing:
-(void) startRecording
{
// Begin the recording session.
_session = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
NSError *startRecordError;
[_session setActive:YES error:&startRecordError];
[self GKLog:[NSString stringWithFormat:#"recorder session error? :%#", startRecordError]];
[_session setCategory: AVAudioSessionCategoryRecord error: &setCategoryError];
if (setCategoryError) { NSLog(#"some error");}
//set me as delegate
_session.delegate=(id <AVAudioSessionDelegate>) self;
NSMutableDictionary* recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
[recordSetting setValue :[NSNumber numberWithInt:8] forKey:AVEncoderBitRateKey];
[recordSetting setValue:[NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
if (!self.currentPath)
{
NSLog(#"can't record, no path set!");
return;
}
NSError *error;
NSURL *url=[NSURL fileURLWithPath:self.currentPath];
//Setup the recorder to use this file and record to it.
_recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&error];
[self GKLog:[NSString stringWithFormat:#" recorder:%#",_recorder]];
_recorder.delegate=(id <AVAudioRecorderDelegate>) self;
[_recorder prepareToRecord];
//Start the actual Recording
[_recorder record];
}
Any ideas, please?
Ok, so the answer to my own question, which took me a long time to find out, is the following: The code I posted is good, but to actually work it needs to work in the background after screen was locked. For this one needs to add a UIBackgroundModes array in the app's plist file, and add 'audio' as one of its objects. This tells the system to let the app work with audio in the background.
Here's the not-so-easy to find documentation. Unfortunately apple doesn't specify that in their documentation of the audio session categories where they claim certain categories work in the background. Anyway, hopefully this answer will be available for others who have a similar problem...
You may want to consider setting the category as AVAudioSessionCategoryRecord to the AudioSession
How about disabling the screen lock until you are done recording?
[UIApplication sharedApplication].idleTimerDisabled = YES;
// Do recording here
[UIApplication sharedApplication].idleTimerDisabled = NO;
Just don't forget to re-enable the screen lock when you're done!
NSString *songNameEscaped = [songName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *songURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", #"http://somerootpath/Music/", songNameEscaped]];
NSLog(#"songURL = %#", songURL);
NSError *avPlayerError = nil;
AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:songURL error:&avPlayerError];
if (avPlayerError)
{
NSLog(#"Error: %#", [avPlayerError description]);
}
else
{
[avPlayer play];
}
If I copy the NSLog output from NSLog(#"songURL = %#", songURL); and paste it in safari, Quicktime plugin plays the files no problem so I know the URLs are valid. I've tried with .m4a and .mp3 files and have tried removing the spaces from songName but not matter what I always get Error:
Error Domain=NSOSStatusErrorDomain Code=-43 "The operation couldn’t be completed. (OSStatus error -43.)".
But they are just standard .m4a / .mp3 files created in iTunes.
Apparently AVAudioPlayer doesn't support streaming. Apple recommends AVPlayer for this although it is not as conveinient for finding things like current time and duration .
Error -43 indicates an inability to find the data. This could be because the url was in fact malformed, or because the server doesn't support streaming. You should try to pre-load the song data with an NSData object.
NSString *songNameEscaped = [songName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *songURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", #"http://somerootpath/Music/", songNameEscaped]];
NSLog(#"songURL = %#", songURL);
NSError *avPlayerError = nil;
NSData* songData = [NSData dataWithContentsOfURL:songURL error:&avPlayerError];
if (songData)
{
AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithData error:&avPlayerError];
if (avPlayer)
{
[avPlayer prepareToPlay];
[avPlayer play];
}
else
{
NSLog(#"Error initializing data for AVAudioPlayer. Possibly an Unsupported Format");
NSLog(#"Error: %#", [avPlayerError description]);
}
}
else
{
NSLog(#"Error initializing data for AVAudioPlayer. Possibly Malformed URL");
NSLog(#"Error: %#", [avPlayerError description]);
}
I had the same problem yesterday. Turns out my url was wrong.
I had something like you here:
NSURL *songURLID = [NSURL URLWithString:[NSString stringWithFormat:#"%#%d", #"http://somerootpath/Music/", songNameEscaped]];
NSLog(#"songURL = **%d**", songURL**ID**);
But, my songURL was of NSString type. My NSLog wrote it correctly but when I put %d in url it turn out wrong. I suggest you try to check out your AVAudioPlayer url again.
try something like described here to see the players url.
You may want to try checking the targets on your audio file. I had a similar issue and fixed it by making sure that my mp4 file target membership check box was checked. I must not have checked it when I was importing the file originally.
in Apple documentation
An instance of the AVAudioPlayer class, called an audio player,
provides playback of audio data from a file or memory.
Apple recommends that you use this class for audio playback unless you
are playing audio captured from a network stream or require very low
I/O latency.
So I have an app I've written for the iPad, and I'd like to be able to allow users to insert images into their documents by selecting an image from an album or the camera. All that works great. Because the user might keep the document longer than they keep the image in an album, I make a copy of it, scale it down a bit, and store it in a core data table that is just used for this purpose.
I store the image like this:
NSManagedObjectContext* moc=[(ActionNote3AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSString* imageName=[NSString stringWithFormat:#"img%lf.png",[NSDate timeIntervalSinceReferenceDate]];
Image* anImage = [NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:moc];
anImage.imageName=imageName;
anImage.imageData=UIImagePNGRepresentation(theImage);
NSError* error=nil;
if(![moc save:&error]) {...
I sub-class NSURLCache, as suggested on Cocoa With Love, and ovverride cachedResponseForRequest thusly:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
NSString *pathString = [[[request URL] absoluteString]lastPathComponent];
NSData* data = [Image dataForImage:pathString];
if (!data) {
return [super cachedResponseForRequest:request];
}
NSURLResponse *response =[[[NSURLResponse alloc]
initWithURL:[request URL]
MIMEType:[NSString stringWithString:#"image/png"]
expectedContentLength:[data length]
textEncodingName:nil]
autorelease];
NSCachedURLResponse* cachedResponse =[[[NSCachedURLResponse alloc] initWithResponse:response data:data] autorelease];
return cachedResponse;
}
I also make sure the app uses the sub-classed NSURLCache by doing this in my app delegate in didFinishLaunchingWithOptions:
ANNSUrlCache* uCache=[[ANNSUrlCache alloc]init];
[NSURLCache setSharedURLCache:uCache];
The method that returns the image data from the core data record looks like this:
+(NSData*)dataForImage:(NSString *)name {
NSData* retval=nil;
NSManagedObjectContext* moc=[(ActionNote3AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Image" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"imageName==%#", name];
[request setPredicate:predicate];
NSError* error=nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if ([array count]>0) {
retval=((Image*)[array objectAtIndex:0]).imageData;
}
return retval;
}
To insert the image into the web view, I have an html img tag where the name in src="" relates back to the name in the image table. The point of the NSURLCache code above is to watch for a name we have stored in the image table, intercept it, and send the actual image data for the image requested.
When I run this, I see the image getting requested in my sub-classed NSURLCache object. It is finding the right record, and returning the data as it should. However, I'm still getting the image not found icon in my uiwebview:
So Marcus (below) suggested that I not store the image data in a core data table. So I made changes to accomodate for that:
Storing the image:
NSString* iName=[NSString stringWithFormat:#"img%lf.png",[NSDate timeIntervalSinceReferenceDate]];
NSData* iData=UIImagePNGRepresentation(theImage);
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:iName];
[iData writeToFile:fullPathToFile atomically:NO];
Retrieving the image:
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
NSString *pathString = [[[request URL] absoluteString]lastPathComponent];
NSString* iPath = [Image pathForImage:pathString];
if (!iPath) {
return [super cachedResponseForRequest:request];
}
NSData* idata=[NSData dataWithContentsOfFile:iPath];
NSURLResponse *response =[[[NSURLResponse alloc]
initWithURL:[request URL]
MIMEType:#"image/png"
expectedContentLength:[idata length]
textEncodingName:nil]
autorelease];
NSCachedURLResponse* cachedResponse =[[[NSCachedURLResponse alloc] initWithResponse:response data:idata] autorelease];
return cachedResponse;
}
In debug mode, I see that idata does get loaded with the proper image data.
And I still get the image-not-found image! Obviously, I'm doing something wrong here. I just dont know what it is.
So... What am I doing wrong here? How can I get this to work properly?
Thank you.
I would strongly suggest that you do not store the binary data in Core Data. Storing binary data in Core Data, especially on an iOS device, causes severe performance issues with the cache.
The preferred way would be to store the actual binary data on disk in a file and have a reference to the file stored within Core Data. From there it is a simple matter to change the image url to point at the local file instead.
So it turns out I was way overthinking this. When I write the HTML, I just write the path to the image in with the image tag. Works like a charm.
I would love to know why the solution I posed in my question did not work, though.
And, I did wind up not storing the images in a table.
I want to play the music from internet by url.
I create a simply project that has one button with the following code:
NSURL *url = [[NSURL alloc] initWithString:#"http://someURL.mp3"];
NSError **err;
QTMovie *movie = [[QTMovie alloc] initWithURL:url error:err];
[movie play];
It works but with some delay (I think because it waits while file has been fully downloaded).
So what I need to do that the music starts to play immediately (when, for example, 10% of file has been downloaded)?
Use -[QTMovie autoplay] to automatically play the music once enough data has been downloaded.
In your case:
NSURL *url = [[NSURL alloc] initWithString:#"http://someURL.mp3"];
NSError **err;
QTMovie *movie = [[QTMovie alloc] initWithURL:url error:err];
[movie autoplay];
From the QTMovie class reference:
The autoplay method configures a QTMovie object to begin playing as soon as enough data is available that the playback can continue uninterrupted to the end of the movie.
If you can consider displaying a Quicktime window over your app, you can use this code :
NSString *url = #"http://someURL.mp3";
UIWebView* tempAudioPlayer = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[tempAudioPlayer loadHTMLString:[NSString stringWithFormat:#"<iframe frameborder=\"0\" width=\"0\" height=\"0\" src=\"%#\"></iframe>", url] baseURL:nil];
[self addSubview:tempAudioPlayer];
I first create a UIWebView which will not be displayed. Then I loadHTMLString a <iframe> in it, with the URL of my file as the src value. And I add it to my view. Quicktime appears immediately.