How to add new items to AVQueuePlayer currently playing with old items - ios

Adding New Items To AVQueuePlayer Doesn't Play
I have scenarios where I'm streaming HLS audios from server. Initially I make an Array of AVPlayerItem. And initialise the AVQueuePlayer, And on button clicks it plays initial items very fine. But down the road when half of my items finishes playing I am trying to add more items at the end of list which doesn't play.
class ViewController: UIViewController, AVAudioPlayerDelegate{
let baseUrl = "********"
var player: AVQueuePlayer?
var items: [AVPlayerItem] = [];
let controller = AVPlayerViewController()
var counter = 0;
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self,
selector: #selector(animationDidFinish(_:)),
name: .AVPlayerItemDidPlayToEndTime,
object: player?.items())
}
override func viewDidAppear(_ animated: Bool) {
queueMaker()
}
#IBAction func btnTapped(_ sender: UIButton) {
let player = AVQueuePlayer(items: self.items)
let playerLayer = AVPlayerLayer(player: player)
self.view.layer.addSublayer(playerLayer)
player.play()
}
#objc func animationDidFinish(_ notification: NSNotification) {
print("HLS : AVQueuePlayer Item Finished Playing")
counter += 1
if ((items.count) - counter) < 4 {
print("HLS : Adding More Items")
addMoreItemsToQueue()
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func queueMaker() {
let listOfAyahs: [String] = ["1/1.m3u8","2/2.m3u8","3/3.m3u8","4/4.m3u8","5/5.m3u8","6/6.m3u8","7/7.m3u8"]
for item in listOfAyahs {
let stringUrl = "\(self.baseUrl)\(item)"
let url = URL(string: stringUrl)
let item = AVPlayerItem(url: url!)
items.append(item)
}
}
func addMoreItemsToQueue() {
let listOfAyahs: [String] = ["8/8.m3u8","9/9.m3u8","10/10.m3u8","11/11.m3u8","12/12.m3u8","13/13.m3u8","14/14.m3u8"]
for item in listOfAyahs {
let stringUrl = "\(self.baseUrl)\(item)"
let url = URL(string: stringUrl)
let item = AVPlayerItem(url: url!)
items.append(item)
}
}
}

You are initialising a AVQuePlayer with some items which is the base copy for the AVQuePlayer and later you are appending new AVPlayerItems to your items array, about which the AVQuePlayer is not aware of. So, update the following to function and it should work.
#IBAction func btnTapped(_ sender: UIButton) {
// UPDATE THE PLAYER's SCOPE TO GLOBAL
player = AVQueuePlayer(items: self.items)
let playerLayer = AVPlayerLayer(player: player)
self.view.layer.addSublayer(playerLayer)
player?.play()
}
And add replace insert items to the queue like this
func addMoreItemsToQueue() {
let listOfAyahs: [String] = ["8/8.m3u8","9/9.m3u8","10/10.m3u8","11/11.m3u8","12/12.m3u8","13/13.m3u8","14/14.m3u8"]
var lastItem = self.player?.items().last
for item in listOfAyahs {
let stringUrl = "\(self.baseUrl)\(item)"
let url = URL(string: stringUrl)
let item = AVPlayerItem(url: url!)
self.player?.insert(item, after: lastItem)
lastItem = item
}
}
Try and share the results.

Related

How to play a sound on iOS 11 with swift 4? And where i place The mp3 file?

