Play sound when app is in background or screen is locked - objective-c

I have a timer that plays a sound when time reaches 0, but now I can't understand how to fire the event in order to play the sound if the app is in background mode or the screen is locked, What I found searching on the web was to set "UIBackgroundModes" in my .plist file, and add "audio" as array member.
UIBackgroundModes Array
Item0 String audio
Then add in the app delegate the following code:
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
But the sound doesn't get played.. So I was wondering if it's possible to do something like this or I should change method
EDIT:
I imported:
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
And this is the code I use to create the sound:
AVAudioPlayer *player;
NSString *soundFilePath = [NSString stringWithFormat:#"%#/clock.mp3",
[[NSBundle mainBundle] resourcePath]];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL
error:nil];
player.numberOfLoops = -1;
dispatch_async(dispatch_get_main_queue(), ^{
[player prepareToPlay];
});
Then to play it:
[player play];

I have just a snippet of Swift code but it should be easy to convert it to Obj-C
Try to use AVPlayerItem init with URL and then set AVPlayer init with PlayerItem
let assetUrl = self.nowPlayingItem!.associatedItem!.valueForProperty(MPMediaItemPropertyAssetURL) as! NSURL
let playerItem = AVPlayerItem(URL: assetUrl)
if let player = self.player {
player.replaceCurrentItemWithPlayerItem(playerItem)
} else {
self.player = AVPlayer(playerItem: playerItem)
}
self.player!.play()
and for this line of code:
NSString *soundFilePath = [NSString stringWithFormat:#"%#/clock.mp3",
[[NSBundle mainBundle] resourcePath]];
Have you tried:
[[NSBundle mainBundle] URLForResource:#"song" withExtension:#"mp3"];

// Create a new player item
NSURL *assetUrl = [nowPlayingItem valueForProperty:MPMediaItemPropertyAssetURL];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:assetUrl];
// Either create a player or replace it
if (self.player) {
[self.player replaceCurrentItemWithPlayerItem:playerItem];
} else {
self.player = [AVPlayer playerWithPlayerItem:playerItem];
}
nowPlayingItem is here a MPMediaItem but just replace NSURL *assetUrl = [nowPlayingItem valueForProperty:MPMediaItemPropertyAssetURL]; by NSURL *assetUrl =[[NSBundle mainBundle] URLForResource:#"song" withExtension:#"mp3"];

Related

How to play audio, even when mute button is on?

I'm trying to play an audio file when a button is tapped.
If I step through my code it works, but if I just tap on the button no sound is played.
Here is my code:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
AVAudioPlayer * player;
NSString * path = [[NSBundle mainBundle] pathForResource:#"soundOne" ofType:#"mp3"];
NSURL * url = [NSURL fileURLWithPath:path];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[player play];
Is this the appropriate way to play audio? Nothing is being flagged as being deprecated.
I also see this message in the debugger:
AudioQueue: request to trim 0 + 2690 = 2690 frames from buffer containing 1152 frames
EDIT:
This code works.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"soundOne"
ofType:#"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filePath];
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:fileURL error:nil];
[self.audioPlayer prepareToPlay];
self.audioPlayer.currentTime = 0;
[self.audioPlayer play];
How can I play audio with the mute button on?
Here is the code I have tried for this:
CFStringRef state;
UInt32 propertySize = sizeof(CFStringRef);
OSStatus audioStatus = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &state);
if (audioStatus == kAudioSessionNoError) {
//NSLog(#"audio route: %#", state);
return (CFStringGetLength(state) <+ 0);
}
return NO;
Stick this before you call play:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
That should do it.

AVAudioPlayer doesn't work with (NSString *)filename

