From 54fb56d93c78e04cc0c5c2e9b6d1f42a08b03d87 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Tue, 22 Nov 2022 11:01:28 +0100 Subject: [PATCH 1/4] Fix crash when entering a chat conversation with audio messages that were not properly downloaded --- Classes/LinphoneUI/UIChatBubblePhotoCell.m | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 29e7554f5..d9073ab74 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -192,14 +192,20 @@ _voiceRecordingFile = nil; LinphoneContent *voiceContent = [UIChatBubbleTextCell voiceContent:self.message]; if (voiceContent) { - _voiceRecordingFile = [NSString stringWithUTF8String:[VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] ? linphone_content_get_plain_file_path(voiceContent) : linphone_content_get_file_path(voiceContent)]; - if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) + const char *fileName = ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] ? linphone_content_get_plain_file_path(voiceContent) : linphone_content_get_file_path(voiceContent)); + if (fileName == nil) { + linphone_content_set_file_path(voiceContent, [[LinphoneManager imagesDirectory] stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]].UTF8String); + linphone_chat_message_download_content(self.message, voiceContent); + } + _voiceRecordingFile = fileName ? [NSString stringWithUTF8String:fileName] : nil; + if (fileName && [VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) { [encrptedFilePaths setValue:_voiceRecordingFile forKey:[NSString stringWithUTF8String:linphone_content_get_name(voiceContent)]]; + } _vrTimerLabel.text = [self formattedDuration:linphone_content_get_file_duration(voiceContent)/1000]; _vrWaveMaskPlayback.frame = CGRectZero; _vrWaveMaskPlayback.backgroundColor = linphone_chat_message_is_outgoing(self.message) ? UIColor.orangeColor : UIColor.grayColor; } - + const bctbx_list_t *contents = linphone_chat_message_get_contents(self.message); size_t contentCount = bctbx_list_size(contents); From 6cb4ea55f650abd7dad1b82df1ecce99bf54b13f Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Mon, 21 Nov 2022 16:52:15 +0100 Subject: [PATCH 2/4] Fix scrollBadge and markAsRead in chat conversation --- Classes/ChatConversationTableView.m | 7 +++++++ Classes/ChatConversationView.m | 1 + 2 files changed, 8 insertions(+) diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m index 376262a19..f7d93687f 100644 --- a/Classes/ChatConversationTableView.m +++ b/Classes/ChatConversationTableView.m @@ -380,6 +380,13 @@ static const int BASIC_EVENT_LIST=15; [_chatRoomDelegate tableViewIsScrolling]; } +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) { + if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) + [ChatConversationView markAsRead:_chatRoom]; + } +} + static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index ea3c860de..b975a721f 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -1451,6 +1451,7 @@ void on_chat_room_chat_message_received(LinphoneChatRoom *cr, const LinphoneEven if (isDisplayingBottomOfTable) { [view.tableController scrollToBottom:TRUE]; } else { + [[view.tableController scrollBadge] setHidden:FALSE]; int unread_msg = linphone_chat_room_get_unread_messages_count(cr); [[view.tableController scrollBadge] setText:[NSString stringWithFormat:@"%d", unread_msg]]; } From fc9c9b950810d1340029b2ffc0afd0dedee6ce77 Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Tue, 22 Nov 2022 12:26:05 +0100 Subject: [PATCH 3/4] Set fullscreen when start or join a conference --- .../CompositeViewControllers/ActiveCallOrConferenceView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift b/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift index 49294477c..c68d6b705 100644 --- a/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift +++ b/Classes/Swift/Voip/Views/CompositeViewControllers/ActiveCallOrConferenceView.swift @@ -341,6 +341,7 @@ import linphonesw ControlsViewModel.shared.callStatsVisible.notifyValue() CallsViewModel.shared.currentCallData.notifyValue() ControlsViewModel.shared.audioRoutesSelected.value = false + ControlsViewModel.shared.fullScreenMode.value = true } override func viewWillDisappear(_ animated: Bool) { From c49013aa2bf0d12c36a01e3a9a58b077a3eebb84 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 22 Nov 2022 12:08:19 +0100 Subject: [PATCH 4/4] Fix an issue where audio does not work when a VoIP Call is resumed after a GSM call has been terminated by the remote party. --- Classes/Swift/CallManager.swift | 9 ++++- Classes/Swift/ProviderDelegate.swift | 53 ++++++++++++++++++---------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/Classes/Swift/CallManager.swift b/Classes/Swift/CallManager.swift index 8d94b317e..c85e86ca5 100644 --- a/Classes/Swift/CallManager.swift +++ b/Classes/Swift/CallManager.swift @@ -49,6 +49,7 @@ import AVFoundation var actionsToPerformOnceWhenCoreIsOn : [(()->Void)] = [] var conference: Conference? var callkitAudioSessionActivated : Bool? = nil // if "nil", ignore. + var actionToFulFill : CXCallAction? = nil; var backgroundContextCall : Call? @objc var backgroundContextCameraIsEnabled : Bool = false @@ -556,7 +557,7 @@ import AVFoundation switch cstate { case .IncomingReceived: let addr = call.remoteAddress - var displayName = incomingDisplayName(call: call) + var displayName = incomingDisplayName(call: call) if (CallManager.callKitEnabled()) { let isConference = isConferenceCall(call: call) @@ -608,7 +609,13 @@ import AVFoundation CallManager.instance().speakerBeforePause = false CallManager.instance().changeRouteToSpeaker() } + actionToFulFill?.fulfill() + actionToFulFill = nil break + case .Paused: + actionToFulFill?.fulfill() + actionToFulFill = nil + break case .OutgoingInit, .OutgoingProgress, .OutgoingRinging, diff --git a/Classes/Swift/ProviderDelegate.swift b/Classes/Swift/ProviderDelegate.swift index 38692b7ee..80eb69a81 100644 --- a/Classes/Swift/ProviderDelegate.swift +++ b/Classes/Swift/ProviderDelegate.swift @@ -205,8 +205,10 @@ extension ProviderDelegate: CXProviderDelegate { let uuid = action.callUUID let callId = callInfos[uuid]?.callId let call = CallManager.instance().callByCallId(callId: callId) - action.fulfill() + if (call == nil) { + Log.directLog(BCTBX_LOG_ERROR, text: "CXSetHeldCallAction: no call !") + action.fail() return } @@ -215,33 +217,46 @@ extension ProviderDelegate: CXProviderDelegate { try CallManager.instance().lc?.leaveConference() Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: call-id: [\(String(describing: callId))] leaving conference") NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) - return - } - - let state = action.isOnHold ? "Paused" : "Resumed" - Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]") - if (action.isOnHold) { - if (call!.params?.localConferenceMode ?? false) { - return - } - CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() - try call!.pause() - } else { - if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) { - try CallManager.instance().lc?.enterConference() - NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) + action.fulfill() + }else{ + let state = action.isOnHold ? "Paused" : "Resumed" + Log.directLog(BCTBX_LOG_DEBUG, text: "CallKit: Call with call-id: [\(String(describing: callId))] and UUID: [\(uuid)] paused status changed to: [\(state)]") + if (action.isOnHold) { + CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() + try call!.pause() + CallManager.instance().actionToFulFill = action; } else { - try call!.resume() + if (CallManager.instance().lc?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) { + try CallManager.instance().lc?.enterConference() + action.fulfill() + NotificationCenter.default.post(name: Notification.Name("LinphoneCallUpdate"), object: self) + } else { + try call!.resume() + CallManager.instance().actionToFulFill = action; + // HORRIBLE HACK HERE - PLEASE APPLE FIX THIS !! + // When resuming a SIP call after a native call has ended remotely, didActivate: audioSession + // is never called. + // It looks like in this case, it is implicit. + // As a result we have to notify the Core that the AudioSession is active. + // The SpeakerBox demo application written by Apple exhibits this behavior. + // https://developer.apple.com/documentation/callkit/making_and_receiving_voip_calls_with_callkit + // We can clearly see there that startAudio() is called immediately in the CXSetHeldCallAction + // handler, while it is called from didActivate: audioSession otherwise. + // Callkit's design is not consistent, or its documentation imcomplete, wich is somewhat disapointing. + // + Log.directLog(BCTBX_LOG_DEBUG, text: "Assuming AudioSession is active when executing a CXSetHeldCallAction with isOnHold=false.") + CallManager.instance().lc?.activateAudioSession(actived: true) + CallManager.instance().callkitAudioSessionActivated = true + } } } } catch { Log.directLog(BCTBX_LOG_ERROR, text: "CallKit: Call set held (paused or resumed) \(uuid) failed because \(error)") + action.fail() } } func provider(_ provider: CXProvider, perform action: CXStartCallAction) { - - do { let uuid = action.callUUID