2

I have an AVQueuePlayer that is used to play a list of MP3 songs from the internet (http). I need to also know which song is currently playing. The current problem is that loading the song causes a delay that blocks the main thread while waiting for the song to load (first song as well as sequential songs after the first has completed playback).

The following code blocks the main thread:

queuePlayer = [[AVQueuePlayer alloc] init];
[queuePlayer insertItem: [AVPlayerItem playerItemWithURL:url] afterItem: nil]; // etc.
[queuePlayer play]

I am looking for a way to create a playlist of MP3s where the next file to be played back is preloaded in the background.

I tried the following code:

NSArray* tracks = [NSArray arrayWithObjects:@"http://example.com/song1.mp3", @"http://example.com/song2.mp3", @"http://example.com/song3.mp3", nil];

for (NSString* trackName in tracks)
{
    AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:[NSURL URLWithString:trackName]
                                                    options:nil];

    AVMutableCompositionTrack* audioTrack = [_composition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                      preferredTrackID:kCMPersistentTrackID_Invalid];

    NSError* error;
    [audioTrack insertTimeRange:CMTimeRangeMake([_composition duration], audioAsset.duration)
                        ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0]
                         atTime:kCMTimeZero
                          error:&error];

    if (error)
    {
        NSLog(@"%@", [error localizedDescription]);
    }

    // Store the track IDs as track name -> track ID
    [_audioMixTrackIDs setValue:[NSNumber numberWithInteger:audioTrack.trackID]
                         forKey:trackName];

}

_player = [[AVPlayer alloc] initWithPlayerItem:playerItem];

[_player play];

The issue with this is that I am not sure how to detect when the next song starts playing. Also, the docs don't specify whether or not this will pre-load MP3 files or not.

I am looking for a solution that:

  • Plays MP3s by pre-loading them in the background prior to playback (ideally start loading the next song before the current song finishes, so it is ready for immediate playback once the current song finishes)
  • Allow me to view the current song playing.
Hope4You
  • 1,927
  • 4
  • 21
  • 45

1 Answers1

1

AVFoundation has some classes designed to do exactly what you're looking for.

It looks like your current solution is to build a single AVPlayerItem that concatenates all of the MP3 files that you want to play. A better solution is to create an AVQueuePlayer with an array of the AVPlayerItem objects that you want to play.

NSArray* tracks = [NSArray arrayWithObjects:@"http://example.com/song1.mp3", @"http://example.com/song2.mp3", @"http://example.com/song3.mp3", nil];
NSMutableArray *playerItems = [[NSMutableArray alloc] init];

for (NSString* trackName in tracks)
{
    NSURL *assetURL = [NSURL URLWithString:trackName];
    if (!assetURL) {
        continue;
    }

    AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:assetURL
                                                     options:nil];
    AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithAsset:audioAsset];
    [playerItems addObject:playerItem];
}

_player = [[AVQueuePlayer alloc] initWithItems:playerItems];

[_player play];

In answer to your final wrap-up questions:

  • Yes, AVQueuePlayer DOES preload the next item in the playlist while it's playing the current one.
  • You can access the currentItem property to determine which AVPlayerItem is currently playing.
Dave Weston
  • 6,527
  • 1
  • 29
  • 44
  • 1
    I have tried using AVQueuePlayer as well. The first MP3 file does not load in a background thread, if I understand correctly. How would you recommend pre-loading the first MP3 in a background thread, and then letting the main thread know when it is finished loading? – Hope4You Jan 31 '17 at 00:18