- Added google ad for karaoke - Added google ad for karaoke record ui - Added google ad for fm - Made a delegate function to handle the ad received or failure - Added ads to games webview bottom banner
474 lines
17 KiB
Swift
474 lines
17 KiB
Swift
//
|
|
// JWKaraokePlayerVC.swift
|
|
// WOKA
|
|
//
|
|
// Created by MacBook Pro on 09/07/24.
|
|
//
|
|
|
|
import UIKit
|
|
import JWPlayerKit
|
|
import AVFAudio
|
|
import AVFoundation
|
|
import GoogleMobileAds
|
|
|
|
class JWKaraokePlayerVC: JWPlayerViewController, JWPlayerViewControllerDelegate {
|
|
|
|
@IBOutlet weak var backButton: UIButton!
|
|
@IBOutlet weak var startRecordBtn: LocalisedElementsButton!
|
|
@IBOutlet weak var playBtn: LocalisedElementsButton!
|
|
@IBOutlet weak var downloadRecordingBtn: LocalisedElementsButton!
|
|
@IBOutlet weak var karaokeStack: UIStackView!
|
|
@IBOutlet weak var karaokeLoading: UIActivityIndicatorView!
|
|
@IBOutlet weak var startStopRecordingStack: UIStackView!
|
|
@IBOutlet weak var outerStack : UIStackView!
|
|
@IBOutlet weak var retryKaraokeBtn: LocalisedElementsButton!
|
|
|
|
@IBOutlet weak var adView: UIView!
|
|
|
|
var config: JWPlayerConfiguration!
|
|
var dismissTapped: (() -> Void)?
|
|
|
|
var isRecording = false
|
|
var isPlaying = false
|
|
|
|
var audioPlayer = AVPlayer()
|
|
|
|
var videoID = Int()
|
|
|
|
var vm = JWKaraokePlayerVM()
|
|
|
|
deinit{
|
|
NotificationCenter.default.removeObserver(self,name: UIApplication.didEnterBackgroundNotification, object: nil)
|
|
NotificationCenter.default.removeObserver(self,name: UIApplication.willEnterForegroundNotification, object: nil)
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
vm.vc = self
|
|
vm.initView()
|
|
|
|
player.configurePlayer(with: config)
|
|
self.delegate = self
|
|
//Disable Picture in Picture
|
|
playerView.allowsPictureInPicturePlayback = false
|
|
playerView.captionStyle = .none
|
|
self.view.bringSubviewToFront(outerStack)
|
|
self.view.bringSubviewToFront(backButton)
|
|
self.view.bringSubviewToFront(adView)
|
|
|
|
// Add observers
|
|
NotificationCenter.default.addObserver(self,selector: #selector(appDidEnterBackground),name: UIApplication.didEnterBackgroundNotification,object: nil)
|
|
NotificationCenter.default.addObserver(self,selector: #selector(appWillEnterForeground),name: UIApplication.willEnterForegroundNotification,object: nil)
|
|
}
|
|
|
|
override func viewWillAppear(_ animated: Bool) {
|
|
super.viewWillAppear(animated)
|
|
// self.navigationController?.isNavigationBarHidden = true
|
|
}
|
|
|
|
override func viewWillDisappear(_ animated: Bool) {
|
|
super.viewWillDisappear(animated)
|
|
player.stop()
|
|
}
|
|
|
|
@IBAction func startRecordingBtnTapped(_ sender: LocalisedElementsButton) {
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
|
|
// if AuthFunc.shareInstance.guestUserLoginPopUp() { return}
|
|
|
|
self.playBtn.isEnabled = false
|
|
if isRecording {
|
|
vm.stopRecording()
|
|
|
|
//make sure the interfacebehaviour is enabbled && updated the record btn title and image
|
|
self.interfaceBehavior = .normal
|
|
sender.setTitle("Start Recording", for: .normal)
|
|
} else {
|
|
//when recording is started change btn name to play and disable it
|
|
playBtn.setTitle("Play", for: .normal)
|
|
playBtn.setImage(UIImage(named: "PlayButtonSmall"), for: .normal)
|
|
playBtn.isEnabled = false
|
|
downloadRecordingBtn.isEnabled = false
|
|
self.player.play()
|
|
|
|
//make sure the interfacebehaviour is disabled && updated the record btn title and image
|
|
self.interfaceBehavior = .hidden
|
|
vm.startRecording()
|
|
sender.setTitle("Stop Recording", for: .normal)
|
|
}
|
|
isRecording.toggle()
|
|
}
|
|
|
|
@IBAction func playBtnTapped(_ sender: LocalisedElementsButton) {
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
if !isPlaying {
|
|
vm.playMixedAudio()
|
|
sender.setTitle("Pause", for: .normal)
|
|
sender.setImage(UIImage(named: "KaraokePause"), for: .normal)
|
|
|
|
// Disable Recording while playing, hide controls for jwplayer
|
|
self.interfaceBehavior = .hidden
|
|
|
|
self.startRecordBtn.isEnabled = false
|
|
self.downloadRecordingBtn.isEnabled = false
|
|
} else {
|
|
sender.setTitle("Play", for: .normal)
|
|
sender.setImage(UIImage(named: "PlayButtonSmall"), for: .normal)
|
|
|
|
// Disable Recording while playing, hide controls for jwplayer
|
|
self.interfaceBehavior = .normal
|
|
self.startRecordBtn.isEnabled = true
|
|
self.downloadRecordingBtn.isEnabled = true
|
|
}
|
|
|
|
isPlaying.toggle()
|
|
|
|
self.player.pause()
|
|
print("Play")
|
|
}
|
|
|
|
@IBAction func downloadRecording(_ sender: LocalisedElementsButton) {
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
print("DownloadRecording")
|
|
vm.saveToFilesApp()
|
|
}
|
|
|
|
@IBAction func backBtnTapped(_ sender: UIButton) {
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
self.player.stop()
|
|
if let postID = vm.postID{
|
|
Utilities.startProgressHUD(msg: "Syncing...")
|
|
let duration = DateFormatterLib.dateDifferenceINT(date1: vm.startTimeStamp, date2: Date())
|
|
AuthFunc.shareInstance.userVideoView(postID: postID, postType: PostType.karaokeVideo.rawValue, duration: duration, catID: 0) { isDone in
|
|
if isDone{
|
|
K.GVar.reloadContinueKaraoke = true
|
|
Utilities.dismissProgressHUD()
|
|
self.dismiss(animated: true)
|
|
}else{
|
|
Utilities.dismissProgressHUD()
|
|
self.dismiss(animated: true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@IBAction func retryBtnTapped(_ sender: LocalisedElementsButton) {
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
retryKaraokeBtn.isHidden = true
|
|
vm.setupKaraoke()
|
|
}
|
|
|
|
// MARK: - App LifeCycle HAndler
|
|
|
|
@objc func appDidEnterBackground() {
|
|
//when app goes in background make a count
|
|
vm.updateKaraokeVideoView()
|
|
self.player.pause()
|
|
|
|
self.playBtn.isEnabled = false
|
|
|
|
if isRecording {
|
|
vm.stopRecording()
|
|
//make sure the interfacebehaviour is enabbled && updated the record btn title and image
|
|
self.interfaceBehavior = .normal
|
|
startRecordBtn.setTitle("Start Recording", for: .normal)
|
|
isRecording = false
|
|
}
|
|
}
|
|
|
|
@objc func appWillEnterForeground() {
|
|
//reset the start time
|
|
vm.startTimeStamp = Date()
|
|
self.player.play()
|
|
}
|
|
|
|
// MARK: - JWPlayerViewControllerDelegate
|
|
|
|
override func jwplayer(_ player: any JWPlayer, didFinishLoadingWithTime loadTime: TimeInterval) {
|
|
super.jwplayer(player, didFinishLoadingWithTime: loadTime)
|
|
print("LoadTime", loadTime)
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let self else{return}
|
|
vm.setupKaraoke()
|
|
// self.startRecordBtn.isEnabled = true
|
|
}
|
|
}
|
|
|
|
override func jwplayerIsReady(_ player: JWPlayer) {
|
|
super.jwplayerIsReady(player)
|
|
player.seek(to: 0)
|
|
print("IsReady")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, failedWithSetupError code: UInt, message: String) {
|
|
super.jwplayer(player, failedWithSetupError: code, message: message)
|
|
print("Setup Error: \(code) - \(message)")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, failedWithError code: UInt, message: String) {
|
|
super.jwplayer(player, failedWithError: code, message: message)
|
|
// if no internet then add network observer
|
|
print("Error: \(code) - \(message)")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, encounteredWarning code: UInt, message: String) {
|
|
super.jwplayer(player, encounteredWarning: code, message: message)
|
|
print("Warning: \(code) - \(message)")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, encounteredAdError code: UInt, message: String) {
|
|
super.jwplayer(player, encounteredAdError: code, message: message)
|
|
print("Ad Error: \(code) - \(message)")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, encounteredAdWarning code: UInt, message: String) {
|
|
super.jwplayer(player, encounteredAdWarning: code, message: message)
|
|
print("Ad Warning: \(code) - \(message)")
|
|
}
|
|
|
|
override func jwplayer(_ player: JWPlayer, isBufferingWithReason reason: JWBufferReason) {
|
|
super.jwplayer(player, isBufferingWithReason: reason)
|
|
// player.play()
|
|
print("Buffering Reason:", reason)
|
|
}
|
|
|
|
//When Player is Paused
|
|
override func jwplayer(_ player: JWPlayer, didPauseWithReason reason: JWPauseReason) {
|
|
super.jwplayer(player, didPauseWithReason: reason)
|
|
if reason == .interaction{
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
}
|
|
}
|
|
|
|
//When Player is Play
|
|
override func jwplayer(_ player: JWPlayer, isPlayingWithReason reason: JWPlayReason) {
|
|
super.jwplayer(player, isPlayingWithReason: reason)
|
|
if reason == .interaction{
|
|
if let postID = vm.postID{
|
|
PersistentStorage.shared.addKaraokeCount(postID: postID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension JWKaraokePlayerVC: UIDocumentPickerDelegate {
|
|
|
|
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
|
deleteTemporaryFile()
|
|
}
|
|
|
|
// Method to delete the temporary file
|
|
func deleteTemporaryFile() {
|
|
let tempFileURL = vm.audioURLFromMP4!
|
|
do {
|
|
try FileManager.default.removeItem(at: tempFileURL)
|
|
print("Temporary file deleted successfully.")
|
|
} catch {
|
|
print("Error deleting temporary file: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
|
|
print("Document picker was cancelled")
|
|
}
|
|
}
|
|
// MARK: - Full Screen Handling
|
|
|
|
extension JWKaraokePlayerVC {
|
|
|
|
func playerViewControllerWillGoFullScreen(_ controller: JWPlayerViewController) -> JWFullScreenViewController? {
|
|
// controller.shouldEnterFullScreen = false
|
|
// self.setDeviceOrientation(orientation: .portrait)
|
|
self.player.stop()
|
|
self.dismiss(animated: true)
|
|
|
|
vm.updateKaraokeVideoView()
|
|
|
|
print("playerViewControllerWillGoFullScreen")
|
|
return nil
|
|
}
|
|
|
|
func playerViewControllerDidGoFullScreen(_ controller: JWPlayerViewController) {
|
|
print("playerViewControllerDidGoFullScreen")
|
|
|
|
return
|
|
}
|
|
|
|
func playerViewControllerWillDismissFullScreen(_ controller: JWPlayerViewController) {
|
|
print("playerViewControllerWillDismissFullScreen")
|
|
|
|
}
|
|
|
|
func playerViewControllerDidDismissFullScreen(_ controller: JWPlayerViewController) {
|
|
// print("playerViewControllerDidDismissFullScreen")
|
|
//
|
|
// self.dismissTapped?()
|
|
// Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
|
|
// self.player.stop()
|
|
// controller.dismiss(animated: true)
|
|
// }
|
|
}
|
|
}
|
|
|
|
// MARK: - JWPlayerViewController Delegate Functions
|
|
|
|
extension JWKaraokePlayerVC {
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, controlBarVisibilityChanged isVisible: Bool, frame: CGRect) {
|
|
self.backButton.isHidden = !isVisible
|
|
// backButton.isHidden = !isVisible
|
|
}
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, sizeChangedFrom oldSize: CGSize, to newSize: CGSize) {
|
|
// Handle size change if necessary
|
|
}
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, screenTappedAt position: CGPoint) {
|
|
// Handle screen tap if necessary
|
|
}
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedMenuOpenedWithItems items: [JWPlayerKit.JWPlayerItem], withMethod method: JWPlayerKit.JWRelatedInteraction) {
|
|
print("Related items:", items)
|
|
}
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedMenuClosedWithMethod method: JWRelatedInteraction) {
|
|
print("Related menu closed")
|
|
}
|
|
|
|
func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedItemBeganPlaying item: JWPlayerKit.JWPlayerItem, atIndex index: Int, withMethod method: JWPlayerKit.JWRelatedMethod) {
|
|
print("Item ", item)
|
|
}
|
|
}
|
|
|
|
// MARK: - Google Ad Banner Delegate
|
|
|
|
extension JWKaraokePlayerVC : GADBannerViewDelegate{
|
|
func bannerViewDidReceiveAd(_ bannerView: GADBannerView) {
|
|
print("bannerViewDidReceiveAd")
|
|
bannerView.backgroundColor = #colorLiteral(red: 0.01960784314, green: 0, blue: 0.2196078431, alpha: 1)
|
|
}
|
|
|
|
func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: Error) {
|
|
print("bannerView:didFailToReceiveAdWithError: \(error.localizedDescription)")
|
|
}
|
|
|
|
func bannerViewDidRecordImpression(_ bannerView: GADBannerView) {
|
|
print("bannerViewDidRecordImpression")
|
|
}
|
|
|
|
func bannerViewWillPresentScreen(_ bannerView: GADBannerView) {
|
|
print("bannerViewWillPresentScreen")
|
|
}
|
|
|
|
func bannerViewWillDismissScreen(_ bannerView: GADBannerView) {
|
|
print("bannerViewWillDIsmissScreen")
|
|
}
|
|
|
|
func bannerViewDidDismissScreen(_ bannerView: GADBannerView) {
|
|
print("bannerViewDidDismissScreen")
|
|
}
|
|
}
|
|
|
|
//OLD Code
|
|
//private var audioEngine: AVAudioEngine!
|
|
// private var audioFile: AVAudioFile!
|
|
// private var audioPlayerNode: AVAudioPlayerNode!
|
|
// private var recordedAudioFile: AVAudioFile!
|
|
//private var recordingURL: URL!
|
|
//
|
|
//private func setupAudioEngine() {
|
|
// audioEngine = AVAudioEngine()
|
|
// audioPlayerNode = AVAudioPlayerNode()
|
|
//
|
|
// audioEngine.attach(audioPlayerNode)
|
|
// let format = audioEngine.mainMixerNode.outputFormat(forBus: 0)
|
|
// audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: format)
|
|
//}
|
|
//
|
|
//private func startRecording() {
|
|
// let format = audioEngine.mainMixerNode.outputFormat(forBus: 0)
|
|
// let outputFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("savedRecordedAudio.m4a")
|
|
// recordingURL = outputFileURL
|
|
//
|
|
// do {
|
|
// recordedAudioFile = try AVAudioFile(forWriting: outputFileURL, settings: format.settings)
|
|
// } catch {
|
|
// print("Error creating audio file for recording: \(error)")
|
|
// return
|
|
// }
|
|
//
|
|
// audioEngine.mainMixerNode.installTap(onBus: 0, bufferSize: 1024, format: format) { (buffer, time) in
|
|
// do {
|
|
// try self.recordedAudioFile?.write(from: buffer)
|
|
// } catch {
|
|
// print("Error writing audio buffer: \(error)")
|
|
// }
|
|
// }
|
|
//
|
|
// do {
|
|
// try audioEngine.start()
|
|
// } catch {
|
|
// print("Error starting audio engine: \(error)")
|
|
// return
|
|
// }
|
|
//
|
|
// audioPlayerNode.play()
|
|
//}
|
|
//
|
|
//private func stopRecording() {
|
|
// audioEngine.mainMixerNode.removeTap(onBus: 0)
|
|
// audioPlayerNode.stop()
|
|
// audioEngine.stop()
|
|
// guard let mixedAudioURL = recordingURL else { return }
|
|
// playAudio(at: mixedAudioURL)
|
|
//// presentDocumentPicker()
|
|
// }
|
|
//
|
|
//private func playAudio(at url: URL) {
|
|
// do {
|
|
// let audioPlayer = try AVAudioPlayer(contentsOf: url)
|
|
// audioPlayer.play()
|
|
// } catch {
|
|
// print("Error playing audio: \(error)")
|
|
// }
|
|
//}
|
|
//
|
|
//private func getDocumentsDirectory() -> URL {
|
|
// return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
|
//}
|
|
//
|
|
//private func presentDocumentPicker() {
|
|
// guard let mixedAudioURL = recordingURL else { return }
|
|
// DispatchQueue.main.async {
|
|
// let documentPicker = UIDocumentPickerViewController(url: mixedAudioURL, in: .exportToService)
|
|
// documentPicker.delegate = self
|
|
// self.present(documentPicker, animated: true, completion: nil)
|
|
// }
|
|
//}
|
|
//
|
|
//private func saveRecordingToFile() {
|
|
// let fileManager = FileManager.default
|
|
// let documentsURL = getDocumentsDirectory().appendingPathComponent("savedRecordedAudio.m4a")
|
|
//
|
|
// do {
|
|
// if fileManager.fileExists(atPath: documentsURL.path) {
|
|
// try fileManager.removeItem(at: documentsURL)
|
|
// }
|
|
// try fileManager.moveItem(at: recordingURL, to: documentsURL)
|
|
// print("Recording saved to: \(documentsURL)")
|
|
// } catch {
|
|
// print("Error saving recording: \(error)")
|
|
// }
|
|
//}
|