PQSingletoVideoPlayer.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. //
  2. // PQVideoPlayer.swift
  3. // PQSpeed
  4. //
  5. // Created by SanW on 2020/6/3.
  6. // Copyright © 2020 BytesFlow. All rights reserved.
  7. //
  8. import BFAnalyzeKit
  9. import BFCommonKit
  10. import BFUploadKit
  11. import UIKit
  12. import CryptoSwift
  13. public class PQSingletoVideoPlayer: NSObject {
  14. public static let shared = PQSingletoVideoPlayer()
  15. public var isPlayEnd: Bool = false // 是否已播放完成
  16. public var isHomePageAllList: Bool = false // 首页加入/关注是否是全部列表
  17. public var lastPlaybackTime: Float = 0 // 上次上报播放时长
  18. public var isRealPlay: Bool = false // 是否已真实播放
  19. public var isSemiRealPlay: Bool = false // 是否已播放到十秒
  20. public var isPlayBegin: Bool = false // 是否已缓冲完成开始播放
  21. public var isFirstFrame: Bool = false // 是否已显示第一帧加载完成
  22. public var isPlayerError: Bool = false // 是否播放失败
  23. public var loadingTime: TimeInterval = 0 // 加载时长
  24. public var playId: String = getUniqueId(desc: "playId") // 播放ID
  25. /// 进度回调
  26. public var progressBloc: ((_ loadProgress: Float, _ playProgress: Float, _ duration: Float) -> Void)?
  27. /// 播放状态回调
  28. public var playStatusBloc: ((_ playStatus: PQVIDEO_PLAY_STATUS) -> Void)?
  29. public var playControllerView: UIView?
  30. public var playVideoData: BFVideoItemProtocol?
  31. public var isPlaying: Bool {
  32. return player.isPlaying()
  33. }
  34. public var autoResumePlayWhenEnterForeground: Bool = true
  35. var shouldResumePlayWhenEnterForeground: Bool = false
  36. public lazy var player: TXVodPlayer = {
  37. let player = TXVodPlayer()
  38. let config = TXVodPlayConfig()
  39. config.cacheFolderPath = videoCacheDirectory
  40. config.maxCacheItems = 5
  41. let httpHeader : [String : String] = ["Referer":"http://appspeed.piaoquantv.com"]
  42. config.headers = httpHeader
  43. player.config = config
  44. player.vodDelegate = self
  45. player.setRenderMode(.RENDER_MODE_FILL_SCREEN)
  46. return player
  47. }()
  48. /// 配置播放器
  49. /// - Parameters:
  50. /// - videoData: <#videoData description#>
  51. /// - controllerView: <#controllerView description#>
  52. public func configPlyer(videoData: BFVideoItemProtocol, controllerView: UIView, renderMode: TX_Enum_Type_RenderMode = .RENDER_MODE_FILL_SCREEN, isAllList: Bool = false) {
  53. // if playVideoData?.id == videoData.id {
  54. // return
  55. // }
  56. isHomePageAllList = isAllList
  57. isPlayEnd = false
  58. isRealPlay = false
  59. isSemiRealPlay = false
  60. isPlayBegin = false
  61. isFirstFrame = false
  62. isPlayerError = false
  63. loadingTime = Date().timeIntervalSince1970 * 1000
  64. player.setRenderMode(renderMode)
  65. player.stopPlay()
  66. player.removeVideoWidget()
  67. player.setupVideoWidget(controllerView, insert: 0)
  68. player.enableHWAcceleration = true
  69. playControllerView = controllerView
  70. playVideoData = videoData
  71. if playVideoData!.playProgress >= 0.0 {
  72. var progress: CGFloat = CGFloat(playVideoData!.playProgress)
  73. if progress > 5.0, progress < 20 {
  74. progress = progress - 5.0
  75. if progress <= 0 {
  76. progress = 0
  77. }
  78. }
  79. BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
  80. player.setStartTime(progress)
  81. }
  82. playId = getUniqueId(desc: "playId")
  83. lastPlaybackTime = 0
  84. BFLog(message: "\(String(describing: videoData.title)) 开始播放 \(videoData.videoPath ?? "")")
  85. if PQSingletoMemoryUtil.shared.playCount < 4 {
  86. PQSingletoMemoryUtil.shared.playCount = PQSingletoMemoryUtil.shared.playCount + 1
  87. }
  88. }
  89. public func reRenderView(newView: UIView) {
  90. player.removeVideoWidget()
  91. player.setupVideoWidget(newView, insert: 0)
  92. }
  93. /// 重制播放
  94. public func resetPlayer() {
  95. if playControllerView != nil {
  96. let playDuration = player.currentPlaybackTime() - lastPlaybackTime
  97. debugPrint("当前播放时长:\(player.currentPlaybackTime()),lastPlaybackTime:\(lastPlaybackTime),playDuration:\(playDuration)")
  98. if playDuration > 0 {
  99. var extParams: [String: Any]?
  100. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  101. extParams = ["topicId": isHomePageAllList ? "all" : "\(playVideoData?.topicData?["id"] ?? "")"]
  102. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  103. extParams = ["followedUid": isHomePageAllList ? "all" : "\(playVideoData?.user?["uid"] ?? "")"]
  104. } else if playVideoData?.pageSource == .sp_cmunit_newTopicDetail || playVideoData?.pageSource == .sp_cmunit_hotTopicDetail {
  105. extParams = ["topicId": "\(playVideoData?.topicData?["id"] ?? "")"]
  106. }
  107. BFEventTrackAdaptor.baseReportUpload(logType: .st_log_type_pLayaction, businessType: .bt_videoPlayDuration, objectType: nil, pageSource: playVideoData?.pageSource ?? .sp_cmunit_recommend, eventData: ["pageSource": (playVideoData?.pageSource ?? .sp_cmunit_recommend).rawValue, "playDuration": Int64(playDuration * 1000), "playId": playId, "uid": "\(playVideoData?.user?["uid"] ?? "")", "videoId": playVideoData?.id ?? 0], extParams: extParams, commonParams: commonParams())
  108. lastPlaybackTime = player.currentPlaybackTime()
  109. }
  110. player.removeVideoWidget()
  111. player.setupVideoWidget(playControllerView, insert: 0)
  112. if playVideoData!.playProgress >= 0.0 {
  113. //
  114. var progress: CGFloat = CGFloat(playVideoData!.playProgress)
  115. if progress > 5.0, progress < 20 {
  116. progress = progress - 5.0
  117. if progress <= 0 {
  118. progress = 0
  119. }
  120. }
  121. BFLog(message: "xxx.playProgress =\(playVideoData!.playProgress),\(progress)")
  122. player.setStartTime(progress)
  123. }
  124. playId = getUniqueId(desc: "playId")
  125. // 开始播放
  126. if let vc = bf_getCurrentViewController(), let playview = playControllerView {
  127. if playview.isDescendant(of: vc.view) {
  128. startPlayr()
  129. }
  130. }
  131. }
  132. }
  133. /// 开始播放
  134. public func startPlayr() {
  135. BFLog(message: "开始播放 \(playVideoData?.videoPath ?? "")")
  136. // 2023-08-28 增加加密地址,修改逻辑
  137. // if isValidURL(url: playVideoData?.videoPath) {
  138. // player.startPlay(playVideoData?.videoPath)
  139. // }
  140. if let realPath = getRealVideoPath(url: playVideoData?.videoPath) {
  141. player.startPlay(realPath)
  142. }
  143. }
  144. public func getRealVideoPath(url: String?) -> String?{
  145. var tmpUrl = url
  146. if tmpUrl == nil || (tmpUrl?.count ?? 0) <= 4 {
  147. return nil
  148. }
  149. if !(tmpUrl!.hasPrefix("http")) && !(tmpUrl!.hasPrefix("https")) {
  150. do {
  151. let encrytoData = Data(base64Encoded: tmpUrl!, options: .ignoreUnknownCharacters) ?? Data()
  152. let key: String = "pqv2jo0lon2vid2t"
  153. let decryptedString = try aes128Decrypt(data: encrytoData, key: key)
  154. print("Decrypted String: \(decryptedString)")
  155. return decryptedString
  156. }catch {
  157. print("Decryption error: \(error)")
  158. }
  159. }
  160. return url
  161. }
  162. func aes128Decrypt(data: Data, key: String) throws -> String {
  163. let keyData = Array(key.utf8)
  164. do {
  165. let aes = try AES(key: keyData, blockMode: ECB(), padding: .pkcs7)
  166. let decrypted = try aes.decrypt(data.bytes)
  167. let decryptedData = Data(decrypted)
  168. if let decryptedString = String(data: decryptedData, encoding: .utf8) {
  169. return decryptedString
  170. } else {
  171. throw CryptoError.decryptionFailed
  172. }
  173. } catch {
  174. throw CryptoError.decryptionFailed
  175. }
  176. }
  177. enum CryptoError: Error {
  178. case decryptionFailed
  179. }
  180. /// 暂停播放
  181. public func pausePlayer() {
  182. player.pause()
  183. let playDuration = player.currentPlaybackTime() - lastPlaybackTime
  184. debugPrint("当前播放时长:\(player.currentPlaybackTime()),lastPlaybackTime:\(lastPlaybackTime),playDuration:\(playDuration)")
  185. if playDuration > 0 {
  186. var extParams: [String: Any]?
  187. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  188. extParams = ["topicId": isHomePageAllList ? "all" : "\(playVideoData?.topicData?["id"] ?? "")"]
  189. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  190. extParams = ["followedUid": isHomePageAllList ? "all" : "\(playVideoData?.user?["uid"] ?? "")"]
  191. } else if playVideoData?.pageSource == .sp_cmunit_newTopicDetail || playVideoData?.pageSource == .sp_cmunit_hotTopicDetail {
  192. extParams = ["topicId": "\(playVideoData?.topicData?["id"] ?? "")"]
  193. }
  194. BFEventTrackAdaptor.baseReportUpload(logType: .st_log_type_pLayaction, businessType: .bt_videoPlayDuration, objectType: nil, pageSource: playVideoData?.pageSource ?? .sp_cmunit_recommend, eventData: ["pageSource": (playVideoData?.pageSource ?? .sp_cmunit_recommend).rawValue, "playDuration": Int64(playDuration * 1000), "playId": playId, "uid": "\(playVideoData?.user?["uid"] ?? "")", "videoId": playVideoData?.id ?? 0], extParams: extParams, commonParams: commonParams())
  195. lastPlaybackTime = player.currentPlaybackTime()
  196. }
  197. }
  198. /// 继续播放
  199. public func resumePlayer(renderMode: TX_Enum_Type_RenderMode? = nil) {
  200. player.resume()
  201. if renderMode != nil {
  202. player.setRenderMode(renderMode!)
  203. }
  204. let playDuration = player.currentPlaybackTime() - lastPlaybackTime
  205. debugPrint("当前播放时长:\(player.currentPlaybackTime()),lastPlaybackTime:\(lastPlaybackTime),playDuration:\(playDuration)")
  206. if playDuration > 0 {
  207. var extParams: [String: Any]?
  208. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  209. extParams = ["topicId": isHomePageAllList ? "all" : "\(playVideoData?.topicData?["id"] ?? "")"]
  210. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  211. extParams = ["followedUid": isHomePageAllList ? "all" : "\(playVideoData?.user?["uid"] ?? "")"]
  212. } else if playVideoData?.pageSource == .sp_cmunit_newTopicDetail || playVideoData?.pageSource == .sp_cmunit_hotTopicDetail {
  213. extParams = ["topicId": "\(playVideoData?.topicData?["id"] ?? "")"]
  214. }
  215. BFEventTrackAdaptor.baseReportUpload(logType: .st_log_type_pLayaction, businessType: .bt_videoPlayDuration, objectType: nil, pageSource: playVideoData?.pageSource ?? .sp_cmunit_recommend, eventData: ["pageSource": (playVideoData?.pageSource ?? .sp_cmunit_recommend).rawValue, "playDuration": Int64(playDuration * 1000), "playId": playId, "uid": "\(playVideoData?.user?["uid"] ?? "")", "videoId": playVideoData?.id ?? 0], extParams: extParams, commonParams: commonParams())
  216. lastPlaybackTime = player.currentPlaybackTime()
  217. }
  218. }
  219. /// 停止播放
  220. /// - Parameter isRemove: 是否移除载体视图
  221. public func stopPlayer(isRemove: Bool = true) {
  222. player.stopPlay()
  223. if isRemove {
  224. player.removeVideoWidget()
  225. playControllerView = nil
  226. playVideoData = nil
  227. }
  228. let playDuration = player.currentPlaybackTime() - lastPlaybackTime
  229. debugPrint("当前播放时长:\(player.currentPlaybackTime()),lastPlaybackTime:\(lastPlaybackTime),playDuration:\(playDuration)")
  230. if playDuration > 0 {
  231. var extParams: [String: Any]?
  232. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  233. extParams = ["topicId": isHomePageAllList ? "all" : "\(playVideoData?.topicData?["id"] ?? "")"]
  234. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  235. extParams = ["followedUid": isHomePageAllList ? "all" : "\(playVideoData?.user?["uid"] ?? "")"]
  236. } else if playVideoData?.pageSource == .sp_cmunit_newTopicDetail || playVideoData?.pageSource == .sp_cmunit_hotTopicDetail {
  237. extParams = ["topicId": "\(playVideoData?.topicData?["id"] ?? "")"]
  238. }
  239. BFEventTrackAdaptor.baseReportUpload(logType: .st_log_type_pLayaction, businessType: .bt_videoPlayDuration, objectType: nil, pageSource: playVideoData?.pageSource ?? .sp_cmunit_recommend, eventData: ["pageSource": (playVideoData?.pageSource ?? .sp_cmunit_recommend).rawValue, "playDuration": Int64(playDuration * 1000), "playId": playId, "uid": "\(playVideoData?.user?["uid"] ?? "")", "videoId": playVideoData?.id ?? 0], extParams: extParams, commonParams: commonParams())
  240. lastPlaybackTime = player.currentPlaybackTime()
  241. }
  242. }
  243. /// seek
  244. /// - Parameter time: <#time description#>
  245. public func seek(time: Float) {
  246. player.seek(time)
  247. }
  248. override private init() {
  249. super.init()
  250. NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { _ in
  251. if self.isPlaying {
  252. self.pausePlayer()
  253. self.shouldResumePlayWhenEnterForeground = true
  254. }
  255. }
  256. NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: nil) { _ in
  257. if self.autoResumePlayWhenEnterForeground, self.shouldResumePlayWhenEnterForeground {
  258. if let vc = bf_getCurrentViewController(), let playview = self.playControllerView {
  259. if playview.isDescendant(of: vc.view) {
  260. self.shouldResumePlayWhenEnterForeground = false
  261. self.resumePlayer()
  262. }
  263. }
  264. }
  265. }
  266. }
  267. override public func copy() -> Any {
  268. return self
  269. }
  270. override public func mutableCopy() -> Any {
  271. return self
  272. }
  273. }
  274. extension PQSingletoVideoPlayer: TXVodPlayListener {
  275. /// 播放进度回调
  276. /// - Parameters:
  277. /// - player: <#player description#>
  278. /// - EvtID: <#EvtID description#>
  279. /// - param: <#param description#>
  280. public func onPlayEvent(_ player: TXVodPlayer!, event: Int32, withParam param: [AnyHashable: Any]!) {
  281. if event != PLAY_EVT_PLAY_PROGRESS.rawValue {
  282. BFLog(message: "播放器状态回调:event:\(event),status:\(EventID(event)),param:\(param ?? [:])")
  283. }
  284. switch event {
  285. case PLAY_EVT_PLAY_PROGRESS.rawValue: // 播放进度
  286. // 加载进度, 单位是秒
  287. let loadProgress: Float = param[EVT_PLAYABLE_DURATION] as! Float
  288. // 播放进度, 单位是秒
  289. let playProgress: Float = param[EVT_PLAY_PROGRESS] as! Float
  290. // 总长度, 单位是秒
  291. let duration: Float = param[EVT_PLAY_DURATION] as! Float
  292. if player.currentPlaybackTime() >= 10.0, player.currentPlaybackTime() <= 10.1 {
  293. // 10.0上报
  294. if !isSemiRealPlay, playVideoData != nil {
  295. isSemiRealPlay = true
  296. // 播放上报
  297. var extParams: [String: Any]?
  298. if isHomePageAllList {
  299. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  300. extParams = ["topicId": "all"]
  301. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  302. extParams = ["followedUid": "all"]
  303. }
  304. }
  305. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoSemiRealPlay, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  306. }
  307. }
  308. if player.currentPlaybackTime() >= 20.0 || ((playProgress / duration) >= 0.3) {
  309. // 视频播放到20s或播放到总时长30%,哪个先到为准
  310. if !isRealPlay, playVideoData != nil {
  311. isRealPlay = true
  312. // 播放上报
  313. var extParams: [String: Any]?
  314. if isHomePageAllList {
  315. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  316. extParams = ["topicId": "all"]
  317. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  318. extParams = ["followedUid": "all"]
  319. }
  320. }
  321. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_realPlay, videoData: playVideoData, pageSource: nil, businessType: .bt_videoRealPlay, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  322. }
  323. }
  324. playVideoData?.playProgress = Float64(playProgress)
  325. if progressBloc != nil {
  326. progressBloc!(loadProgress, playProgress, duration)
  327. }
  328. case PLAY_EVT_RCV_FIRST_I_FRAME.rawValue:
  329. // 首帧完成开始播放
  330. if !isPlayBegin, playVideoData != nil {
  331. isPlayBegin = true
  332. // 播放上报
  333. var extParams: [String: Any]?
  334. if isHomePageAllList {
  335. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  336. extParams = ["topicId": "all"]
  337. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  338. extParams = ["followedUid": "all"]
  339. }
  340. }
  341. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySuccess, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  342. }
  343. case PLAY_EVT_PLAY_LOADING.rawValue: // 视频播放loading
  344. if playStatusBloc != nil {
  345. playStatusBloc!(.PQVIDEO_PLAY_STATUS_LOADING)
  346. }
  347. case PLAY_EVT_PLAY_BEGIN.rawValue: // 开始播放
  348. if playStatusBloc != nil {
  349. playStatusBloc!(.PQVIDEO_PLAY_STATUS_BEGIN)
  350. }
  351. // 首帧加载完成
  352. if !isFirstFrame, playVideoData != nil {
  353. isFirstFrame = true
  354. // 播放上报
  355. var extParams: [String: Any]?
  356. if isHomePageAllList {
  357. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  358. extParams = ["topicId": "all"]
  359. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  360. extParams = ["followedUid": "all"]
  361. }
  362. }
  363. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_play, videoData: playVideoData, pageSource: nil, businessType: nil, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  364. let duration = Int((Date().timeIntervalSince1970 * 1000) - loadingTime)
  365. BFLog(message: "加载时长:\(duration)")
  366. // 加载时间上报
  367. var timeExtParams: [String: Any] = ["duration": duration, "proxyEnable": "0", "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0"]
  368. if extParams != nil {
  369. timeExtParams.merge(extParams!) { keyValue, _ in
  370. keyValue
  371. }
  372. }
  373. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySuccessTime, objectType: nil, extParams: timeExtParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  374. }
  375. BFLog(message: "首帧加载完成")
  376. case PLAY_EVT_PLAY_END.rawValue: // 播放结束
  377. player.pause()
  378. playId = getUniqueId(desc: "playId")
  379. if playStatusBloc != nil {
  380. playStatusBloc!(.PQVIDEO_PLAY_STATUS_END)
  381. }
  382. if !isPlayEnd, playVideoData != nil {
  383. isPlayEnd = true
  384. // 播放结束上报
  385. var extParams: [String: Any]?
  386. if isHomePageAllList {
  387. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  388. extParams = ["topicId": "all"]
  389. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  390. extParams = ["followedUid": "all"]
  391. }
  392. }
  393. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayEnd, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  394. }
  395. let playDuration = player.currentPlaybackTime() - lastPlaybackTime
  396. debugPrint("当前播放时长:\(player.currentPlaybackTime()),lastPlaybackTime:\(lastPlaybackTime),playDuration:\(playDuration)")
  397. if playDuration > 0 {
  398. var extParams: [String: Any]?
  399. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  400. extParams = ["topicId": isHomePageAllList ? "all" : "\(playVideoData?.topicData?["id"] ?? "")"]
  401. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  402. extParams = ["followedUid": isHomePageAllList ? "all" : "\(playVideoData?.user?["uid"] ?? "")"]
  403. } else if playVideoData?.pageSource == .sp_cmunit_newTopicDetail || playVideoData?.pageSource == .sp_cmunit_hotTopicDetail {
  404. extParams = ["topicId": "\(playVideoData?.topicData?["id"] ?? "")"]
  405. }
  406. BFEventTrackAdaptor.baseReportUpload(logType: .st_log_type_pLayaction, businessType: .bt_videoPlayDuration, objectType: nil, pageSource: playVideoData?.pageSource ?? .sp_cmunit_recommend, eventData: ["pageSource": (playVideoData?.pageSource ?? .sp_cmunit_recommend).rawValue, "playDuration": Int64(playDuration * 1000), "playId": playId, "uid": "\(playVideoData?.user?["uid"] ?? "")", "videoId": playVideoData?.id ?? 0], extParams: extParams, commonParams: commonParams())
  407. lastPlaybackTime = player.currentPlaybackTime()
  408. }
  409. case PLAY_ERR_NET_DISCONNECT.rawValue, -2301: // 重连失败
  410. if playStatusBloc != nil {
  411. playStatusBloc!(.PQVIDEO_PLAY_STATUS_DISCONNECT)
  412. }
  413. if !isPlayerError, playVideoData != nil {
  414. isPlayerError = true
  415. // 播放失败
  416. var extParams: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": true, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event]
  417. if isHomePageAllList {
  418. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  419. extParams["topicId"] = "all"
  420. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  421. extParams["followedUid"] = "all"
  422. }
  423. }
  424. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  425. }
  426. case PLAY_ERR_FILE_NOT_FOUND.rawValue: // 播放文件不存在
  427. if playStatusBloc != nil {
  428. playStatusBloc!(.PQVIDEO_PLAY_STATUS_NOT_FOUND)
  429. }
  430. if !isPlayerError, playVideoData != nil {
  431. isPlayerError = true
  432. // 播放失败
  433. var extParams: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": false, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event]
  434. if isHomePageAllList {
  435. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  436. extParams["topicId"] = "all"
  437. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  438. extParams["followedUid"] = "all"
  439. }
  440. }
  441. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  442. }
  443. case PLAY_ERR_HEVC_DECODE_FAIL.rawValue, PLAY_ERR_HLS_KEY.rawValue, PLAY_ERR_GET_PLAYINFO_FAIL.rawValue, PLAY_WARNING_VIDEO_DECODE_FAIL.rawValue, PLAY_WARNING_AUDIO_DECODE_FAIL.rawValue: // H265解码失败,HLS解码key获取失败,获取点播文件信息失败,当前视频解码失败,当前音频解码失败
  444. if playStatusBloc != nil {
  445. playStatusBloc!(PQVIDEO_PLAY_STATUS.PQVIDEO_PLAY_STATUS_FAUILE)
  446. }
  447. if !isPlayerError, playVideoData != nil {
  448. isPlayerError = true
  449. // 播放失败
  450. var extParams: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": false, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event]
  451. if isHomePageAllList {
  452. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  453. extParams["topicId"] = "all"
  454. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  455. extParams["followedUid"] = "all"
  456. }
  457. }
  458. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayError, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  459. }
  460. case PLAY_WARNING_RECONNECT.rawValue: // 断线重连已启动重新连接
  461. if playStatusBloc != nil {
  462. playStatusBloc!(.PQVIDEO_PLAY_STATUS_RECONNECT)
  463. }
  464. var extParams: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": true, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event]
  465. if isHomePageAllList {
  466. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  467. extParams["topicId"] = "all"
  468. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  469. extParams["followedUid"] = "all"
  470. }
  471. }
  472. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayException, objectType: nil, extParams: extParams, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  473. case PLAY_WARNING_RECV_DATA_LAG.rawValue, PLAY_WARNING_VIDEO_PLAY_LAG.rawValue: // 网络来包不稳:可能是下行带宽不足 | 当前视频播放出现卡顿(用户直观感受)
  474. // 播放失败
  475. var extParams1: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event, "position": player.currentPlaybackTime()]
  476. var extParams2: [String: Any] = ["pageSource": playVideoData!.pageSource.rawValue, "networkType": networkStatus(), "extra": "0", "hasRetry": true, "url": playVideoData?.videoPath ?? "", "videoId": playVideoData?.uniqueId ?? "0", "what": event]
  477. if isHomePageAllList {
  478. if playVideoData?.pageSource == .sp_cmunit_joinTopic {
  479. extParams1["topicId"] = "all"
  480. extParams2["topicId"] = "all"
  481. } else if playVideoData?.pageSource == .sp_cmunit_follow {
  482. extParams1["followedUid"] = "all"
  483. extParams2["topicId"] = "all"
  484. }
  485. }
  486. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Frontend, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlaySlow, objectType: nil, extParams: extParams1, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  487. BFEventTrackAdaptor.videoRelationReportUpload(reportLogType: .reportLogType_Action, videoData: playVideoData, pageSource: nil, businessType: .bt_videoPlayException, objectType: nil, extParams: extParams2, shareId: nil, videoIds: nil, playId: playId, headVideoId: (playVideoData as? PQVideoListModel)?.headVideoId, projectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.projectId ?? "", parentProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentProjectId ?? "", rootProjectId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.rootProjectId ?? "", canProduce: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.canReproduce ?? 0, parentVideoId: (playVideoData as? PQVideoListModel)?.reCreateVideoData?.parentVideoId ?? "", commonParams: commonParams())
  488. default:
  489. break
  490. }
  491. }
  492. /// 网络状态回调
  493. /// - Parameters:
  494. /// - player: <#player description#>
  495. /// - param: <#param description#>
  496. public func onNetStatus(_: TXVodPlayer!, withParam _: [AnyHashable: Any]!) {
  497. // BFLog(message: "onNetStatus:\(param)")
  498. }
  499. }