From 9b9e95301ea97acf79d791d88e6dcdab25ae6bdc Mon Sep 17 00:00:00 2001 From: Bilal Date: Mon, 19 Aug 2024 23:43:40 +0530 Subject: [PATCH] added new checks for avplayer --- WOKA.xcodeproj/project.pbxproj | 6 +- WOKA/Info.plist | 6 +- .../SideMenu/SideMenuController.swift | 18 +++ WOKA/Theme/Base.lproj/Theme.storyboard | 36 +++-- WOKA/Theme/Controller/ThemeOneVC.swift | 125 ++++++++++++------ WOKA/Theme/Controller/ThemeTwoVC.swift | 65 +++++++++ WOKA/Theme/ViewModel/ThemeOneVM.swift | 99 ++++++-------- WOKA/Theme/ViewModel/ThemeTwoVM.swift | 34 ++++- WOKA/WOKAFM/Controller/WokaFMVC.swift | 14 +- 9 files changed, 271 insertions(+), 132 deletions(-) diff --git a/WOKA.xcodeproj/project.pbxproj b/WOKA.xcodeproj/project.pbxproj index 6843e8b..192b8e6 100644 --- a/WOKA.xcodeproj/project.pbxproj +++ b/WOKA.xcodeproj/project.pbxproj @@ -2746,14 +2746,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = WOKA/WOKA.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 4S9A74ZB6H; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WOKA/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = WOKA; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "Give Permissions for Karaoke"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -2786,14 +2785,13 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = WOKA/WOKA.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 6; DEVELOPMENT_TEAM = 4S9A74ZB6H; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = WOKA/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = WOKA; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "Give Permissions for Karaoke"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard; INFOPLIST_KEY_UIMainStoryboardFile = Main; diff --git a/WOKA/Info.plist b/WOKA/Info.plist index 7d2da2e..51ab366 100644 --- a/WOKA/Info.plist +++ b/WOKA/Info.plist @@ -6,6 +6,8 @@ $(API_KEY_ID) API_KEY_PASS $(API_KEY_PASS) + NSUserNotificationsUsageDescription + You need to allow for notifications to keep you updated about the content. STAGING_URL $(STAGING_URL) UIAppFonts @@ -41,7 +43,7 @@ audio remote-notification - NSUserNotificationsUsageDescription - You need to allow for notifications to keep you updated about the content. + NSMicrophoneUsageDescription + Give Permissions for Karaoke diff --git a/WOKA/TabBar & SideMenu/SideMenu/SideMenuController.swift b/WOKA/TabBar & SideMenu/SideMenu/SideMenuController.swift index f6a21e0..ad60e9d 100644 --- a/WOKA/TabBar & SideMenu/SideMenu/SideMenuController.swift +++ b/WOKA/TabBar & SideMenu/SideMenu/SideMenuController.swift @@ -862,3 +862,21 @@ extension SideMenuController: UIGestureRecognizerDelegate { return abs(velocity.y / velocity.x) < preferences.basic.panGestureSensitivity } } + +func topVC(in rootViewController: UIViewController) -> UIViewController? { + if let sideMenuController = rootViewController as? SideMenuController { + // The main content is managed by contentViewController in SideMenuController + if let mainViewController = sideMenuController.contentViewController { + return topVC(in: mainViewController) + } + } else if let tabBarController = rootViewController as? UITabBarController, let selectedVC = tabBarController.selectedViewController{ + return topVC(in: selectedVC) + } else if let navigationController = rootViewController as? UINavigationController, let visibleVC = navigationController.visibleViewController { + return topVC(in: visibleVC) + } else if let presentedViewController = rootViewController.presentedViewController { + return topVC(in: presentedViewController) + } else { + return rootViewController + } + return nil +} diff --git a/WOKA/Theme/Base.lproj/Theme.storyboard b/WOKA/Theme/Base.lproj/Theme.storyboard index 1c9fc1e..c323fda 100644 --- a/WOKA/Theme/Base.lproj/Theme.storyboard +++ b/WOKA/Theme/Base.lproj/Theme.storyboard @@ -562,16 +562,16 @@ - + - + @@ -605,7 +605,7 @@ - + - + @@ -659,16 +659,16 @@ - + - + @@ -775,9 +775,17 @@ - + + + + + + @@ -1015,6 +1023,7 @@ + @@ -1312,6 +1321,9 @@ + + + @@ -1319,7 +1331,7 @@ - + diff --git a/WOKA/Theme/Controller/ThemeOneVC.swift b/WOKA/Theme/Controller/ThemeOneVC.swift index f431ffe..e873026 100644 --- a/WOKA/Theme/Controller/ThemeOneVC.swift +++ b/WOKA/Theme/Controller/ThemeOneVC.swift @@ -7,6 +7,7 @@ import UIKit import Alamofire +import AVFoundation class ThemeOneVC: UIViewController { @@ -42,6 +43,9 @@ class ThemeOneVC: UIViewController { weak var delegate: ChildViewControllerDelegate? + + // MARK: - LifeCycle + deinit{ timer?.invalidate() // Removing observers @@ -51,10 +55,10 @@ class ThemeOneVC: UIViewController { NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: K.NotificationCenterReloads.themeOnePush), object: nil) if let playerItem = vm.playerItem{ playerItem.removeObserver(self, forKeyPath: "status") - playerItem.removeObserver(self, forKeyPath: "isPlaybackBufferEmpty") - playerItem.removeObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp") +// playerItem.removeObserver(self, forKeyPath: "isPlaybackBufferEmpty") +// playerItem.removeObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp") } - if let playerLayer = vm.playerLayer, let avPlayer = vm.avPlayer { + if let avPlayer = vm.avPlayer { avPlayer.removeObserver(self, forKeyPath: "timeControlStatus") avPlayer.pause() } @@ -171,51 +175,94 @@ extension ThemeOneVC{ vm.avPlayer.addObserver(self, forKeyPath: "timeControlStatus", options: [.new, .old], context: nil) // Observe buffering status - vm.playerItem.addObserver(self, forKeyPath: "isPlaybackBufferEmpty", options: [.new, .old], context: nil) - vm.playerItem.addObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp", options: [.new, .old], context: nil) +// vm.playerItem.addObserver(self, forKeyPath: "isPlaybackBufferEmpty", options: [.new, .old], context: nil) +// vm.playerItem.addObserver(self, forKeyPath: "isPlaybackLikelyToKeepUp", options: [.new, .old], context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + //this will oberver if player loads the url or fails if keyPath == "status" { if vm.playerItem.status == .readyToPlay { - print("Player is ready to play") + print("Theme 2 Player is ready to play") vm.avPlayer.play() } else if vm.playerItem.status == .failed { - print("Player failed to load") - if !liveTVActivityIndicator.isAnimating{ - liveTVActivityIndicator.startAnimating() - } - } - } else if keyPath == "timeControlStatus" { - switch vm.avPlayer.timeControlStatus { - case .playing: - print("Player is playing") - liveTVActivityIndicator.stopAnimating() - case .paused: - print("Player is paused") - vm.avPlayer.play() - liveTVActivityIndicator.stopAnimating() - case .waitingToPlayAtSpecifiedRate: - print("Player is Buffering 1") - if !(NetworkReachabilityManager()?.isReachable ?? false){ - if !NetworkReachibility.shared.isMonitoring{ - startMonitoring() - } - } - @unknown default: - break - } - } else if keyPath == "isPlaybackBufferEmpty" { - if vm.playerItem.isPlaybackBufferEmpty { - print("Player is buffering 2") - liveTVActivityIndicator.startAnimating() - startMonitoring() - } - } else if keyPath == "isPlaybackLikelyToKeepUp" { - if vm.playerItem.isPlaybackLikelyToKeepUp { - print("Player is likely to keep up with the playback") + print("Theme 2 Player failed to load") + vm.setupAvPlayer() } } + + //this will give status of buffering, play pause. + if keyPath == "timeControlStatus" { + if let player = object as? AVPlayer { + switch player.timeControlStatus { + case .waitingToPlayAtSpecifiedRate: + print("Theme 2 Player Buffering...") + vm.startStopActivity(isStart: true) + case .playing: + print("Theme 2 Player Playing") + vm.startStopActivity(isStart: false) + case .paused: + print("Theme 2 Player Paused") + + // check if app is in background return it + if UIApplication.shared.applicationState == .background {return} + if let rootViewController = UIApplication.shared.mainKeyWindow?.rootViewController { + if let topVC = topVC(in: rootViewController) { + if topVC is HomeVC{ + vm.avPlayer.play() + } else { + print("The top view controller is not HomeVC") + } + } else { + print("No top view controller found") + } + } + + @unknown default: + print("Theme 2 Player Unknown status") + } + } + } +// if keyPath == "status" { +// if vm.playerItem.status == .readyToPlay { +// print("Player is ready to play") +// vm.avPlayer.play() +// } else if vm.playerItem.status == .failed { +// print("Player failed to load") +// if !liveTVActivityIndicator.isAnimating{ +// liveTVActivityIndicator.startAnimating() +// } +// } +// } else if keyPath == "timeControlStatus" { +// switch vm.avPlayer.timeControlStatus { +// case .playing: +// print("Player is playing") +// liveTVActivityIndicator.stopAnimating() +// case .paused: +// print("Player is paused") +// vm.avPlayer.play() +// liveTVActivityIndicator.stopAnimating() +// case .waitingToPlayAtSpecifiedRate: +// print("Player is Buffering 1") +// if !(NetworkReachabilityManager()?.isReachable ?? false){ +// if !NetworkReachibility.shared.isMonitoring{ +// startMonitoring() +// } +// } +// @unknown default: +// break +// } +// } else if keyPath == "isPlaybackBufferEmpty" { +// if vm.playerItem.isPlaybackBufferEmpty { +// print("Player is buffering 2") +// liveTVActivityIndicator.startAnimating() +// startMonitoring() +// } +// } else if keyPath == "isPlaybackLikelyToKeepUp" { +// if vm.playerItem.isPlaybackLikelyToKeepUp { +// print("Player is likely to keep up with the playback") +// } +// } } } diff --git a/WOKA/Theme/Controller/ThemeTwoVC.swift b/WOKA/Theme/Controller/ThemeTwoVC.swift index ed2d497..40698af 100644 --- a/WOKA/Theme/Controller/ThemeTwoVC.swift +++ b/WOKA/Theme/Controller/ThemeTwoVC.swift @@ -7,6 +7,7 @@ import UIKit import AVFAudio +import AVFoundation class ThemeTwoVC: UIViewController { @@ -17,11 +18,25 @@ class ThemeTwoVC: UIViewController { @IBOutlet weak var avatarImage: UIImageView! @IBOutlet weak var notificationBtn: UIButton! + @IBOutlet weak var liveTVActivityIndicator: UIActivityIndicatorView! + var vm = ThemeTwoVM() deinit{ NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: K.NotificationCenterReloads.reloadTheme), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: K.NotificationCenterReloads.themeTwoPush), object: nil) + NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil) +// vm.avPlayer.removeObserver(self, forKeyPath: "timeControlStatus") +// vm.playerItem.removeObserver(self, forKeyPath: "status") + + if let playerItem = vm.playerItem{ + playerItem.removeObserver(self, forKeyPath: "status") + } + if let avPlayer = vm.avPlayer { + avPlayer.removeObserver(self, forKeyPath: "timeControlStatus") + avPlayer.pause() + } } override var preferredStatusBarStyle: UIStatusBarStyle { @@ -78,6 +93,56 @@ class ThemeTwoVC: UIViewController { let item = JwPlayerItemCreate(url: APIEndPoints.StaticURLs.masilaUrl, poster: nil, titles: "Masila") JWPlayerManager.shared.presentPlayer(from: self, playerItems: [item], contentType: .trailer, videoIDs: [0]) } + + // MARK: - Handler for AvPlayer + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + + //this will oberver if player loads the url or fails + if keyPath == "status" { + if vm.playerItem.status == .readyToPlay { + print("Theme 1 Player is ready to play") + vm.avPlayer.play() + } else if vm.playerItem.status == .failed { + print("Theme 1 Player failed to load") + vm.setupAvPlayer() + } + } + + //this will give status of buffering, play pause. + if keyPath == "timeControlStatus" { + if let player = object as? AVPlayer { + switch player.timeControlStatus { + case .waitingToPlayAtSpecifiedRate: + print("Theme 1 Player Buffering...") + vm.startStopActivity(isStart: true) + case .playing: + print("Theme 1 Player Playing") + vm.startStopActivity(isStart: false) + case .paused: + print("Theme 1 Player Paused") + + // check if app is in background return it + if UIApplication.shared.applicationState == .background {return} + if let rootViewController = UIApplication.shared.mainKeyWindow?.rootViewController { + if let topVC = topVC(in: rootViewController) { + if topVC is HomeVC{ + vm.avPlayer.play() + } else { + print("The top view controller is not HomeVC") + } + } else { + print("No top view controller found") + } + } + + @unknown default: + print("Theme 2 Player Unknown status") + } + } + } + } + } // MARK: - CollectionView DataSource Delegate diff --git a/WOKA/Theme/ViewModel/ThemeOneVM.swift b/WOKA/Theme/ViewModel/ThemeOneVM.swift index 56fd92f..ab07696 100644 --- a/WOKA/Theme/ViewModel/ThemeOneVM.swift +++ b/WOKA/Theme/ViewModel/ThemeOneVM.swift @@ -23,9 +23,7 @@ class ThemeOneVM{ var shouldAnimate = true let reachability = NetworkReachabilityManager() - - // var jwPlayerViewController: JWPlayerViewController! - + func initView(){ AuthFunc.shareInstance.initTimePeriods() @@ -50,59 +48,6 @@ class ThemeOneVM{ } func setupAvPlayer(){ - // Ensure the liveStreamURL is valid - // guard let liveStreamURL = URL(string: self.liveStreamURL) else { - // print("Invalid live stream URL") - // Utilities.dismissProgressHUD() - // return - // } - // jwPlayerViewController = JWPlayerViewController() - // do{ - // let videoSourceBuilder = try JWVideoSourceBuilder() - // // .defaultVideo(true) - // .file(liveStreamURL) - // .label("Live Stream") - // .build() - // - // // Create a JWPlayerItem - // let item = try JWPlayerItemBuilder() - // // .file(liveStreamURL) - // .videoSources([videoSourceBuilder]) - // .build() - // - // // Create a JWPlayerConfiguration - // let config = try JWPlayerConfigurationBuilder() - // .playlist(items: [item]) - //// .preload(JWPreload(rawValue: 20) ?? .none) - // .autostart(true) - // .build() - // - // - // - // // Add JWPlayerViewController's view as a subview - // self.vc.liveTvPlayer.addSubview(jwPlayerViewController.view) - // jwPlayerViewController.view.frame = self.vc.liveTvPlayer.bounds - // - //// // Set up constraints - //// jwPlayerViewController.view.translatesAutoresizingMaskIntoConstraints = false - //// NSLayoutConstraint.activate([ - //// jwPlayerViewController.view.topAnchor.constraint(equalTo: self.vc.liveTvPlayer.topAnchor), - //// jwPlayerViewController.view.leadingAnchor.constraint(equalTo: self.vc.liveTvPlayer.leadingAnchor), - //// jwPlayerViewController.view.trailingAnchor.constraint(equalTo: self.vc.liveTvPlayer.trailingAnchor), - //// jwPlayerViewController.view.bottomAnchor.constraint(equalTo: self.vc.liveTvPlayer.bottomAnchor) - //// ]) - // jwPlayerViewController.player.volume = 0.0 - // - // jwPlayerViewController.player.configurePlayer(with: config) - // jwPlayerViewController.interfaceBehavior = .hidden - //// self.vc.liveTvPlayer.addSubview(jwPlayerViewController.view) - //// jwPlayerViewController.player.play() - // - // }catch{ - // print(error) - // } - - /* Av Player Setup */ @@ -139,6 +84,20 @@ class ThemeOneVM{ avPlayer.volume = 0 } + // MARK: - start stop activity Indicator + + func startStopActivity(isStart : Bool){ + DispatchQueue.main.async { [weak self] in + guard let self else{return} + if isStart{ + vc.liveTVActivityIndicator.startAnimating() + }else{ + vc.liveTVActivityIndicator.hidesWhenStopped = true + vc.liveTVActivityIndicator.stopAnimating() + } + } + } + func setUserData(){ guard let data = AuthFunc.shareInstance.userData else{return} //set the first name as the name @@ -179,18 +138,34 @@ class ThemeOneVM{ @objc func appDidEnterBackground() { // Code to execute when the app enters the background print("App entered background") - if UIApplication.topViewController() == ThemeOneVC(){ - avPlayer.pause() - handleBackground() + if let rootViewController = UIApplication.shared.mainKeyWindow?.rootViewController { + if let topVC = topVC(in: rootViewController) { + if topVC is HomeVC{ + avPlayer.pause() + handleBackground() + } else { + print("The top view controller is not HomeVC") + } + } else { + print("No top view controller found") + } } } @objc func appWillEnterForeground() { // Code to execute when the app enters the foreground print("App will enter foreground") - if UIApplication.topViewController() == ThemeOneVC(){ - avPlayer.play() - handleBackground() + if let rootViewController = UIApplication.shared.mainKeyWindow?.rootViewController { + if let topVC = topVC(in: rootViewController) { + if topVC is HomeVC{ + avPlayer.play() + handleBackground() + } else { + print("The top view controller is not HomeVC") + } + } else { + print("No top view controller found") + } } } diff --git a/WOKA/Theme/ViewModel/ThemeTwoVM.swift b/WOKA/Theme/ViewModel/ThemeTwoVM.swift index 249073e..8b7b95b 100644 --- a/WOKA/Theme/ViewModel/ThemeTwoVM.swift +++ b/WOKA/Theme/ViewModel/ThemeTwoVM.swift @@ -52,7 +52,7 @@ class ThemeTwoVM{ NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.viewPush(notification:)), name: NSNotification.Name(rawValue: K.NotificationCenterReloads.themeTwoPush), object: nil) } - + // MARK: - This will handle all clicks for modules // This comes from Explore WOKA CLicks @@ -171,6 +171,9 @@ class ThemeTwoVM{ vc.config = config vc.dismissTapped = self.tapped vc.contentType = .liveStream + if let streamID = AuthFunc.shareInstance.staticURLs?.liveData?.first?.id{ + vc.vm.videoIDs = [streamID] + } vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .crossDissolve @@ -240,7 +243,7 @@ class ThemeTwoVM{ Av Player Setup */ guard let data = AuthFunc.shareInstance.staticURLs , let liveStreamData = data.liveData?.first else{ - self.vc.toast(msg: "Issue with live streaming", time: 2) + vc.toast(msg: "Issue with live streaming", time: 2) return } var url = String() @@ -252,7 +255,7 @@ class ThemeTwoVM{ } guard let streamURL = URL(string: url) else{return} - + startStopActivity(isStart: true) playerItem = AVPlayerItem(url: streamURL) // Create AVPlayer with the stream URL @@ -263,11 +266,16 @@ class ThemeTwoVM{ playerLayer = AVPlayerLayer(player: avPlayer) playerLayer.videoGravity = .resizeAspectFill // You can set different videoGravity as per your need - playerLayer.frame = self.vc.liveTvView.bounds - self.vc.liveTvView.layer.addSublayer(playerLayer) - self.vc.liveTvView.layoutIfNeeded() + playerLayer.frame = vc.liveTvView.bounds + vc.liveTvView.layer.addSublayer(playerLayer) + vc.liveTvView.bringSubviewToFront(vc.liveTVActivityIndicator) + vc.liveTvView.layoutIfNeeded() avPlayer.play() avPlayer.volume = 0 + + //Add Observer after the player is setup + avPlayer.addObserver(vc, forKeyPath: "timeControlStatus", options: [.new, .old], context: nil) + playerItem.addObserver(vc, forKeyPath: "status", options: [.new, .old], context: nil) } func setData(){ @@ -294,6 +302,20 @@ class ThemeTwoVM{ } + // MARK: - start stop activity Indicator + + func startStopActivity(isStart : Bool){ + DispatchQueue.main.async { [weak self] in + guard let self else{return} + if isStart{ + vc.liveTVActivityIndicator.startAnimating() + }else{ + vc.liveTVActivityIndicator.hidesWhenStopped = true + vc.liveTVActivityIndicator.stopAnimating() + } + } + } + // MARK: - SetupCell func setupCell(){ diff --git a/WOKA/WOKAFM/Controller/WokaFMVC.swift b/WOKA/WOKAFM/Controller/WokaFMVC.swift index b01de1e..a9bbe75 100644 --- a/WOKA/WOKAFM/Controller/WokaFMVC.swift +++ b/WOKA/WOKAFM/Controller/WokaFMVC.swift @@ -145,10 +145,10 @@ class WokaFMVC: UIViewController { override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "status" { if vm.playerItem.status == .readyToPlay { - print("Player is ready to play") + print("FM is ready to play") vm.player.play() } else if vm.playerItem.status == .failed { - print("Player failed to load") + print("FM failed to load") activityIndicator.stopAnimating() playBtn.setImage(UIImage(named: "Reload"), for: .normal) playBtn.isEnabled = true @@ -156,12 +156,12 @@ class WokaFMVC: UIViewController { } else if keyPath == "timeControlStatus" { switch vm.player.timeControlStatus { case .playing: - print("Player is playing") + print("FM is playing") activityIndicator.stopAnimating() playBtn.isEnabled = true playBtn.setImage(UIImage(named: "PauseButton"), for: .normal) case .paused: - print("Player is paused") + print("FM is paused") playBtn.setImage(UIImage(named: "PlayButton"), for: .normal) case .waitingToPlayAtSpecifiedRate: activityIndicator.startAnimating() @@ -170,20 +170,20 @@ class WokaFMVC: UIViewController { if !(NetworkReachabilityManager()?.isReachable ?? false){ startMonitoring() } - print("Player is buffering 1 ") + print("FM is buffering 1 ") @unknown default: break } } else if keyPath == "isPlaybackBufferEmpty" { if vm.playerItem.isPlaybackBufferEmpty { - print("Player is buffering 2") + print("FM is buffering 2") playBtn.isEnabled = false activityIndicator.startAnimating() startMonitoring() } } else if keyPath == "isPlaybackLikelyToKeepUp" { if vm.playerItem.isPlaybackLikelyToKeepUp { - print("Player is likely to keep up with the playback") + print("FM is likely to keep up with the playback") } } }