Audio stream with AVPlayer - iphone

There's a lot of streaming apps out there for iOS. They all use a player, which I assume is the AVPlayer. Yet it seems impossible to find a decent documentation with sample code that works ! I'm pretty sure it's nothing but a few line of codes, but I just can't figure out what's wrong...
I have an EXC_BAD_ACCESS error when trying to call the "play" method. But the url is good and there is an instance of the player.
- (void)viewDidLoad {
[super viewDidLoad];
// Load the array with the sample file
NSString *urlAddress = #"http://mystreamadress.mp3";
//Create a URL object.
urlStream = [NSURL URLWithString:urlAddress];
self.player = [AVPlayer playerWithURL:urlStream];
[urlAddress release];
}
The urlStream is a property with retain attribute. Then I have an IBAction that fires when the button is clicked and that tries to play it, and that's where it crashes.
- (IBAction)playButtonPressed
{
[player play];
}
Can my problem be because I'm trying to play MP3 or what ? The real url adress I'm using works fine when I use a webview to load it.
If anyone could point me to a good sample (not the AVFoundation ou AVPlayer docs from Apple nor the AVTouchController project) it would be realy appreciated.
Thanks !

urlAddress release is causing the issue I think.
You didn't create your NSString with alloc, init so by releasing it you are overreleasing it and getting the EXC_BAD_ACCESS.
Unless you explicitly create an NSString with alloc and init then the convenience methods of creating the string are autoreleased.

AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:fileURL];
//AVPlayer *avPlayer = [[AVPlayer playerWithURL:[NSURL URLWithString:url]] retain];
avPlayer = [[AVPlayer playerWithPlayerItem:playerItem] retain];
//AVPlayerLayer *avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];
[avPlayer play];
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
I use it this way to play mp3, but it doesn't support stop.

Related

How does my app recognize that a song finished?

I´m working on my first app. It plays an mp3 song. Everything works fine, but I need the app to recognize that the sound finished, then change the button “pause” image to the “play” one. I can already do that, but just when the button is pressed, not when song ends.
Another issue is that when the song restarts after stop->play, it doesn´t continue playing at the previous volume setting (got a slider). The player starts at maximum volume. I can change the volume slider position, but I am not able to make the app respect the set volume when restarts.
Any help will be very appreciated!
Thnx a lot.
When using "AVAudioPlayerDelegate protocol delegate", please do not forget to set delegate (for example) as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"33fr" ofType:#"mp3"];
NSURL *fileURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
if (error) {
NSLog(#"error = %#", error);
return;
}
[myPlayer setDelegate:self]; <<=== HERE!
}
I uploaded sample code here. Please check it. ->
http://yahoo.jp/box/X7Hxfk
I have not done much of Objective-C but it looks like you need to implement a delegate.
I quote: "You implement a delegate to handle interruptions (such as an incoming phone call) and to update the user interface when a sound has finished playing."
I am just reading the AVAudioPlayer Class Reference here:
https://developer.apple.com/library/mac/#documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html#//apple_ref/doc/uid/TP40008067
you can use the AVAudioPlayerDelegate protocol delegate
After the audio player is finished playing the song (if it does so
successfully), the audio PlayerDidFinishPlaying:successfully: delegate
method will be called in the delegate object of the audio player. We
can implement this method like below (this method is defined in the
AVAudioPlayerDelegate protocol):
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag)
{
NSLog(#"Audio player stopped correctly.");
}
else
{ NSLog(#"Audio player did not stop correctly.");
}
if ([player isEqual:self.audioPlayer])
{ self.audioPlayer = nil;
}
else
{ /* This is not the player */ }
}
in .h file add delegate like below code
#interface yourViewController : UIViewController <AVAudioPlayerDelegate>

Can not call method from another view controller in Objective C, iPhone SDK

At my StartWorkoutViewController.m I trigger:
#import "WorkoutViewController.h"
#implementation StartWorkoutViewController
- (IBAction) start
{
[firstViewController performSelector:#selector(callMyAction)];
WorkoutViewController *ViewCon = [[WorkoutViewController alloc]init];
[ViewCon callMyAction];
[ViewCon release];
}
then at my WorkOutViewController.h I added this:
- (void)callMyAction;
and at my WorkOutViewController.m I added this:
#import "StartWorkoutViewController.h"
-(void)viewWillAppear:(BOOL)animated{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/achtergrondgeluid.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = -1;
[audioPlayer play];
}
-(void)callMyAction{
NSLog(#"suckers");
[audioPlayer pause];
}
Now my NSLog (#"suckers") triggers very well from the StarWorkoutViewController, but for some reason the audioPlayer does nothing, any idea? Also setting labels in the Workout ViewController from the callMyAction in this file. Don't work! Any idea? Thanks!
The reason nothing is happening is because your are calling the pause method before the player even starts playing. viewWillAppear does not get called until it is visually on the screen. It actually doesn't always get called even then but that is another issue entirely. So if you want to pause the player it needs to actually be playing. If you put that viewWillAppear code in viewDidLoad it will probably work as expected.
Currently your code is doing this:
Load WorkoutViewController
Pause Audio
WorkourViewController become visible (actually this may never happen as I am not seeing it being added to any windows or anything).
Plays audio.

Crashes when using AVAudioPlayer on iPhone

I am trying to use AVAudioPlayer to play some sounds in quick succession. When I invoke the sound-playing function less frequently so that the sounds play fully before the function is invoked again, the application runs fine. But if I invoke the function quickly in rapid succession (so that sounds are played while the previous sounds are still being played), the app eventually crashes after ~20 calls to the function, with the message "EXC_BAD_ACCESS". Here is code from the function:
NSString *nsWavPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:wavFileName];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:nsWavPath] error:NULL];
theAudio.delegate = self;
[theAudio play];
As mentioned in another thread, I implemented the following delegate function:
- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if(!flag)
NSLog(#"audio did NOT finish successfully\n");
[player release];
}
But the app still crashes after around ~20 rapid calls to the function. Any idea what I'm doing wrong?
First off: Make sure you're not trying to play a sound a second time that has already been released via [player release]; If you are, you'll get that error message right away. Once you release the player associated with a specific sound, you cannot play the file again like you have shown here. Try commenting out that line of code and see if it still happens.
I've also run into an issue where AVAudioPlayer allocates 32kb everytime a new player is created and if you have enough sounds you can run out of memory and get a crash. I highly doubt this is your problem though since it doesn't typically throw that error code.
EXC_BAD_ACCESS is typically from trying to access a pointer that no longer exists (such as your player object) for most of the cases I've seen on this forum
I found a better solution to this problem.
You simply need to active/deactivate your AVAudioSession.
For example: In you viewDidLoad method put this:
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&activationError];
Then, you can play a sound in whatever method like this:
... some awesome code ...
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
[self.audioPlayer setDelegate:self];
[self.audioPlayer setVolume: 0.7f];
[self.audioPlayer setNumberOfLoops:0];
if ([self.audioPlayer prepareToPlay]) {
[self.audioPlayer play];
}
....
And finally, (no matters if sound was finished playing), when you're done with sounds then just do this:
// I've made it on the view's callback
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.audioPlayer stop];
[self setAudioPlayer:nil];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive:NO
error:&activationError];
.... etc, etc...
}
And that's all :)
Your app will never crash again with an EXC_BAD_ACCESS.
Hope this helps you and avoid that hacky [self retain] / [self release]
From the Apple's Audio Session Programming Guide:
https://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/ConfiguringanAudioSession/ConfiguringanAudioSession.html

