I am building an app using PhoneGap that needs to be able to play local .mp3 files even though the phone is locked/standby.
The audio player is build in HTML5, and is working fine, but the music stops when I either close the app or turn off the phone.
I tried following the answer given in this link
UIWebView: HTML5 audio pauses in iOS 6 when app enters background
But no luck...
I did the import code at the top with the other import functions.
And I also included the AVFoundation framework to my target.
This is how the code looks in the AppDelegate.m
/**
* This is main kick off after the app inits, the views and Settings are setup here. (preferred -iOS4 and up)
*/
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
/* THE GOOD STUFF */
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
BOOL ok;
NSError *setCategoryError = nil;
ok = [audioSession setCategory:AVAudioSessionCategoryPlayback
error:&setCategoryError];
if (!ok) {
NSLog(#"%s setCategoryError=%#", __PRETTY_FUNCTION__, setCategoryError);
}
I tried in simulator and on iPhone 5.
Is anyone able to help?
Firstly you have to set your audio category in your app_name-info.plist
Then use the phonegap API media player
http://docs.phonegap.com/en/2.7.0/cordova_media_media.md.html#media.play
function playAudio(url) {
// Play the audio file at url
var my_media = new Media(url,
// success callback
function() {
console.log("playAudio():Audio Success");
},
// error callback
function(err) {
console.log("playAudio():Audio Error: "+err);
});
// Play audio
my_media.play({ playAudioWhenScreenIsLocked : true });
Notice the playAudioWhenScreenIsLocked defaults to true anyways.
Also note in the Simulator the Audio will never work in background, so you will need to test on a device.
Please mark as Answered if this helped ?
Related
Using the Plugin.AudioRecorder NuGet in Xamarin Forms / iOS, I am able to record audio on iPhone 8 but on playback it is whisper quiet. How to increase the sound volume?
In AppDelegate.cs I have:
AudioPlayer.RequestAVAudioSessionCategory (AVAudioSessionCategory.PlayAndRecord);
By default playback was via the phone's upper speaker. Directing output to the lower speaker solves the problem.
In AppDelegate.cs, add:
AudioPlayer.OnPrepareAudioSession = x =>
{
// Route audio to the lower speaker rather than the upper speaker so sound volume is not minimal
x.OverrideOutputAudioPort ( AVAudioSessionPortOverride.Speaker, out NSError error );
};
AudioPlayer.OnPrepareAudioSession was not getting called for me. An alternative solution to direct audio output to the lower speaker:
var audioSession = AVAudioSession.SharedInstance();
var success = audioSession.SetCategory(AVAudioSession.CategoryPlayAndRecord, out var error);
if (success)
{
success = audioSession.OverrideOutputAudioPort(AVAudioSessionPortOverride.Speaker, out error);
if (success)
audioSession.SetActive(true, out error);
}
I ran this code in my AppDelegate.FinishedLaunching() override
How do I make my Tags NativeScript app play sound mixed in with other app playing in background?
I have looked everywhere, please help!
My solution for this. Add this lines in app.js
var audioSession = AVAudioSession.sharedInstance();
try {
audioSession.setCategoryError(AVAudioSessionCategoryAmbient);
audioSession.setActiveError(true);
} catch(err) {
console.log("setting audioSession category failed");
}
I have an app that has been published on the iTunes App Store, and it has background mode enabled for audio.
After updating to XCode 8, I published an update for my app, after which I've found that the app stops playing whenever the screen locks. I had not made any changes to background play otherwise. Not sure if the behavior or coding requirements changed for iOS 9+
Here's what my code does:
App plist file:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>remote-notification</string>
</array>
AudioController.m
-(void)setBackgroundPlay:(bool)backgroundPlay
{
NSLog(#"setBackgroundPlay %d", backgroundPlay);
AVAudioSession *mySession = [AVAudioSession sharedInstance];
NSError *audioSessionError = nil;
if (backgroundPlay) {
// Assign the Playback category to the audio session.
[mySession setCategory: AVAudioSessionCategoryPlayback
error: &audioSessionError];
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers, // 1
sizeof (allowMixing), // 2
&allowMixing // 3
);
if (propertySetError != 0) {
NSLog (#"Error setting audio property MixWithOthers");
}
} else {
// Assign the Playback category to the audio session.
[mySession setCategory: AVAudioSessionCategoryPlayback
error: &audioSessionError];
}
if (audioSessionError != nil) {
NSLog (#"Error setting audio session category.");
}
}
The audio does continue playing when I minimize the app, and it continues playing until the screen auto-locks. Whenever the screen turns on (like when a notification is received), audio resumes, and then shuts off when the screen goes black.
As mentioned, this stuff used to work, and seems to have changed behavior after update to Xcode 8/iOS 9.
I've tried searching the forum and other places for people experiences similar issues, but haven't been able to locate anything.
Any suggestions, or a fresh pair of eyes looking at this would be appreciated!
Thanks,
Sridhar
Ok, I found the problem! Everything was ok with regard to how I had setup background audio.
The key giveaway was looking at the console of the device when the screen lock had turned on:
Jan 17 11:03:59 My-iPad Talanome[1179] : kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=1156
A little searching led me to this Technical note - https://developer.apple.com/library/content/qa/qa1606/_index.html
The key is this --
// set the mixer unit to handle 4096 samples per slice since we want to keep rendering during screen lock
UInt32 maxFPS = 4096;
AudioUnitSetProperty(mMixer, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0,
&maxFPS, sizeof(maxFPS));
I had not set my maxFramesPerSlice, and so it was defaulting to 1156, which was too small for when the auto-lock is on (which is 4096). Setting the maxFramesPerSlice to 4096 in my audio initialization ensured that I have enough for when the screen locks.
Hope this helps others who may face similar issues!
-Sridhar
I'm testing my app in XCode 6 and find an issue with AVAudioSession in iOS8.
When I call
[[AVAudioSession sharedInstance] setActive:NO error:nil];
I get the following error message:
AVAudioSession.mm:623: -[AVAudioSession setActive:withOptions:error:]:
Deactivating an audio session that has running I/O. All I/O should be
stopped or paused prior to deactivating the audio session.
In AVAudioSession.h, it says
Note that this method will throw an exception in apps linked on or after iOS 8 if the session is set inactive while it has running or paused I/O (e.g. audio queues, players, recorders, converters, remote
I/Os, etc.).
But I'm not sure how can I check if there's running I/O and how can I dispose all when I need to reset the audio session.
I solved this problem, inserting this code in the method of AVAudioPlayerDelegate.
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[audioPlayer stop];
[audioPlayer prepareToPlay];
}
where audioPlayer is a variable declared in the header of my class.
the instruction prepareToPlay should resolve your problem!
Be warned. If you are playing a movie (even with no sound and the audio track removed) then it will still create an I/O thread which will always cause the above error to be thrown.
I'm using AVAudioEngine and AVAudioPlayerNode to play sounds. I meet the same problem. My environment is iOS 10.
I use AVAudioSession.sharedInstance() to handle AVAudioSession. When I run my app in simulator everything is fine, but when I switch it to my device. It failed.
I suppose that I'm using the same session to handle recording and playing. So it may cause some strange issues. In my case, I record the sound and delay 1s to play it. So when I use stopRecordingAudio(), I add this piece of code :
if audioEngine.running {
audioEngine = AVAudioEngine() // var audioEngine = AVAudioEngine()
try! AVAudioSession.sharedInstance().setActive(false)
}
After redefining audioEngine, audioEngine had been forced to stop and session was released. Crash is never happened again.
Hope this message could help you.
I pasued My AVplayer before AVAudioSession setActive NO;
[self.audioPlayer pause];
[[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
Swift 5, IOS 12
I use AVPlayer, it does not have a prepareToPlay method. Therefore, Alessio Campanelli's answer does not solve my problem.
But I noticed the following
player.pause()
print("currentTime:", player.currentTime().seconds) //currentTime: 4.258164744
print("status:", player.status.rawValue) //status: 1 (readyToPlay)
print("timeControlStatus:", player.timeControlStatus.rawValue) //timeControlStatus: 0 (paused)
print("rate:", player.rate) //rate: 0.0
sleep(1)
print("currentTime:", player.currentTime().seconds) //currentTime: 4.261325767
print("status:", player.status.rawValue) //status: 1 (readyToPlay)
print("timeControlStatus:", player.timeControlStatus.rawValue) //timeControlStatus: 0 (paused)
print("rate:", player.rate) //rate: 0.0
After you call the pause method, the player plays the audio file for a while. Although other properties say that it is in a pause.
So the only solution I found is
player.pause()
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch let error {
print(error)
}
}
In fact, even 0.1 seconds is sufficient. This is a bad way, but I could not find anything better. If anyone knows how to check when the player stops playing the audio file, let me know.
I am implementing a C listener to Audio Session Interruption. When it is called for interruption, I would deactivate my audio session. Then when my app resumes, I would activate the audio session again. I have set a number of properties and category for my audio session, do I have to reset everything after re-activation?
Thanks in advance.
Some code for reference:
Initialization, setting category:
OSStatus error = AudioSessionInitialize(NULL, NULL, interuptListenerCallBack, (__bridge void *)(self));
UInt32 category = kAudioSessionCategory_PlayAndRecord;
error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
if (error) printf("couldn't set audio category!");
//use speaker as default
UInt32 doChangeDefaultOutput = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefaultOutput), &doChangeDefaultOutput);
//allow bluethoothInput
UInt32 allowBluetoothInput = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, sizeof(allowBluetoothInput), &allowBluetoothInput);
The interuptListenerCallBack is where I deactivate and reactive the Audio Session because of the interruption, using
OSStatus error = AudioSessionSetActive(false);
if (error) printf("couldn't deactivate audio session!");
Or
OSStatus error = AudioSessionSetActive(true);
if (error) printf("AudioSessionSetActive (true) failed");
If you are correctly using the Audio session interruption listener, then no, you should not have to reset the properties. You just need to make sure that you actually call kAudioSessionBeginInterruption and kAudioSessionEndInterruption. I am not sure what your listener looks like, but if you are doing something like this:
if (inInterruptionState == kAudioSessionBeginInterruption) {
AudioSessionSetActive(NO);
}
if (inInterruptionState == kAudioSessionEndInterruption) {
AudioSessionSetActive(YES);
}
And are following the rules of Audio Session, Then theoretically, you should not have to reset your properties.
I don't know what you are using the Audio Session for, but you could also pause and resume playback by using the:
kAudioSessionInterruptionType_ShouldResume
and
kAudioSessionInterruptionType_ShouldNotResume.
You can use these as stated in the Docs:
kAudioSessionInterruptionType_ShouldResume
Indicates that the interruption that has just ended was one for
which it is appropriate to immediately resume playback; for example,
an incoming phone call was rejected by the user.
Available in iOS 4.0 and later.
Declared in AudioSession.h.
kAudioSessionInterruptionType_ShouldNotResume
Indicates that the interruption that has just ended was one for which it is not appropriate to resume playback; for example, your app
had been interrupted by iPod playback.
Available in iOS 4.0 and later.
Declared in AudioSession.h.
You should read the docs because there is a lot of info in there about pausing, resuming, and handling interruptions for the AudioSession.
NOTE:
AudioSession has been deprecated since iOS7. Use AVAudioSession methods instead, or set Pause and Resume option by setting the constant AVAudioSessionInterruptionOptions or AVAudioSessionInterruptionType.
(Available since iOS 6)