tvOS/Swift 3: Why is contentOverlayView not displayed? - swift

I have the following code for a tvOS app. It plays video just as I would like, but the the contentOverlayView I've set does not appear. From examples I've looked at I think it should be working. Can someone please explain what I am doing wrong?
import Foundation
import UIKit
import AVKit
class videoPlayer: AVPlayerViewController {
var thePlayer: AVPlayer?
var movieToPlay: AVPlayerItem?
var movieURL: String?
let theVideoPlayer = AVPlayerViewController()
#IBOutlet weak var videoInfo: UIView!
override func viewDidLoad(){
theVideoPlayer.contentOverlayView?.addSubview(videoInfo)
theVideoPlayer.player = thePlayer
self.view.addSubview(theVideoPlayer.view)
theVideoPlayer.view.frame = self.view.frame
NotificationCenter.default.addObserver(self, selector: #selector(videoPlayer.videoDone), name: NSNotification.Name(rawValue: "AVPlayerItemDidPlayToEndTimeNotification"), object: thePlayer?.currentItem)
playVideo(movieURL!)
}
func playVideo(_ movieURL: String){
let movieToPlay = AVPlayerItem(url: URL(string: movieURL)!)
thePlayer = AVPlayer(playerItem: movieToPlay)
thePlayer!.play()
}
func videoDone(){
dismiss(animated: true, completion: nil)
}
}

I was confused about some things. Here's what worked:
import Foundation
import UIKit
import AVKit
class videoPlayer: UIViewController {
var movieURL:String = ""
var movieTitle:String = ""
var playerController:AVPlayerViewController?
#IBOutlet weak var videoInfo: UIView!
#IBOutlet var titleLabel: UILabel!
override func viewDidLoad(){
titleLabel.text = movieTitle
playerController = AVPlayerViewController()
playerController?.player = AVPlayer()
self.addChildViewController(playerController!)
self.view.addSubview((playerController?.view)!)
playerController?.didMove(toParentViewController: self)
playerController?.view.frame = self.view.frame
playerController?.contentOverlayView?.addSubview(videoInfo)
let movieToPlay = AVPlayerItem(url: URL(string: movieURL)!)
playerController?.player = AVPlayer(playerItem: movieToPlay)
playerController?.player?.play()
NotificationCenter.default.addObserver(self, selector: #selector(videoDone), name: NSNotification.Name(rawValue: "AVPlayerItemDidPlayToEndTimeNotification"), object: playerController?.player?.currentItem)
}
func videoDone(){
print("DONE")
dismiss(animated: true, completion: nil)
}
}
The UIView displays just as expected.

Related

why currentTime and duration of AVAudioPlayer are nil?

why currentTime and duration of AVAudioPlayer are nil?
Recently faced with a task when creating a player
link to the mp3 working, checked
but at the same time track duration and currenttime nil
I try to change AVAudioPlayer to AVPlayer, but I have same problem
What I need to do to correct this?
Maybe I must to download this mp3 before read duration?
But it would be better to solve this problem without downloading mp3
import UIKit
import AVFoundation
class PlayerViewController: UIViewController {
//Instantiate the AVFoundation audio player class
var player: AVAudioPlayer?
//Timer for tracking the progress
var timer: Timer? = nil
#IBOutlet weak var bookCoverImageView: UIImageView!
#IBOutlet weak var timeSlider: CustomSlider!
#IBOutlet weak var timeFromStartLabel: UILabel!
#IBOutlet weak var remainingTimeLabel: UILabel!
#IBOutlet weak var previousButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var playButton: UIButton!
#IBOutlet weak var bookNameLabel: UILabel!
#IBOutlet weak var authorNameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
_ = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateSlider), userInfo: nil, repeats: true)
do {
//Set the path to the audio file (comes from the bundle)
let path = URL(string: "https://firebasestorage.googleapis.com/v0/b/audio-summary-v3.appspot.com/o/%D0%92%D1%8B%D1%81%D1%82%D1%83%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B2%20%D1%81%D1%82%D0%B8%D0%BB%D0%B5%20TED%20-%20%D0%94%D0%B6%D0%B5%D1%80%D0%B5%D0%BC%D0%B8%20%D0%94%D0%BE%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD.mp3?alt=media&token=58cae883-36b8-445f-8338-cc04cd518eee")
//Unpacking the path string optional
if let unpackedPath = path {
try player = AVAudioPlayer(contentsOf: unpackedPath)
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
self.timeFromStartLabel.text = String(format: "%d:%02d", Int(self.player!.currentTime) / 60, Int(self.player!.currentTime) % 60)
self.remainingTimeLabel.text = String(format: "%d:%02d", Int(self.player!.duration - self.player!.currentTime) / 60, Int(self.player!.duration - self.player!.currentTime) % 60)
}
player!.play()
timer!.fire()
}
} catch {
print(error)
}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
I have error here
timeSlider.maximumValue = Float(self.player!.duration)
}
#IBAction func playButtonTapped(_ sender: Any) {
if player!.isPlaying {
player?.stop()
playButton.setImage(UIImage(named: "play_button"), for: .normal)
}
else {
player?.play()
playButton.setImage(UIImage(named: "stop_button"), for: .normal)
}
}
#IBAction func timeSliderScrolling(_ sender: Any) {
player?.stop()
player?.currentTime = TimeInterval(timeSlider.value)
player?.prepareToPlay()
player?.play()
}
#objc func updateSlider() {
I have error here
timeSlider.value = Float(player!.currentTime)
}
}
Use AVPlayer over AVAudioPlayer so that you can observe the current play time with addPeriodicTimeObserver.
import UIKit
import AVFoundation
class ViewController: UIViewController {
// MARK: - Variables
var player: AVPlayer?
#IBAction func playAudio(_ sender: UIBarButtonItem) {
player?.play()
}
override func viewDidLoad() {
super.viewDidLoad()
guard let path = Bundle.main.path(forResource: "myAudio", ofType:"m4a") else {
debugPrint("File not found")
return
}
let audioURL = URL(fileURLWithPath: path)
let playerItem = AVPlayerItem(url: audioURL)
player = AVPlayer(playerItem: playerItem)
player!.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: DispatchQueue.main) { (CMTime) -> Void in
if self.player!.currentItem?.status == .readyToPlay {
let time : Float64 = CMTimeGetSeconds(self.player!.currentTime());
print("Current play time: \(time)")
}
}
}
}

