AVAudioRecorder background modes and phone call - objective-c

My app Used Required background modes "App plays audio"
I can record on background mode. but if phone call?
I used the delegate
-(void)loadView
{
NSError *error=nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if (error) {//Do something error}
error = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error) {//Do something error}
}
-(void)audioRecorderBeginInterruption
{
[AVAudioRecorder pause];
}
-(void)audioRecorderEndInterruption
{
[AVAudioRecorder record];
}
These two methods are executed normally
But AVAudioRecorder is not Run.
I want keep recording when the phone call end.

try this delegate method,
- (void)applicationWillResignActive:(UIApplication *)application
{
//post your Notification
}
it should be call back at your working class which include your method,
-(void)audioRecorderEndInterruption
{
// add Notification
[AVAudioRecorder record];
}

Related

How to play audio in notification action in ios8?

I'm trying to use new ios8 notification actions to let users play audio from their lock screen.
I manage to download the data in the background, but the avaudioplayer does not seem to play.
Any help would be greatly appreciated !
Here is the code :
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
//handle the actions
if ([identifier isEqualToString:#"ACCEPT_IDENTIFIER"]){
Message *newMessage = [Message rawMessageToInstance:[userInfo valueForKey:#"message"]];
AVAudioSession* session = [AVAudioSession sharedInstance];
BOOL success; NSError* error;
success = [session setCategory:AVAudioSessionCategoryPlayback
error:&error];
if (!success)
NSLog(#"AVAudioSession error setting category:%#",error);
[session setActive:YES error:nil];
NSLog(#"%lu",newMessage.identifier);
[ApiUtils downloadAudioFileAtURL:[newMessage getMessageURL] success:^void(NSData *data) {
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:nil];
[player setVolume:2];
[player play];
[self performSelector:#selector(completeNotif:) withObject:completionHandler afterDelay:[player duration]];
} failure:^(){
completionHandler();
}];
}
}
I had the same problem ... first I came up, it must have to do something with background and sound playing options - so I added the background audio flag to the info.plist.
With standard AVAudio stuf it works on the simulator, but not on the device. The special hook is, that you want to start the audio while you are in background - so add the code from anger: How to use kAudioSessionProperty_OverrideCategoryMixWithOthers before starting with the AVAudioPlayer and it will also work on the device.
Hope that helps, for me it works.

ios 7 non deprecated solution to resuming background music from duck [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am able to duck my background audio while playing new sounds. However I am unable to resume the background audio level to maximum again. When my delegate tries to "unduck" it just keeps being ducked. The normal fix for this is AudiosessionSetProperty, but that's deprecated in iOS 7 and Apple doesn't give any hints in the deprecation warnings or documentation.
I call this method on load of view.
- (void) configureAVAudioSession
{
//get your app's audioSession singleton object
AVAudioSession* session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
success=[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if (!success)
{
NSLog(#"AVAudioSession error :%#",error);
}
else
{
}
success = [session setActive:YES error:&error];
if (!success) {
NSLog(#"Error setting active %#",error);
}
else
{
NSLog(#"succes settings active");
}
}
This is when I play audio
-(void)playTimeOnGo
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"just-like-magic"
ofType:#"mp3"]];
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:nil];
self.audioPlayer.delegate=(id<AVAudioPlayerDelegate>)self;
//get your app's audioSession singleton object
AVAudioSession* session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
success=[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error];
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
This is my delegate when audio is done to resume background audio and undock audio
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)data successfully:(BOOL)flag{
[self configureAVAudioSession];
NSLog(#"playback ended");
}
So how do I unduck the background music again without deprecated APIs? calling [self configureAVAudioSession]; apparently doesn't work....
Ladies an gentlemen, I provide you with a non-deprecated working example of how to properly use ducking in iOS 7.
In your whatever "view load method" call this method, where the bool is set to YES. this will mix the background audio and prepare it for ducking
- (void) configureAVAudioSession:(bool) active
{
//get your app's audioSession singleton object
AVAudioSession* session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
success=[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if (!success)
{
NSLog(#"AVAudioSession error :%#",error);
}
else
{
}
success = [session setActive:active error:&error];
if (!success) {
NSLog(#"Error setting active %#",error);
}
else
{
//NSLog(#"success settings active");
}
}
Play you audio file with this method. Watch how ducking happens.. remember to set the delegate as i have in this example EVERY time you play a new audio alert. dont set it once in view load methods.
-(void)playTimeOnGo
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
//alertName is the name of your audio file without extention. extenstions is, doh extenstion like "mp"
pathForResource:_dataManager.optionsSettings.setStarts.alertName
ofType:_dataManager.optionsSettings.setStarts.alertExtension]];
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:nil];
self.audioPlayer.delegate=(id<AVAudioPlayerDelegate>)self;
//get your app's audioSession singleton object
AVAudioSession* session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
success=[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error];
[self.audioPlayer prepareToPlay];
[self.audioPlayer play];
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
the delegate will call this method after playback and turn up the volume of background music :) Please dont get confused that i am using a thread for this. u can just call the method if you wish but this stalls the main thread about a second maybe even two seconds. So it thats okay with you, dont use a thread and just call [self configureAVAudioSession:NO];
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)data successfully:(BOOL)flag
{
_playBackFinishedDelegateThead = [[NSThread alloc] initWithTarget:self selector:#selector(configureAVAudioSession:) object:NO];
[_playBackFinishedDelegateThead start];
}
This example IS 100% tested and working in my app.

presentRequestsDialogModallyWithSession does not work, but gives good result

When I use the webdialog for a friendrequest, everything is going fine, except no request or anything is made.
The code:
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
facebookFriend.id, #"to",
nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:FBSession.activeSession
message:NSLocalizedString(#"FB_FRIEND_INVITE_MESSAGE", #"Facebook friend invite message")
title:NSLocalizedString(#"FB_FRIEND_INVITE_TITLE", #"Facebook friend invite title")
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
}];
This is the result I get:
fbconnect://success?request=xxxxxxxxxxxx&to%5B0%5D=xxxxxxxx
How can I debug what is going wrong?
Thanks in advance.
Ruud
For SDK 3.2 or above we have a facility to use FBWebDialogs class that will help us to show a popup along with the friend list and pick one or more from list to send invitation.
Lets do it step by step:
1) Download and setup SDK 3.2 or above.
2) First setup your application on facebook by following this url.
3) Then use the attached code.
Sample Code: (It generates invite friend request)
-(void)inviteFriends
{
if ([[FBSession activeSession] isOpen])
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}
];
}
else
{
/*
* open a new session with publish permission
*/
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObject:#"publish_stream"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
if (!error && status == FBSessionStateOpen)
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}];
}
else
{
[self requestFailedWithError:error];
}
}];
}
}
and here are the helper functions that calls delegates function OnFBSuccess and OnFBFailed.
- (void)requestSucceeded
{
NSLog(#"requestSucceeded");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBSuccess");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
- (void)requestFailedWithError:(NSError *)error
{
NSLog(#"requestFailed");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBFailed:");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback setArgument:&error atIndex:2];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
So the class taht calls method InviteFriend MUST have these functions:
-(void)OnFBSuccess
{
CCLOG(#"successful");
// do stuff here
[login release];
}
-(void)OnFBFailed:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
// do stuff here
[login release];
}
Recommended Reads:
Send Invitation via Facebook
API Permissions
An Example
NOTE:
1) Don't forget to setup Facebook application ID in plist.
2) Don't forget to adjust AppDelegate to handle urls.
Partial snippet taken from above link in point 2:
/*
* If we have a valid session at the time of openURL call, we handle
* Facebook transitions by passing the url argument to handleOpenURL
*/
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
return [FBSession.activeSession handleOpenURL:url];
}
Hope it helps!
EDIT
Here:
declaration for fbDelegate is:
#property (nonatomic, assign) id <FBLoginDelegate> fbDelegate;
#protocol FBLoginDelegate <NSObject>
#required
-(void) OnFBSuccess;
-(void) OnFBFailed : (NSError *)error;
#end
and this is how you can consume this code:
FBLoginHandler *login = [[FBLoginHandler alloc] initWithDelegate:self]; // here 'self' is the fbDelegate you have asked about
[login inviteFriends];
I think your application is not enable for Android and for web . And you are trying to get notification on web or on Android device.
Points : For getting notification on Android or on web you have to enable your app for Android and web too .
To Enable Android and Web on your App : GoTo your App > Setting > Click on + Add platform add enter necessary information and Save .
Lets Enjoy Notification . :-)

