blob: 9d36d9b2bed146186be1e5e81863149020cc4044 [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
denicija124a6fc2017-03-31 02:47:29 -070015#import "WebRTC/RTCMTLNSVideoView.h"
tkchin9eeb6242016-04-27 01:54:20 -070016#import "WebRTC/RTCNSGLVideoView.h"
17#import "WebRTC/RTCVideoTrack.h"
hjon79858f82016-03-13 22:08:26 -070018
tkchin@webrtc.org87776a82014-12-09 19:32:35 +000019#import "ARDAppClient.h"
sakalc522e752017-04-05 12:17:48 -070020#import "ARDCaptureController.h"
sakalc4adacf2017-03-28 01:22:48 -070021#import "ARDSettingsModel.h"
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000022
denicija647915f2016-10-20 01:46:41 -070023static NSUInteger const kContentWidth = 900;
24static NSUInteger const kRoomFieldWidth = 200;
25static NSUInteger const kActionItemHeight = 30;
26static NSUInteger const kBottomViewHeight = 200;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000027
28@class APPRTCMainView;
29@protocol APPRTCMainViewDelegate
30
31- (void)appRTCMainView:(APPRTCMainView*)mainView
denicija647915f2016-10-20 01:46:41 -070032 didEnterRoomId:(NSString*)roomId
33 loopback:(BOOL)isLoopback;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000034
35@end
36
37@interface APPRTCMainView : NSView
38
39@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
denicija124a6fc2017-03-31 02:47:29 -070040@property(nonatomic, readonly) NSView<RTCVideoRenderer>* localVideoView;
41@property(nonatomic, readonly) NSView<RTCVideoRenderer>* remoteVideoView;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000042
43- (void)displayLogMessage:(NSString*)message;
44
45@end
46
47@interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate>
48@end
49@implementation APPRTCMainView {
50 NSScrollView* _scrollView;
denicija647915f2016-10-20 01:46:41 -070051 NSView* _actionItemsView;
52 NSButton* _connectButton;
53 NSButton* _loopbackButton;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000054 NSTextField* _roomField;
55 NSTextView* _logView;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000056 CGSize _localVideoSize;
57 CGSize _remoteVideoSize;
58}
59
tkchin2ddfdba2016-08-07 21:37:45 -070060@synthesize delegate = _delegate;
61@synthesize localVideoView = _localVideoView;
62@synthesize remoteVideoView = _remoteVideoView;
63
denicija647915f2016-10-20 01:46:41 -070064
65- (void)displayLogMessage:(NSString *)message {
66 _logView.string =
67 [NSString stringWithFormat:@"%@%@\n", _logView.string, message];
68 NSRange range = NSMakeRange(_logView.string.length, 0);
69 [_logView scrollRangeToVisible:range];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000070}
71
denicija647915f2016-10-20 01:46:41 -070072#pragma mark - Private
73
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000074- (instancetype)initWithFrame:(NSRect)frame {
75 if (self = [super initWithFrame:frame]) {
76 [self setupViews];
77 }
78 return self;
79}
80
denicija647915f2016-10-20 01:46:41 -070081+ (BOOL)requiresConstraintBasedLayout {
82 return YES;
83}
84
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000085- (void)updateConstraints {
86 NSParameterAssert(
denicija647915f2016-10-20 01:46:41 -070087 _roomField != nil &&
88 _scrollView != nil &&
89 _remoteVideoView != nil &&
90 _localVideoView != nil &&
91 _actionItemsView!= nil &&
92 _connectButton != nil &&
93 _loopbackButton != nil);
94
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000095 [self removeConstraints:[self constraints]];
96 NSDictionary* viewsDictionary =
denicija647915f2016-10-20 01:46:41 -070097 NSDictionaryOfVariableBindings(_roomField,
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +000098 _scrollView,
kthelgason314bc5f2016-08-31 10:23:27 -070099 _remoteVideoView,
denicija647915f2016-10-20 01:46:41 -0700100 _localVideoView,
101 _actionItemsView,
102 _connectButton,
103 _loopbackButton);
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000104
105 NSSize remoteViewSize = [self remoteVideoViewSize];
106 NSDictionary* metrics = @{
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000107 @"remoteViewWidth" : @(remoteViewSize.width),
108 @"remoteViewHeight" : @(remoteViewSize.height),
denicija647915f2016-10-20 01:46:41 -0700109 @"kBottomViewHeight" : @(kBottomViewHeight),
110 @"localViewHeight" : @(remoteViewSize.height / 3),
111 @"localViewWidth" : @(remoteViewSize.width / 3),
112 @"kRoomFieldWidth" : @(kRoomFieldWidth),
113 @"kActionItemHeight" : @(kActionItemHeight)
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000114 };
115 // Declare this separately to avoid compiler warning about splitting string
116 // within an NSArray expression.
denicija647915f2016-10-20 01:46:41 -0700117 NSString* verticalConstraintLeft =
118 @"V:|-[_remoteVideoView(remoteViewHeight)]-[_scrollView(kBottomViewHeight)]-|";
119 NSString* verticalConstraintRight =
120 @"V:|-[_remoteVideoView(remoteViewHeight)]-[_actionItemsView(kBottomViewHeight)]-|";
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000121 NSArray* constraintFormats = @[
denicija647915f2016-10-20 01:46:41 -0700122 verticalConstraintLeft,
123 verticalConstraintRight,
124 @"H:|-[_remoteVideoView(remoteViewWidth)]-|",
125 @"V:|-[_localVideoView(localViewHeight)]",
126 @"H:|-[_localVideoView(localViewWidth)]",
127 @"H:|-[_scrollView(==_actionItemsView)]-[_actionItemsView]-|"
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000128 ];
denicija647915f2016-10-20 01:46:41 -0700129
130 NSArray* actionItemsConstraints = @[
131 @"H:|-[_roomField(kRoomFieldWidth)]-[_loopbackButton(kRoomFieldWidth)]",
132 @"H:|-[_connectButton(kRoomFieldWidth)]",
133 @"V:|-[_roomField(kActionItemHeight)]-[_connectButton(kActionItemHeight)]",
134 @"V:|-[_loopbackButton(kActionItemHeight)]",
135 ];
136
137 [APPRTCMainView addConstraints:constraintFormats
138 toView:self
139 viewsDictionary:viewsDictionary
140 metrics:metrics];
141 [APPRTCMainView addConstraints:actionItemsConstraints
142 toView:_actionItemsView
143 viewsDictionary:viewsDictionary
144 metrics:metrics];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000145 [super updateConstraints];
146}
147
denicija647915f2016-10-20 01:46:41 -0700148#pragma mark - Constraints helper
149
150+ (void)addConstraints:(NSArray*)constraints toView:(NSView*)view
151 viewsDictionary:(NSDictionary*)viewsDictionary
152 metrics:(NSDictionary*)metrics {
153 for (NSString* constraintFormat in constraints) {
154 NSArray* constraints =
155 [NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
156 options:0
157 metrics:metrics
158 views:viewsDictionary];
159 for (NSLayoutConstraint* constraint in constraints) {
160 [view addConstraint:constraint];
161 }
162 }
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000163}
164
denicija647915f2016-10-20 01:46:41 -0700165#pragma mark - Control actions
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000166
denicija647915f2016-10-20 01:46:41 -0700167- (void)startCall:(id)sender {
168 NSString* roomString = _roomField.stringValue;
169 // Generate room id for loopback options.
170 if (_loopbackButton.intValue && [roomString isEqualToString:@""]) {
171 roomString = [NSUUID UUID].UUIDString;
172 roomString = [roomString stringByReplacingOccurrencesOfString:@"-" withString:@""];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000173 }
denicija647915f2016-10-20 01:46:41 -0700174 [self.delegate appRTCMainView:self
175 didEnterRoomId:roomString
176 loopback:_loopbackButton.intValue];
denicija124a6fc2017-03-31 02:47:29 -0700177 [self setNeedsUpdateConstraints:YES];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000178}
179
180#pragma mark - RTCNSGLVideoViewDelegate
181
182- (void)videoView:(RTCNSGLVideoView*)videoView
183 didChangeVideoSize:(NSSize)size {
184 if (videoView == _remoteVideoView) {
185 _remoteVideoSize = size;
186 } else if (videoView == _localVideoView) {
187 _localVideoSize = size;
188 } else {
189 return;
190 }
denicija647915f2016-10-20 01:46:41 -0700191
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000192 [self setNeedsUpdateConstraints:YES];
193}
194
195#pragma mark - Private
196
197- (void)setupViews {
198 NSParameterAssert([[self subviews] count] == 0);
199
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000200 _logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
denicija647915f2016-10-20 01:46:41 -0700201 [_logView setMinSize:NSMakeSize(0, kBottomViewHeight)];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000202 [_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
203 [_logView setVerticallyResizable:YES];
204 [_logView setAutoresizingMask:NSViewWidthSizable];
205 NSTextContainer* textContainer = [_logView textContainer];
206 NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
207 [textContainer setContainerSize:containerSize];
208 [textContainer setWidthTracksTextView:YES];
209 [_logView setEditable:NO];
210
denicija647915f2016-10-20 01:46:41 -0700211 [self setupActionItemsView];
212
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000213 _scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
214 [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
215 [_scrollView setHasVerticalScroller:YES];
216 [_scrollView setDocumentView:_logView];
217 [self addSubview:_scrollView];
218
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000219
denicija124a6fc2017-03-31 02:47:29 -0700220// NOTE (daniela): Ignoring Clang diagonstic here.
221// We're performing run time check to make sure class is available on runtime.
222// If not we're providing sensible default.
223#pragma clang diagnostic push
224#pragma clang diagnostic ignored "-Wpartial-availability"
225 if ([RTCMTLNSVideoView class]) {
226 _remoteVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];
227 _localVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];
228 } else {
229 NSOpenGLPixelFormatAttribute attributes[] = {
230 NSOpenGLPFADoubleBuffer,
231 NSOpenGLPFADepthSize, 24,
232 NSOpenGLPFAOpenGLProfile,
233 NSOpenGLProfileVersion3_2Core,
234 0
235 };
236 NSOpenGLPixelFormat* pixelFormat =
237 [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
238
239 RTCNSGLVideoView* remote =
240 [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];
241 remote.delegate = self;
242 _remoteVideoView = remote;
243
244 RTCNSGLVideoView* local =
245 [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];
246 local.delegate = self;
247 _localVideoView = local;
248 }
249#pragma clang diagnostic pop
250
251 [_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
252 [self addSubview:_remoteVideoView];
kthelgason314bc5f2016-08-31 10:23:27 -0700253 [_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
kthelgason314bc5f2016-08-31 10:23:27 -0700254 [self addSubview:_localVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000255}
256
denicija647915f2016-10-20 01:46:41 -0700257- (void)setupActionItemsView {
258 _actionItemsView = [[NSView alloc] initWithFrame:NSZeroRect];
259 [_actionItemsView setTranslatesAutoresizingMaskIntoConstraints:NO];
260 [self addSubview:_actionItemsView];
261
262 _roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
263 [_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
magjeda445b9b2017-02-20 07:56:53 -0800264 [[_roomField cell] setPlaceholderString: @"Enter AppRTC room id"];
denicija647915f2016-10-20 01:46:41 -0700265 [_actionItemsView addSubview:_roomField];
266 [_roomField setEditable:YES];
267
268 _connectButton = [[NSButton alloc] initWithFrame:NSZeroRect];
269 [_connectButton setTranslatesAutoresizingMaskIntoConstraints:NO];
270 _connectButton.title = @"Start call";
271 _connectButton.bezelStyle = NSRoundedBezelStyle;
272 _connectButton.target = self;
273 _connectButton.action = @selector(startCall:);
274 [_actionItemsView addSubview:_connectButton];
275
276 _loopbackButton = [[NSButton alloc] initWithFrame:NSZeroRect];
277 [_loopbackButton setTranslatesAutoresizingMaskIntoConstraints:NO];
278 _loopbackButton.title = @"Loopback";
279 [_loopbackButton setButtonType:NSSwitchButton];
280 [_actionItemsView addSubview:_loopbackButton];
281}
282
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000283- (NSSize)remoteVideoViewSize {
denicija647915f2016-10-20 01:46:41 -0700284 if (!_remoteVideoView.bounds.size.width) {
285 return NSMakeSize(kContentWidth, 0);
286 }
287 NSInteger width = MAX(_remoteVideoView.bounds.size.width, kContentWidth);
kthelgason314bc5f2016-08-31 10:23:27 -0700288 NSInteger height = (width/16) * 9;
289 return NSMakeSize(width, height);
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000290}
291
292@end
293
294@interface APPRTCViewController ()
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000295 <ARDAppClientDelegate, APPRTCMainViewDelegate>
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000296@property(nonatomic, readonly) APPRTCMainView* mainView;
297@end
298
299@implementation APPRTCViewController {
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000300 ARDAppClient* _client;
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000301 RTCVideoTrack* _localVideoTrack;
302 RTCVideoTrack* _remoteVideoTrack;
sakalc522e752017-04-05 12:17:48 -0700303 ARDCaptureController* _captureController;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000304}
305
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000306- (void)dealloc {
307 [self disconnect];
308}
309
denicija647915f2016-10-20 01:46:41 -0700310- (void)viewDidAppear {
311 [super viewDidAppear];
312 [self displayUsageInstructions];
313}
314
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000315- (void)loadView {
316 APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
317 [view setTranslatesAutoresizingMaskIntoConstraints:NO];
318 view.delegate = self;
319 self.view = view;
320}
321
322- (void)windowWillClose:(NSNotification*)notification {
323 [self disconnect];
324}
325
denicija647915f2016-10-20 01:46:41 -0700326#pragma mark - Usage
327
328- (void)displayUsageInstructions {
329 [self.mainView displayLogMessage:
330 @"To start call:\n"
331 @"• Enter AppRTC room id (not neccessary for loopback)\n"
332 @"• Start call"];
333}
334
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000335#pragma mark - ARDAppClientDelegate
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000336
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000337- (void)appClient:(ARDAppClient *)client
338 didChangeState:(ARDAppClientState)state {
339 switch (state) {
340 case kARDAppClientStateConnected:
denicija647915f2016-10-20 01:46:41 -0700341 [self.mainView displayLogMessage:@"Client connected."];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000342 break;
343 case kARDAppClientStateConnecting:
denicija647915f2016-10-20 01:46:41 -0700344 [self.mainView displayLogMessage:@"Client connecting."];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000345 break;
346 case kARDAppClientStateDisconnected:
denicija647915f2016-10-20 01:46:41 -0700347 [self.mainView displayLogMessage:@"Client disconnected."];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000348 [self resetUI];
349 _client = nil;
350 break;
351 }
352}
353
354- (void)appClient:(ARDAppClient *)client
hjon79858f82016-03-13 22:08:26 -0700355 didChangeConnectionState:(RTCIceConnectionState)state {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000356}
357
sakalc522e752017-04-05 12:17:48 -0700358- (void)appClient:(ARDAppClient*)client
359 didCreateLocalCapturer:(RTCCameraVideoCapturer*)localCapturer {
360 _captureController =
361 [[ARDCaptureController alloc] initWithCapturer:localCapturer
362 settings:[[ARDSettingsModel alloc] init]];
363 [_captureController startCapture];
364}
365
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34 +0000366- (void)appClient:(ARDAppClient *)client
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000367 didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000368 _localVideoTrack = localVideoTrack;
kthelgason314bc5f2016-08-31 10:23:27 -0700369 [_localVideoTrack addRenderer:self.mainView.localVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000370}
371
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000372- (void)appClient:(ARDAppClient *)client
373 didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000374 _remoteVideoTrack = remoteVideoTrack;
375 [_remoteVideoTrack addRenderer:self.mainView.remoteVideoView];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000376}
377
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000378- (void)appClient:(ARDAppClient *)client
379 didError:(NSError *)error {
380 [self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000381 [self disconnect];
382}
383
Zeke Chind3325802015-08-14 11:00:02 -0700384- (void)appClient:(ARDAppClient *)client
385 didGetStats:(NSArray *)stats {
386}
387
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000388#pragma mark - APPRTCMainViewDelegate
389
390- (void)appRTCMainView:(APPRTCMainView*)mainView
denicija647915f2016-10-20 01:46:41 -0700391 didEnterRoomId:(NSString*)roomId
392 loopback:(BOOL)isLoopback {
393
394 if ([roomId isEqualToString:@""]) {
395 [self.mainView displayLogMessage:@"Missing room id"];
396 return;
397 }
398
sakalc522e752017-04-05 12:17:48 -0700399 [self disconnect];
sakalc4adacf2017-03-28 01:22:48 -0700400 ARDAppClient* client = [[ARDAppClient alloc] initWithDelegate:self];
tkchinab1293a2016-08-30 12:35:05 -0700401 [client connectToRoomWithId:roomId
sakalc4adacf2017-03-28 01:22:48 -0700402 settings:[[ARDSettingsModel alloc] init] // Use default settings.
denicija647915f2016-10-20 01:46:41 -0700403 isLoopback:isLoopback
tkchinab1293a2016-08-30 12:35:05 -0700404 isAudioOnly:NO
405 shouldMakeAecDump:NO
406 shouldUseLevelControl:NO];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000407 _client = client;
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000408}
409
410#pragma mark - Private
411
412- (APPRTCMainView*)mainView {
413 return (APPRTCMainView*)self.view;
414}
415
416- (void)showAlertWithMessage:(NSString*)message {
417 NSAlert* alert = [[NSAlert alloc] init];
418 [alert setMessageText:message];
419 [alert runModal];
420}
421
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000422- (void)resetUI {
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000423 [_remoteVideoTrack removeRenderer:self.mainView.remoteVideoView];
kthelgason314bc5f2016-08-31 10:23:27 -0700424 [_localVideoTrack removeRenderer:self.mainView.localVideoView];
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000425 _remoteVideoTrack = nil;
kthelgason314bc5f2016-08-31 10:23:27 -0700426 _localVideoTrack = nil;
tkchin@webrtc.org81257442014-11-04 23:06:15 +0000427 [self.mainView.remoteVideoView renderFrame:nil];
kthelgason314bc5f2016-08-31 10:23:27 -0700428 [self.mainView.localVideoView renderFrame:nil];
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000429}
430
431- (void)disconnect {
432 [self resetUI];
sakalc522e752017-04-05 12:17:48 -0700433 [_captureController stopCapture];
434 _captureController = nil;
tkchin@webrtc.org87776a82014-12-09 19:32:35 +0000435 [_client disconnect];
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +0000436}
437
438@end