tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

APPRTCViewController.m (13529B)


      1 /*
      2 *  Copyright 2014 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 "APPRTCViewController.h"
     12 
     13 #import <AVFoundation/AVFoundation.h>
     14 
     15 #import "sdk/objc/api/peerconnection/RTCVideoTrack.h"
     16 #import "sdk/objc/components/renderer/metal/RTCMTLNSVideoView.h"
     17 
     18 #import "ARDAppClient.h"
     19 #import "ARDCaptureController.h"
     20 #import "ARDSettingsModel.h"
     21 
     22 static NSUInteger const kContentWidth = 900;
     23 static NSUInteger const kRoomFieldWidth = 200;
     24 static NSUInteger const kActionItemHeight = 30;
     25 static NSUInteger const kBottomViewHeight = 200;
     26 
     27 @class APPRTCMainView;
     28 @protocol APPRTCMainViewDelegate
     29 
     30 - (void)appRTCMainView:(APPRTCMainView*)mainView
     31        didEnterRoomId:(NSString*)roomId
     32              loopback:(BOOL)isLoopback;
     33 
     34 @end
     35 
     36 @interface APPRTCMainView : NSView
     37 
     38 @property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
     39 @property(nonatomic, readonly)
     40    NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>* localVideoView;
     41 @property(nonatomic, readonly)
     42    NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>* remoteVideoView;
     43 @property(nonatomic, readonly) NSTextView* logView;
     44 
     45 - (void)displayLogMessage:(NSString*)message;
     46 
     47 @end
     48 
     49 @interface APPRTCMainView () <NSTextFieldDelegate,
     50                              RTC_OBJC_TYPE (RTCVideoViewDelegate)>
     51 @end
     52 @implementation APPRTCMainView {
     53  NSScrollView* _scrollView;
     54  NSView* _actionItemsView;
     55  NSButton* _connectButton;
     56  NSButton* _loopbackButton;
     57  NSTextField* _roomField;
     58  CGSize _localVideoSize;
     59  CGSize _remoteVideoSize;
     60 }
     61 
     62 @synthesize delegate = _delegate;
     63 @synthesize localVideoView = _localVideoView;
     64 @synthesize remoteVideoView = _remoteVideoView;
     65 @synthesize logView = _logView;
     66 
     67 - (void)displayLogMessage:(NSString*)message {
     68  dispatch_async(dispatch_get_main_queue(), ^{
     69    self.logView.string =
     70        [NSString stringWithFormat:@"%@%@\n", self.logView.string, message];
     71    NSRange range = NSMakeRange(self.logView.string.length, 0);
     72    [self.logView scrollRangeToVisible:range];
     73  });
     74 }
     75 
     76 #pragma mark - Private
     77 
     78 - (instancetype)initWithFrame:(NSRect)frame {
     79  self = [super initWithFrame:frame];
     80  if (self) {
     81    [self setupViews];
     82  }
     83  return self;
     84 }
     85 
     86 + (BOOL)requiresConstraintBasedLayout {
     87  return YES;
     88 }
     89 
     90 - (void)updateConstraints {
     91  NSParameterAssert(_roomField != nil && _scrollView != nil &&
     92                    _remoteVideoView != nil && _localVideoView != nil &&
     93                    _actionItemsView != nil && _connectButton != nil &&
     94                    _loopbackButton != nil);
     95 
     96  [self removeConstraints:[self constraints]];
     97  NSDictionary* viewsDictionary =
     98      NSDictionaryOfVariableBindings(_roomField,
     99                                     _scrollView,
    100                                     _remoteVideoView,
    101                                     _localVideoView,
    102                                     _actionItemsView,
    103                                     _connectButton,
    104                                     _loopbackButton);
    105 
    106  NSSize remoteViewSize = [self remoteVideoViewSize];
    107  NSDictionary* metrics = @{
    108    @"remoteViewWidth" : @(remoteViewSize.width),
    109    @"remoteViewHeight" : @(remoteViewSize.height),
    110    @"kBottomViewHeight" : @(kBottomViewHeight),
    111    @"localViewHeight" : @(remoteViewSize.height / 3),
    112    @"localViewWidth" : @(remoteViewSize.width / 3),
    113    @"kRoomFieldWidth" : @(kRoomFieldWidth),
    114    @"kActionItemHeight" : @(kActionItemHeight)
    115  };
    116  // Declare this separately to avoid compiler warning about splitting string
    117  // within an NSArray expression.
    118  NSString* verticalConstraintLeft = @"V:|-[_remoteVideoView(remoteViewHeight)]"
    119                                     @"-[_scrollView(kBottomViewHeight)]-|";
    120  NSString* verticalConstraintRight =
    121      @"V:|-[_remoteVideoView(remoteViewHeight)]-[_actionItemsView("
    122      @"kBottomViewHeight)]-|";
    123  NSArray* constraintFormats = @[
    124    verticalConstraintLeft,
    125    verticalConstraintRight,
    126    @"H:|-[_remoteVideoView(remoteViewWidth)]-|",
    127    @"V:|-[_localVideoView(localViewHeight)]",
    128    @"H:|-[_localVideoView(localViewWidth)]",
    129    @"H:|-[_scrollView(==_actionItemsView)]-[_actionItemsView]-|"
    130  ];
    131 
    132  NSArray* actionItemsConstraints = @[
    133    @"H:|-[_roomField(kRoomFieldWidth)]-[_loopbackButton(kRoomFieldWidth)]",
    134    @"H:|-[_connectButton(kRoomFieldWidth)]",
    135    @"V:|-[_roomField(kActionItemHeight)]-[_connectButton(kActionItemHeight)]",
    136    @"V:|-[_loopbackButton(kActionItemHeight)]",
    137  ];
    138 
    139  [APPRTCMainView addConstraints:constraintFormats
    140                          toView:self
    141                 viewsDictionary:viewsDictionary
    142                         metrics:metrics];
    143  [APPRTCMainView addConstraints:actionItemsConstraints
    144                          toView:_actionItemsView
    145                 viewsDictionary:viewsDictionary
    146                         metrics:metrics];
    147  [super updateConstraints];
    148 }
    149 
    150 #pragma mark - Constraints helper
    151 
    152 + (void)addConstraints:(NSArray*)constraintFormats
    153                toView:(NSView*)view
    154       viewsDictionary:(NSDictionary*)viewsDictionary
    155               metrics:(NSDictionary*)metrics {
    156  for (NSString* constraintFormat in constraintFormats) {
    157    NSArray* constraints =
    158        [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
    159                                                options:0
    160                                                metrics:metrics
    161                                                  views:viewsDictionary];
    162    for (NSLayoutConstraint* constraint in constraints) {
    163      [view addConstraint:constraint];
    164    }
    165  }
    166 }
    167 
    168 #pragma mark - Control actions
    169 
    170 - (void)startCall:(id)sender {
    171  NSString* roomString = _roomField.stringValue;
    172  // Generate room id for loopback options.
    173  if (_loopbackButton.intValue && [roomString isEqualToString:@""]) {
    174    roomString = [NSUUID UUID].UUIDString;
    175    roomString = [roomString stringByReplacingOccurrencesOfString:@"-"
    176                                                       withString:@""];
    177  }
    178  [self.delegate appRTCMainView:self
    179                 didEnterRoomId:roomString
    180                       loopback:_loopbackButton.intValue];
    181  [self setNeedsUpdateConstraints:YES];
    182 }
    183 
    184 #pragma mark - RTCVideoViewDelegate
    185 
    186 - (void)videoView:(id<RTC_OBJC_TYPE(RTCVideoRenderer)>)videoView
    187    didChangeVideoSize:(CGSize)size {
    188  if (videoView == _remoteVideoView) {
    189    _remoteVideoSize = size;
    190  } else if (videoView == _localVideoView) {
    191    _localVideoSize = size;
    192  } else {
    193    return;
    194  }
    195 
    196  [self setNeedsUpdateConstraints:YES];
    197 }
    198 
    199 #pragma mark - Private
    200 
    201 - (void)setupViews {
    202  NSParameterAssert([[self subviews] count] == 0);
    203 
    204  _logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
    205  [_logView setMinSize:NSMakeSize(0, kBottomViewHeight)];
    206  [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
    207  [_logView setVerticallyResizable:YES];
    208  [_logView setAutoresizingMask:NSViewWidthSizable];
    209  NSTextContainer* textContainer = [_logView textContainer];
    210  NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
    211  [textContainer setContainerSize:containerSize];
    212  [textContainer setWidthTracksTextView:YES];
    213  [_logView setEditable:NO];
    214 
    215  [self setupActionItemsView];
    216 
    217  _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
    218  [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
    219  [_scrollView setHasVerticalScroller:YES];
    220  [_scrollView setDocumentView:_logView];
    221  [self addSubview:_scrollView];
    222 
    223  _remoteVideoView =
    224      [[RTC_OBJC_TYPE(RTCMTLNSVideoView) alloc] initWithFrame:NSZeroRect];
    225  _localVideoView =
    226      [[RTC_OBJC_TYPE(RTCMTLNSVideoView) alloc] initWithFrame:NSZeroRect];
    227 
    228  [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
    229  [self addSubview:_remoteVideoView];
    230  [_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
    231  [self addSubview:_localVideoView];
    232 }
    233 
    234 - (void)setupActionItemsView {
    235  _actionItemsView = [[NSView alloc] initWithFrame:NSZeroRect];
    236  [_actionItemsView setTranslatesAutoresizingMaskIntoConstraints:NO];
    237  [self addSubview:_actionItemsView];
    238 
    239  _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
    240  [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
    241  [[_roomField cell] setPlaceholderString:@"Enter AppRTC room id"];
    242  [_actionItemsView addSubview:_roomField];
    243  [_roomField setEditable:YES];
    244 
    245  _connectButton = [[NSButton alloc] initWithFrame:NSZeroRect];
    246  [_connectButton setTranslatesAutoresizingMaskIntoConstraints:NO];
    247  _connectButton.title = @"Start call";
    248  _connectButton.bezelStyle = NSBezelStyleSmallSquare;
    249  _connectButton.target = self;
    250  _connectButton.action = @selector(startCall:);
    251  [_actionItemsView addSubview:_connectButton];
    252 
    253  _loopbackButton = [[NSButton alloc] initWithFrame:NSZeroRect];
    254  [_loopbackButton setTranslatesAutoresizingMaskIntoConstraints:NO];
    255  _loopbackButton.title = @"Loopback";
    256  [_loopbackButton setButtonType:NSButtonTypeSwitch];
    257  [_actionItemsView addSubview:_loopbackButton];
    258 }
    259 
    260 - (NSSize)remoteVideoViewSize {
    261  if (!_remoteVideoView.bounds.size.width) {
    262    return NSMakeSize(kContentWidth, 0);
    263  }
    264  NSInteger width = MAX(_remoteVideoView.bounds.size.width, kContentWidth);
    265  NSInteger height = (width / 16) * 9;
    266  return NSMakeSize(width, height);
    267 }
    268 
    269 @end
    270 
    271 @interface APPRTCViewController () <ARDAppClientDelegate,
    272                                    APPRTCMainViewDelegate>
    273 @property(nonatomic, readonly) APPRTCMainView* mainView;
    274 @end
    275 
    276 @implementation APPRTCViewController {
    277  ARDAppClient* _client;
    278  RTC_OBJC_TYPE(RTCVideoTrack) * _localVideoTrack;
    279  RTC_OBJC_TYPE(RTCVideoTrack) * _remoteVideoTrack;
    280  ARDCaptureController* _captureController;
    281 }
    282 
    283 - (void)dealloc {
    284  [self disconnect];
    285 }
    286 
    287 - (void)viewDidAppear {
    288  [super viewDidAppear];
    289  [self displayUsageInstructions];
    290 }
    291 
    292 - (void)loadView {
    293  APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
    294  [view setTranslatesAutoresizingMaskIntoConstraints:NO];
    295  view.delegate = self;
    296  self.view = view;
    297 }
    298 
    299 - (void)windowWillClose:(NSNotification*)notification {
    300  [self disconnect];
    301 }
    302 
    303 #pragma mark - Usage
    304 
    305 - (void)displayUsageInstructions {
    306  [self.mainView displayLogMessage:
    307                     @"To start call:\n"
    308                     @"• Enter AppRTC room id (not neccessary for loopback)\n"
    309                     @"• Start call"];
    310 }
    311 
    312 #pragma mark - ARDAppClientDelegate
    313 
    314 - (void)appClient:(ARDAppClient*)client
    315    didChangeState:(ARDAppClientState)state {
    316  switch (state) {
    317    case kARDAppClientStateConnected:
    318      [self.mainView displayLogMessage:@"Client connected."];
    319      break;
    320    case kARDAppClientStateConnecting:
    321      [self.mainView displayLogMessage:@"Client connecting."];
    322      break;
    323    case kARDAppClientStateDisconnected:
    324      [self.mainView displayLogMessage:@"Client disconnected."];
    325      [self resetUI];
    326      _client = nil;
    327      break;
    328  }
    329 }
    330 
    331 - (void)appClient:(ARDAppClient*)client
    332    didChangeConnectionState:(RTCIceConnectionState)state {
    333 }
    334 
    335 - (void)appClient:(ARDAppClient*)client
    336    didCreateLocalCapturer:
    337        (RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)localCapturer {
    338  _captureController = [[ARDCaptureController alloc]
    339      initWithCapturer:localCapturer
    340              settings:[[ARDSettingsModel alloc] init]];
    341  [_captureController startCapture];
    342 }
    343 
    344 - (void)appClient:(ARDAppClient*)client
    345    didReceiveLocalVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)localVideoTrack {
    346  _localVideoTrack = localVideoTrack;
    347  [_localVideoTrack addRenderer:self.mainView.localVideoView];
    348 }
    349 
    350 - (void)appClient:(ARDAppClient*)client
    351    didReceiveRemoteVideoTrack:
    352        (RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack {
    353  _remoteVideoTrack = remoteVideoTrack;
    354  [_remoteVideoTrack addRenderer:self.mainView.remoteVideoView];
    355 }
    356 
    357 - (void)appClient:(ARDAppClient*)client didError:(NSError*)error {
    358  [self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]];
    359  [self disconnect];
    360 }
    361 
    362 - (void)appClient:(ARDAppClient*)client didGetStats:(NSArray*)stats {
    363 }
    364 
    365 #pragma mark - APPRTCMainViewDelegate
    366 
    367 - (void)appRTCMainView:(APPRTCMainView*)mainView
    368        didEnterRoomId:(NSString*)roomId
    369              loopback:(BOOL)isLoopback {
    370  if ([roomId isEqualToString:@""]) {
    371    [self.mainView displayLogMessage:@"Missing room id"];
    372    return;
    373  }
    374 
    375  [self disconnect];
    376  ARDAppClient* client = [[ARDAppClient alloc] initWithDelegate:self];
    377  [client connectToRoomWithId:roomId
    378                     settings:[[ARDSettingsModel alloc]
    379                                  init]  // Use default settings.
    380                   isLoopback:isLoopback];
    381  _client = client;
    382 }
    383 
    384 #pragma mark - Private
    385 
    386 - (APPRTCMainView*)mainView {
    387  return (APPRTCMainView*)self.view;
    388 }
    389 
    390 - (void)showAlertWithMessage:(NSString*)message {
    391  dispatch_async(dispatch_get_main_queue(), ^{
    392    NSAlert* alert = [[NSAlert alloc] init];
    393    [alert setMessageText:message];
    394    [alert runModal];
    395  });
    396 }
    397 
    398 - (void)resetUI {
    399  [_remoteVideoTrack removeRenderer:self.mainView.remoteVideoView];
    400  [_localVideoTrack removeRenderer:self.mainView.localVideoView];
    401  _remoteVideoTrack = nil;
    402  _localVideoTrack = nil;
    403  [self.mainView.remoteVideoView renderFrame:nil];
    404  [self.mainView.localVideoView renderFrame:nil];
    405 }
    406 
    407 - (void)disconnect {
    408  [self resetUI];
    409  [_captureController stopCapture];
    410  _captureController = nil;
    411  [_client disconnect];
    412 }
    413 
    414 @end