AVaudioPlayer regarding song overlapping

I have using AVAudioPlayer in my app but the problem is that when i play the song from list it will played while before stopping the song i am again goes to song list then select another song then both song will start playing simultaneously so please tell me the code which will terminate my first song.
I use flag variable for initializing the song file---
fileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#" Om Namo" ofType:#"aac"]];
self._player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self._player)
{
_fileName.text = [NSString stringWithFormat: #"%# (%d ch.)", [[self._player.url relativePath] lastPathComponent], self._player.numberOfChannels, nil];
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
}
[fileURL release];
break;
Play and push function---
- (void)startPlayback
{
if ([self._player play])
{
//[self stop];
[self updateViewForPlayerState];
self._player.delegate = self;
}
else
NSLog(#"Could not play %#\n", self._player.url);
}
- (void)pausePlayback
{
[self._player pause];
[self updateViewForPlayerState];
}
I also make stop function---
-(void)stop
{
[_player release];
self._player=nil;
}
Please help me .
Is correct my stop function.
and where i put our stop function or any other solution to fix this problem...
I can think of 3 things :
1) You can make code look like code by putting 4 spaces infront of each line. The reason you've gt no answers so far is probably because your question is almost unreadable ;)
2) In your stop method you might want to try this :
- (void) stop {
[_player stop];
self._player = nil;
}
3) Apple highly discourage using an underscore in front of member names. I've never run into problems but I'd rename _player to player.

Can you see anything wrong in this code?

NSString *path = [[NSBundle mainBundle] pathForResource:[arraySub objectAtIndex:indexPathHere.row] ofType:#"mp3"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
self.player = myPlayer;
[player prepareToPlay];
[player setDelegate:self];
[self.player play];
NSTimeInterval lenghtMusic = player.duration;
if (player.currentTime == lenghtMusic) {
NSLog(#"It worked");
[tableThing deselectRowAtIndexPath:indexPathHere animated:YES];
[myPlayer autorelease];
[file autorelease];
}
Can you see anything wrong?
Apparently, the "if"-statement never gets called...
If I read your code correctly you are trying to find out when the player has finished playing and then you want to deselect the current rode and release the player. Your problem is that you start the player and then immediately checks where it is currently playing. Unless you have an almost 0 length file the currentTime and length will NEVER be equal.
If that is what you are trying to do you should use the AVAudioPlayerDelegate Protocol and especially the:
– audioPlayerDidFinishPlaying:successfully:
method that is called when the player is finished.
So you need to change your class that controls the player by editing the .h file to use the AVAudioPlayerDelegate Protocol. Obviously keep extending whatever you were before.
#interface YourClass <AVAudioPlayerDelegate>
#end
In your .m file:
Then when you have created and assigned your player instance:
[player setDelegate:self];
In the .m file also add the method
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Your success code goes here
}
You are comparing double's with ==, which is almost always false due to round-off errors.
Compare with a range e.g.
if (fabs(player.currentTime - lenghtMusic) < 0.0001) {
...
}
I'm a noob iPhone dev, but are you sure that player.currentTime is a NSTimeInterval? That looks like the most obvious candidate.
Also, I'd log out what your player.currentTime is and what lenghtMusic is before your if and that'll probably let you know what's going on.