I want to implement a player that plays sounds and/or music. I have these two methods:
-(void)playSound:(int)soundIndex
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[SoundFxFilenameArray objectAtIndex:soundIndex] ofType:#"mp3"]];
if(FxPlayer)
{
[FxPlayer release];
FxPlayer = nil;
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategorySoloAmbient error:nil];
FxPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[FxPlayer play];
}
-(void)playMusic:(NSString *)filename
{
NSURL *url = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:filename ofType:#"mp3"]];
if(MusicPlayer)
{
[MusicPlayer release];
MusicPlayer = nil;
}
MusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[MusicPlayer play];
}
Now, [[SoundPlayer sharedManager] playSound:FXIndex_Default] works just fine. When I try to play music though, [[SoundPlayer sharedManager] playMusic:#"music_file_name_here" just doesn't do anything. Note that both the sound file and the music file are of the same format (mp3).
Also, the "sharedInstance" is because I implemented the singleton pattern for this audio player.
Any pointers or ideas on what is so wrong in my code so that I can play sounds but not music?
Use fileURLWithPath instead of URLWithString in playMusic:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:filename ofType:#"mp3"]];
URLWithString expects a complete URL such as "file://path/to/file.mp3" as argument, fileURLWithPath expects just a file path.

Play Audio iOS Objective-C

I'm trying to get an audio file playing in my iOS app. This is my current code
NSString *soundFilePath = [NSString stringWithFormat:#"%#/test.m4a", [[NSBundle mainBundle] resourcePath]];
NSLog(#"%#",soundFilePath);
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[audioPlayer setVolume:1.0];
audioPlayer.delegate = self;
[audioPlayer stop];
[audioPlayer setCurrentTime:0];
[audioPlayer play];
I've being checking a bunch of other posts but they all generally do the same thing. I'm not getting an error, but I don't hear any audio playing on the simulator or device.
This is the path I get for the audio file on the simulator
/Users/username/Library/Application Support/iPhone Simulator/5.1/Applications/long-numbered-thing/BookAdventure.app/test.m4a
Any help is appreciated!
Maybe you should try using the NSBundle method pathForResource:ofType: method to create the path to the file.
The following code should successfully play an audio file. I have only used it with an mp3, but I imagine it should also work with m4a. If this code does not work, you could try changing the format of the audio file. For this code, the audio file is located in the main project directory.
/* Use this code to play an audio file */
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"m4a"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops = -1; //Infinite
[player play];
EDIT
Ok, so try this:
NSString *soundFilePath = [NSString stringWithFormat:#"%#/test.m4a",[[NSBundle mainBundle] resourcePath]];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops = -1; //Infinite
[player play];
Also, make sure you do the proper imports:
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
You need to store a strong reference to 'AVAudioPlayer'
#property (strong) AVAudioPlayer *audioPlayer;
And if you are sure that your audio file is in following Bundle Resources, it should play.
Project>Build Phases>Copy
To play file with extension .caf, .m4a, .mp4, .mp3,.wav, .aif
Download following two files from GitHub
SoundManager.h
SoundManager.m
Add these files to your project
Also add audio files to resource folder (sample files)
mysound.mp3, song.mp3
Import header file in desired file
#import "SoundManager.h"
And add following two lines in -(void)viewDidLoad
[SoundManager sharedManager].allowsBackgroundMusic = YES;
[[SoundManager sharedManager] prepareToPlay];
Use following line to play sound (mysound.mp3)
[[SoundManager sharedManager] playSound:#"mysound" looping:NO];
Use following line to stop the sound (mysound.mp3)
[[SoundManager sharedManager] stopSound:#"mysound"];
Also you can play music (song.mp3) as
[[SoundManager sharedManager] playMusic:#"song" looping:YES];
And can be stop music as
[[SoundManager sharedManager] stopMusic];
Complete Documentation is on GitHub
First import this framework to your file
#import <AVFoundation/AVFoundation.h>
Then declare an instance of AVAudioPlayer.
AVAudioPlayer *audioPlayer;
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"Name of your audio file"
ofType:#"type of your audio file example: mp3"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
audioPlayer.numberOfLoops = -1;
[audioPlayer play];
To play your bundle audio file using below code if you generate the system sound ID
for(int i = 0 ;i< 5;i++)
{
SystemSoundID soundFileObject;
NSString *audioFileName = [NSString stringWithFormat:#"Alarm%d",i+1];
NSURL *tapSound = [[NSBundle mainBundle] URLForResource: audioFileName
withExtension: #"caf"];
// Store the URL as a CFURLRef instance
CFURLRef soundFileURLRef = (__bridge CFURLRef) tapSound;
// Create a system sound object representing the sound file.
AudioServicesCreateSystemSoundID (
soundFileURLRef,
&soundFileObject
);
[alarmToneIdList addObject:[NSNumber numberWithUnsignedLong:soundFileObject]];
}
You can play the sound by using below code
AudioServicesPlaySystemSound([[alarmToneIdList objectAtIndex:row]unsignedLongValue]);
To achieve this below framework need to add in your Xcode
AudioToolbox
Finally below header files are needs to be import in controller
#import AudioToolbox/AudioToolbox.h
#import AudioToolbox/AudioServices.h
Updated for Swift 4
Playing from main bundle
- iOS 11 only
import AVFoundation
var player: AVAudioPlayer?
The following code loads the sound file and plays it, returning an error if necessary.
guard let url = Bundle.main.url(forResource: "test", withExtension: "m4a") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
guard let player = player else { return }
player.play()
} catch let error {
// Prints a readable error
print(error.localizedDescription)
}
Swift 4.2
var soundFilePath = "\(Bundle.main.resourcePath ?? "")/test.m4a"
var soundFileURL = URL(fileURLWithPath: soundFilePath)
var player = try? AVAudioPlayer(contentsOf: soundFileURL)
player?.numberOfLoops = -1 //Infinite
player?.play()

background music

(using AVFoundation.framework)
#import "AVFoundation/AVFoundation.h"
So I got a problem, I tried this code first in init method of my class (that is the one that is loaded first)
NSString* soundFilePath = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
NSURL* soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops=-1;
[player play];
But it didn't work, than I decided to do it in thread:
in init method:
[NSThread detachNewThreadSelector:#selector(playMusic) toTarget:self withObject:nil];
and method itself:
-(void) playMusic {
NSString* soundFilePath = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
NSURL* soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops=-1;
[player play];
}
it is declared in *.h file of course. It also didn't work.
I tried to debug, on line
}
of playMusic method the file is played for 2 or 3 seconds and then stops. It isn't played without debug. What is the problem?
The AVAudioPlayer will be deallocated immediately. You need to retain the player.
So make the AVAudioPlayer an instance variable of the class.

Prompting AVAudioPlayer to play based on a timer

I am trying to setup a stopwatch alarm that is enabled via UISwitch. I want the alarm to be triggered after an x amount of secs after the timer has started. I have an ivar int variable (timerCount) that holds the amount of secs that has passed and I want to play a sound based on that ivar. When the timer begins and I enable the switch I would hope that the player would fire at 10 secs, but that is not the case. I know the "if statement" is the culprit because when I remove it the AVPlayer will play the wav file when the switch is enabled. I just need another set of eyeballs to look at this and figure out what I missed.
Here is the code snippet:
- (IBAction)timerSound{
if (voiceSwitch.on){
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"horn"
ofType:#"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
if (timerCount == 10)
[self.player play];
}
else {
[self.player stop];
}
}
You are looking for playAt:.
Example based on yours –
- (IBAction)valueChanged:(id)sender {
UISwitch *aSwitch = (UISwitch*)sender;
if ( aSwitch.on ) {
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"horn"
ofType:#"wav"];
NSURL *fileURL = [NSURL fileURLWithPath:soundFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
error:nil];
[audioPlayer playAtTime:(audioPlayer.deviceCurrentTime + 3)];
} else {
[audioPlayer stop];
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
[self.theSwitch setOn:NO animated:YES];
[player release];
}