session-ios/Signal/src/phone/PhoneManager.m

162 lines
6.8 KiB
Objective-C

#import "AppAudioManager.h"
#import "CallAudioManager.h"
#import "PhoneManager.h"
#import "RecentCallManager.h"
@implementation PhoneManager
+ (PhoneManager *)phoneManagerWithErrorHandler:(ErrorHandlerBlock)errorHandler {
PhoneManager *m = [PhoneManager new];
m->_errorHandler = errorHandler;
m->currentCallControllerObservable = [ObservableValueController observableValueControllerWithInitialValue:nil];
m->currentCallStateObservable = [ObservableValueController observableValueControllerWithInitialValue:nil];
[m->currentCallControllerObservable watchLatestValue:^(CallController *latestValue) {
[m->currentCallStateObservable updateValue:latestValue.callState];
}
onThread:NSThread.currentThread
untilCancelled:nil];
return m;
}
- (ObservableValue *)currentCallObservable {
return currentCallStateObservable;
}
- (CallController *)cancelExistingCallAndInitNewCallWork:(bool)initiatedLocally
remote:(PhoneNumber *)remoteNumber
optionalContact:(Contact *)contact {
CallController *old = [self curCallController];
CallController *new = [
CallController callControllerForCallInitiatedLocally : initiatedLocally withRemoteNumber : remoteNumber
andOptionallySpecifiedContact : contact
];
[old terminateWithReason:CallTerminationType_ReplacedByNext withFailureInfo:nil andRelatedInfo:nil];
[currentCallControllerObservable updateValue:new];
return new;
}
- (void)initiateOutgoingCallToContact:(Contact *)contact atRemoteNumber:(PhoneNumber *)remoteNumber {
ows_require(remoteNumber != nil);
[self initiateOutgoingCallToRemoteNumber:remoteNumber withOptionallyKnownContact:contact];
}
- (void)initiateOutgoingCallToRemoteNumber:(PhoneNumber *)remoteNumber {
ows_require(remoteNumber != nil);
[self initiateOutgoingCallToRemoteNumber:remoteNumber withOptionallyKnownContact:nil];
}
- (void)initiateOutgoingCallToRemoteNumber:(PhoneNumber *)remoteNumber withOptionallyKnownContact:(Contact *)contact {
ows_require(remoteNumber != nil);
[[AppAudioManager sharedInstance] requestRequiredPermissionsIfNeededWithCompletion:^(BOOL granted) {
if (granted) {
[self callToRemoteNumber:remoteNumber withOptionallyKnownContact:contact];
}
}
incoming:NO];
}
- (void)callToRemoteNumber:(PhoneNumber *)remoteNumber withOptionallyKnownContact:(Contact *)contact {
CallController *callController =
[self cancelExistingCallAndInitNewCallWork:true remote:remoteNumber optionalContact:contact];
[callController acceptCall]; // initiator implicitly accepts call
TOCCancelToken *lifetime = [callController untilCancelledToken];
TOCFuture *futureConnected =
[CallConnectUtil asyncInitiateCallToRemoteNumber:remoteNumber andCallController:callController];
TOCFuture *futureCalling = [futureConnected thenTry:^id(CallConnectResult *connectResult) {
[callController
advanceCallProgressToConversingWithShortAuthenticationString:connectResult.shortAuthenticationString];
CallAudioManager *cam = [CallAudioManager callAudioManagerStartedWithAudioSocket:connectResult.audioSocket
andErrorHandler:callController.errorHandler
untilCancelled:lifetime];
[callController setCallAudioManager:cam];
return nil;
}];
[futureCalling catchDo:^(id error) {
callController.errorHandler(error, nil, true);
}];
}
- (void)incomingCallWithSession:(ResponderSessionDescriptor *)session {
ows_require(session != nil);
int64_t prevSession = lastIncomingSessionId;
lastIncomingSessionId = session.sessionId;
if ([currentCallControllerObservable.currentValue callState].futureTermination.isIncomplete) {
if (session.sessionId == prevSession) {
Environment.errorNoter(@"Ignoring duplicate incoming call signal.", session, false);
return;
}
[Environment.getCurrent.recentCallManager addMissedCallDueToBusy:session];
[[CallConnectUtil asyncSignalTooBusyToAnswerCallWithSessionDescriptor:session] catchDo:^(id error) {
Environment.errorNoter(error, @"Failed to signal busy.", false);
}];
return;
}
[[AppAudioManager sharedInstance] requestRequiredPermissionsIfNeededWithCompletion:^(BOOL granted) {
if (granted) {
Contact *callingContact =
[Environment.getCurrent.contactsManager latestContactForPhoneNumber:session.initiatorNumber];
CallController *callController = [self cancelExistingCallAndInitNewCallWork:false
remote:session.initiatorNumber
optionalContact:callingContact];
TOCCancelToken *lifetime = [callController untilCancelledToken];
TOCFuture *futureConnected =
[CallConnectUtil asyncRespondToCallWithSessionDescriptor:session andCallController:callController];
TOCFuture *futureStarted = [futureConnected thenTry:^id(CallConnectResult *connectResult) {
[callController
advanceCallProgressToConversingWithShortAuthenticationString:connectResult.shortAuthenticationString];
CallAudioManager *cam = [CallAudioManager callAudioManagerStartedWithAudioSocket:connectResult.audioSocket
andErrorHandler:callController.errorHandler
untilCancelled:lifetime];
[callController setCallAudioManager:cam];
return nil;
}];
[futureStarted catchDo:^(id error) {
callController.errorHandler(error, nil, true);
}];
}
}
incoming:YES];
}
- (CallController *)curCallController {
return currentCallControllerObservable.currentValue;
}
- (void)answerCall {
[[self curCallController] acceptCall];
}
- (void)hangupOrDenyCall {
[[self curCallController] hangupOrDenyCall];
}
- (void)backgroundTimeExpired {
[[self curCallController] backgroundTimeExpired];
}
- (BOOL)toggleMute {
return [self.curCallController toggleMute];
}
- (void)terminate {
[[self curCallController] terminateWithReason:CallTerminationType_UncategorizedFailure
withFailureInfo:@"PhoneManager terminated"
andRelatedInfo:nil];
}
@end