Play video from url without extension swift

I want to play video from url returns from service, url doesn't have extension, so it doesn't work. what should I do?
xcode9 swift 4
import AVKit
import AVFoundation
import MediaPlayer
import AudioToolbox
class ViewController: UIViewController {
#IBOutlet weak var player_View: UIView!
let videoURL = URL(string: "http://45.58.42.105:82/Handlers/ImageHandler.ashx?fileReference=67f0dce7-a5f5-4894-a8fd-5996f135626c");
var playerVC = AVPlayerViewController()
var playerView = AVPlayer()
var urlStr = "";
override func viewDidLoad() {
super.viewDidLoad()
self.playVideo();
}
func playVideo() {
self.playerView = AVPlayer(url: videoURL!)
self.playerVC.player = playerView
self.player_View.addSubview(self.playerVC.view)
playerVC.view.frame = self.player_View.frame
playerView.play()
}
}

AVAudioplayer no resetting on viewDidAppear

The idea is simple and I do not think that the question has been asked in the past.
I want to build a simple mp3 player.
some songs displayed in a collection view the user selects a song
segue to another view with options to play, pause or stop only issue
is when you go back to the home screen to select a new song with the
current still playing. It is impossible to deactivate the current
player. When you need to play the 2 songs, the 2 are playing together
I have tried a lot of things
- create a new instance of player (player = AVAudioPlayer())
- player.pause() and player.play()
I do not see what I am doing wrong really.
this is my code :
import UIKit
import AVFoundation
class LecteurViewController: UIViewController {
var chansonSelected: Chanson? = nil
var lecteur:AVAudioPlayer = AVAudioPlayer()
var timer1 = Timer()
var timer2 = Timer()
#IBOutlet weak var dureeChansonSlider: UISlider!
#IBOutlet weak var chansonImageView: UIImageView!
#IBOutlet weak var chansonVolumeSlider: UISlider!
#IBOutlet weak var debutLabel: UILabel!
#IBOutlet weak var finLabel: UILabel!
#IBAction func stopMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.stop()
LecteurManager.isActive = false
}
#IBAction func pauseMusicAction(_ sender: UIBarButtonItem) {
var player = AVAudioPlayer()
lecteur.pause()
LecteurManager.isActive = false
}
#IBAction func jouerMusicAction(_ sender: UIButton) {
if LecteurManager.isActive {
changeSong()
print("lecteur déjà en cours")
} else {
var player = AVAudioPlayer()
lecteur.play()
}
print(LecteurManager.isActive )
LecteurManager.isActive = true
}
func changeSong() {
lecteur.stop()
//lecteur = AVAudioPlayer()
jouerLecteurMp3()
print(chansonSelected!)
lecteur.play()
}
override func viewDidLoad() {
super.viewDidLoad()
configureView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
jouerLecteurMp3()
}
func configureView() {
self.title = (chansonSelected!.titre!).capitalized
chansonImageView.image = UIImage(named: "\(chansonSelected!.image).jpgs")
//formatter 'back' button
let backBtn = UIBarButtonItem(title: "< Playlist", style: .plain, target: self, action: #selector(LecteurViewController.reset(_sender:)))
self.navigationItem.leftBarButtonItem = backBtn
self.navigationController?.navigationBar.tintColor = UIColor.white
//contrôler volume chanson
chansonVolumeSlider.addTarget(self, action: #selector(LecteurViewController.ajusterVolume(_ :)), for: UIControlEvents.valueChanged)
//contrôler durée chanson
dureeChansonSlider.addTarget(self, action: #selector(LecteurViewController.ajusterDurée(_ :)), for: UIControlEvents.valueChanged)
updateUI()
}
func updateUI() {
//indiquer position chanson
timer1 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.mettreAJourDurée), userInfo: nil, repeats: true)
//afficher durée chanson
timer2 = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LecteurViewController.afficherDurée), userInfo: nil, repeats: true)
}
func reset(_sender:UIBarButtonItem) {
self.navigationController?.popViewController(animated: true)
}
func ajusterVolume(_ sender:UISlider) {
//print("volume ajusté \(chansonVolumeSlider.value)")
lecteur.volume = chansonVolumeSlider.value
}
func ajusterDurée(_ sender:UISlider) {
lecteur.currentTime = TimeInterval(dureeChansonSlider.value)
}
func mettreAJourDurée() {
dureeChansonSlider.value = Float(lecteur.currentTime)
}
func afficherDurée() {
print("durée actuelle: \(lecteur.duration - lecteur.currentTime)")
debutLabel.text = retournerPositionActuelle()
finLabel.text = retournerDureeTotal()
}
func retournerPositionActuelle() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func retournerDureeTotal() -> String {
let seconds = Int(lecteur.currentTime) % 60
let minutes = (Int(lecteur.currentTime) / 60) % 60
return String(format: "%0.2i:%0.2i", minutes, seconds)
}
func jouerLecteurMp3() {
let chanson = "bensound-\(chansonSelected!.titre!)"
let fichierMp3 = Bundle.main.path(forResource: chanson, ofType: "mp3")
do {
try lecteur = AVAudioPlayer(contentsOf: URL(string: fichierMp3!)!)
dureeChansonSlider.maximumValue = Float(lecteur.duration)
} catch {
print("erreur lecture mp3")
}
}
}
Try this:
func reset(_sender:UIBarButtonItem)
{
self.navigationController?.popViewController(animated: true)
lecteur.stop()
}

