Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

JMCallKitEmitter.swift 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright @ 2018-present Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import AVKit
  17. import CallKit
  18. import Foundation
  19. @available(iOS 10.0, *)
  20. internal final class JMCallKitEmitter: NSObject, CXProviderDelegate {
  21. private var listeners = Set<JMCallKitEventListenerWrapper>()
  22. private var pendingMuteActions = Set<UUID>()
  23. internal override init() {}
  24. // MARK: - Add/remove listeners
  25. func addListener(_ listener: JMCallKitListener) {
  26. let wrapper = JMCallKitEventListenerWrapper(listener: listener)
  27. listeners.insert(wrapper)
  28. }
  29. func removeListener(_ listener: JMCallKitListener) {
  30. // XXX Constructing a new JMCallKitEventListenerWrapper instance in
  31. // order to remove the specified listener from listeners is (1) a bit
  32. // funny (though may make a statement about performance) and (2) not
  33. // really an option because the specified listener may already be
  34. // executing its dealloc (like RNCallKit).
  35. listeners.forEach {
  36. // 1. JMCallKitEventListenerWrapper weakly references
  37. // JMCallKitListener so it may be nice to clean
  38. // JMCallKitEventListenerWrapperinstances up if they've lost
  39. // their associated JMCallKitListener instances (e.g. for
  40. // example, because whoever did addListener forgot to
  41. // removeListener). Unfortunately, I don't know how to do it
  42. // because JMCallKitEventListenerWrapper is a struct.
  43. //
  44. // 2. XXX JMCallKitEventListenerWrapper implements the weird
  45. // equality by JMCallKitListener hash which (1) I don't
  46. // understand and (2) I don't know how to invoke without
  47. // duplicating.
  48. if ($0.hashValue == listener.hash) {
  49. listeners.remove($0)
  50. }
  51. }
  52. }
  53. // MARK: - Add mute action
  54. func addMuteAction(_ actionUUID: UUID) {
  55. pendingMuteActions.insert(actionUUID)
  56. }
  57. // MARK: - CXProviderDelegate
  58. func providerDidReset(_ provider: CXProvider) {
  59. listeners.forEach { $0.listener?.providerDidReset?() }
  60. pendingMuteActions.removeAll()
  61. }
  62. func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
  63. listeners.forEach {
  64. $0.listener?.performAnswerCall?(UUID: action.callUUID)
  65. }
  66. action.fulfill()
  67. }
  68. func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
  69. listeners.forEach {
  70. $0.listener?.performEndCall?(UUID: action.callUUID)
  71. }
  72. action.fulfill()
  73. }
  74. func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
  75. let uuid = pendingMuteActions.remove(action.uuid)
  76. // XXX avoid mute actions ping-pong: if the mute action was caused by
  77. // the JS side (we requested a transaction) don't call the delegate
  78. // method. If it was called by the provder itself (when the user presses
  79. // the mute button in the CallKit view) then call the delegate method.
  80. if (uuid == nil) {
  81. listeners.forEach {
  82. $0.listener?.performSetMutedCall?(UUID: action.callUUID,
  83. isMuted: action.isMuted)
  84. }
  85. }
  86. action.fulfill()
  87. }
  88. func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
  89. listeners.forEach {
  90. $0.listener?.performStartCall?(UUID: action.callUUID,
  91. isVideo: action.isVideo)
  92. }
  93. action.fulfill()
  94. }
  95. func provider(_ provider: CXProvider,
  96. didActivate audioSession: AVAudioSession) {
  97. listeners.forEach {
  98. $0.listener?.providerDidActivateAudioSession?(session: audioSession)
  99. }
  100. }
  101. func provider(_ provider: CXProvider,
  102. didDeactivate audioSession: AVAudioSession) {
  103. listeners.forEach {
  104. $0.listener?.providerDidDeactivateAudioSession?(
  105. session: audioSession)
  106. }
  107. }
  108. }
  109. @available(iOS 10.0, *)
  110. fileprivate struct JMCallKitEventListenerWrapper: Hashable {
  111. public var hashValue: Int
  112. internal weak var listener: JMCallKitListener?
  113. public init(listener: JMCallKitListener) {
  114. self.listener = listener
  115. self.hashValue = listener.hash
  116. }
  117. public static func ==(lhs: JMCallKitEventListenerWrapper,
  118. rhs: JMCallKitEventListenerWrapper) -> Bool {
  119. // XXX We're aware that "[t]wo instances with equal hash values are not
  120. // necessarily equal to each other."
  121. return lhs.hashValue == rhs.hashValue
  122. }
  123. }