Play audio with controls in iOS

I made an application with tab bar,nav bar and table view .

In the table view, you can choose to listen to some sound.

A new view will appear, and I have some controls, such as: play, pause, volume slider, progress slider, label with the current time.

It works, but not perfect. I can play the sound, I can pause the sound, I can also use the slider to scroll forward or backward. But now:

When I press the back button on the navigation bar, the song continues to play. This is normal, but when I return to viewing again, the timer and slider reset themselves. I can not pause the song, just need to wait until it stops playing.

In addition, when I click on the game, return to the table view, select another file to play, the first file will not stop playback .

Here is the Audio1DetailViewController.h code:

  #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface Audio1DetailViewController: UIViewController <AVAudioPlayerDelegate> { IBOutlet UISlider *volumeControl; IBOutlet UILabel *timerLabel; IBOutlet UISlider *progressBar; AVAudioPlayer *audioPlayer; NSTimer *playbackTimer; } @property (nonatomic, retain) IBOutlet UISlider *volumeControl; @property (nonatomic, retain) IBOutlet UILabel *timerLabel; @property (nonatomic, retain) IBOutlet UISlider *progressBar; @property (nonatomic, retain) NSTimer *playbackTimer; @property (nonatomic, retain) AVAudioPlayer *audioPlayer; -(IBAction) playAudio; -(IBAction) stopAudio; -(IBAction) adjustVolume; -(IBAction) sliderChanged; @end 

Here is the Audio1DetailViewController.m code:

  #import "Audio1DetailViewController.h" @implementation Audio1DetailViewController @synthesize volumeControl, timerLabel, playbackTimer, progressBar, audioPlayer; -(void)playAudio { playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime) userInfo:nil repeats:YES]; [audioPlayer play]; } -(void)stopAudio { [playbackTimer invalidate]; [audioPlayer stop]; } -(void)adjustVolume { if (audioPlayer != nil) { audioPlayer.volume = volumeControl.value; } } -(void)updateTime { float minutes = floor(audioPlayer.currentTime/60); float seconds = audioPlayer.currentTime - (minutes * 60); float duration_minutes = floor(audioPlayer.duration/60); float duration_seconds = audioPlayer.duration - (duration_minutes * 60); NSString *timeInfoString = [[NSString alloc] initWithFormat:@"%0.0f.%0.0f / %0.0f.%0.0f", minutes, seconds, duration_minutes, duration_seconds]; timerLabel.text = timeInfoString; [timeInfoString release]; } - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"001Fatiha" ofType:@"MP3"]]; NSError *error; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [[AVAudioSession sharedInstance] setActive: YES error: nil]; if (error) { NSLog(@"Error in audioPlayer: %@", [error localizedDescription]); } else { audioPlayer.delegate = self; [audioPlayer prepareToPlay]; } playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES]; progressBar.maximumValue = audioPlayer.duration; // Set the valueChanged target [progressBar addTarget:self action:@selector(sliderChanged:) forControlEvents: UIControl EventValueChanged]; } - (void)updateSlider { // Update the slider about the music time progressBar.value = audioPlayer.currentTime; } - (IBAction)sliderChanged:(UISlider *)sender { // Fast skip the music when user scroll the UISlider [audioPlayer stop]; [audioPlayer setCurrentTime:progressBar.value]; [audioPlayer prepareToPlay]; [audioPlayer play]; } -(void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully:(BOOL)flag { } -(void)audioPlayerDecodeErrorDidOccur: (AVAudioPlayer *)player error:(NSError *)error { } -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player { } -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player { } -(void)viewDidUnload { audioPlayer = nil; volumeControl = nil; } -(void)dealloc { [audioPlayer release]; [volumeControl release]; [playbackTimer release]; [super dealloc]; } @end 

Here is AudioTableViewController.h

  #import <UIKit/UIKit.h> @class Audio1DetailViewController; @interface AudioTableViewController : UITableViewController <UITableViewDelegate,UITableViewDataSource>{ IBOutlet UITableView *audioTableView; NSMutableArray *audioArray; Audio1DetailViewController *audio1DetailViewController; } @property (nonatomic, retain) NSMutableArray *audioArray; @property (nonatomic, retain) Audio1DetailViewController *audio1DetailViewController; @end 

