Merge pull request #2673 from vector-im/riot_2646

VoIP: Fallback to matrix.org STUN server with a confirmation dialog
This commit is contained in:
manuroe
2019-08-28 18:58:20 +02:00
committed by GitHub
10 changed files with 223 additions and 25 deletions
+3 -1
View File
@@ -5,7 +5,9 @@ Improvements:
* Upgrade MatrixKit version ([v0.11.0](https://github.com/matrix-org/matrix-ios-kit/releases/tag/v0.11.0)).
* Privacy: Prompt to accept integration manager policies on use (#2600).
* Privacy: Make clear that device names are publicly readable (#2662).
* Widgets: Whitelist [MSC1961](https://github.com/matrix-org/matrix-doc/pull/1961) widget urls
* Widgets: Whitelist [MSC1961](https://github.com/matrix-org/matrix-doc/pull/1961) widget urls.
* Settings: CALLS section: Always display the CallKit option but grey it out when not available (only on China).
* VoIP: Fallback to matrix.org STUN server with a confirmation dialog (#2646).
Changes in 0.9.2 (2019-08-08)
===============================================
+57
View File
@@ -2605,6 +2605,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Let's call invite be valid for 1 minute
mxSession.callManager.inviteLifetime = 60000;
if (RiotSettings.shared.allowStunServerFallback)
{
mxSession.callManager.fallbackSTUNServer = RiotSettings.shared.stunServerFallback;
}
// Setup CallKit
if ([MXCallKitAdapter callKitAvailable])
{
@@ -3850,6 +3855,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
NSString *btnTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"active_call_details", @"Vector", nil), callViewController.callerNameLabel.text];
[self addCallStatusBar:btnTitle];
}
if ([callViewController isKindOfClass:[CallViewController class]]
&& ((CallViewController*)callViewController).shouldPromptForStunServerFallback)
{
[self promptForStunServerFallback];
}
if (completion)
{
@@ -3883,6 +3894,52 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
}
- (void)promptForStunServerFallback
{
[_errorNotification dismissViewControllerAnimated:NO completion:nil];
NSString *stunFallbackHost = RiotSettings.shared.stunServerFallback;
// Remove "stun:"
stunFallbackHost = [stunFallbackHost componentsSeparatedByString:@":"].lastObject;
MXSession *mainSession = self.mxSessions.firstObject;
NSString *homeServerName = mainSession.matrixRestClient.credentials.homeServerName;
NSString *message = [NSString stringWithFormat:@"%@\n\n%@",
[NSString stringWithFormat:NSLocalizedStringFromTable(@"call_no_stun_server_error_message_1", @"Vector", nil), homeServerName],
[NSString stringWithFormat: NSLocalizedStringFromTable(@"call_no_stun_server_error_message_2", @"Vector", nil), stunFallbackHost]];
_errorNotification = [UIAlertController alertControllerWithTitle:NSLocalizedStringFromTable(@"call_no_stun_server_error_title", @"Vector", nil)
message:message
preferredStyle:UIAlertControllerStyleAlert];
[_errorNotification addAction:[UIAlertAction actionWithTitle:[NSString stringWithFormat: NSLocalizedStringFromTable(@"call_no_stun_server_error_use_fallback_button", @"Vector", nil), stunFallbackHost]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
RiotSettings.shared.allowStunServerFallback = YES;
mainSession.callManager.fallbackSTUNServer = RiotSettings.shared.stunServerFallback;
[AppDelegate theDelegate].errorNotification = nil;
}]];
[_errorNotification addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
RiotSettings.shared.allowStunServerFallback = NO;
[AppDelegate theDelegate].errorNotification = nil;
}]];
// Display the error notification
if (!isErrorNotificationSuspended)
{
[_errorNotification mxk_setAccessibilityIdentifier:@"AppDelegateErrorAlert"];
[self showNotificationAlert:_errorNotification];
}
}
#pragma mark - Jitsi call
- (void)displayJitsiViewControllerWithWidget:(Widget*)jitsiWidget andVideo:(BOOL)video
+2
View File
@@ -59,6 +59,8 @@
<false/>
<key>createConferenceCallsWithJitsi</key>
<true/>
<key>stunServerFallback</key>
<string>stun:turn.matrix.org</string>
<key>enableRageShake</key>
<true/>
<key>maxAllowedMediaCacheSize</key>
+8
View File
@@ -405,6 +405,9 @@
"settings_enable_callkit" = "Integrated calling";
"settings_callkit_info" = "Receive incoming calls on your lock screen. See your Riot calls in the system's call history. If iCloud is enabled, this call history will be shared with Apple.";
"settings_calls_stun_server_fallback_button" = "Allow fallback call assist server";
"settings_calls_stun_server_fallback_description" = "Allow fallback call assist server %@ when your homeserver does not offer one (your IP address would be shared during a call).";
"settings_ui_language" = "Language";
"settings_ui_theme" = "Theme";
"settings_ui_theme_auto" = "Auto";
@@ -631,6 +634,11 @@
"call_already_displayed" = "There is already a call in progress.";
"call_jitsi_error" = "Failed to join the conference call.";
"call_no_stun_server_error_title" ="Call failed due to misconfigured server";
"call_no_stun_server_error_message_1" ="Please ask the administrator of your homeserver %@ to configure a TURN server in order for calls to work reliably.";
"call_no_stun_server_error_message_2" ="Alternatively, you can try to use the public server at %@, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings";
"call_no_stun_server_error_use_fallback_button" = "Try using %@";
// No VoIP support
"no_voip_title" = "Incoming call";
"no_voip" = "%@ is calling you but %@ does not support calls yet.\nYou can ignore this notification and answer the call from another device or you can reject it.";
+1
View File
@@ -39,6 +39,7 @@ internal enum RiotDefaults {
internal static let showRedactionsInRoomHistory: Bool = _document["showRedactionsInRoomHistory"]
internal static let showUnsupportedEventsInRoomHistory: Bool = _document["showUnsupportedEventsInRoomHistory"]
internal static let sortRoomMembersUsingLastSeenTime: Bool = _document["sortRoomMembersUsingLastSeenTime"]
internal static let stunServerFallback: String = _document["stunServerFallback"]
internal static let syncLocalContacts: Bool = _document["syncLocalContacts"]
internal static let webAppUrl: String = _document["webAppUrl"]
internal static let webAppUrlBeta: String = _document["webAppUrlBeta"]
+24
View File
@@ -370,6 +370,22 @@ internal enum VectorL10n {
internal static var callJitsiError: String {
return VectorL10n.tr("Vector", "call_jitsi_error")
}
/// Please ask the administrator of your homeserver %@ to configure a TURN server in order for calls to work reliably.
internal static func callNoStunServerErrorMessage1(_ p1: String) -> String {
return VectorL10n.tr("Vector", "call_no_stun_server_error_message_1", p1)
}
/// Alternatively, you can try to use the public server at %@, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings
internal static func callNoStunServerErrorMessage2(_ p1: String) -> String {
return VectorL10n.tr("Vector", "call_no_stun_server_error_message_2", p1)
}
/// Call failed due to misconfigured server
internal static var callNoStunServerErrorTitle: String {
return VectorL10n.tr("Vector", "call_no_stun_server_error_title")
}
/// Try using %@
internal static func callNoStunServerErrorUseFallbackButton(_ p1: String) -> String {
return VectorL10n.tr("Vector", "call_no_stun_server_error_use_fallback_button", p1)
}
/// Camera
internal static var camera: String {
return VectorL10n.tr("Vector", "camera")
@@ -2394,6 +2410,14 @@ internal enum VectorL10n {
internal static var settingsCallsSettings: String {
return VectorL10n.tr("Vector", "settings_calls_settings")
}
/// Allow fallback call assist server
internal static var settingsCallsStunServerFallbackButton: String {
return VectorL10n.tr("Vector", "settings_calls_stun_server_fallback_button")
}
/// Allow fallback call assist server %@ when your homeserver does not offer one (your IP address would be shared during a call).
internal static func settingsCallsStunServerFallbackDescription(_ p1: String) -> String {
return VectorL10n.tr("Vector", "settings_calls_stun_server_fallback_description", p1)
}
/// Change password
internal static var settingsChangePassword: String {
return VectorL10n.tr("Vector", "settings_change_password")
+22
View File
@@ -30,6 +30,8 @@ final class RiotSettings: NSObject {
static let notificationsShowDecryptedContent = "showDecryptedContent"
static let pinRoomsWithMissedNotifications = "pinRoomsWithMissedNotif"
static let pinRoomsWithUnreadMessages = "pinRoomsWithUnread"
static let allowStunServerFallback = "allowStunServerFallback"
static let stunServerFallback = "stunServerFallback"
}
/// Riot Standard Room Member Power Level
@@ -119,4 +121,24 @@ final class RiotSettings: NSObject {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.createConferenceCallsWithJitsi)
}
}
// MARK: Calls
/// Indicate if `allowStunServerFallback` settings has been set once.
var isAllowStunServerFallbackHasBeenSetOnce: Bool {
return UserDefaults.standard.object(forKey: UserDefaultsKeys.allowStunServerFallback) != nil
}
var allowStunServerFallback: Bool {
get {
return UserDefaults.standard.bool(forKey: UserDefaultsKeys.allowStunServerFallback)
} set {
UserDefaults.standard.set(newValue, forKey: UserDefaultsKeys.allowStunServerFallback)
}
}
var stunServerFallback: String? {
return UserDefaults.standard.string(forKey: UserDefaultsKeys.stunServerFallback)
}
}
+3
View File
@@ -26,4 +26,7 @@
@property (unsafe_unretained, nonatomic) IBOutlet NSLayoutConstraint *callerImageViewWidthConstraint;
// At the end of call, this flag indicates if the prompt to use the fallback should be displayed
@property (nonatomic) BOOL shouldPromptForStunServerFallback;
@end
+48
View File
@@ -39,6 +39,9 @@
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
id kThemeServiceDidChangeThemeNotificationObserver;
// Flag to compute self.shouldPromptForStunServerFallback
BOOL promptForStunServerFallback;
}
@end
@@ -52,6 +55,9 @@
// Setup `MXKViewControllerHandling` properties
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
promptForStunServerFallback = NO;
_shouldPromptForStunServerFallback = NO;
}
- (void)viewDidLoad
@@ -229,6 +235,13 @@
#pragma mark - MXCallDelegate
- (void)call:(MXCall *)call stateDidChange:(MXCallState)state reason:(MXEvent *)event
{
[super call:call stateDidChange:state reason:event];
[self checkStunServerFallbackWithCallState:state];
}
- (void)call:(MXCall *)call didEncounterError:(NSError *)error
{
if ([error.domain isEqualToString:MXEncryptingErrorDomain]
@@ -333,6 +346,41 @@
}
}
#pragma mark - Fallback STUN server
- (void)checkStunServerFallbackWithCallState:(MXCallState)callState
{
// Detect if we should display the prompt to fallback to the STUN server defined
// in the app plist if the homeserver does not provide STUN or TURN servers.
// We should if the call ends while we were in connecting state
if (!self.mainSession.callManager.turnServers
&& !self.mainSession.callManager.fallbackSTUNServer
&& !RiotSettings.shared.isAllowStunServerFallbackHasBeenSetOnce)
{
switch (callState)
{
case MXCallStateConnecting:
promptForStunServerFallback = YES;
break;
case MXCallStateConnected:
promptForStunServerFallback = NO;
break;
case MXCallStateEnded:
if (promptForStunServerFallback)
{
_shouldPromptForStunServerFallback = YES;
}
default:
break;
}
}
}
#pragma mark - Properties
- (UIImage*)picturePlaceholder
+55 -24
View File
@@ -86,7 +86,9 @@ enum
enum
{
CALLS_ENABLE_CALLKIT_INDEX = 0,
CALLS_DESCRIPTION_INDEX,
CALLS_CALLKIT_DESCRIPTION_INDEX,
CALLS_ENABLE_STUN_SERVER_FALLBACK_INDEX,
CALLS_STUN_SERVER_FALLBACK_DESCRIPTION_INDEX,
CALLS_COUNT
};
@@ -1265,9 +1267,11 @@ SingleImagePickerPresenterDelegate>
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if ([MXCallKitAdapter callKitAvailable])
count = CALLS_COUNT;
if (!RiotSettings.shared.stunServerFallback)
{
count = CALLS_COUNT;
count -= 2;
}
}
else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX)
@@ -1827,16 +1831,52 @@ SingleImagePickerPresenterDelegate>
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
labelAndSwitchCell.mxkSwitch.enabled = YES;
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleCallKit:) forControlEvents:UIControlEventTouchUpInside];
if (![MXCallKitAdapter callKitAvailable])
{
labelAndSwitchCell.mxkSwitch.on = NO;
labelAndSwitchCell.mxkSwitch.enabled = NO;
labelAndSwitchCell.mxkLabel.enabled = NO;
}
cell = labelAndSwitchCell;
}
else if (row == CALLS_DESCRIPTION_INDEX)
else if (row == CALLS_CALLKIT_DESCRIPTION_INDEX)
{
MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView];
globalInfoCell.textLabel.text = NSLocalizedStringFromTable(@"settings_callkit_info", @"Vector", nil);
globalInfoCell.textLabel.numberOfLines = 0;
globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone;
if (![MXCallKitAdapter callKitAvailable])
{
globalInfoCell.textLabel.enabled = NO;
}
cell = globalInfoCell;
}
else if (row == CALLS_ENABLE_STUN_SERVER_FALLBACK_INDEX)
{
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_calls_stun_server_fallback_button", @"Vector", nil);
labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.allowStunServerFallback;
labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor;
labelAndSwitchCell.mxkSwitch.enabled = YES;
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleStunServerFallback:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == CALLS_STUN_SERVER_FALLBACK_DESCRIPTION_INDEX)
{
NSString *stunFallbackHost = RiotSettings.shared.stunServerFallback;
// Remove "stun:"
stunFallbackHost = [stunFallbackHost componentsSeparatedByString:@":"].lastObject;
MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView];
globalInfoCell.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"settings_calls_stun_server_fallback_description", @"Vector", nil), stunFallbackHost];
globalInfoCell.textLabel.numberOfLines = 0;
globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone;
cell = globalInfoCell;
}
}
@@ -2337,10 +2377,7 @@ SingleImagePickerPresenterDelegate>
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if ([MXCallKitAdapter callKitAvailable])
{
return NSLocalizedStringFromTable(@"settings_calls_settings", @"Vector", nil);
}
return NSLocalizedStringFromTable(@"settings_calls_settings", @"Vector", nil);
}
else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX)
{
@@ -2486,13 +2523,6 @@ SingleImagePickerPresenterDelegate>
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
else if (section == SETTINGS_SECTION_FLAIR_INDEX)
{
if (groupsDataSource.joinedGroupsSection == -1)
@@ -2518,13 +2548,6 @@ SingleImagePickerPresenterDelegate>
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
else if (section == SETTINGS_SECTION_FLAIR_INDEX)
{
if (groupsDataSource.joinedGroupsSection == -1)
@@ -2953,6 +2976,14 @@ SingleImagePickerPresenterDelegate>
[MXKAppSettings standardAppSettings].enableCallKit = switchButton.isOn;
}
- (void)toggleStunServerFallback:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;
RiotSettings.shared.allowStunServerFallback = switchButton.isOn;
self.mainSession.callManager.fallbackSTUNServer = RiotSettings.shared.allowStunServerFallback ? RiotSettings.shared.stunServerFallback : nil;
}
- (void)toggleShowDecodedContent:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;