浏览代码

播放器

jsonwang 3 年之前
父节点
当前提交
121f04c4dd
共有 1 个文件被更改,包括 192 次插入0 次删除
  1. 192 0
      BFFramework/Classes/BFModules/BFUtility/BFAudioPlayer.swift

+ 192 - 0
BFFramework/Classes/BFModules/BFUtility/BFAudioPlayer.swift

@@ -0,0 +1,192 @@
+//
+//  BFAudioPlayer.swift
+//  PQSpeed
+//
+//  Created by ak on 2020/8/14.
+//  Copyright © 2020 BytesFlow. All rights reserved.
+//  功能:播放音频文件
+/*  e.g.
+ 
+ BFAudioPlayer.shared.configPlayer(audioPathURL: audioPath)
+ BFAudioPlayer.shared.delegate = self
+ BFAudioPlayer.shared.playOrPause()
+ */
+
+import Foundation
+
+import AVFoundation
+import UIKit
+
+@objc protocol BFAudioPlayerDelegate: NSObjectProtocol {
+    // 播放完成
+    @objc optional func audioPlayerDidFinish()
+
+    // 播放开始
+    @objc optional func audioPlayerStart()
+    // 播放进度
+    @objc optional func playProgress(currentTime: TimeInterval, progress: Double)
+}
+
+class BFAudioPlayer: NSObject {
+    // MARK: - Variables
+
+    var player: AVAudioPlayer?
+    var title: String = ""
+    var artist: String = ""
+    var album: String = ""
+    var artwork: UIImage?
+
+    private var timer: Timer?
+
+    weak var delegate: BFAudioPlayerDelegate?
+
+    // MARK: - Constructor
+
+    override func copy() -> Any {
+        return self
+    }
+
+    override func mutableCopy() -> Any {
+        return self
+    }
+
+    static let shared = BFAudioPlayer()
+
+    override private init() {
+        super.init()
+    }
+
+    func configPlayer(audioPathURL: URL) {
+        BFLog(message: "audioPath is \(audioPathURL.relativePath)")
+        loadMetaDataFromAudioFile(audioPathURL)
+        if !(player != nil && player?.url?.absoluteString == audioPathURL.absoluteString) {
+            do {
+                try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
+                try AVAudioSession.sharedInstance().setActive(true)
+
+                // Prepare player
+                let data: Data = try Data(contentsOf: audioPathURL)
+                player = try AVAudioPlayer(data: data)
+
+            } catch _ {
+                BFLog(message: "播放失败 向上看 系统LOG ")
+                return
+            }
+            player?.currentTime = 0
+            player?.delegate = self
+            player?.enableRate = true
+            player?.prepareToPlay()
+        }
+    }
+
+    // MARK: - Internal methods
+
+    func playOrPause() {
+        if player?.isPlaying ?? false {
+            stopTimer()
+            player?.pause()
+            BFLog(message: "停止播放了")
+        } else {
+            if delegate != nil {
+                delegate?.audioPlayerStart!()
+            }
+            startTimer()
+            player?.play()
+            BFLog(message: "playOrPause开始播放了")
+        }
+    }
+
+    func pause() {
+        if player != nil, player?.isPlaying ?? false {
+            BFLog(message: "停止播放了")
+            stopTimer()
+            player?.pause()
+        }
+    }
+
+    func play() {
+        if delegate != nil {
+            delegate?.audioPlayerStart!()
+        }
+        BFLog(message: "开始播放了")
+        player?.play()
+        startTimer()
+    }
+
+    func stop() {
+        stopTimer()
+        if player != nil {
+            player?.stop()
+        }
+    }
+
+    func setRate(_ rate: Float) {
+        player?.rate = rate
+    }
+
+    func setPlayingTime(_ pos: Double) {
+        player?.currentTime = pos
+    }
+
+    // MARK: - Private methods
+
+    func loadMetaDataFromAudioFile(_ url: URL) {
+        let asset: AVAsset = AVURLAsset(url: url, options: avAssertOptions)
+        let metadata: Array = asset.commonMetadata
+
+        for item in metadata {
+            switch item.commonKey {
+            case AVMetadataKey.commonKeyTitle:
+                title = item.stringValue!
+            case AVMetadataKey.commonKeyAlbumName:
+                album = item.stringValue!
+            case AVMetadataKey.commonKeyArtist:
+                artist = item.stringValue!
+            case AVMetadataKey.commonKeyArtwork:
+                artwork = UIImage(data: item.dataValue!)
+            default:
+                break
+            }
+        }
+    }
+
+    // 开始计时
+    func startTimer() {
+        if timer == nil {
+            timer = PQWeakTimer.scheduledTimer(timeInterval: 1 / 60, target: self, repeats: true) { [weak self] _ in
+
+//                BFLog(message: "播放进度 \(String(describing: self?.player?.currentTime)) 总时长:\(String(describing: self?.player?.duration))")
+                // currentTime 有可能不是从0开始
+                var progress = 0.0
+                if self?.player?.duration ?? 0 > 0 {
+                    progress = Double((self?.player?.currentTime ?? 0) / (self?.player?.duration ?? 1))
+                }
+//                BFLog(message: "progress is \(progress) currentTime\(self?.player?.currentTime)")
+                if self?.delegate != nil {
+                    self!.delegate!.playProgress!(currentTime: self?.player?.currentTime ?? 0, progress: progress)
+                }
+            }
+        }
+    }
+
+    // 停止计时
+    func stopTimer() {
+        if timer != nil {
+            timer?.invalidate() // 销毁timer
+            timer = nil
+        }
+    }
+}
+
+extension BFAudioPlayer: AVAudioPlayerDelegate {
+    func audioPlayerDidFinishPlaying(_: AVAudioPlayer, successfully _: Bool) {
+        if delegate != nil {
+            delegate?.audioPlayerDidFinish!()
+        }
+        stop()
+
+        // Send notification
+        let notification = Notification(name: Notification.Name(rawValue: "stop"), object: self)
+        NotificationCenter.default.post(notification)
+    }
+}