I have tried everything I can find to try and get my app to play an mp3. I have a few 2-3 second mp3s that play as sound effects that work, but I am trying to play a 15s mp3 without any luck.
NSError *error;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource: #"test" withExtension: #"mp3"] error:&error];
if (error) {
NSLog(#"Error creating audio player: %#", [error userInfo]);
} else {
if([audioPlayer play] == FALSE) {
NSLog(#"Fail %#", error);
}
}
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval: 15.0 target: self
selector: #selector(stopMusic) userInfo: nil repeats: NO];
I doubt the timer has anything to do with it but thought I would include it just in case. Basically my error checks are not getting triggered at all. It "should" be playing properly but no sound is coming out, and no errors are being displayed.
I have tried a few other things to try and get this working, and I have tried without the timer. I can't find a decent guide. I don't need a full blown media player, just some background music for an UIScreenViewController.
I have also tried the following code, which works good with short MP3s, not with the longer MP3 I want to play.
NSString *path = [[NSBundle mainBundle] pathForResource:#"bgmusic" ofType:#"mp3"];
NSURL *pathURL = [NSURL fileURLWithPath : path];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
Please help, I have spent hours trying to sort this. It seems apple re-jig their audio every time they release an OS.
I did a little testing for you: It turned out that music files aren't added to target by default in Xcode 5. Therefore URLForResource:error: likely returns nil.
Try removing the mp3 from your project. Then add it again and this time make shure you add it to your target:
The other thing is: It seems like you're defining the AVAudioPlayer inside a method. You normally set up a #property for your audio player because otherwise its life is limited to the method - and the music stops playing after you reach the end of the method.
Related
I managed to load an audio file onto a player and play it via the following method:
- (void) play:(NSString*)loop{
NSString* resourcePath = [[NSBundle mainBundle] pathForResource:loop
ofType:#"mp3"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:resourcePath]];
player.delegate = self;
[player play];
player.numberOfLoops = 1;
player.currentTime = 0;
player.volume = 1.0;
}
}
(I removed a couple of lines in this post but the method itself works great)
The problem here is, that the sound only gets loaded when the method play() is being called which results in a little delay in between the button click that calls the method and the player actually playing it.
I have about 200 sounds in my app and one way would be to load each sound in its own AVAudioPLayer in the viewDidLoad, but I doubt that this is considered good code.
On Android, I am using the SoundPool for this concern and it works great but I don't think there is an equivalent for this on iOS.
I now managed to do it via AudioServicesPlaySystemSound()
I use a method that loads all the sounds in a giant array
- (void)prepSounds{
NSString *soundPath =
[[NSBundle mainBundle] pathForResource:#"bl3"
ofType:#"mp3"];
NSURL *soundPathURL = [NSURL fileURLWithPath:soundPath];
AudioServicesCreateSystemSoundID(
(__bridge CFURLRef)soundPathURL, &soundID[0]);
AudioServicesPlaySystemSound(soundID[0]);
}
where soundID[] is an array of SystemSoundID declared in the header.
Now, I can just easily fire the sound via AudioServicesPlaySystemSound(soundID[0]) where 0 relates to the first sound I loaded. The latency is close to 0 (I would guess 5ms)
However, this only works for sounds no longer than about 30 seconds.
If you need any assistance with that, just comment here, I'm glad to help.
The app must to play a sound when it is in background. In the capabilities background fetch and audio & airplay are checked.
The method called for play the sound is that
-(void)playSound
{
NSString* str = [[NSBundle mainBundle] pathForResource:#"alarm4" ofType:#"wav"];
NSURL* url = [NSURL fileURLWithPath:str];
NSError* erreur;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&erreur];
if(!erreur)
{
[self.audioPlayer setVolume:1];
[self.audioPlayer setNumberOfLoops:-1];
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
}
else
NSLog(#"erreur de chargemnt %#", [erreur localizedDescription]);
}
Can you give me some advice, please?
My advice is: Don't even dream of such a thing. In general, you can't do it.
You can continue playing a sound as you go into the background, but you cannot spontaneously produce a sound out of the blue in an already backgrounded app. It would be terrible if this could happen, because the user would not know where the sound is coming from, the sound could mess up the user's music listening experience, etc.
You should ask yourself why you think you need to do such a thing in the first place. You probably don't need to.
(Some Apple apps can do it. For example, the Clock app produces a repeating alarm sound out of the blue, in the background. But you, as you have probably noticed by now, are not Apple.)
I'm trying to play a sound when a button is clicked. First, I imported the AudioToolbox in the header file, then added the code into the IBAction that fires when the button is pressed, like so:
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)button1:(id)sender {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"mySong" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundPath], &soundID);
AudioServicesPlaySystemSound (soundID);
}
I even threw an NSLog in the method to make sure it's firing. It is. I also but in a foo path in the string to see if it would crash, it did. I made sure that I dragged and dropped the short sound file into the app as well. Tested my speakers, tested audio on the device simulator by going to youtube on the simulator, everything. I can't figure out what I'm doing wrong.
When I changed the code to this:
- (IBAction)button1:(id)sender {
AVAudioPlayer *testAudioPlayer;
// *** Implementation... ***
// Load the audio data
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"3" ofType:#"wav"];
NSData *sampleData = [[NSData alloc] initWithContentsOfFile:soundFilePath];
NSError *audioError = nil;
// Set up the audio player
testAudioPlayer = [[AVAudioPlayer alloc] initWithData:sampleData error:&audioError];
if(audioError != nil) {
NSLog(#"An audio error occurred: \"%#\"", audioError);
}
else {
[testAudioPlayer setNumberOfLoops: -1];
[testAudioPlayer play];
}}
I get the error: WARNING: 137: Error '!dat' trying to set the (null) audio devices' sample rate
Hi as per you question can you please check whether you audio file is present in you project folder.It might happen that u have forgotten to checkmark "copy item if needed" so it might not be there in your project file.
You can also play sounds provided in device. Visit the below link it will be helpful.
https://github.com/TUNER88/iOSSystemSoundsLibrary
I've tested your code and it working fine and not getting crashed. Here's what I did.
As said in #matt's comment, sound playback fails in the Simulator. I had this problem when trying to play back a video.
The funny part is that sound plays just fine for the same video inside the Photos app.
I'm developing an app that plays sounds using AVAudioPlayer, and I want to know when a sound has finished playing. I want to change an image when the sound stops playing
Here's the code I use to create the player:
NSURL* url = [[NSBundle mainBundle] URLForResource:#"LOLManFace1" withExtension:#"mp3"];
NSAssert(url, #"URL is valid.");
NSError* error = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&url];error;
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}
And here's the code I use to play the sound:
[self.player play];
How can I tell that playback has finished?
Thank you so much in advance!
Look at the AVAudioPlayerDelegate protocol which has a method to tell the delegate when audio playback has finished among other things, specifically what you are looking for is - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag, here is a reference
Hope it helps
Daniel
Long time ago and I am pretty sure you figured out at one point. If someone reads this post:
1) Your class should implement the AVAudioPlayerDelegate. (https://developer.apple.com/documentation/avfoundation/avaudioplayerdelegate)
One of the delegate methods is:
audioPlayerDidFinishPlaying:successfully:
2) Set delegate:
self.player.delegate = self
I'm using AVAudioPlayer from iOS SDK for playing short sounds on each click in tableView rows.
I have manually made #selector on button in each row that fires up method playSound:(id)receiver {}. From receiver I get sound url so I can play it up.
This method looks like that:
- (void)playSound:(id)sender {
[audioPlayer prepareToPlay];
UIButton *audioButton = (UIButton *)sender;
[audioButton setImage:[UIImage imageNamed:#"sound_preview.png"] forState:UIControlStateNormal];
NSString *soundUrl = [[listOfItems objectForKey:[NSString stringWithFormat:#"%i",currentPlayingIndex]] objectForKey:#"sound_url"];
//here I get mp3 file from http url via NSRequest in NSData
NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:&error];
audioPlayer.numberOfLoops = 0;
if (error) {
NSLog(#"Error: %#",[error description]);
}
else {
audioPlayer.delegate = self;
[audioPlayer play];
}
}
Everything works fine except for the first play of some sound. The application freezes for about 2 seconds and than sound is played. Second and every other sound play works just right after click on sound button.
I wonder why there is that about 2 seconds freeze on first play when application starts?
From your code snippet, audioPlayer must be an ivar, right?
At the top of the method, you invoke -prepareToPlay on the existing audioPlayer instance (which could be nil, at least on the first pass).
Later in the method, you replace this existing audio player with a brand new AVAudioPlayer instance. The previous -prepareToPlay is wasted. And you're leaking memory with each new AVAudioPlayer.
Instead of caching sound data or URLs, I would try creating a cache of AVAudioPlayer objects, one for each sound. In your -playSound: method, get a reference to the appropriate audio player for the table row, and -play.
You can use -tableView:cellForRowAtIndexPath: as the appropriate point to get the AVAudioPlayer instance for that row, maybe lazily creating the instance and caching it there as well.
You can try -tableView:willDisplayCell:forRowAtIndexPath: as the point where you would invoke -prepareToPlay on the row's AVAudioPlayer instance.
Or you could just do the prepare in -tableView:cellForRowAtIndexPath:. Experiment and see which works best.
Check whether you are getting data asynchronously in function..
NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];
If you are getting asynchronously the execution will be blocked until it will get data.
If your audio is less than 30 seconds long in length and is in linear PCM or IMA4 format, and is packaged as a .caf, .wav, or .aiff you can use system sounds:
Import the AudioToolbox Framework
In your .h file create this variable:
SystemSoundID mySound;
In your .m file implement it in your init method:
-(id)init{
if (self) {
//Get path of VICTORY.WAV <-- the sound file in your bundle
NSString* soundPath = [[NSBundle mainBundle] pathForResource:#"VICTORY" ofType:#"WAV"];
//If the file is in the bundle
if (soundPath) {
//Create a file URL with this path
NSURL* soundURL = [NSURL fileURLWithPath:soundPath];
//Register sound file located at that URL as a system sound
OSStatus err = AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &mySound);
if (err != kAudioServicesNoError) {
NSLog(#"Could not load %#, error code: %ld", soundURL, err);
}
}
}
return self;
}
In your IBAction method you call the sound with this:
AudioServicesPlaySystemSound(mySound);
This works for me, plays the sound pretty damn close to when the button is pressed. Hope this helps you.
This sometimes happens in the simulator for me too. Everything seems to work fine on the device. Have you tested on actual hardware?