Change WebView url from AppDelegate

I'm receiving notifications from Firebase in the AppDelegate class.
This notification contains a String named "notif_url". I've put this value in a var named "desired_url" and now I need to change my WebView url with the "desired_url" value.
But I can't access to the webview to change it url like this :
#IBOutlet weak var my_web_view: UIWebView!
func load_url(server_url: String){
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
}
load_url(server_url: desired_url);
Do you know if I can do that and if yes, how ?
Images :
EDIT 1:
After adding breakPoint to know the wrong line, it seem't that the line is this one :
my_web_view.loadRequest(request)
EDIT 2:
If need, that's a part of my AppDelegate class code.
import UIKit
import UserNotifications
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
#IBOutlet weak var my_web_view: UIWebView!
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}
// [START ios_10_message_handling]
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate{
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void){
print("Step : 12");
let userInfo = notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey]{
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
var url: String = userInfo[AnyHashable("url")] as! String;
load_url(server_url: url);
// Change this to your preferred presentation option
completionHandler([])
}
func load_url(server_url: String){
/*
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
*/
guard let url = URL(string: server_url) else {
print("Invalid URL")
return
}
print("TRY : "+server_url);
let request = URLRequest(url: url)
my_web_view.loadRequest(request)
}
}
EDIT 3:
If need, that's my ViewController class code.
import Foundation
import UIKit
import SafariServices
import UserNotifications
class ViewController: UIViewController, UIWebViewDelegate{
#IBOutlet weak var my_web_view: UIWebView!
#IBOutlet weak var my_loading_view: UIView!
#IBOutlet weak var spinner : UIActivityIndicatorView!
#IBOutlet weak var app_logo : UIImageView!
#IBOutlet weak var deadlinePicker: UIDatePicker!
#IBOutlet weak var titleField: UITextField!
var new_url: String = "";
override func viewDidLoad(){
super.viewDidLoad()
let server_url = "https://www.sortirauhavre.com/";
NotificationCenter.default.addObserver(self, selector: #selector(self.rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
rotated();
spinner.startAnimating();
my_web_view.scrollView.bounces = false;
my_web_view.scrollView.isScrollEnabled = true;
let url = URL(string: server_url);
let request = URLRequest(url: url!);
my_web_view.loadRequest(request);
}
// CETTE FONCITON SE LANCE A LA ROTATION DE L'APPAREIL
func rotated(){
app_logo.center = my_loading_view.center;
let y = app_logo.frame.origin.y;
let h = app_logo.frame.size.height
app_logo.frame.origin.y = y-(h/2);
spinner.center = my_loading_view.center;
}
// CETTE FONCTION MET EN ARRIERE PLAN L'ANNIMATION DE CHARGEMENT
func removeLoader(){
self.view.addSubview(my_web_view);
}
// CETTE FONCTION MET EN PREMIER PLAN L'ANNIMATION DE CHARGEMENT
func addLoader(){
self.view.addSubview(my_loading_view);
}
// CETTE FONCTION SE DECLANCHE QUAND LES PAGES DE LA WEBVIEW COMMENCE A CHANGER
func webViewDidStartLoad(_ webView: UIWebView){
addLoader();
let server_url = "https://www.sortirauhavre.com/";
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.removeLoader), userInfo: nil, repeats: false);
if let text = webView.request?.url?.absoluteString{
if text.hasPrefix(server_url){
}
else if text != ""{
UIApplication.shared.openURL(URL(string: text)!)
my_web_view.goBack()
}
}
}
// CETTE FONCTION SE DECLANCHE QUAND LES PAGES DE LA WEBVIEW FINI DE CHANGER
func webViewDidFinishLoad(_ webView: UIWebView){
let server_url = "https://www.sortirauhavre.com/";
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.removeLoader), userInfo: nil, repeats: false);
if let text = webView.request?.url?.absoluteString{
if text.hasPrefix(server_url){
}
else if text != ""{
UIApplication.shared.openURL(URL(string: text)!)
my_web_view.goBack()
}
}
}
}
You are force unwrapping url which is not a valid URL. I would suggest adding a guard statement to prevent the crash if a invalid URL is created:
func load_url(server_url: String) {
guard let url = URL(string: server_url) else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
my_web_view.loadRequest(request)
}
As you are obtaining the URL in the AppDelegate you cannot simply update the UIWebView from this class. You will need to call a function in the my_web_view's parent class which updates the URL.
// App Delegate
var serverURL: String?
func load_url(server_url: String) {
serverURL = server_url
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.post(name: notificationName, object: nil)
}
// View Controller
override func viewDidLoad() {
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateWebView), name: notificationName, object: nil)
updateWebView()
}
func updateWebView() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let serverURL = appDelegate.serverURL
guard let url = URL(string: serverURL) else {
print("Invalid URL")
return
}
let request = URLRequest(url: URL)
my_web_view.loadRequest(request)
}
Instead of creating a new instance of your view controller, or trying to duplicate the outlet, you just need to access the current instance of your view controller. You can use either:
A global value for the view controller, or
A singleton-like pattern.
Then you can access the instance from your app delegate, by calling either myGlobalViewController.webView or ViewController.instance.webView.
So, here's an example:
import UIKit
private var thisViewController: ViewController? // Will hold the instance.
class ViewController: UIViewController {
static var instance: ViewController {
guard let thisViewController = thisViewController else { fatalError() } // Don't do this unless you're 100% sure that you'll never access this before the instance is loaded.
return thisViewController
}
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
thisViewController = self // Set the property to self.
}
...
}
After this, you can access the web view from your app delegate:
func load_url(server_url: String){
guard let url = URL(string: server_url) else {
return
}
let request = URLRequest(url: url)
ViewController.instance.webView.loadRequest(request)
}

