71

As you see I'm streaming an audio broadcast. But when I press the home button and exit the app streaming stops or I cannot hear. How can I continue streaming in background and listen it from lock screen?

ViewController.Swift

import UIKit
import AVFoundation
import MediaPlayer
import GoogleMobileAds


    class ViewController: UIViewController, GADInterstitialDelegate {
    
        @IBOutlet weak var exitMapButton: UIButton!
        @IBOutlet weak var radarMap: UIWebView!
        var interstitial: GADInterstitial!
        func createAndLoadInterstitial() -> GADInterstitial {
            var interstitial = GADInterstitial(adUnitID: "adUnitID-XXXX")
            interstitial.delegate = self
            interstitial.loadRequest(GADRequest())
            return interstitial
        }
        
        func getAd(){
            if (self.interstitial.isReady)
            {
                self.interstitial.presentFromRootViewController(self)
                self.interstitial = self.createAndLoadInterstitial()
            }
        }
        @IBOutlet weak var ataturkButton: UIButton!
        @IBOutlet weak var sabihaButton: UIButton!
        @IBOutlet weak var esenbogaButton: UIButton!
        @IBOutlet weak var weatherButton: UIButton!
        @IBOutlet weak var statusLabel: UILabel!
        @IBOutlet weak var playButton: UIButton!
        @IBOutlet weak var webViewButton: UIButton!
        var googleBannerView: GADBannerView!
override func viewDidLoad() {
            super.viewDidLoad()
        }
class PlayerAv {
            var audioLink: String?
            var player: AVPlayer
            init(link: String) {
                self.audioLink = link
                self.player = AVPlayer(URL: NSURL(string: link))
            }
        }
        var myPlayer = PlayerAv(link: "http://somewebsite.com/abc.pls")
        var setTowerState = ""
        
        @IBAction func sliderValueChanged(sender: UISlider) {
            var currentValue = Float(sender.value)
            println(currentValue)
            myPlayer.player.volume = currentValue
        }
        @IBAction func getWeatherWindow(sender: AnyObject) {
            UIApplication.sharedApplication().openURL(NSURL(string: "http://somewebpage.com")!)
            println("Directed to weather page")
        }
        @IBAction func changeToAtaturk() {
            myPlayer.player.pause()
            myPlayer = PlayerAv(link: "http://somewebsite.com/abc.pls")
            myPlayer.audioLink == ""
            println("\(myPlayer.audioLink!)--a")
            playButton.setTitle("Pause", forState: UIControlState.Normal)
            myPlayer.player.play()
            setTowerState = "ataturk"
            statusLabel.text = "Status: Playing, LTBA"
        }
        @IBAction func changeToEsenboga() {
            myPlayer.player.pause()
            myPlayer = PlayerAv(link: "http://somewebsite.com/def.pls")
            println("\(myPlayer.audioLink!)--a")
            playButton.setTitle("Pause", forState: UIControlState.Normal)
            myPlayer.player.play()
            setTowerState = "esenboga"
            statusLabel.text = "Status: Playing, LTAC"
        }
        @IBAction func changeToSabiha() {
            myPlayer.player.pause()
            myPlayer = PlayerAv(link: "http://somewebsite.com/efg.pls")
            println("\(myPlayer.audioLink!)--a")
            playButton.setTitle("Pause", forState: UIControlState.Normal)
            myPlayer.player.play()
            setTowerState = "sabiha"
            statusLabel.text = "Status: Playing, LTFJ"
        }
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
        @IBAction func playButtonPressed(sender: AnyObject) {
            toggle()
        }
        func toggle() {
            if playButton.titleLabel?.text == "Play" {
                playRadio()
                println("Playing")
                statusLabel.text = "Status: Playing"
            } else {
                pauseRadio()
                println("Paused")
                statusLabel.text = "Status: Paused"
            }
        }
        func playRadio() {
            myPlayer.player.play()
            playButton.setTitle("Pause", forState: UIControlState.Normal)   
        }
        func pauseRadio() {
            myPlayer.player.pause()
            playButton.setTitle("Play", forState: UIControlState.Normal)
        }
    }
do it better
  • 4,627
  • 6
  • 25
  • 41

4 Answers4

179

You need to set your app Capabilities Background Modes (Audio and AirPlay) and set your AVAudioSession category to AVAudioSessionCategoryPlayback and set it active

From Xcode 11.4 • Swift 5.2

do {
    try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
    print("Playback OK")
    try AVAudioSession.sharedInstance().setActive(true)
    print("Session is Active")
} catch {
    print(error)
}

