play , pause , stop music with UIActionSheet - uiactionsheet

I am Newbie to Xcode and I need some experience from who mastered xcode .
I Am trying to play , pause , stop Music with an UIActionSheet but when I click in Pause and Stop button they don't stop or even Pause only Play button works.Can someone help me with it ?
Here is my code.
#import <AVFoundation/AVFoundation.h>
#interface MainViewController () <UIActionSheetDelegate,AVAudioPlayerDelegate>
#property(nonatomic,retain)AVAudioPlayer *playAudio;
#end
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *buttonTitle =[actionSheet buttonTitleAtIndex:buttonIndex];
NSURL *url =[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/MusicName.mp3",[[NSBundle mainBundle] resourcePath]]];
NSError *error;
self.playAudio=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
if (buttonIndex==0) {
[self.playAudio play];
}
if ([buttonTitle isEqualToString:#"Pause"]) {
[self.playAudio pause];
}
if (buttonIndex==2) {
[self.playAudio stop];
}
}
- (IBAction)Music:(id)sender {
UIActionSheet *musicSheet =[[UIActionSheet alloc]initWithTitle:#"Choose" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Play",#"Pause",#"Stop", nil];
[musicSheet showInView:self.view];
}
. I am a Vietnamese so my English skills can make you hard to understand what I say. Thank you for your time . I am looking forward to seeing your reply

First of all : you should not rely on the button title. Use the button index to identify which button is pressed, that's what it's for.
Second :
Are you sure the index of your buttons is right ? You may try using a switch statement.
Such as :
switch (buttonIndex) {
case 0:
[self.playAudio play];
break;
case 1:
[self.playAudio pause];
break;
case 2:
[self.playAudio stop];
break;
default:
break;
}

Related

Unable to receive remoteControlReceivedWithEvent - objective c - ios

I successfully enabled my app to be able to play audio and video in background after the screen is locked. However, for better user experience I want to show play and pause controls of the running media on the locked screen. After following couple of blogs online, added the following code:
#interface MyControllerClass () <UIGestureRecognizerDelegate, UIApplicationDelegate>
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:avAsset];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
NSError *activationError = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
}
- (void)viewWillDisappear:(BOOL)animated {
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
NSLog(#"received event %#",receivedEvent);
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause: {
if ([self isVideoPlaying]) {
[self.avPlayer pause];
} else {
[self.avPlayer play];
}
break;
}
case UIEventSubtypeRemoteControlPlay: {
[self.avPlayer play];
break;
}
case UIEventSubtypeRemoteControlPause: {
[self.avPlayer pause];
break;
}
default:
break;
}
}
}
Added background modes in info.plist
Even though I am able to see the control screen, no user event is received by my app upon clicking the buttons.
I believe I am missing out on something very obvious. Any pointers would be helpful.
EDIT 1: The accepted answer in iOS - UIEventTypeRemoteControl events not received says that Your app must be the “Now Playing” app. How do I do this?
I found the answer to my question. I need to implement the code in my question in AppDelegate to receive events instead of implementing in ViewController.

Get AVAudioPlayer delegate audioPlayerDidFinishPlaying when app was in background [duplicate]