I saw a lot of tutorials but when i click button (that actvivate The func playsound) The sound doesn’t play. I saw the code reccomended by stackoverflow but nothing.
I put The mp3 file info asset.xcasset. It’s right?
SWIFT 4 / XCODE 9.1
import AVFoundation
var objPlayer: AVAudioPlayer?
func playAudioFile() {
guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
// For iOS 11
objPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
// For iOS versions < 11
objPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
guard let aPlayer = objPlayer else { return }
aPlayer.play()
} catch let error {
print(error.localizedDescription)
}
}
SWIFT 4.2 / XCODE 10.1
Note that you must call
AVAudioSession.sharedInstance().setCategory() with the mode parameter in Swift 4.2.
import AVFoundation
var audioPlayer: AVAudioPlayer?
func playSound() {
if let audioPlayer = audioPlayer, audioPlayer.isPlaying { audioPlayer.stop() }
guard let soundURL = Bundle.main.url(forResource: "audio_file", withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default)
try AVAudioSession.sharedInstance().setActive(true)
audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
audioPlayer?.play()
} catch let error {
Print.detailed(error.localizedDescription)
}
}
A very simple solution.
import AVFoundation
var myAudioPlayer = AVAudioPlayer?
func playAudioFile() {
let audioFileURL = Bundle.main.url(forResource: "<name-of-file>", withExtension: "mp3/wav/m4a etc.")
do {
try myAudioPlayer = AVAudioPlayer(contentsOf: audioFileURL!)
} catch let error {
print(error.localizedDescription)
}
myAudioPlayer?.play()
}
Now, play this audio file anywhere by calling: playAudioFile()
Add your .mp3 file to Bundle
import AVFoundation
let url = Bundle.main.url(forResource: "SampleAudio", withExtension: "mp3")
let playerItem = AVPlayerItem(url: url!)
let player=AVPlayer(playerItem: playerItem)
let playerLayer=AVPlayerLayer(player: player)
playerLayer.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
self.view.layer.addSublayer(playerLayer)
player.play()
You can also put a timer to show the progress of the music played
import AVFoundation
class ViewController: UIViewController {
var player : AVAudioPlayer?
var timer : Timer?
#IBOutlet var pauseBtn: UIButton!
#IBOutlet var replayBtn: UIButton!
#IBAction func rewind2(_ sender: Any) {
}
#IBAction func forward(_ sender: Any) {
var time : TimeInterval = (player?.currentTime)!
time += 5.0
if (time > (player?.duration)!)
{
// stop, track skip or whatever you want
}
else
{
player?.currentTime = time
}
}
#IBOutlet var progress: UIProgressView!
#IBAction func playClicked(_ sender: Any) {
if player == nil {
let resource = Bundle.main.url(forResource: "audioFX", withExtension: "mp3")
do {
player = try AVAudioPlayer(contentsOf: resource!)
player?.isMeteringEnabled = true
player?.prepareToPlay()
} catch let error {
print(error)
}
}
if player != nil {
player?.play()
enableTimer()
player!.delegate = self as? AVAudioPlayerDelegate
}
}
#IBAction func pauseClicked(_ sender: Any) {
if(player != nil){
if(player?.isPlaying == true){
endTimer()
player!.pause()
pauseBtn.setTitle("Resume", for: .normal)
}else{
player!.play()
enableTimer()
pauseBtn.setTitle("Stop", for: .normal)
}
}
}
#IBAction func replayClicked(_ sender: Any) {
if player != nil{
endTimer()
player = nil
pauseBtn.setTitle("Stop", for: .normal)
playClicked(replayBtn)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func enableTimer(){
if(player != nil){
timer = Timer(timeInterval: 0.1, target: self, selector: (#selector(self.updateProgress)), userInfo: nil, repeats: true)
RunLoop.main.add(timer!, forMode: RunLoopMode(rawValue: "NSDefaultRunLoopMode"))
}
}
func endTimer(){
if(timer != nil){
timer!.invalidate()
}
}
#objc func updateProgress(){
if(player != nil){
player!.updateMeters() //refresh state
progress.progress = Float(player!.currentTime/player!.duration)
}
}
}
Simple way with Swift 4.2:
import AVFoundation
and
let soundEffect = URL(fileURLWithPath: Bundle.main.path(forResource: "btn_click_sound", ofType: "mp3")!)
var audioPlayer = AVAudioPlayer()
#IBAction func buttonClick(sender: AnyObject) {
do {
audioPlayer = try AVAudioPlayer(contentsOf: soundEffect)
audioPlayer.play()
} catch {
// couldn't load file :(
}
}

How to manage the AVAudioPlayer isPlaying in each tableviewCell?