Can not play sound Swift

I'm having some trouble playing a sound which is attached to a button/IBAction.
When I do the exact same thing for iOS in Xcode, it works perfectly. However, when I do this for OS X, it doesn't work. Any ideas?
import Cocoa
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var pingAudioPlayer : AVAudioPlayer?
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
func playPing(){
let pingSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
pingAudioPlayer = AVAudioPlayer(contentsOfURL: pingSound, error: nil)
pingAudioPlayer!.prepareToPlay()
pingAudioPlayer!.currentTime = 0
pingAudioPlayer!.play()
}
#IBAction func soundTest(sender: AnyObject) {
playPing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sr.delegate = self
sr.commands = ["Ping", "Ping Mac"]
sr.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: AnyObject?) {
output!.string! += "\(command)\n"
playPing()
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
The main problem was the speechRecognizer method, it wasn't the right signature.
import AVFoundation
class ViewController: NSViewController, NSSpeechRecognizerDelegate {
var pingAudioPlayer : AVAudioPlayer?
var sr = NSSpeechRecognizer()
#IBOutlet var output: NSTextView?
func playPing(){
let pingSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("ping", ofType: "mp3")!)
pingAudioPlayer = try? AVAudioPlayer(contentsOfURL: pingSound)
pingAudioPlayer?.prepareToPlay()
pingAudioPlayer?.currentTime = 0
pingAudioPlayer?.play()
}
#IBAction func soundTest(sender: AnyObject) {
playPing()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sr?.delegate = self
sr?.commands = ["Ping", "Ping Mac"]
sr?.startListening()
}
func speechRecognizer(sender: NSSpeechRecognizer, didRecognizeCommand command: String) {
output?.string! += "\(command)\n"
playPing()
}
}