And AudioTableViewController.m

  #import "AudioTableViewController.h" #import "Audio1DetailViewController.h" #import "DEQAppDelegate.h" @implementation AudioTableViewController @synthesize audioArray; @synthesize audio1DetailViewController; - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization { return self; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle - (void)viewDidLoad{ [super viewDidLoad]; self.title = NSLocalizedString(@"Audio", @"Audio"); self.audioArray = [[NSArray alloc] initWithObjects: @"1. Het Begin", @"2. De Mensen", //etcetera nil]; // Uncomment the following line to preserve selection between presentations. self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. self.audioArray = nil; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait); } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete method implementation. // Return the number of rows in the section. return [self.audioArray count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier] autorelease]; } // Configure the cell... cell.textLabel.text = [self.audioArray objectAtIndex:[indexPath row]]; return cell; } #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here. Create and push another view controller. NSUInteger row = indexPath.row; if (row == 0) { Audio1DetailViewController *audio1DetailViewController =[[Audio1DetailViewController alloc] initWithNibName:@"Audio1DetailViewController" bundle:nil]; audio1DetailViewController.title = @"Audio"; [self.navigationController pushViewController:audio1DetailViewController animated:YES]; [audio1DetailViewController release]; } if (row == 1) { //etcetera } } - (void)dealloc{ [audioArray release]; [super dealloc]; } @end 
+7
source share
3 answers

I would suggest creating a global player object. Because right now, every time you click this view on the navigation controller, you are creating a new one. It also means that you do not have a link to the previous player (and he cannot stop him). So: declare AVAudioPlayer one step higher (in the table). Now, when you select a row in it, assign it the property of this new view (the one you linked to).

Do you work with storyboards? Then you must implement the prepareForSegue: method. Give your segue on the storyboard an identifier (for example, showPlayer and verify this with if (segue.identifier isEqualToString:@"showPlayer") ).

Now in your viewDidLoad check if the audioPlayer is zero. If you

 - (void)viewDidLoad { [super viewDidLoad]; if (audioPlayer == nil) { // your init (audioplayer =[[AVAudioPlayer ... } else { if (audioPlayer.isPlaying) { // ie pause the player or do other stuff } } } 

Hope this helps you.

Also . Do not post images with code. Just paste the code into your answer or post it on a site like pastebin.com and put this page together in your question. This makes it easier for others to respond and make suggestions for code changes.

In response to your comment : Relevant material should be: In AudioTableViewController.h:

 @property (strong, nonatomic) AVAudioPlayer *audioPlayer; 

In AudioTableViewController.m:

 @synthesize audioPlayer; ... - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic may go here. Create and push another view controller. NSUInteger row = indexPath.row; if (row == 0) { self.audio1DetailViewController =[[Audio1DetailViewController alloc] initWithNibName:@"Audio1DetailViewController" bundle:nil]; self.audio1DetailViewController.title = @"Audio"; self.audio1DetailViewController.audioPlayer = self.audioPlayer; [self.navigationController pushViewController:self.audio1DetailViewController animated:YES]; [self.audio1DetailViewController release]; ... 

Audio1DetailViewController.m

 - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"001Fatiha" ofType:@"MP3"]]; NSError *error; // this is the important part: if we already have something playing, stop it! if (audioPlayer != nil) { [audioPlayer stop]; } // everything else should happen as normal. audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [[AVAudioSession sharedInstance] setActive: YES error: nil]; 
+9
source

To stop playing two songs at the same time, you must do this:

 - (void)viewWillDisappear:(BOOL)animated { audioPlayer = nil; volumeControl = nil; } 

for additional help when playing sound, you can use the sample Apple code:

http://developer.apple.com/library/ios/#samplecode/avTouch/Introduction/Intro.html

+4
source

Surprisingly, MPMoviePlayerController also plays an MP3 player with controls !!!

 self.moviePlayer=[[MPMoviePlayerController alloc] initWithContentURL:url]; [self.moviePlayer.view setFrame:CGRectMake(0, 0, self.videoContainer.bounds.size.width, self.videoContainer.bounds.size.height)]; self.moviePlayer.controlStyle=MPMovieControlStyleDefault; [self.videoContainer addSubview:self.moviePlayer.view]; [self.moviePlayer prepareToPlay]; [self.moviePlayer play]; 
+1
source

All Articles