| | |
| | | self.pendingCall = NULL; |
| | | self.pendingAddr = NULL; |
| | | self.pendingCallVideo = FALSE; |
| | | CXCallController *callController = [[CXCallController alloc] initWithQueue:dispatch_get_main_queue()]; |
| | | [callController.callObserver setDelegate:self queue:dispatch_get_main_queue()]; |
| | | self.controller = callController; |
| | | self.callKitCalls = 0; |
| | | // CXCallController *callController = [[CXCallController alloc] initWithQueue:dispatch_get_main_queue()]; |
| | | // [callController.callObserver setDelegate:self queue:dispatch_get_main_queue()]; |
| | | // self.controller = callController; |
| | | self.callKCalls = 0; |
| | | |
| | | if (!self) { |
| | | NSLog(@"ProviderDelegate not initialized..."); |
| | |
| | | } |
| | | |
| | | - (void)config { |
| | | CXProviderConfiguration *config = [[CXProviderConfiguration alloc] |
| | | initWithLocalizedName:[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]]; |
| | | config.ringtoneSound = @"notes_of_the_optimistic.caf"; |
| | | config.supportsVideo = TRUE; |
| | | config.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:@"callkit_logo"]); |
| | | |
| | | NSArray *ar = @[ [NSNumber numberWithInt:(int)CXHandleTypeGeneric] ]; |
| | | NSSet *handleTypes = [[NSSet alloc] initWithArray:ar]; |
| | | [config setSupportedHandleTypes:handleTypes]; |
| | | [config setMaximumCallGroups:2]; |
| | | [config setMaximumCallsPerCallGroup:1]; |
| | | //not show app's calls in tel's history |
| | | //config.includesCallsInRecents = NO; |
| | | self.provider = [[CXProvider alloc] initWithConfiguration:config]; |
| | | [self.provider setDelegate:self queue:dispatch_get_main_queue()]; |
| | | // CXProviderConfiguration *config = [[CXProviderConfiguration alloc] |
| | | // initWithLocalizedName:[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]]; |
| | | // config.ringtoneSound = @"notes_of_the_optimistic.caf"; |
| | | // config.supportsVideo = TRUE; |
| | | // config.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:@"callkit_logo"]); |
| | | // |
| | | // NSArray *ar = @[ [NSNumber numberWithInt:(int)CXHandleTypeGeneric] ]; |
| | | // NSSet *handleTypes = [[NSSet alloc] initWithArray:ar]; |
| | | // [config setSupportedHandleTypes:handleTypes]; |
| | | // [config setMaximumCallGroups:2]; |
| | | // [config setMaximumCallsPerCallGroup:1]; |
| | | // //not show app's calls in tel's history |
| | | // //config.includesCallsInRecents = NO; |
| | | // self.provider = [[CXProvider alloc] initWithConfiguration:config]; |
| | | // [self.provider setDelegate:self queue:dispatch_get_main_queue()]; |
| | | } |
| | | |
| | | - (void)configAudioSession:(AVAudioSession *)audioSession { |
| | |
| | | } |
| | | } |
| | | |
| | | - (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; { |
| | | // Create update to describe the incoming call and caller |
| | | CXCallUpdate *update = [[CXCallUpdate alloc] init]; |
| | | update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle]; |
| | | update.supportsDTMF = TRUE; |
| | | update.supportsHolding = TRUE; |
| | | update.supportsGrouping = TRUE; |
| | | update.supportsUngrouping = TRUE; |
| | | update.hasVideo = _pendingCallVideo = video; |
| | | |
| | | // Report incoming call to system |
| | | // LOGD(@"CallKit: report new incoming call with call-id: [%@] and UUID: [%@]", [_calls objectForKey:uuid], uuid); |
| | | [self.provider reportNewIncomingCallWithUUID:uuid |
| | | update:update |
| | | completion:^(NSError *error) { |
| | | if (error) { |
| | | // LOGE(@"CallKit: cannot complete incoming call with call-id: [%@] and UUID: [%@] from [%@] caused by [%@]", |
| | | // [_calls objectForKey:uuid], uuid, handle, [error localizedDescription]); |
| | | if ([error code] == CXErrorCodeIncomingCallErrorFilteredByDoNotDisturb || |
| | | [error code] == CXErrorCodeIncomingCallErrorFilteredByBlockList) |
| | | linphone_call_decline(call,LinphoneReasonBusy); /*to give a chance for other devices to answer*/ |
| | | else |
| | | linphone_call_decline(call,LinphoneReasonUnknown); |
| | | } |
| | | }]; |
| | | } |
| | | //- (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; { |
| | | // // Create update to describe the incoming call and caller |
| | | // CXCallUpdate *update = [[CXCallUpdate alloc] init]; |
| | | // update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle]; |
| | | // update.supportsDTMF = TRUE; |
| | | // update.supportsHolding = TRUE; |
| | | // update.supportsGrouping = TRUE; |
| | | // update.supportsUngrouping = TRUE; |
| | | // update.hasVideo = _pendingCallVideo = video; |
| | | // |
| | | // // Report incoming call to system |
| | | //// LOGD(@"CallKit: report new incoming call with call-id: [%@] and UUID: [%@]", [_calls objectForKey:uuid], uuid); |
| | | // [self.provider reportNewIncomingCallWithUUID:uuid |
| | | // update:update |
| | | // completion:^(NSError *error) { |
| | | // if (error) { |
| | | //// LOGE(@"CallKit: cannot complete incoming call with call-id: [%@] and UUID: [%@] from [%@] caused by [%@]", |
| | | //// [_calls objectForKey:uuid], uuid, handle, [error localizedDescription]); |
| | | // if ([error code] == CXErrorCodeIncomingCallErrorFilteredByDoNotDisturb || |
| | | // [error code] == CXErrorCodeIncomingCallErrorFilteredByBlockList) |
| | | // linphone_call_decline(call,LinphoneReasonBusy); /*to give a chance for other devices to answer*/ |
| | | // else |
| | | // linphone_call_decline(call,LinphoneReasonUnknown); |
| | | // } |
| | | // }]; |
| | | //} |
| | | |
| | | - (void)setPendingCall:(LinphoneCall *)pendingCall { |
| | | if (pendingCall) { |
| | |
| | | |
| | | #pragma mark - CXProviderDelegate Protocol |
| | | |
| | | - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { |
| | | NSUUID *uuid = action.callUUID; |
| | | NSString *callID = [self.calls objectForKey:uuid]; // first, make sure this callid is not already involved in a call |
| | | // LOGD(@"CallKit: Answering call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | [action fulfill]; |
| | | LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | if (!call) |
| | | return; |
| | | //- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { |
| | | // NSUUID *uuid = action.callUUID; |
| | | // NSString *callID = [self.calls objectForKey:uuid]; // first, make sure this callid is not already involved in a call |
| | | //// LOGD(@"CallKit: Answering call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | // [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | // [action fulfill]; |
| | | // LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | // if (!call) |
| | | // return; |
| | | // |
| | | // self.callKitCalls++; |
| | | // self.pendingCall = call; |
| | | //} |
| | | |
| | | self.callKitCalls++; |
| | | self.pendingCall = call; |
| | | } |
| | | |
| | | - (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action { |
| | | NSUUID *uuid = action.callUUID; |
| | | NSString *callID = [self.calls objectForKey:uuid]; // first, make sure this callid is not already involved in a call |
| | | NSLog(@"CallKit: Starting Call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | // To restart Audio Unit |
| | | [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | [action fulfill]; |
| | | LinphoneCall *call; |
| | | if (![callID isEqualToString:@""]) { |
| | | call = linphone_core_get_current_call(LC); |
| | | } else { |
| | | call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | } |
| | | if (call != NULL) { |
| | | self.callKitCalls++; |
| | | self.pendingCall = call; |
| | | } |
| | | } |
| | | |
| | | - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action { |
| | | self.callKitCalls--; |
| | | [action fulfill]; |
| | | if (linphone_core_is_in_conference(LC)) { |
| | | HDLLinphoneManager.instance.conf = TRUE; |
| | | linphone_core_terminate_conference(LC); |
| | | // LOGD(@"CallKit: Ending the conference"); |
| | | } else if (linphone_core_get_calls_nb(LC) > 1) { |
| | | HDLLinphoneManager.instance.conf = TRUE; |
| | | linphone_core_terminate_all_calls(LC); |
| | | // LOGD(@"CallKit: Ending all the ongoing calls"); |
| | | } else { |
| | | NSUUID *uuid = action.callUUID; |
| | | NSString *callID = [self.calls objectForKey:uuid]; |
| | | if (callID) { |
| | | // LOGD(@"CallKit: Ending the call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | if (call) { |
| | | linphone_call_terminate((LinphoneCall *)call); |
| | | } |
| | | [self.uuids removeObjectForKey:callID]; |
| | | [self.calls removeObjectForKey:uuid]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)provider:(CXProvider *)provider performSetMutedCallAction:(nonnull CXSetMutedCallAction *)action { |
| | | [action fulfill]; |
| | | // if ([[PhoneMainView.instance currentView] equal:CallView.compositeViewDescription]) { |
| | | // CallView *view = (CallView *)[PhoneMainView.instance popToView:CallView.compositeViewDescription]; |
| | | // [view.microButton toggle]; |
| | | //- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action { |
| | | // NSUUID *uuid = action.callUUID; |
| | | // NSString *callID = [self.calls objectForKey:uuid]; // first, make sure this callid is not already involved in a call |
| | | // NSLog(@"CallKit: Starting Call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | // // To restart Audio Unit |
| | | // [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | // [action fulfill]; |
| | | // LinphoneCall *call; |
| | | // if (![callID isEqualToString:@""]) { |
| | | // call = linphone_core_get_current_call(LC); |
| | | // } else { |
| | | // call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | // } |
| | | } |
| | | // if (call != NULL) { |
| | | // self.callKitCalls++; |
| | | // self.pendingCall = call; |
| | | // } |
| | | //} |
| | | |
| | | - (void)provider:(CXProvider *)provider performSetHeldCallAction:(nonnull CXSetHeldCallAction *)action { |
| | | [action fulfill]; |
| | | if (linphone_core_is_in_conference(LC) && action.isOnHold) { |
| | | linphone_core_leave_conference(LC); |
| | | // LOGD(@"CallKit: Leaving conference"); |
| | | [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; |
| | | return; |
| | | } |
| | | //- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action { |
| | | // self.callKitCalls--; |
| | | // [action fulfill]; |
| | | // if (linphone_core_is_in_conference(LC)) { |
| | | // HDLLinphoneManager.instance.conf = TRUE; |
| | | // linphone_core_terminate_conference(LC); |
| | | //// LOGD(@"CallKit: Ending the conference"); |
| | | // } else if (linphone_core_get_calls_nb(LC) > 1) { |
| | | // HDLLinphoneManager.instance.conf = TRUE; |
| | | // linphone_core_terminate_all_calls(LC); |
| | | //// LOGD(@"CallKit: Ending all the ongoing calls"); |
| | | // } else { |
| | | // NSUUID *uuid = action.callUUID; |
| | | // NSString *callID = [self.calls objectForKey:uuid]; |
| | | // if (callID) { |
| | | //// LOGD(@"CallKit: Ending the call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | // LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | // if (call) { |
| | | // linphone_call_terminate((LinphoneCall *)call); |
| | | // } |
| | | // [self.uuids removeObjectForKey:callID]; |
| | | // [self.calls removeObjectForKey:uuid]; |
| | | // } |
| | | // } |
| | | //} |
| | | |
| | | if (linphone_core_get_calls_nb(LC) > 1 && action.isOnHold) { |
| | | linphone_core_pause_all_calls(LC); |
| | | // LOGD(@"CallKit: Pausing all ongoing calls"); |
| | | return; |
| | | } |
| | | //- (void)provider:(CXProvider *)provider performSetMutedCallAction:(nonnull CXSetMutedCallAction *)action { |
| | | // [action fulfill]; |
| | | //// if ([[PhoneMainView.instance currentView] equal:CallView.compositeViewDescription]) { |
| | | //// CallView *view = (CallView *)[PhoneMainView.instance popToView:CallView.compositeViewDescription]; |
| | | //// [view.microButton toggle]; |
| | | //// } |
| | | //} |
| | | |
| | | NSUUID *uuid = action.callUUID; |
| | | NSString *callID = [self.calls objectForKey:uuid]; |
| | | if (!callID) { |
| | | return; |
| | | } |
| | | //- (void)provider:(CXProvider *)provider performSetHeldCallAction:(nonnull CXSetHeldCallAction *)action { |
| | | // [action fulfill]; |
| | | // if (linphone_core_is_in_conference(LC) && action.isOnHold) { |
| | | // linphone_core_leave_conference(LC); |
| | | //// LOGD(@"CallKit: Leaving conference"); |
| | | // [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; |
| | | // return; |
| | | // } |
| | | // |
| | | // if (linphone_core_get_calls_nb(LC) > 1 && action.isOnHold) { |
| | | // linphone_core_pause_all_calls(LC); |
| | | //// LOGD(@"CallKit: Pausing all ongoing calls"); |
| | | // return; |
| | | // } |
| | | // |
| | | // NSUUID *uuid = action.callUUID; |
| | | // NSString *callID = [self.calls objectForKey:uuid]; |
| | | // if (!callID) { |
| | | // return; |
| | | // } |
| | | // |
| | | //// LOGD(@"CallKit: Call with call-id: [%@] and UUID: [%@] paused status changed to: []", callID, uuid, action.isOnHold ? @"Paused" : @"Resumed"); |
| | | // LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | // if (!call) |
| | | // return; |
| | | // |
| | | // if (action.isOnHold) { |
| | | // HDLLinphoneManager.instance.speakerBeforePause = HDLLinphoneManager.instance.speakerEnabled; |
| | | // linphone_call_pause((LinphoneCall *)call); |
| | | // } else { |
| | | // if (linphone_core_get_conference(LC)) { |
| | | // linphone_core_enter_conference(LC); |
| | | // [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; |
| | | // } else { |
| | | // [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | // self.pendingCall = call; |
| | | // } |
| | | // } |
| | | //} |
| | | |
| | | // LOGD(@"CallKit: Call with call-id: [%@] and UUID: [%@] paused status changed to: []", callID, uuid, action.isOnHold ? @"Paused" : @"Resumed"); |
| | | LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | if (!call) |
| | | return; |
| | | //- (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action { |
| | | // [action fulfill]; |
| | | // NSUUID *uuid = action.callUUID; |
| | | // NSString *callID = [self.calls objectForKey:uuid]; |
| | | //// LOGD(@"CallKit: playing DTMF for call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | // LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | // char digit = action.digits.UTF8String[0]; |
| | | // linphone_call_send_dtmf((LinphoneCall *)call, digit); |
| | | //} |
| | | |
| | | if (action.isOnHold) { |
| | | HDLLinphoneManager.instance.speakerBeforePause = HDLLinphoneManager.instance.speakerEnabled; |
| | | linphone_call_pause((LinphoneCall *)call); |
| | | } else { |
| | | if (linphone_core_get_conference(LC)) { |
| | | linphone_core_enter_conference(LC); |
| | | [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; |
| | | } else { |
| | | [self configAudioSession:[AVAudioSession sharedInstance]]; |
| | | self.pendingCall = call; |
| | | } |
| | | } |
| | | } |
| | | //- (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession { |
| | | // NSLog(@"CallKit: Audio session activated"); |
| | | // // Now we can (re)start the call |
| | | // if (self.pendingCall) { |
| | | // LinphoneCallState state = linphone_call_get_state(self.pendingCall); |
| | | // switch (state) { |
| | | // case LinphoneCallIncomingReceived: |
| | | // [HDLLinphoneManager.instance acceptCall:(LinphoneCall *)self.pendingCall evenWithVideo:_pendingCallVideo]; |
| | | // break; |
| | | // case LinphoneCallPaused: |
| | | // linphone_call_resume((LinphoneCall *)self.pendingCall); |
| | | // break; |
| | | // case LinphoneCallStreamsRunning: |
| | | // // May happen when multiple calls |
| | | // break; |
| | | // default: |
| | | // break; |
| | | // } |
| | | // } else { |
| | | // if (_pendingAddr) { |
| | | // [HDLLinphoneManager.instance doCall:_pendingAddr]; |
| | | // } else { |
| | | //// LOGE(@"CallKit: No pending call"); |
| | | // } |
| | | // } |
| | | // |
| | | // [self setPendingCall:NULL]; |
| | | // if (_pendingAddr) |
| | | // linphone_address_unref(_pendingAddr); |
| | | // _pendingAddr = NULL; |
| | | // _pendingCallVideo = FALSE; |
| | | //} |
| | | // |
| | | //- (void)provider:(CXProvider *)provider didDeactivateAudioSession:(nonnull AVAudioSession *)audioSession { |
| | | // NSLog(@"CallKit : Audio session deactivated"); |
| | | // [self setPendingCall:NULL]; |
| | | // if (_pendingAddr) |
| | | // linphone_address_unref(_pendingAddr); |
| | | // _pendingAddr = NULL; |
| | | // _pendingCallVideo = FALSE; |
| | | //} |
| | | |
| | | - (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action { |
| | | [action fulfill]; |
| | | NSUUID *uuid = action.callUUID; |
| | | NSString *callID = [self.calls objectForKey:uuid]; |
| | | // LOGD(@"CallKit: playing DTMF for call with call-id: [%@] and UUID: [%@]", callID, uuid); |
| | | LinphoneCall *call = [HDLLinphoneManager.instance callByCallId:callID]; |
| | | char digit = action.digits.UTF8String[0]; |
| | | linphone_call_send_dtmf((LinphoneCall *)call, digit); |
| | | } |
| | | |
| | | - (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession { |
| | | NSLog(@"CallKit: Audio session activated"); |
| | | // Now we can (re)start the call |
| | | if (self.pendingCall) { |
| | | LinphoneCallState state = linphone_call_get_state(self.pendingCall); |
| | | switch (state) { |
| | | case LinphoneCallIncomingReceived: |
| | | [HDLLinphoneManager.instance acceptCall:(LinphoneCall *)self.pendingCall evenWithVideo:_pendingCallVideo]; |
| | | break; |
| | | case LinphoneCallPaused: |
| | | linphone_call_resume((LinphoneCall *)self.pendingCall); |
| | | break; |
| | | case LinphoneCallStreamsRunning: |
| | | // May happen when multiple calls |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } else { |
| | | if (_pendingAddr) { |
| | | [HDLLinphoneManager.instance doCall:_pendingAddr]; |
| | | } else { |
| | | // LOGE(@"CallKit: No pending call"); |
| | | } |
| | | } |
| | | |
| | | [self setPendingCall:NULL]; |
| | | if (_pendingAddr) |
| | | linphone_address_unref(_pendingAddr); |
| | | _pendingAddr = NULL; |
| | | _pendingCallVideo = FALSE; |
| | | } |
| | | |
| | | - (void)provider:(CXProvider *)provider didDeactivateAudioSession:(nonnull AVAudioSession *)audioSession { |
| | | NSLog(@"CallKit : Audio session deactivated"); |
| | | [self setPendingCall:NULL]; |
| | | if (_pendingAddr) |
| | | linphone_address_unref(_pendingAddr); |
| | | _pendingAddr = NULL; |
| | | _pendingCallVideo = FALSE; |
| | | } |
| | | |
| | | - (void)providerDidReset:(CXProvider *)provider { |
| | | // LOGD(@"CallKit: Provider reset"); |
| | | HDLLinphoneManager.instance.conf = TRUE; |
| | | linphone_core_terminate_all_calls(LC); |
| | | [self.calls removeAllObjects]; |
| | | [self.uuids removeAllObjects]; |
| | | } |
| | | |
| | | #pragma mark - CXCallObserverDelegate Protocol |
| | | |
| | | - (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call { |
| | | NSLog(@"CallKit: Call changed"); |
| | | } |
| | | //- (void)providerDidReset:(CXProvider *)provider { |
| | | //// LOGD(@"CallKit: Provider reset"); |
| | | // HDLLinphoneManager.instance.conf = TRUE; |
| | | // linphone_core_terminate_all_calls(LC); |
| | | // [self.calls removeAllObjects]; |
| | | // [self.uuids removeAllObjects]; |
| | | //} |
| | | // |
| | | //#pragma mark - CXCallObserverDelegate Protocol |
| | | // |
| | | //- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call { |
| | | // NSLog(@"CallKit: Call changed"); |
| | | //} |
| | | |
| | | @end |