2017-08-07 22:11:39 +03:00
|
|
|
//
|
|
|
|
// CallViewController.m
|
|
|
|
// VideoCalls
|
|
|
|
//
|
|
|
|
// Created by Ivan Sein on 31.07.17.
|
|
|
|
// Copyright © 2017 struktur AG. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "CallViewController.h"
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
#import <WebRTC/RTCCameraVideoCapturer.h>
|
|
|
|
#import <WebRTC/RTCMediaStream.h>
|
|
|
|
#import <WebRTC/RTCEAGLVideoView.h>
|
|
|
|
#import <WebRTC/RTCVideoTrack.h>
|
2017-08-07 22:11:39 +03:00
|
|
|
#import "ARDCaptureController.h"
|
2017-10-12 15:37:36 +03:00
|
|
|
#import "CallParticipantViewCell.h"
|
|
|
|
#import "NBMPeersFlowLayout.h"
|
|
|
|
#import "NCCallController.h"
|
2017-12-15 21:37:50 +03:00
|
|
|
#import "NCAPIController.h"
|
2017-12-20 19:22:04 +03:00
|
|
|
#import "NCSettingsController.h"
|
2017-12-15 21:37:50 +03:00
|
|
|
#import "UIImageView+AFNetworking.h"
|
2017-10-12 15:37:36 +03:00
|
|
|
|
|
|
|
typedef NS_ENUM(NSInteger, CallState) {
|
|
|
|
CallStateJoining,
|
|
|
|
CallStateWaitingParticipants,
|
|
|
|
CallStateInCall
|
|
|
|
};
|
|
|
|
|
|
|
|
@interface CallViewController () <NCCallControllerDelegate, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, RTCEAGLVideoViewDelegate>
|
|
|
|
{
|
|
|
|
CallState _callState;
|
|
|
|
NSMutableArray *_peersInCall;
|
|
|
|
NSMutableDictionary *_renderersDict;
|
|
|
|
NCCallController *_callController;
|
2017-08-07 22:11:39 +03:00
|
|
|
ARDCaptureController *_captureController;
|
2018-04-12 12:22:35 +03:00
|
|
|
UITapGestureRecognizer *_tapGestureForDetailedView;
|
2018-02-07 15:20:34 +03:00
|
|
|
NSTimer *_detailedViewTimer;
|
2018-03-20 13:46:50 +03:00
|
|
|
BOOL _isAudioOnly;
|
2018-02-01 12:47:24 +03:00
|
|
|
BOOL _userDisabledVideo;
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
|
2018-01-30 21:02:55 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIView *buttonsContainerView;
|
2018-01-31 12:29:14 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIButton *audioMuteButton;
|
2018-03-20 21:01:40 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIButton *speakerButton;
|
2018-01-31 12:29:14 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIButton *videoDisableButton;
|
2018-01-31 20:22:19 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIButton *switchCameraButton;
|
2018-01-31 12:29:14 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UIButton *hangUpButton;
|
2017-10-12 15:37:36 +03:00
|
|
|
@property (nonatomic, strong) IBOutlet UICollectionView *collectionView;
|
|
|
|
@property (nonatomic, strong) IBOutlet UICollectionViewFlowLayout *flowLayout;
|
|
|
|
|
2017-08-07 22:11:39 +03:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation CallViewController
|
|
|
|
|
2017-08-28 12:55:06 +03:00
|
|
|
@synthesize delegate = _delegate;
|
|
|
|
|
2018-05-15 17:00:05 +03:00
|
|
|
- (instancetype)initCallInRoom:(NCRoom *)room asUser:(NSString*)displayName audioOnly:(BOOL)audioOnly withSessionId:(NSString *)sessionId
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (!self) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2018-05-15 17:00:05 +03:00
|
|
|
_callController = [[NCCallController alloc] initWithDelegate:self inRoom:room forAudioOnlyCall:audioOnly withSessionId:sessionId];
|
2017-10-12 15:37:36 +03:00
|
|
|
_callController.userDisplayName = displayName;
|
2017-12-15 19:42:37 +03:00
|
|
|
_room = room;
|
2018-03-20 13:46:50 +03:00
|
|
|
_isAudioOnly = audioOnly;
|
2017-10-12 15:37:36 +03:00
|
|
|
_peersInCall = [[NSMutableArray alloc] init];
|
|
|
|
_renderersDict = [[NSMutableDictionary alloc] init];
|
2017-08-07 22:11:39 +03:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)viewDidLoad {
|
2017-08-07 22:11:39 +03:00
|
|
|
[super viewDidLoad];
|
2017-10-12 15:37:36 +03:00
|
|
|
[self setCallState:CallStateJoining];
|
|
|
|
[_callController startCall];
|
2017-09-19 12:38:41 +03:00
|
|
|
|
2018-02-01 12:34:51 +03:00
|
|
|
[[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
|
2018-02-02 14:29:17 +03:00
|
|
|
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
2018-02-01 12:34:51 +03:00
|
|
|
|
2018-04-12 12:22:35 +03:00
|
|
|
_tapGestureForDetailedView = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showDetailedViewWithTimer)];
|
|
|
|
[_tapGestureForDetailedView setNumberOfTapsRequired:1];
|
2018-01-30 22:03:59 +03:00
|
|
|
|
2018-03-28 10:54:25 +03:00
|
|
|
[self.audioMuteButton.layer setCornerRadius:24.0f];
|
|
|
|
[self.speakerButton.layer setCornerRadius:24.0f];
|
|
|
|
[self.videoDisableButton.layer setCornerRadius:24.0f];
|
|
|
|
[self.hangUpButton.layer setCornerRadius:24.0f];
|
2018-01-31 12:29:14 +03:00
|
|
|
|
2018-03-20 21:01:40 +03:00
|
|
|
[self adjustButtonsConainer];
|
2018-01-30 22:03:59 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
self.collectionView.delegate = self;
|
2017-12-15 19:42:37 +03:00
|
|
|
|
|
|
|
self.waitingImageView.layer.cornerRadius = 64;
|
|
|
|
self.waitingImageView.layer.masksToBounds = YES;
|
|
|
|
|
2018-03-20 13:46:50 +03:00
|
|
|
if ([[[NCSettingsController sharedInstance] videoSettingsModel] videoDisabledSettingFromStore] || _isAudioOnly) {
|
2018-03-16 21:27:42 +03:00
|
|
|
_userDisabledVideo = YES;
|
|
|
|
[self disableLocalVideo];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
[self.collectionView registerNib:[UINib nibWithNibName:kCallParticipantCellNibName bundle:nil] forCellWithReuseIdentifier:kCallParticipantCellIdentifier];
|
2017-08-08 14:53:32 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
if (@available(iOS 11.0, *)) {
|
|
|
|
[self.collectionView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
|
|
|
|
}
|
2018-02-01 12:34:51 +03:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sensorStateChange:)
|
|
|
|
name:@"UIDeviceProximityStateDidChangeNotification" object:nil];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2018-04-11 19:38:49 +03:00
|
|
|
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
|
|
|
|
{
|
|
|
|
[self setLocalVideoRect];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
|
|
{
|
|
|
|
[self setLocalVideoRect];
|
|
|
|
}
|
|
|
|
|
2018-02-01 17:33:53 +03:00
|
|
|
- (void)viewWillDisappear:(BOOL)animated
|
|
|
|
{
|
|
|
|
[super viewWillDisappear:animated];
|
|
|
|
[[UIDevice currentDevice] setProximityMonitoringEnabled:NO];
|
2018-02-02 14:29:17 +03:00
|
|
|
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
2018-02-01 17:33:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)didReceiveMemoryWarning {
|
2017-08-07 22:11:39 +03:00
|
|
|
[super didReceiveMemoryWarning];
|
|
|
|
// Dispose of any resources that can be recreated.
|
|
|
|
}
|
|
|
|
|
2018-04-11 19:38:49 +03:00
|
|
|
#pragma mark - Local video
|
|
|
|
|
|
|
|
- (void)setLocalVideoRect
|
|
|
|
{
|
|
|
|
CGSize localVideoSize = CGSizeMake(0, 0);
|
|
|
|
|
|
|
|
CGFloat width = [UIScreen mainScreen].bounds.size.width / 5;
|
|
|
|
CGFloat height = [UIScreen mainScreen].bounds.size.height / 5;
|
|
|
|
|
|
|
|
NSString *videoResolution = [[[NCSettingsController sharedInstance] videoSettingsModel] currentVideoResolutionSettingFromStore];
|
|
|
|
NSString *localVideoRes = [[[NCSettingsController sharedInstance] videoSettingsModel] readableResolution:videoResolution];
|
|
|
|
|
|
|
|
if ([localVideoRes isEqualToString:@"Low"] || [localVideoRes isEqualToString:@"Normal"]) {
|
|
|
|
if (width < height) {
|
|
|
|
localVideoSize = CGSizeMake(height * 3/4, height);
|
|
|
|
} else {
|
2018-04-13 12:09:28 +03:00
|
|
|
localVideoSize = CGSizeMake(width, width * 3/4);
|
2018-04-11 19:38:49 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (width < height) {
|
2018-04-13 12:09:28 +03:00
|
|
|
localVideoSize = CGSizeMake(height * 9/16, height);
|
2018-04-11 19:38:49 +03:00
|
|
|
} else {
|
2018-04-13 12:09:28 +03:00
|
|
|
localVideoSize = CGSizeMake(width, width * 9/16);
|
2018-04-11 19:38:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CGRect localVideoRect = CGRectMake(16, 62, localVideoSize.width, localVideoSize.height);
|
|
|
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
_localVideoView.frame = localVideoRect;
|
|
|
|
_localVideoView.layer.cornerRadius = 4.0f;
|
|
|
|
_localVideoView.layer.masksToBounds = YES;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-01 12:34:51 +03:00
|
|
|
#pragma mark - Proximity sensor
|
|
|
|
|
|
|
|
- (void)sensorStateChange:(NSNotificationCenter *)notification
|
|
|
|
{
|
2018-03-20 21:01:40 +03:00
|
|
|
if (!_isAudioOnly) {
|
|
|
|
if ([[UIDevice currentDevice] proximityState] == YES) {
|
|
|
|
[self disableLocalVideo];
|
|
|
|
[_callController setAudioSessionToVoiceChatMode];
|
|
|
|
} else {
|
|
|
|
// Only enable video if it was not disabled by the user.
|
|
|
|
if (!_userDisabledVideo) {
|
|
|
|
[self enableLocalVideo];
|
|
|
|
}
|
|
|
|
[_callController setAudioSessionToVideoChatMode];
|
2018-02-01 12:47:24 +03:00
|
|
|
}
|
2018-02-01 12:34:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-15 19:42:37 +03:00
|
|
|
#pragma mark - User Interface
|
2017-08-07 22:11:39 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)setCallState:(CallState)state
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2018-04-12 13:00:43 +03:00
|
|
|
_callState = state;
|
2017-10-12 15:37:36 +03:00
|
|
|
switch (state) {
|
|
|
|
case CallStateJoining:
|
|
|
|
case CallStateWaitingParticipants:
|
2018-04-12 12:22:35 +03:00
|
|
|
{
|
|
|
|
[self showWaitingScreen];
|
|
|
|
[self showDetailedView];
|
|
|
|
[self removeTapGestureForDetailedView];
|
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CallStateInCall:
|
2018-04-12 12:22:35 +03:00
|
|
|
{
|
|
|
|
[self hideWaitingScreen];
|
|
|
|
if (!_isAudioOnly) {
|
|
|
|
[self addTapGestureForDetailedView];
|
|
|
|
[self showDetailedViewWithTimer];
|
|
|
|
}
|
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2017-08-08 14:56:06 +03:00
|
|
|
}
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2018-04-12 13:00:43 +03:00
|
|
|
- (void)setCallStateForPeersInCall
|
|
|
|
{
|
|
|
|
if ([_peersInCall count] > 0) {
|
|
|
|
if (_callState != CallStateInCall) {
|
|
|
|
[self setCallState:CallStateInCall];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (_callState == CallStateInCall) {
|
|
|
|
[self setCallState:CallStateWaitingParticipants];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 12:22:35 +03:00
|
|
|
- (void)showWaitingScreen
|
2017-12-15 19:42:37 +03:00
|
|
|
{
|
|
|
|
if (_room.type == kNCRoomTypeOneToOneCall) {
|
2017-12-15 21:37:50 +03:00
|
|
|
self.waitingLabel.text = [NSString stringWithFormat:@"Waiting for %@ to join call…", _room.displayName];
|
2017-12-19 00:10:32 +03:00
|
|
|
[self.waitingImageView setImageWithURLRequest:[[NCAPIController sharedInstance] createAvatarRequestForUser:_room.name andSize:256]
|
2017-12-15 21:37:50 +03:00
|
|
|
placeholderImage:nil success:nil failure:nil];
|
2017-12-15 19:42:37 +03:00
|
|
|
} else {
|
2017-12-15 21:37:50 +03:00
|
|
|
self.waitingLabel.text = @"Waiting for others to join call…";
|
2017-12-15 19:42:37 +03:00
|
|
|
if (_room.type == kNCRoomTypeGroupCall) {
|
2018-04-13 18:00:15 +03:00
|
|
|
[self.waitingImageView setImage:[UIImage imageNamed:@"group-bg-128"]];
|
2017-12-15 19:42:37 +03:00
|
|
|
} else {
|
2018-04-13 18:00:15 +03:00
|
|
|
[self.waitingImageView setImage:[UIImage imageNamed:@"public-bg-128"]];
|
2017-12-15 19:42:37 +03:00
|
|
|
}
|
|
|
|
}
|
2018-01-31 12:51:11 +03:00
|
|
|
|
2018-04-12 12:22:35 +03:00
|
|
|
self.collectionView.backgroundView = self.waitingView;
|
2018-01-31 12:51:11 +03:00
|
|
|
}
|
|
|
|
|
2018-04-12 12:22:35 +03:00
|
|
|
- (void)hideWaitingScreen
|
2018-01-31 12:51:11 +03:00
|
|
|
{
|
2018-04-12 12:22:35 +03:00
|
|
|
self.collectionView.backgroundView = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)addTapGestureForDetailedView
|
|
|
|
{
|
|
|
|
[self.view addGestureRecognizer:_tapGestureForDetailedView];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)removeTapGestureForDetailedView
|
|
|
|
{
|
|
|
|
[self.view removeGestureRecognizer:_tapGestureForDetailedView];
|
2017-12-15 19:42:37 +03:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:20:34 +03:00
|
|
|
- (void)showDetailedView
|
|
|
|
{
|
|
|
|
[self showButtonsContainer];
|
|
|
|
[self showPeersInfo];
|
2018-04-12 12:22:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showDetailedViewWithTimer
|
|
|
|
{
|
|
|
|
[self showDetailedView];
|
2018-02-07 15:20:34 +03:00
|
|
|
[self setDetailedViewTimer];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)hideDetailedView
|
|
|
|
{
|
|
|
|
[self hideButtonsContainer];
|
|
|
|
[self hidePeersInfo];
|
|
|
|
[self invalidateDetailedViewTimer];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)showButtonsContainer
|
|
|
|
{
|
2018-01-30 22:03:59 +03:00
|
|
|
[UIView animateWithDuration:0.3f animations:^{
|
2018-02-07 15:20:34 +03:00
|
|
|
[self.buttonsContainerView setAlpha:1.0f];
|
2018-03-27 19:23:49 +03:00
|
|
|
[self.switchCameraButton setAlpha:1.0f];
|
2018-02-07 15:20:34 +03:00
|
|
|
[self.view layoutIfNeeded];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2018-03-20 21:01:40 +03:00
|
|
|
- (void)hideButtonsContainer
|
|
|
|
{
|
2018-02-07 15:20:34 +03:00
|
|
|
[UIView animateWithDuration:0.3f animations:^{
|
|
|
|
[self.buttonsContainerView setAlpha:0.0f];
|
2018-03-27 19:23:49 +03:00
|
|
|
[self.switchCameraButton setAlpha:0.0f];
|
2018-01-30 22:03:59 +03:00
|
|
|
[self.view layoutIfNeeded];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2018-03-20 21:01:40 +03:00
|
|
|
- (void)adjustButtonsConainer
|
|
|
|
{
|
|
|
|
if (_isAudioOnly) {
|
|
|
|
_videoDisableButton.hidden = YES;
|
|
|
|
_switchCameraButton.hidden = YES;
|
|
|
|
} else {
|
|
|
|
_speakerButton.hidden = YES;
|
|
|
|
}
|
2018-04-16 12:49:37 +03:00
|
|
|
|
|
|
|
// Enable speaker button for iPhones only
|
|
|
|
if(![[UIDevice currentDevice].model isEqualToString:@"iPhone"]) {
|
|
|
|
_speakerButton.enabled = NO;
|
|
|
|
}
|
2018-03-20 21:01:40 +03:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:20:34 +03:00
|
|
|
- (void)setDetailedViewTimer
|
2018-01-30 22:12:07 +03:00
|
|
|
{
|
2018-02-07 15:20:34 +03:00
|
|
|
[self invalidateDetailedViewTimer];
|
|
|
|
_detailedViewTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(hideDetailedView) userInfo:nil repeats:NO];
|
2018-01-30 22:12:07 +03:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:20:34 +03:00
|
|
|
- (void)invalidateDetailedViewTimer
|
2018-01-30 22:12:07 +03:00
|
|
|
{
|
2018-02-07 15:20:34 +03:00
|
|
|
[_detailedViewTimer invalidate];
|
|
|
|
_detailedViewTimer = nil;
|
2018-01-30 22:12:07 +03:00
|
|
|
}
|
|
|
|
|
2017-08-28 12:55:06 +03:00
|
|
|
#pragma mark - Call actions
|
|
|
|
|
2017-09-19 12:38:41 +03:00
|
|
|
- (IBAction)audioButtonPressed:(id)sender
|
|
|
|
{
|
|
|
|
UIButton *audioButton = sender;
|
2017-10-12 15:37:36 +03:00
|
|
|
if ([_callController isAudioEnabled]) {
|
|
|
|
[_callController enableAudio:NO];
|
2017-09-19 12:38:41 +03:00
|
|
|
[audioButton setImage:[UIImage imageNamed:@"audio-off"] forState:UIControlStateNormal];
|
2017-10-12 15:37:36 +03:00
|
|
|
} else {
|
|
|
|
[_callController enableAudio:YES];
|
|
|
|
[audioButton setImage:[UIImage imageNamed:@"audio"] forState:UIControlStateNormal];
|
2017-09-19 12:38:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)videoButtonPressed:(id)sender
|
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
if ([_callController isVideoEnabled]) {
|
2018-02-01 12:34:51 +03:00
|
|
|
[self disableLocalVideo];
|
2018-02-01 12:47:24 +03:00
|
|
|
_userDisabledVideo = YES;
|
2017-10-12 15:37:36 +03:00
|
|
|
} else {
|
2018-02-01 12:34:51 +03:00
|
|
|
[self enableLocalVideo];
|
2018-02-01 12:47:24 +03:00
|
|
|
_userDisabledVideo = NO;
|
2017-09-19 12:38:41 +03:00
|
|
|
}
|
|
|
|
}
|
2018-02-01 12:34:51 +03:00
|
|
|
|
|
|
|
- (void)disableLocalVideo
|
|
|
|
{
|
|
|
|
[_callController enableVideo:NO];
|
|
|
|
[_captureController stopCapture];
|
2018-03-27 19:23:49 +03:00
|
|
|
[_localVideoView setHidden:YES];
|
2018-03-16 21:27:42 +03:00
|
|
|
[_videoDisableButton setImage:[UIImage imageNamed:@"video-off"] forState:UIControlStateNormal];
|
2018-02-01 12:34:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)enableLocalVideo
|
|
|
|
{
|
|
|
|
[_callController enableVideo:YES];
|
|
|
|
[_captureController startCapture];
|
2018-03-27 19:23:49 +03:00
|
|
|
[_localVideoView setHidden:NO];
|
2018-03-16 21:27:42 +03:00
|
|
|
[_videoDisableButton setImage:[UIImage imageNamed:@"video"] forState:UIControlStateNormal];
|
2018-02-01 12:34:51 +03:00
|
|
|
}
|
|
|
|
|
2018-01-31 20:22:19 +03:00
|
|
|
- (IBAction)switchCameraButtonPressed:(id)sender
|
|
|
|
{
|
|
|
|
[self switchCamera];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)switchCamera
|
|
|
|
{
|
|
|
|
[_captureController switchCamera];
|
2018-01-31 20:37:32 +03:00
|
|
|
[self flipLocalVideoView];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)flipLocalVideoView
|
|
|
|
{
|
|
|
|
CATransition *animation = [CATransition animation];
|
|
|
|
animation.duration = .5f;
|
|
|
|
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
|
|
|
animation.type = @"oglFlip";
|
|
|
|
animation.subtype = kCATransitionFromRight;
|
|
|
|
|
|
|
|
[self.localVideoView.layer addAnimation:animation forKey:nil];
|
2018-01-31 20:22:19 +03:00
|
|
|
}
|
2017-09-19 12:38:41 +03:00
|
|
|
|
2018-03-20 21:01:40 +03:00
|
|
|
- (IBAction)speakerButtonPressed:(id)sender
|
|
|
|
{
|
|
|
|
if ([_callController isSpeakerActive]) {
|
|
|
|
[self disableSpeaker];
|
|
|
|
} else {
|
|
|
|
[self enableSpeaker];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)disableSpeaker
|
|
|
|
{
|
|
|
|
[_callController setAudioSessionToVoiceChatMode];
|
|
|
|
[_speakerButton setImage:[UIImage imageNamed:@"speaker-off"] forState:UIControlStateNormal];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)enableSpeaker
|
|
|
|
{
|
|
|
|
[_callController setAudioSessionToVideoChatMode];
|
|
|
|
[_speakerButton setImage:[UIImage imageNamed:@"speaker"] forState:UIControlStateNormal];
|
|
|
|
}
|
|
|
|
|
2018-01-31 20:22:19 +03:00
|
|
|
- (IBAction)hangupButtonPressed:(id)sender
|
|
|
|
{
|
2017-08-28 15:15:45 +03:00
|
|
|
[self hangup];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)hangup
|
|
|
|
{
|
2018-03-07 21:19:31 +03:00
|
|
|
[self dismissCallView];
|
2018-01-31 13:08:31 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
[_localVideoView.captureSession stopRunning];
|
|
|
|
_localVideoView.captureSession = nil;
|
2018-03-27 19:35:15 +03:00
|
|
|
[_localVideoView setHidden:YES];
|
2017-08-28 12:55:06 +03:00
|
|
|
[_captureController stopCapture];
|
|
|
|
_captureController = nil;
|
2017-08-28 13:09:12 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
for (NCPeerConnection *peerConnection in _peersInCall) {
|
|
|
|
RTCEAGLVideoView *renderer = [_renderersDict objectForKey:peerConnection.peerId];
|
|
|
|
[[peerConnection.remoteStream.videoTracks firstObject] removeRenderer:renderer];
|
|
|
|
[_renderersDict removeObjectForKey:peerConnection.peerId];
|
|
|
|
}
|
2017-08-28 13:09:12 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
[_callController leaveCall];
|
2017-08-28 12:55:06 +03:00
|
|
|
}
|
|
|
|
|
2018-03-07 21:19:31 +03:00
|
|
|
- (void)dismissCallView
|
|
|
|
{
|
|
|
|
[self.delegate callViewControllerWantsToBeDismissed:self];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)finishCall
|
2017-09-19 12:38:41 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
_callController = nil;
|
2018-03-01 14:04:43 +03:00
|
|
|
[self.delegate callViewControllerDidFinish:self];
|
2017-09-19 12:38:41 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
#pragma mark - UICollectionView Datasource
|
2017-08-07 22:11:39 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2018-04-12 13:00:43 +03:00
|
|
|
[self setCallStateForPeersInCall];
|
2017-10-12 15:37:36 +03:00
|
|
|
return [_peersInCall count];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
|
|
|
{
|
|
|
|
CallParticipantViewCell *cell = (CallParticipantViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:kCallParticipantCellIdentifier forIndexPath:indexPath];
|
|
|
|
NCPeerConnection *peerConnection = [_peersInCall objectAtIndex:indexPath.row];
|
2017-08-24 20:36:26 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
[cell setVideoView:[_renderersDict objectForKey:peerConnection.peerId]];
|
2017-12-18 23:58:56 +03:00
|
|
|
[cell setUserAvatar:[_callController getUserIdFromSessionId:peerConnection.peerId]];
|
2017-10-15 13:28:33 +03:00
|
|
|
[cell setDisplayName:peerConnection.peerName];
|
|
|
|
[cell setAudioDisabled:peerConnection.isRemoteAudioDisabled];
|
2018-03-20 13:46:50 +03:00
|
|
|
[cell setVideoDisabled: (_isAudioOnly) ? YES : peerConnection.isRemoteVideoDisabled];
|
2017-08-24 20:36:26 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
return cell;
|
2017-08-24 20:36:26 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
CGRect frame = [NBMPeersFlowLayout frameForWithNumberOfItems:_peersInCall.count
|
|
|
|
row:indexPath.row
|
|
|
|
contentSize:self.collectionView.frame.size];
|
|
|
|
return frame.size;
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
[self.collectionView reloadData];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
#pragma mark - Call Controller delegate
|
|
|
|
|
|
|
|
- (void)callControllerDidJoinCall:(NCCallController *)callController
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
[self setCallState:CallStateWaitingParticipants];
|
2017-08-07 22:11:39 +03:00
|
|
|
|
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callControllerDidEndCall:(NCCallController *)callController
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
[self finishCall];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController peerJoined:(NCPeerConnection *)peer
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
// Start adding cell for that peer and wait until add
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:47:16 +03:00
|
|
|
- (void)callController:(NCCallController *)callController peerLeft:(NCPeerConnection *)peer
|
|
|
|
{
|
|
|
|
RTCEAGLVideoView *renderer = [_renderersDict objectForKey:peer.peerId];
|
|
|
|
[[peer.remoteStream.videoTracks firstObject] removeRenderer:renderer];
|
|
|
|
[_renderersDict removeObjectForKey:peer.peerId];
|
|
|
|
[_peersInCall removeObject:peer];
|
|
|
|
[self.collectionView reloadData];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didCreateLocalVideoCapturer:(RTCCameraVideoCapturer *)videoCapturer
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
_localVideoView.captureSession = videoCapturer.captureSession;
|
2018-03-15 17:39:37 +03:00
|
|
|
_captureController = [[ARDCaptureController alloc] initWithCapturer:videoCapturer settings:[[NCSettingsController sharedInstance] videoSettingsModel]];
|
2017-10-12 15:37:36 +03:00
|
|
|
[_captureController startCapture];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didAddLocalStream:(RTCMediaStream *)localStream
|
2017-08-24 16:38:10 +03:00
|
|
|
{
|
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didRemoveLocalStream:(RTCMediaStream *)localStream
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didAddStream:(RTCMediaStream *)remoteStream ofPeer:(NCPeerConnection *)remotePeer
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
RTCEAGLVideoView *renderView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero];
|
|
|
|
renderView.delegate = self;
|
|
|
|
RTCVideoTrack *remoteVideoTrack = [remotePeer.remoteStream.videoTracks firstObject];
|
|
|
|
[remoteVideoTrack addRenderer:renderView];
|
|
|
|
[_renderersDict setObject:renderView forKey:remotePeer.peerId];
|
|
|
|
[_peersInCall addObject:remotePeer];
|
|
|
|
[self.collectionView reloadData];
|
|
|
|
}
|
|
|
|
- (void)callController:(NCCallController *)callController didRemoveStream:(RTCMediaStream *)remoteStream ofPeer:(NCPeerConnection *)remotePeer
|
|
|
|
{
|
2017-10-15 22:47:16 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
}
|
|
|
|
- (void)callController:(NCCallController *)callController iceStatusChanged:(RTCIceConnectionState)state ofPeer:(NCPeerConnection *)peer
|
|
|
|
{
|
2018-01-30 17:02:15 +03:00
|
|
|
if (state == RTCIceConnectionStateClosed) {
|
2017-10-12 15:37:36 +03:00
|
|
|
[_peersInCall removeObject:peer];
|
|
|
|
[self.collectionView reloadData];
|
2017-08-24 15:00:50 +03:00
|
|
|
}
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didAddDataChannel:(RTCDataChannel *)dataChannel
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-10-15 13:28:33 +03:00
|
|
|
- (void)callController:(NCCallController *)callController didReceiveDataChannelMessage:(NSString *)message fromPeer:(NCPeerConnection *)peer
|
|
|
|
{
|
|
|
|
if ([message isEqualToString:@"audioOn"] || [message isEqualToString:@"audioOff"]) {
|
|
|
|
[self updatePeer:peer block:^(CallParticipantViewCell *cell) {
|
|
|
|
[cell setAudioDisabled:peer.isRemoteAudioDisabled];
|
|
|
|
}];
|
2017-12-18 23:58:56 +03:00
|
|
|
} else if ([message isEqualToString:@"videoOn"] || [message isEqualToString:@"videoOff"]) {
|
2018-03-20 13:46:50 +03:00
|
|
|
if (!_isAudioOnly) {
|
|
|
|
[self updatePeer:peer block:^(CallParticipantViewCell *cell) {
|
|
|
|
[cell setVideoDisabled:peer.isRemoteVideoDisabled];
|
|
|
|
}];
|
|
|
|
}
|
2017-10-15 13:28:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
- (void)callController:(NCCallController *)callController didReceiveNick:(NSString *)nick fromPeer:(NCPeerConnection *)peer
|
|
|
|
{
|
|
|
|
[self updatePeer:peer block:^(CallParticipantViewCell *cell) {
|
|
|
|
[cell setDisplayName:nick];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
#pragma mark - RTCEAGLVideoViewDelegate
|
2017-08-07 22:11:39 +03:00
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
- (void)videoView:(RTCEAGLVideoView*)videoView didChangeVideoSize:(CGSize)size
|
2017-08-07 22:11:39 +03:00
|
|
|
{
|
2017-10-12 15:37:36 +03:00
|
|
|
for (RTCEAGLVideoView *rendererView in [_renderersDict allValues]) {
|
|
|
|
if ([videoView isEqual:rendererView]) {
|
|
|
|
rendererView.frame = CGRectMake(0, 0, size.width, size.height);
|
|
|
|
}
|
2017-08-24 15:00:50 +03:00
|
|
|
}
|
|
|
|
|
2017-10-12 15:37:36 +03:00
|
|
|
[self.collectionView reloadData];
|
2017-08-07 22:11:39 +03:00
|
|
|
}
|
|
|
|
|
2017-10-15 13:28:33 +03:00
|
|
|
#pragma mark - Cell updates
|
|
|
|
|
|
|
|
- (NSIndexPath *)indexPathOfPeer:(NCPeerConnection *)peer {
|
|
|
|
NSUInteger idx = [_peersInCall indexOfObject:peer];
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
|
|
|
|
|
|
|
|
return indexPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)updatePeer:(NCPeerConnection *)peer block:(void(^)(CallParticipantViewCell* cell))block {
|
|
|
|
NSIndexPath *indexPath = [self indexPathOfPeer:peer];
|
2017-12-13 17:25:27 +03:00
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
CallParticipantViewCell *cell = (id)[self.collectionView cellForItemAtIndexPath:indexPath];
|
|
|
|
block(cell);
|
|
|
|
});
|
2017-10-15 13:28:33 +03:00
|
|
|
}
|
|
|
|
|
2018-02-07 15:20:34 +03:00
|
|
|
- (void)showPeersInfo
|
|
|
|
{
|
|
|
|
NSArray *visibleCells = [_collectionView visibleCells];
|
|
|
|
for (CallParticipantViewCell *cell in visibleCells) {
|
|
|
|
[UIView animateWithDuration:0.3f animations:^{
|
|
|
|
[cell.peerNameLabel setAlpha:1.0f];
|
|
|
|
[cell.audioOffIndicator setAlpha:0.5f];
|
|
|
|
[cell layoutIfNeeded];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)hidePeersInfo
|
|
|
|
{
|
|
|
|
NSArray *visibleCells = [_collectionView visibleCells];
|
|
|
|
for (CallParticipantViewCell *cell in visibleCells) {
|
|
|
|
[UIView animateWithDuration:0.3f animations:^{
|
|
|
|
[cell.peerNameLabel setAlpha:0.0f];
|
|
|
|
[cell.audioOffIndicator setAlpha:0.0f];
|
|
|
|
[cell layoutIfNeeded];
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-07 22:11:39 +03:00
|
|
|
@end
|