Home | History | Annotate | Download | only in ios
      1 /*
      2  *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #import "ARDVideoCallView.h"
     12 
     13 #import <AVFoundation/AVFoundation.h>
     14 #import "UIImage+ARDUtilities.h"
     15 
     16 static CGFloat const kButtonPadding = 16;
     17 static CGFloat const kButtonSize = 48;
     18 static CGFloat const kLocalVideoViewSize = 120;
     19 static CGFloat const kLocalVideoViewPadding = 8;
     20 static CGFloat const kStatusBarHeight = 20;
     21 
     22 @interface ARDVideoCallView () <RTCEAGLVideoViewDelegate>
     23 @end
     24 
     25 @implementation ARDVideoCallView {
     26   UIButton *_cameraSwitchButton;
     27   UIButton *_hangupButton;
     28   CGSize _remoteVideoSize;
     29   BOOL _useRearCamera;
     30 }
     31 
     32 @synthesize statusLabel = _statusLabel;
     33 @synthesize localVideoView = _localVideoView;
     34 @synthesize remoteVideoView = _remoteVideoView;
     35 @synthesize statsView = _statsView;
     36 @synthesize delegate = _delegate;
     37 
     38 - (instancetype)initWithFrame:(CGRect)frame {
     39   if (self = [super initWithFrame:frame]) {
     40     _remoteVideoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero];
     41     _remoteVideoView.delegate = self;
     42     [self addSubview:_remoteVideoView];
     43 
     44     _localVideoView = [[RTCCameraPreviewView alloc] initWithFrame:CGRectZero];
     45     [self addSubview:_localVideoView];
     46 
     47     _statsView = [[ARDStatsView alloc] initWithFrame:CGRectZero];
     48     _statsView.hidden = YES;
     49     [self addSubview:_statsView];
     50 
     51     // TODO(tkchin): don't display this if we can't actually do camera switch.
     52     _cameraSwitchButton = [UIButton buttonWithType:UIButtonTypeCustom];
     53     _cameraSwitchButton.backgroundColor = [UIColor whiteColor];
     54     _cameraSwitchButton.layer.cornerRadius = kButtonSize / 2;
     55     _cameraSwitchButton.layer.masksToBounds = YES;
     56     UIImage *image = [UIImage imageNamed:@"ic_switch_video_black_24dp.png"];
     57     [_cameraSwitchButton setImage:image forState:UIControlStateNormal];
     58     [_cameraSwitchButton addTarget:self
     59                       action:@selector(onCameraSwitch:)
     60             forControlEvents:UIControlEventTouchUpInside];
     61     [self addSubview:_cameraSwitchButton];
     62 
     63     _hangupButton = [UIButton buttonWithType:UIButtonTypeCustom];
     64     _hangupButton.backgroundColor = [UIColor redColor];
     65     _hangupButton.layer.cornerRadius = kButtonSize / 2;
     66     _hangupButton.layer.masksToBounds = YES;
     67     image = [UIImage imageForName:@"ic_call_end_black_24dp.png"
     68                             color:[UIColor whiteColor]];
     69     [_hangupButton setImage:image forState:UIControlStateNormal];
     70     [_hangupButton addTarget:self
     71                       action:@selector(onHangup:)
     72             forControlEvents:UIControlEventTouchUpInside];
     73     [self addSubview:_hangupButton];
     74 
     75     _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     76     _statusLabel.font = [UIFont fontWithName:@"Roboto" size:16];
     77     _statusLabel.textColor = [UIColor whiteColor];
     78     [self addSubview:_statusLabel];
     79 
     80     UITapGestureRecognizer *tapRecognizer =
     81         [[UITapGestureRecognizer alloc]
     82             initWithTarget:self
     83                     action:@selector(didTripleTap:)];
     84     tapRecognizer.numberOfTapsRequired = 3;
     85     [self addGestureRecognizer:tapRecognizer];
     86   }
     87   return self;
     88 }
     89 
     90 - (void)layoutSubviews {
     91   CGRect bounds = self.bounds;
     92   if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) {
     93     // Aspect fill remote video into bounds.
     94     CGRect remoteVideoFrame =
     95         AVMakeRectWithAspectRatioInsideRect(_remoteVideoSize, bounds);
     96     CGFloat scale = 1;
     97     if (remoteVideoFrame.size.width > remoteVideoFrame.size.height) {
     98       // Scale by height.
     99       scale = bounds.size.height / remoteVideoFrame.size.height;
    100     } else {
    101       // Scale by width.
    102       scale = bounds.size.width / remoteVideoFrame.size.width;
    103     }
    104     remoteVideoFrame.size.height *= scale;
    105     remoteVideoFrame.size.width *= scale;
    106     _remoteVideoView.frame = remoteVideoFrame;
    107     _remoteVideoView.center =
    108         CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    109   } else {
    110     _remoteVideoView.frame = bounds;
    111   }
    112 
    113   // Aspect fit local video view into a square box.
    114   CGRect localVideoFrame =
    115       CGRectMake(0, 0, kLocalVideoViewSize, kLocalVideoViewSize);
    116   // Place the view in the bottom right.
    117   localVideoFrame.origin.x = CGRectGetMaxX(bounds)
    118       - localVideoFrame.size.width - kLocalVideoViewPadding;
    119   localVideoFrame.origin.y = CGRectGetMaxY(bounds)
    120       - localVideoFrame.size.height - kLocalVideoViewPadding;
    121   _localVideoView.frame = localVideoFrame;
    122 
    123   // Place stats at the top.
    124   CGSize statsSize = [_statsView sizeThatFits:bounds.size];
    125   _statsView.frame = CGRectMake(CGRectGetMinX(bounds),
    126                                 CGRectGetMinY(bounds) + kStatusBarHeight,
    127                                 statsSize.width, statsSize.height);
    128 
    129   // Place hangup button in the bottom left.
    130   _hangupButton.frame =
    131       CGRectMake(CGRectGetMinX(bounds) + kButtonPadding,
    132                  CGRectGetMaxY(bounds) - kButtonPadding -
    133                      kButtonSize,
    134                  kButtonSize,
    135                  kButtonSize);
    136 
    137   // Place button to the right of hangup button.
    138   CGRect cameraSwitchFrame = _hangupButton.frame;
    139   cameraSwitchFrame.origin.x =
    140       CGRectGetMaxX(cameraSwitchFrame) + kButtonPadding;
    141   _cameraSwitchButton.frame = cameraSwitchFrame;
    142 
    143   [_statusLabel sizeToFit];
    144   _statusLabel.center =
    145       CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    146 }
    147 
    148 #pragma mark - RTCEAGLVideoViewDelegate
    149 
    150 - (void)videoView:(RTCEAGLVideoView*)videoView didChangeVideoSize:(CGSize)size {
    151  if (videoView == _remoteVideoView) {
    152     _remoteVideoSize = size;
    153   }
    154   [self setNeedsLayout];
    155 }
    156 
    157 #pragma mark - Private
    158 
    159 - (void)onCameraSwitch:(id)sender {
    160   [_delegate videoCallViewDidSwitchCamera:self];
    161 }
    162 
    163 - (void)onHangup:(id)sender {
    164   [_delegate videoCallViewDidHangup:self];
    165 }
    166 
    167 - (void)didTripleTap:(UITapGestureRecognizer *)recognizer {
    168   [_delegate videoCallViewDidEnableStats:self];
    169 }
    170 
    171 @end
    172