I have a tableview and have multiple cells in tableView.
Each cell has an item of AVAudioPlayer
And I face a problem.
I don't know how to manage the AVAudioPlayer.
When I play first AVAudioPlayer, and then play second AVAudioPlayer, the sound will overlap.
How to stop first AVAudioPlayer in my customized cell, and play second AVAudioPlayer?
Thanks.
This is my customized cell:
class TableViewCell: UITableViewCell {
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var myChatBubbleView: UIView!
#IBOutlet weak var myDateLabel: UILabel!
#IBOutlet weak var mySecondLabel: UILabel!
#IBOutlet weak var myRecordPlayerBtn: MenuButton!
private var timer:Timer?
private var elapsedTimeInSecond:Int = 0
var audioPlayer:AVAudioPlayer?
var message:ChatroomMessage?
var chatroomId:String = ""
var delegate:PlayRecordDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.backgroundColor = defaultBackgroundColor
self.tintColor = defaultChatroomCheckButtonColor
myImageView.layer.masksToBounds = true
myImageView.layer.cornerRadius = defaultIconRadius
myChatBubbleView.backgroundColor = defaultChatGreenBubbleColor
myChatBubbleView.layer.cornerRadius = defaultButtonRadius
myDateLabel.textColor = defaultChatTimeColor
mySecondLabel.textColor = defaultChatTimeColor
mySecondLabel.isHidden = true
myRecordPlayerBtn.imageView?.animationDuration = 1
myRecordPlayerBtn.imageView?.animationImages = [
UIImage(named: "img_myRocordPlaying1")!,
UIImage(named: "img_myRocordPlaying2")!,
UIImage(named: "img_myRocordPlaying3")!
]
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func loadByMessage(_ message:ChatroomMessage, chatroomId:String) {
self.message = message
self.chatroomId = chatroomId
myRecordPlayerBtn.addTarget(self, action: #selector(recordPlay), for: .touchUpInside)
}
func resetRecordAnimation() {
self.myRecordPlayerBtn.imageView!.stopAnimating()
self.myRecordPlayerBtn.isSelected = false
}
func recordPlay(_ sender: UIButton) {
self.myRecordPlayerBtn.imageView?.startAnimating()
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(chatroomId)/Record/")
let fileName = message?.content.substring(from: 62)
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)
if FileManager.default.fileExists(atPath: fileURL.path) {
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
self.elapsedTimeInSecond = Int(audioDurationSeconds)
if audioPlayer?.isPlaying == true {
audioPlayer?.stop()
DispatchQueue.main.async {
self.resetTimer(second: self.elapsedTimeInSecond)
self.startTimer()
}
}
updateTimeLabel()
startTimer()
audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
audioPlayer?.delegate = self
audioPlayer?.play()
}else{
//don't have file in local
let recordUrl = URL(string: (message?.content)!)
URLSession.shared.downloadTask(with: recordUrl!, completionHandler: { (location, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
let location = location, error == nil
else { return }
do {
try FileManager.default.moveItem(at: location, to: fileURL)
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
self.elapsedTimeInSecond = Int(audioDurationSeconds)
DispatchQueue.main.async {
self.updateTimeLabel()
self.startTimer()
}
self.audioPlayer = try? AVAudioPlayer(contentsOf: fileURL)
self.audioPlayer?.delegate = self
self.audioPlayer?.play()
} catch {
print(error)
}
}).resume()
}
}
func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { (timer) in
self.elapsedTimeInSecond -= 1
self.updateTimeLabel()
})
}
func resetTimer(second:Int) {
timer?.invalidate()
elapsedTimeInSecond = second
updateTimeLabel()
}
func updateTimeLabel() {
let seconds = elapsedTimeInSecond % 60
let minutes = (elapsedTimeInSecond/60) % 60
mySecondLabel.isHidden = false
mySecondLabel.text = String(format: "%02d:%02d", minutes,seconds)
}
}
extension TableViewCell:AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(Id)/Record/")
let fileName = message?.content.substring(from: 62)
let fileURL = documentsDirectoryURL.appendingPathComponent(fileName!)
if FileManager.default.fileExists(atPath: fileURL.path) {
let asset = AVURLAsset(url: URL(fileURLWithPath: fileURL.path), options: nil)
let audioDuration = asset.duration
let audioDurationSeconds = CMTimeGetSeconds(audioDuration)
DispatchQueue.main.async {
self.resetTimer(second: Int(audioDurationSeconds))
self.myRecordPlayerBtn.imageView!.stopAnimating()
self.myRecordPlayerBtn.imageView?.image = #imageLiteral(resourceName: "img_myRocordDefault")
}
}
}
}
Probably first initialize to check if your player is playing
if audioPlayer != nil{
if audioPlayer?.isPlaying == true {
audioPlayer?.stop()
DispatchQueue.main.async {
self.resetTimer(second: self.elapsedTimeInSecond)
self.startTimer()
}
}
}
If you don't want to play two audio track at the same time, you should use a shared instance of AVAudioPlayer
It will be better for performances and you can define the instance as static var in your controller. It will be accessible in each cell.
I have developed a music palyer application, and I used a shared instance in the MusicPlayManager:
class MusicPlayManager{
var player : AVAudioPlayer?
static let sharedInstance = MusicPlayManager.init()
private override init() {
super.init()
}
// something else, such as palyNext, playPrevious methods
}
In your viewController,you can use MusicPlayManager.sharedInstance.player

How do I play many audio files one by one

I created the 4 UIButtons on the Main StoryBoard.
I would like "Button4" to implement the other buttons function in a row. That means when I press button 4, player 1 should be played first, after that player 2 and after that player 3.
However, when I press "Button4", "Button2" and "Button3" are played at same time.
fileprivate var player1:AVAudioPlayer?
fileprivate var player2:AVAudioPlayer?
fileprivate var player3:AVAudioPlayer?
let url1 = Bundle.main.bundleURL.appendingPathComponent("music1.mp3")
let url2 = Bundle.main.bundleURL.appendingPathComponent("music2.mp3")
let url3 = Bundle.main.bundleURL.appendingPathComponent("music3.mp3")
#IBAction func pushButton1(sender: UIButton) {
Player(url: url1)
}
#IBAction func pushButton2(sender: UIButton) {
Player1(url: url2)
}
#IBAction func pushButton3(_ sender: UIButton) {
Player2(url: url1, url2: url2, url3: url3)
}
//"yourButton2" and "yourButton3" is played at same time in this code at player2
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if (player === player1) {
yourButton.isSelected = false
} else if (player === player2) {
yourButton2.isSelected = false
} else if (player === player3) {
yourButton.isSelected = false
player2!.play()
yourButton2.isSelected = true
player2!.play()
yourButton3.isSelected = true
player1!.play()
}
}
func Player(url: URL) {
do {
try player1 = AVAudioPlayer(contentsOf:url)
player1!.play()
yourButton.isSelected = true
player1!.delegate = self
} catch {
print(error)
}
}
func Player1(url: URL) {
do {
try player2 = AVAudioPlayer(contentsOf:url)
player2!.play()
yourButton2.isSelected = true
player2!.delegate = self
} catch {
print(error)
}
}
func Player2(url: URL, url2: URL, url3: URL) {
do {
try player3 = AVAudioPlayer(contentsOf:url)
try player2 = AVAudioPlayer(contentsOf: url2)
try player1 = AVAudioPlayer(contentsOf: url3)
player3!.play()
yourButton.isSelected = true
player3!.delegate = self
player2!.delegate = self
player1!.delegate = self
} catch {
print(error)
}
}
Rather than using an AVAudioPlayer, how about an AVQueuePlayer?
Here's a quick example:
var files = ["file1", "file2", "file3"]
var player: AVQueuePlayer = {
var pathArray = [String]()
files.forEach { resource in
if let path = Bundle.main.path(forResource: resource, ofType: "mp3") {
pathArray.append(path)
}
}
var urlArray = [URL]()
pathArray.forEach { path in
urlArray.append(URL(fileURLWithPath: path))
}
var playerItems = [AVPlayerItem]()
urlArray.forEach { url in
playerItems.append(AVPlayerItem(url: url))
}
let player = AVQueuePlayer(items: playerItems)
player.actionAtItemEnd = AVPlayerActionAtItemEnd.advance
return player
}()
and in your button's action:
#IBAction func buttonTapped(_ sender: UIButton) {
files = ["file2", "file3", "file1"]
player.play()
}
Admittedly, this is pretty quick and dirty, but something kind of like this because we're passing the files array into the player. It shouldn't be too difficult to find more optimization for this code.
EDIT: realized I wasn't passing in an array of AVPlayerItems, so updated.
Edit....
Each of the buttons, 1, 2, 3 etc...will work but "push button 2" is a bit of a mix...
Anyway, reexplain?

