зеркало из https://github.com/nextcloud/talk-ios.git
Коммит
1f5514688e
|
@ -184,6 +184,18 @@
|
|||
1F8848122A75B68D00063860 /* IntentsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F90EFC225FE489B00F3FA55 /* IntentsUI.framework */; };
|
||||
1F8995B32970644C00CABA33 /* ColorGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8995B22970644C00CABA33 /* ColorGenerator.swift */; };
|
||||
1F8995B52973547700CABA33 /* WebRTCCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8995B42973547700CABA33 /* WebRTCCommon.swift */; };
|
||||
1F8AAC322C518759004DA20A /* SignalingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC312C518759004DA20A /* SignalingSettings.swift */; };
|
||||
1F8AAC332C518B8A004DA20A /* SignalingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC312C518759004DA20A /* SignalingSettings.swift */; };
|
||||
1F8AAC342C518B8A004DA20A /* SignalingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC312C518759004DA20A /* SignalingSettings.swift */; };
|
||||
1F8AAC352C518B8B004DA20A /* SignalingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC312C518759004DA20A /* SignalingSettings.swift */; };
|
||||
1F8AAC372C519577004DA20A /* TurnServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC362C519577004DA20A /* TurnServer.swift */; };
|
||||
1F8AAC382C519577004DA20A /* TurnServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC362C519577004DA20A /* TurnServer.swift */; };
|
||||
1F8AAC392C519577004DA20A /* TurnServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC362C519577004DA20A /* TurnServer.swift */; };
|
||||
1F8AAC3A2C519577004DA20A /* TurnServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC362C519577004DA20A /* TurnServer.swift */; };
|
||||
1F8AAC3C2C519689004DA20A /* StunServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC3B2C519689004DA20A /* StunServer.swift */; };
|
||||
1F8AAC3D2C519689004DA20A /* StunServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC3B2C519689004DA20A /* StunServer.swift */; };
|
||||
1F8AAC3E2C519689004DA20A /* StunServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC3B2C519689004DA20A /* StunServer.swift */; };
|
||||
1F8AAC3F2C519689004DA20A /* StunServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F8AAC3B2C519689004DA20A /* StunServer.swift */; };
|
||||
1F90DA0429E9A28E00E81E3D /* AvatarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F90DA0329E9A28E00E81E3D /* AvatarManager.swift */; };
|
||||
1F90EFBC25FE39F800F3FA55 /* NCIntentController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F90EFBB25FE39F800F3FA55 /* NCIntentController.m */; };
|
||||
1F90EFBD25FE39F800F3FA55 /* NCIntentController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F90EFBB25FE39F800F3FA55 /* NCIntentController.m */; };
|
||||
|
@ -707,6 +719,9 @@
|
|||
1F785DDC2707865F00AC4B40 /* VoiceMessageTranscribeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VoiceMessageTranscribeViewController.h; sourceTree = "<group>"; };
|
||||
1F8995B22970644C00CABA33 /* ColorGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorGenerator.swift; sourceTree = "<group>"; };
|
||||
1F8995B42973547700CABA33 /* WebRTCCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTCCommon.swift; sourceTree = "<group>"; };
|
||||
1F8AAC312C518759004DA20A /* SignalingSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalingSettings.swift; sourceTree = "<group>"; };
|
||||
1F8AAC362C519577004DA20A /* TurnServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServer.swift; sourceTree = "<group>"; };
|
||||
1F8AAC3B2C519689004DA20A /* StunServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StunServer.swift; sourceTree = "<group>"; };
|
||||
1F90DA0329E9A28E00E81E3D /* AvatarManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarManager.swift; sourceTree = "<group>"; };
|
||||
1F90EFBA25FE39F800F3FA55 /* NCIntentController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCIntentController.h; sourceTree = "<group>"; };
|
||||
1F90EFBB25FE39F800F3FA55 /* NCIntentController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NCIntentController.m; sourceTree = "<group>"; };
|
||||
|
@ -1859,6 +1874,9 @@
|
|||
2CD5F3232142781A006B71BF /* NCExternalSignalingController.m */,
|
||||
2C69323B2923ECAA00017AD2 /* WSMessage.h */,
|
||||
2C69323C2923ECAA00017AD2 /* WSMessage.m */,
|
||||
1F8AAC312C518759004DA20A /* SignalingSettings.swift */,
|
||||
1F8AAC362C519577004DA20A /* TurnServer.swift */,
|
||||
1F8AAC3B2C519689004DA20A /* StunServer.swift */,
|
||||
1F8995B42973547700CABA33 /* WebRTCCommon.swift */,
|
||||
);
|
||||
name = WebRTC;
|
||||
|
@ -2685,6 +2703,7 @@
|
|||
1F77A5F82AB9A4CD007B6037 /* NCDeckCardParameter.m in Sources */,
|
||||
1F77A5FD2AB9A4F3007B6037 /* ServerCapabilities.m in Sources */,
|
||||
1FF4DA892C0262BB00C1B952 /* NCBaseSessionManager.swift in Sources */,
|
||||
1F8AAC352C518B8B004DA20A /* SignalingSettings.swift in Sources */,
|
||||
1F77A6062AB9A581007B6037 /* NCKeyChainController.m in Sources */,
|
||||
1F0B0A732BA265300073FF8D /* MentionSuggestion.swift in Sources */,
|
||||
1F77A5FB2AB9A4E6007B6037 /* NCMessageParameter.m in Sources */,
|
||||
|
@ -2701,6 +2720,7 @@
|
|||
1F77A60D2AB9A5CC007B6037 /* NCPoll.m in Sources */,
|
||||
1F77A6032AB9A56D007B6037 /* NotificationCenterNotifications.m in Sources */,
|
||||
1F77A60A2AB9A5AE007B6037 /* NCUser.m in Sources */,
|
||||
1F8AAC3F2C519689004DA20A /* StunServer.swift in Sources */,
|
||||
1FF4DA992C0327FF00C1B952 /* NCWebImageDownloaderOperation.swift in Sources */,
|
||||
1F1B504A2B90CF0800B0F2F4 /* TalkCapabilities.m in Sources */,
|
||||
2C6955122B0CE1A10070F6E1 /* NCUtils.swift in Sources */,
|
||||
|
@ -2709,6 +2729,7 @@
|
|||
1F77A5F52AB9A4B9007B6037 /* NCAPIController.m in Sources */,
|
||||
1F77A5F92AB9A4D9007B6037 /* NCMessageFileParameter.m in Sources */,
|
||||
1FF2FD852AB99F51000C9905 /* NCUserStatus.m in Sources */,
|
||||
1F8AAC3A2C519577004DA20A /* TurnServer.swift in Sources */,
|
||||
1FB78E202B6ADBB600B0D69D /* NCAPIControllerExtensions.swift in Sources */,
|
||||
1FF136122BFB4F8C006A6101 /* NCRoom.swift in Sources */,
|
||||
1FF2FD7F2AB99E4D000C9905 /* Atomic.swift in Sources */,
|
||||
|
@ -2774,6 +2795,7 @@
|
|||
1F1B0F452BE047CE003FD766 /* ModalPresentationController.swift in Sources */,
|
||||
2CBF82AE1FC888FC00636459 /* NCPushNotification.m in Sources */,
|
||||
2CC7159420C54D080045C789 /* ChatTableViewCell.m in Sources */,
|
||||
1F8AAC322C518759004DA20A /* SignalingSettings.swift in Sources */,
|
||||
1F1B0F272BDA61C5003FD766 /* AllocationTracker.swift in Sources */,
|
||||
2CA1CCAA1F02D1A4002FE6A2 /* NCAPIController.m in Sources */,
|
||||
1F1B0F302BDBC9D6003FD766 /* NCMediaViewerPageViewController.swift in Sources */,
|
||||
|
@ -2797,6 +2819,7 @@
|
|||
2C9B0B9C217F756B00A4752C /* NCNotification.m in Sources */,
|
||||
2C2D7A172B8C9C0000642373 /* RoomCreationTableViewController.swift in Sources */,
|
||||
1F8995B52973547700CABA33 /* WebRTCCommon.swift in Sources */,
|
||||
1F8AAC3C2C519689004DA20A /* StunServer.swift in Sources */,
|
||||
2C2145682BF6B8E900470C0C /* NewRoomTableViewController.swift in Sources */,
|
||||
1F1B503E2B8FB12100B0F2F4 /* BaseChatTableViewCell+Message.swift in Sources */,
|
||||
DA66583127B6B24E00B46B11 /* UserProfileTableViewController+Utils.swift in Sources */,
|
||||
|
@ -2825,6 +2848,7 @@
|
|||
1FAB2E852ACB482B001214EB /* ChatViewController.swift in Sources */,
|
||||
1F5813F828EB23EF00318FC3 /* NCSplitViewController.swift in Sources */,
|
||||
2C5BFBFE2891C3DF00E75118 /* PollResultsDetailsViewController.swift in Sources */,
|
||||
1F8AAC372C519577004DA20A /* TurnServer.swift in Sources */,
|
||||
2CA1CCA41F025F64002FE6A2 /* RoomsTableViewController.m in Sources */,
|
||||
2CB3041A2264775E0053078A /* SLKTextInput+Implementation.m in Sources */,
|
||||
2C90E5D31EE80C870093D85A /* AuthenticationViewController.m in Sources */,
|
||||
|
@ -2976,6 +3000,7 @@
|
|||
1FF136172BFB74CF006A6101 /* NCChatMessage.swift in Sources */,
|
||||
1FF4DA8A2C0262BB00C1B952 /* NCBaseSessionManager.swift in Sources */,
|
||||
2C62B00C24C1BDC1007E460A /* NCNotification.m in Sources */,
|
||||
1F8AAC3E2C519689004DA20A /* StunServer.swift in Sources */,
|
||||
1F1C0D7F29A7F33600D17C6D /* NCNotificationAction.swift in Sources */,
|
||||
1F35F8E62AEEBC0300044BDA /* SLKTextInput+Implementation.m in Sources */,
|
||||
1FF4DA982C0327FF00C1B952 /* NCWebImageDownloaderOperation.swift in Sources */,
|
||||
|
@ -3004,6 +3029,7 @@
|
|||
1FDFC94F2BA50B9100670DF4 /* UIFontExtension.swift in Sources */,
|
||||
1F35F8EA2AEEBC0E00044BDA /* SLKTextViewController.m in Sources */,
|
||||
2C6955132B0CE1A20070F6E1 /* NCUtils.swift in Sources */,
|
||||
1F8AAC342C518B8A004DA20A /* SignalingSettings.swift in Sources */,
|
||||
2C62AFFF24C1BDAA007E460A /* NCUser.m in Sources */,
|
||||
1FAB2EF22AD1EAA3001214EB /* RLMSupport.swift in Sources */,
|
||||
1FB78E212B6ADBB700B0D69D /* NCAPIControllerExtensions.swift in Sources */,
|
||||
|
@ -3033,6 +3059,7 @@
|
|||
1F35F8FC2AEEDBC600044BDA /* ChatViewControllerExtension.swift in Sources */,
|
||||
1FEDE3D0257D43AB00853F79 /* NCMessageFileParameter.m in Sources */,
|
||||
2C62AFB924C1A4E6007E460A /* ShareViewController.m in Sources */,
|
||||
1F8AAC392C519577004DA20A /* TurnServer.swift in Sources */,
|
||||
1F35F8F32AEEC29A00044BDA /* AvatarButton.swift in Sources */,
|
||||
2C4446DF2658158000DF1DBC /* NCChatBlock.m in Sources */,
|
||||
1FF4DAAC2C0A114900C1B952 /* OcsResponse.swift in Sources */,
|
||||
|
@ -3071,14 +3098,17 @@
|
|||
1F45A1352A026EFA005FE87D /* NCWebImageDownloaderOperation.m in Sources */,
|
||||
2CC0017324A3795B00A20167 /* NCImageSessionManager.m in Sources */,
|
||||
1FB7B9922BF0CDF90093CE98 /* BannedActor.swift in Sources */,
|
||||
1F8AAC382C519577004DA20A /* TurnServer.swift in Sources */,
|
||||
2CC001C124A37AC500A20167 /* NCNotification.m in Sources */,
|
||||
2C4446FD265D5DFA00DF1DBC /* ABContact.m in Sources */,
|
||||
1F8AAC3D2C519689004DA20A /* StunServer.swift in Sources */,
|
||||
2C4446F8265D5A0700DF1DBC /* NotificationCenterNotifications.m in Sources */,
|
||||
2C6955142B0CE1A20070F6E1 /* NCUtils.swift in Sources */,
|
||||
1FF4DA942C02678000C1B952 /* NCImageSessionManager.swift in Sources */,
|
||||
1F0B0A752BA265310073FF8D /* MentionSuggestion.swift in Sources */,
|
||||
1FC940B92A5F21FC00FFFADE /* SwiftMarkdownObjCBridge.swift in Sources */,
|
||||
1FF4DA882C0262BA00C1B952 /* NCBaseSessionManager.swift in Sources */,
|
||||
1F8AAC332C518B8A004DA20A /* SignalingSettings.swift in Sources */,
|
||||
2CB6ACDB2641483800D3D641 /* NCMessageLocationParameter.m in Sources */,
|
||||
2C4446FB265D5C5700DF1DBC /* NCRoomParticipants.m in Sources */,
|
||||
2CC1FF492818395E009F7288 /* NCDeckCardParameter.m in Sources */,
|
||||
|
|
|
@ -153,6 +153,13 @@ class BaseChatTableViewCell: UITableViewCell, ReactionsViewDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
var titleLabel = actorDisplayName.withTextColor(.secondaryLabel)
|
||||
|
||||
if message.actorType == "federated_users", let remoteServer = message.actorId.split(separator: "@").last {
|
||||
let remoteServerString = " (\(String(remoteServer)))"
|
||||
titleLabel.append(remoteServerString.withTextColor(.tertiaryLabel))
|
||||
}
|
||||
|
||||
if let lastEditActorDisplayName = message.lastEditActorDisplayName, message.lastEditTimestamp > 0 {
|
||||
var editedString = ""
|
||||
|
||||
|
@ -161,18 +168,16 @@ class BaseChatTableViewCell: UITableViewCell, ReactionsViewDelegate {
|
|||
editedString = " (\(editedString))"
|
||||
} else {
|
||||
editedString = NSLocalizedString("edited by", comment: "A message was edited by ...")
|
||||
editedString = " (\(editedString) \(lastEditActorDisplayName)"
|
||||
editedString = " (\(editedString) \(lastEditActorDisplayName))"
|
||||
}
|
||||
|
||||
let editedAttributedString = editedString.withTextColor(.tertiaryLabel)
|
||||
let actorDisplayName = actorDisplayName.withTextColor(.secondaryLabel)
|
||||
|
||||
actorDisplayName.append(editedAttributedString)
|
||||
self.titleLabel.attributedText = actorDisplayName
|
||||
} else {
|
||||
self.titleLabel.text = actorDisplayName
|
||||
titleLabel.append(editedAttributedString)
|
||||
}
|
||||
|
||||
self.titleLabel.attributedText = titleLabel
|
||||
|
||||
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
|
||||
|
||||
guard let room = NCDatabaseManager.sharedInstance().room(withToken: message.token, forAccountId: activeAccount.accountId)
|
||||
|
|
|
@ -155,10 +155,7 @@ import UIKit
|
|||
public override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
if NCDatabaseManager.sharedInstance().roomTalkCapabilities(for: self.room)?.callEnabled ?? false &&
|
||||
room.type != .changelog && room.type != .noteToSelf,
|
||||
!room.isFederated {
|
||||
|
||||
if room.supportsCalling {
|
||||
self.navigationItem.rightBarButtonItems = [videoCallButton, voiceCallButton]
|
||||
}
|
||||
|
||||
|
@ -1187,8 +1184,10 @@ import UIKit
|
|||
|
||||
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
|
||||
let userId = notification.userInfo?["userId"] as? String
|
||||
let isFederated = notification.userInfo?["isFederated"] as? Bool ?? false
|
||||
|
||||
if userId == activeAccount.userId || serverCapabilities.typingPrivacy {
|
||||
// Since our own userId can exist on other servers, only suppress the notification if it's not federated
|
||||
if (userId == activeAccount.userId && !isFederated) || serverCapabilities.typingPrivacy {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@ typedef void (^PollCompletionBlock)(NCPoll *poll, NSError *error, NSInteger stat
|
|||
|
||||
typedef void (^SendSignalingMessagesCompletionBlock)(NSError *error);
|
||||
typedef void (^PullSignalingMessagesCompletionBlock)(NSDictionary *messages, NSError *error);
|
||||
typedef void (^GetSignalingSettingsCompletionBlock)(NSDictionary *settings, NSError *error);
|
||||
|
||||
typedef void (^SetReadStatusPrivacySettingCompletionBlock)(NSError *error);
|
||||
typedef void (^SetTypingPrivacySettingCompletionBlock)(NSError *error);
|
||||
|
@ -226,7 +225,6 @@ extern NSInteger const kReceivedChatMessagesLimit;
|
|||
// Signaling Controller
|
||||
- (NSURLSessionDataTask *)sendSignalingMessages:(NSString *)messages toRoom:(NSString *)token forAccount:(TalkAccount *)account withCompletionBlock:(SendSignalingMessagesCompletionBlock)block;
|
||||
- (NSURLSessionDataTask *)pullSignalingMessagesFromRoom:(NSString *)token forAccount:(TalkAccount *)account withCompletionBlock:(PullSignalingMessagesCompletionBlock)block;
|
||||
- (NSURLSessionDataTask *)getSignalingSettingsForAccount:(TalkAccount *)account withCompletionBlock:(GetSignalingSettingsCompletionBlock)block;
|
||||
- (NSString *)authenticationBackendUrlForAccount:(TalkAccount *)account;
|
||||
|
||||
// Settings Controller
|
||||
|
|
|
@ -1810,29 +1810,6 @@ NSInteger const kReceivedChatMessagesLimit = 100;
|
|||
return task;
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)getSignalingSettingsForAccount:(TalkAccount *)account withCompletionBlock:(GetSignalingSettingsCompletionBlock)block
|
||||
{
|
||||
NSString *endpoint = @"signaling/settings";
|
||||
NSInteger signalingAPIVersion = [self signalingAPIVersionForAccount:account];
|
||||
NSString *URLString = [self getRequestURLForEndpoint:endpoint withAPIVersion:signalingAPIVersion forAccount:account];
|
||||
|
||||
NCAPISessionManager *apiSessionManager = [_apiSessionManagers objectForKey:account.accountId];
|
||||
NSURLSessionDataTask *task = [apiSessionManager GET:URLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
NSDictionary *responseDict = responseObject;
|
||||
if (block) {
|
||||
block(responseDict, nil);
|
||||
}
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
NSInteger statusCode = [self getResponseStatusCode:task.response];
|
||||
[self checkResponseStatusCode:statusCode forAccount:account];
|
||||
if (block) {
|
||||
block(nil, error);
|
||||
}
|
||||
}];
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
- (NSString *)authenticationBackendUrlForAccount:(TalkAccount *)account
|
||||
{
|
||||
NSString *endpoint = @"signaling/backend";
|
||||
|
|
|
@ -213,6 +213,32 @@ import Foundation
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Signaling
|
||||
|
||||
@discardableResult
|
||||
public func getSignalingSettings(for account: TalkAccount, forRoom roomToken: String?, completionBlock: @escaping (_ signalingSettings: SignalingSettings?, _ error: (any Error)?) -> Void) -> URLSessionDataTask? {
|
||||
guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
|
||||
else {
|
||||
completionBlock(nil, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
let apiVersion = self.signalingAPIVersion(for: account)
|
||||
let urlString = self.getRequestURL(forEndpoint: "signaling/settings", withAPIVersion: apiVersion, for: account)
|
||||
|
||||
var parameters: [String: Any]?
|
||||
|
||||
if let roomToken, let encodedToken = roomToken.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
|
||||
parameters = [
|
||||
"token": encodedToken
|
||||
]
|
||||
}
|
||||
|
||||
return apiSessionManager.getOcs(urlString, account: account, parameters: parameters) { ocs, error in
|
||||
completionBlock(SignalingSettings(dictionary: ocs?.dataDict), error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mentions
|
||||
|
||||
public func getMentionSuggestions(for accountId: String, in roomToken: String, with searchString: String, completionBlock: @escaping (_ mentions: [MentionSuggestion]?) -> Void) {
|
||||
|
|
|
@ -139,19 +139,22 @@ static NSString * const kNCScreenTrackKind = @"screen";
|
|||
|
||||
- (void)startCall
|
||||
{
|
||||
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
// Make sure the signaling controller has retrieved the settings before joining a call
|
||||
[_signalingController updateSignalingSettingsWithCompletionBlock:^(SignalingSettings *signalingSettings) {
|
||||
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
|
||||
if (!_isAudioOnly && authStatus == AVAuthorizationStatusNotDetermined) {
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
[self createLocalMedia];
|
||||
[self joinCall];
|
||||
}];
|
||||
if (!self->_isAudioOnly && authStatus == AVAuthorizationStatusNotDetermined) {
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
[self createLocalMedia];
|
||||
[self joinCall];
|
||||
}];
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[self createLocalMedia];
|
||||
[self joinCall];
|
||||
[self createLocalMedia];
|
||||
[self joinCall];
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSString *)signalingSessionId
|
||||
|
|
|
@ -69,6 +69,7 @@ extern NSString * const kCapabilityMediaCaption;
|
|||
extern NSString * const kCapabilityEditMessages;
|
||||
extern NSString * const kCapabilityDeleteMessagesUnlimited;
|
||||
extern NSString * const kCapabilityFederationV1;
|
||||
extern NSString * const kCapabilityFederationV2;
|
||||
extern NSString * const kCapabilityChatReadLast;
|
||||
extern NSString * const kCapabilityBanV1;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ NSString * const kCapabilityMediaCaption = @"media-caption";
|
|||
NSString * const kCapabilityEditMessages = @"edit-messages";
|
||||
NSString * const kCapabilityDeleteMessagesUnlimited = @"delete-messages-unlimited";
|
||||
NSString * const kCapabilityFederationV1 = @"federation-v1";
|
||||
NSString * const kCapabilityFederationV2 = @"federation-v2";
|
||||
NSString * const kCapabilityChatReadLast = @"chat-read-last";
|
||||
NSString * const kCapabilityBanV1 = @"ban-v1";
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef void (^JoinRoomExternalSignalingCompletionBlock)(NSError *error);
|
|||
- (instancetype)initWithAccount:(TalkAccount *)account server:(NSString *)serverUrl andTicket:(NSString *)ticket;
|
||||
- (BOOL)hasMCU;
|
||||
- (NSString *)sessionId;
|
||||
- (void)joinRoom:(NSString *)roomId withSessionId:(NSString *)sessionId withCompletionBlock:(JoinRoomExternalSignalingCompletionBlock)block;
|
||||
- (void)joinRoom:(NSString *)roomId withSessionId:(NSString *)sessionId withFederation:(NSDictionary * _Nullable)federationDict withCompletionBlock:(JoinRoomExternalSignalingCompletionBlock)block;
|
||||
- (void)leaveRoom:(NSString *)roomId;
|
||||
- (void)sendCallMessage:(NCSignalingMessage *)message;
|
||||
- (void)sendSendOfferMessageWithSessionId:(NSString *)sessionId andRoomType:(NSString *)roomType;
|
||||
|
|
|
@ -381,7 +381,7 @@ NSString * const NCExternalSignalingControllerDidReceiveStoppedTypingNotificatio
|
|||
[self executeCompletionBlockForMessageId:messageId withStatus:SendMessageApplicationError];
|
||||
}
|
||||
|
||||
- (void)joinRoom:(NSString *)roomId withSessionId:(NSString *)sessionId withCompletionBlock:(JoinRoomExternalSignalingCompletionBlock)block
|
||||
- (void)joinRoom:(NSString *)roomId withSessionId:(NSString *)sessionId withFederation:(NSDictionary *)federationDict withCompletionBlock:(JoinRoomExternalSignalingCompletionBlock)block
|
||||
{
|
||||
|
||||
if (_disconnected) {
|
||||
|
@ -400,6 +400,17 @@ NSString * const NCExternalSignalingControllerDidReceiveStoppedTypingNotificatio
|
|||
}
|
||||
};
|
||||
|
||||
if (federationDict) {
|
||||
messageDict = @{
|
||||
@"type": @"room",
|
||||
@"room": @{
|
||||
@"roomid": roomId,
|
||||
@"sessionid": sessionId,
|
||||
@"federation": federationDict
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[self sendMessage:messageDict withCompletionBlock:^(NSURLSessionWebSocketTask *task, NCExternalSignalingSendMessageStatus status) {
|
||||
if (status == SendMessageSocketError && task == self->_webSocket) {
|
||||
// Reconnect if this is still the same socket we tried to send the message on
|
||||
|
@ -425,7 +436,7 @@ NSString * const NCExternalSignalingControllerDidReceiveStoppedTypingNotificatio
|
|||
{
|
||||
if ([_currentRoom isEqualToString:roomId]) {
|
||||
_currentRoom = nil;
|
||||
[self joinRoom:@"" withSessionId:@"" withCompletionBlock:nil];
|
||||
[self joinRoom:@"" withSessionId:@"" withFederation:nil withCompletionBlock:nil];
|
||||
} else {
|
||||
NSLog(@"External signaling: Not leaving because it's not room we joined");
|
||||
}
|
||||
|
@ -665,8 +676,10 @@ NSString * const NCExternalSignalingControllerDidReceiveStoppedTypingNotificatio
|
|||
NSString *messageType = [[messageDict objectForKey:@"data"] objectForKey:@"type"];
|
||||
if ([messageType isEqualToString:@"startedTyping"] || [messageType isEqualToString:@"stoppedTyping"]) {
|
||||
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
|
||||
NSString *fromSession = [[messageDict objectForKey:@"sender"] objectForKey:@"sessionid"];
|
||||
NSString *fromUser = [[messageDict objectForKey:@"sender"] objectForKey:@"userid"];
|
||||
|
||||
NSDictionary *sender = [messageDict objectForKey:@"sender"];
|
||||
NSString *fromSession = [sender objectForKey:@"sessionid"];
|
||||
NSString *fromUser = [sender objectForKey:@"userid"];
|
||||
|
||||
if (_currentRoom && fromSession){
|
||||
[userInfo setObject:_currentRoom forKey:@"roomToken"];
|
||||
|
@ -676,6 +689,12 @@ NSString * const NCExternalSignalingControllerDidReceiveStoppedTypingNotificatio
|
|||
[userInfo setObject:fromUser forKey:@"userId"];
|
||||
}
|
||||
|
||||
NSDictionary *participant = [_participantsMap objectForKey:fromSession];
|
||||
if (participant) {
|
||||
BOOL isFederated = [[participant objectForKey:@"federated"] boolValue];
|
||||
[userInfo setObject:@(isFederated) forKey:@"isFederated"];
|
||||
}
|
||||
|
||||
NSString *displayName = [self getDisplayNameFromSessionId:fromSession];
|
||||
|
||||
if (displayName) {
|
||||
|
|
|
@ -58,6 +58,16 @@ import Realm
|
|||
return false
|
||||
}
|
||||
|
||||
public var supportsCalling: Bool {
|
||||
// Federated calling is only supported with federation-v2
|
||||
if self.isFederated, !NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityFederationV2, for: self) {
|
||||
return false
|
||||
}
|
||||
|
||||
return NCDatabaseManager.sharedInstance().roomTalkCapabilities(for: self)?.callEnabled ?? false &&
|
||||
self.type != .changelog && self.type != .noteToSelf
|
||||
}
|
||||
|
||||
public var isBreakoutRoom: Bool {
|
||||
return self.objectType == NCRoomObjectTypeRoom
|
||||
}
|
||||
|
|
|
@ -162,32 +162,49 @@ import Foundation
|
|||
// Remember the latest sessionId we're using to join a room, to be able to check when joining the external signaling server
|
||||
self.joiningSessionId = sessionId
|
||||
|
||||
extSignalingController.joinRoom(token, withSessionId: sessionId) { error in
|
||||
// If the sessionId is not the same anymore we tried to join with, we either already left again before
|
||||
// joining the external signaling server succeeded, or we already have another join in process
|
||||
if !self.isJoiningRoom(withToken: token) {
|
||||
NCUtils.log("Not joining the room any more. Ignore external signaling completion block, but we joined the Nextcloud instance before.")
|
||||
completionBlock(nil, nil, nil, NCRoomsManager.statusCodeShouldIgnoreAttemptButJoinedSuccessfully, nil)
|
||||
return
|
||||
}
|
||||
self.getSignalingSettingsHelper(for: activeAccount, forRoom: token) { signalingSettings in
|
||||
let federation = signalingSettings?.getFederationJoinDictionary()
|
||||
|
||||
if !self.isJoiningRoom(withSessionId: sessionId ?? "") {
|
||||
NCUtils.log("Joining the same room with a different sessionId. Ignore external signaling completion block.")
|
||||
completionBlock(nil, nil, nil, NCRoomsManager.statusCodeIgnoreJoinAttempt, nil)
|
||||
return
|
||||
}
|
||||
extSignalingController.joinRoom(token, withSessionId: sessionId, withFederation: federation) { error in
|
||||
// If the sessionId is not the same anymore we tried to join with, we either already left again before
|
||||
// joining the external signaling server succeeded, or we already have another join in process
|
||||
if !self.isJoiningRoom(withToken: token) {
|
||||
NCUtils.log("Not joining the room any more. Ignore external signaling completion block, but we joined the Nextcloud instance before.")
|
||||
completionBlock(nil, nil, nil, NCRoomsManager.statusCodeShouldIgnoreAttemptButJoinedSuccessfully, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if error == nil {
|
||||
NCUtils.log("Joined room \(token) in external signaling server successfully.")
|
||||
completionBlock(sessionId, room, nil, 0, nil)
|
||||
} else {
|
||||
NCUtils.log("Failed joining room \(token) in external signaling server.")
|
||||
completionBlock(nil, nil, error, statusCode, statusReason)
|
||||
if !self.isJoiningRoom(withSessionId: sessionId ?? "") {
|
||||
NCUtils.log("Joining the same room with a different sessionId. Ignore external signaling completion block.")
|
||||
completionBlock(nil, nil, nil, NCRoomsManager.statusCodeIgnoreJoinAttempt, nil)
|
||||
return
|
||||
}
|
||||
|
||||
if error == nil {
|
||||
NCUtils.log("Joined room \(token) in external signaling server successfully.")
|
||||
completionBlock(sessionId, room, nil, 0, nil)
|
||||
} else {
|
||||
NCUtils.log("Failed joining room \(token) in external signaling server.")
|
||||
completionBlock(nil, nil, error, statusCode, statusReason)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func getSignalingSettingsHelper(for account: TalkAccount, forRoom token: String, withCompletion completion: @escaping (SignalingSettings?) -> Void) {
|
||||
// Currently we only need the signaling settings in case the room is federated and we support federation-v2
|
||||
if let room = NCDatabaseManager.sharedInstance().room(withToken: token, forAccountId: account.accountId), room.isFederated,
|
||||
NCDatabaseManager.sharedInstance().serverHasTalkCapability(kCapabilityFederationV2, forAccountId: account.accountId) {
|
||||
|
||||
NCAPIController.sharedInstance().getSignalingSettings(for: account, forRoom: token) { signalingSettings, _ in
|
||||
completion(signalingSettings)
|
||||
}
|
||||
} else {
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func rejoinRoom(_ token: String) {
|
||||
guard let roomController = self.activeRooms[token] as? NCRoomController else { return }
|
||||
|
||||
|
@ -200,7 +217,11 @@ import Foundation
|
|||
roomController.inChat = true
|
||||
|
||||
if let extSignalingController = NCSettingsController.sharedInstance().externalSignalingController(forAccountId: activeAccount.accountId) {
|
||||
extSignalingController.joinRoom(token, withSessionId: sessionId, withCompletionBlock: nil)
|
||||
self.getSignalingSettingsHelper(for: activeAccount, forRoom: token) { signalingSettings in
|
||||
let federation = signalingSettings?.getFederationJoinDictionary()
|
||||
|
||||
extSignalingController.joinRoom(token, withSessionId: sessionId, withFederation: federation, withCompletionBlock: nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("Could not re-join room. Status code: \(statusCode). Error: \(error?.localizedDescription ?? "Unknown")")
|
||||
|
|
|
@ -474,12 +474,10 @@ NSString * const kDidReceiveCallsFromOldAccount = @"receivedCallsFromOldAccount"
|
|||
return;
|
||||
}
|
||||
|
||||
[[NCAPIController sharedInstance] getSignalingSettingsForAccount:account withCompletionBlock:^(NSDictionary *settings, NSError *error) {
|
||||
[[NCAPIController sharedInstance] getSignalingSettingsFor:account forRoom:nil completionBlock:^(SignalingSettings * _Nullable settings, NSError * _Nullable error) {
|
||||
if (!error) {
|
||||
NSDictionary *signalingConfiguration = [[settings objectForKey:@"ocs"] objectForKey:@"data"];
|
||||
|
||||
if (signalingConfiguration && account && account.accountId) {
|
||||
[self->_signalingConfigurations setObject:signalingConfiguration forKey:account.accountId];
|
||||
if (settings && account && account.accountId) {
|
||||
[self->_signalingConfigurations setObject:settings forKey:account.accountId];
|
||||
|
||||
if (block) {
|
||||
block(nil);
|
||||
|
@ -501,16 +499,9 @@ NSString * const kDidReceiveCallsFromOldAccount = @"receivedCallsFromOldAccount"
|
|||
// SetSignalingConfiguration should be called just once
|
||||
- (void)setSignalingConfigurationForAccountId:(NSString *)accountId
|
||||
{
|
||||
NSDictionary *signalingConfiguration = [_signalingConfigurations objectForKey:accountId];
|
||||
NSString *externalSignalingTicket = [signalingConfiguration objectForKey:@"ticket"];
|
||||
NSString *externalSignalingServer = nil;
|
||||
|
||||
id server = [signalingConfiguration objectForKey:@"server"];
|
||||
if ([server isKindOfClass:[NSString class]] && ![server isEqualToString:@""]) {
|
||||
externalSignalingServer = server;
|
||||
}
|
||||
SignalingSettings *signalingSettings = [_signalingConfigurations objectForKey:accountId];
|
||||
|
||||
if (externalSignalingServer && externalSignalingTicket) {
|
||||
if (signalingSettings.server && signalingSettings.server.length > 0 && signalingSettings.ticket && signalingSettings.ticket.length > 0) {
|
||||
BGTaskHelper *bgTask = [BGTaskHelper startBackgroundTaskWithName:@"NCSetSignalingConfiguration" expirationHandler:nil];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
@ -521,7 +512,7 @@ NSString * const kDidReceiveCallsFromOldAccount = @"receivedCallsFromOldAccount"
|
|||
}
|
||||
|
||||
TalkAccount *account = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:accountId];
|
||||
extSignalingController = [[NCExternalSignalingController alloc] initWithAccount:account server:externalSignalingServer andTicket:externalSignalingTicket];
|
||||
extSignalingController = [[NCExternalSignalingController alloc] initWithAccount:account server:signalingSettings.server andTicket:signalingSettings.ticket];
|
||||
[self->_externalSignalingControllers setObject:extSignalingController forKey:accountId];
|
||||
|
||||
[bgTask stopBackgroundTask];
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import "NCSignalingMessage.h"
|
||||
|
||||
@class NCSignalingController;
|
||||
@class SignalingSettings;
|
||||
|
||||
@protocol NCSignalingControllerObserver <NSObject>
|
||||
|
||||
|
@ -16,6 +17,8 @@
|
|||
|
||||
@end
|
||||
|
||||
typedef void (^SignalingSettingsUpdatedCompletionBlock)(SignalingSettings *signalingSettings);
|
||||
|
||||
@interface NCSignalingController : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<NCSignalingControllerObserver> observer;
|
||||
|
@ -25,5 +28,6 @@
|
|||
- (void)startPullingSignalingMessages;
|
||||
- (void)sendSignalingMessage:(NCSignalingMessage *)message;
|
||||
- (void)stopAllRequests;
|
||||
- (void)updateSignalingSettingsWithCompletionBlock:(SignalingSettingsUpdatedCompletionBlock)block;
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#import "NCAPIController.h"
|
||||
#import "NCDatabaseManager.h"
|
||||
|
||||
#import "NextcloudTalk-Swift.h"
|
||||
|
||||
@interface NCSignalingController()
|
||||
{
|
||||
NCRoom *_room;
|
||||
BOOL _shouldStopPullingMessages;
|
||||
NSDictionary *_signalingSettings;
|
||||
SignalingSettings *_signalingSettings;
|
||||
NSURLSessionTask *_getSignalingSettingsTask;
|
||||
NSURLSessionTask *_pullSignalingMessagesTask;
|
||||
}
|
||||
|
@ -28,7 +30,6 @@
|
|||
self = [super init];
|
||||
if (self) {
|
||||
_room = room;
|
||||
[self getSignalingSettings];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -38,16 +39,26 @@
|
|||
NSLog(@"NCSignalingController dealloc");
|
||||
}
|
||||
|
||||
- (void)getSignalingSettings
|
||||
- (void)updateSignalingSettingsWithCompletionBlock:(SignalingSettingsUpdatedCompletionBlock)block
|
||||
{
|
||||
_getSignalingSettingsTask = [[NCAPIController sharedInstance] getSignalingSettingsForAccount:[[NCDatabaseManager sharedInstance] activeAccount] withCompletionBlock:^(NSDictionary *settings, NSError *error) {
|
||||
TalkAccount *activeAccount = [[NCDatabaseManager sharedInstance] activeAccount];
|
||||
|
||||
_getSignalingSettingsTask = [[NCAPIController sharedInstance] getSignalingSettingsFor:activeAccount forRoom:_room.token completionBlock:^(SignalingSettings * _Nullable settings, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
//TODO: Error handling
|
||||
NSLog(@"Error getting signaling settings.");
|
||||
if (error.code == NSURLErrorCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Error handling
|
||||
[NCUtils log:[NSString stringWithFormat:@"Could not get signaling settings. Error: %@", error.description]];
|
||||
}
|
||||
|
||||
|
||||
if (settings) {
|
||||
self->_signalingSettings = [[settings objectForKey:@"ocs"] objectForKey:@"data"];
|
||||
self->_signalingSettings = settings;
|
||||
}
|
||||
|
||||
if (block) {
|
||||
block(self->_signalingSettings);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
@ -55,36 +66,20 @@
|
|||
- (NSArray *)getIceServers
|
||||
{
|
||||
NSMutableArray *servers = [[NSMutableArray alloc] init];
|
||||
NSInteger signalingAPIVersion = [[NCAPIController sharedInstance] signalingAPIVersionForAccount:[[NCDatabaseManager sharedInstance] activeAccount]];
|
||||
|
||||
|
||||
if (_signalingSettings) {
|
||||
NSArray *stunServers = [_signalingSettings objectForKey:@"stunservers"];
|
||||
for (NSDictionary *stunServer in stunServers) {
|
||||
NSArray *stunURLs = nil;
|
||||
if (signalingAPIVersion >= APIv3) {
|
||||
stunURLs = [stunServer objectForKey:@"urls"];
|
||||
} else {
|
||||
NSString *stunURL = [stunServer objectForKey:@"url"];
|
||||
stunURLs = @[stunURL];
|
||||
}
|
||||
RTCIceServer *iceServer = [[RTCIceServer alloc] initWithURLStrings:stunURLs
|
||||
username:@""
|
||||
credential:@""];
|
||||
for (StunServer *stunServer in _signalingSettings.stunServers) {
|
||||
RTCIceServer *iceServer = [[RTCIceServer alloc] initWithURLStrings:stunServer.urls
|
||||
username:@""
|
||||
credential:@""];
|
||||
[servers addObject:iceServer];
|
||||
}
|
||||
NSArray *turnServers = [_signalingSettings objectForKey:@"turnservers"];
|
||||
for (NSDictionary *turnServer in turnServers) {
|
||||
NSArray *turnURLs = nil;
|
||||
if (signalingAPIVersion >= APIv3) {
|
||||
turnURLs = [turnServer objectForKey:@"urls"];
|
||||
} else {
|
||||
turnURLs = [turnServer objectForKey:@"url"];
|
||||
}
|
||||
NSString *turnUserName = [turnServer objectForKey:@"username"];
|
||||
NSString *turnCredential = [turnServer objectForKey:@"credential"];
|
||||
RTCIceServer *iceServer = [[RTCIceServer alloc] initWithURLStrings:turnURLs
|
||||
username:turnUserName
|
||||
credential:turnCredential];
|
||||
|
||||
for (TurnServer *turnServer in _signalingSettings.turnServers) {
|
||||
RTCIceServer *iceServer = [[RTCIceServer alloc] initWithURLStrings:turnServer.urls
|
||||
username:turnServer.username
|
||||
credential:turnServer.credential];
|
||||
|
||||
[servers addObject:iceServer];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class SignalingSettings: NSObject {
|
||||
|
||||
public var server: String?
|
||||
public var signalingMode: String?
|
||||
public var ticket: String?
|
||||
public var userId: String?
|
||||
public var stunServers: [StunServer] = []
|
||||
public var turnServers: [TurnServer] = []
|
||||
public var federation: [String: Any]?
|
||||
|
||||
init?(dictionary: [String: Any]?) {
|
||||
guard let dictionary else { return nil }
|
||||
|
||||
super.init()
|
||||
|
||||
self.server = dictionary["server"] as? String
|
||||
self.signalingMode = dictionary["signalingMode"] as? String
|
||||
self.ticket = dictionary["ticket"] as? String
|
||||
self.userId = dictionary["userId"] as? String
|
||||
self.federation = dictionary["federation"] as? [String: Any]
|
||||
|
||||
if let stunArray = dictionary["stunservers"] as? [[String: Any]] {
|
||||
for case let stunDict in stunArray {
|
||||
stunServers.append(StunServer(dictionary: stunDict))
|
||||
}
|
||||
}
|
||||
|
||||
if let turnArray = dictionary["turnservers"] as? [[String: Any]] {
|
||||
for case let turnDict in turnArray {
|
||||
turnServers.append(TurnServer(dictionary: turnDict))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func getFederationJoinDictionary() -> [String: String]? {
|
||||
guard let federation, !federation.isEmpty else { return nil }
|
||||
|
||||
var result: [String: String] = [:]
|
||||
|
||||
if let server = federation["server"] as? String {
|
||||
result["signaling"] = server
|
||||
}
|
||||
|
||||
if let roomid = federation["roomId"] as? String {
|
||||
result["roomid"] = roomid
|
||||
}
|
||||
|
||||
if let url = federation["nextcloudServer"] as? String {
|
||||
// TODO: Add index.php here to be safe?
|
||||
result["url"] = url + "/ocs/v2.php/apps/spreed/api/v3/signaling/backend"
|
||||
}
|
||||
|
||||
if let helloAuthParams = federation["helloAuthParams"] as? [String: String], let token = helloAuthParams["token"] {
|
||||
result["token"] = token
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class StunServer: NSObject {
|
||||
|
||||
public var urls: [String]?
|
||||
|
||||
init(dictionary: [String: Any]) {
|
||||
super.init()
|
||||
|
||||
if let stunUrl = dictionary["url"] as? String {
|
||||
urls = [stunUrl]
|
||||
} else if let stunUrls = dictionary["urls"] as? [String] {
|
||||
urls = stunUrls
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class TurnServer: NSObject {
|
||||
|
||||
public var urls: [String]?
|
||||
public var username: String?
|
||||
public var credential: String?
|
||||
|
||||
init(dictionary: [String: Any]) {
|
||||
super.init()
|
||||
|
||||
if let turnUrl = dictionary["url"] as? String {
|
||||
urls = [turnUrl]
|
||||
} else if let turnUrls = dictionary["urls"] as? [String] {
|
||||
urls = turnUrls
|
||||
}
|
||||
|
||||
if let turnUsername = dictionary["username"] as? String {
|
||||
username = turnUsername
|
||||
}
|
||||
|
||||
if let turnCredential = dictionary["credential"] as? String {
|
||||
credential = turnCredential
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче