mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Respect silent switch in and out of app.
// FREEBIE
This commit is contained in:
parent
a89bde933d
commit
4374e431a2
|
@ -102,6 +102,8 @@
|
||||||
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
||||||
45F170AD1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
45F170AD1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */; };
|
||||||
45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */; };
|
45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */; };
|
||||||
|
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||||
|
45F170BC1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */; };
|
||||||
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */; };
|
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */; };
|
||||||
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */; };
|
45F2B1971D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */; };
|
||||||
45F2B1981D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */; };
|
45F2B1981D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 45F2B1961D9CA207000D2C69 /* OWSOutgoingMessageCollectionViewCell.xib */; };
|
||||||
|
@ -696,6 +698,7 @@
|
||||||
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; };
|
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; };
|
||||||
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallAudioSessionTest.swift; path = test/call/CallAudioSessionTest.swift; sourceTree = "<group>"; };
|
45F170AE1E2F0393003FC1F2 /* CallAudioSessionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallAudioSessionTest.swift; path = test/call/CallAudioSessionTest.swift; sourceTree = "<group>"; };
|
||||||
45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; };
|
45F170B31E2F0A6A003FC1F2 /* RTCAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCAudioSession.h; sourceTree = "<group>"; };
|
||||||
|
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioService.swift; sourceTree = "<group>"; };
|
||||||
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingMessageCollectionViewCell.h; sourceTree = "<group>"; };
|
45F2B1921D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOutgoingMessageCollectionViewCell.h; sourceTree = "<group>"; };
|
||||||
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingMessageCollectionViewCell.m; sourceTree = "<group>"; };
|
45F2B1931D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOutgoingMessageCollectionViewCell.m; sourceTree = "<group>"; };
|
||||||
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSIncomingMessageCollectionViewCell.xib; sourceTree = "<group>"; };
|
45F2B1951D9CA207000D2C69 /* OWSIncomingMessageCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSIncomingMessageCollectionViewCell.xib; sourceTree = "<group>"; };
|
||||||
|
@ -1535,6 +1538,7 @@
|
||||||
458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */,
|
458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */,
|
||||||
4574A5D51DD6704700C6B692 /* CallService.swift */,
|
4574A5D51DD6704700C6B692 /* CallService.swift */,
|
||||||
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */,
|
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */,
|
||||||
|
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */,
|
||||||
);
|
);
|
||||||
path = call;
|
path = call;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3182,6 +3186,7 @@
|
||||||
453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */,
|
453D28B71D32BA5F00D523F0 /* OWSDisplayedMessage.m in Sources */,
|
||||||
76EB05DC18170B33006006FC /* StreamPair.m in Sources */,
|
76EB05DC18170B33006006FC /* StreamPair.m in Sources */,
|
||||||
76EB064618170B33006006FC /* TimeUtil.m in Sources */,
|
76EB064618170B33006006FC /* TimeUtil.m in Sources */,
|
||||||
|
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
||||||
70BAFD5D190584BE00FA5E0B /* NotificationTracker.m in Sources */,
|
70BAFD5D190584BE00FA5E0B /* NotificationTracker.m in Sources */,
|
||||||
76EB05A418170B33006006FC /* PacketHandler.m in Sources */,
|
76EB05A418170B33006006FC /* PacketHandler.m in Sources */,
|
||||||
E197B62118BBF12700F073E5 /* AppAudioManager.m in Sources */,
|
E197B62118BBF12700F073E5 /* AppAudioManager.m in Sources */,
|
||||||
|
@ -3272,6 +3277,7 @@
|
||||||
B660F70C1C29988E00687D6E /* StretchFactorController.m in Sources */,
|
B660F70C1C29988E00687D6E /* StretchFactorController.m in Sources */,
|
||||||
B660F70D1C29988E00687D6E /* AnonymousAudioCallbackHandler.m in Sources */,
|
B660F70D1C29988E00687D6E /* AnonymousAudioCallbackHandler.m in Sources */,
|
||||||
45F170AD1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */,
|
45F170AD1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */,
|
||||||
|
45F170BC1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
||||||
B660F70E1C29988E00687D6E /* RemoteIOAudio.m in Sources */,
|
B660F70E1C29988E00687D6E /* RemoteIOAudio.m in Sources */,
|
||||||
B660F70F1C29988E00687D6E /* RemoteIOBufferListWrapper.m in Sources */,
|
B660F70F1C29988E00687D6E /* RemoteIOBufferListWrapper.m in Sources */,
|
||||||
456F6E2F1E261D1000FD2210 /* PeerConnectionClientTest.swift in Sources */,
|
456F6E2F1E261D1000FD2210 /* PeerConnectionClientTest.swift in Sources */,
|
||||||
|
|
154
Signal/src/call/CallAudioService.swift
Normal file
154
Signal/src/call/CallAudioService.swift
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
//
|
||||||
|
// Copyright © 2017 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc class CallAudioService: NSObject {
|
||||||
|
private let TAG = "[CallAudioService]"
|
||||||
|
private var vibrateTimer: Timer?
|
||||||
|
private let audioManager = AppAudioManager.sharedInstance()
|
||||||
|
private let soundPlayer = JSQSystemSoundPlayer.shared()!
|
||||||
|
|
||||||
|
enum SoundFilenames: String {
|
||||||
|
case incomingRing = "r"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark: Vibration config
|
||||||
|
private let vibrateRepeatDuration = 1.6
|
||||||
|
|
||||||
|
// Our ring buzz is a pair of vibrations.
|
||||||
|
// `pulseDuration` is the small pause between the two vibrations in the pair.
|
||||||
|
private let pulseDuration = 0.2
|
||||||
|
|
||||||
|
public var isSpeakerphoneEnabled = false {
|
||||||
|
didSet {
|
||||||
|
handleUpdatedSpeakerphone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func handleState(_ state: CallState) {
|
||||||
|
switch state {
|
||||||
|
case .idle: handleIdle()
|
||||||
|
case .dialing: handleDialing()
|
||||||
|
case .answering: handleAnswering()
|
||||||
|
case .remoteRinging: handleRemoteRinging()
|
||||||
|
case .localRinging: handleLocalRinging()
|
||||||
|
case .connected: handleConnected()
|
||||||
|
case .localFailure: handleLocalFailure()
|
||||||
|
case .localHangup: handleLocalHangup()
|
||||||
|
case .remoteHangup: handleRemoteHangup()
|
||||||
|
case .remoteBusy: handleBusy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleIdle() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleDialing() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleAnswering() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleRemoteRinging() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleLocalRinging() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
|
||||||
|
vibrateTimer = Timer.scheduledTimer(timeInterval: vibrateRepeatDuration, target: self, selector: #selector(ringVibration), userInfo: nil, repeats: true)
|
||||||
|
|
||||||
|
// Stop other sounds and play ringer through external speaker
|
||||||
|
setAudioSession(category: AVAudioSessionCategorySoloAmbient)
|
||||||
|
soundPlayer.playSound(withFilename: SoundFilenames.incomingRing.rawValue, fileExtension: kJSQSystemSoundTypeCAF)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleConnected() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
|
||||||
|
// disable start recording to transmit call audio.
|
||||||
|
setAudioSession(category: AVAudioSessionCategoryPlayAndRecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleLocalFailure() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleLocalHangup() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleRemoteHangup() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleBusy() {
|
||||||
|
Logger.debug("\(TAG) \(#function)")
|
||||||
|
stopRinging()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleUpdatedSpeakerphone() {
|
||||||
|
// TODO
|
||||||
|
// let category = AVAudioSession.sharedInstance().getCategory()
|
||||||
|
// if isSpeakerphoneEnabled {
|
||||||
|
// AVAudioSession.sharedInstance().setCategory(category, option: AVAudioSessionCategoryOptionDefaultToSpeaker)
|
||||||
|
// } else {
|
||||||
|
// Will this disable speaker?
|
||||||
|
// AVAudioSession.sharedInstance().setCategory(category)
|
||||||
|
// }
|
||||||
|
|
||||||
|
audioManager.toggleSpeakerPhone(isEnabled: isSpeakerphoneEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Helpers
|
||||||
|
|
||||||
|
private func stopRinging() {
|
||||||
|
vibrateTimer?.invalidate()
|
||||||
|
vibrateTimer = nil
|
||||||
|
soundPlayer.stopSound(withFilename: SoundFilenames.incomingRing.rawValue)
|
||||||
|
// Stop playing out of speaker
|
||||||
|
setAudioSession(category: AVAudioSessionCategoryAmbient)
|
||||||
|
}
|
||||||
|
|
||||||
|
// public so it can be called by timer via selector
|
||||||
|
public func ringVibration() {
|
||||||
|
// Since a call notification is more urgent than a message notifaction, we
|
||||||
|
// vibrate twice, like a pulse, to differentiate from a normal notification vibration.
|
||||||
|
soundPlayer.playVibrateSound()
|
||||||
|
DispatchQueue.default.asyncAfter(deadline: DispatchTime.now() + pulseDuration) {
|
||||||
|
self.soundPlayer.playVibrateSound()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setAudioSession(category: String, options: AVAudioSessionCategoryOptions) {
|
||||||
|
do {
|
||||||
|
try AVAudioSession.sharedInstance().setCategory(category, with: options)
|
||||||
|
Logger.debug("\(self.TAG) set category: \(category) options: \(options)")
|
||||||
|
} catch {
|
||||||
|
let message = "\(self.TAG) in \(#function) failed to set category: \(category) with error: \(error)"
|
||||||
|
assertionFailure(message)
|
||||||
|
Logger.error(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setAudioSession(category: String) {
|
||||||
|
do {
|
||||||
|
try AVAudioSession.sharedInstance().setCategory(category)
|
||||||
|
Logger.debug("\(self.TAG) set category: \(category)")
|
||||||
|
} catch {
|
||||||
|
let message = "\(self.TAG) in \(#function) failed to set category: \(category) with error: \(error)"
|
||||||
|
assertionFailure(message)
|
||||||
|
Logger.error(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,117 +6,6 @@ import Foundation
|
||||||
import WebRTC
|
import WebRTC
|
||||||
import PromiseKit
|
import PromiseKit
|
||||||
|
|
||||||
// TODO move this somewhere else.
|
|
||||||
@objc class CallAudioService: NSObject {
|
|
||||||
private let TAG = "[CallAudioService]"
|
|
||||||
private var vibrateTimer: Timer?
|
|
||||||
private let audioManager = AppAudioManager.sharedInstance()
|
|
||||||
private let soundPlayer = JSQSystemSoundPlayer.shared()!
|
|
||||||
|
|
||||||
enum SoundFilenames: String {
|
|
||||||
case incomingRing = "r"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark: Vibration config
|
|
||||||
private let vibrateRepeatDuration = 1.6
|
|
||||||
|
|
||||||
// Our ring buzz is a pair of vibrations.
|
|
||||||
// `pulseDuration` is the small pause between the two vibrations in the pair.
|
|
||||||
private let pulseDuration = 0.2
|
|
||||||
|
|
||||||
public var isSpeakerphoneEnabled = false {
|
|
||||||
didSet {
|
|
||||||
handleUpdatedSpeakerphone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func handleState(_ state: CallState) {
|
|
||||||
switch state {
|
|
||||||
case .idle: handleIdle()
|
|
||||||
case .dialing: handleDialing()
|
|
||||||
case .answering: handleAnswering()
|
|
||||||
case .remoteRinging: handleRemoteRinging()
|
|
||||||
case .localRinging: handleLocalRinging()
|
|
||||||
case .connected: handleConnected()
|
|
||||||
case .localFailure: handleLocalFailure()
|
|
||||||
case .localHangup: handleLocalHangup()
|
|
||||||
case .remoteHangup: handleRemoteHangup()
|
|
||||||
case .remoteBusy: handleBusy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleIdle() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleDialing() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleAnswering() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleRemoteRinging() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleLocalRinging() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
|
|
||||||
vibrateTimer = Timer.scheduledTimer(timeInterval: vibrateRepeatDuration, target: self, selector: #selector(ringVibration), userInfo: nil, repeats: true)
|
|
||||||
soundPlayer.playSound(withFilename: SoundFilenames.incomingRing.rawValue, fileExtension: kJSQSystemSoundTypeCAF)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleConnected() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleLocalFailure() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleLocalHangup() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleRemoteHangup() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleBusy() {
|
|
||||||
Logger.debug("\(TAG) \(#function)")
|
|
||||||
stopRinging()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func handleUpdatedSpeakerphone() {
|
|
||||||
audioManager.toggleSpeakerPhone(isEnabled: isSpeakerphoneEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Helpers
|
|
||||||
|
|
||||||
private func stopRinging() {
|
|
||||||
vibrateTimer?.invalidate()
|
|
||||||
vibrateTimer = nil
|
|
||||||
|
|
||||||
soundPlayer.stopSound(withFilename: SoundFilenames.incomingRing.rawValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func ringVibration() {
|
|
||||||
// Since a call notification is more urgent than a message notifaction, we
|
|
||||||
// vibrate twice, like a pulse, to differentiate from a normal notification vibration.
|
|
||||||
soundPlayer.playVibrateSound()
|
|
||||||
DispatchQueue.default.asyncAfter(deadline: DispatchTime.now() + pulseDuration) {
|
|
||||||
self.soundPlayer.playVibrateSound()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add category so that button handlers can be defined where button is created.
|
// TODO: Add category so that button handlers can be defined where button is created.
|
||||||
// TODO: Add logic to button handlers.
|
// TODO: Add logic to button handlers.
|
||||||
// TODO: Ensure buttons enabled & disabled as necessary.
|
// TODO: Ensure buttons enabled & disabled as necessary.
|
||||||
|
|
Loading…
Reference in a new issue