2016-04-16 26 views
5

Tôi muốn phát âm thanh luồng từ Internet. Tôi đã viết mã mà chơi dòng nhưng nó không có bất kỳ bộ đệm vì vậy nếu tín hiệu là yếu ứng dụng ngừng chơi âm thanh. Đây là mã của tôi:Làm thế nào để đệm âm thanh bằng cách sử dụng AVPlayer trong iOS?

import UIKit 
import AVFoundation 
import MediaPlayer 
import AudioToolbox 

class ViewController: UIViewController { 

var playerItem:AVPlayerItem? 
var player:AVPlayer? 

@IBOutlet weak var PlayButton: UIButton! 

override func viewDidLoad() { 
    super.viewDidLoad() 

    var buffer = AVAudioBuffer() 
    let url = NSURL (string: "http://radio.afera.com.pl/afera64.aac") 
    playerItem = AVPlayerItem(URL: url!) 
    player = AVPlayer(playerItem: playerItem!) 

} 

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

@IBAction func PlayButtonTapped(sender: AnyObject) 
{ 
    if ((player!.rate != 0) && (player!.error == nil)) 
    { 
     player!.pause() 
     PlayButton.setImage(UIImage(named:"Play"), forState: UIControlState.Normal) 
    } 
    else 
    { 
     player!.play() 
     PlayButton.setImage(UIImage(named:"Stop"), forState:UIControlState.Normal) 
    } 
} 
} 

Tôi không biết cách đệm luồng này. Tôi đã tìm tài liệu về apple nhưng không thể tìm thấy gì trong Swift.

Tôi tìm thấy một cái gì đó như AVAudioBuffer nhưng tôi không biết cách sử dụng và nếu chính xác để giải quyết vấn đề này.

P.S. C# có tài liệu trên MSDN, là điều gì đó tương tự trên Apple trong trường hợp Swift?

+1

tài liệu Swift: https://developer.apple.com/library/ios/documentation/ Tài liệu về Swift/Conceptual/Swift_Programming_Language/TheBasics.html # // apple_ref/doc/uid/TP40014097-CH5-ID309 // iOS: https://developer.apple.com/library/ios/navigation/ – Moritz

Trả lời

7

Câu trả lời là trong việc tạo ra một đại biểu lỗi mà đưa ra một chọn mỗi khi người chơi dừng lại (Lỗi thay đổi khi kết nối mạng bị gián đoạn hoặc dòng không tải đúng):

Dưới đây là các đại biểu, chỉ bên ngoài và ở trên lớp Radioplayer tôi:

protocol errorMessageDelegate { 
func errorMessageChanged(newVal: String) 
} 

lớp:

import Foundation 
import AVFoundation 
import UIKit 

class RadioPlayer : NSObject { 

static let sharedInstance = RadioPlayer() 
var instanceDelegate:sharedInstanceDelegate? = nil 
var sharedInstanceBool = false { 
    didSet { 
     if let delegate = self.instanceDelegate { 
      delegate.sharedInstanceChanged(self.sharedInstanceBool) 
     } 
    } 
} 
private var player = AVPlayer(URL: NSURL(string: Globals.radioURL)!) 
private var playerItem = AVPlayerItem?() 
private var isPlaying = false 

var errorDelegate:errorMessageDelegate? = nil 
var errorMessage = "" { 
    didSet { 
     if let delegate = self.errorDelegate { 
      delegate.errorMessageChanged(self.errorMessage) 
     } 
    } 
} 

override init() { 
    super.init() 

    errorMessage = "" 

    let asset: AVURLAsset = AVURLAsset(URL: NSURL(string: Globals.radioURL)!, options: nil) 

    let statusKey = "tracks" 

    asset.loadValuesAsynchronouslyForKeys([statusKey], completionHandler: { 
     var error: NSError? = nil 

     dispatch_async(dispatch_get_main_queue(), { 
      let status: AVKeyValueStatus = asset.statusOfValueForKey(statusKey, error: &error) 

      if status == AVKeyValueStatus.Loaded{ 

       let playerItem = AVPlayerItem(asset: asset) 

       self.player = AVPlayer(playerItem: playerItem) 
       self.sharedInstanceBool = true 

      } else { 
       self.errorMessage = error!.localizedDescription 
       print(error!) 
      } 

     }) 


    }) 

    NSNotificationCenter.defaultCenter().addObserverForName(
     AVPlayerItemFailedToPlayToEndTimeNotification, 
     object: nil, 
     queue: nil, 
     usingBlock: { notification in 
      print("Status: Failed to continue") 
      self.errorMessage = "Stream was interrupted" 
    }) 

    print("Initializing new player") 

} 

func resetPlayer() { 
    errorMessage = "" 

    let asset: AVURLAsset = AVURLAsset(URL: NSURL(string: Globals.radioURL)!, options: nil) 

    let statusKey = "tracks" 

    asset.loadValuesAsynchronouslyForKeys([statusKey], completionHandler: { 
     var error: NSError? = nil 

     dispatch_async(dispatch_get_main_queue(), { 
      let status: AVKeyValueStatus = asset.statusOfValueForKey(statusKey, error: &error) 

      if status == AVKeyValueStatus.Loaded{ 

       let playerItem = AVPlayerItem(asset: asset) 
       //playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: &ItemStatusContext) 

       self.player = AVPlayer(playerItem: playerItem) 
       self.sharedInstanceBool = true 

      } else { 
       self.errorMessage = error!.localizedDescription 
       print(error!) 
      } 

     }) 
    }) 
} 

func bufferFull() -> Bool { 
    return bufferAvailableSeconds() > 45.0 
} 

func bufferAvailableSeconds() -> NSTimeInterval { 
    // Check if there is a player instance 
    if ((player.currentItem) != nil) { 

     // Get current AVPlayerItem 
     let item: AVPlayerItem = player.currentItem! 
     if (item.status == AVPlayerItemStatus.ReadyToPlay) { 

      let timeRangeArray: NSArray = item.loadedTimeRanges 
      if timeRangeArray.count < 1 { return(CMTimeGetSeconds(kCMTimeInvalid)) } 
      let aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue 
      //let startTime = CMTimeGetSeconds(aTimeRange.end) 
      let loadedDuration = CMTimeGetSeconds(aTimeRange.duration) 

      return (NSTimeInterval)(loadedDuration); 
     } 
     else { 
      return(CMTimeGetSeconds(kCMTimeInvalid)) 
     } 
    } 
    else { 
     return(CMTimeGetSeconds(kCMTimeInvalid)) 
    } 
} 

func play() { 
    player.play() 
    isPlaying = true 
    print("Radio is \(isPlaying ? "" : "not ")playing") 
} 

func pause() { 
    player.pause() 
    isPlaying = false 
    print("Radio is \(isPlaying ? "" : "not ")playing") 
} 

func currentlyPlaying() -> Bool { 
    return isPlaying 
} 

} 
protocol sharedInstanceDelegate { 
func sharedInstanceChanged(newVal: Bool) 
} 

