2015-11-03 2 views
2

Je développe une application de diffusion en continu, elle fonctionne en continu. En outre, il joue en arrière-plan lorsque vous appuyez sur le bouton «Accueil» et le bouton «verrouillage».Laisser AVPlayer continuer à jouer lorsque vous appuyez sur le bouton 'back' sur le contrôleur UINavigation dans Swift 2

L'application est intégrée dans un UINavigationController et lorsque j'appuie sur le bouton «retour» dans le UINavigationController, la lecture s'arrête. Ma question est: Comment puis-je laisser le UIViewController qui contient le AVPlayer pour rester actif lorsque vous appuyez sur le bouton «retour» dans le contrôleur de navigation de sorte que le AVPlayer continuer à diffuser?

Mon code

import UIKit 
import AVFoundation 
import MediaPlayer 
import Foundation 

class RadioFunctionViewController: UIViewController { 

@IBOutlet var playButton: UIButton! 
@IBOutlet var statusLabel: UILabel! 
var player:AVPlayer = AVPlayer() 
private let ObservatingKeyPath = "currentItem.status" 
private let PlayerStatusObservingContext = UnsafeMutablePointer<Int>(bitPattern: 1) 
private var playingState:Bool = false 


override func viewDidLoad() { 
    super.viewDidLoad() 

    setStatus(4) 
    getAudioData("http://184.107.179.162:7546/;") 
    playingState = true 


} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 


@IBAction func buttonPressed(sender: AnyObject) 
{ 
    toggle() 
} 

func getAudioData(audioURL:String) 
{ 
    player = AVPlayer(URL: NSURL(string: audioURL)!) 
    player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.Initial, context: nil) 
} 

func setStatus(rawValue:Int) 
{ 
    if rawValue == 1 
    { 
     statusLabel.textColor = UIColor.blueColor() 
     statusLabel.text = "Ready for Streaming" 
    }else if rawValue == 2 
    { 
     statusLabel.textColor = UIColor.redColor() 
     statusLabel.text = "Failed" 

    }else if rawValue == 0 
    { 
     statusLabel.textColor = UIColor.redColor() 
     statusLabel.text = "Failed to load data" 
    }else if rawValue == 3 
    { 
     statusLabel.textColor = UIColor.blueColor() 
     statusLabel.text = "Streaming" 
    }else if rawValue == 4 
    { 
     statusLabel.textColor = UIColor.purpleColor() 
     statusLabel.text = "Gather data..." 
    } 
    print("The raw value send is: \(rawValue)") 
} 

func audioBackgroundPlayback() 
{ 
    do{ 
     try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) 
    }catch { 
     print("Could not play audio in the background") 
    } 

    if (NSClassFromString("MPNowPlayingInfoCenter") != nil) 
    { 
     let artWorkImage = MPMediaItemArtwork(image: UIImage(named: "ws")!) 
     let songInfo2: [String: AnyObject] = [MPMediaItemPropertyTitle: "Wide Streamings ABC Edition", MPMediaItemPropertyArtist: "Rumbera Network", MPMediaItemPropertyAlbumTitle: "107.9 FM", MPMediaItemPropertyArtwork: artWorkImage] 

     MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo2 
     UIApplication.sharedApplication().beginReceivingRemoteControlEvents() 
    } 


} 

func toggle() 
{ 
    if playButton.titleLabel?.text == "Play" 
    { 
     print("The play option is chosen") 
     playRadio() 
    }else{ 
     print("The pause option is chosen") 
     pauseRadio() 
    } 
} 

func playRadio() 
{ 
    player.play() 
    setStatus(3) 
    playButton.setTitle("Pause", forState: UIControlState.Normal) 
    audioBackgroundPlayback() 
} 

func pauseRadio() 
{ 
    player.pause() 
    playButton.setTitle("Play", forState: UIControlState.Normal) 
} 

