AvAudioPlayer memory leaks? - iphone

Im doing an application that needs to play alot of short sounds (mp3-files). Im using AvAudioPlayer and the sounds are playing just fine, BUT the leaks are building up until my app crashes.
I have a seperate class for the player
AVSnd.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface AVSoundPlayer : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *msoundPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *msoundPlayer;
-(id)initWithMp3File: (NSString *)inString;
-(void) playNum:(int)num;
#end
AVSND.m
#implementation AVSoundPlayer
#synthesize msoundPlayer;
-(id)initWithMp3File: (NSString *)fileName{
if (self = [super init]){
NSBundle *mainBundle = [NSBundle mainBundle];
NSError *error;
NSURL *sURL = [NSURL fileURLWithPath:[mainBundle
pathForResource:fileName ofType:#"mp3"]];
self.msoundPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:sURL error:&error];
if (!self.msoundPlayer) {
NSLog(#"Sound player problem: %#", [error localizedDescription]);
}
}
return self;
}
-(void) playNum:(int)num{
self.msoundPlayer.numberOfLoops = num;
[self.msoundPlayer prepareToPlay];
AVAudioPlayer *tmpPlayer = self.msoundPlayer;
[tmpPlayer play];
}
- (void)dealloc {
[self.msoundPlayer release];
[super dealloc];
}
#end
Then I make an instance of this object in the views i want sound.
in .h files I add following lines:
#class AVSnd;
AVSnd *mPlayer;
#property (nonatomic, retain) AVSnd *mPlayer;
and in .m files i use:
#synthezise mPlayer;
[self.mPlayer initWithMp3File:#"soundFileName"];
[self.mPlayer playNum:1];
[self.mPlayer release];
But why do I get memory-leaks every time i play a sound? Should i implement the player in another way?
Thank you so much for any help!

I had the same problem and solved it with autorelease:
self.audioPlayer = [[[AVAudioPlayer alloc]
initWithContentsOfURL:url error:&error] autorelease];

self.msoundPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:sURL error:&error];
Here you are retaining the object twice, in self. (because of the property), and when alloc. It could be the reason.

Related

ios AVAudioPlayer plays sound with echo

I have two AVAudioPlayer to determine what sound has finished to do something after that. the first sound plays just fine but the second sound (twoPlayer) plays the sound with echo. any of you knows why or how this happend?
I have this on my .h file:
#interface myClass : UIViewController<AVAudioPlayerDelegate>
{
AVAudioPlayer *onePlayer;
AVAudioPlayer *twoPlayer;
}
#property (retain, nonatomic) AVAudioPlayer *onePlayer;
#property (retain, nonatomic) AVAudioPlayer *twoPlayer;
.m file:
NSString *urlAddress = [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"m4a"];
NSURL *url = [NSURL fileURLWithPath:urlAddress];
NSError *error;
twoPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
twoPlayer.delegate=self;
twoPlayer.volume=0.5;
if (twoPlayer == nil)
NSLog(#"[error description]");
else
[twoPlayer play];
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if (player==onePlayer) {
[onePlayer release];
}
if (player==twoPlayer) {
[numberPlayer release];
}
}
I found the error I was setting a UIButton with "forControlEvents:UIControlEventAllTouchEvents" and the actionw was been trigger more then once. I replace the UIButton with this forControlEvents:UIControlEventTouchDown and works just fine.

AVAudioPlayerDelegate method doesn't seem to work

I'm simply trying to do something when an audio file has finished playing, but it doesn't seem to work.
In my .h file I've got this:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreAudio/CoreAudioTypes.h>
#interface soundViewController : UIViewController
<AVAudioPlayerDelegate>
{
//various outlets
}
#property (strong, nonatomic) AVAudioPlayer *audioPlayer;
#end
And in the .m file I've got:
#import "soundViewController.h"
#interface soundViewController ()
#end
#implementation soundViewController
#synthesize audioPlayer;
And the method's:
- (void) playWord{
Word *currentWord = [[Word alloc]init];
currentWord = [testWords objectAtIndex:wordNum-1];
NSString *item = [currentWord word];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#.mp3", [[NSBundle mainBundle] resourcePath], item]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
if (audioPlayer == nil){
NSLog(#"error in audioPlayer");
}
else{
[audioPlayer play];
NSLog(#"Playing word");
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
if (flag==YES){
NSLog(#"Finished!");
}
}
So... it all works swimmingly (apart from the fact that the sound file won't work if it starts with a capital letter), but why am I not seeing the log message "Finished" when the sound finishes?
Thanks for your help,
Morten
You actually need to set the delegate of the player after you instantiate it, like:
audioPlayer.delegate = self;
Hope this helps!

audioPlayerDidFinishPlaying never triggers

I created a custom class to handle audio playback.
AudioPlayback.h
#import <Foundation/Foundation.h>
#import "AVFoundation/AVAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#interface AudioPlayback : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
BOOL playing;
NSTimeInterval duration;
}
#property (nonatomic, assign) AVAudioPlayer *player;
#property (readonly) BOOL playing;
#property (readonly) NSTimeInterval duration;
-(NSTimeInterval)GetSoundFileDuration:(NSString *) sound_file_name;
-(void)PlaySoundFile:(NSString *) sound_file_name;
-(void)play;
-(void)stop;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
#end
Then, in AudioPlayback.h
#import "AudioPlayback.h"
#implementation AudioPlayback
#synthesize player;
-(id)init
{
self = [super init];
if (self != nil)
{
player = [[AVAudioPlayer alloc] init];
[player initWithContentsOfURL:nil error:nil];
player.delegate = self;
}
return self;
}
-(void)PlaySoundFile:(NSString *) sound_file_name
{
NSURL *sound_file = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:sound_file_name ofType:#"mp3"]];
[player initWithContentsOfURL:sound_file error:nil];
[player prepareToPlay];
[player play];
[sound_file release];
}
...
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"audioPlayerDidFinishPlaying");
}
The callback never triggers. Am I missing anything obvious?
I think "player.delegate = self" is call too early. You "initWithContentsOfURL" again in your "PlaySoundFile", which I think that cause the problem.
Try to put "player.delegate = self" before the "[player prepareToPlay]" in your "PlaySoundFile" method

How do you make an iPhone beep?

What code allows me to produce a standard beep sound on the iPhone?
Well it depends on what kind of sound you want.
Here's how to play a sound using the AVFoundation audio framework.
#import <UIKit/UIKit.h>
#class AVAudioPlayer;
#interface AudioPlayer : UIViewController {
IBOutlet UIButton *playButton;
IBOutlet UIButton *stopButton;
AVAudioPlayer *audioPlayer;
}
#property (nonatomic, retain) IBOutlet UIButton *playButton;
#property (nonatomic, retain) IBOutlet UIButton *stopButton;
#property (nonatomic, retain) AVAudioPlayer *audioPlayer;
-(IBAction)play;
-(IBAction)stop;
#end
- (void)viewDidLoad {
[super viewDidLoad];
// Get the file path to the song to play.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"TNG_Theme"
ofType:#"mp3"];
// Convert the file path to a URL.
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filePath];
//Initialize the AVAudioPlayer.
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:fileURL error:nil];
// Preloads the buffer and prepares the audio for playing.
[self.audioPlayer prepareToPlay];
[filePath release];
[fileURL release];
}
-(IBAction)play {
// Make sure the audio is at the start of the stream.
self.audioPlayer.currentTime = 0;
[self.audioPlayer play];
}
-(IBAction)stop {
[self.audioPlayer stop];
}
AudioServicesPlaySystemSound is one thing you can do for a simple sound.

Do an action when a sound has finished playing in AVAudioPlayer?

I am using the AVAudioPlayer framework, and I have several sounds that play one at a time. When a sound is finished playing, I want the application to do something. I tried to use audioPlayerDidFinishPlaying to do the action at the end of the first sound, but I couldn't use that for the second sound because I got a redefinition error. Can I use NSTimeInterval to get the duration of a sound?
// ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface ViewController : UIViewController {
UIButton *begin;
UIWindow *firstTestWindow;
UIWindow *secondTestWindow;
AVAudioPlayer *player;
NSTimeInterval duration;
}
#property (nonatomic, retain) IBOutlet UIButton *begin;
#property (nonatomic, retain) IBOutlet UIWindow *firstTestWindow;
#property (nonatomic, retain) IBOutlet UIWindow *secondTestWindow;
#property (nonatomic, retain) AVAudioPlayer *player;
#property (readonly) NSTimeInterval duration;
- (IBAction)begin:(id)sender;
- (IBAction)doTapScreen:(id)sender;
#end
//ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize begin, player, firstTestWindow, secondTestWindow;
//first sound
- (IBAction)begin:(id)sender; {
[firstTestWindow makeKeyAndVisible];
NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource: #"Tone1"
ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
AVAudioPlayer *newPlayer =
[[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: nil];
[fileURL release];
self.player = newPlayer;
[newPlayer release];
[player prepareToPlay];
[self.player play];
}
//If user does not do anything by the end of the sound go to secondWindow
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player
successfully: (BOOL) flag {
if (flag==YES) {
[secondWindow makeKeyAndVisible];
}
}
//second sound
- (IBAction)doTapScreen:(id)sender {
//When user touches the screen, either play the sound or go to the next window
if (self.player.playing) {
[self.player stop];
[thirdWindow makeKeyAndVisible];
}
else {
NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource: #"Tone2"
ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
AVAudioPlayer *newPlayer =
[[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: nil];
[fileURL release];
self.player = newPlayer;
[newPlayer release];
[player prepareToPlay];
[self.player play];
}
}
When a sound is finished playing, I want the application to do something.
Then set yourself as the delegate and respond to audioPlayerDidFinishPlaying:successfully:.
In the code snippet you showed, you've done step 2 but not step 1: You're not setting yourself as the delegate.
I tried to use applicationDidFinishLaunching to do the action at the end of the first sound …
Brain fart? That method has nothing that I can see to do with playing sounds.
…, but I couldn't use that for the second sound because I got a redefinition error.
Huh? Did you implement the method twice or something instead of just comparing the player object in the method body?
It would help if you showed the exact error message you got.
Swift 3:
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("sound file finished")
}