In Swift, How to Let Other Apps Continue to Play Audio When My App Is Open

In Swift, how do I let other apps continue to play audio when my app is open?

Set your AVAudioSession category to Ambient.

import AVFoundation.AVAudioSession

AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)

This category is also appropriate for “play along” style apps, such as a virtual piano that a user plays while the Music app is playing. When you use this category, audio from other apps mixes with your audio. Your audio is silenced by screen locking and by the Silent switch (called the Ring/Silent switch on iPhone).

How can I allow background music to continue playing while my app still plays its sounds while using Swift

You need to set the AVAudioSession category, with one of the following value: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/index.html (AVAudioSession Class Reference).

The default value is set to AVAudioSessionCategorySoloAmbient. As you can read :

[...] using this category implies that your app’s audio is nonmixable—activating your session will interrupt any other audio sessions which are also nonmixable. To allow mixing, use the AVAudioSessionCategoryAmbient category instead.

You have to change the category, before you play your sound. To do so :

AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)

You don't need to call those line each time you play the sound. You might want to do it only once.

Music from other apps stops playing when my app starts

Try this instead:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient withOptions:0 error:nil];

Or this if above doesn't work:

[[AVAudioSession sharedInstance] setActive:NO error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];

EDIT:

If none of the above works for you, you should maybe try set another category you see fit together with AVAudioSessionCategoryOptionMixWithOthers if that works for your use-case.

Determines whether audio from this session is mixed with audio from
active sessions in other audio apps.

How to interrupt device audio to play a sound and then let the device audio continue on iOS

In theory, Apple has provided a "protocol" for interrupting and resuming background audio, and in a downloadable example, I show you what it is and prove that it works:

https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch14p653backgroundPlayerAndInterrupter

In that example, there are two projects, representing two different apps. You run both of them simultaneously. BackgroundPlayer plays sound in the background; Interrupter interrupts it, pausing it, and when it is finished interrupting, BackgroundPlayer resumes.

This, as you will see, is done by having Interrupter change its audio session category from ambient to playback while interrupting, and changing it back when finished, along with first deactivating itself entirely while sending the .notifyOthersOnDeactivation signal:

func playFile(atPath path:String) {
self.player?.delegate = nil
self.player?.stop()
let fileURL = URL(fileURLWithPath: path)
guard let p = try? AVAudioPlayer(contentsOf: fileURL) else {return} // nicer
self.player = p
// error-checking omitted

// switch to playback category while playing, interrupt background audio
try? AVAudioSession.sharedInstance().setCategory(.playback, mode:.default)
try? AVAudioSession.sharedInstance().setActive(true)

self.player.prepareToPlay()
self.player.delegate = self
let ok = self.player.play()
print("interrupter trying to play \(path): \(ok)")
}

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { // *
let sess = AVAudioSession.sharedInstance()
// this is the key move
try? sess.setActive(false, options: .notifyOthersOnDeactivation)
// now go back to ambient
try? sess.setCategory(.ambient, mode:.default)
try? sess.setActive(true)
delegate?.soundFinished(self)
}

The trouble, however, is that response to .notifyOthersOnDeactivation is entirely dependent on the other app being well behaved. My other app, BackgroundPlayer, is well behaved. This is what it does:

self.observer = NotificationCenter.default.addObserver(forName:
AVAudioSession.interruptionNotification, object: nil, queue: nil) {
[weak self] n in
guard let self = self else { return } // legal in Swift 4.2
let why = n.userInfo![AVAudioSessionInterruptionTypeKey] as! UInt
let type = AVAudioSession.InterruptionType(rawValue: why)!
switch type {
case .began:
print("interruption began:\n\(n.userInfo!)")
case .ended:
print("interruption ended:\n\(n.userInfo!)")
guard let opt = n.userInfo![AVAudioSessionInterruptionOptionKey] as? UInt else {return}
let opts = AVAudioSession.InterruptionOptions(rawValue: opt)
if opts.contains(.shouldResume) {
print("should resume")
self.player.prepareToPlay()
let ok = self.player.play()
print("bp tried to resume play: did I? \(ok as Any)")
} else {
print("not should resume")
}
@unknown default:
fatalError()
}
}

As you can see, we register for interruption notifications, and if we are interrupted, we look for the .shouldResume option — which is the result of the interrupter setting the notifyOthersOnDeactivation in the first place.

So far, so good. But there's a snag. Some apps are not well behaved in this regard. And the most non-well-behaved is Apple's own Music app! Thus it is actually impossible to get the Music app to do what you want it to do. You are better off using ducking, where the system just adjusts the relative levels of the two apps for you, allowing the background app (Music) to continue playing but more quietly.

Let other apps play background music

Set your AVAudioSession category to Ambient.

import AVFoundation

do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
try AVAudioSession.sharedInstance().setActive(true)
}
catch let error as NSError {
print(error)
}

AVAudioSession Class Reference

How to play sounds in iOS 10 when app is in the background with Swift 3

You cannot play in the background with an Ambient audio session category. Your category must be Playback.

To allow sounds from other apps to play, modify your Playback category with the Mixable option (.mixWithOthers).

(Also keep in mind that you can change your category at any time. You could have it be Ambient most of the time but switch to Playback when you know you're about to go into the background so that you can keep playing.)

EDIT Also it occurs to me that there is another possible misconception that might need clearing up. You cannot (easily) start a new sound while in the background. All that background audio allows you to do is continue playing the current sound when your app goes into the background. Once that sound stops (in the background), your app suspends and that's the end of that.

iOS: Play music from another app while camera is open and taking a picture

There has to be some code that uses the AV system for audio in the way. Check for a call like

[session addInput:audioDeviceInput];

where session is an instance of AVCaptureSession.

To demonstrate and research, you can take the Apple example AVCam (https://developer.apple.com/library/ios/samplecode/AVCam/Introduction/Intro.html) and run it from XCode. When music is playing, it will stop playing when the AVCam app starts.

Now open the source file AVCam/AVCamViewController.m and search for the line

[session addInput:audioDeviceInput];

When you delete this line or comment it out, music will continue to play when you run the app.

Off course, there may be other statements that block the sound playing in your app. Check calls to methods from AV objects and look especially for audio input and output.

How to handle background audio playing while iOS device is locked or on another application?

Playing Background Audio

An app that plays or records audio continuously (even while the app is
running in the background) can register to perform those tasks in the
background. You enable audio support from the Background modes section
of the Capabilities tab in your Xcode project. (You can also enable
this support by including the UIBackgroundModes key with the audio
value in your app’s Info.plist file.) Apps that play audio content in
the background must play audible content and not silence.

Apple reference "Playing and Recording Background Audio"

Ensuring That Audio Continues When the Screen Locks

For enabling/disabling this feature I found Activating and Deactivating Your Audio Session, I haven't tried it myself, but it looks like what you need.



Related Topics



Leave a reply



Submit