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

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.

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.

NSFetchedResultController won't show data in IOS 5

I am new to IOS development. At the moment I'm building an iPad app, what gets data back from the webservice, saves it in a core database and shows it in a tableview using NSFetchedResultController.
What is the problem. In IOS6 it al works like a charm, in IOS 5.0 it saves the data but not showing it in the tableview. It gives the following error.
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. The NIB data is invalid. with userInfo (null)
And when I test in IOS 5.1 it does not do anything. It does not shows data in a tableview and data is not being stored in core database.
Here is what I do. In my view did appear I check if there is a document I can use.
if (!self.genkDatabase) { // we'll create a default database if none is set
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"Default appGenk Database"];
self.genkDatabase = [[UIManagedDocument alloc] initWithFileURL:url]; // setter will create this for us on disk
}
Then it goes to my setter. And next in usedocument gonna check in which state my document is.
- (void)setGenkDatabase:(UIManagedDocument *)genkDatabase
{
if (_genkDatabase != genkDatabase) {
_genkDatabase = genkDatabase;
[self useDocument];
}
NSLog(#"Comes in the setdatabase methode.");
}
- (void)useDocument
{
NSLog(#"Comses in the use document");
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.genkDatabase.fileURL path]]) {
// does not exist on disk, so create it
[self.genkDatabase saveToURL:self.genkDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"create");
[self setupFetchedResultsController];
NSLog(#"create 2");
[self fetchNewsIntoDocument:self.genkDatabase];
NSLog(#"create 3");
}];
} else if (self.genkDatabase.documentState == UIDocumentStateClosed) {
NSLog(#"closed news");
// exists on disk, but we need to open it
[self.genkDatabase openWithCompletionHandler:^(BOOL success) {
[self setupFetchedResultsController];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateNormal) {
NSLog(#"normal");
// already open and ready to use
[self setupFetchedResultsController];
}
}
Finally I fetch my data in my document using the following function.
- (void)fetchNewsIntoDocument:(UIManagedDocument *)document
{
dispatch_queue_t fetchNews = dispatch_queue_create("news fetcher", NULL);
dispatch_async(fetchNews, ^{
NSArray *news = [GenkData getNews];
[document.managedObjectContext performBlock:^{
int newsId = 0;
for (NSDictionary *genkInfo in news) {
newsId++;
[News newsWithGenkInfo:genkInfo inManagedObjectContext:document.managedObjectContext withNewsId:newsId];
NSLog(#"news inserted");
}
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
}];
});
dispatch_release(fetchNews);
}
For the problem in IOS 5.0 is this my NSFetchResultController method.
- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"News"];
request.sortDescriptors = [NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES],nil];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.genkDatabase.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
I am doing this like the example from Paul Hegarty in stanford university. You can find the example Photomania over here.
Hope anyone can help me!
Kind regards

AVAudioPlayer returns success but no sound from device

I have a very simple app that I have built to test out AVAudioPlayer. I have a 16s aif file that plays just fine on my Mac. Put it in a simple app and ran on my iPhone but no sound. Sending 'play' to the object returns success and audioPlayerDidFinishPlaying comes back with success after 16 seconds. Still no sound. Have checked the sound volume on the iPhone, just fine. Have checked to make sure my AVAudioPlayer object has volume set at 1.0 - it does. Can anybody help?
Here's my code
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"Soothing" ofType:#"aif"];
NSURL *playURL = [NSURL fileURLWithPath:soundPath];
NSError *error;
self.myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:playURL error:&error];
NSLog(#"About to play sound");
self.myAudioPlayer.delegate = self;
[self.myAudioPlayer prepareToPlay];
bool success = [self.myAudioPlayer play];
if (!success) {
NSLog(#"Failed to play file");
} else NSLog(#"Looks like it succeded");
OK - got it figured out. I had not configured the AVAudioSession for my app. Did something very simple as follows (copied from Apple's example code):
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError)
NSLog(#"Error setting category! %#", setCategoryError);
Sound now plays - plus learned a lot about how to control playback through screen locks, etc., which will be valuable.
Did you check if you get anything from the error?
if(error) {
NSLog( #"%#", [error localizedDescription] );
}

IOS can I use AVAudioPlayer on the appDelegate?

I have a TabBarController with two tabs and I want to play music on both tabs. Right now I have my code on the main appDelegate
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"My Song"
ofType:#"m4a"]]; // My Song.m4a
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
//audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
but I'm getting the error Program received signal: "SIGABRT" on UIApplicationMain
Is there a better way to accomplish what I'm trying to do? If this is how I should do it, where do I start checking for problems?
yes you can use AVAudioPlayer in App Delegate.
What you need to do is:-
In appDelegate.h file do:-
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AVAudioPlayer *_backgroundMusicPlayer;
BOOL _backgroundMusicPlaying;
BOOL _backgroundMusicInterrupted;
UInt32 _otherMusicIsPlaying;
Make backgroundMusicPlayer property and sythesize it.
In appDelegate.m file do:-
Add these lines in did FinishLaunching method
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
// Create audio player with background music
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:#"SplashScreen" ofType:#"wav"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer setNumberOfLoops:-1]; // Negative number means loop forever
Now implement delegate methods
#pragma mark -
#pragma mark AVAudioPlayer delegate methods
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
_backgroundMusicInterrupted = YES;
_backgroundMusicPlaying = NO;
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player {
if (_backgroundMusicInterrupted) {
[self tryPlayMusic];
_backgroundMusicInterrupted = NO;
}
}
- (void)tryPlayMusic {
// Check to see if iPod music is already playing
UInt32 propertySize = sizeof(_otherMusicIsPlaying);
AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &_otherMusicIsPlaying);
// Play the music if no other music is playing and we aren't playing already
if (_otherMusicIsPlaying != 1 && !_backgroundMusicPlaying) {
[_backgroundMusicPlayer prepareToPlay];
if (soundsEnabled==YES) {
[_backgroundMusicPlayer play];
_backgroundMusicPlaying = YES;
}
}
}

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];