Advertisement
jessedirisu

Untitled

Dec 30th, 2023
1,255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 10.53 KB | None | 0 0
  1. import UIKit
  2. import Flutter
  3. import AVFoundation
  4. import MediaPlayer
  5.  
  6. import flutter_downloader
  7.  
  8. @available(iOS 11, *)
  9. @UIApplicationMain
  10. @objc class AppDelegate: FlutterAppDelegate {
  11.     var player: AVPlayer?
  12.     var volume: Float = 1
  13.     var muted: Bool = false
  14.     var lastTrack: String = ""
  15.     var channel: FlutterMethodChannel!
  16.     override func application(
  17.         _ application: UIApplication,
  18.         didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  19.     ) -> Bool {
  20.         GeneratedPluginRegistrant.register(with: self)
  21.         FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
  22.         let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
  23.         channel = FlutterMethodChannel(name: "lighthouse_audio_stream", binaryMessenger: controller.binaryMessenger)
  24.        
  25.         NotificationCenter.default.addObserver(
  26.             self,
  27.             selector: #selector(playerItemDidReachEnd),
  28.             name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
  29.             object: nil
  30.         )
  31.  
  32.         channel.setMethodCallHandler({
  33.                 (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
  34.                 switch(call.method) {
  35.                 case "play":
  36.                     if let args = call.arguments as? Dictionary<String, String> {
  37.                         let url = args["url"] ?? ""
  38.                         let title = args["title"] ?? ""
  39.                         let description = args["description"] ?? ""
  40.                         let image = args["image"] ?? ""
  41.                         if (url.isEmpty) {
  42.                             result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
  43.                         } else {
  44.                             do {
  45.                                let isSameTrack = self.lastTrack == url;
  46.                                if !isSameTrack {
  47.                                    self.lastTrack = url;
  48.                                }
  49.                                try self.play(url: url, isSameTrack: isSameTrack, title: title, description: description, image: image)
  50.                                UIApplication.shared.beginReceivingRemoteControlEvents()
  51.                                result(0)
  52.                            } catch {
  53.                                result(0)
  54.                            }
  55.                         }
  56.                     } else {
  57.                         result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
  58.                     }
  59.                     result(0)
  60.                     return
  61.                 case "disk":
  62.                     if let args = call.arguments as? Dictionary<String, Any>,
  63.                         let path = args["path"] as? String {
  64.                         result(self.diskUsage(path: path))
  65.                     } else {
  66.                         result(FlutterError.init(code: "no url passed", message: "nill", details: "Nill"))
  67.                     }
  68.                     result(0)
  69.                     return
  70.                 case "seek":
  71.                     if let args = call.arguments as? Dictionary<String, Any>,
  72.                         let pos = args["pos"] as? Double {
  73.                         self.seek(pos: pos / 1000)
  74.                         result(nil)
  75.                     } else {
  76.                         result(FlutterError.init(code: "no position passed", message: "nill", details: "Nill"))
  77.                     }
  78.                     result(0)
  79.                     return
  80.                 case "pause":
  81.                     self.pause()
  82.                     result(nil)
  83.                     return
  84.                 case "stop":
  85.                     self.stop()
  86.                     result(nil)
  87.                     return
  88.                 case "mute":
  89.                     self.mute()
  90.                     result(nil)
  91.                     return
  92.                 case "forward":
  93.                     self.seekTo(forward: true)
  94.                     return
  95.                 case "rewind":
  96.                     self.seekTo(forward: false)
  97.                     return
  98.                 case "currentPos":
  99.                     let position = self.currentPos();
  100.                     result(position)
  101.                     return
  102.                 case "rate":
  103.                     self.rate()
  104.                     result(nil)
  105.                     return
  106.                 default:
  107.                     result(FlutterMethodNotImplemented)
  108.                 }
  109.             })
  110.         return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  111.     }
  112.    
  113.     @objc func playerItemDidReachEnd(notification: NSNotification) {
  114.         channel.invokeMethod("stop", arguments: 0)
  115.     }
  116.    
  117.  
  118.     override func remoteControlReceived(with event: UIEvent?) {
  119.         guard let event = event else {
  120.            
  121.             return
  122.         }
  123.         guard event.type == UIEvent.EventType.remoteControl else {
  124.             return
  125.         }
  126.         switch event.subtype {
  127.         case UIEventSubtype.remoteControlPlay:
  128.             player?.play()
  129.             channel.invokeMethod("playing", arguments: 0)
  130.         case UIEventSubtype.remoteControlPause:
  131.             player?.pause()
  132.             channel.invokeMethod("pause", arguments: nil)
  133.         case UIEventSubtype.remoteControlTogglePlayPause:
  134.             print("received toggle\n")
  135.         case UIEventSubtype.remoteControlNextTrack:
  136.             channel.invokeMethod("next", arguments: nil)
  137.         case UIEventSubtype.remoteControlPreviousTrack:
  138.             channel.invokeMethod("prev", arguments: nil)
  139.         default:
  140.             print("received \(event.subtype) which we did not process\n")
  141.         }
  142.     }
  143.    
  144.  
  145.    
  146.     private func play(url: String, isSameTrack: Bool, title: String, description: String, image: String) throws {
  147.         let location: URL? = url.hasPrefix("http") ? URL(string: url) : NSURL.fileURL(withPath: url);
  148.         if let audioUrl = location {
  149.            
  150.             if (player == nil || !isSameTrack) {
  151.                 player = AVPlayer(url: audioUrl)
  152.                 player?.automaticallyWaitsToMinimizeStalling = false;
  153.                 setupNowPlayingInfo(title: title, artist: description, image: image)
  154.             }
  155.             player?.play()
  156.         } else {
  157.             throw PlayerErrors.InvalidUrl
  158.         }
  159.     }
  160.    
  161.     private func seekTo(forward: Bool)  {
  162.         if player != nil {
  163.             let currentPos = CMTimeGetSeconds(player?.currentTime() ?? CMTime(seconds: 0.0, preferredTimescale: 1))
  164.             let goto = forward ? (currentPos + 10.0) : (currentPos - 10.0)
  165.             player?.seek(to: CMTime(seconds: goto, preferredTimescale: 1))
  166.         }
  167.     }
  168.    
  169.     private func seek(pos: Double)  {
  170.         if player != nil {
  171.             player?.seek(to: CMTime(seconds: pos, preferredTimescale: 1))
  172.         }
  173.     }
  174.    
  175.     private func pause() {
  176.         if player != nil {
  177.             player?.pause()
  178.         }
  179.     }
  180.    
  181.     private func stop() {
  182.         if player != nil {
  183.             player?.pause()
  184.             player = nil
  185.         }
  186.     }
  187.    
  188.     private func rate() {
  189.         if let url = URL(string: "itms-apps://apple.com/app/com.thelighthouseapp.app") {
  190.             UIApplication.shared.open(url)
  191.         }
  192.     }
  193.    
  194.     private func currentPos() -> [String: Double] {
  195.         if player != nil {
  196.             var duration = CMTimeGetSeconds(player?.currentItem?.duration ?? CMTime(seconds: 1.0, preferredTimescale: 1))
  197.             if (duration.isNaN || duration < 1) {
  198.                 duration = 1
  199.             }
  200.             let currentTime = CMTimeGetSeconds(player?.currentTime() ?? CMTime(seconds: 0.0, preferredTimescale: 1));
  201.             MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = (currentTime / duration) * 100
  202.             return ["duration": duration * 1000.0, "currentPos": currentTime * 1000.0]
  203.         }
  204.         return ["duration": 1.0, "currentPos": 0.0]
  205.     }
  206.    
  207.     private func mute() {
  208.         if player != nil {
  209.             if muted {
  210.                 player?.volume = volume
  211.                 muted = false
  212.             } else {
  213.                 volume = player?.volume ?? 1.0
  214.                 player?.volume = 0.0
  215.                 muted = true
  216.             }
  217.         }
  218.     }
  219.    
  220.     @available(iOS 11, *)
  221.     private func diskUsage(path: String) -> [String: Int] {
  222.         let dirURL = URL(fileURLWithPath: path)
  223.         do {
  224.             let values = try dirURL.resourceValues(forKeys: [.volumeAvailableCapacityKey, .fileSizeKey, .isDirectoryKey])
  225.             if (values.isDirectory ?? false) {
  226.                 let diskSize = values.volumeAvailableCapacity ?? 0
  227.                 var usedSpace = 0
  228.                 (FileManager.default.enumerator(at: dirURL, includingPropertiesForKeys: nil)?.allObjects as? [URL])?.lazy.forEach {
  229.                     usedSpace += (try? $0.resourceValues(forKeys: [.totalFileAllocatedSizeKey]))?.totalFileAllocatedSize ?? 0
  230.                 }
  231.                 return ["totalSpace": diskSize, "usedSpace": usedSpace]
  232.             } else {
  233.                 return ["totalSpace": 1, "usedSpace": 0]
  234.             }
  235.         } catch {
  236.             return ["totalSpace": 1, "usedSpace": 0]
  237.         }
  238.     }
  239.    
  240.     func setupNowPlayingInfo(title: String, artist: String, image: String) {
  241.             var nowPlayingInfo = [String: Any]()
  242.             nowPlayingInfo[MPMediaItemPropertyTitle] = title
  243.             nowPlayingInfo[MPMediaItemPropertyArtist] = artist
  244.             MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
  245.     }
  246.  
  247.         fileprivate func setupAudioSession() {
  248.             do {
  249.                 try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default)
  250.                 try AVAudioSession.sharedInstance().setActive(true)
  251.             } catch let sessionErr {
  252.                 print("Failed to activate session:", sessionErr)
  253.             }
  254.         }
  255.    
  256.         deinit {
  257.             NotificationCenter.default.removeObserver(self)
  258.         }
  259.  
  260. }
  261.  
  262. enum PlayerErrors: Error {
  263.     case InvalidUrl
  264.    
  265.     func val() -> String {
  266.         switch self {
  267.         case .InvalidUrl:
  268.             return "Cannot play file from this url"
  269.         }
  270.     }
  271. }
  272.  
  273. private func registerPlugins(registry: FlutterPluginRegistry) {
  274.     if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
  275.         FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin"))
  276.     }
  277. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement