2015-11-03 31 views
2

我正在開發Radio Streaming應用程序,它流傳輸正常。當按下'Home'按鈕和'lock'按鈕時,它也會在後臺播放。在Swift 2中按下UINavigation Controller上的'後退'按鈕時,讓AVPlayer繼續播放

該應用程序被嵌入到UINavigationController中,當我按下UINavigationController中的「後退」按鈕時,它將停止播放。 我的問題是:如何在按下導航控制器中的「後退」按鈕時讓包含AVPlayerUIViewController保持活動狀態,以便AVPlayer繼續流式傳輸?

我的代碼

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") 
    } 


} 

希望有人能夠幫助我走出這個 預先感謝

回答

2

我管理由修復它對AppDelegate類進行一些修改。

改造成的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 
} 

其他功能已添加到AppDelegate類

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") 
    } 

} 

處理該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") 
    } 
} 

希望我解決方案可以幫助遇到同樣問題的人。 感謝球員們的反饋。

2

這裏的問題是,玩家在控制器中嵌入

var player:AVPlayer = AVPlayer() 

所以當您按下後退按鈕時,控制器會彈出並釋放,您的播放器也隨之釋放。 你必須做的是把播放器的屬性放在別的地方(AppDelegate,例如自定義導航控制器)來保存它的引用,以保持它的活力。

+0

或者你可以做一些單身像''AudioPlayerProvider'類AudioPlayerProvider { 靜態令sharedProvider = AudioPlayerProvider() ... }' –

+0

這也是一個解決方案。但如果可以的話,我避免辛格爾頓,這是個人選擇:)。 – KIDdAe

+0

@KIDdAe:我正在嘗試將AVPlayer函數實現到AppDelegate類中。我會在完成我的解決方案後立即發佈結果。 – Melchior

5

AVPlayer只要有效就會繼續工作。一旦引用UIViewController被彈出釋放AVPlayer也將從內存中丟棄。

我會建議你創建一個單身玩家類,並創建API來啓動/停止/播放/暫停AVPlayer。現在,您可以從應用程序的任何地方全局訪問它。

編輯:對於OP方便(樣本入手):

class MyAVPlayer { 
    static let sharedInstance = MyAVPlayer() 

    var player:AVPlayer = AVPlayer() 

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

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

這樣稱呼它(在應用程序的任何地方):

MyAVPlayer.sharedInstance.playWithURL(myURL) 
+0

感謝Abhinav爲您的快速回復。我將嘗試實現一個單例類,因爲我對這種編程語言很陌生。 – Melchior

+0

總是樂於幫助:)!實現單身人士是一項相當簡單的任務。你可以參考一下[這個博客](https://thatthinginswift.com/singletons/)。 – Abhinav

+0

爲你工作@Melchior – Abhinav

相關問題