blob: 710b8a5ea40e1264c73d60d2c9be953e84111d93 [file] [log] [blame]
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * 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.
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +00009 */
10
11#import "APPRTCViewController.h"
12
13#import <AVFoundation/AVFoundation.h>
tkchin9eeb6242016-04-27 01:54:20 -070014
15#import "WebRTC/RTCNSGLVideoView.h"
16#import "WebRTC/RTCVideoTrack.h"
hjon79858f82016-03-13 22:08:26 -070017
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000018#import "ARDAppClient.h"
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000019
20static NSUInteger const kContentWidth = 1280;
21static NSUInteger const kContentHeight = 720;
22static NSUInteger const kRoomFieldWidth = 80;
23static NSUInteger const kLogViewHeight = 280;
kthelgason314bc5f2016-08-31 10:23:27 -070024static NSUInteger const kPreviewWidth = 490;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000025
26@class APPRTCMainView;
27@protocol APPRTCMainViewDelegate
28
29- (void)appRTCMainView:(APPRTCMainView*)mainView
30 didEnterRoomId:(NSString*)roomId;
31
32@end
33
34@interface APPRTCMainView : NSView
35
36@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
37@property(nonatomic, readonly) RTCNSGLVideoView* localVideoView;
38@property(nonatomic, readonly) RTCNSGLVideoView* remoteVideoView;
39
40- (void)displayLogMessage:(NSString*)message;
41
42@end
43
44@interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate>
45@end
46@implementation APPRTCMainView {
47 NSScrollView* _scrollView;
48 NSTextField* _roomLabel;
49 NSTextField* _roomField;
50 NSTextView* _logView;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000051 CGSize _localVideoSize;
52 CGSize _remoteVideoSize;
53}
54
tkchin2ddfdba2016-08-07 21:37:45 -070055@synthesize delegate = _delegate;
56@synthesize localVideoView = _localVideoView;
57@synthesize remoteVideoView = _remoteVideoView;
58
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000059+ (BOOL)requiresConstraintBasedLayout {
60 return YES;
61}
62
63- (instancetype)initWithFrame:(NSRect)frame {
64 if (self = [super initWithFrame:frame]) {
65 [self setupViews];
66 }
67 return self;
68}
69
70- (void)updateConstraints {
71 NSParameterAssert(
72 _roomField != nil && _scrollView != nil && _remoteVideoView != nil);
73 [self removeConstraints:[self constraints]];
74 NSDictionary* viewsDictionary =
75 NSDictionaryOfVariableBindings(_roomLabel,
76 _roomField,
77 _scrollView,
kthelgason314bc5f2016-08-31 10:23:27 -070078 _remoteVideoView,
79 _localVideoView);
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000080
81 NSSize remoteViewSize = [self remoteVideoViewSize];
82 NSDictionary* metrics = @{
83 @"kLogViewHeight" : @(kLogViewHeight),
kthelgason314bc5f2016-08-31 10:23:27 -070084 @"kPreviewWidth" : @(kPreviewWidth),
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000085 @"kRoomFieldWidth" : @(kRoomFieldWidth),
86 @"remoteViewWidth" : @(remoteViewSize.width),
87 @"remoteViewHeight" : @(remoteViewSize.height),
kthelgason314bc5f2016-08-31 10:23:27 -070088 @"localViewHeight" : @(remoteViewSize.height),
89 @"scrollViewWidth" : @(kContentWidth - kPreviewWidth),
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000090 };
91 // Declare this separately to avoid compiler warning about splitting string
92 // within an NSArray expression.
93 NSString* verticalConstraint =
94 @"V:|-[_roomLabel]-[_roomField]-[_scrollView(kLogViewHeight)]"
95 "-[_remoteVideoView(remoteViewHeight)]-|";
96 NSArray* constraintFormats = @[
97 verticalConstraint,
kthelgason314bc5f2016-08-31 10:23:27 -070098 @"V:[_localVideoView]-[_remoteVideoView]",
99 @"V:[_localVideoView(kLogViewHeight)]",
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000100 @"|-[_roomLabel]",
101 @"|-[_roomField(kRoomFieldWidth)]",
kthelgason314bc5f2016-08-31 10:23:27 -0700102 @"|-[_scrollView(scrollViewWidth)]",
103 @"[_scrollView]-[_localVideoView]",
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000104 @"|-[_remoteVideoView(remoteViewWidth)]-|",
kthelgason314bc5f2016-08-31 10:23:27 -0700105 @"[_localVideoView(kPreviewWidth)]-|",
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000106 ];
107 for (NSString* constraintFormat in constraintFormats) {
108 NSArray* constraints =
109 [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
110 options:0
111 metrics:metrics
112 views:viewsDictionary];
113 for (NSLayoutConstraint* constraint in constraints) {
114 [self addConstraint:constraint];
115 }
116 }
117 [super updateConstraints];
118}
119
120- (void)displayLogMessage:(NSString*)message {
121 _logView.string =
122 [NSString stringWithFormat:@"%@%@\n", _logView.string, message];
123 NSRange range = NSMakeRange([_logView.string length], 0);
124 [_logView scrollRangeToVisible:range];
125}
126
127#pragma mark - NSControl delegate
128
129- (void)controlTextDidEndEditing:(NSNotification*)notification {
130 NSDictionary* userInfo = [notification userInfo];
131 NSInteger textMovement = [userInfo[@"NSTextMovement"] intValue];
132 if (textMovement == NSReturnTextMovement) {
133 [self.delegate appRTCMainView:self didEnterRoomId:_roomField.stringValue];
134 }
135}
136
137#pragma mark - RTCNSGLVideoViewDelegate
138
139- (void)videoView:(RTCNSGLVideoView*)videoView
140 didChangeVideoSize:(NSSize)size {
141 if (videoView == _remoteVideoView) {
142 _remoteVideoSize = size;
143 } else if (videoView == _localVideoView) {
144 _localVideoSize = size;
145 } else {
146 return;
147 }
148 [self setNeedsUpdateConstraints:YES];
149}
150
151#pragma mark - Private
152
153- (void)setupViews {
154 NSParameterAssert([[self subviews] count] == 0);
155
156 _roomLabel = [[NSTextField alloc] initWithFrame:NSZeroRect];
157 [_roomLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
158 [_roomLabel setBezeled:NO];
159 [_roomLabel setDrawsBackground:NO];
160 [_roomLabel setEditable:NO];
161 [_roomLabel setStringValue:@"Enter AppRTC room id:"];
162 [self addSubview:_roomLabel];
163
164 _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
165 [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
166 [self addSubview:_roomField];
167 [_roomField setEditable:YES];
168 [_roomField setDelegate:self];
169
170 _logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
171 [_logView setMinSize:NSMakeSize(0, kLogViewHeight)];
172 [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
173 [_logView setVerticallyResizable:YES];
174 [_logView setAutoresizingMask:NSViewWidthSizable];
175 NSTextContainer* textContainer = [_logView textContainer];
176 NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
177 [textContainer setContainerSize:containerSize];
178 [textContainer setWidthTracksTextView:YES];
179 [_logView setEditable:NO];
180
181 _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
182 [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
183 [_scrollView setHasVerticalScroller:YES];
184 [_scrollView setDocumentView:_logView];
185 [self addSubview:_scrollView];
186
187 NSOpenGLPixelFormatAttribute attributes[] = {
188 NSOpenGLPFADoubleBuffer,
189 NSOpenGLPFADepthSize, 24,
190 NSOpenGLPFAOpenGLProfile,
191 NSOpenGLProfileVersion3_2Core,
192 0
193 };
194 NSOpenGLPixelFormat* pixelFormat =
195 [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
196 _remoteVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
197 pixelFormat:pixelFormat];
198 [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
199 _remoteVideoView.delegate = self;
200 [self addSubview:_remoteVideoView];
201
kthelgason314bc5f2016-08-31 10:23:27 -0700202 _localVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
203 pixelFormat:pixelFormat];
204 [_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
205 _localVideoView.delegate = self;
206 [self addSubview:_localVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000207}
208
209- (NSSize)remoteVideoViewSize {
kthelgason314bc5f2016-08-31 10:23:27 -0700210 NSInteger width = MAX(_remoteVideoSize.width, kContentWidth);
211 NSInteger height = (width/16) * 9;
212 return NSMakeSize(width, height);
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000213}
214
215@end
216
217@interface APPRTCViewController ()
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000218 <ARDAppClientDelegate, APPRTCMainViewDelegate>
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000219@property(nonatomic, readonly) APPRTCMainView* mainView;
220@end
221
222@implementation APPRTCViewController {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000223 ARDAppClient* _client;
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000224 RTCVideoTrack* _localVideoTrack;
225 RTCVideoTrack* _remoteVideoTrack;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000226}
227
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000228- (void)dealloc {
229 [self disconnect];
230}
231
232- (void)loadView {
233 APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
234 [view setTranslatesAutoresizingMaskIntoConstraints:NO];
235 view.delegate = self;
236 self.view = view;
237}
238
239- (void)windowWillClose:(NSNotification*)notification {
240 [self disconnect];
241}
242
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000243#pragma mark - ARDAppClientDelegate
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000244
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000245- (void)appClient:(ARDAppClient *)client
246 didChangeState:(ARDAppClientState)state {
247 switch (state) {
248 case kARDAppClientStateConnected:
249 NSLog(@"Client connected.");
250 break;
251 case kARDAppClientStateConnecting:
252 NSLog(@"Client connecting.");
253 break;
254 case kARDAppClientStateDisconnected:
255 NSLog(@"Client disconnected.");
256 [self resetUI];
257 _client = nil;
258 break;
259 }
260}
261
262- (void)appClient:(ARDAppClient *)client
hjon79858f82016-03-13 22:08:26 -0700263 didChangeConnectionState:(RTCIceConnectionState)state {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000264}
265
266- (void)appClient:(ARDAppClient *)client
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000267 didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000268 _localVideoTrack = localVideoTrack;
kthelgason314bc5f2016-08-31 10:23:27 -0700269 [_localVideoTrack addRenderer:self.mainView.localVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000270}
271
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000272- (void)appClient:(ARDAppClient *)client
273 didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000274 _remoteVideoTrack = remoteVideoTrack;
275 [_remoteVideoTrack addRenderer:self.mainView.remoteVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000276}
277
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000278- (void)appClient:(ARDAppClient *)client
279 didError:(NSError *)error {
280 [self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000281 [self disconnect];
282}
283
Zeke Chind3325802015-08-14 11:00:02 -0700284- (void)appClient:(ARDAppClient *)client
285 didGetStats:(NSArray *)stats {
286}
287
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000288#pragma mark - APPRTCMainViewDelegate
289
290- (void)appRTCMainView:(APPRTCMainView*)mainView
291 didEnterRoomId:(NSString*)roomId {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000292 [_client disconnect];
293 ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self];
tkchinab1293a2016-08-30 12:35:05 -0700294 [client connectToRoomWithId:roomId
295 isLoopback:NO
296 isAudioOnly:NO
297 shouldMakeAecDump:NO
298 shouldUseLevelControl:NO];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000299 _client = client;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000300}
301
302#pragma mark - Private
303
304- (APPRTCMainView*)mainView {
305 return (APPRTCMainView*)self.view;
306}
307
308- (void)showAlertWithMessage:(NSString*)message {
309 NSAlert* alert = [[NSAlert alloc] init];
310 [alert setMessageText:message];
311 [alert runModal];
312}
313
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000314- (void)resetUI {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000315 [_remoteVideoTrack removeRenderer:self.mainView.remoteVideoView];
kthelgason314bc5f2016-08-31 10:23:27 -0700316 [_localVideoTrack removeRenderer:self.mainView.localVideoView];
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000317 _remoteVideoTrack = nil;
kthelgason314bc5f2016-08-31 10:23:27 -0700318 _localVideoTrack = nil;
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000319 [self.mainView.remoteVideoView renderFrame:nil];
kthelgason314bc5f2016-08-31 10:23:27 -0700320 [self.mainView.localVideoView renderFrame:nil];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000321}
322
323- (void)disconnect {
324 [self resetUI];
325 [_client disconnect];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000326}
327
328@end