enter image description here

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 2
    @LeoDabus where do we put that code? I added that to the viewDidLoad and app delegate and it didn't work. Confused as to where it should go? – Lukesivi Nov 26 '15 at 11:17
  • @lukeslvi anywhere before you try to start playing your audio. – Leo Dabus Nov 26 '15 at 21:59
  • 1
    Hey @LeoDabus it still turns off. I'm adding it in the cellForRowAtIndexPath as well as in the App Delegate and it's not working. I also added it in the custom cell without any luck. Any ideas what could be wrong? Btw, I'm using YouTubeSDK, but I'm assuming that sound is sound and it doesn't matter. Please let me know. Thank you! – Lukesivi Dec 02 '15 at 13:15
  • it is not the same. You can't play video in the background. – Leo Dabus Dec 02 '15 at 13:46
  • 1
    But what about just the sound? @LeoDabus – Lukesivi Dec 02 '15 at 13:58
  • What do you mean? When playing the YouTube video or? I posted a question earlier (so it doesn't conflict with this question) http://stackoverflow.com/questions/34029098/playing-youtubeplayer-sound-in-background-swift @LeoDabus Btw, when I press home and then use the drag up menu to play the music it plays. So it's possible, it's about changing the state. I'm just not sure how to do that... – Lukesivi Dec 02 '15 at 14:09
  • @LeoDabus I was using EZAudio, and trying to play an audio. when I go background player stop. and I cannot play any audio after that, Any idea? – vinbhai4u Dec 21 '15 at 10:42
  • If you are streaming, you also must add the "App downloads content from the network" to the capabilities / required background modes – Tony Jan 24 '16 at 01:22
  • This solution works for me. By chance while the audio was playing an alert on my phone went off (alarm of default clock app) which stopped the audio. Is there a way to avoid even alerts from interrupting the audio? Thx – rockhammer Aug 06 '16 at 02:08
  • @Leo Dabus, thanks for your response, the code (so quick) and follow up. I'm trying to implement now and will respond with results. The option == .shouldResume is giving me a compile error saying == cannot be applied to operand of AVAudioSessionInterruptionOptions and '_' – rockhammer Aug 06 '16 at 02:30
  • @Leo Dabus, thx for follow up. I tried to add observer thus: let theSession = AVAudioSession.sharedInstance() NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.handleInterruption(_:)), name: AVAudioSessionInterruptionNotification, object: theSession) But when my alarm goes off the console is not showing "began" or "ended" – rockhammer Aug 06 '16 at 02:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120293/discussion-between-rockhammer-and-leo-dabus). – rockhammer Aug 06 '16 at 03:40
  • Perfect! But used to delete "with: .mixWithOthers", otherwise control center buttons on a lock screen disappeared. try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) – Anton Eregin Aug 08 '18 at 12:51
  • Hello How can i set all details like song name , song thumb image on lock screen as well as bottom swipe menu – Hardik Vyas Oct 24 '18 at 12:16
  • @LeoDabus I am running your code in viewDidLoad. It plays in the background, but it does not show any controls to play/stop when screen is locked. What am I missing here? https://imgur.com/he8ZUBu – bibscy Jun 10 '19 at 16:26
  • Man, running into this with XCode 12. No end in sight. Have tried everything imaginable. – TheJeff Feb 04 '21 at 03:07
  • @TheJeff this is too vague. Create a new post, add what you have tried and the issues you are facing. – Leo Dabus Feb 04 '21 at 03:17
11

Xcode 10.2.1 Swift 4

Please add the following code in your AppDelegate

func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, mode: AVAudioSessionModeDefault, options: [.mixWithOthers, .allowAirPlay])
            print("Playback OK")
            try AVAudioSession.sharedInstance().setActive(true)
            print("Session is Active")
        } catch {
            print(error)
        }
        return true
    }

Note: - Please configure options as required. E.g to stop a background audio while a video file being played add

 options: [.allowAirPlay, .defaultToSpeaker]

And don't forget to enable audio and airplay in Background mode enter image description here

Pratik
  • 676
  • 10
  • 9
  • You are a genius. This has been the only asnwer I have been able to find to make audio run in the background with a current swiftUI application. Thank you! – Nate Apr 14 '21 at 09:12
5

Only paste on the viewDidload

enter image description here

    let path = Bundle.main.path(forResource:"Bismallah", ofType: "mp3")

    do{
        try playerr = AVAudioPlayer(contentsOf: URL(fileURLWithPath: path!))
    } catch {
        print("File is not Loaded")
    }
    let session = AVAudioSession.sharedInstance()
    do{
        try session.setCategory(AVAudioSessionCategoryPlayback)
    }
    catch{
    }

    player.play()
halfer
  • 19,824
  • 17
  • 99
  • 186
M Hamayun zeb
  • 448
  • 4
  • 10
3

Swift 5 Xcode 11.2.1

Add this code where you have initialized the AudioPlayer.

audioPlayer.delegate = self
audioPlayer.prepareToPlay()
let audioSession = AVAudioSession.sharedInstance()
do{
    try audioSession.setCategory(AVAudioSession.Category.playback)
}
catch{
    fatalError("playback failed")
}
Prashant Gaikwad
  • 3,493
  • 1
  • 24
  • 26