override func remoteControlReceivedWithEvent(event: UIEvent?) { 
    if event?.type == UIEventType.RemoteControl 
    { 
     if event?.subtype == UIEventSubtype.RemoteControlPlay 
     { 
      toggle() 
     }else if event?.subtype == UIEventSubtype.RemoteControlPause 
     { 
      pauseRadio() 
     }else if event?.subtype == UIEventSubtype.RemoteControlTogglePlayPause 
     { 
      toggle() 
     } 
    } 
} 

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) 
{ 
    if (keyPath!.containsString("status")) 
    { 
     if player.status == AVPlayerStatus.ReadyToPlay 
     { 
      player.prerollAtRate(0.001, completionHandler: {(succes:Bool)-> Void in 

       if succes{ 
        self.setStatus(1) 
        self.setStatus(3) 
        self.playRadio() 

       }else{ 
        self.setStatus(1) 
        self.setStatus(2) 
       } 

      }) 
     }else if player.status == AVPlayerStatus.Failed{ 
      self.setStatus(2) 

     }else if player.status == AVPlayerStatus.Unknown 
     { 
      self.setStatus(0) 
     } 

    } 
} 

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 
    self.navigationController?.navigationBarHidden = false 
} 

override func viewWillDisappear(animated: Bool) { 
    super.viewWillDisappear(animated) 
    self.navigationController?.navigationBarHidden = false 
    if playingState == true 
    { 
     audioBackgroundPlayback() 
     player.removeObserver(self, forKeyPath: "status") 
     print("The AVPlayer is playing in background") 
    }else{ 
     player.removeObserver(self, forKeyPath: "status") 
     print("The view Dissapear") 
    } 


} 

quelqu'un Hope pourrait me aider avec celui-ci Merci à l'avance

Répondre

2

je parviens à le fixer par faire une modification à la classe AppDelegate.

La modification dans le AppDelegate:

var player:AVPlayer = AVPlayer() 
internal var avPlayerUpdateNotification = NSNotificationCenter.defaultCenter() 
let notificationStateupdate = "RadioStationChangeUpdate" 
let radioStationChangeNSString:NSString = "RadioStationChangeNotification" 
private var isPlaying:Bool = false 
private var selectedRadioStation:String = "" 

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 
{ 
    // Override point for customization after application launch. 
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "setNewSelectedRadioStation:", name: radioStationChangeNSString as String, object: nil) 

    return true 
} 

Autres fonctions qui a été ajoutée dans la AppDelegate classe

func streamAudio(audioLink:String) 
{ 
    player = AVPlayer(URL: NSURL(string: audioLink)!) 
    player.play() 
    isPlaying = true 
} 

func play() 
{ 
    player.play() 
    isPlaying = true 
} 

func pause() 
{ 
    player.pause() 
    isPlaying = false 
} 

func getPlayerState() -> Bool 
{ 
    return isPlaying 
} 

func setCurrentSelectedRadioStation(selectedStation:String) 
{ 
    self.selectedRadioStation = selectedStation 
} 

func getCurrentSelectedRadioStation() -> String 
{ 
    return selectedRadioStation 
} 

func setNewSelectedRadioStation(notification: NSNotification) 
{ 
    let radioStation = notification.object! 

    if (radioStation.containsString("Rumbera network")) 
    { 
     if(selectedRadioStation == radioStation as! String) 
     { 
      print("Rumbera Network is already playing") 
     }else{ 
      print("Rumbera Network is selected in AppDelegate") 
      streamAudio("http://184.107.179.162:7546/;") 
      setCurrentSelectedRadioStation(radioStation as! String) 
     } 
    }else if (radioStation.containsString("RocKorsow")) 
    { 
     if(selectedRadioStation == radioStation as! String) 
     { 
      print("RocKorsow is already playing") 
     }else{ 
      print("RocKorsow is selected in AppDelegate") 
      streamAudio("http://youngfreshfast.serverroom.us:9166") 
      setCurrentSelectedRadioStation(radioStation as! String) 
     } 
    }else if (radioStation.containsString("Pause")) 
    { 
     pause() 
    }else if (radioStation.containsString("Play")) 
    { 
     play() 
    }else{ 
     print("Nothing is found") 
    } 

} 

La classe qui gère la AVPlayer:

import UIKit 
import AVFoundation 
import MediaPlayer 
import Foundation 

