Preload streaming with avplayer/avaudioplayer - ios

I have a problem with avplayer/avaudioplayer. I'm using these classes for streaming aac or pls audio content (radio).
I would like to preload specified time od content and play streaming with delay, for example 20 seconds. it occurs that when I turn on, for example, airplane mode and network is lost, player should play from this moment 20 seconds while it stops.
I use this code for mp4 from network and it seems to works but when i change this for aac/pls streaming...it's loading and everything seems to work but when I turn on airplane mode, it stops immidiately...
is it possible to keep in buffer content and play with delay with streaming?
My code:
#interface AVFViewController ()
{
AVPlayer *player;
PlayerView *playerView;
id t
imeObserver;
NSInteger _playing;
}
#end
#implementation AVFViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self playURL:[NSURL URLWithString:#"http://nba.cdn.turner.com/nba/big/channels/top_plays/2012/02/03/20120203_top10.nba_nba_ipad.mp4"]];
//http://acdn.smcloud.net/t042-1_mp3.pls
//http://nba.cdn.turner.com/nba/big/channels/top_plays/2012/02/03/20120203_top10.nba_nba_ipad.mp4
}
- (void)playURL:(NSURL *)videoURL
{
if (!player) {
player = [[AVPlayer alloc] init];
playerView = [[PlayerView alloc] init];
[playerView setPlayer:player];
playerView.frame = CGRectInset(self.view.bounds, 20, 20);
playerView.backgroundColor = [UIColor greenColor];
playerView.alpha = 1;
[self.view addSubview:playerView];
[player addObserver:self forKeyPath:#"currentItem.loadedTimeRanges" options:NSKeyValueObservingOptionNew context:kTimeRangesKVO];
}
[player replaceCurrentItemWithPlayerItem:[[AVPlayerItem alloc] initWithURL:videoURL]];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (kTimeRangesKVO == context) {
NSArray *timeRanges = (NSArray *)[change objectForKey:NSKeyValueChangeNewKey];
if (timeRanges && [timeRanges count]) {
NSArray *loadedTimeRanges = [[player currentItem] loadedTimeRanges];
CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;
NSLog(#"duration is %f",result);
if (!_playing && result > 20) {
[player.currentItem seekToTime:CMTimeMakeWithSeconds(0, 1)];
[player play];
_playing = 1;
}
}
}
}
#end

Related

iOS get audio duration from avplayer

I'm new to ios, i have an app which contain online audio player. i need to get total duration for the audio. i have tried lot but all codes returns NaN or 0 duration. What is the best way to get total duration for the audio..?
MY CODE
NSString *songUrl = #"http://9xmusiq.com/songs2/tamil/Kaatru%20Veliyidai/Azhagiye%20%5bStarmusiq.cc%5d.mp3"
AVURLAsset *asset = [AVURLAsset assetWithURL:[NSURL URLWithString:songUrl]];
AVPlayerItem *playerItem1 = [AVPlayerItem playerItemWithAsset:asset];
AVPlayer *player1 = [AVPlayer playerWithPlayerItem:playerItem1];
AVPlayerLayer *playerLayer1 = [AVPlayerLayer playerLayerWithPlayer:player1];
playerLayer1.videoGravity = AVLayerVideoGravityResizeAspectFill;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
playerLayer1.frame = self.view.frame;
});
[self.view.layer insertSublayer:playerLayer1 atIndex:1];
[player1 play];
[playerItem1 addObserver:self forKeyPath:#"status" options:0 context:nil];
[playerItem1 addObserver:self forKeyPath:#"playbackBufferEmpty" options:0 context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([object isKindOfClass:[AVPlayerItem class]]){
AVPlayerItem *item = (AVPlayerItem *)object;
if ([keyPath isEqualToString:#"status"]){
switch(item.status){
case AVPlayerItemStatusFailed:
NSLog(#"player item status failed");
break;
case AVPlayerItemStatusReadyToPlay:
NSLog(#"player item status is ready to play");
Float64 duration = CMTimeGetSeconds(self.avPlayer.currentItem.duration);
NSLog(#"Duration--> %f",duration) // NaN returns
break;
case AVPlayerItemStatusUnknown:
NSLog(#"player item status is unknown");
break;
}
}else if ([keyPath isEqualToString:#"playbackBufferEmpty"]){
if (item.playbackBufferEmpty){
NSLog(#"player item playback buffer is empty");
}
}
}
}
Thanks for your support friends, Finally i find the solution for my problem instead of using AVPlayer i used AVAudioPlayer and i fixed the problem and i got the audio duration.
NSString* resourcePath = #"http://9xmusiq.com/songs2/tamil/Kaatru%20Veliyidai/Azhagiye%20%5bStarmusiq.cc%5d.mp3"; //your url
NSData *_objectData = [NSData dataWithContentsOfURL:[NSURL URLWithString:resourcePath]];
NSError *error;
AVAudioPlayer *player1 = [[AVAudioPlayer alloc] initWithData:_objectData error:&error];
player1.numberOfLoops = 0;
player1.volume = 1.0f;
[player1 prepareToPlay];
NSLog(#"Total Duration : %f",player1.duration);
if (player1 == nil){
NSLog(#"%#", [error description]);
}else{
[player1 play];
}
I'm not that familiar with AVPlayer, but in digging around in the docs it looks like the AVAsset (or in your case AVURLAsset) is the object that holds a duration.
Try querying the asset:
AVURLAsset *asset = [AVURLAsset assetWithURL:[NSURL
URLWithString:songUrl]];
CMTime durationCMTime = asset.duration;
Float64 duration =
CMTimeGetSeconds(durationCMTime);
NSLog(#"Duration of asset is %f", duration);
When your AVPlayer ready to play (under the case of AVPlayerItemStatusReadyToPlay), you can use
CMTime duration = self.player.currentItem.asset.duration;
float seconds = CMTimeGetSeconds(duration);
You can access the duration of an AVPlayerItem's asset using duration property. If you need precise seconds with decimals, use Float64 to receive time from CMTimeGetSeconds. For regular use cases, I guess int would be sufficient.
CMTime duration = playerItem1.asset.duration;
int durationTotalSeconds = CMTimeGetSeconds(duration);
int durationHours = floor(durationTotalSeconds / 3600);
int durationMinutes = floor(durationTotalSeconds % 3600 / 60);
int durationSeconds = floor(durationTotalSeconds % 3600 % 60);
NSString *audioDurationString = [NSString stringWithFormat:#"%d:%d:%d",durationHours, durationMinutes, durationSeconds];
you can get duration - (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
#property(nonatomic,strong) AVPlayer *player;
#property(nonatomic,strong) id obsever;
self.player = [[AVPlayer alloc]initWithURL:URL];
[self.player play];
self.obsever = [self.player addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {//you can get duration in block
CMTimeGetSeconds(theItem.currentTime);
CMTimeGetSeconds(theItem.duration)
}];

AVPlayer crashes after multiple time play video from local directory

When i click my local video url and present Viewcontroller and Play video in AVPlayer.Play 14-15 times and Player crash.Avplayer showing like
- (void)viewDidLoad
{
[self PlayVideoinPlayer:_videoURL];
}
-(void)PlayVideoinPlayer:(NSString *)URL
{
NSURL *fileURL = [NSURL fileURLWithPath:URL];
_Avcontroller=[[AVPlayerViewController alloc]init];
asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
anItem = [AVPlayerItem playerItemWithAsset:asset];
_avPlayer = [AVPlayer playerWithPlayerItem:anItem];
[_avPlayer addObserver:self forKeyPath:#"status" options:0 context:nil];
self.Avcontroller.view.frame = self.view.bounds;
[self.Avcontroller setPlayer:_avPlayer];
_Avcontroller.videoGravity=AVLayerVideoGravityResizeAspectFill;
[self.view addSubview:self.Avcontroller.view];
[self.view addSubview:self.Avcontroller.view];
[_avPlayer play];
CMTime interval = CMTimeMake(1, 1800);
__strong __typeof(self) weakself = self;
playbackObserver = [_avPlayer addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock: ^(CMTime time) {
CMTime endTime = CMTimeConvertScale (_avPlayer.currentItem.asset.duration, _avPlayer.currentTime.timescale, kCMTimeRoundingMethod_RoundHalfAwayFromZero);
if (CMTimeCompare(endTime, kCMTimeZero) != 0)
{
// double normalizedTime = (double) avPlayer.currentTime.value / (double) endTime.value;
//NSLog(#"--------->>>>%#",playbackObserver);
}
int CurrentSecond=[[weakself getStringFromCMTime:_avPlayer.currentTime] intValue];
_avPlayer.rate=1.0f;
}
Anyone have solution.? Please help me.Thanks

Playing stacked videos

I have multiple imageview subviews getting stacked based on my incoming data. Basically all these subviews are either set to an image or a video layer based on my incoming data. The problem i have is playing videos. i can play the first video in the stack but every video after that is just the sound of the first video. How can i play each accordingly?
the views are navigated through with a tap event like snapchat. see below:
#interface SceneImageViewController ()
#property (strong, nonatomic) NSURL *videoUrl;
#property (strong, nonatomic) AVPlayer *avPlayer;
#property (strong, nonatomic) AVPlayerLayer *avPlayerLayer;
#end
#implementation SceneImageViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mySubviews = [[NSMutableArray alloc] init];
self.videoCounterTags = [[NSMutableArray alloc] init];
int c = (int)[self.scenes count];
c--;
NSLog(#"int c = %d", c);
self.myCounter = [NSNumber numberWithInt:c];
for (int i=0; i<=c; i++) {
//create imageView
UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
imageView.tag = i; // <--- Add tag to track this subview in the view stack
[self.view addSubview:imageView];
NSLog(#"added image view %d", i);
//get scene object
PFObject *sceneObject = self.scenes[i];
//get the PFFile and filetype
PFFile *file = [sceneObject objectForKey:#"file"];
NSString *fileType = [sceneObject objectForKey:#"fileType"];
//check the filetype
if ([fileType isEqual: #"image"])
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//get image
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
}
//its a video
else
{
// the video player
NSURL *fileUrl = [NSURL URLWithString:file.url];
self.avPlayer = [AVPlayer playerWithURL:fileUrl];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
//self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
CGRect screenRect = [[UIScreen mainScreen] bounds];
self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
[imageView.layer addSublayer:self.avPlayerLayer];
NSNumber *tag = [NSNumber numberWithInt:i+1];
NSLog(#"tag = %#", tag);
[self.videoCounterTags addObject:tag];
//[self.avPlayer play];
}
}
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
[self.view bringSubviewToFront:self.screen];
[self.screen addGestureRecognizer:tapGesture];
}
- (void)viewTapped:(UIGestureRecognizer *)gesture{
NSLog(#"touch!");
[self.avPlayer pause];
int i = [self.myCounter intValue];
NSLog(#"counter = %d", i);
for(UIImageView *subview in [self.view subviews]) {
if(subview.tag== i) {
[subview removeFromSuperview];
}
}
if ([self.videoCounterTags containsObject:self.myCounter]) {
NSLog(#"play video!!!");
[self.avPlayer play];
}
if (i == 0) {
[self.avPlayer pause];
[self.navigationController popViewControllerAnimated:NO];
}
i--;
self.myCounter = [NSNumber numberWithInt:i];
NSLog(#"counter after = %d", i);
}
What Brooks Hanes said is correct you keep overriding the avplayer.
This is what i suggest for you to do:
Add the tap gesture to the imageView instead of the screen (or for a cleaner approach use UIButton instead):
UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
imageView.tag = i; // <--- Add tag to track this subview in the view stack
[self.view addSubview:imageView];
NSLog(#"added image view %d", i);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:imageView action:#selector(viewTapped:)];
[imageView addGestureRecognizer:tapGesture];
This way in your viewTapped: method you could get the tag of the pressed image like so: gesture.view.tag instead of using the myCounter.
To get the video working you could create a new AVPlayer for each video but that might turn quite expensive memory wise. A better approach will be to use AVPlayerItem and switch the AVPlayer's AVPlayerItem when changing the video.
So in the for loop do something like this where self.videoFiles is a NSMutableDictionary property:
// the video player
NSNumber *tag = [NSNumber numberWithInt:i+1];
NSURL *fileUrl = [NSURL URLWithString:file.url];
//save your video file url paired with the ImageView it belongs to.
[self.videosFiles setObject:fileUrl forKey:tag];
// you only need to initialize the player once.
if(self.avPlayer == nil){
AVAsset *asset = [AVAsset assetWithURL:fileUrl];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:item];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.avPlayer currentItem]];
}
// you don't need to keep the layer as a property
// (unless you need it for some reason
AVPlayerLayer* avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
CGRect screenRect = [[UIScreen mainScreen] bounds];
avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
[imageView.layer addSublayer:avPlayerLayer];
NSLog(#"tag = %#", tag);
[self.videoCounterTags addObject:tag];
Now in your viewTapped:
if ([self.videoCounterTags containsObject:gesture.view.tag]) {
NSLog(#"play video!!!");
AVAsset *asset = [AVAsset assetWithURL:[self.videoFiles objectForKey:gesture.view.tag]];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer replaceCurrentItemWithPlayerItem: item];
[self.avLayer play];
}
Or use the self.videoFiles instead and then you don't need self.videoCounterTags at all:
NSURL* fileURL = [self.videoFiles objectForKey:gesture.view.tag];
if (fileURL!=nil) {
NSLog(#"play video!!!");
AVAsset *asset = [AVAsset assetWithURL:fileURL];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
self.avPlayer replaceCurrentItemWithPlayerItem: item];
[self.avLayer play];
}
That's the gist of it.
Take a look at the way you're setting up the myCounter variable. It is set one time and never changes until a view is tapped, and then it is set to the count of scenes, -1.
In addition, try looking at the way you're setting to the _avPlayer pointer var. It's always being set, over and over, and it seems that in a for loop you'd want to be storing references instead of simply updating the same pointer to the value latest in collection of scenes.
Also, from Apple's documentation:
You can create arbitrary numbers of player layers with the same AVPlayer object. Only the most recently created player layer will actually display the video content on-screen.
So, it's possible that since you're using the same AVPlayer object to create all these AVPlayer layers, that you're never going to see any more than one actual video layer work.

why am i getting progress slider exception error

I am making an application which will play audio.I have used a slider to show the time elapsed and time remaining graphically in the slider.But i am not getting how to get the value programitcically.I have used the following code but its throwing an exception.
-(void) updateMyProgress
{
float progress = [avPlayer currentTime]/[avPlayer duration];
self.myProgressView.progress = progress;
}
The code im my viewcontoller.m file is
#import "ViewController.h"
#interface ViewController ()
{
AVAudioPlayer *avPlayer;
AVPlayer *avp;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *stringPath = [[NSBundle mainBundle]pathForResource:#"naat" ofType:#"mp3"];
NSURL *url = [NSURL fileURLWithPath:stringPath];
NSError *error;
avPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
[avPlayer setNumberOfLoops:2];
[avPlayer setVolume:self.sliderVolumeOutlet.value];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateMyProgress) userInfo:nil repeats:YES];
}
/*-(void) updateMyProgress
{
CGFloat progress = [avPlayer currentTime]/[avPlayer duration];
self.myProgressView.progress = progress;
}
*/
-(void) updateMyProgress
{
AVPlayerItem *currentItem = avp.currentItem ;
CMTime duration = currentItem.duration; //total time
CMTime currentTime = currentItem.currentTime; //playing time
CGFloat progress = currentTime.value/duration.value;
self.myProgressView.progress = progress;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sliderVolumeAction:(id)sender
{
UISlider *myslider= sender;
[avPlayer setVolume:myslider.value];
}
- (IBAction)stopButton:(id)sender
{
[avPlayer stop];
[avPlayer setCurrentTime:0];
}
- (IBAction)pauseButton:(id)sender
{
[avPlayer pause];
}
- (IBAction)playButton:(id)sender
{
[avPlayer play];
}
#end![enter image description here][1]
The attached image shows the screenshot of the exception
! [1]: http://i.stack.imgur.com/WsxtI.png
AVPlayer has no property called "duration".
"duration" is the property of AVPlayerItem.
And both duration and currentTime are of "CMTime" dataType
We have to get the value of CMTime then update the progress.
-(void) updateMyProgress
{
AVPlayerItem *currentItem = avPlayer.currentItem;
CMTime duration = currentItem.duration; //total time
CMTime currentTime = currentItem.currentTime; //playing time
CGFloat progress = currentTime.value/duration.value;
self.myProgressView.progress = progress;
}

How can I use this code to play more sounds?

//Action to play Audio//
-(IBAction)playAudio:(id)sender {
[self.loopPlayer play];
}
//Action to stop Audio//
-(IBAction)stopAudio:(id)sender {
if (self.loopPlayer.isPlaying) {
[self.loopPlayer stop];
self.loopPlayer.currentTime = 0;
self.loopPlayer.numberOfLoops = -1;
[self.loopPlayer prepareToPlay];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//Code that gets audio file "trap synth"//
NSURL* audioFileURL = [[NSBundle mainBundle] URLForResource:#"trapsynth" withExtension:#"wav"];
self.loopPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL error:nil];
}
This is the code i'm using with one button to play the sound when the button is tapped and stop the sound when the button is released. How would I go about adding more sounds to more buttons? I want to have more buttons that play and stop different sounds just like this.
property (nonatomic, strong) AVAudioPlayer *loopPlayer;
This code is also in my ViewController.h file
Ok although the answer provided by Miro is on the write track the code example given has issues.
Should be this in viewDidLoad -
- (void)viewDidLoad {
[super viewDidLoad];
NSURL* audioFileURL1 = [[NSBundle mainBundle] URLForResource:#"trapsynth" withExtension:#"wav"];
self.loopPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL1 error:nil];
NSURL* audioFileURL2 = [[NSBundle mainBundle] URLForResource:#"other_audio_file" withExtension:#"wav"];
self.loopPlayer2 = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL2 error:nil];
}
also stopAudio: method should be this
-(IBAction)stopAudio:(id)sender {
if (self.loopPlayer1.isPlaying && (sender.tag == 1)) {
[self.loopPlayer1 stop];
self.loopPlayer1.currentTime = 0;
self.loopPlayer1.numberOfLoops = -1;
[self.loopPlayer1 prepareToPlay];
}
if (self.loopPlayer2.isPlaying && (sender.tag == 2)) {
[self.loopPlayer2 stop];
self.loopPlayer2.currentTime = 0;
self.loopPlayer2.numberOfLoops = -1;
[self.loopPlayer2 prepareToPlay];
}
}
And finally for playAudio:
-(IBAction)playAudio:(id)sender {
if([sender tag] == 1){
[self.loopPlayer1 play];
}
if([sender tag] == 2){
[self.loopPlayer2 play];
}
}
If you want to play different sounds at the same time you should look into creating separate AVAudioPlayers - if you create a different one for each sound, then you can easily control (play/stop) each of them separately with a specific button.
On the simplest level, you could do something like this, which allows you to use the same button handlers for all your audio. The playAudio checks the tag of the Play button you press (be sure to set the tag value in IB, to 1,2,etc). There really only need be one Stop button.
You could enhance this in many ways, like attempting to reuse the AVAudioPlayer somehow, and loading the audio on the fly instead of all at the beginning. Or storing your audio file info in an array, creating an array of AVAudioPlayers for management, etc. But this is a start.
-(IBAction)playAudio:(id)sender {
// first, stop any already playing audio
[self stopAudio:sender];
if([sender tag] == 1){
[self.loopPlayer1 play];
} else if([sender tag] == 2){
[self.loopPlayer2 play];
}
}
-(IBAction)stopAudio:(id)sender {
if (self.loopPlayer1.isPlaying) {
[self.loopPlayer1 stop];
self.loopPlayer1.currentTime = 0;
self.loopPlayer1.numberOfLoops = -1;
[self.loopPlayer1 prepareToPlay];
} else if (self.loopPlayer2.isPlaying) {
[self.loopPlayer2 stop];
self.loopPlayer2.currentTime = 0;
self.loopPlayer2.numberOfLoops = -1;
[self.loopPlayer2 prepareToPlay];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
NSURL* audioFileURL1 = [[NSBundle mainBundle] URLForResource:#"trapsynth" withExtension:#"wav"];
self.loopPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL error:nil];
NSURL* audioFileURL2 = [[NSBundle mainBundle] URLForResource:#"trapsynth" withExtension:#"wav"];
self.loopPlayer2 = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL error:nil];
}
AND, in the .h file;
property (nonatomic, strong) AVAudioPlayer *loopPlayer1;
property (nonatomic, strong) AVAudioPlayer *loopPlayer2;

Resources