RadioViewController:

import UIKit 
import AVFoundation 

class RadioViewController: UIViewController, errorMessageDelegate, sharedInstanceDelegate { 

// MARK: Properties 

var firstErrorSkip = true 
var firstInstanceSkip = true 

@IBOutlet weak var listenLabel: UILabel! 
@IBOutlet weak var radioSwitch: UIImageView! 

@IBAction func back(sender: AnyObject) { 
    print("Dismissing radio view") 
    if let navigationController = self.navigationController 
    { 
     navigationController.popViewControllerAnimated(true) 
    } 
} 

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

override func viewDidLoad() { 
    super.viewDidLoad() 

    do { 
     try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) 
     print("AVAudioSession Category Playback OK") 
     do { 
      try AVAudioSession.sharedInstance().setActive(true) 
      print("AVAudioSession is Active") 

     } catch let error as NSError { 
      print(error.localizedDescription) 
     } 
    } catch let error as NSError { 
     print(error.localizedDescription) 
    } 

    RadioPlayer.sharedInstance.errorDelegate = self 
    RadioPlayer.sharedInstance.instanceDelegate = self 

    if RadioPlayer.sharedInstance.currentlyPlaying() { 
     radioSwitch.image = UIImage(named: "Radio_Switch_Active") 
     listenLabel.text = "Click to Pause Radio Stream:" 
    } 

} 

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

func toggle() { 
    if RadioPlayer.sharedInstance.currentlyPlaying() { 
     pauseRadio() 
    } else { 
     playRadio() 
    } 
} 

func playRadio() { 
    firstErrorSkip = false 
    firstInstanceSkip = false 

    if RadioPlayer.sharedInstance.errorMessage != "" || RadioPlayer.sharedInstance.bufferFull() { 
     resetStream() 
    } else { 
     radioSwitch.image = UIImage(named: "Radio_Switch_Active") 
     listenLabel.text = "Click to Pause Radio Stream:" 
     RadioPlayer.sharedInstance.play() 
    } 
} 

func pauseRadio() { 
    RadioPlayer.sharedInstance.pause() 
    radioSwitch.image = UIImage(named: "Radio_Switch_Inactive") 
    listenLabel.text = "Click to Play Radio Stream:" 
} 

func resetStream() { 
    print("Reloading interrupted stream"); 
    RadioPlayer.sharedInstance.resetPlayer() 
    //RadioPlayer.sharedInstance = RadioPlayer(); 
    RadioPlayer.sharedInstance.errorDelegate = self 
    RadioPlayer.sharedInstance.instanceDelegate = self 
    if RadioPlayer.sharedInstance.bufferFull() { 
     radioSwitch.image = UIImage(named: "Radio_Switch_Active") 
     listenLabel.text = "Click to Pause Radio Stream:" 
     RadioPlayer.sharedInstance.play() 
    } else { 
     playRadio() 
    } 
} 

func errorMessageChanged(newVal: String) { 
    if !firstErrorSkip { 
     print("Error changed to '\(newVal)'") 
     if RadioPlayer.sharedInstance.errorMessage != "" { 
      print("Showing Error Message") 
      let alertController = UIAlertController(title: "Stream Failure", message: RadioPlayer.sharedInstance.errorMessage, preferredStyle: UIAlertControllerStyle.Alert) 
      alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil)) 

      self.presentViewController(alertController, animated: true, completion: nil) 

      pauseRadio() 

     } 
    } else { 
     print("Skipping first init") 
     firstErrorSkip = false 
    } 
} 

func sharedInstanceChanged(newVal: Bool) { 
    if !firstInstanceSkip { 
    print("Detected New Instance") 
     if newVal { 
      RadioPlayer.sharedInstance.play() 
     } 
    } else { 
     firstInstanceSkip = false 
    } 
} 

} 

Hy vọng điều này sẽ giúp :)

+0

Cảm ơn bạn! :) Tôi không hiểu một điều. Điều này: "Globals.radioURL"? Một số cài đặt chung trong dự án? Tôi có thể chỉnh sửa chúng ở đâu? –

+1

yo're welcome. :) nó chỉ là url không có gì khai báo trên toàn cầu để sử dụng mọi nơi. – Lion

+0

Làm cách nào để tôi có thể khai báo biến toàn cầu sử dụng với tiền tố "Toàn cầu"? –

0

thay đổi

playerItem = AVPlayerItem?() 

để

playerItem:AVPlayerItem? 
Các vấn đề liên quan