So I have an app that plays a bunch of songs while the user can flip through a comic book. I use AVAudioPlayer and I have it set up to play the songs in a set order. So when one song finishes, the next one will play. This works flawlessly when the app is open. The problem occurs when the app is in the background. I set up the app to play in the background, and that works fine. So when the user presses the home screen the music continues to play. The problem occurs when the song ends, it is suppose to play the next song like it does when the app is open. Instead nothing happens. According to the my NSLog statements the correct methods are being called but nothing happens. Here is my code:
- (void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully: (BOOL) flag {
NSLog(#"Song finished");
if ([songSelect isEqualToString: #"01icecapades"]) {
isPlay = #"yes";
songSelect = #"02sugarcube";
imageSelect = #"playbanner02";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"02sugarcube"]) {
isPlay = #"yes";
songSelect = #"03bullets";
imageSelect = #"playbanner03";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"03bullets"]) {
isPlay = #"yes";
songSelect = #"04satanama";
imageSelect = #"playbanner04";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"04satanama"]) {
isPlay = #"yes";
songSelect = #"05uglyjoke";
imageSelect = #"playbanner05";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"05uglyjoke"]) {
isPlay = #"yes";
songSelect = #"01icecapades";
imageSelect = #"playbanner01";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}}
Above is the code that recognizes which song is playing, and sets the correct song next. Then it triggers another method that sets up the player.
- (void)triggerSong {
NSLog(#"triggerSong called");
NSString *path;
NSError *error;
// Path the audio file
path = [[NSBundle mainBundle] pathForResource:songSelect ofType:#"mp3"];
// If we can access the file...
if ([[NSFileManager defaultManager] fileExistsAtPath:path])
{
// Setup the player
player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
//player = [initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[player setDelegate: self];
// Set the volume (range is 0 to 1)
player.volume = 1.0f;
[player prepareToPlay];
[player setNumberOfLoops:0];
[player play];
NSLog(#"player play");
[error release];
player.delegate = self;
// schedules an action every second for countdown
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateTimeLeft) userInfo:nil repeats:YES];
}}
Now I assuming this is not the best way to do this, but it works great when the app is in the foreground state. I've been looking through the documentation and I can't seem to find the cause of this problem. I was hoping somebody might be able to see an error to my approach. Like I said before, the two NSLogs in the triggerSong method are being called so I can't see why the AVAudioPlayer (player) is not being called.
Also I have the correct setting in my info.plist and I have this in my viewDidLoad:
//Make sure the system follows our playback status
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
Thanks for any insight. Much appreciated.
Relevant discussion
SHORT ANSWER:
You need this code in either your first view controller's init or viewDidLoad method:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
LONG ANSWER W/ SAMPLE:
Here is my example. Like you, I began with an app that would play music in the background but could never continue playing after the first clip ended. I made a copy of the original Music.mp3 and named it Music2.mp3. My intention was to play Music2.mp3 as soon as Music.mp3 ended (audioPlayerDidFinishPlaying:). I goofed around with the background tasks for awhile until I got this working WITHOUT the background task:
-(id)init{
self = [super initWithNibName:#"MediaPlayerViewController" bundle:nil];
if(self){
//Need this to play background playlist
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//MUSIC CLIP
//Sets up the first song...
NSString *musicPath = [[NSBundle mainBundle] pathForResource:#"Music" ofType:#"mp3"];
if(musicPath){
NSURL *musicURL = [NSURL fileURLWithPath:musicPath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil];
[audioPlayer setDelegate:self];
}
}
return self;
}
-(IBAction)playAudioFile:(id)sender{
if([audioPlayer isPlaying]){
//Stop playing audio and change test of button
[audioPlayer stop];
[sender setTitle:#"Play Audio File" forState:UIControlStateNormal];
}
else{
//Start playing audio and change text of button so
//user can tap to stop playback
[audioPlayer play];
[sender setTitle:#"Stop Audio File" forState:UIControlStateNormal];
}
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[audioButton setTitle:#"Play Audio File" forState:UIControlStateNormal];
[playRecordingButton setTitle:#"Play Rec File" forState:UIControlStateNormal];
//PLAY THE SECOND SONG
NSString *musicPath2 = [[NSBundle mainBundle] pathForResource:#"Music2" ofType:#"mp3"];
if(musicPath2){
NSURL *musicURL2 = [NSURL fileURLWithPath:musicPath2];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL2 error:nil];
[audioPlayer setDelegate:self];
NSLog(#"Play it again: \n%#", musicPath2);
[audioPlayer play];
}
}
The end result is that my app is now playing Music2.mp3 on a continuous loop, even if the app is in the background.
Just to confirm what Squatch said, this is also the solution in Swift:
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
OS X exhibits the same problem using AVAudioPlayer, however UIApplication is an iOS-only construct. OS X requires using NSApplication instead, but NSApplication doesn't return until the application is terminating so we need to use threads. As a bonus, there's an assert() somewhere in the depths of NSApplication that demands the main thread.
This hybrid C++/Objective C function is one workaround for this OS X issue:
void do_the_dumb (void real_application(void)) {
std::thread thread ([real_application]() {
real_application();
[[NSApplication sharedApplication] terminate: [NSApplication sharedApplication]];
});
[[NSApplication sharedApplication] run];
thread.join();
};

Need assistance playing sound on uiactionsheet tap

-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if(actionSheet.tag == 2) {
if(buttonIndex != actionSheet.cancelButtonIndex) {
NSString *s = [actionSheet buttonTitleAtIndex:buttonIndex];
NSString *soundFile = [[NSBundle mainBundle] pathForResource:s ofType:#"m4a"];
NSURL *soundUrl = [NSURL fileURLWithPath:soundFile];
AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:soundUrl error:nil];
player.numberOfLoops = 0;
[player play];
}
}
}
When I place a breakpoint on [player play]; and step over, iPhone is playing the sound. Without breakpoint its not playing the sound. Why this is happening?
I think your project is enabled ARC.
When ARC enable local variables destroy after method execution.
So you have to declare your AVAudioPlayre object as global.
It will maintain your object till view destroy.

Why do the Lock Screen audio controls disappear when I pause AVAudioPlayer?

I'm using an instance of AVAudioPlayer to play an audio file. The app is configured to play audio in the background and an appropriate audio session is set. I am also successfully receiving remote control events.
Here's the code:
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#interface ViewController ()
#property (nonatomic) AVAudioPlayer *player;
#end
#implementation ViewController
#synthesize player;
- (BOOL)canBecomeFirstResponder { return YES; }
- (void)viewDidLoad
{
[super viewDidLoad];
// Turn on remote control event delivery
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
// Set ourselves as the first responder
[self becomeFirstResponder];
// Set the audio session
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
NSError *activationError = nil;
success = [audioSession setActive:YES error:&activationError];
// Play an mp3 with AVAudioPlayer
NSString *audioFileName = #"%#/Via_Aurora.mp3";
NSURL *audioURL = [NSURL fileURLWithPath:[NSString stringWithFormat:audioFileName, [[NSBundle mainBundle] resourcePath]]];
player = [[AVPlayer alloc] initWithURL:audioURL];
[player play];
}
- (void)viewWillDisappear:(BOOL)animated {
// Turn off remote control event delivery & Resign as first responder
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
// Don't forget to call super
[super viewWillDisappear:animated];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlPreviousTrack:
NSLog(#"prev");
break;
case UIEventSubtypeRemoteControlNextTrack:
NSLog(#"next");
break;
case UIEventSubtypeRemoteControlPlay:
[player play];
break;
case UIEventSubtypeRemoteControlPause:
[player pause];
break;
default:
break;
}
}
}
#end
When I run the app the audio plays when the view loads. The app continues to play audio when it goes into background mode. I am able to successfully pause and/or play audio from the Control Center (accessed either from within the app or the Lock Screen) but, if I access the Lock Screen audio controls and pause the player, the music pauses and the lock screen controls disappear. I expect the music to pause, but not for the controls to disappear.
In other audio apps that I use you can pause, then play, audio from the Lock Screen. Have I overlooked something? Is this a correct approach to do something like this?
You're on the right track ...
You seem to be missing setting;
MPNowPlayingInfoCenter nowPlayingInfo
Without it, you will get the results described, IE after pressing pause, the lock screen no longer shows the pause, or indeed that it is playing a song. Here's a guide on how to set it (i've taken this from working code I did some time back, but I'm sure you can figure out what's what).
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc]initWithImage:albumImage];
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = [NSDictionary dictionaryWithObjectsAndKeys:aSong.songTitle, MPMediaItemPropertyTitle,
aSong.artistName, MPMediaItemPropertyArtist, artwork, MPMediaItemPropertyArtwork, 1.0f, MPNowPlayingInfoPropertyPlaybackRate, nil];
Add this Code in ViewDidLoad() For background play. It work for me. You should try it
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
let session:AVAudioSession = AVAudioSession.sharedInstance()
do
{
try session.setCategory(AVAudioSessionCategoryPlayback)
}
catch
{
print("Background Play Error")
}

Correct way to add a sound to UIAlertView

What is the most correct way to add a sound to a UIAlertView?
Should I subclass it and then play a system sound when the view appears?
Or would it be more correct, not to subclass but instead call a separate method to play a sound when it appears?
Can anyone recommend a control that plays sound and looks prettier than UIAlertView?
you can achieve this by using AVAudioPlayer bellow code:-
Set dalagete of UIAlertView in .h file like:-
#interface ViewController : UIViewController <UIAlertViewDelegate>
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/foo.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"message" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 1;
[audioPlayer play];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex==0) {
[audioPlayer stop];
}
}
EDIT
NOTE:- Do not forget to Add AVAudio framework And if you wish to sound playing till not press Button of UIAlertView then set audioPlayer.numberOfLoops = -1;

Resources