blob: cf5b836012a177c5327f68bf3f16bd0ccfaa23af [file] [log] [blame]
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +00001/*
2 * libjingle
3 * Copyright 2014, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#import "APPRTCViewController.h"
29
30#import <AVFoundation/AVFoundation.h>
31#import "APPRTCConnectionManager.h"
32#import "RTCNSGLVideoView.h"
33
34static NSUInteger const kContentWidth = 1280;
35static NSUInteger const kContentHeight = 720;
36static NSUInteger const kRoomFieldWidth = 80;
37static NSUInteger const kLogViewHeight = 280;
38
39@class APPRTCMainView;
40@protocol APPRTCMainViewDelegate
41
42- (void)appRTCMainView:(APPRTCMainView*)mainView
43 didEnterRoomId:(NSString*)roomId;
44
45@end
46
47@interface APPRTCMainView : NSView
48
49@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
50@property(nonatomic, readonly) RTCNSGLVideoView* localVideoView;
51@property(nonatomic, readonly) RTCNSGLVideoView* remoteVideoView;
52
53- (void)displayLogMessage:(NSString*)message;
54
55@end
56
57@interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate>
58@end
59@implementation APPRTCMainView {
60 NSScrollView* _scrollView;
61 NSTextField* _roomLabel;
62 NSTextField* _roomField;
63 NSTextView* _logView;
64 RTCNSGLVideoView* _localVideoView;
65 RTCNSGLVideoView* _remoteVideoView;
66 CGSize _localVideoSize;
67 CGSize _remoteVideoSize;
68}
69
70+ (BOOL)requiresConstraintBasedLayout {
71 return YES;
72}
73
74- (instancetype)initWithFrame:(NSRect)frame {
75 if (self = [super initWithFrame:frame]) {
76 [self setupViews];
77 }
78 return self;
79}
80
81- (void)updateConstraints {
82 NSParameterAssert(
83 _roomField != nil && _scrollView != nil && _remoteVideoView != nil);
84 [self removeConstraints:[self constraints]];
85 NSDictionary* viewsDictionary =
86 NSDictionaryOfVariableBindings(_roomLabel,
87 _roomField,
88 _scrollView,
89 _remoteVideoView);
90
91 NSSize remoteViewSize = [self remoteVideoViewSize];
92 NSDictionary* metrics = @{
93 @"kLogViewHeight" : @(kLogViewHeight),
94 @"kRoomFieldWidth" : @(kRoomFieldWidth),
95 @"remoteViewWidth" : @(remoteViewSize.width),
96 @"remoteViewHeight" : @(remoteViewSize.height),
97 };
98 // Declare this separately to avoid compiler warning about splitting string
99 // within an NSArray expression.
100 NSString* verticalConstraint =
101 @"V:|-[_roomLabel]-[_roomField]-[_scrollView(kLogViewHeight)]"
102 "-[_remoteVideoView(remoteViewHeight)]-|";
103 NSArray* constraintFormats = @[
104 verticalConstraint,
105 @"|-[_roomLabel]",
106 @"|-[_roomField(kRoomFieldWidth)]",
107 @"|-[_scrollView(remoteViewWidth)]-|",
108 @"|-[_remoteVideoView(remoteViewWidth)]-|",
109 ];
110 for (NSString* constraintFormat in constraintFormats) {
111 NSArray* constraints =
112 [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
113 options:0
114 metrics:metrics
115 views:viewsDictionary];
116 for (NSLayoutConstraint* constraint in constraints) {
117 [self addConstraint:constraint];
118 }
119 }
120 [super updateConstraints];
121}
122
123- (void)displayLogMessage:(NSString*)message {
124 _logView.string =
125 [NSString stringWithFormat:@"%@%@\n", _logView.string, message];
126 NSRange range = NSMakeRange([_logView.string length], 0);
127 [_logView scrollRangeToVisible:range];
128}
129
130#pragma mark - NSControl delegate
131
132- (void)controlTextDidEndEditing:(NSNotification*)notification {
133 NSDictionary* userInfo = [notification userInfo];
134 NSInteger textMovement = [userInfo[@"NSTextMovement"] intValue];
135 if (textMovement == NSReturnTextMovement) {
136 [self.delegate appRTCMainView:self didEnterRoomId:_roomField.stringValue];
137 }
138}
139
140#pragma mark - RTCNSGLVideoViewDelegate
141
142- (void)videoView:(RTCNSGLVideoView*)videoView
143 didChangeVideoSize:(NSSize)size {
144 if (videoView == _remoteVideoView) {
145 _remoteVideoSize = size;
146 } else if (videoView == _localVideoView) {
147 _localVideoSize = size;
148 } else {
149 return;
150 }
151 [self setNeedsUpdateConstraints:YES];
152}
153
154#pragma mark - Private
155
156- (void)setupViews {
157 NSParameterAssert([[self subviews] count] == 0);
158
159 _roomLabel = [[NSTextField alloc] initWithFrame:NSZeroRect];
160 [_roomLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
161 [_roomLabel setBezeled:NO];
162 [_roomLabel setDrawsBackground:NO];
163 [_roomLabel setEditable:NO];
164 [_roomLabel setStringValue:@"Enter AppRTC room id:"];
165 [self addSubview:_roomLabel];
166
167 _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
168 [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
169 [self addSubview:_roomField];
170 [_roomField setEditable:YES];
171 [_roomField setDelegate:self];
172
173 _logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
174 [_logView setMinSize:NSMakeSize(0, kLogViewHeight)];
175 [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
176 [_logView setVerticallyResizable:YES];
177 [_logView setAutoresizingMask:NSViewWidthSizable];
178 NSTextContainer* textContainer = [_logView textContainer];
179 NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
180 [textContainer setContainerSize:containerSize];
181 [textContainer setWidthTracksTextView:YES];
182 [_logView setEditable:NO];
183
184 _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
185 [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
186 [_scrollView setHasVerticalScroller:YES];
187 [_scrollView setDocumentView:_logView];
188 [self addSubview:_scrollView];
189
190 NSOpenGLPixelFormatAttribute attributes[] = {
191 NSOpenGLPFADoubleBuffer,
192 NSOpenGLPFADepthSize, 24,
193 NSOpenGLPFAOpenGLProfile,
194 NSOpenGLProfileVersion3_2Core,
195 0
196 };
197 NSOpenGLPixelFormat* pixelFormat =
198 [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
199 _remoteVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
200 pixelFormat:pixelFormat];
201 [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
202 _remoteVideoView.delegate = self;
203 [self addSubview:_remoteVideoView];
204
205 // TODO(tkchin): create local video view.
206 // https://code.google.com/p/webrtc/issues/detail?id=3417.
207}
208
209- (NSSize)remoteVideoViewSize {
210 if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) {
211 return _remoteVideoSize;
212 } else {
213 return NSMakeSize(kContentWidth, kContentHeight);
214 }
215}
216
217- (NSSize)localVideoViewSize {
218 return NSZeroSize;
219}
220
221@end
222
223@interface APPRTCViewController ()
224 <APPRTCConnectionManagerDelegate, APPRTCMainViewDelegate, APPRTCLogger>
225@property(nonatomic, readonly) APPRTCMainView* mainView;
226@end
227
228@implementation APPRTCViewController {
229 APPRTCConnectionManager* _connectionManager;
230}
231
232- (instancetype)initWithNibName:(NSString*)nibName
233 bundle:(NSBundle*)bundle {
234 if (self = [super initWithNibName:nibName bundle:bundle]) {
235 _connectionManager =
236 [[APPRTCConnectionManager alloc] initWithDelegate:self
237 logger:self];
238 }
239 return self;
240}
241
242- (void)dealloc {
243 [self disconnect];
244}
245
246- (void)loadView {
247 APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
248 [view setTranslatesAutoresizingMaskIntoConstraints:NO];
249 view.delegate = self;
250 self.view = view;
251}
252
253- (void)windowWillClose:(NSNotification*)notification {
254 [self disconnect];
255}
256
257#pragma mark - APPRTCConnectionManagerDelegate
258
259- (void)connectionManager:(APPRTCConnectionManager*)manager
260 didReceiveLocalVideoTrack:(RTCVideoTrack*)localVideoTrack {
261 self.mainView.localVideoView.videoTrack = localVideoTrack;
262}
263
264- (void)connectionManager:(APPRTCConnectionManager*)manager
265 didReceiveRemoteVideoTrack:(RTCVideoTrack*)remoteVideoTrack {
266 self.mainView.remoteVideoView.videoTrack = remoteVideoTrack;
267}
268
269- (void)connectionManagerDidReceiveHangup:(APPRTCConnectionManager*)manager {
270 [self showAlertWithMessage:@"Remote closed connection"];
271 [self disconnect];
272}
273
274- (void)connectionManager:(APPRTCConnectionManager*)manager
275 didErrorWithMessage:(NSString*)message {
276 [self showAlertWithMessage:message];
277 [self disconnect];
278}
279
280#pragma mark - APPRTCLogger
281
282- (void)logMessage:(NSString*)message {
283 [self.mainView displayLogMessage:message];
284}
285
286#pragma mark - APPRTCMainViewDelegate
287
288- (void)appRTCMainView:(APPRTCMainView*)mainView
289 didEnterRoomId:(NSString*)roomId {
290 NSString* urlString =
291 [NSString stringWithFormat:@"https://apprtc.appspot.com/?r=%@", roomId];
292 [_connectionManager connectToRoomWithURL:[NSURL URLWithString:urlString]];
293}
294
295#pragma mark - Private
296
297- (APPRTCMainView*)mainView {
298 return (APPRTCMainView*)self.view;
299}
300
301- (void)showAlertWithMessage:(NSString*)message {
302 NSAlert* alert = [[NSAlert alloc] init];
303 [alert setMessageText:message];
304 [alert runModal];
305}
306
307- (void)disconnect {
308 self.mainView.remoteVideoView.videoTrack = nil;
309 [_connectionManager disconnect];
310}
311
312@end