10

I have 5 songs in my app that I would like to play one after the other with AVAudioPlayer.

Are there any examples of this? How can I accomplish this?

Any example code would be greatly appreciated!

Thanks!

dot
  • 2,823
  • 7
  • 38
  • 52

4 Answers4

15

AVQueuePlayer work for this situation.

AVQueuePlayer is a subclass of AVPlayer you use to play a number of items in sequence.

Ken
  • 1,141
  • 12
  • 12
9

Instead of AVAudioPlayer you can use AVQueuePlayer which suits this use case better as suggested by Ken. Here is a bit of code you can use:

@interface AVSound : NSObject 

@property (nonatomic, retain) AVQueuePlayer* queuePlayer;

- (void)addToPlaylist:(NSString*)pathForResource ofType:(NSString*)ofType;
- (void)playQueue;

@end

@implementation AVSound
- (void)addToPlaylist:(NSString*)pathForResource ofType:(NSString*)ofType
{
    // Path to the audio file
    NSString *path = [[NSBundle mainBundle] pathForResource:pathForResource ofType:ofType];

    // If we can access the file...
    if ([[NSFileManager defaultManager] fileExistsAtPath:path])
    {

        AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:path]];

        if (_queuePlayer == nil) {
            _queuePlayer = [[AVQueuePlayer alloc] initWithPlayerItem:item];
        }else{
            [_queuePlayer insertItem:item afterItem:nil];
        }
    }

}


- (void)playQueue
{
    [_queuePlayer play];
}
@end

Then to use it: In your interface file:

@property (strong, nonatomic) AVSound *pageSound;

In your implementation file:

- (void)addAudio:(Book*)book pageNum:(int)pageNum
{

    NSString *soundFileEven = [NSString stringWithFormat:@"%02d", pageNum-1];
    NSString *soundPathEven = [NSString stringWithFormat:@"%@_%@", book.productId,     soundFileEven];
    NSString *soundFileOdd = [NSString stringWithFormat:@"%02d", pageNum];
    NSString *soundPathOdd = [NSString stringWithFormat:@"%@_%@", book.productId, soundFileOdd];

    if (_pageSound == nil) {
        _pageSound = [[AVSound alloc]init];
        _pageSound.player.volume = 0.5;
    }

    [_pageSound clearQueue];

    [_pageSound addToPlaylist:soundPathEven ofType:@"mp3"];
    [_pageSound addToPlaylist:soundPathOdd ofType:@"mp3"];
    [_pageSound playQueue];
}

HTH

Nathan Noble
  • 806
  • 7
  • 14
1

For every song you want to make make a single AVPlayer.

NSURL *url = [NSURL URLWithString:pathToYourFile];
AVPlayer *audioPlayer = [[AVPlayer alloc] initWithURL:url];
[audioPlayer play];

You can get a Notification when the player ends. Check AVPlayerItemDidPlayToEndTimeNotification when setting up the player:

  audioPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(playerItemDidReachEnd:)
                                               name:AVPlayerItemDidPlayToEndTimeNotification
                                             object:[audioPlayer currentItem]];

this will prevent the player to pause at the end.

in the notification:

- (void)playerItemDidReachEnd:(NSNotification *)notification
{
    // start your next song here
}

You can start your next song as soon as you get a notification that the current playing song is done. Maintain some counter which is persistent across selector calls. That way using counter % [songs count] will give you an infinite looping playlist :)

Don't forget un unregister the notification when releasing the player.

Srikar Appalaraju
  • 71,928
  • 54
  • 216
  • 264
1

Unfortunately, AVAudioPlayer can only play one file. To play two files, you have to kill the first instance of the AVAudioPlayer and recreate it a second time (it can be initiated using - (id)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError). The problem with this approach is that there is a slight delay between when the first file finishes playing and when the second file starts playing. If you want to get rid of this delay you have to dig into Core Audio and come up with a much more complex solution.

Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
  • i think there is a way. check out my answer. `AVPlayer` has a notification selector which tells us when a currently playing song is over. That way we can play our next song as soon as current is done. That could work. – Srikar Appalaraju Nov 12 '11 at 03:16
  • I actually made a radio app for the iPhone and iPad. I know as of iOS 4.2 there was still a delay when trying to play two files in a row using AVAudioPlayer. I even tried to prep a separate AVAudioPlayer using the `prepareToPlay` method and have the second one start playing as soon as the first one was done, but there was still a slight delay. If you don't mind a slight delay between the sounds it's no big deal, but if you want completely continuous playback between the two files I don't think AVAudioPlayer is the way to go. – Michael Frederick Nov 12 '11 at 03:25
  • cant imagine having a noticeable gap when trying to use notification unless the audio file itself has white noise or some blank noise at the end. That way `AVAudioPlayer` would still play but the user thinks there is gap. Still curious to know why this is so... – Srikar Appalaraju Nov 12 '11 at 03:33
  • the gap comes from the AVAudioPlayer prepping to play the audio file – Michael Frederick Nov 12 '11 at 03:45