Playing multiple audio files using AVAudioPlayer

I created the 3 UIButtons on the Main StoryBoard.
When I press "Button1" or "Button2" each plays an audio file ( "player 1" , "player 2".) and while the audio is playing the UIButton is set to selected.
I would like "Button3" to implement multiple functions in a row.
That means when I press "Button 3", "player 3" should be played first, after that "player 1" and after that "player 2".
However, when I press "Button3", "player 1" and "player 2" are played at same time as there is no delay for the previous to finish.
I found out setting the delegate of the AVAudioPlayer or using AVQueuePlayer would solve the problem, but I find it difficult to make changes.
fileprivate var player1:AVAudioPlayer?
fileprivate var player2:AVAudioPlayer?
fileprivate var player3:AVAudioPlayer?
#IBAction func pushButton1(sender: UIButton) {
audioPlayer1(url: url1)
}
#IBAction func pushButton2(sender: UIButton) {
audioPlayer2(url: url2)
}
#IBAction func pushButton3(_ sender: UIButton) {
audioPlayer3(url: url1, url2: url2, url3: url3)
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if (player === player1) {
yourButton1.isSelected = false
} else if (player === player2) {
yourButton2.isSelected = false
} else if (player === player3) {
//"player 1" and "player 2" are played at same time
yourButton3.isSelected = false
player1!.play()
yourButton1.isSelected = true
player2!.play()
yourButton2.isSelected = false
}
}
func audioPlayer1(url: URL) {
do {
try player1 = AVAudioPlayer(contentsOf:url)
player1!.play()
yourButton1.isSelected = true
player1!.delegate = self
} catch {
print(error)
}
}
func audioPlayer2(url: URL) {
do {
try player2 = AVAudioPlayer(contentsOf:url)
player2!.play()
yourButton2.isSelected = true
player2!.delegate = self
} catch {
print(error)
}
}
func audioPlayer3(url: URL, url2: URL, url3: URL) {
do {
try player3 = AVAudioPlayer(contentsOf:url3)
try player1 = AVAudioPlayer(contentsOf: url1)
try player2 = AVAudioPlayer(contentsOf: url2)
player3!.play()
yourButton3.isSelected = true
player3!.delegate = self
player1!.delegate = self
} catch {
print(error)
}
}
}
Changed code
var queue = AVQueuePlayer()
var items = [AVPlayerItem]()
override func viewDidLoad() {
super.viewDidLoad()
player1?.delegate = self
player2?.delegate = self
player3?.delegate = self
let asset1 = AVPlayerItem(url: url1)
let asset2 = AVPlayerItem(url: url2)
let asset3 = AVPlayerItem(url: url3)
let asset4 = AVPlayerItem(url: url4)
items = [asset1, asset2, asset3, asset4]
queue = AVQueuePlayer(items: items)
for item in queue.items() {
NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)), name: .AVPlayerItemDidPlayToEndTime, object: item)
}
}
#IBAction func pushButton3(_ sender: UIButton) {
//audioPlayer3(url: url1, url2: url2)
sender.isSelected = true
queue.play()
}
func playerItemDidReachEnd(notification: NSNotification) {
if notification.object as? AVPlayerItem == items[0] {
yourButton3.isSelected = false
yourButton1.isSelected = true
}
if notification.object as? AVPlayerItem == items[1] {
yourButton1.isSelected = false
yourButton2.isSelected = true
}
if notification.object as? AVPlayerItem == items[2] {
yourButton2.isSelected = false
yourButton4.isSelected = true
//yourButton1.isSelected = true
}
if notification.object as? AVPlayerItem == items[3] {
yourButton4.isSelected = false
print("item 3")
}
EDIT: This is the method for AVAudioPlayer
So basically:
1: Add only one player, remove the rest of the players.
2: Create an NSMutableArray with your objects that you want to play.
3: Depending on what button gets pressed, you can re-arrange the NSMutableArray objects to set the correct order as you wish. (Simply recreate the array if you want to make it easy) And start playing the firstObject (url) in the array adding it accordingly to your player.
4: When the player finished playing, you can start playing the next object adding it to your player from the NSMutableArray the same way as done above.
Following above steps will avoid having multiple players playing simultaniously, together with other benefits (like avoid loading multiple URLs at the same time etc)
You may need some variable to check the currentPlayingObject to determine which one is next, maybe an int, and check that you don't try to load a new item from the array if it is the last item playing, to avoid crash on accessing objectAtIndex that does not exist.

How to play video with AVPlayerViewController (AVKit) in Swift

How do you play a video with AV Kit Player View Controller in Swift?
override func viewDidLoad() {
super.viewDidLoad()
let videoURLWithPath = "http://****/5.m3u8"
let videoURL = NSURL(string: videoURLWithPath)
playerViewController = AVPlayerViewController()
dispatch_async(dispatch_get_main_queue()) {
self.playerViewController?.player = AVPlayer.playerWithURL(videoURL) as AVPlayer
}
}
Swift 3.x - 5.x
Necessary: import AVKit, import AVFoundation
AVFoundation framework is needed even if you use AVPlayer
If you want to use AVPlayerViewController:
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
or just AVPlayer:
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
It's better to put this code into the method: override func viewDidAppear(_ animated: Bool) or somewhere after.
Objective-C
AVPlayerViewController:
NSURL *videoURL = [NSURL URLWithString:#"https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerViewController *playerViewController = [AVPlayerViewController new];
playerViewController.player = player;
[self presentViewController:playerViewController animated:YES completion:^{
[playerViewController.player play];
}];
or just AVPlayer:
NSURL *videoURL = [NSURL URLWithString:#"https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.frame = self.view.bounds;
[self.view.layer addSublayer:playerLayer];
[player play];
Try this, definitely works for Swift 2.0
let player = AVPlayer(URL: url)
let playerController = AVPlayerViewController()
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = self.view.frame
player.play()
Swift 5+
First of all you have to define 2 variables globally inside your view controller.
var player: AVPlayer!
var playerViewController: AVPlayerViewController!
Here I'm adding player to a desired view.
#IBOutlet weak var playerView: UIView!
Then add following code to the viewDidLoad method.
let videoURL = URL(string: "videoUrl")
self.player = AVPlayer(url: videoURL!)
self.playerViewController = AVPlayerViewController()
playerViewController.player = self.player
playerViewController.view.frame = self.playerView.frame
playerViewController.player?.pause()
self.playerView.addSubview(playerViewController.view)
If you are not defining player and playerViewController globally, you won't be able to embed player.
Try This
var player:AVPlayer!
var avPlayerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
avPlayerLayer.frame = CGRectMake(your frame)
self.view.layer .addSublayer(avPlayerLayer)
var steamingURL:NSURL = NSURL(string:playerURL)
player = AVPlayer(URL: steamingURL)
player.play()
Swift 3.0 Full source code:
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController,AVPlayerViewControllerDelegate
{
var playerController = AVPlayerViewController()
#IBAction func Play(_ sender: Any)
{
let path = Bundle.main.path(forResource: "video", ofType: "mp4")
let url = NSURL(fileURLWithPath: path!)
let player = AVPlayer(url:url as URL)
playerController = AVPlayerViewController()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didfinishplaying(note:)),name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
playerController.player = player
playerController.allowsPictureInPicturePlayback = true
playerController.delegate = self
playerController.player?.play()
self.present(playerController,animated:true,completion:nil)
}
func didfinishplaying(note : NSNotification)
{
playerController.dismiss(animated: true,completion: nil)
let alertview = UIAlertController(title:"finished",message:"video finished",preferredStyle: .alert)
alertview.addAction(UIAlertAction(title:"Ok",style: .default, handler: nil))
self.present(alertview,animated:true,completion: nil)
}
func playerViewController(_ playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: #escaping (Bool) -> Void) {
let currentviewController = navigationController?.visibleViewController
if currentviewController != playerViewController
{
currentviewController?.present(playerViewController,animated: true,completion:nil)
}
}
}
Objective c
This only works in Xcode 7
Go to .h file and import AVKit/AVKit.h and
AVFoundation/AVFoundation.h. Then go .m file and add this code:
NSURL *url=[[NSBundle mainBundle]URLForResource:#"arreg" withExtension:#"mp4"];
AVPlayer *video=[AVPlayer playerWithURL:url];
AVPlayerViewController *controller=[[AVPlayerViewController alloc]init];
controller.player=video;
[self.view addSubview:controller.view];
controller.view.frame=self.view.frame;
[self addChildViewController:controller];
[video play];
Using MPMoviePlayerController :
import UIKit
import MediaPlayer
class ViewController: UIViewController {
var streamPlayer : MPMoviePlayerController = MPMoviePlayerController(contentURL: NSURL(string:"video url here"))
override func viewDidLoad() {
super.viewDidLoad()
streamPlayer.view.frame = self.view.bounds
self.view.addSubview(streamPlayer.view)
streamPlayer.fullscreen = true
// Play the movie!
streamPlayer.play()
}
}
Using AVPlayer :
import AVFoundation
var playerItem:AVPlayerItem?
var player:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "url of the audio or video")
playerItem = AVPlayerItem(URL: url!)
player=AVPlayer(playerItem: playerItem!)
let playerLayer=AVPlayerLayer(player: player!)
playerLayer.frame=CGRectMake(0, 0, 300, 50)
self.view.layer.addSublayer(playerLayer)
}
I have a play button to handle button tap.
playButton.addTarget(self, action: "playButtonTapped:", forControlEvents: .TouchUpInside)
func playButtonTapped(sender: AnyObject) {
if player?.rate == 0
{
player!.play()
playButton.setImage(UIImage(named: "player_control_pause_50px.png"), forState: UIControlState.Normal)
} else {
player!.pause()
playButton.setImage(UIImage(named: "player_control_play_50px.png"), forState: UIControlState.Normal)
}
}
I have added an observer listening for AVPlayerItemDidPlayToEndTimeNotification.
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "finishedPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
}
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
When video/audio play is finished, reset button image and notification
func finishedPlaying(myNotification:NSNotification) {
playButton.setImage(UIImage(named: "player_control_play_50px.png"), forState: UIControlState.Normal)
let stopedPlayerItem: AVPlayerItem = myNotification.object as! AVPlayerItem
stopedPlayerItem.seekToTime(kCMTimeZero)
}
a bug(?!) in iOS10/Swift3/Xcode 8?
if let url = URL(string: "http://devstreaming.apple.com/videos/wwdc/2016/102w0bsn0ge83qfv7za/102/hls_vod_mvp.m3u8"){
let playerItem = AVPlayerItem(url: url)
let player = AVPlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame=CGRect(x: 10, y: 10, width: 300, height: 300)
self.view.layer.addSublayer(playerLayer)
}
does not work (empty rect...)
this works:
if let url = URL(string: "http://devstreaming.apple.com/videos/wwdc/2016/102w0bsn0ge83qfv7za/102/hls_vod_mvp.m3u8"){
let player = AVPlayer(url: url)
let controller=AVPlayerViewController()
controller.player=player
controller.view.frame = self.view.frame
self.view.addSubview(controller.view)
self.addChildViewController(controller)
player.play()
}
Same URL...
Swift 3:
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var viewPlay: UIView!
var player : AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
let url : URL = URL(string: "http://static.videokart.ir/clip/100/480.mp4")!
player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.viewPlay.bounds
self.viewPlay.layer.addSublayer(playerLayer)
}
#IBAction func play(_ sender: Any) {
player?.play()
}
#IBAction func stop(_ sender: Any) {
player?.pause()
}
}
This worked for me in Swift 5
Just added sample video to the project from Sample Videos
Added action Buttons for playing videos from Website and Local with the following swift code example
import UIKit
import AVKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//TODO : Make Sure Add and copy "SampleVideo.mp4" file in project before play
}
#IBAction func playWebVideo(_ sender: Any) {
guard let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4") else {
return
}
// Create an AVPlayer, passing it the HTTP Live Streaming URL.
let player = AVPlayer(url: url)
let controller = AVPlayerViewController()
controller.player = player
present(controller, animated: true) {
player.play()
}
}
#IBAction func playLocalVideo(_ sender: Any) {
guard let path = Bundle.main.path(forResource: "SampleVideo", ofType: "mp4") else {
return
}
let videoURL = NSURL(fileURLWithPath: path)
// Create an AVPlayer, passing it the local video url path
let player = AVPlayer(url: videoURL as URL)
let controller = AVPlayerViewController()
controller.player = player
present(controller, animated: true) {
player.play()
}
}
}
let videoUrl = //URL: Your Video URL
//Create player first using your URL
let yourplayer = AVPlayer(url: videoUrl)
//Create player controller and set it’s player
let playerController = AVPlayerViewController()
playerController.player = yourplayer
//Final step To present controller with player in your view controller
present(playerController, animated: true, completion: {
playerController.player!.play()
})
Swift 5.0
Improved from #ingconti answer . This worked for me.
if let url = URL(string: "urUrlString"){
let player = AVPlayer(url: url)
let avController = AVPlayerViewController()
avController.player = player
// your desired frame
avController.view.frame = self.view.frame
self.view.addSubview(avController.view)
self.addChild(avController)
player.play()
}
Custom VideoPlayer using ASVideoPlayer Library from github link : https://github.com/Asbat/ASVideoPlayer
// --------------------------------------------------------
// MARK:- variables
// --------------------------------------------------------
var videoPlayer = ASVideoPlayerController()
var videoData : [VideoModel] = []
var allVideoData : [AllVideoModel] = []
var cellHeights = [IndexPath: CGFloat]()
let loadingCellTableViewCellCellIdentifier = "LoadingCellTableViewCell"
var pauseIndexPath : Int = 0
var pageNumber = 1
var index = 0
var id = ""
var titleVideo = ""
var isUpdate = false
var myVideo : [MyVideo] = []
var imgs = [UIImage]()
var activityViewController : UIActivityViewController!
private var activityIndicator = NVActivityIndicatorView(frame: CGRect(x: 5, y: 5, width: 5, height: 5), type: .circleStrokeSpin, color: .systemBlue, padding: 5)
private let refreshControl = UIRefreshControl()
// --------------------------------------------------------
// MARK:- Outlets
// --------------------------------------------------------
#IBOutlet private var tableVideo: UITableView!
#IBOutlet private var _btnBack: UIButton!
#IBOutlet var _btnide: UIButton!
// ---------------------------------------------------------
// MARK:- Lifecycle
// ---------------------------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
self._btnide.isHidden = true
tableVideo.rowHeight = UITableView.automaticDimension
tableVideo.separatorStyle = .none
tableVideo.delegate = self
tableVideo.dataSource = self
tableVideo.register(UINib(nibName: "VideoPlayerTableCell", bundle: nil), forCellReuseIdentifier: "VideoPlayerTableCell")
let cellNib = UINib(nibName:loadingCellTableViewCellCellIdentifier, bundle: nil)
tableVideo.register(cellNib, forCellReuseIdentifier: loadingCellTableViewCellCellIdentifier)
navigationController?.navigationBar.isHidden = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo)
tableVideo.scrollToRow(at: IndexPath(row: index, section: 0), at: .none, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tableVideo.scrollToRow(at: IndexPath(row: pauseIndexPath, section: 0), at: .none, animated: true)
puasVideoWhenPushVC(index: pauseIndexPath)
NotificationCenter.default.removeObserver(self)
if tableVideo.isHidden == true {
}
}
#IBAction func _onTapBackBtnAction(_ sender: UIButton) {
tableVideo.scrollToRow(at: IndexPath(row: pauseIndexPath, section: 0), at: .none, animated: true)
self.puasVideoWhenPushVC(index: pauseIndexPath)
navigationController?.popViewController(animated: true)
navigationController?.navigationBar.isHidden = false
}
// ---------------------------------------------------------------------
// MARK:- TableView Delegate & DataSource
// ---------------------------------------------------------------------
extension VideoPlayerVC :
UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isUpdate{
return videoData.count
}else{
return allVideoData.count
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if tableView == tableVideo {
return view.bounds.height
}else {
return UITableView.automaticDimension
}
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if tableView == tableVideo {
if let videoCell = cell as? ASAutoPlayVideoLayerContainer, let _ = videoCell.videoURL {
ASVideoPlayerController.sharedVideoPlayer.removeLayerFor(cell: videoCell)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableVideo.dequeueReusableCell(withIdentifier: "VideoPlayerTableCell", for: indexPath) as! VideoPlayerTableCell
if isUpdate{
self.id = videoData[indexPath.row].id ?? ""
cell.configureCell(videoUrl: videoData[indexPath.row].videoLink )
}else{
self.id = allVideoData[indexPath.row].id ?? ""
cell.configureCell(videoUrl: allVideoData[indexPath.row].videoLink)
}
cell.btnPlayPause.isSelected = false
cell.btnPlayPause.tag = indexPath.row
cell.btnPlayPause.addTarget(self, action: #selector(didTapPlayPauseButton(_:)), for: .touchUpInside)
cell.btnPlayPause.setImage(UIImage(named: ""), for: .normal)
cell.btnPlayPause.setImage(UIImage(named: "btn_play_video"), for: .selected)
cell.btnUseNow.tag = indexPath.row
cell.btnUseNow.addTarget(self, action: #selector(btnUseNowTapped(sender:)), for: .touchUpInside)
cell.btnShare.tag = indexPath.row
cell.btnShare.addTarget(self, action: #selector(btnShareTapped(sender:)), for: .touchUpInside)
cell.btnSave.tag = indexPath.row
cell.btnSave.addTarget(self, action: #selector(btnSaveTapped(sender:)), for: .touchUpInside)
pauseIndexPath = indexPath.row
return cell
}
#objc func btnUseNowTapped(sender: UIButton){
self._btnide.isHidden = false
self.pausePlayeVideos()
let editVC = EditVideoVC()
var fileName : String = kEmptyString
if self.isUpdate{
editVC.videoString = self.videoData[sender.tag].videoLink ?? kEmptyString
editVC.id = self.videoData[sender.tag].id ?? kEmptyString
editVC.titleVideo = self.videoData[sender.tag].title ?? kEmptyString
fileName = self.videoData[sender.tag].videoZip ?? kEmptyString
guard !FileManager.isExist(id: self.videoData[sender.tag].id ?? kEmptyString) else{
print("File Downloaded")
self.puasVideoWhenPushVC(index: sender.tag)
self.navigationController?.pushViewController(editVC, animated: true)
return }
FileManager.download(id: self.videoData[sender.tag].id ?? kEmptyString, url: fileName) { (url) in
guard url != nil else {
print("not download")
return
}
self.puasVideoWhenPushVC(index: sender.tag)
self.navigationController?.pushViewController(editVC, animated: true)
}
}
else{
editVC.videoString = self.allVideoData[sender.tag].videoLink ?? kEmptyString
editVC.id = self.allVideoData[sender.tag].id ?? kEmptyString
editVC.titleVideo = self.allVideoData[sender.tag].title ?? kEmptyString
fileName = self.allVideoData[sender.tag].videoZip ?? kEmptyString
guard !FileManager.isExist(id: self.allVideoData[sender.tag].id ?? kEmptyString) else{
print("File Downloaded")
self.puasVideoWhenPushVC(index: sender.tag)
self.navigationController?.pushViewController(editVC, animated: true)
return }
FileManager.download(id: self.allVideoData[sender.tag].id ?? kEmptyString, url: fileName) { (url) in
guard url != nil else {
print("not download")
return
}
self.puasVideoWhenPushVC(index: sender.tag)
self.navigationController?.pushViewController(editVC, animated: true)
}
}
}
#objc func btnShareTapped(sender: UIButton){
if self.isUpdate{
let video = ["\(String(describing: self.videoData[sender.tag].videoLink))"]
self.activityViewController = UIActivityViewController(activityItems: video, applicationActivities: nil)
self.activityViewController.setValue("Video Share", forKey: "subject")
self.activityViewController.popoverPresentationController?.sourceView = self.view
self.activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToTwitter, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact,UIActivity.ActivityType.copyToPasteboard,UIActivity.ActivityType.mail,UIActivity.ActivityType.markupAsPDF,UIActivity.ActivityType.message,UIActivity.ActivityType.postToFacebook,UIActivity.ActivityType.postToFlickr,UIActivity.ActivityType.postToTencentWeibo,UIActivity.ActivityType.postToVimeo,UIActivity.ActivityType.postToWeibo,UIActivity.ActivityType.saveToCameraRoll]
self.present(self.activityViewController, animated: true, completion: nil)
}
else{
let categoryVideo = ["\(String(describing: self.allVideoData[sender.tag].videoLink))"]
self.activityViewController = UIActivityViewController(activityItems: categoryVideo, applicationActivities: nil)
self.activityViewController.setValue("Video Share", forKey: "subject")
self.activityViewController.popoverPresentationController?.sourceView = self.view
self.activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToTwitter]
self.present(self.activityViewController, animated: true, completion: nil)
}
}
#objc func btnSaveTapped(sender: UIButton){
if self.isUpdate{
self.downloadVideos(video: self.videoData[sender.tag].videoLink ?? kEmptyString)
}else{
self.downloadVideos(video: self.allVideoData[sender.tag].videoLink ?? kEmptyString)
}
}
private func downloadVideos(video : String){
Alamofire.request(video).downloadProgress(closure : { (progress) in
}).responseData{ (response) in
///# Create folder in documetn directory #///
if let data = response.result.value{
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("Videos")
if !FileManager.default.fileExists(atPath: path) {
try! FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
}
let fileURL = URL(fileURLWithPath:path).appendingPathComponent("\(self.id)/\(self.titleVideo)/output.mp4")
print(fileURL)
do{
try data.write(to: fileURL, options: .atomic)
}catch{
print("could not download")
}
print(fileURL)
}
}
}
// ----------------------------------------------------------------------
// MARK:- Scrollview Method
// ----------------------------------------------------------------------
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView == tableVideo {
pauseIndexPath = Int(scrollView.contentOffset.y / scrollView.frame.size.height)
pausePlayeVideos()
}
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if scrollView == tableVideo {
if !decelerate {
pausePlayeVideos()
}
}
}
// ----------------------------------------------------------------------
// MARK:- Function Pause & Play Button
// ----------------------------------------------------------------------
func puasVideoWhenPushVC (index : NSInteger) {
if isUpdate{
guard let cell = tableVideo.cellForRow(at: IndexPath(row: index, section: 0)) as? VideoPlayerTableCell else { return }
ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: videoData[index].videoLink ?? "")
}
else{
guard let cell = tableVideo.cellForRow(at: IndexPath(row: index, section: 0)) as? VideoPlayerTableCell else { return }
ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: allVideoData[index].videoLink ?? "")
}
}
#objc func pausePlayeVideos(){
ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo)
}
#objc func appEnteredFromBackground() {
ASVideoPlayerController.sharedVideoPlayer.pausePlayeVideosFor(tableView: tableVideo, appEnteredFromBackground: true)
}
#objc func didTapPlayPauseButton(_ sender: UIButton) {
guard let cell = tableVideo.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? VideoPlayerTableCell else { return }
if sender.isSelected {
if isUpdate{
ASVideoPlayerController.sharedVideoPlayer.playVideo(withLayer: cell.videoLayer, url: videoData[sender.tag].videoLink ?? "")
}else{
ASVideoPlayerController.sharedVideoPlayer.playVideo(withLayer: cell.videoLayer, url: allVideoData[sender.tag].videoLink ?? "")
}
} else {
if isUpdate{
ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: videoData[sender.tag].videoLink ?? "")
}else{
ASVideoPlayerController.sharedVideoPlayer.pauseVideo(forLayer: cell.videoLayer, url: allVideoData[sender.tag].videoLink ?? "")
}
}
sender.isSelected = !sender.isSelected
}
Swift 5
#IBAction func buttonPressed(_ sender: Any) {
let videoURL = course.introductionVideoURL
let player = AVPlayer(url: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
present(playerViewController, animated: true, completion: {
playerViewController.player!.play()
})
// here the course includes a model file, inside it I have given the url, so I am calling the function from model using course function.
// also introductionVideoUrl is a URL which I declared inside model .
var introductionVideoURL: URL
Also alternatively you can use the below code instead of calling the function from model
Replace this code
let videoURL = course.introductionVideoURL
with
guard let videoURL = URL(string: "https://something.mp4) else {
return

Resources