Commit a6563206 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Andreas Traczyk

call: add options

This patch adds the following call options:
- mute audio
- mute video
- pause call
- switch camera

Change-Id: Ia02deae0e86e117d9c262ed3db2ec223414a4c92
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 70702cba
...@@ -238,7 +238,6 @@ ...@@ -238,7 +238,6 @@
62A88D371F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */; }; 62A88D371F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */; };
62A88D391F6C323500F8AB18 /* PresenceAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */; }; 62A88D391F6C323500F8AB18 /* PresenceAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */; };
62A88D3B1F6C3ACC00F8AB18 /* PresenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */; }; 62A88D3B1F6C3ACC00F8AB18 /* PresenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */; };
62AA15B21FF422810064A063 /* src in Resources */ = {isa = PBXBuildFile; fileRef = 62AA15B11FF422810064A063 /* src */; };
62AA15BF1FFC36840064A063 /* VideoAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15BE1FFC36840064A063 /* VideoAdapter.mm */; }; 62AA15BF1FFC36840064A063 /* VideoAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15BE1FFC36840064A063 /* VideoAdapter.mm */; };
62AA15C31FFC39C80064A063 /* VideoAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15C21FFC39C80064A063 /* VideoAdapterDelegate.swift */; }; 62AA15C31FFC39C80064A063 /* VideoAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15C21FFC39C80064A063 /* VideoAdapterDelegate.swift */; };
62AA15CA1FFD3D7E0064A063 /* VideoService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15C91FFD3D7E0064A063 /* VideoService.swift */; }; 62AA15CA1FFD3D7E0064A063 /* VideoService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AA15C91FFD3D7E0064A063 /* VideoService.swift */; };
...@@ -512,7 +511,6 @@ ...@@ -512,7 +511,6 @@
62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceAdapterDelegate.swift; sourceTree = "<group>"; }; 62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceAdapterDelegate.swift; sourceTree = "<group>"; };
62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PresenceAdapter.mm; sourceTree = "<group>"; }; 62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PresenceAdapter.mm; sourceTree = "<group>"; };
62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceService.swift; sourceTree = "<group>"; }; 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceService.swift; sourceTree = "<group>"; };
62AA15B11FF422810064A063 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = ../../daemon/src; sourceTree = "<group>"; };
62AA15BD1FFC366D0064A063 /* VideoAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VideoAdapter.h; sourceTree = "<group>"; }; 62AA15BD1FFC366D0064A063 /* VideoAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VideoAdapter.h; sourceTree = "<group>"; };
62AA15BE1FFC36840064A063 /* VideoAdapter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoAdapter.mm; sourceTree = "<group>"; }; 62AA15BE1FFC36840064A063 /* VideoAdapter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VideoAdapter.mm; sourceTree = "<group>"; };
62AA15C21FFC39C80064A063 /* VideoAdapterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoAdapterDelegate.swift; sourceTree = "<group>"; }; 62AA15C21FFC39C80064A063 /* VideoAdapterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoAdapterDelegate.swift; sourceTree = "<group>"; };
......
...@@ -37,5 +37,6 @@ ...@@ -37,5 +37,6 @@
- (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId; - (NSDictionary<NSString*,NSString*>*)callDetailsWithCallId:(NSString*)callId;
- (NSArray<NSString*>*)calls; - (NSArray<NSString*>*)calls;
- (void) sendTextMessageWithCallID:(NSString*)callId message:(NSDictionary*)message accountId:(NSString*)accountId sMixed:(bool)isMixed; - (void) sendTextMessageWithCallID:(NSString*)callId message:(NSDictionary*)message accountId:(NSString*)accountId sMixed:(bool)isMixed;
- (BOOL) muteMedia:(NSString*)callId mediaType:(NSString*)media muted:(bool)muted;
@end @end
...@@ -118,7 +118,7 @@ static id <CallsAdapterDelegate> _delegate; ...@@ -118,7 +118,7 @@ static id <CallsAdapterDelegate> _delegate;
bool muted) { bool muted) {
if (CallsAdapter.delegate) { if (CallsAdapter.delegate) {
NSString* callIdString = [NSString stringWithUTF8String:callId.c_str()]; NSString* callIdString = [NSString stringWithUTF8String:callId.c_str()];
[CallsAdapter.delegate muteVideoWithCall: callIdString mute: muted]; [CallsAdapter.delegate videoMutedWithCall: callIdString mute: muted];
} }
})); }));
...@@ -126,8 +126,7 @@ static id <CallsAdapterDelegate> _delegate; ...@@ -126,8 +126,7 @@ static id <CallsAdapterDelegate> _delegate;
bool muted) { bool muted) {
if (CallsAdapter.delegate) { if (CallsAdapter.delegate) {
NSString* callIdString = [NSString stringWithUTF8String:callId.c_str()]; NSString* callIdString = [NSString stringWithUTF8String:callId.c_str()];
[CallsAdapter.delegate muteAudioWithCall: callIdString mute: muted]; [CallsAdapter.delegate audioMutedWithCall: callIdString mute: muted];
} }
})); }));
...@@ -175,6 +174,10 @@ static id <CallsAdapterDelegate> _delegate; ...@@ -175,6 +174,10 @@ static id <CallsAdapterDelegate> _delegate;
return [Utils vectorToArray:calls]; 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);
}
#pragma mark AccountAdapterDelegate #pragma mark AccountAdapterDelegate
+ (id <CallsAdapterDelegate>)delegate { + (id <CallsAdapterDelegate>)delegate {
......
...@@ -167,7 +167,7 @@ ...@@ -167,7 +167,7 @@
<constraint firstAttribute="height" constant="50" id="RC6-BN-8ID"/> <constraint firstAttribute="height" constant="50" id="RC6-BN-8ID"/>
<constraint firstAttribute="width" constant="50" id="wXp-ed-p3H"/> <constraint firstAttribute="width" constant="50" id="wXp-ed-p3H"/>
</constraints> </constraints>
<state key="normal" image="mute_video"/> <state key="normal" image="video_running"/>
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
<constraint firstAttribute="width" constant="50" id="KAL-kW-Ak4"/> <constraint firstAttribute="width" constant="50" id="KAL-kW-Ak4"/>
<constraint firstAttribute="height" constant="50" id="guZ-o3-hkm"/> <constraint firstAttribute="height" constant="50" id="guZ-o3-hkm"/>
</constraints> </constraints>
<state key="normal" image="mute_audio"/> <state key="normal" image="audio_running"/>
<userDefinedRuntimeAttributes> <userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/> <userDefinedRuntimeAttribute type="boolean" keyPath="roundedCorners" value="YES"/>
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
...@@ -326,8 +326,8 @@ ...@@ -326,8 +326,8 @@
<outlet property="infoContainer" destination="3RN-4M-qR4" id="CUO-h6-mFf"/> <outlet property="infoContainer" destination="3RN-4M-qR4" id="CUO-h6-mFf"/>
<outlet property="infoLabelConstraint" destination="72y-vN-PbI" id="sGV-5n-H9t"/> <outlet property="infoLabelConstraint" destination="72y-vN-PbI" id="sGV-5n-H9t"/>
<outlet property="mainView" destination="QpJ-Sx-9dG" id="0y9-R4-q5W"/> <outlet property="mainView" destination="QpJ-Sx-9dG" id="0y9-R4-q5W"/>
<outlet property="muteAudioButton" destination="UHr-JD-OOn" id="nWm-1S-3Im"/> <outlet property="muteAudioButton" destination="Ezt-ru-2cK" id="0Cf-gc-w9s"/>
<outlet property="muteVideoButton" destination="Ezt-ru-2cK" id="NXD-9b-dCI"/> <outlet property="muteVideoButton" destination="UHr-JD-OOn" id="ciL-mV-cxA"/>
<outlet property="nameLabel" destination="73Y-N1-Yga" id="XcQ-V6-ZrF"/> <outlet property="nameLabel" destination="73Y-N1-Yga" id="XcQ-V6-ZrF"/>
<outlet property="pauseCallButton" destination="f4r-vz-8h0" id="rqE-oX-VxA"/> <outlet property="pauseCallButton" destination="f4r-vz-8h0" id="rqE-oX-VxA"/>
<outlet property="profileImageView" destination="fnt-PQ-Q6P" id="MgB-Ev-bTc"/> <outlet property="profileImageView" destination="fnt-PQ-Q6P" id="MgB-Ev-bTc"/>
...@@ -338,30 +338,13 @@ ...@@ -338,30 +338,13 @@
</objects> </objects>
<point key="canvasLocation" x="-74.400000000000006" y="131.78410794602701"/> <point key="canvasLocation" x="-74.400000000000006" y="131.78410794602701"/>
</scene> </scene>
<!--View Controller-->
<scene sceneID="zIN-Yk-WAp">
<objects>
<viewController id="n3h-fo-GaE" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="VPJ-zk-yXm"/>
<viewControllerLayoutGuide type="bottom" id="DbS-bx-Lwr"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="htX-h9-kf0">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="fSK-jF-f8o" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes> </scenes>
<resources> <resources>
<image name="audio_running" width="24" height="24"/>
<image name="ic_contact_picture" width="128" height="128"/> <image name="ic_contact_picture" width="128" height="128"/>
<image name="mute_audio" width="24" height="24"/>
<image name="mute_video" width="24" height="24"/>
<image name="pause_call" width="24" height="24"/> <image name="pause_call" width="24" height="24"/>
<image name="stop_call" width="24" height="24"/> <image name="stop_call" width="24" height="24"/>
<image name="switch_camera" width="24" height="24"/> <image name="switch_camera" width="24" height="24"/>
<image name="video_running" width="24" height="24"/>
</resources> </resources>
</document> </document>
...@@ -76,13 +76,33 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased { ...@@ -76,13 +76,33 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
} }
func setupBindings() { func setupBindings() {
//Cancel button action //bind actions
self.cancelButton.rx.tap self.cancelButton.rx.tap
.subscribe(onNext: { [weak self] in .subscribe(onNext: { [weak self] in
self?.removeFromScreen() self?.removeFromScreen()
self?.viewModel.cancelCall() self?.viewModel.cancelCall()
}).disposed(by: self.disposeBag) }).disposed(by: self.disposeBag)
self.muteAudioButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel.muteAudio()
}).disposed(by: self.disposeBag)
self.muteVideoButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel.muteVideo()
}).disposed(by: self.disposeBag)
self.pauseCallButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel.pauseCall()
}).disposed(by: self.disposeBag)
self.switchCameraButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.viewModel.switchCamera()
}).disposed(by: self.disposeBag)
//Data bindings //Data bindings
self.viewModel.contactImageData.asObservable() self.viewModel.contactImageData.asObservable()
.observeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
...@@ -125,7 +145,6 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased { ...@@ -125,7 +145,6 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
.subscribe(onNext: { [weak self] frame in .subscribe(onNext: { [weak self] frame in
if let image = frame { if let image = frame {
DispatchQueue.main.async { DispatchQueue.main.async {
self?.callView.isHidden = false
self?.incomingVideo.image = image self?.incomingVideo.image = image
} }
} }
...@@ -142,12 +161,37 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased { ...@@ -142,12 +161,37 @@ class CallViewController: UIViewController, StoryboardBased, ViewModelBased {
}).disposed(by: self.disposeBag) }).disposed(by: self.disposeBag)
self.viewModel.showCallOptions self.viewModel.showCallOptions
.subscribeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
.subscribe(onNext: { show in .subscribe(onNext: { show in
if show { if show {
self.showContactInfo() self.showContactInfo()
} }
}).disposed(by: self.disposeBag) }).disposed(by: self.disposeBag)
self.viewModel.videoButtonState
.observeOn(MainScheduler.instance)
.bind(to: self.muteVideoButton.rx.image())
.disposed(by: self.disposeBag)
self.viewModel.videoMuted
.observeOn(MainScheduler.instance)
.bind(to: self.capturedVideo.rx.isHidden)
.disposed(by: self.disposeBag)
self.viewModel.audioButtonState
.observeOn(MainScheduler.instance)
.bind(to: self.muteAudioButton.rx.image())
.disposed(by: self.disposeBag)
self.viewModel.callButtonState
.observeOn(MainScheduler.instance)
.bind(to: self.pauseCallButton.rx.image())
.disposed(by: self.disposeBag)
self.viewModel.callPaused
.observeOn(MainScheduler.instance)
.bind(to: self.callView.rx.isHidden)
.disposed(by: self.disposeBag)
} }
func removeFromScreen() { func removeFromScreen() {
......
...@@ -107,6 +107,8 @@ class CallViewModel: Stateable, ViewModel { ...@@ -107,6 +107,8 @@ class CallViewModel: Stateable, ViewModel {
}).asDriver(onErrorJustReturn: "") }).asDriver(onErrorJustReturn: "")
}() }()
//let timer: Observable<String>
lazy var callDuration: Driver<String> = { lazy var callDuration: Driver<String> = {
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance) let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.takeUntil(self.callService.currentCall .takeUntil(self.callService.currentCall
...@@ -116,9 +118,10 @@ class CallViewModel: Stateable, ViewModel { ...@@ -116,9 +118,10 @@ class CallViewModel: Stateable, ViewModel {
}) })
.map({ elapsed in .map({ elapsed in
return CallViewModel.formattedDurationFrom(interval: elapsed) return CallViewModel.formattedDurationFrom(interval: elapsed)
}) }).share()
return self.callService.currentCall.filter({ call in return self.callService.currentCall.filter({ [weak self] call in
return call.state == .current return call.state == .current &&
call.callId == self?.call?.callId
}).flatMap({ _ in }).flatMap({ _ in
return timer return timer
}).asDriver(onErrorJustReturn: "") }).asDriver(onErrorJustReturn: "")
...@@ -126,7 +129,9 @@ class CallViewModel: Stateable, ViewModel { ...@@ -126,7 +129,9 @@ class CallViewModel: Stateable, ViewModel {
lazy var bottomInfo: Observable<String> = { lazy var bottomInfo: Observable<String> = {
return callService.currentCall.map({ [weak self] call in return callService.currentCall.map({ [weak self] call in
if call.state == .connecting || call.state == .ringing && call.callType == .outgoing && call.callId == self?.call?.callId { if call.state == .connecting || call.state == .ringing &&
call.callType == .outgoing &&
call.callId == self?.call?.callId {
return L10n.Calls.calling return L10n.Calls.calling
} else if call.state == .over { } else if call.state == .over {
return L10n.Calls.callFinished return L10n.Calls.callFinished
...@@ -137,8 +142,9 @@ class CallViewModel: Stateable, ViewModel { ...@@ -137,8 +142,9 @@ class CallViewModel: Stateable, ViewModel {
}() }()
lazy var showCallOptions: Observable<Bool> = { lazy var showCallOptions: Observable<Bool> = {
return Observable.combineLatest(self.callIsActive, self.screenTapped.asObservable()) {(active, tapped) -> Bool in return Observable.combineLatest(self.callIsActive,
return active && tapped self.screenTapped.asObservable()) {(active, tapped) -> Bool in
return active && tapped
} }
}() }()
...@@ -152,6 +158,75 @@ class CallViewModel: Stateable, ViewModel { ...@@ -152,6 +158,75 @@ class CallViewModel: Stateable, ViewModel {
var screenTapped = BehaviorSubject(value: false) var screenTapped = BehaviorSubject(value: false)
lazy var videoButtonState: Observable<UIImage?> = {
let onImage = UIImage(asset: Asset.videoRunning)
let offImage = UIImage(asset: Asset.videoMuted)
return self.videoMuted.map({ muted in
if muted {
return offImage
}
return onImage
})
}()
lazy var videoMuted: Observable<Bool> = {
return self.callService.currentCall.filter({ call in
call.callId == self.call?.callId &&
call.state == .current
}).map({call in
return call.videoMuted
})
}()
lazy var audioButtonState: Observable<UIImage?> = {
let onImage = UIImage(asset: Asset.audioRunning)
let offImage = UIImage(asset: Asset.audioMuted)
return self.audioMuted.map({ muted in
if muted {
return offImage
}
return onImage
})
}()
lazy var audioMuted: Observable<Bool> = {
return self.callService.currentCall.filter({ call in
call.callId == self.call?.callId &&
call.state == .current
}).map({call in
return call.audioMuted
})
}()
lazy var callButtonState: Observable<UIImage?> = {
let unpauseCall = UIImage(asset: Asset.unpauseCall)
let pauseCall = UIImage(asset: Asset.pauseCall)
return self.callPaused.map({ muted in
if muted {
return unpauseCall
}
return pauseCall
})
}()
lazy var callPaused: Observable<Bool> = {
return self.callService.currentCall.filter({ call in
call.callId == self.call?.callId &&
(call.state == .hold ||
call.state == .unhold ||
call.state == .current)
}).map({call in
if call.state == .hold ||
(call.state == .current && call.peerHolding) {
return true
}
return false
})
}()
required init(with injectionBag: InjectionBag) { required init(with injectionBag: InjectionBag) {
self.callService = injectionBag.callService self.callService = injectionBag.callService
self.contactsService = injectionBag.contactsService self.contactsService = injectionBag.contactsService
...@@ -206,8 +281,9 @@ class CallViewModel: Stateable, ViewModel { ...@@ -206,8 +281,9 @@ class CallViewModel: Stateable, ViewModel {
guard let photo = profile.photo else { guard let photo = profile.photo else {
return return
} }
guard let data = NSData(base64Encoded: photo, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as Data? else { guard let data = NSData(base64Encoded: photo,
return options: NSData.Base64DecodingOptions.ignoreUnknownCharacters) as Data? else {
return
} }
self.contactImageData.value = data self.contactImageData.value = data
} }
...@@ -215,4 +291,47 @@ class CallViewModel: Stateable, ViewModel { ...@@ -215,4 +291,47 @@ class CallViewModel: Stateable, ViewModel {
func respondOnTap() { func respondOnTap() {
self.screenTapped.onNext(true) self.screenTapped.onNext(true)
} }
// MARK: call options
func pauseCall() {
guard let call = self.call else {
return
}
if call.state == .current {
self.callService.hold(callId: call.callId)
.subscribe(onCompleted: { [weak self] in
self?.log.info("call paused")
}, onError: { [weak self](error) in
self?.log.info(error)
}).disposed(by: self.disposeBag)
} else if call.state == .hold {
self.callService.unhold(callId: call.callId)
.subscribe(onCompleted: { [weak self] in
self?.log.info("call unpaused")
}, onError: { [weak self](error) in
self?.log.info(error)
}).disposed(by: self.disposeBag)
}
}
func muteAudio() {
guard let call = self.call else {
return
}
let mute = !call.audioMuted
self.callService.muteAudio(call: call.callId, mute: mute)
}
func muteVideo() {
guard let call = self.call else {
return
}
let mute = !call.videoMuted
self.callService.muteVideo(call: call.callId, mute: mute)
}
func switchCamera() {
self.videoService.switchCamera()
}
} }
...@@ -48,6 +48,8 @@ struct ColorAsset { ...@@ -48,6 +48,8 @@ struct ColorAsset {
enum Asset { enum Asset {
static let accountIcon = ImageAsset(name: "account_icon") static let accountIcon = ImageAsset(name: "account_icon")
static let addPerson = ImageAsset(name: "add_person") static let addPerson = ImageAsset(name: "add_person")
static let audioMuted = ImageAsset(name: "audio_muted")
static let audioRunning = ImageAsset(name: "audio_running")
static let backgroundRing = ImageAsset(name: "background_ring") static let backgroundRing = ImageAsset(name: "background_ring")
static let blockIcon = ImageAsset(name: "block_icon") static let blockIcon = ImageAsset(name: "block_icon")
static let callButton = ImageAsset(name: "call_button") static let callButton = ImageAsset(name: "call_button")
...@@ -57,13 +59,14 @@ enum Asset { ...@@ -57,13 +59,14 @@ enum Asset {
static let fallbackAvatar = ImageAsset(name: "fallback_avatar") static let fallbackAvatar = ImageAsset(name: "fallback_avatar")
static let icContactPicture = ImageAsset(name: "ic_contact_picture") static let icContactPicture = ImageAsset(name: "ic_contact_picture")
static let moreSettings = ImageAsset(name: "more_settings") static let moreSettings = ImageAsset(name: "more_settings")
static let muteAudio = ImageAsset(name: "mute_audio")
static let muteVideo = ImageAsset(name: "mute_video")
static let pauseCall = ImageAsset(name: "pause_call") static let pauseCall = ImageAsset(name: "pause_call")
static let ringLogo = ImageAsset(name: "ring_logo") static let ringLogo = ImageAsset(name: "ring_logo")
static let settingsIcon = ImageAsset(name: "settings_icon") static let settingsIcon = ImageAsset(name: "settings_icon")
static let stopCall = ImageAsset(name: "stop_call") static let stopCall = ImageAsset(name: "stop_call")
static let switchCamera = ImageAsset(name: "switch_camera") static let switchCamera = ImageAsset(name: "switch_camera")
static let unpauseCall = ImageAsset(name: "unpause_call")
static let videoMuted = ImageAsset(name: "video_muted")
static let videoRunning = ImageAsset(name: "video_running")
// swiftlint:disable trailing_comma // swiftlint:disable trailing_comma
static let allColors: [ColorAsset] = [ static let allColors: [ColorAsset] = [
...@@ -71,6 +74,8 @@ enum Asset { ...@@ -71,6 +74,8 @@ enum Asset {
static let allImages: [ImageAsset] = [ static let allImages: [ImageAsset] = [
accountIcon, accountIcon,
addPerson, addPerson,
audioMuted,
audioRunning,
backgroundRing, backgroundRing,
blockIcon, blockIcon,
callButton, callButton,
...@@ -80,13 +85,14 @@ enum Asset { ...@@ -80,13 +85,14 @@ enum Asset {
fallbackAvatar, fallbackAvatar,
icContactPicture, icContactPicture,
moreSettings, moreSettings,
muteAudio,
muteVideo,
pauseCall, pauseCall,
ringLogo, ringLogo,
settingsIcon, settingsIcon,
stopCall, stopCall,
switchCamera, switchCamera,
unpauseCall,
videoMuted,
videoRunning,
] ]
// swiftlint:enable trailing_comma // swiftlint:enable trailing_comma
@available(*, deprecated, renamed: "allImages") @available(*, deprecated, renamed: "allImages")
......
...@@ -63,6 +63,7 @@ class CallModel { ...@@ -63,6 +63,7 @@ class CallModel {
var accountId: String = "" var accountId: String = ""
var audioMuted: Bool = false var audioMuted: Bool = false
var videoMuted: Bool = false var videoMuted: Bool = false
var peerHolding: Bool = false
var stateValue = CallState.unknown.rawValue var stateValue = CallState.unknown.rawValue
var callTypeValue = CallType.missed.rawValue var callTypeValue = CallType.missed.rawValue
...@@ -140,5 +141,9 @@ class CallModel { ...@@ -140,5 +141,9 @@ class CallModel {
if let accountId = dictionary[CallDetailKey.accountIdKey.rawValue] { if let accountId = dictionary[CallDetailKey.accountIdKey.rawValue] {
self.accountId = accountId self.accountId = accountId
} }
if let peerHolding = dictionary[CallDetailKey.peerHoldingKey.rawValue]?.toBool() {
self.peerHolding = peerHolding
}
} }
} }
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "ic_volume_mute_white.png", "filename" : "ic_mic_off_white.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "ic_volume_mute_white_2x.png", "filename" : "ic_mic_off_white_2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "ic_volume_mute_white_3x.png", "filename" : "ic_mic_off_white_3x.png",
"scale" : "3x" "scale" : "3x"
} }
], ],
......
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_mic_white.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_mic_white_2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_mic_white_3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
"images" : [ "images" : [
{ {
"idiom" : "universal", "idiom" : "universal",
"filename" : "ic_replay_white.png", "filename" : "rotate_camera.png",
"scale" : "1x" "scale" : "1x"