OLD | NEW |
| (Empty) |
1 /* | |
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 "ARDAppClient.h" | |
32 #import "RTCNSGLVideoView.h" | |
33 #import "RTCVideoTrack.h" | |
34 | |
35 static NSUInteger const kContentWidth = 1280; | |
36 static NSUInteger const kContentHeight = 720; | |
37 static NSUInteger const kRoomFieldWidth = 80; | |
38 static NSUInteger const kLogViewHeight = 280; | |
39 | |
40 @class APPRTCMainView; | |
41 @protocol APPRTCMainViewDelegate | |
42 | |
43 - (void)appRTCMainView:(APPRTCMainView*)mainView | |
44 didEnterRoomId:(NSString*)roomId; | |
45 | |
46 @end | |
47 | |
48 @interface APPRTCMainView : NSView | |
49 | |
50 @property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate; | |
51 @property(nonatomic, readonly) RTCNSGLVideoView* localVideoView; | |
52 @property(nonatomic, readonly) RTCNSGLVideoView* remoteVideoView; | |
53 | |
54 - (void)displayLogMessage:(NSString*)message; | |
55 | |
56 @end | |
57 | |
58 @interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate> | |
59 @end | |
60 @implementation APPRTCMainView { | |
61 NSScrollView* _scrollView; | |
62 NSTextField* _roomLabel; | |
63 NSTextField* _roomField; | |
64 NSTextView* _logView; | |
65 RTCNSGLVideoView* _localVideoView; | |
66 RTCNSGLVideoView* _remoteVideoView; | |
67 CGSize _localVideoSize; | |
68 CGSize _remoteVideoSize; | |
69 } | |
70 | |
71 + (BOOL)requiresConstraintBasedLayout { | |
72 return YES; | |
73 } | |
74 | |
75 - (instancetype)initWithFrame:(NSRect)frame { | |
76 if (self = [super initWithFrame:frame]) { | |
77 [self setupViews]; | |
78 } | |
79 return self; | |
80 } | |
81 | |
82 - (void)updateConstraints { | |
83 NSParameterAssert( | |
84 _roomField != nil && _scrollView != nil && _remoteVideoView != nil); | |
85 [self removeConstraints:[self constraints]]; | |
86 NSDictionary* viewsDictionary = | |
87 NSDictionaryOfVariableBindings(_roomLabel, | |
88 _roomField, | |
89 _scrollView, | |
90 _remoteVideoView); | |
91 | |
92 NSSize remoteViewSize = [self remoteVideoViewSize]; | |
93 NSDictionary* metrics = @{ | |
94 @"kLogViewHeight" : @(kLogViewHeight), | |
95 @"kRoomFieldWidth" : @(kRoomFieldWidth), | |
96 @"remoteViewWidth" : @(remoteViewSize.width), | |
97 @"remoteViewHeight" : @(remoteViewSize.height), | |
98 }; | |
99 // Declare this separately to avoid compiler warning about splitting string | |
100 // within an NSArray expression. | |
101 NSString* verticalConstraint = | |
102 @"V:|-[_roomLabel]-[_roomField]-[_scrollView(kLogViewHeight)]" | |
103 "-[_remoteVideoView(remoteViewHeight)]-|"; | |
104 NSArray* constraintFormats = @[ | |
105 verticalConstraint, | |
106 @"|-[_roomLabel]", | |
107 @"|-[_roomField(kRoomFieldWidth)]", | |
108 @"|-[_scrollView(remoteViewWidth)]-|", | |
109 @"|-[_remoteVideoView(remoteViewWidth)]-|", | |
110 ]; | |
111 for (NSString* constraintFormat in constraintFormats) { | |
112 NSArray* constraints = | |
113 [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat | |
114 options:0 | |
115 metrics:metrics | |
116 views:viewsDictionary]; | |
117 for (NSLayoutConstraint* constraint in constraints) { | |
118 [self addConstraint:constraint]; | |
119 } | |
120 } | |
121 [super updateConstraints]; | |
122 } | |
123 | |
124 - (void)displayLogMessage:(NSString*)message { | |
125 _logView.string = | |
126 [NSString stringWithFormat:@"%@%@\n", _logView.string, message]; | |
127 NSRange range = NSMakeRange([_logView.string length], 0); | |
128 [_logView scrollRangeToVisible:range]; | |
129 } | |
130 | |
131 #pragma mark - NSControl delegate | |
132 | |
133 - (void)controlTextDidEndEditing:(NSNotification*)notification { | |
134 NSDictionary* userInfo = [notification userInfo]; | |
135 NSInteger textMovement = [userInfo[@"NSTextMovement"] intValue]; | |
136 if (textMovement == NSReturnTextMovement) { | |
137 [self.delegate appRTCMainView:self didEnterRoomId:_roomField.stringValue]; | |
138 } | |
139 } | |
140 | |
141 #pragma mark - RTCNSGLVideoViewDelegate | |
142 | |
143 - (void)videoView:(RTCNSGLVideoView*)videoView | |
144 didChangeVideoSize:(NSSize)size { | |
145 if (videoView == _remoteVideoView) { | |
146 _remoteVideoSize = size; | |
147 } else if (videoView == _localVideoView) { | |
148 _localVideoSize = size; | |
149 } else { | |
150 return; | |
151 } | |
152 [self setNeedsUpdateConstraints:YES]; | |
153 } | |
154 | |
155 #pragma mark - Private | |
156 | |
157 - (void)setupViews { | |
158 NSParameterAssert([[self subviews] count] == 0); | |
159 | |
160 _roomLabel = [[NSTextField alloc] initWithFrame:NSZeroRect]; | |
161 [_roomLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
162 [_roomLabel setBezeled:NO]; | |
163 [_roomLabel setDrawsBackground:NO]; | |
164 [_roomLabel setEditable:NO]; | |
165 [_roomLabel setStringValue:@"Enter AppRTC room id:"]; | |
166 [self addSubview:_roomLabel]; | |
167 | |
168 _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect]; | |
169 [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
170 [self addSubview:_roomField]; | |
171 [_roomField setEditable:YES]; | |
172 [_roomField setDelegate:self]; | |
173 | |
174 _logView = [[NSTextView alloc] initWithFrame:NSZeroRect]; | |
175 [_logView setMinSize:NSMakeSize(0, kLogViewHeight)]; | |
176 [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; | |
177 [_logView setVerticallyResizable:YES]; | |
178 [_logView setAutoresizingMask:NSViewWidthSizable]; | |
179 NSTextContainer* textContainer = [_logView textContainer]; | |
180 NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX); | |
181 [textContainer setContainerSize:containerSize]; | |
182 [textContainer setWidthTracksTextView:YES]; | |
183 [_logView setEditable:NO]; | |
184 | |
185 _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect]; | |
186 [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
187 [_scrollView setHasVerticalScroller:YES]; | |
188 [_scrollView setDocumentView:_logView]; | |
189 [self addSubview:_scrollView]; | |
190 | |
191 NSOpenGLPixelFormatAttribute attributes[] = { | |
192 NSOpenGLPFADoubleBuffer, | |
193 NSOpenGLPFADepthSize, 24, | |
194 NSOpenGLPFAOpenGLProfile, | |
195 NSOpenGLProfileVersion3_2Core, | |
196 0 | |
197 }; | |
198 NSOpenGLPixelFormat* pixelFormat = | |
199 [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; | |
200 _remoteVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect | |
201 pixelFormat:pixelFormat]; | |
202 [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
203 _remoteVideoView.delegate = self; | |
204 [self addSubview:_remoteVideoView]; | |
205 | |
206 // TODO(tkchin): create local video view. | |
207 // https://code.google.com/p/webrtc/issues/detail?id=3417. | |
208 } | |
209 | |
210 - (NSSize)remoteVideoViewSize { | |
211 if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) { | |
212 return _remoteVideoSize; | |
213 } else { | |
214 return NSMakeSize(kContentWidth, kContentHeight); | |
215 } | |
216 } | |
217 | |
218 - (NSSize)localVideoViewSize { | |
219 return NSZeroSize; | |
220 } | |
221 | |
222 @end | |
223 | |
224 @interface APPRTCViewController () | |
225 <ARDAppClientDelegate, APPRTCMainViewDelegate> | |
226 @property(nonatomic, readonly) APPRTCMainView* mainView; | |
227 @end | |
228 | |
229 @implementation APPRTCViewController { | |
230 ARDAppClient* _client; | |
231 RTCVideoTrack* _localVideoTrack; | |
232 RTCVideoTrack* _remoteVideoTrack; | |
233 } | |
234 | |
235 - (void)dealloc { | |
236 [self disconnect]; | |
237 } | |
238 | |
239 - (void)loadView { | |
240 APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect]; | |
241 [view setTranslatesAutoresizingMaskIntoConstraints:NO]; | |
242 view.delegate = self; | |
243 self.view = view; | |
244 } | |
245 | |
246 - (void)windowWillClose:(NSNotification*)notification { | |
247 [self disconnect]; | |
248 } | |
249 | |
250 #pragma mark - ARDAppClientDelegate | |
251 | |
252 - (void)appClient:(ARDAppClient *)client | |
253 didChangeState:(ARDAppClientState)state { | |
254 switch (state) { | |
255 case kARDAppClientStateConnected: | |
256 NSLog(@"Client connected."); | |
257 break; | |
258 case kARDAppClientStateConnecting: | |
259 NSLog(@"Client connecting."); | |
260 break; | |
261 case kARDAppClientStateDisconnected: | |
262 NSLog(@"Client disconnected."); | |
263 [self resetUI]; | |
264 _client = nil; | |
265 break; | |
266 } | |
267 } | |
268 | |
269 - (void)appClient:(ARDAppClient *)client | |
270 didChangeConnectionState:(RTCICEConnectionState)state { | |
271 } | |
272 | |
273 - (void)appClient:(ARDAppClient *)client | |
274 didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack { | |
275 _localVideoTrack = localVideoTrack; | |
276 } | |
277 | |
278 - (void)appClient:(ARDAppClient *)client | |
279 didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { | |
280 _remoteVideoTrack = remoteVideoTrack; | |
281 [_remoteVideoTrack addRenderer:self.mainView.remoteVideoView]; | |
282 } | |
283 | |
284 - (void)appClient:(ARDAppClient *)client | |
285 didError:(NSError *)error { | |
286 [self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]]; | |
287 [self disconnect]; | |
288 } | |
289 | |
290 #pragma mark - APPRTCMainViewDelegate | |
291 | |
292 - (void)appRTCMainView:(APPRTCMainView*)mainView | |
293 didEnterRoomId:(NSString*)roomId { | |
294 [_client disconnect]; | |
295 ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self]; | |
296 [client connectToRoomWithId:roomId options:nil]; | |
297 _client = client; | |
298 } | |
299 | |
300 #pragma mark - Private | |
301 | |
302 - (APPRTCMainView*)mainView { | |
303 return (APPRTCMainView*)self.view; | |
304 } | |
305 | |
306 - (void)showAlertWithMessage:(NSString*)message { | |
307 NSAlert* alert = [[NSAlert alloc] init]; | |
308 [alert setMessageText:message]; | |
309 [alert runModal]; | |
310 } | |
311 | |
312 - (void)resetUI { | |
313 [_remoteVideoTrack removeRenderer:self.mainView.remoteVideoView]; | |
314 _remoteVideoTrack = nil; | |
315 [self.mainView.remoteVideoView renderFrame:nil]; | |
316 } | |
317 | |
318 - (void)disconnect { | |
319 [self resetUI]; | |
320 [_client disconnect]; | |
321 } | |
322 | |
323 @end | |
OLD | NEW |