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