playing mp3 from nsbundle - ios

SETUP
I put a mp3 into my bundle just for testing, i will have them download into the documents directory. But for now i am going to work off the bundle.
I have found a couple tutorials, but not anything for what i need. The below is definitely a mix of a couple solutions and probably not the best approach.
Problem
How do i pull a song out of my bundle and play within the app?
//Create an instance of MPMusicPlayerController
MPMusicPlayerController* myPlayer = [MPMusicPlayerController applicationMusicPlayer];
//Read the song off the bundle.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"LittleMoments" ofType:#"mp3"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
if (myData) {
//This wont work for me because i don't want to query songs from the iPod,
i want to play songs out of the Bundle.
//Create a query that will return all songs by The Beatles grouped by album
MPMediaQuery* query = [MPMediaQuery songsQuery];
[query addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:#"The Beatles" forProperty:MPMediaItemPropertyArtist comparisonType:MPMediaPredicateComparisonEqualTo]];
[query setGroupingType:MPMediaGroupingAlbum];
//Pass the query to the player
[myPlayer setQueueWithQuery:query];
/////**** how can i get nsdata into MyPlayer?*****//////
//Start playing and set a label text to the name and image to the cover art of the song that is playing
[myPlayer play];
}

Try playing the file with AVAudioPlayer
AVAudioPlayer *audioPlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithData:myData error:nil];
audioPlayer.delegate = self;
[audioPlayer play];

Related

MP3 Queue Player - Load in background thread?

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.
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.

Playing a sound in background

I have read some threads about this topic, and currently have this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *soundFilePath = [NSString stringWithFormat:#"%#/testsoundsr.aiff",
[[NSBundle mainBundle] resourcePath]];
NSURL *soundFileURL = [NSURL fileURLWithPath: soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL
error:nil];
player.numberOfLoops = -1; //Infinite
[player play];
}
The sound is not played though, and I can only imagine that the problem is with the NSString definition which is used to reference the file
The file I'm trying to play is named 'testsoundsr.aiff' and I have dragged that into the project. Also I have added several frameworks to the project, including AudioToolBox.framework
---UPDATE---
I have now tried using an .mp3 file instead, but still getting no sound through.
Try player.delegate = self before [player play]

Play audio after a Time Interval IOS7

Hi in my application, audio is playing when user press the button but now I have two audio buttons like audio1 and audio2, now I want to play second audio after a time interval once the audio1 is completed by clicking the same button.
- (IBAction)btn1:(id)sender {
NSString *audioPath = [[NSBundle mainBundle] pathForResource:#"audio" ofType:#"mp3" ];
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
}
The above code I have used for play one audio now I want to play second audio once the first audio completed please tell me how to make it.
Thanks.
Try this:
You have to add a bool variable with the name 'firstAudioPlayed' on start the variable should be NO or FALSE.
- (IBAction)btn1:(id)sender {
if (![self.audioPlayer isPlaying]) {
NSString *audioPath;
if (self.firstAudioPlayed) {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio2" ofType:#"mp3" ];
} else {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio1" ofType:#"mp3" ];
}
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
self.firstAudioPlayed = !self.firstAudioPlayed;
}
}
I'm not sure if it's working like this, else just ask with a comment...
Explication of the code:
First you check if the player is already playing a song, if he isn't, you check if the first audio already has played (self.firstAudioPlayed) with this you can give the correct path to load the audio file. Now you play this audio file.
(Sorry for my grammar and my english, corrections are welcome)
You probably should use player's delegate. Set audioPlayer.delegate=self; and implement audioPlayerDidFinishPlaying:successfully: method to see when a player finished playing.
Then you can do whatever you want in there, for example start the second audio.

Play multiple audio at one same time

My client wants to create an app in which user can play 4 audio at once and then start start any audio and then record them as one file.
I have not worked on audio/video apps so i want to know that is that possible in ios sdk?
How many audio file can be played at same time?
You can play many musics at the same time using AVAudioSession.
UInt32 allowMixing = true;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
You can play multiple audio file with this code
NSString *songA = [[NSBundle mainBundle] pathForResource:#"songA" ofType:#"mp3"];
NSError *soundError = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:songA] error:&soundError];
if(self.player == nil)
NSLog(#"%#",soundError);
else
{
[self.player setDelegate:self];
[self.player setVolume:0.75];
[self.player play];
}
NSString *songB = [[NSBundle mainBundle] pathForResource:#"songB" ofType:#"mp3"];
soundError = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:songB] error:&soundError];
if(self.player == nil)
NSLog(#"%#",soundError);
else
{
[self.player setDelegate:self];
[self.player setVolume:0.25];
[self.player play];
}
To marge more than one audio file you can use ans from this question Combining two .caf files on iPhone

Pick songs from plist(NSArray) and play using AVAudioPlayer?

I'm student working on a coding exercise and I am stumped!
I have two instances of AVAudioPlayer in my app - I can load the songs into each player using a direct path no problem.
What I'd like to be able to do is play multiple songs held within an array on each player.
Is this possible? and if so how would I go about doing this?
In my plist I have the key set to "One.mp3" as a string and the value as the path to the file... (was guessing at that part).
Thanks for any insight.
- (void)viewDidLoad {
[super viewDidLoad];
//multiple song array
NSString *soundsPath = [[NSBundle mainBundle] pathForResource:#"soundslist"
ofType:#"plist"];
soundsList = [[NSArray alloc] initWithContentsOfFile:soundsPath];
NSString* filename = [soundsList objectAtIndex:0];
NSString *path = [[NSBundle mainBundle] pathForResource:filename
ofType:#"mp3"];
AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path]
error:NULL];
self.audioPlayer = newAudio; // automatically retain audio and dealloc old file if new file is loaded
[newAudio release]; // release the audio safely
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer setNumberOfLoops:0];
[audioPlayer play];
}
It sounds like you want to try to play multiple songs on a single player. This isn't possible as stated in the AVAudioPlayer Overview (4th bullet). It is possible to play multiple songs with multiple AVAudioPlayers. Something like this:
NSMutableArray *audioPlayers = [NSMutableArray arrayWithCapacity:[soundsList count]];
for (NSString *soundPath in soundsList) {
NSError *error = nil;
AVAudioPlayer *audioPlayer = [AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[audioPlayers addObject:audioPlayer];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer setNumberOfLoops:0];
[audioPlayer play];
}
I would suggest that you hardcode the file path instead of reading it in with a plist. Once you get that working, then you can try reading it in with the plist. Something like this would work:
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"One" withExtension:#"mp3"];
AVAudioPlayer *soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error]
This way, you remove one level of indirection and one point of failure.

Resources