I am trying to play a video inside a view controller when I enter it, but a get one error, listed below.Not too familiar with video playback, so is it supposed to be in a viewcontroller and how do I fix that error?The video is stored in xcode. Thanks.
import UIKit
import MediaPlayer
import AVFoundation
class AuroraViewController: UIViewController {
#IBOutlet var AuroraViewController: UIView!
var moviePlayer: AVPlayer?
private func playVideo() {
if let path = NSBundle.mainBundle().pathForResource("Aurora", ofType:"mp4") {
let url = NSURL(fileURLWithPath: path)
The line below is where I get the error of: Type of expression is ambiguous without more context
moviePlayer = AVPlayer(contentURL: url) {
self.moviePlayer = moviePlayer
moviePlayer.AuroraViewController.frame = self.AuroraViewController.bounds
moviePlayer.prepareToPlay()
moviePlayer.scalingMode = .AspectFill
self.AuroraViewController.addSubview(moviePlayer.view)
}
} else {
debugPrint("Ops, something wrong when playing video.m4v")
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
playVideo()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
UPDATE Correct code:
import UIKit
import AVFoundation
import AVKit
class AuroraViewController: AVPlayerViewController {
private func playVideo() {
if let path = NSBundle.mainBundle().pathForResource("Aurora", ofType: "mp4") {
let url = NSURL(fileURLWithPath: path)
player = AVPlayer(URL: url)
}
else {
println("Oops, could not find resource Aurora.mp4")
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
}
This was a 'total re-write'.
The following did the job:
Add "AVKit.framework" to the "Build Phases" -> "Link Binary With Libraries" in Project settings.
In Storyboard, change the identity of your UIViewController to be AuroraViewController.
The resulting code then is all that's needed:
import UIKit
import AVFoundation
import AVKit
class AuroraViewController: AVPlayerViewController {
private func playVideo() {
if let path = NSBundle.mainBundle().pathForResource("Aurora", ofType: "mp4") {
let url = NSURL(fileURLWithPath: path)
player = AVPlayer(URL: url)
}
else {
println("Oops, could not find resource Aurora.mp4")
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
}
Related
I wrote this code for iOS to play a song, however I'm not sure how to write the code to play multiple songs.
This is the line of code for a song:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVAudioPlayer = AVAudioPlayer()
#IBAction func play(_ sender: AnyObject)
{
player.play()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
do
{
let audioPath = Bundle.main.path(forResource: "Ken", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
}
catch
{
//ERROR
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You actually can play it with just two instances of the AVAudioPlayer resp. every sound file needs it's own AVAudioPlayer if you want to play them simultaneously.
I already wrote an answer, so I will post even there is already a correct answer. What palme said is correct. You could use multiple AVAudioPlayer instances to play multiple sounds simultaneously:
import UIKit
import AVFoundation
class ViewController: UIViewController {
let paths = ["a","b"]
var sounds = [AVAudioPlayer]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
for path in paths {
do
{
let audioPath = Bundle.main.path(forResource: path, ofType: "mp3")
let player = try AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
sounds.append(player)
}
catch
{
//ERROR
}
}
for sound in sounds {
sound.play()
}
}
}
I am very new to coding and have no experience.
I have found a way to make a video play but it autoplays / autopens. I need the video to only open and play when a button is pressed. Please can someone help me tweak my code to do this.
This is my current code:
import UIKit
import UIKit
import AVKit
import AVFoundation
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/MorganEvans/Documents/Apps/Warm Up/Video View/Video View/ViewController.swift")
playerview = AVPlayer(URL: fileURL)
playerviewcontroller.player = playerview
self.presentViewController(playerviewcontroller, animated: true){
self.playerviewcontroller.player?.play()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try this:
#IBAction func playMusic(sender: AnyObject) {
var fileURL = NSURL(fileURLWithPath:"/Users/MorganEvans/Documents/Apps/Warm Up/Video View/Video View/ViewController.swift")
playerview = AVPlayer(URL: fileURL)
playerviewcontroller.player = playerview
self.presentViewController(playerviewcontroller, animated: true){
self.playerviewcontroller.player?.play()
}
}
You can simply put it anywhere in your ViewController, as long as it is not inside another function.
Then connect it with a button in your storyboard:
this is how a button would set up to look, this example is pulling a movie from firebase but other than that this is how it would look
#IBAction func playV(sender: UIButton) {
let amovieUrl:NSURL? = NSURL(string: "https://firebasestorage.googleapis.com/v0/b/messenger-test-d225b.appspot.com/o/test%2FTestVideo.mov?alt=media&token=bd4ccba3-b446-43bc-809e-b1152aa3c2ff")
if let aurl = amovieUrl {
self.avPlayer = AVPlayer(url: aurl as URL)
self.avPlayerViewController.player = self.avPlayer
self.present(self.avPlayerViewController, animated: true) { () -> Void in
self.avPlayerViewController.player?.play()
}
}
}
Create an Action Connection as explained here.
Move that code in viewDidAppear to the action you created in step 1.
Profit.
Also, you don't need those default implementation for viewDidLoad and didReceiveMemoryWarning:
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
var playerviewcontroller = AVPlayerViewController()
var playerview = AVPlayer ()
#IBAction func yourActionForButton(sender: UIButton) {
// Your code.
}
First of all, I just want to let you know I'm a newbie in iOS programming ;)
I would like to know if the following scenario is possible or which way I need to update my code to make it work.
I would like to play an audio file located in the player class file within the ViewController file.
I added the file "test.wav" to the root of project.
My problem
When I play the sound by tapping a button, the program can't find the sound file. I have the following error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Main swift file: ViewController.swift
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player1: Player!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playAudio(sender: AnyObject) {
player1.playAudioFile()
}
}
Class file: Player.swift
import Foundation
import AVFoundation
class Player {
// Variables
var vc: ViewController!
var audioFile: AVAudioPlayer!
// Initializer
init (){
}
// Methods
func playAudioFile() {
if audioFile.playing {
audioFile.stop()
} else {
audioFile.play()
}
}
// Intialize ViewController
init (vc:ViewController!) {
// Set path for the attack sound
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
let audioFileURL = NSURL(fileURLWithPath: audioSnd!)
do {
try audioFile = AVAudioPlayer(contentsOfURL: audioFileURL, fileTypeHint: nil)
audioFile.prepareToPlay()
} catch let err as NSError {
print(err.debugDescription)
}
}
}
More information
My program has a class "Player", with subclasses such as "Human" and "Monster".
By default, my class player has some audio files for attacks, dying, etc.
Under some conditions, the "player" can become a human or a monster and get custom attack and dying sounds.
Thanks a lot for your help! ;)
Why are you initializing you player with a viewController ? You dont need that.
Change the Player class to:
import Foundation
import AVFoundation
class Player {
// Variables
var audioFile: AVAudioPlayer!
// Initializer
init() {
// Set path for the attack sound
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
let audioFileURL = NSURL(fileURLWithPath: audioSnd!)
do {
try audioFile = AVAudioPlayer(contentsOfURL: audioFileURL, fileTypeHint: nil)
audioFile.prepareToPlay()
} catch let err as NSError {
print(err.debugDescription)
}
}
// Methods
func playAudioFile() {
if audioFile.playing {
audioFile.stop()
} else {
audioFile.play()
}
}
}
And your ViewController.swift to:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player1: Player!
override func viewDidLoad() {
super.viewDidLoad()
// Note, that you need to initialize the player1 variable
player1 = Player()
}
#IBAction func playAudio(sender: AnyObject) {
player1.playAudioFile()
}
}
Swift is functional programming, so it is way better to separate the audio operation and viewController into different file/class. Then they could be reused in any scenarios.
Audio part
import AVFoundation
class AudioPlayer {
// Singleton to keep audio playing anywhere
static let shared = AudioPlayer()
var player: AVAudioPlayer?
private init() {}
func play(url: URL) {
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
} catch {
print("error occurred")
}
}
}
ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func playAudio(sender: AnyObject) {
let audioSnd = NSBundle.mainBundle().pathForResource("test", ofType: "wav")
// don't use force unwrap
guard let audioFileURL = NSURL(fileURLWithPath: audioSnd) else { return }
// call the shared instance here
AudioPlayer.shared.play(url: url)
}
}
I have imported both mediaPlayer and AVfoundation
class AuroraViewController: UIViewController {
var moviePlayer: AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func playVideo() {
if let
path = NSBundle.mainBundle().pathForResource("Aurora", ofType:"mp4"),
url = NSURL(fileURLWithPath: path),
moviePlayer = AVPlayer(contentURL: url) {
self.moviePlayer = moviePlayer
moviePlayer.view.frame = self.view.bounds
moviePlayer.prepareToPlay()
moviePlayer.scalingMode = .AspectFill
self.view.addSubview(moviePlayer.view)
} else {
debugPrint("oops, something wrong when playing video.m4v")
}
}
I Get an error about the 'if let': Initializer for conditional binding must have Optional type, not 'NSURL'. Is there a different way to do this?
UPDATE Correct code:
import UIKit
import AVFoundation
import AVKit
class myClass: AVPlayerViewController {
private func playVideo() {
if let path = NSBundle.mainBundle().pathForResource("Video Name", ofType: "mp4") {
let url = NSURL(fileURLWithPath: path)
player = AVPlayer(URL: url)
}
else {
print("Oops, something wrong when playing video.m4v")
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
playVideo()
}
}
Hope this helps.
You can only use "if let" for optional values:
if let nonoptional = optional {
}
If the right hand side is not optional, then the if let is just unnecessary.
The url is not an optional,after you got the path you are sure that there is something and the url is not an optional because there you can have an url where the file doesn't exists, but now you are sure that the file exists because you done if let with the path . Try this
private func playVideo() {
if let path = NSBundle.mainBundle().pathForResource("Video Name", ofType: "mp4") {
let url = NSURL(fileURLWithPath: path)
player = AVPlayer(URL: url)
player?.play()
}
else {
print("Oops, something wrong when playing video.m4v")
}
}
Lately I have run into an issue while using the beta version of Xcode (7.0).
I am not able to hear the sound that I play through this code:
(It is a ViewController from the Main.storyboard, there is a button connected to buttonTouchUpInside())
import UIKit
import AVFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer {
let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
let url = NSURL.fileURLWithPath(path!)
var audioPlayer:AVAudioPlayer?
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
} catch {
print("NO AUDIO PLAYER")
}
return audioPlayer!
}
#IBAction func buttonTouchUpInside(sender: AnyObject) {
let backMusic = setupAudioPlayerWithFile("sound", type: "wav")
backMusic.play()
}
}
You just have to move the declaration of backMusic out of your IBAction:
Try like this:
class ViewController: UIViewController {
var backMusic: AVAudioPlayer!
// ...
#IBAction func buttonTouchUpInside(sender: AnyObject) {
backMusic = setupAudioPlayerWithFile("sound", type: "wav")
backMusic.play()
}
}