BellFeature.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. //
  2. // BellFeature.swift
  3. // Pods
  4. //
  5. // Created by janejntang on 2024/11/20.
  6. //
  7. import AVFAudio
  8. class BellFeature: NSObject, AVAudioPlayerDelegate {
  9. private var audioPlayer: AVAudioPlayer?
  10. private let placeholderBellName = "phone_ringing"
  11. private let placeholderBellType = "mp3"
  12. private lazy var customBellPath: String? = {
  13. return ConferenceSession.sharedInstance.implementation.bellPath
  14. }()
  15. private lazy var enableMuteMode: Bool = {
  16. return ConferenceSession.sharedInstance.implementation.enableMuteMode
  17. }()
  18. private var needPlayRingtone = false
  19. override init() {
  20. super.init()
  21. registerNotifications()
  22. }
  23. private func registerNotifications() {
  24. NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption(_:)), name: AVAudioSession.interruptionNotification, object: nil)
  25. NotificationCenter.default.addObserver(self, selector: #selector(handleAppWillResignActive), name: UIApplication.willResignActiveNotification, object: nil)
  26. NotificationCenter.default.addObserver(self, selector: #selector(handleAppDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
  27. }
  28. deinit {
  29. NotificationCenter.default.removeObserver(self)
  30. }
  31. @objc func handleInterruption(_ notification: Notification) {
  32. DispatchQueue.main.async { [weak self] in
  33. guard let self = self else { return }
  34. guard let userInfo = notification.userInfo else { return }
  35. guard let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt else { return }
  36. guard let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return }
  37. switch type {
  38. case .began:
  39. self.audioPlayer?.pause()
  40. case .ended:
  41. let optinsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt ?? 0
  42. let options = AVAudioSession.InterruptionOptions(rawValue: optinsValue)
  43. if options.contains(.shouldResume), !self.enableMuteMode, let audioPlayer = self.audioPlayer {
  44. audioPlayer.play()
  45. }
  46. default: break
  47. }
  48. }
  49. }
  50. @objc func handleAppWillResignActive() {
  51. audioPlayer?.pause()
  52. }
  53. @objc func handleAppDidBecomeActive() {
  54. if needPlayRingtone {
  55. playBell()
  56. needPlayRingtone = false
  57. } else if let audioPlayer = audioPlayer, !audioPlayer.isPlaying, !self.enableMuteMode {
  58. audioPlayer.play()
  59. }
  60. }
  61. func playBell() {
  62. guard !enableMuteMode else { return }
  63. guard let bellURL = findBellPath() else { return }
  64. if UIApplication.shared.applicationState != .background {
  65. playAudio(bellURL)
  66. } else {
  67. needPlayRingtone = true
  68. }
  69. }
  70. func stopBell() {
  71. audioPlayer?.stop()
  72. audioPlayer = nil
  73. needPlayRingtone = false
  74. }
  75. private func findBellPath() -> URL? {
  76. let customBellPath = customBellPath?.replacingOccurrences(of: "file://", with: "")
  77. if let bellPath = customBellPath, checkResourceExisted(path: bellPath) {
  78. return URL(fileURLWithPath: bellPath)
  79. } else {
  80. return tuiRoomKitBundle().url(forResource: placeholderBellName, withExtension: placeholderBellType)
  81. }
  82. }
  83. private func checkResourceExisted(path: String) -> Bool {
  84. return FileManager.default.fileExists(atPath: path)
  85. }
  86. private func playAudio(_ audioURL: URL) {
  87. do {
  88. try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
  89. } catch let error {
  90. debugPrint("AVAudioSession set outputAudioPort error:\(error.localizedDescription)")
  91. }
  92. do {
  93. try audioPlayer = AVAudioPlayer(contentsOf: audioURL)
  94. audioPlayer?.numberOfLoops = -1
  95. audioPlayer?.delegate = self
  96. audioPlayer?.prepareToPlay()
  97. } catch let error {
  98. debugPrint("audioPlayer error: \(error.localizedDescription)")
  99. }
  100. audioPlayer?.play()
  101. }
  102. }