diff --git a/Ring/Ring.xcodeproj/project.pbxproj b/Ring/Ring.xcodeproj/project.pbxproj index 8be49975ea23562f3518884681b91420e08e4727..21bbb6b4c92de72b914a1fa505123c0ba9476db2 100644 --- a/Ring/Ring.xcodeproj/project.pbxproj +++ b/Ring/Ring.xcodeproj/project.pbxproj @@ -247,6 +247,8 @@ 263B7158246D9390007044C4 /* SmartListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263B7157246D9390007044C4 /* SmartListCell.swift */; }; 263B715A246D9556007044C4 /* IncognitoSmartListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263B7159246D9556007044C4 /* IncognitoSmartListCell.swift */; }; 263B715C246D96E5007044C4 /* IncognitoSmartListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 263B715B246D96E5007044C4 /* IncognitoSmartListCell.xib */; }; + 2659F65827483656009107F1 /* VideoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2659F65727483656009107F1 /* VideoManager.swift */; }; + 2659F65C27483A27009107F1 /* DecodingAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2659F65B27483A27009107F1 /* DecodingAdapterDelegate.swift */; }; 2662FC79246B1E1700FA7782 /* JamiSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2662FC78246B1E1700FA7782 /* JamiSearchView.swift */; }; 2662FC7B246B216B00FA7782 /* JamiSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2662FC7A246B216B00FA7782 /* JamiSearchViewModel.swift */; }; 2662FC7D246B78E800FA7782 /* IncognitoSmartListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2662FC7C246B78E800FA7782 /* IncognitoSmartListViewController.swift */; }; @@ -661,6 +663,8 @@ 263B7157246D9390007044C4 /* SmartListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmartListCell.swift; sourceTree = "<group>"; }; 263B7159246D9556007044C4 /* IncognitoSmartListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoSmartListCell.swift; sourceTree = "<group>"; }; 263B715B246D96E5007044C4 /* IncognitoSmartListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IncognitoSmartListCell.xib; sourceTree = "<group>"; }; + 2659F65727483656009107F1 /* VideoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoManager.swift; sourceTree = "<group>"; }; + 2659F65B27483A27009107F1 /* DecodingAdapterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingAdapterDelegate.swift; sourceTree = "<group>"; }; 2662FC78246B1E1700FA7782 /* JamiSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JamiSearchView.swift; sourceTree = "<group>"; }; 2662FC7A246B216B00FA7782 /* JamiSearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JamiSearchViewModel.swift; sourceTree = "<group>"; }; 2662FC7C246B78E800FA7782 /* IncognitoSmartListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = IncognitoSmartListViewController.swift; path = Ring/Features/Conversations/SmartList/IncognitoSmartListViewController.swift; sourceTree = SOURCE_ROOT; }; @@ -1015,6 +1019,8 @@ 645BDD8024B74BCB009129B1 /* LocationSharingService.swift */, 26D08AB8269628F400E37574 /* RequestsService.swift */, 26D08ABA2696293100E37574 /* RequestsAdapterDelegate.swift */, + 2659F65727483656009107F1 /* VideoManager.swift */, + 2659F65B27483A27009107F1 /* DecodingAdapterDelegate.swift */, ); path = Services; sourceTree = "<group>"; @@ -2217,6 +2223,7 @@ 5CE66F761FBF769B00EE9291 /* InitialLoadingViewController.swift in Sources */, 66ACB430214AE28C00A94162 /* ScanViewController.swift in Sources */, 0E6D959A2407115800996A28 /* LinkToAccountManagerViewController.swift in Sources */, + 2659F65C27483A27009107F1 /* DecodingAdapterDelegate.swift in Sources */, 56BBC99F1ED714CB00CDAF8B /* ConversationsAdapter.mm in Sources */, 0E438A9A204F47E700402900 /* SettingsTableView.swift in Sources */, 0E49096A1FEAB156005CAA50 /* CallsAdapter.mm in Sources */, @@ -2286,6 +2293,7 @@ 1A20417C1F1E56FF00C08435 /* WelcomeViewModel.swift in Sources */, 1A5DC03D1F35678D0075E8EF /* RequestItem.swift in Sources */, 0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */, + 2659F65827483656009107F1 /* VideoManager.swift in Sources */, 64F8127A24BBC19C00A7DE6A /* MessageCellLocationSharing.swift in Sources */, 0E6D959C2407116E00996A28 /* LinkToAccountManagerViewModel.swift in Sources */, 62AD584C2056DB2700AF0701 /* MessageCellDataTransferSent.swift in Sources */, diff --git a/Ring/Ring/Account/VCardUtils.swift b/Ring/Ring/Account/VCardUtils.swift index 236984ae91b9b7319dc3500763d95e72db55a3d6..4c5854b11fe80862adf27561f229f02c443878f9 100644 --- a/Ring/Ring/Account/VCardUtils.swift +++ b/Ring/Ring/Account/VCardUtils.swift @@ -102,7 +102,7 @@ class VCardUtils { return name } - class func sendVCard(card: CNContact, callID: String, accountID: String, sender: CallsService) { + class func sendVCard(card: CNContact, callID: String, accountID: String, sender: CallsService, from: String) { do { let vCard = card guard let vCardData = try CNContactVCardSerialization.dataWithImageAndUUID(from: vCard, andImageCompression: 40000, encoding: .utf8), @@ -131,7 +131,7 @@ class VCardUtils { chunk[key] = vCardString } i += 1 - sender.sendChunk(callID: callID, message: chunk, accountId: accountID) + sender.sendChunk(callID: callID, message: chunk, accountId: accountID, from: from) } } catch { print(error) diff --git a/Ring/Ring/AppDelegate.swift b/Ring/Ring/AppDelegate.swift index aae55bd32d778a1db966dcee233469e72052e4de..71dab3251b00a6e4f44d88058483428fc3de37ea 100644 --- a/Ring/Ring/AppDelegate.swift +++ b/Ring/Ring/AppDelegate.swift @@ -45,6 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD private let callsProvider: CallsProviderDelegate = CallsProviderDelegate() private var conversationManager: ConversationsManager? private var interactionsManager: GeneratedInteractionsManager? + private var videoManager: VideoManager? private lazy var callService: CallsService = { CallsService(withCallsAdapter: CallsAdapter(), dbManager: self.dBManager) }() @@ -152,8 +153,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD dataTransferService: self.dataTransferService, callService: self.callService, locationSharingService: self.locationSharingService, contactsService: self.contactsService, - callsProvider: self.callsProvider, - videoService: self.videoService, requestsService: self.requestsService) + callsProvider: self.callsProvider, requestsService: self.requestsService) + self.videoManager = VideoManager(with: self.callService, callsProvider: self.callsProvider, videoService: self.videoService) self.window?.rootViewController = self.appCoordinator.rootViewController self.window?.makeKeyAndVisible() diff --git a/Ring/Ring/Bridging/CallsAdapter.h b/Ring/Ring/Bridging/CallsAdapter.h index 8f47337ad575403034d1135f9cc0e3b3893dd5ed..e433cd223df4a9cb3d3b0848e9608a02d6d212f5 100644 --- a/Ring/Ring/Bridging/CallsAdapter.h +++ b/Ring/Ring/Bridging/CallsAdapter.h @@ -27,32 +27,32 @@ @property (class, nonatomic, weak) id <CallsAdapterDelegate> delegate; -- (BOOL)acceptCallWithId:(NSString*)callId withMedia:(NSArray*)mediaList; -- (BOOL)refuseCallWithId:(NSString*)callId; -- (BOOL)hangUpCallWithId:(NSString*)callId; -- (BOOL)holdCallWithId:(NSString*)callId; -- (BOOL)unholdCallWithId:(NSString*)callId; - -- (BOOL)requestMediaChange:(NSString*)callId withMedia: (NSArray*)mediaList; -- (void)answerMediaChangeResquest:(NSString*)callId withMedia: (NSArray*)mediaList; - -- (NSString*)placeCallWithAccountId:(NSString*)accountId toRingId:(NSString*)ringId withMedia: (NSArray*)mediaList; -- (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId; -- (NSArray<NSString*>*)calls; -- (void) sendTextMessageWithCallID:(NSString*)callId message:(NSDictionary*)message accountId:(NSString*)accountId sMixed:(bool)isMixed; -- (BOOL) muteMedia:(NSString*)callId mediaType:(NSString*)media muted:(bool)muted; -- (void) playDTMF:(NSString*)code; - -- (BOOL)joinConference:(NSString*)confID call:(NSString*)callID; -- (BOOL)joinConferences:(NSString*)firstConf secondConference:(NSString*)secondConf; -- (BOOL)joinCall:(NSString*)firstCall second:(NSString*)secondCall; -- (NSDictionary<NSString*,NSString*>*)getConferenceDetails:(NSString*)conferenceId; -- (NSArray<NSString*>*)getConferenceCalls:(NSString*)conferenceId; -- (BOOL)hangUpConference:(NSString*)conferenceId; -- (void)setActiveParticipant:(NSString*)callId forConference:(NSString*)conferenceId; -- (void)setConferenceLayout:(int)layout forConference:(NSString*)conferenceId; -- (NSArray*)getConferenceInfo:(NSString*)conferenceId; -- (void)setConferenceModerator:(NSString*)participantId forConference:(NSString*)conferenceId active:(BOOL)isActive; -- (void)muteConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId active:(BOOL)isActive; -- (void)hangupConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId; +- (BOOL)acceptCallWithId:(NSString*)callId accountId:(NSString*)accountId withMedia:(NSArray*)mediaList; +- (BOOL)refuseCallWithId:(NSString*)callId accountId:(NSString*)accountId; +- (BOOL)hangUpCallWithId:(NSString*)callId accountId:(NSString*)accountId; +- (BOOL)holdCallWithId:(NSString*)callId accountId:(NSString*)accountId; +- (BOOL)unholdCallWithId:(NSString*)callId accountId:(NSString*)accountId; +- (void)playDTMF:(NSString*)code; + +- (BOOL)requestMediaChange:(NSString*)callId accountId:(NSString*)accountId withMedia:(NSArray*)mediaList; +- (void)answerMediaChangeResquest:(NSString*)callId accountId:(NSString*)accountId withMedia: (NSArray*)mediaList; + +- (NSString*)placeCallWithAccountId:(NSString*)accountId toParticipantId:(NSString*)participantId withMedia: (NSArray*)mediaList; +- (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId accountId:(NSString*)accountId; +- (NSArray<NSString*>*)callsForAccountId:(NSString*)accountId; +- (void)sendTextMessageWithCallID:(NSString*)callId accountId:(NSString*)accountId message:(NSDictionary*)message from:(NSString*)jamiId isMixed:(bool)isMixed; +- (BOOL)muteMedia:(NSString*)callId accountId:(NSString*)accountId mediaType:(NSString*)media muted:(bool)muted; + +- (BOOL)joinConference:(NSString*)confID call:(NSString*)callID accountId:(NSString*)accountId account2Id:(NSString*)account2Id; +- (BOOL)joinConferences:(NSString*)firstConf secondConference:(NSString*)secondConf accountId:(NSString*)accountId account2Id:(NSString*)account2Id; +- (BOOL)joinCall:(NSString*)firstCall second:(NSString*)secondCall accountId:(NSString*)accountId account2Id:(NSString*)account2Id; +- (NSArray*)getConferenceInfo:(NSString*)conferenceId accountId:(NSString*)accountId; +- (NSDictionary<NSString*,NSString*>*)getConferenceDetails:(NSString*)conferenceId accountId:(NSString*)accountId; +- (NSArray<NSString*>*)getConferenceCalls:(NSString*)conferenceId accountId:(NSString*)accountId; +- (BOOL)hangUpConference:(NSString*)conferenceId accountId:(NSString*)accountId; +- (void)setActiveParticipant:(NSString*)callId forConference:(NSString*)conferenceId accountId:(NSString*)accountId; +- (void)setConferenceLayout:(int)layout forConference:(NSString*)conferenceId accountId:(NSString*)accountId; +- (void)setConferenceModerator:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId active:(BOOL)isActive; +- (void)muteConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId active:(BOOL)isActive; +- (void)hangupConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId; @end diff --git a/Ring/Ring/Bridging/CallsAdapter.mm b/Ring/Ring/Bridging/CallsAdapter.mm index a1135db8d86ca35bd64b9d960f491da5307e05ed..949a7a2c593aa2343f954d9eb889bb2a7feb72c7 100644 --- a/Ring/Ring/Bridging/CallsAdapter.mm +++ b/Ring/Ring/Bridging/CallsAdapter.mm @@ -48,7 +48,7 @@ static id <CallsAdapterDelegate> _delegate; std::map<std::string, std::shared_ptr<CallbackWrapperBase>> callHandlers; //State changed signal - callHandlers.insert(exportable_callback<CallSignal::StateChange>([&](const std::string& callId, + callHandlers.insert(exportable_callback<CallSignal::StateChange>([&](const std::string& accountId, const std::string& callId, const std::string& state, int errorCode) { if (CallsAdapter.delegate) { @@ -56,12 +56,14 @@ static id <CallsAdapterDelegate> _delegate; NSString* stateString = [NSString stringWithUTF8String:state.c_str()]; [CallsAdapter.delegate didChangeCallStateWithCallId:callIdString state:stateString + accountId:[NSString stringWithUTF8String:accountId.c_str()] stateCode:errorCode]; } })); //Incoming message signal - callHandlers.insert(exportable_callback<CallSignal::IncomingMessage>([&](const std::string& callId, + callHandlers.insert(exportable_callback<CallSignal::IncomingMessage>([&](const std::string& accountId, + const std::string& callId, const std::string& fromURI, const std::map<std::string, std::string>& message) { @@ -75,7 +77,7 @@ static id <CallsAdapterDelegate> _delegate; message:messageDict]; } })); - + callHandlers.insert(exportable_callback<CallSignal::IncomingCallWithMedia>([&](const std::string& accountId, const std::string& callId, const std::string& fromURI, @@ -141,22 +143,22 @@ static id <CallsAdapterDelegate> _delegate; } })); - callHandlers.insert(exportable_callback<CallSignal::ConferenceCreated>([&](const std::string& confId) { + callHandlers.insert(exportable_callback<CallSignal::ConferenceCreated>([&](const std::string& accountId, const std::string& confId) { if (CallsAdapter.delegate) { NSString* confIdString = [NSString stringWithUTF8String:confId.c_str()]; - [CallsAdapter.delegate conferenceCreatedWithConference: confIdString]; + [CallsAdapter.delegate conferenceCreatedWithConference: confIdString accountId:[NSString stringWithUTF8String:accountId.c_str()] ]; } })); - callHandlers.insert(exportable_callback<CallSignal::ConferenceChanged>([&](const std::string& confId, const std::string& state) { + callHandlers.insert(exportable_callback<CallSignal::ConferenceChanged>([&](const std::string& accountId, const std::string& confId, const std::string& state) { if (CallsAdapter.delegate) { NSString* confIdString = [NSString stringWithUTF8String:confId.c_str()]; NSString* stateString = [NSString stringWithUTF8String:state.c_str()]; - [CallsAdapter.delegate conferenceChangedWithConference: confIdString state: stateString]; + [CallsAdapter.delegate conferenceChangedWithConference: confIdString accountId: [NSString stringWithUTF8String:accountId.c_str()] state: stateString]; } })); - callHandlers.insert(exportable_callback<CallSignal::ConferenceRemoved>([&](const std::string& confId) { + callHandlers.insert(exportable_callback<CallSignal::ConferenceRemoved>([&](const std::string& accountId, const std::string& confId) { if (CallsAdapter.delegate) { NSString* confIdString = [NSString stringWithUTF8String:confId.c_str()]; [CallsAdapter.delegate conferenceRemovedWithConference: confIdString]; @@ -175,115 +177,116 @@ static id <CallsAdapterDelegate> _delegate; #pragma mark - -- (BOOL)acceptCallWithId:(NSString*)callId withMedia:(NSArray*)mediaList { - return acceptWithMedia(std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); +- (BOOL)acceptCallWithId:(NSString*)callId accountId:(NSString*)accountId withMedia:(NSArray*)mediaList { + return acceptWithMedia(std::string([accountId UTF8String]), std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); } -- (BOOL)refuseCallWithId:(NSString*)callId { - return refuse(std::string([callId UTF8String])); +- (BOOL)refuseCallWithId:(NSString*)callId accountId:(NSString*)accountId { + return refuse(std::string([accountId UTF8String]), std::string([callId UTF8String])); } -- (BOOL)hangUpCallWithId:(NSString*)callId { - return hangUp(std::string([callId UTF8String])); +- (BOOL)hangUpCallWithId:(NSString*)callId accountId:(NSString*)accountId { + return hangUp(std::string([accountId UTF8String]), std::string([callId UTF8String])); } -- (BOOL)holdCallWithId:(NSString*)callId { - return hold(std::string([callId UTF8String])); +- (BOOL)holdCallWithId:(NSString*)callId accountId:(NSString*)accountId { + return hold(std::string([accountId UTF8String]), std::string([callId UTF8String])); } -- (BOOL)unholdCallWithId:(NSString*)callId { - return unhold(std::string([callId UTF8String])); +- (BOOL)unholdCallWithId:(NSString*)callId accountId:(NSString*)accountId { + return unhold(std::string([accountId UTF8String]), std::string([callId UTF8String])); } -- (void) playDTMF:(NSString*)code { +- (void)playDTMF:(NSString*)code { playDTMF(std::string([code UTF8String])); } -- (BOOL)requestMediaChange:(NSString*)callId withMedia: (NSArray*)mediaList { - requestMediaChange(std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); +- (BOOL)requestMediaChange:(NSString*)callId accountId:(NSString*)accountId withMedia:(NSArray*)mediaList { + requestMediaChange(std::string([accountId UTF8String]), std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); return false; } -- (void)answerMediaChangeResquest:(NSString*)callId withMedia: (NSArray*)mediaList { - answerMediaChangeRequest(std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); +- (void)answerMediaChangeResquest:(NSString*)callId accountId:(NSString*)accountId withMedia: (NSArray*)mediaList { + answerMediaChangeRequest(std::string([accountId UTF8String]), std::string([callId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap: mediaList]); } -- (NSString*)placeCallWithAccountId:(NSString*)accountId toRingId:(NSString*)ringId withMedia:(NSArray*)mediaList { +- (NSString*)placeCallWithAccountId:(NSString*)accountId toParticipantId:(NSString*)participantId withMedia:(NSArray*)mediaList { std::string callId; - callId = placeCallWithMedia(std::string([accountId UTF8String]), std::string([ringId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap:mediaList]); + callId = placeCallWithMedia(std::string([accountId UTF8String]), std::string([participantId UTF8String]), [Utils arrayOfDictionnarisToVectorOfMap:mediaList]); return [NSString stringWithUTF8String:callId.c_str()]; } -- (void)sendTextMessageWithCallID:(NSString*)callId message:(NSDictionary*)message accountId:(NSString*)accountId sMixed:(bool)isMixed { - sendTextMessage(std::string([callId UTF8String]), [Utils dictionnaryToMap:message], std::string([accountId UTF8String]), isMixed); -} - -- (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId { - std::map<std::string, std::string> callDetails = getCallDetails(std::string([callId UTF8String])); +- (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId accountId:(NSString*)accountId { + std::map<std::string, std::string> callDetails = getCallDetails(std::string([accountId UTF8String]), std::string([callId UTF8String])); return [Utils mapToDictionnary:callDetails]; } -- (NSArray<NSString*>*)calls { - std::vector<std::string> calls = getCallList(); +- (NSArray<NSString*>*)callsForAccountId:(NSString*)accountId { + std::vector<std::string> calls = getCallList(std::string([accountId UTF8String])); return [Utils vectorToArray:calls]; } -- (BOOL)muteMedia:(NSString*)callId mediaType:(NSString*)media muted:(bool)muted { - return muteLocalMedia(std::string([callId UTF8String]), std::string([media UTF8String]), muted); +- (void)sendTextMessageWithCallID:(NSString*)callId accountId:(NSString*)accountId message:(NSDictionary*)message from:(NSString*)jamiId isMixed:(bool)isMixed { + sendTextMessage(std::string([accountId UTF8String]), std::string([callId UTF8String]), [Utils dictionnaryToMap:message], std::string([jamiId UTF8String]), isMixed); } -- (BOOL)joinConference:(NSString*)confID call:(NSString*)callID { - return addParticipant(std::string([callID UTF8String]), std::string([confID UTF8String])); +- (BOOL)muteMedia:(NSString*)callId accountId:(NSString*)accountId mediaType:(NSString*)media muted:(bool)muted { + return muteLocalMedia(std::string([accountId UTF8String]), std::string([callId UTF8String]), std::string([media UTF8String]), muted); } -- (BOOL)joinCall:(NSString*)firstCall second:(NSString*)secondCall { - return joinParticipant(std::string([firstCall UTF8String]), std::string([secondCall UTF8String])); +- (BOOL)joinConference:(NSString*)confID call:(NSString*)callID accountId:(NSString*)accountId account2Id:(NSString*)account2Id { + return addParticipant(std::string([accountId UTF8String]), std::string([callID UTF8String]), std::string([account2Id UTF8String]), std::string([confID UTF8String])); } -- (BOOL)joinConferences:(NSString*)firstConf secondConference:(NSString*)secondConf { - return joinConference(std::string([firstConf UTF8String]), std::string([secondConf UTF8String])); +- (BOOL)joinConferences:(NSString*)firstConf secondConference:(NSString*)secondConf accountId:(NSString*)accountId account2Id:(NSString*)account2Id { + return joinConference(std::string([accountId UTF8String]), std::string([firstConf UTF8String]), std::string([account2Id UTF8String]), std::string([secondConf UTF8String])); } -- (BOOL)hangUpConference:(NSString*)conferenceId { - return hangUpConference(std::string([conferenceId UTF8String])); +- (BOOL)joinCall:(NSString*)firstCall second:(NSString*)secondCall accountId:(NSString*)accountId account2Id:(NSString*)account2Id { + return joinParticipant(std::string([accountId UTF8String]), std::string([firstCall UTF8String]), std::string([account2Id UTF8String]), std::string([secondCall UTF8String])); } -- (void)setActiveParticipant:(NSString*)callId forConference:(NSString*)conferenceId { - setActiveParticipant(std::string([conferenceId UTF8String]), std::string([callId UTF8String])); +- (NSArray*)getConferenceInfo:(NSString*)conferenceId accountId:(NSString*)accountId { + auto result = getConferenceInfos(std::string([accountId UTF8String]), std::string([conferenceId UTF8String])); + NSArray* arrayResult = [Utils vectorOfMapsToArray:result]; + return arrayResult; } -- (void)setConferenceLayout:(int)layout forConference:(NSString*)conferenceId { - setConferenceLayout(std::string([conferenceId UTF8String]), layout); +- (NSDictionary<NSString*,NSString*>*)getConferenceDetails:(NSString*)conferenceId accountId:(NSString*)accountId { + std::map<std::string, std::string> confDetails = getConferenceDetails(std::string([accountId UTF8String]), std::string([conferenceId UTF8String])); + return [Utils mapToDictionnary:confDetails]; } -- (void)setConferenceModerator:(NSString*)participantId forConference:(NSString*)conferenceId active:(BOOL)isActive { - setModerator(std::string([conferenceId UTF8String]), std::string([participantId UTF8String]), isActive); +- (NSArray<NSString*>*)getConferenceCalls:(NSString*)conferenceId accountId:(NSString*)accountId { + std::vector<std::string> calls = getParticipantList(std::string([accountId UTF8String]), std::string([conferenceId UTF8String])); + return [Utils vectorToArray:calls]; } -- (void)muteConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId active:(BOOL)isActive { - muteParticipant(std::string([conferenceId UTF8String]), std::string([participantId UTF8String]), isActive); +- (BOOL)hangUpConference:(NSString*)conferenceId accountId:(NSString*)accountId { + return hangUpConference(std::string([accountId UTF8String]), std::string([conferenceId UTF8String])); } -- (void)hangupConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId { - hangupParticipant(std::string([conferenceId UTF8String]), std::string([participantId UTF8String])); +- (void)setActiveParticipant:(NSString*)callId forConference:(NSString*)conferenceId accountId:(NSString*)accountId { + setActiveParticipant(std::string([accountId UTF8String]), std::string([conferenceId UTF8String]), std::string([callId UTF8String])); } -- (NSArray*)getConferenceInfo:(NSString*)conferenceId { - auto result = getConferenceInfos(std::string([conferenceId UTF8String])); - NSArray* arrayResult = [Utils vectorOfMapsToArray:result]; - return arrayResult; +- (void)setConferenceLayout:(int)layout forConference:(NSString*)conferenceId accountId:(NSString*)accountId { + setConferenceLayout(std::string([accountId UTF8String]), std::string([conferenceId UTF8String]), layout); } -- (NSDictionary<NSString*,NSString*>*)getConferenceDetails:(NSString*)conferenceId { - std::map<std::string, std::string> confDetails = getConferenceDetails(std::string([conferenceId UTF8String])); - return [Utils mapToDictionnary:confDetails]; +- (void)setConferenceModerator:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId active:(BOOL)isActive { + setModerator(std::string([accountId UTF8String]), std::string([conferenceId UTF8String]), std::string([participantId UTF8String]), isActive); } -- (NSArray<NSString*>*)getConferenceCalls:(NSString*)conferenceId { - std::vector<std::string> calls = getParticipantList(std::string([conferenceId UTF8String])); - return [Utils vectorToArray:calls]; +- (void)muteConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId active:(BOOL)isActive { + muteParticipant(std::string([accountId UTF8String]), std::string([conferenceId UTF8String]), std::string([participantId UTF8String]), isActive); } +- (void)hangupConferenceParticipant:(NSString*)participantId forConference:(NSString*)conferenceId accountId:(NSString*)accountId { + hangupParticipant(std::string([accountId UTF8String]), std::string([conferenceId UTF8String]), std::string([participantId UTF8String])); +} + + #pragma mark AccountAdapterDelegate + (id <CallsAdapterDelegate>)delegate { diff --git a/Ring/Ring/Bridging/VideoAdapter.h b/Ring/Ring/Bridging/VideoAdapter.h index c17ede31049f67cc92ddefc08f85a85a85f06914..446d7bf8bac4d3e39e83b2b09417f5e4e44ea0be 100644 --- a/Ring/Ring/Bridging/VideoAdapter.h +++ b/Ring/Ring/Bridging/VideoAdapter.h @@ -23,10 +23,12 @@ #import <AVFoundation/AVFoundation.h> @protocol VideoAdapterDelegate; +@protocol DecodingAdapterDelegate; @interface VideoAdapter : NSObject -@property (class, nonatomic, weak) id <VideoAdapterDelegate> delegate; +@property (class, nonatomic, weak) id <VideoAdapterDelegate> videoDelegate; +@property (class, nonatomic, weak) id <DecodingAdapterDelegate> decodingDelegate; - (void)addVideoDeviceWithName:(NSString*)deviceName withDevInfo:(NSDictionary*)deviceInfoDict; - (void)setDefaultDevice:(NSString*)deviceName; @@ -36,18 +38,18 @@ withHeight:(NSInteger)h; - (void)removeSinkTargetWithSinkId:(NSString*)sinkId; - (void)writeOutgoingFrameWithBuffer:(CVImageBufferRef)image - angle:(int)angle; + angle:(int)angle + videoInputId:(NSString*)videoInputId; - (void)setDecodingAccelerated:(BOOL)state; - (BOOL)getDecodingAccelerated; -- (void)switchInput:(NSString*)deviceName; -- (void)switchInput:(NSString*)deviceName forCall:(NSString*) callID; +- (void)switchInput:(NSString*)videoInputId accountId:(NSString*)accountId forCall:(NSString*)callID; - (void)setEncodingAccelerated:(BOOL)state; - (BOOL)getEncodingAccelerated; - (void)stopAudioDevice; -- (NSString*)startLocalRecording:(NSString*) path audioOnly:(BOOL)audioOnly; +- (NSString*)startLocalRecording:(NSString*)videoInputId path:(NSString*)path; - (void)stopLocalRecording:(NSString*) path; -- (void)startCamera; -- (void)stopCamera; +- (void)openVideoInput:(NSString*)path; +- (void)closeVideoInput:(NSString*)path; - (NSString*)createMediaPlayer:(NSString*)path; - (bool)pausePlayer:(NSString*)playerId pause:(BOOL)pause; - (bool)closePlayer:(NSString*)playerId; diff --git a/Ring/Ring/Bridging/VideoAdapter.mm b/Ring/Ring/Bridging/VideoAdapter.mm index 528474bd3795f39bc627fc909276fe6342a71c65..49f69b22a35d9e57304d1790e599cd69926cd753 100644 --- a/Ring/Ring/Bridging/VideoAdapter.mm +++ b/Ring/Ring/Bridging/VideoAdapter.mm @@ -46,14 +46,14 @@ struct Renderer void bindAVSinkFunctions() { avtarget.push = [this](std::unique_ptr<DRing::VideoFrame> frame) { - if(!VideoAdapter.delegate) { + if(!VideoAdapter.videoDelegate) { return; } @autoreleasepool { UIImage *image = [Utils convertHardwareDecodedFrameToImage: std::move(frame->pointer())]; isRendering = true; - [VideoAdapter.delegate writeFrameWithImage: image forCallId: rendererId]; + [VideoAdapter.videoDelegate writeFrameWithImage: image forCallId: rendererId]; isRendering = false; } }; @@ -72,7 +72,7 @@ struct Renderer target.push = [this](DRing::SinkTarget::FrameBufferPtr buf) { std::lock_guard<std::mutex> lk(renderMutex); daemonFramePtr_ = std::move(buf); - if(VideoAdapter.delegate) { + if(VideoAdapter.videoDelegate) { @autoreleasepool { CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef bitmapContext = CGBitmapContextCreate((void *)daemonFramePtr_->ptr, @@ -88,7 +88,7 @@ struct Renderer UIImage* image = [UIImage imageWithCGImage:cgImage]; CGImageRelease(cgImage); isRendering = true; - [VideoAdapter.delegate writeFrameWithImage: image forCallId: rendererId]; + [VideoAdapter.videoDelegate writeFrameWithImage: image forCallId: rendererId]; isRendering = false; } } @@ -101,8 +101,9 @@ struct Renderer std::map<std::string, std::shared_ptr<Renderer>> renderers; } -// Static delegate that will receive the propagated daemon events -static id <VideoAdapterDelegate> _delegate; +// Static delegates that will receive the propagated daemon events +static id <VideoAdapterDelegate> _videoDelegate; +static id <DecodingAdapterDelegate> _decodingDelegate; #pragma mark Init @@ -125,44 +126,39 @@ static id <VideoAdapterDelegate> _delegate; int w, int h, bool is_mixer) { - if(VideoAdapter.delegate) { + if(VideoAdapter.decodingDelegate) { NSString* rendererId = [NSString stringWithUTF8String:renderer_id.c_str()]; - NSString* codecName = @""; - std::map<std::string, std::string> callDetails = getCallDetails(renderer_id); - if (callDetails.find("VIDEO_CODEC") != callDetails.end()) { - codecName = [NSString stringWithUTF8String: callDetails["VIDEO_CODEC"].c_str()]; - } - [VideoAdapter.delegate decodingStartedWithRendererId:rendererId withWidth:(NSInteger)w withHeight:(NSInteger)h withCodec: codecName]; + [VideoAdapter.decodingDelegate decodingStartedWithRendererId:rendererId withWidth:(NSInteger)w withHeight:(NSInteger)h]; } })); videoHandlers.insert(exportable_callback<VideoSignal::DecodingStopped>([&](const std::string& renderer_id, const std::string& shm_path, bool is_mixer) { - if(VideoAdapter.delegate) { + if(VideoAdapter.decodingDelegate) { NSString* rendererId = [NSString stringWithUTF8String:renderer_id.c_str()]; - [VideoAdapter.delegate decodingStoppedWithRendererId:rendererId]; + [VideoAdapter.decodingDelegate decodingStoppedWithRendererId:rendererId]; } })); videoHandlers.insert(exportable_callback<VideoSignal::StartCapture>([&](const std::string& device) { - if(VideoAdapter.delegate) { + if(VideoAdapter.videoDelegate) { NSString* deviceString = [NSString stringWithUTF8String:device.c_str()]; - [VideoAdapter.delegate startCaptureWithDevice:deviceString]; + [VideoAdapter.videoDelegate startCaptureWithDevice:deviceString]; } })); - videoHandlers.insert(exportable_callback<VideoSignal::StopCapture>([&]() { - if(VideoAdapter.delegate) { - [VideoAdapter.delegate stopCapture]; + videoHandlers.insert(exportable_callback<VideoSignal::StopCapture>([&](const std::string& deviceId) { + if(VideoAdapter.videoDelegate) { + [VideoAdapter.videoDelegate stopCapture]; } })); videoHandlers.insert(exportable_callback<MediaPlayerSignal::FileOpened>([&](const std::string& playerId, std::map<std::string, std::string> playerInfo) { - if(VideoAdapter.delegate) { + if(VideoAdapter.videoDelegate) { NSString* player = @(playerId.c_str()); NSMutableDictionary* info = [Utils mapToDictionnary:playerInfo]; - [VideoAdapter.delegate fileOpenedFor:player fileInfo:info]; + [VideoAdapter.videoDelegate fileOpenedFor:player fileInfo:info]; } })); @@ -211,8 +207,10 @@ static id <VideoAdapterDelegate> _delegate; } - (void)writeOutgoingFrameWithBuffer:(CVImageBufferRef)image - angle:(int)angle{ - auto frame = DRing::getNewFrame(); + angle:(int)angle + videoInputId:(NSString*)videoInputId +{ + auto frame = DRing::getNewFrame(std::string([videoInputId UTF8String])); if(!frame) { return; } @@ -221,7 +219,7 @@ static id <VideoAdapterDelegate> _delegate; fromImageBuffer:image angle:(int) angle]; - DRing::publishFrame(); + DRing::publishFrame(std::string([videoInputId UTF8String])); } - (void)addVideoDeviceWithName:(NSString*)deviceName withDevInfo:(NSDictionary*)deviceInfoDict { @@ -254,20 +252,16 @@ static id <VideoAdapterDelegate> _delegate; return DRing::getEncodingAccelerated(); } -- (void)switchInput:(NSString*)deviceName { - DRing::switchInput(std::string([deviceName UTF8String])); -} - -- (void)switchInput:(NSString*)deviceName forCall:(NSString*) callID { - DRing::switchInput(std::string([callID UTF8String]), std::string([deviceName UTF8String])); +- (void)switchInput:(NSString*)videoInputId accountId:(NSString*)accountId forCall:(NSString*)callID { + DRing::switchInput(std::string([accountId UTF8String]), std::string([callID UTF8String]), std::string([videoInputId UTF8String])); } - (void)stopAudioDevice { DRing::stopAudioDevice(); } -- (NSString* )startLocalRecording:(NSString*) path audioOnly:(BOOL)audioOnly { - return @(DRing::startLocalRecorder(audioOnly, std::string([path UTF8String])).c_str()); +- (NSString*)startLocalRecording:(NSString*)videoInputId path:(NSString*)path { + return @(DRing::startLocalMediaRecorder(std::string([videoInputId UTF8String]), std::string([path UTF8String])).c_str()); } - (void)stopLocalRecording:(NSString*) path { @@ -281,8 +275,8 @@ static id <VideoAdapterDelegate> _delegate; return DRing::pausePlayer(std::string([playerId UTF8String]), pause); } -- (bool)closePlayer:(NSString*)playerId { - return DRing::closePlayer(std::string([playerId UTF8String])); +-(bool)closePlayer:(NSString*)playerId { + return DRing::closeMediaPlayer(std::string([playerId UTF8String])); } - (bool)mutePlayerAudio:(NSString*)playerId mute:(BOOL)mute { @@ -297,22 +291,32 @@ static id <VideoAdapterDelegate> _delegate; return DRing::getPlayerPosition(std::string([playerId UTF8String])); } -- (void)startCamera { - DRing::startCamera(); +- (void)openVideoInput:(NSString*)path { + DRing::openVideoInput(std::string([path UTF8String])); +} + +- (void)closeVideoInput:(NSString*)path { + DRing::closeVideoInput(std::string([path UTF8String])); +} + +#pragma mark VideoAdapterDelegate + ++ (id <VideoAdapterDelegate>)videoDelegate { + return _videoDelegate; } -- (void)stopCamera { - DRing::stopCamera(); ++ (void) setVideoDelegate:(id<VideoAdapterDelegate>)videoDelegate { + _videoDelegate = videoDelegate; } -#pragma mark PresenceAdapterDelegate +#pragma mark DecodingAdapterDelegate -+ (id <VideoAdapterDelegate>)delegate { - return _delegate; ++ (id <DecodingAdapterDelegate>)decodingDelegate { + return _decodingDelegate; } -+ (void) setDelegate:(id<VideoAdapterDelegate>)delegate { - _delegate = delegate; ++ (void) setDecodingDelegate:(id<DecodingAdapterDelegate>)decodingDelegate { + _decodingDelegate = decodingDelegate; } #pragma mark - diff --git a/Ring/Ring/Calls/CallViewModel.swift b/Ring/Ring/Calls/CallViewModel.swift index 9dfbc6e549096e66c8347a7fcf517fda19b71862..e1d50071e3a7fcb01721e2ea9b636c4f91a32fc1 100644 --- a/Ring/Ring/Calls/CallViewModel.swift +++ b/Ring/Ring/Calls/CallViewModel.swift @@ -581,7 +581,7 @@ extension CallViewModel { } guard let secondCall = self.callService.call(callID: contact.conferenceID) else { return } if call.participantsCallId.count == 1 { - self.callService.joinCall(firstCall: call.callId, secondCall: secondCall.callId) + self.callService.joinCall(firstCallId: call.callId, secondCallId: secondCall.callId) } else { self.callService.joinConference(confID: contact.conferenceID, callID: self.rendererId) } @@ -752,10 +752,9 @@ extension CallViewModel { guard let account = self.accountService.currentAccount else { return false } return self.callService.isModerator(participantId: account.jamiId, inConference: self.rendererId) } - func getItemsForConferenceMenu(participantId: String, callId: String) -> [MenuItem] { let conference = self.callService.call(callID: self.rendererId) - let active = self.callService.isParticipant(participantURI: participantId, activeIn: self.rendererId) + let active = self.callService.isParticipant(participantURI: participantId, activeIn: self.rendererId, accountId: conference?.accountId ?? "") // menu for local call if self.isLocalCall(participantId: participantId) || participantId.isEmpty { return menuItemsManager.getMenuItemsForLocalCall(conference: conference, active: active) diff --git a/Ring/Ring/Features/Conversations/SendFile/SendFileViewModel.swift b/Ring/Ring/Features/Conversations/SendFile/SendFileViewModel.swift index c6117cfb6ccc92e302ecb47eb1878c946db2164a..b02db5b2304348d0138cd44304989ff67d1a32da 100644 --- a/Ring/Ring/Features/Conversations/SendFile/SendFileViewModel.swift +++ b/Ring/Ring/Features/Conversations/SendFile/SendFileViewModel.swift @@ -131,7 +131,7 @@ class SendFileViewModel: Stateable, ViewModel { self.injectionBag = injectionBag if !audioOnly { videoService.setCameraOrientation(orientation: UIDevice.current.orientation) - videoService.startCamera() + videoService.startMediumCamera() } videoService.capturedVideoFrame.asObservable() .subscribe(onNext: { [weak self] frame in @@ -163,7 +163,10 @@ class SendFileViewModel: Stateable, ViewModel { let dateString = dateFormatter.string(from: date) let random = String(arc4random_uniform(9999)) let nameForRecordingFile = dateString + "_" + random - guard let url = self.fileTransferService.getFilePathForRecordings(forFile: nameForRecordingFile, accountID: conversation.accountId, conversationID: conversation.id, isSwarm: self.conversation.isSwarm()) else { return } + guard let url = self.fileTransferService.getFilePathForRecordings(forFile: nameForRecordingFile, + accountID: conversation.accountId, + conversationID: conversation.id, + isSwarm: self.conversation.isSwarm()) else { return } guard let name = self.videoService .startLocalRecorder(audioOnly: audioOnly, path: url.path) else { return diff --git a/Ring/Ring/Models/CallModel.swift b/Ring/Ring/Models/CallModel.swift index 86862cde7e0e736d7c8f5dec8ace1d8da406138d..2ed9a210b0770c1676cf33c820792246d5b1bb67 100644 --- a/Ring/Ring/Models/CallModel.swift +++ b/Ring/Ring/Models/CallModel.swift @@ -68,6 +68,7 @@ enum CallDetailKey: String { case videoSourceKey = "VIDEO_SOURCE" case audioOnlyKey = "AUDIO_ONLY" case confID = "CONF_ID" + case videoCodec = "VIDEO_CODEC" } enum MediaAttributeKey: String { diff --git a/Ring/Ring/Services/CallsAdapterDelegate.swift b/Ring/Ring/Services/CallsAdapterDelegate.swift index 9743f947b63dafa7f80dbc95617e8a95f4865759..07a5cd19ced68da8a43e1e51ced1002864e57cfc 100644 --- a/Ring/Ring/Services/CallsAdapterDelegate.swift +++ b/Ring/Ring/Services/CallsAdapterDelegate.swift @@ -20,15 +20,15 @@ */ @objc protocol CallsAdapterDelegate { - func didChangeCallState(withCallId callId: String, state: String, stateCode: NSInteger) + func didChangeCallState(withCallId callId: String, state: String, accountId: String, stateCode: NSInteger) func didReceiveMediaChangeRequest(withAccountId accountId: String, callId: String, withMedia: [[String: String]]) func didReceiveMessage(withCallId callId: String, fromURI uri: String, message: [String: String]) func receivingCall(withAccountId accountId: String, callId: String, fromURI uri: String, withMedia: [[String: String]]) func callPlacedOnHold(withCallId callId: String, holding: Bool) func audioMuted(call callId: String, mute: Bool) func videoMuted(call callId: String, mute: Bool) - func conferenceCreated(conference conferenceID: String) - func conferenceChanged(conference conferenceID: String, state: String) + func conferenceCreated(conference conferenceID: String, accountId: String) + func conferenceChanged(conference conferenceID: String, accountId: String, state: String) func conferenceRemoved(conference conferenceID: String) func conferenceInfoUpdated(conference conferenceID: String, info: [[String: String]]) func didChangeMediaNegotiationStatus(withCallId callId: String, event: String, withMedia: [[String: String]]) diff --git a/Ring/Ring/Services/CallsService.swift b/Ring/Ring/Services/CallsService.swift index 67e01bcd7b1b2601a5d87a3947d2f510625c1f36..084c0279a0fb8eed4c58c51e92f334a1f6048de2 100644 --- a/Ring/Ring/Services/CallsService.swift +++ b/Ring/Ring/Services/CallsService.swift @@ -56,6 +56,7 @@ class CallsService: CallsAdapterDelegate { var calls = BehaviorRelay<[String: CallModel]>(value: [String: CallModel]()) var pendingConferences = [String: Set<String>]() + var createdConferences = Set<String>() /// set of created conferences, waiting to calls to be attached private let ringVCardMIMEType = "x-ring/ring.profile.vcard;" @@ -102,15 +103,15 @@ class CallsService: CallsAdapterDelegate { @objc func refuseUnansweredCall(_ notification: NSNotification) { - guard let callid = notification.userInfo?[NotificationUserInfoKeys.callID.rawValue] as? String else { + guard let callId = notification.userInfo?[NotificationUserInfoKeys.callID.rawValue] as? String else { return } - guard let call = self.call(callID: callid) else { + guard let call = self.call(callID: callId) else { return } if call.state == .incoming { - self.refuse(callId: callid) + self.refuse(callId: callId) .subscribe({_ in print("Call ignored") }) @@ -122,6 +123,11 @@ class CallsService: CallsAdapterDelegate { return self.calls.value[callID] } + func getVideoCodec(call: CallModel) -> String? { + let callDetails = self.callsAdapter.callDetails(withCallId: call.callId, accountId: call.accountId) + return callDetails?[CallDetailKey.videoCodec.rawValue] + } + func call(participantHash: String, accountID: String) -> CallModel? { return self.calls .value.values @@ -137,7 +143,7 @@ class CallsService: CallsAdapterDelegate { completable(.error(CallServiceError.acceptCallFailed)) return Disposables.create { } } - let success = self.callsAdapter.acceptCall(withId: callId, withMedia: call?.mediaList) + let success = self.callsAdapter.acceptCall(withId: callId, accountId: call?.accountId, withMedia: call?.mediaList) if success { completable(.completed) } else { @@ -149,30 +155,33 @@ class CallsService: CallsAdapterDelegate { func joinConference(confID: String, callID: String) { guard let secondConf = self.call(callID: callID) else { return } + guard let firstConf = self.call(callID: confID) else { return } if let pending = self.pendingConferences[confID], !pending.isEmpty { self.pendingConferences[confID]!.insert(callID) } else { self.pendingConferences[confID] = [callID] } if secondConf.participantsCallId.count == 1 { - self.callsAdapter.joinConference(confID, call: callID) + self.callsAdapter.joinConference(confID, call: callID, accountId: firstConf.accountId, account2Id: secondConf.accountId) } else { - self.callsAdapter.joinConferences(confID, secondConference: callID) + self.callsAdapter.joinConferences(confID, secondConference: callID, accountId: firstConf.accountId, account2Id: secondConf.accountId) } } - func joinCall(firstCall: String, secondCall: String) { - if let pending = self.pendingConferences[firstCall], !pending.isEmpty { - self.pendingConferences[firstCall]!.insert(secondCall) + func joinCall(firstCallId: String, secondCallId: String) { + guard let firstCall = self.call(callID: firstCallId) else { return } + guard let secondCall = self.call(callID: secondCallId) else { return } + if let pending = self.pendingConferences[firstCallId], !pending.isEmpty { + self.pendingConferences[firstCallId]!.insert(secondCallId) } else { - self.pendingConferences[firstCall] = [secondCall] + self.pendingConferences[firstCallId] = [secondCallId] } - self.callsAdapter.joinCall(firstCall, second: secondCall) + self.callsAdapter.joinCall(firstCallId, second: secondCallId, accountId: firstCall.accountId, account2Id: secondCall.accountId) } - func isParticipant(participantURI: String?, activeIn conferenceId: String) -> Bool? { + func isParticipant(participantURI: String?, activeIn conferenceId: String, accountId: String) -> Bool? { guard let uri = participantURI, - let participantsArray = self.callsAdapter.getConferenceInfo(conferenceId) as? [[String: String]] else { return nil } + let participantsArray = self.callsAdapter.getConferenceInfo(conferenceId, accountId: accountId) as? [[String: String]] else { return nil } let participants = self.arrayToConferenceParticipants(participants: participantsArray, onlyURIAndActive: true) for participant in participants where participant.uri?.filterOutHost() == uri.filterOutHost() { return participant.isActive @@ -210,11 +219,11 @@ class CallsService: CallsAdapterDelegate { func setActiveParticipant(conferenceId: String, maximixe: Bool, jamiId: String) { guard let conference = self.call(callID: conferenceId), - let isActive = self.isParticipant(participantURI: jamiId, activeIn: conferenceId) else { return } + let isActive = self.isParticipant(participantURI: jamiId, activeIn: conferenceId, accountId: conference.accountId) else { return } let newLayout = isActive ? self.getNewLayoutForActiveParticipant(currentLayout: conference.layout, maximixe: maximixe) : .oneWithSmal conference.layout = newLayout - self.callsAdapter.setActiveParticipant(jamiId, forConference: conferenceId) - self.callsAdapter.setConferenceLayout(newLayout.rawValue, forConference: conferenceId) + self.callsAdapter.setActiveParticipant(jamiId, forConference: conferenceId, accountId: conference.accountId) + self.callsAdapter.setConferenceLayout(newLayout.rawValue, forConference: conferenceId, accountId: conference.accountId) } private func getNewLayoutForActiveParticipant(currentLayout: CallLayout, maximixe: Bool) -> CallLayout { @@ -236,7 +245,13 @@ class CallsService: CallsAdapterDelegate { userName: String, isAudioOnly: Bool = false) -> Observable<CallModel> { let call = self.calls.value[callId] - let placeCall = self.placeCall(withAccount: account, toRingId: contactId, userName: userName, isAudioOnly: isAudioOnly, withMedia: call?.mediaList ?? [[String: String]]()).asObservable().publish() + let placeCall = self.placeCall(withAccount: account, + toRingId: contactId, + userName: userName, + isAudioOnly: isAudioOnly, + withMedia: call?.mediaList ?? [[String: String]]()) + .asObservable() + .publish() placeCall .subscribe(onNext: { (callModel) in self.inConferenceCalls.onNext(callModel) @@ -253,7 +268,11 @@ class CallsService: CallsAdapterDelegate { func refuse(callId: String) -> Completable { return Completable.create(subscribe: { completable in - let success = self.callsAdapter.refuseCall(withId: callId) + guard let call = self.call(callID: callId) else { + completable(.error(CallServiceError.hangUpCallFailed)) + return Disposables.create { } + } + let success = self.callsAdapter.refuseCall(withId: callId, accountId: call.accountId) if success { completable(.completed) } else { @@ -266,7 +285,11 @@ class CallsService: CallsAdapterDelegate { func hangUp(callId: String) -> Completable { return Completable.create(subscribe: { completable in var success: Bool - success = self.callsAdapter.hangUpCall(withId: callId) + guard let call = self.call(callID: callId) else { + completable(.error(CallServiceError.hangUpCallFailed)) + return Disposables.create { } + } + success = self.callsAdapter.hangUpCall(withId: callId, accountId: call.accountId) if success { completable(.completed) } else { @@ -284,9 +307,9 @@ class CallsService: CallsAdapterDelegate { } var success: Bool if call.participantsCallId.count < 2 { - success = self.callsAdapter.hangUpCall(withId: callId) + success = self.callsAdapter.hangUpCall(withId: callId, accountId: call.accountId) } else { - success = self.callsAdapter.hangUpConference(callId) + success = self.callsAdapter.hangUpConference(callId, accountId: call.accountId) } if success { completable(.completed) @@ -299,7 +322,11 @@ class CallsService: CallsAdapterDelegate { func hold(callId: String) -> Completable { return Completable.create(subscribe: { completable in - let success = self.callsAdapter.holdCall(withId: callId) + guard let call = self.call(callID: callId) else { + completable(.error(CallServiceError.hangUpCallFailed)) + return Disposables.create { } + } + let success = self.callsAdapter.holdCall(withId: callId, accountId: call.accountId) if success { completable(.completed) } else { @@ -311,7 +338,11 @@ class CallsService: CallsAdapterDelegate { func unhold(callId: String) -> Completable { return Completable.create(subscribe: { completable in - let success = self.callsAdapter.unholdCall(withId: callId) + guard let call = self.call(callID: callId) else { + completable(.error(CallServiceError.hangUpCallFailed)) + return Disposables.create { } + } + let success = self.callsAdapter.unholdCall(withId: callId, accountId: call.accountId) if success { completable(.completed) } else { @@ -355,9 +386,9 @@ class CallsService: CallsAdapterDelegate { call.callType = .outgoing return Single<CallModel>.create(subscribe: { [weak self] single in if let self = self, let callId = self.callsAdapter.placeCall(withAccountId: account.id, - toRingId: ringId, + toParticipantId: ringId, withMedia: mediaList), - let callDictionary = self.callsAdapter.callDetails(withCallId: callId) { + let callDictionary = self.callsAdapter.callDetails(withCallId: callId, accountId: account.id) { call.update(withDictionary: callDictionary, withMedia: mediaList) call.callId = callId call.participantsCallId.removeAll() @@ -375,8 +406,10 @@ class CallsService: CallsAdapterDelegate { } func hostMuteAudio(conferenceId: String, mute: Bool, localCallId: String) { + guard let conference = call(callID: conferenceId) else { return } let success = self.callsAdapter .muteMedia(conferenceId, + accountId: conference.accountId, mediaType: String(describing: MediaType.audio), muted: mute) guard let call = self.calls.value[localCallId], success else { @@ -387,8 +420,11 @@ class CallsService: CallsAdapterDelegate { } func hostMuteVideo(conferenceId: String, mute: Bool, localCallId: String) { + guard let conference = self.calls.value[conferenceId] else { + return + } let success = self.callsAdapter - .muteMedia(conferenceId, + .muteMedia(conferenceId, accountId: conference.accountId, mediaType: String(describing: MediaType.video), muted: mute) guard let call = self.calls.value[localCallId], success else { @@ -421,8 +457,8 @@ class CallsService: CallsAdapterDelegate { media[MediaAttributeKey.label.rawValue] = mediaLabel mediaList.append(media) } - self.callsAdapter.requestMediaChange(callId, withMedia: mediaList) - if let callDictionary = self.callsAdapter.callDetails(withCallId: callId) { + self.callsAdapter.requestMediaChange(callId, accountId: call.accountId, withMedia: mediaList) + if let callDictionary = self.callsAdapter.callDetails(withCallId: callId, accountId: call.accountId) { call.update(withDictionary: callDictionary, withMedia: mediaList) self.currentCallsEvents.onNext(call) } @@ -431,7 +467,7 @@ class CallsService: CallsAdapterDelegate { func muteCurrentCallVideoVideo(mute: Bool) { for call in self.calls.value.values where call.state == .current { self.callsAdapter - .muteMedia(call.callId, + .muteMedia(call.callId, accountId: call.accountId, mediaType: String(describing: MediaType.video), muted: mute) return @@ -446,13 +482,14 @@ class CallsService: CallsAdapterDelegate { if accountID.isEmpty || callID.isEmpty { return } - guard let vCard = self.dbManager.accountVCard(for: accountID) else { return } + guard let vCard = self.dbManager.accountVCard(for: accountID), + let phoneNumber = vCard.phoneNumbers.first?.value else { return } DispatchQueue.main.async { [weak self] in guard let self = self else { return } VCardUtils.sendVCard(card: vCard, callID: callID, accountID: accountID, - sender: self) + sender: self, from: phoneNumber.stringValue) } } @@ -460,9 +497,10 @@ class CallsService: CallsAdapterDelegate { guard let call = self.call(callID: callID) else { return } let messageDictionary = ["text/plain": message] self.callsAdapter.sendTextMessage(withCallID: callID, - message: messageDictionary, accountId: accountId.id, - sMixed: true) + message: messageDictionary, + from: call.paricipantHash(), + isMixed: true) let accountHelper = AccountModelHelper(withAccount: accountId) let type = accountHelper.isAccountSip() ? URIType.sip : URIType.ring let contactUri = JamiURI.init(schema: type, infoHach: call.participantUri, account: accountId) @@ -480,18 +518,19 @@ class CallsService: CallsAdapterDelegate { } } - func sendChunk(callID: String, message: [String: String], accountId: String) { + func sendChunk(callID: String, message: [String: String], accountId: String, from: String) { self.callsAdapter.sendTextMessage(withCallID: callID, - message: message, accountId: accountId, - sMixed: true) + message: message, + from: from, + isMixed: true) } // MARK: CallsAdapterDelegate // swiftlint:disable cyclomatic_complexity - func didChangeCallState(withCallId callId: String, state: String, stateCode: NSInteger) { + func didChangeCallState(withCallId callId: String, state: String, accountId: String, stateCode: NSInteger) { - if let callDictionary = self.callsAdapter.callDetails(withCallId: callId) { + if let callDictionary = self.callsAdapter.callDetails(withCallId: callId, accountId: accountId) { // Add or update new call var call = self.calls.value[callId] call?.state = CallState(rawValue: state) ?? CallState.unknown @@ -551,9 +590,9 @@ class CallsService: CallsAdapterDelegate { if let pendingCall = self.call(callID: confId) { DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { if pendingCall.participantsCallId.count == 1 { - self.callsAdapter.joinCall(confId, second: callId) + self.callsAdapter.joinCall(confId, second: callId, accountId: pendingCall.accountId, account2Id: accountId) } else { - self.callsAdapter.joinConference(confId, call: callId) + self.callsAdapter.joinConference(confId, call: callId, accountId: pendingCall.accountId, account2Id: accountId) } } } @@ -567,7 +606,7 @@ class CallsService: CallsAdapterDelegate { func didChangeMediaNegotiationStatus(withCallId callId: String, event: String, withMedia: [[String: String]]) { guard let call = self.calls.value[callId], - let callDictionary = self.callsAdapter.callDetails(withCallId: callId) else { return } + let callDictionary = self.callsAdapter.callDetails(withCallId: callId, accountId: call.accountId) else { return } call.update(withDictionary: callDictionary, withMedia: withMedia) self.currentCallsEvents.onNext(call) } @@ -595,7 +634,7 @@ class CallsService: CallsAdapterDelegate { answerMedias.append(answerMedia) } } - self.callsAdapter.answerMediaChangeResquest(callId, withMedia: answerMedias) + self.callsAdapter.answerMediaChangeResquest(callId, accountId: accountId, withMedia: answerMedias) } func shouldCallBeAddedToConference(callId: String) -> String? { @@ -634,7 +673,7 @@ class CallsService: CallsAdapterDelegate { // swiftlint:enable cyclomatic_complexity func receivingCall(withAccountId accountId: String, callId: String, fromURI uri: String, withMedia mediaList: [[String: String]]) { - if let callDictionary = self.callsAdapter.callDetails(withCallId: callId) { + if let callDictionary = self.callsAdapter.callDetails(withCallId: callId, accountId: accountId) { if !isCurrentCall() { var call = self.calls.value[callId] @@ -692,9 +731,15 @@ class CallsService: CallsAdapterDelegate { self.currentCallsEvents.onNext(call) } - func conferenceCreated(conference conferenceID: String) { + func conferenceCreated(conference conferenceID: String, accountId: String) { let conferenceCalls = Set(self.callsAdapter - .getConferenceCalls(conferenceID)) + .getConferenceCalls(conferenceID, accountId: accountId)) + if conferenceCalls.isEmpty { + // no calls attached to a conference. Wait until conference changed to check the calls. + createdConferences.insert(conferenceID) + return + } + createdConferences.remove(conferenceID) self.pendingConferences.forEach { pending in if !conferenceCalls.contains(pending.key) || conferenceCalls.isDisjoint(with: pending.value) { @@ -714,7 +759,7 @@ class CallsService: CallsAdapterDelegate { values.forEach { (call) in self.call(callID: call)?.participantsCallId = conferenceCalls } - guard var callDetails = self.callsAdapter.getConferenceDetails(conferenceID) else { return } + guard var callDetails = self.callsAdapter.getConferenceDetails(conferenceID, accountId: accountId) else { return } callDetails[CallDetailKey.accountIdKey.rawValue] = self.call(callID: callId)?.accountId callDetails[CallDetailKey.audioOnlyKey.rawValue] = self.call(callID: callId)?.isAudioOnly.toString() let mediaList = [[String: String]]() @@ -727,10 +772,15 @@ class CallsService: CallsAdapterDelegate { } } - func conferenceChanged(conference conferenceID: String, state: String) { + func conferenceChanged(conference conferenceID: String, accountId: String, state: String) { + if createdConferences.contains(conferenceID) { + // a conference was created but calls was not attached to a conference. In this case a conference should be added first. + self.conferenceCreated(conference: conferenceID, accountId: accountId) + return + } guard let conference = self.call(callID: conferenceID) else { return } let conferenceCalls = Set(self.callsAdapter - .getConferenceCalls(conferenceID)) + .getConferenceCalls(conferenceID, accountId: conference.accountId)) conference.participantsCallId = conferenceCalls conferenceCalls.forEach { (callId) in guard let call = self.call(callID: callId) else { return } @@ -759,7 +809,7 @@ class CallsService: CallsAdapterDelegate { guard let conferenceID = conferences.first, let conference = call(callID: conferenceID) else { return } let conferenceCalls = Set(self.callsAdapter - .getConferenceCalls(conferenceID)) + .getConferenceCalls(conferenceID, accountId: conference.accountId)) conference.participantsCallId = conferenceCalls conferenceCalls.forEach { (callID) in self.call(callID: callID)?.participantsCallId = conferenceCalls @@ -767,14 +817,17 @@ class CallsService: CallsAdapterDelegate { } func muteParticipant(confId: String, participantId: String, active: Bool) { - self.callsAdapter.muteConferenceParticipant(participantId, forConference: confId, active: active) + guard let conference = call(callID: confId) else { return } + self.callsAdapter.muteConferenceParticipant(participantId, forConference: confId, accountId: conference.accountId, active: active) } func setModeratorParticipant(confId: String, participantId: String, active: Bool) { - self.callsAdapter.setConferenceModerator(participantId, forConference: confId, active: active) + guard let conference = call(callID: confId) else { return } + self.callsAdapter.setConferenceModerator(participantId, forConference: confId, accountId: conference.accountId, active: active) } func hangupParticipant(confId: String, participantId: String) { - self.callsAdapter.hangupConferenceParticipant(participantId, forConference: confId) + guard let conference = call(callID: confId) else { return } + self.callsAdapter.hangupConferenceParticipant(participantId, forConference: confId, accountId: conference.accountId) } } diff --git a/Ring/Ring/Services/ConversationsManager.swift b/Ring/Ring/Services/ConversationsManager.swift index 112f43a2f4877b9ac1002487e2e50cf146b9a291..23a152c821d72aeeb6136c1b8e89c2f4cd722890 100644 --- a/Ring/Ring/Services/ConversationsManager.swift +++ b/Ring/Ring/Services/ConversationsManager.swift @@ -36,7 +36,6 @@ class ConversationsManager { private let callService: CallsService private let locationSharingService: LocationSharingService private let callsProvider: CallsProviderDelegate - private let videoService: VideoService private let requestService: RequestsService private let disposeBag = DisposeBag() @@ -54,7 +53,6 @@ class ConversationsManager { locationSharingService: LocationSharingService, contactsService: ContactsService, callsProvider: CallsProviderDelegate, - videoService: VideoService, requestsService: RequestsService) { self.conversationService = conversationService self.accountsService = accountsService @@ -64,7 +62,6 @@ class ConversationsManager { self.locationSharingService = locationSharingService self.contactsService = contactsService self.callsProvider = callsProvider - self.videoService = videoService self.requestService = requestsService ConversationsAdapter.messagesDelegate = self @@ -161,26 +158,6 @@ class ConversationsManager { } private func subscribeCallsEvents() { - self.callService.sharedResponseStream - .filter { event in - event.eventType == .callEnded - } - .subscribe { [weak self] event in - guard let self = self else { return } - guard let accountID: String = event.getEventInput(.accountId) else { - return - } - guard let jamiId: String = event.getEventInput(.uri) else { - return - } - guard let call = self.callService.call(participantHash: jamiId.filterOutHost(), accountID: accountID) else { return } - self.callsProvider.stopCall(callUUID: call.callUUID) - self.videoService.stopCapture() - self.videoService.setCameraOrientation(orientation: UIDevice.current.orientation) - } onError: { _ in - } - .disposed(by: disposeBag) - self.callService.newMessage .filter({ (event) in return event.eventType == ServiceEventType.newIncomingMessage diff --git a/Ring/Ring/Services/DecodingAdapterDelegate.swift b/Ring/Ring/Services/DecodingAdapterDelegate.swift new file mode 100644 index 0000000000000000000000000000000000000000..d68f5988b3c9d0780a615de68150e1c8a53f029a --- /dev/null +++ b/Ring/Ring/Services/DecodingAdapterDelegate.swift @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 Savoir-faire Linux Inc. + * + * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +@objc protocol DecodingAdapterDelegate { + func decodingStarted(withRendererId rendererId: String, + withWidth width: Int, + withHeight height: Int) + func decodingStopped(withRendererId rendererId: String) +} diff --git a/Ring/Ring/Services/VideoAdapterDelegate.swift b/Ring/Ring/Services/VideoAdapterDelegate.swift index 9f67779f71142a5be708f51b75c401006c1157cd..acccb66de32d3578329c9964da864e0d5be08889 100644 --- a/Ring/Ring/Services/VideoAdapterDelegate.swift +++ b/Ring/Ring/Services/VideoAdapterDelegate.swift @@ -19,15 +19,9 @@ */ @objc protocol VideoAdapterDelegate { - func decodingStarted(withRendererId rendererId: String, - withWidth width: Int, - withHeight height: Int, - withCodec codecId: String) - func decodingStopped(withRendererId rendererId: String) func startCapture(withDevice device: String) func stopCapture() func writeFrame(withImage image: UIImage?, forCallId: String) func setDecodingAccelerated(withState state: Bool) - func switchInput(toDevice device: String, callID: String?) func fileOpened(for playerId: String, fileInfo: [String: String]) } diff --git a/Ring/Ring/Services/VideoManager.swift b/Ring/Ring/Services/VideoManager.swift new file mode 100644 index 0000000000000000000000000000000000000000..5dc4a9b4bcb9d91f0cfc139cb1eb1621cee141fb --- /dev/null +++ b/Ring/Ring/Services/VideoManager.swift @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Savoir-faire Linux Inc. + * + * Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +import RxSwift +import SwiftyBeaver + +class VideoManager { + + let log = SwiftyBeaver.self + private let callService: CallsService + private let callsProvider: CallsProviderDelegate + private let videoService: VideoService + + private let disposeBag = DisposeBag() + + init(with callService: CallsService, + callsProvider: CallsProviderDelegate, + videoService: VideoService) { + self.callService = callService + self.callsProvider = callsProvider + self.videoService = videoService + self.subscribeCallsEvents() + VideoAdapter.decodingDelegate = self + } + + private func subscribeCallsEvents() { + self.callService.sharedResponseStream + .filter { event in + event.eventType == .callEnded + } + .subscribe { [weak self] event in + guard let self = self else { return } + guard let accountID: String = event.getEventInput(.accountId) else { + return + } + guard let jamiId: String = event.getEventInput(.uri) else { + return + } + guard let call = self.callService.call(participantHash: jamiId.filterOutHost(), accountID: accountID) else { return } + self.callsProvider.stopCall(callUUID: call.callUUID) + self.videoService.stopCapture() + self.videoService.setCameraOrientation(orientation: UIDevice.current.orientation) + } onError: {_ in + } + .disposed(by: disposeBag) + } +} + +extension VideoManager: DecodingAdapterDelegate { + func decodingStarted(withRendererId rendererId: String, + withWidth width: Int, + withHeight height: Int) { + var accountId = "" + var codecId: String? + if let call = self.callService.call(callID: rendererId), + let codec = self.callService.getVideoCodec(call: call) { + codecId = codec + accountId = call.accountId + } + self.videoService.decodingStarted(withRendererId: rendererId, withWidth: width, withHeight: height, withCodec: codecId, withaAccountId: accountId) + } + func decodingStopped(withRendererId rendererId: String) { + self.videoService.decodingStopped(withRendererId: rendererId) + } + +} diff --git a/Ring/Ring/Services/VideoService.swift b/Ring/Ring/Services/VideoService.swift index a681165dd80c2406a358e9cefcebdb328404b60e..b133365ef844377e59cb303b52263ada2254456f 100644 --- a/Ring/Ring/Services/VideoService.swift +++ b/Ring/Ring/Services/VideoService.swift @@ -286,18 +286,20 @@ class VideoService: FrameExtractorDelegate { private var hardwareAccelerationEnabledByUser = true var angle: Int = 0 var switchInputRequested: Bool = false + var currentDeviceId = "" private let disposeBag = DisposeBag() init(withVideoAdapter videoAdapter: VideoAdapter) { self.videoAdapter = videoAdapter currentOrientation = camera.getOrientation - VideoAdapter.delegate = self + VideoAdapter.videoDelegate = self self.hardwareAccelerationEnabledByUser = videoAdapter.getEncodingAccelerated() camera.delegate = self NotificationCenter.default.addObserver(self, selector: #selector(self.restoreDefaultDevice), name: NSNotification.Name(rawValue: NotificationName.restoreDefaultVideoDevice.rawValue), object: nil) + self.currentDeviceId = self.videoAdapter.getDefaultDevice() } @objc @@ -388,12 +390,14 @@ class VideoService: FrameExtractorDelegate { } extension VideoService: VideoAdapterDelegate { - func switchInput(toDevice device: String, callID: String?) { + func switchInput(toDevice device: String, callID: String?, accountId: String) { if let call = callID { - videoAdapter.switchInput(device, forCall: call) + videoAdapter.switchInput(device, accountId: accountId, forCall: call) return } - videoAdapter.switchInput(device) + let current = self.videoAdapter.getDefaultDevice() + self.videoAdapter.closeVideoInput(current) + self.videoAdapter.openVideoInput(device) } func setDecodingAccelerated(withState state: Bool) { @@ -423,19 +427,20 @@ extension VideoService: VideoAdapterDelegate { } } - func decodingStarted(withRendererId rendererId: String, withWidth width: Int, withHeight height: Int, withCodec codecId: String) { - if !codecId.isEmpty { + func decodingStarted(withRendererId rendererId: String, withWidth width: Int, withHeight height: Int, withCodec codec: String?, withaAccountId accountId: String) { + if let codecId = codec, !codecId.isEmpty { // we do not support hardware acceleration with VP8 codec. In this case software // encoding will be used. Downgrate resolution if needed. After call finished // resolution will be restored in restoreDefaultDevice() let codec = VideoCodecs(rawValue: codecId) ?? VideoCodecs.unknown if !supportHardware(codec: codec) && self.camera.quality == AVCaptureSession.Preset.hd1280x720 { self.videoAdapter.setDefaultDevice(camera.namePortrait) - self.videoAdapter.switchInput("camera://" + camera.namePortrait, forCall: rendererId) + self.videoAdapter.switchInput("camera://" + camera.namePortrait, accountId: accountId, forCall: rendererId) } } self.log.debug("Decoding started...") videoAdapter.registerSinkTarget(withSinkId: rendererId, withWidth: width, withHeight: height) + self.currentDeviceId = self.videoAdapter.getDefaultDevice() } func supportHardware(codec: VideoCodecs) -> Bool { @@ -464,15 +469,15 @@ extension VideoService: VideoAdapterDelegate { self.camera.startCapturing() } - func startCamera() { - self.videoAdapter.startCamera() + func startMediumCamera() { + self.videoAdapter.openVideoInput("camera://" + self.camera.namePortrait) } func videRecordingFinished() { if self.cameraPosition == .back { self.switchCamera() } - self.videoAdapter.stopCamera() + self.videoAdapter.closeVideoInput("camera://" + self.camera.namePortrait) self.stopAudioDevice() } @@ -513,7 +518,7 @@ extension VideoService: VideoAdapterDelegate { orientation: self.getImageOrienation())) } videoAdapter.writeOutgoingFrame(with: imageBuffer, - angle: Int32(self.angle)) + angle: Int32(self.angle), videoInputId: "camera://" + self.currentDeviceId) } func updateDevicePosition(position: AVCaptureDevice.Position) { @@ -526,7 +531,9 @@ extension VideoService: VideoAdapterDelegate { } func startLocalRecorder(audioOnly: Bool, path: String) -> String? { - return self.videoAdapter.startLocalRecording(path, audioOnly: audioOnly) + let device = audioOnly ? "" : "camera://" + camera.namePortrait + self.currentDeviceId = camera.namePortrait + return self.videoAdapter.startLocalRecording(device, path: path) } func stopLocalRecorder(path: String) {