class RadioFunctionViewController: UIViewController { 
@IBOutlet var playButton: UIButton! 
var player:AVPlayer = AVPlayer() 
private let ObservatingKeyPath = "currentItem.status" 
private let PlayerStatusObservingContext = UnsafeMutablePointer<Int>(bitPattern: 1) 
private var playingState:Bool = false 
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 

override func viewDidLoad() { 
    super.viewDidLoad() 
    checkPlayerCurrentState() 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 


@IBAction func performAction(sender: UIButton) 
{ 
    let buttonLabel = (sender.titleLabel?.text)! 

    switch buttonLabel 
    { 
     case "Play": 
     print("The AVPlayer is playing") 
     NSNotificationCenter.defaultCenter().postNotificationName("RadioStationChangeNotification", object: NSString(string: "Play")) 
     playButton.setTitle("Pause", forState: UIControlState.Normal) 
     case "Pause": 
     print("The AVPlayer is pause") 
     NSNotificationCenter.defaultCenter().postNotificationName("RadioStationChangeNotification", object: NSString(string: "Pause")) 
     playButton.setTitle("Play", forState: UIControlState.Normal) 
    default: 
     break 

    } 
} 

func checkPlayerCurrentState() 
{ 
    let player_state = getPlayerState() 
    if player_state == true 
    { 
     print("The AVPlayer is playing") 
     playButton.setTitle("Pause", forState: UIControlState.Normal) 
    }else{ 
     print("The AVPlayer is not playing") 
     playButton.setTitle("Play", forState: UIControlState.Normal) 
    } 
} 

func getPlayerState() -> Bool 
{ 
    let state = appDelegate.getPlayerState() 
    return state 
} 

func audioBackgroundPlayback() 
{ 
    do{ 
     try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) 
    }catch { 
     print("Could not play audio in the background") 
    } 
} 

espère que mon solution pourrait aider quelqu'un qui rencontre le même problème. Merci les gars pour vos commentaires.

2

Le problème ici est que le joueur est Intégrer dans votre contrôleur

var player:AVPlayer = AVPlayer() 

Alors lorsque vous appuyez sur le bouton de retour, le contrôleur est sauté et libéré et votre lecteur avec elle. Ce que vous avez à faire est de placer la propriété du lecteur ailleurs (AppDelegate, contrôleur de navigation personnalisé par exemple) pour conserver une référence qui le gardera en vie.

+0

Ou vous pouvez faire un peu singleton comme '' AudioPlayerProvider' classe AudioPlayerProvider { let statique sharedProvider = AudioPlayerProvider() ... } ' –

+0

Il est aussi une solution. Mais si je peux, j'évite Singleton, c'est un choix personnel :). – KIDdAe

+0

@KIDdAe: J'essaie d'implémenter la fonction AVPlayer dans la classe AppDelegate. Je posterai les résultats dès que j'en aurai fini avec ma solution. – Melchior

5

AVPlayer continuera à fonctionner tant qu'il est actif. Une fois le référencement UIViewController est libéré en remontant AVPlayer sera également supprimé de la mémoire.

Je vous conseillerais de créer une classe de joueur singleton et de créer des API pour démarrer/arrêter/jouer/mettre en pause AVPlayer dans cela. Maintenant, vous pouvez y accéder de partout dans votre application.

EDIT: Pour plus de commodité OP (un exemple pour commencer):

class MyAVPlayer { 
    static let sharedInstance = MyAVPlayer() 

    var player:AVPlayer = AVPlayer() 

    func play() { 
     // Put play code here 
    } 

    func playWithURL(url : NSURL) { 
     // Put play code here 
    } 
} 

appel comme (de partout dans votre application):

MyAVPlayer.sharedInstance.playWithURL(myURL) 
+0

Merci Abhinav pour votre réponse rapide. Je vais essayer d'implémenter une classe singleton puisque je suis nouveau dans ce langage de programmation. – Melchior

+0

Toujours heureux d'aider :)! L'implémentation de singleton est une tâche assez simple. Vous pouvez vous référer à [ce blog] (https://thatthinginswift.com/singletons/) une fois. – Abhinav

+0

Cela fonctionne pour vous @Melchior – Abhinav