So I am creating a simple radio station app. I have coded the following and got the play / pause button switching text. I just can't work out how to access the player in the button when the func is inside ViewDidLoad. I am sure I need to set global variables?
override func viewDidAppear(_ animated: Bool) {
guard let url = URL(string: "http://stream.radiomedia.com.au:8003/stream") else {
return
}
// Create a new AVPlayer and associate it with the player view
let player = AVPlayer(url: url)
player.allowsExternalPlayback = true
player.usesExternalPlaybackWhileExternalScreenIsActive = true
// Create a new AVPlayerViewController and pass it a reference to the player.
let playerViewController = AVPlayerViewController()
playerViewController.contentOverlayView?.backgroundColor = UIColor.white
playerViewController.view.frame = CGRect (x:100, y:100, width:200, height:200)
playerViewController.player = player
self.addChild(playerViewController)
self.view.addSubview(playerViewController.view)
playerViewController.didMove(toParent: self)
playerViewController.player = player
player.play()
}
#IBAction func playVideo(_ sender: Any) {
if(playButton == false){
playButton = true;
(sender as! UIButton).setTitle("Pause", for: [])
player.pause() // does not work
}else
{
playButton = false;
(sender as! UIButton).setTitle("Play", for: [])
player.play() // does not work
}
}
class YourVC: UIViewController {
var player = AVPlayer()
}
just declare the player inside your class so that other functions can access it.
and in your viewDidApper(), change:
let player = AVPlayer(url: url)
to
self.player = AVPlayer(url: url)
then you can call player.pause() and player.play() from anywhere inside your Class.
import UIKit
import AVFoundation
class AudioPlayerVC: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("wakeUp", ofType: ".mp3"))
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
#IBAction func onPressPlayPaush(_ sender: UIButton) {
if(sender == false){
sender = true
audioPlayer.pause()
}else
{
sender = false
audioPlayer.play()
}
}
Related
I am new to ios programming, actually I need to stream video URL but i am unable to stream video URL using avplayer, but using avplayer downloaded file i am able to play.Actual problem is my file format is different
for example my file name is like this song.apa but it is song.mp4
code:
let avplayerController = AVPlayerViewController()
var avPlayer:AVPlayer?
override func viewDidLoad()
{
super.viewDidLoad()
let movieUrl = URL.init(string: "http://techslides.com/demos/sample-videos/small.3gp")
self.avPlayer = AVPlayer.init(url: movieUrl!)
self.avplayerController.player = self.avPlayer
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func playVideo(_ sender: Any)
{
self.present(self.avplayerController, animated: true) {
self.avplayerController.player?.play()
}
}
In Swift 3
import Foundation
import AVFoundation
import MediaPlayer
import AVKit
func play()
{
let player = AVPlayer(url: "Your Url")
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true)
{
playerViewController.player!.play()
}
}
You cant play this particular link (http://techslides.com/demos/sample-videos/small.3gp) using AVPlayer or AVPlayerViewController because that file is in AMR (Adaptive Multi-Rate, a format for speech) - which is not supported since iOS 4.3
Some of 3gp files can be played but only ones that have video and audio streams supported by Apple.
In Swift 3, try this code for playing video in project
import UIKit
import AVKit
import AVFoundation
import MediaPlayer
import MobileCoreServices
class VideoPlayerViewController: UIViewController,AVPlayerViewControllerDelegate {
//MARK: - Outlet -
#IBOutlet weak var viewVidioPlayer: UIView!
//MARK: - Variable
//MARK: - View Life Cycle -
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: - Action -
//for Playing Video
#IBAction func btnvideoPlayClicked(_ sender: UIButton) {
self.videoPlay()
}
func videoPlay()
{
let playerController = AVPlayerViewController()
playerController.delegate = self
let bundle = Bundle.main
let moviePath: String? = "http://techslides.com/demos/sample-videos/small.3gp"
let movieURL = URL(fileURLWithPath: moviePath!)
let player = AVPlayer(url: movieURL)
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = self.view.frame
player.play()
}
//MARK: - other Function -
func playerViewControllerWillStartPictureInPicture(_ playerViewController: AVPlayerViewController){
print("playerViewControllerWillStartPictureInPicture")
}
func playerViewControllerDidStartPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerDidStartPictureInPicture")
}
func playerViewController(_ playerViewController: AVPlayerViewController, failedToStartPictureInPictureWithError error: Error)
{
print("failedToStartPictureInPictureWithError")
}
func playerViewControllerWillStopPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerWillStopPictureInPicture")
}
func playerViewControllerDidStopPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerDidStopPictureInPicture")
}
func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_ playerViewController: AVPlayerViewController) -> Bool
{
print("playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart")
return true
}
}
I hope it's work for you,
thank you
heres an example of streaming video..
override func viewDidLoad() {
super.viewDidLoad()
let player = AVPlayer(url: URL(string: "http://techslides.com/demos/sample-videos/small.mp4")!)
let controller = AVPlayerViewController()
present(controller, animated: true) { _ in }
controller.player = player
addChildViewController(controller)
view.addSubview(controller.view)
controller.view.frame = CGRect(x: 50, y: 50, width: 300, height: 300)
controller.player = player
controller.showsPlaybackControls = true
player.isClosedCaptionDisplayEnabled = false
player.play()
}
you can use YoutubePlayerView for playing youtube videos, and for else formats you can use UIWebView. For doing so, simply use if-else block,
if movieUrl.contains("youtube.com/") {
var videoId: String = extractYoutubeId(fromLink: movieUrl)
youtubePlayerView.load(withVideoId: videoId)
} else {
webView = UIWebView(frame: CGRect(x: 0, y: 0, width: 288, height: 277))
webView.delegate = self
webView.backgroundColor = UIColor.black
webView?.loadRequest(movieUrl)
}
For Swift 3 play video from URL
//AVPlayerViewControllerDelegate // example : class TestAudioVideoVC: UIViewController,AVPlayerViewControllerDelegate
func videoPlay()
{
let playerController = AVPlayerViewController()
playerController.delegate = self
let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL! as URL)
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = CGRect(x: 0, y: 64, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 64)
playerController.showsPlaybackControls = true
player.play()
}
//MARK: - AVPlayerViewController Delegate -
func playerViewControllerWillStartPictureInPicture(_ playerViewController: AVPlayerViewController){
print("playerViewControllerWillStartPictureInPicture")
}
func playerViewControllerDidStartPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerDidStartPictureInPicture")
}
func playerViewController(_ playerViewController: AVPlayerViewController, failedToStartPictureInPictureWithError error: Error)
{
print("failedToStartPictureInPictureWithError")
}
func playerViewControllerWillStopPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerWillStopPictureInPicture")
}
func playerViewControllerDidStopPictureInPicture(_ playerViewController: AVPlayerViewController)
{
print("playerViewControllerDidStopPictureInPicture")
}
func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_ playerViewController: AVPlayerViewController) -> Bool
{
print("playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart")
return true
}
Play video in swift 5
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playVideoUsingURL(_ sender: Any) {
playGlobalVideo()
}
#IBAction func playVideoFromLocalDrive(_ sender: Any) {
playLocalVideo()
}
func playGlobalVideo() {
guard let videoURL = URL(string: "http://static.videokart.ir/clip/100/480.mp4") else {
return
}
let player = AVPlayer(url: videoURL)
let vc = AVPlayerViewController()
vc.player = player
present(vc, animated: true) {
player.play()
}
}
func playLocalVideo() {
guard let videoPath = Bundle.main.path(forResource: "movie", ofType: "mov") else {
return
}
let player = AVPlayer(url: URL.init(fileURLWithPath: videoPath))
let playCtr = AVPlayerViewController()
playCtr.player = player
present(playCtr, animated: true) {
player.play()
}
}
}
My code is supposed to play a C Major scale wave file on a button press. Hitting a separate stop button will stop playback and reset the currentTime to zero.
#IBAction func onPlayButtonClick(sender: UIButton)
{
play.enabled = false
let path = NSBundle.mainBundle().pathForResource("cmajor", ofType: "wav")!
let url = NSURL(fileURLWithPath: path)
do
{
scalePlayer = try AVAudioPlayer(contentsOfURL: url)
scalePlayer.prepareToPlay()
scalePlayer.enableRate = true
scalePlayer.rate = 0.75
scalePlayer.play()
}
catch
{
}
}
It works as intended, but how do I set the currentTime to zero when the file is finished playing? I couldn't find anything on the developer docs.
You have to set a delegate:
scalePlayer.delegate = self
Then you implement this callback
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
//set the current time here
scalePlayer.currentTime = 0
}
Update
Here is an example how you can implement this (based on your code):
class MyViewController: UIViewController, AVAudioPlayerDelegate {
#IBOutlet weak var play: UIButton!
private var scalePlayer: AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("cmajor", ofType: "wav")!
let url = NSURL(fileURLWithPath: path)
scalePlayer = try? AVAudioPlayer(contentsOfURL: url)
scalePlayer?.delegate = self
}
#IBAction func onPlayButtonClick(sender: UIButton) {
play.enabled = false
scalePlayer?.prepareToPlay()
scalePlayer?.enableRate = true
scalePlayer?.rate = 0.75
scalePlayer?.play()
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
scalePlayer?.currentTime = 0
}
}
I get my local video to load into a new view controller, but after hitting done it disappears and immediately pops back up again. I don't know if there is a way to track the notifications or what.
Here is my code:
import UIKit
import AVKit
import AVFoundation
class VideoController1: UIViewController {
var playerViewController = AVPlayerViewController()
var playerView = AVPlayer()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
let fileURL = NSURL(fileURLWithPath: "/Users/jamesjarrett/Desktop/NIMS/NIMS/NIMS/Vid2.mp4")
playerView = AVPlayer(url: fileURL as URL)
playerViewController.player = playerView
self.present(playerViewController, animated: true){
self.playerViewController.player?.play()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You put your code
let fileURL = NSURL(fileURLWithPath: "/Users/jamesjarrett/Desktop/NIMS/NIMS/NIMS/Vid2.mp4")
playerView = AVPlayer(url: fileURL as URL)
playerViewController.player = playerView
self.present(playerViewController, animated: true){
self.playerViewController.player?.play()
}
inside of ViewDidAppear for the ViewController.
ViewDidAppear() occurs when your view is presented on the screen again. So this means, that when the AVPlayer is closed, it goes back to that View, and the AVPlayer will be presented again.
You have 2 options:
Make a UIButton and an Action to that button
var button = UIButton(frame: CGRect(0, self.view.frame.height*0.9, self.view.frame.width, self.view.frame.height*0.1))
button.addTarget(self, #selector(VideoController1.playController), nil)
self.view.addSubview(button)
let fileURL = NSURL(fileURLWithPath: "/Users/jamesjarrett/Desktop/NIMS/NIMS/NIMS/Vid2.mp4")
func playController() {
playerView = AVPlayer(url: fileURL as URL)
playerViewController.player = playerView
self.present(playerViewController, animated: true){
self.playerViewController.player?.play()
}
}
-- OR --
If you want the controller to play only the first time the user sees the view, and that is it, then you can do
var played = false
func viewDidAppear() {
if(!played) {
let fileURL = NSURL(fileURLWithPath: "/Users/jamesjarrett/Desktop/NIMS/NIMS/NIMS/Vid2.mp4")
playerView = AVPlayer(url: fileURL as URL)
playerViewController.player = playerView
self.present(playerViewController, animated: true){
played = true
self.playerViewController.player?.play()
}
}
}
Don't quote me on the code above, just typed it up real quick to give you a general idea.
How would i go about making a local .mp4 file with no sound play on a loop, so it would only take up part of the screen and have no user controls. Just a looping video, sort of like a gif. I am using xcode, swift2.
class ViewController: UIViewController {
var playerViewController = AVPlayerViewController()
var playerView = AVPlayer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
var fileURL = NSURL(fileURLWithPath: "/Users/Mantas/Desktop/123/123/video-1453562323.mp4.mp4")
playerView = AVPlayer(URL: fileURL)
playerViewController.player = playerView
self.presentViewController(playerViewController, animated: true){
self.playerViewController.player?.play()
}
}
}
I have made this, it plays the video, but in full screen, i dont know how to make it only take up part of the screen and how to make it loop
Alternate version in Swift 3.0:
Add these properties:
fileprivate var player: AVPlayer? {
didSet { player?.play() }
}
fileprivate var playerObserver: Any?
Add this to your deinit:
deinit {
guard let observer = playerObserver else { return }
NotificationCenter.default.removeObserver(observer)
}
Add this function:
func videoPlayerLayer() -> AVPlayerLayer {
let fileURL = URL(fileURLWithPath: mediaPath)
let player = AVPlayer(url: fileURL)
let resetPlayer = {
player.seek(to: kCMTimeZero)
player.play()
}
playerObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil) { notification in
resetPlayer()
}
self.player = player
return AVPlayerLayer(player: player)
}
Then add to your layer wherever you feel like (viewDidLoad, viewDidAppear, viewDidFinishLayingOutSubviews):
let playerLayer = videoPlayerLayer()
playerLayer.frame = view.bounds
view.layer.insertSublayer(playerLayer, at: 0)
Adding observer when video going to finish you can make replay the video
override func viewDidAppear(animated: Bool) {
super.viewDidAppear()
var fileURL = NSURL(fileURLWithPath: "/Users/Mantas/Desktop/123/123/video-1453562323.mp4.mp4")
playerView = AVPlayer(URL: fileURL)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "playerItemDidReachEnd:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: self.playerView.currentItem) // Add observer
playerViewController.player = playerView
//amend the frame of the view
self.playerViewController.player.frame = CGRectMake(0, 0, 200, 200)
//reset the layer's frame, and re-add it to the view
var playerLayer: AVPlayerLayer = AVPlayerLayer.playerLayerWithPlayer(self.playerView)
playerLayer.frame = videoHolderView.bounds
videoHolderView.layer.addSublayer(playerLayer)
/* Full Screen
self.presentViewController(playerViewController, animated: true){
self.playerViewController.player?.play()
} */
}
func playerItemDidReachEnd(notification: NSNotification) {
self.playerView.seekToTime(kCMTimeZero)
self.playerView.play()
}
For a seemless repeating video without a black flash. Use the AVPlayerLooper like so:
private var player: AVQueuePlayer!
private var playerLayer: AVPlayerLayer!
private var playerItem: AVPlayerItem!
private var playerLooper: AVPlayerLooper!
override func viewDidLoad(){
super.viewDidLoad()
let path = Bundle.main.path(forResource: "background_cloudy", ofType: "mov")
let pathURL = URL(fileURLWithPath: path!)
let duration = Int64( ( (Float64(CMTimeGetSeconds(AVAsset(url: pathURL).duration)) * 10.0) - 1) / 10.0 )
player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: pathURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem,
timeRange: CMTimeRange(start: kCMTimeZero, end: CMTimeMake(duration, 1)) )
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
playerLayer.frame = view.layer.bounds
view.layer.insertSublayer(playerLayer, at: 1)
}
This is tested with Swift 5, I found in https://gist.github.com/lanserxt/33fd8c479185cba181497315299e0e31
import UIKit
import AVFoundation
class LoopedVideoPlayerView: UIView {
fileprivate var videoURL: URL?
fileprivate var queuePlayer: AVQueuePlayer?
fileprivate var playerLayer: AVPlayerLayer?
fileprivate var playbackLooper: AVPlayerLooper?
func prepareVideo(_ videoURL: URL) {
let playerItem = AVPlayerItem(url: videoURL)
self.queuePlayer = AVQueuePlayer(playerItem: playerItem)
self.playerLayer = AVPlayerLayer(player: self.queuePlayer)
guard let playerLayer = self.playerLayer else {return}
guard let queuePlayer = self.queuePlayer else {return}
self.playbackLooper = AVPlayerLooper.init(player: queuePlayer, templateItem: playerItem)
playerLayer.videoGravity = .resizeAspectFill
playerLayer.frame = self.frame
self.layer.addSublayer(playerLayer)
}
func play() {
self.queuePlayer?.play()
}
func pause() {
self.queuePlayer?.pause()
}
func stop() {
self.queuePlayer?.pause()
self.queuePlayer?.seek(to: CMTime.init(seconds: 0, preferredTimescale: 1))
}
func unload() {
self.playerLayer?.removeFromSuperlayer()
self.playerLayer = nil
self.queuePlayer = nil
self.playbackLooper = nil
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
self.playerLayer?.frame = self.bounds
}
}
I have created a sound player in swift with AVFoundation. I am trying to start the next song in array when the playing song is finished. I was trying to implement this code
if (audioPlayer.currentTime >= audioPlayer.duration){
var recentSong = songPlaylist[selectedSongNumber + 1]
audioPlayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath:
NSBundle.mainBundle().pathForResource(recentSong, ofType: "mp3")!), error: nil)
audioPlayer.play()
}
but I am not being able to implement this code (I do not know where to implement it).Here is my complete code
import UIKit
import AVFoundation
import AVKit
public var audioPlayer = AVPlayer()
public var selectedSongNumber = Int()
public var songPlaylist:[String] = ["song1", "song2"]
public var recentSong = "song1"
let playImage = UIImage(named: "Play.png") as UIImage!
let pauseImage = UIImage(named: "Pause.png") as UIImage!
class FirstViewController: UIViewController {
#IBOutlet weak var musicSlider: UISlider!
#IBOutlet weak var PlayPause: UIButton!
var audioPlayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath:
NSBundle.mainBundle().pathForResource(recentSong, ofType: "mp3")!), error: nil)
override func viewDidLoad() {
super.viewDidLoad()
musicSlider.maximumValue = Float(audioPlayer.duration)
var timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("updateMusicSlider"), userInfo: nil, repeats: true)
if (audioPlayer.currentTime >= audioPlayer.duration){
var recentSong = songPlaylist[selectedSongNumber + 1]
audioPlayer = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath:
NSBundle.mainBundle().pathForResource(recentSong, ofType: "mp3")!), error: nil)
audioPlayer.play()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func PlayPauseButton(sender: AnyObject) {
if (audioPlayer.playing == false){
audioPlayer.play()
PlayPause.setImage(pauseImage, forState: .Normal)
}else{
audioPlayer.pause()
PlayPause.setImage(playImage, forState: .Normal)
}
}
#IBAction func StopButton(sender: AnyObject) {
audioPlayer.stop()
audioPlayer.currentTime = 0
PlayPause.setImage(playImage, forState: .Normal)
}
#IBAction func musicSliderAction(sender: UISlider) {
audioPlayer.stop()
audioPlayer.currentTime = NSTimeInterval(musicSlider.value)
audioPlayer.play()
}
func updateMusicSlider(){
musicSlider.value = Float(audioPlayer.currentTime)
}
}
I am updating my code with something different:
import UIKit
import AVFoundation
class ViewController: UIViewController, AVAudioPlayerDelegate {
var counter = 0
var song = ["1","2","3"]
var player = AVAudioPlayer()
#IBOutlet weak var musicSlider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
musicSlider.value = 0.0
}
func updateMusicSlider(){
musicSlider.value = Float(player.currentTime)
}
#IBAction func playSong(sender: AnyObject) {
music()
}
#IBAction func sliderAction(sender: AnyObject) {
player.stop()
player.currentTime = NSTimeInterval(musicSlider.value)
player.play()
}
func music(){
var audioPath = NSBundle.mainBundle().pathForResource("\(song[counter])", ofType: "mp3")!
var error : NSError? = nil
player = AVAudioPlayer(contentsOfURL: NSURL(string: audioPath), error: &error)
musicSlider.maximumValue = Float(player.duration)
var timer = NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: Selector("updateMusicSlider"), userInfo: nil, repeats: true)
player.delegate = self
if error == nil {
player.delegate = self
player.prepareToPlay()
player.play()
}
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool)
{
println("Called")
if flag {
counter++
}
if ((counter + 1) == song.count) {
counter = 0
}
music()
}
}
You can do it this way.
Hope It will help and HERE is sample project for more Info.
You need to implement AVAudioPlayerDelegate Protocol's method:
optional func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer!, successfully flag: Bool)
Documentation link
Play your next music item here.
But I will not recommend, since AVAudioPlayer can only play one item at a time. You need to instantiate again with another music item after completion. I will suggest you to use AVQueuePlayer. Detaled answer has been given here. Hope it helps!
I created a sound player in swift with AVFoundation. I used progressView to time the song and then when it hits 0.98743 it will update to the next song automatically this is the Github link: https://github.com/ryan-wlr/MusicPlayerIOS
func updateProgressView() {
if (progressView.progress > a.advanced(by: 0.98743)) {
audioPlayerDidFinishPlayeing()
}
if audioPlayer.isPlaying {
let progress = Float(audioPlayer.currentTime/audioPlayer.duration)
progressView.setProgress(progress, animated: true)
}
}