openActiveSessionWithReadPermissions does not log in automatically

I have recently started using Facebook SDK 3.1, and am encountering some problems with logging in using openActiveSessionWithReadPermissions.
Actually, loggin in works perfectly, if there is a cached token available, it logs in without presenting Facebook UI, and if not, it presents the UI.
The problem occurs after I make a call to reauthorizeWithPublishPermissions. If I call reauthorizeWithPublishPermissions, then close and reopen the application, and make a call to openActiveSessionWithReadPermissions, it presents the Facebook UI and requires the user to say "yes I'm OK with read permissions", even though there is a cached token available.
It only presents the Facebook UI erroneously if I make a call to reauthorizeWithPublishPermissions, otherwise everything works fine.
Open for read code:
[FBSession openActiveSessionWithReadPermissions:readpermissions allowLoginUI:YES
completionHandler:^(FBSession *aSession, FBSessionState status, NSError *error) {
[self sessionStateChanged:[FBSession activeSession] state:status error:error];
if (status != FBSessionStateOpenTokenExtended) {
// and here we make sure to update our UX according to the new session state
FBRequest *me = [[FBRequest alloc] initWithSession:aSession
graphPath:#"me"];
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *aUser,
NSError *error) {
self.user = aUser;
aCompletionBlock(aSession, status, error);
}];
}
}];
the sessionStateChanged function:
- (void)sessionStateChanged:(FBSession *)aSession state:(FBSessionState)state error:(NSError *)error {
if (aSession.isOpen) {
// Initiate a Facebook instance and properties
if (nil == self.facebook || state == FBSessionStateOpenTokenExtended) {
self.facebook = [[Facebook alloc]
initWithAppId:FBSession.activeSession.appID
andDelegate:nil];
// Store the Facebook session information
self.facebook.accessToken = FBSession.activeSession.accessToken;
self.facebook.expirationDate = FBSession.activeSession.expirationDate;
}
} else {
// Clear out the Facebook instance
if (state == FBSessionStateClosedLoginFailed) {
[FBSession.activeSession closeAndClearTokenInformation];
}
self.facebook = nil;
}
}
the Publish call, with an empty aPublishAction for testing:
- (void)doPublishAction:(void(^)(FBSession *aSession, NSError *error))aPublishAction {
if ([FBSession.activeSession.permissions
indexOfObject:#"publish_actions"] == NSNotFound) {
NSArray *writepermissions = [[NSArray alloc] initWithObjects:
#"publish_stream",
#"publish_actions",
nil];
[[FBSession activeSession]reauthorizeWithPublishPermissions:writepermissions defaultAudience:FBSessionDefaultAudienceFriends completionHandler:^(FBSession *aSession, NSError *error){
if (error) {
NSLog(#"Error on public permissions: %#", error);
}
else {
aPublishAction(aSession, error);
}
}];
}
else {
// If permissions present, publish the story
aPublishAction(FBSession.activeSession, nil);
}
}
Thanks for everything in advance, I would be grateful for any and all help!!
You need to add
[FBSession.activeSession handleDidBecomeActive];
to your -(void) applicationDidBecomeActive:(UIApplication *)application method in your app's delegate as stated in the migration guide.
What if you use openActiveSessionWithPermissions instead of openActiveSessionWithReadPermissions?

iphone iOS5 audioPlayerDidFinishPlaying not called screen lock?

I have a series of audio files which I want to play in sequence. I setup audioPlayerDidFinishPlaying delegate method to start the next file in the sequence. This works with no problem if I turn off screen lock or if I run it on the emulator or on an iOS4 device. However, when I run it on a disconnected device, iOS5, screen locked, it stops after the first track. Is there some way to start a new sound track after the screen lock has come on?
Here is my basic code
// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setDelegate: self];
// Use this code instead to allow the app sound to continue to play when the screen is locked.
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
UInt32 doSetProperty = 0;
AudioSessionSetProperty ( kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (doSetProperty),
&doSetProperty
);
// Registers the audio route change listener callback function
AudioSessionAddPropertyListener (
kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
self
);
// Activates the audio session.
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:#"m4a"];
float vol = [appSoundPlayer volume];
AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
self.appSoundPlayer = newAudio; // automatically retain audio and dealloc old file if new file is loaded
[newAudio release]; // release the audio safely
appSoundPlayer.delegate = self;
[appSoundPlayer prepareToPlay];
[appSoundPlayer setNumberOfLoops:0];
[appSoundPlayer play];
[appSoundPlayer setVolume:vol];
[progTime setProgress:0];
}
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) lappSoundPlayer successfully: (BOOL) flag {
//... code here to select nex sound track
[lappSoundPlayer play];
}
I have already made it so the app continues to play the current track even when screen lock comes on, I just can't get it to start up the next track.
Note: I have verified that this was working in iOS4.
Have you set up an audio session category, specifically AVAudioSessionCategoryPlayback, as described here?
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
If that doesn't work, another thing to try, according to user ascanio in this message in the Apple dev forums, is to set your app up to listen for remote control events:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];