blob: a4a0bd33d1b8a5a320aaf4432d7cbcd8904bf10e [file] [log] [blame]
tkchin@webrtc.orgacca6752014-05-30 22:26:06 +00001/*
2 * libjingle
3 * Copyright 2013, 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#if !defined(__has_feature) || !__has_feature(objc_arc)
29#error "This file requires ARC support."
30#endif
31
32#import "APPRTCViewController.h"
33
34#import <AVFoundation/AVFoundation.h>
35#import "APPRTCConnectionManager.h"
36#import "RTCEAGLVideoView.h"
37
38// Padding space for local video view with its parent.
39static CGFloat const kLocalViewPadding = 20;
40
41@interface APPRTCViewController ()
42<APPRTCConnectionManagerDelegate, APPRTCLogger, RTCEAGLVideoViewDelegate>
43@property(nonatomic, assign) UIInterfaceOrientation statusBarOrientation;
44@property(nonatomic, strong) RTCEAGLVideoView* localVideoView;
45@property(nonatomic, strong) RTCEAGLVideoView* remoteVideoView;
46@end
47
48@implementation APPRTCViewController {
49 APPRTCConnectionManager* _connectionManager;
50 CGSize _localVideoSize;
51 CGSize _remoteVideoSize;
52}
53
54- (instancetype)initWithNibName:(NSString*)nibName
55 bundle:(NSBundle*)bundle {
56 if (self = [super initWithNibName:nibName bundle:bundle]) {
57 _connectionManager =
58 [[APPRTCConnectionManager alloc] initWithDelegate:self
59 logger:self];
60 }
61 return self;
62}
63
64- (void)viewDidLoad {
65 [super viewDidLoad];
66 self.statusBarOrientation =
67 [UIApplication sharedApplication].statusBarOrientation;
68 self.roomInput.delegate = self;
69 [self.roomInput becomeFirstResponder];
70}
71
72- (void)viewDidLayoutSubviews {
73 if (self.statusBarOrientation !=
74 [UIApplication sharedApplication].statusBarOrientation) {
75 self.statusBarOrientation =
76 [UIApplication sharedApplication].statusBarOrientation;
77 [[NSNotificationCenter defaultCenter]
78 postNotificationName:@"StatusBarOrientationDidChange"
79 object:nil];
80 }
81}
82
83- (void)applicationWillResignActive:(UIApplication*)application {
84 [self logMessage:@"Application lost focus, connection broken."];
85 [self disconnect];
86}
87
88#pragma mark - APPRTCConnectionManagerDelegate
89
90- (void)connectionManager:(APPRTCConnectionManager*)manager
91 didReceiveLocalVideoTrack:(RTCVideoTrack*)localVideoTrack {
92 self.localVideoView.hidden = NO;
93 self.localVideoView.videoTrack = localVideoTrack;
94}
95
96- (void)connectionManager:(APPRTCConnectionManager*)manager
97 didReceiveRemoteVideoTrack:(RTCVideoTrack*)remoteVideoTrack {
98 self.remoteVideoView.videoTrack = remoteVideoTrack;
99}
100
101- (void)connectionManagerDidReceiveHangup:(APPRTCConnectionManager*)manager {
102 [self showAlertWithMessage:@"Remote hung up."];
103 [self disconnect];
104}
105
106- (void)connectionManager:(APPRTCConnectionManager*)manager
107 didErrorWithMessage:(NSString*)message {
108 [self showAlertWithMessage:message];
109 [self disconnect];
110}
111
112#pragma mark - APPRTCLogger
113
114- (void)logMessage:(NSString*)message {
115 dispatch_async(dispatch_get_main_queue(), ^{
116 NSString* output =
117 [NSString stringWithFormat:@"%@\n%@", self.logView.text, message];
118 self.logView.text = output;
119 [self.logView
120 scrollRangeToVisible:NSMakeRange([self.logView.text length], 0)];
121 });
122}
123
124#pragma mark - RTCEAGLVideoViewDelegate
125
126- (void)videoView:(RTCEAGLVideoView*)videoView
127 didChangeVideoSize:(CGSize)size {
128 if (videoView == self.localVideoView) {
129 _localVideoSize = size;
130 } else if (videoView == self.remoteVideoView) {
131 _remoteVideoSize = size;
132 } else {
133 NSParameterAssert(NO);
134 }
135 [self updateVideoViewLayout];
136}
137
138#pragma mark - UITextFieldDelegate
139
140- (void)textFieldDidEndEditing:(UITextField*)textField {
141 NSString* room = textField.text;
142 if ([room length] == 0) {
143 return;
144 }
145 textField.hidden = YES;
146 self.instructionsView.hidden = YES;
147 self.logView.hidden = NO;
148 NSString* url =
149 [NSString stringWithFormat:@"https://apprtc.appspot.com/?r=%@", room];
150 [_connectionManager connectToRoomWithURL:[NSURL URLWithString:url]];
151 [self setupCaptureSession];
152}
153
154- (BOOL)textFieldShouldReturn:(UITextField*)textField {
155 // There is no other control that can take focus, so manually resign focus
156 // when return (Join) is pressed to trigger |textFieldDidEndEditing|.
157 [textField resignFirstResponder];
158 return YES;
159}
160
161#pragma mark - Private
162
163- (void)disconnect {
164 [self resetUI];
165 [_connectionManager disconnect];
166}
167
168- (void)showAlertWithMessage:(NSString*)message {
169 UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil
170 message:message
171 delegate:nil
172 cancelButtonTitle:@"OK"
173 otherButtonTitles:nil];
174 [alertView show];
175}
176
177- (void)resetUI {
178 [self.roomInput resignFirstResponder];
179 self.roomInput.text = nil;
180 self.roomInput.hidden = NO;
181 self.instructionsView.hidden = NO;
182 self.logView.hidden = YES;
183 self.logView.text = nil;
184 self.blackView.hidden = YES;
185 [self.remoteVideoView removeFromSuperview];
186 self.remoteVideoView = nil;
187 [self.localVideoView removeFromSuperview];
188 self.localVideoView = nil;
189}
190
191- (void)setupCaptureSession {
192 self.blackView.hidden = NO;
193 self.remoteVideoView =
194 [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds];
195 self.remoteVideoView.delegate = self;
196 self.remoteVideoView.transform = CGAffineTransformMakeScale(-1, 1);
197 [self.blackView addSubview:self.remoteVideoView];
198
199 self.localVideoView =
200 [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds];
201 self.localVideoView.delegate = self;
202 [self.blackView addSubview:self.localVideoView];
203 [self updateVideoViewLayout];
204}
205
206- (void)updateVideoViewLayout {
207 // TODO(tkchin): handle rotation.
208 CGSize defaultAspectRatio = CGSizeMake(4, 3);
209 CGSize localAspectRatio = CGSizeEqualToSize(_localVideoSize, CGSizeZero) ?
210 defaultAspectRatio : _localVideoSize;
211 CGSize remoteAspectRatio = CGSizeEqualToSize(_remoteVideoSize, CGSizeZero) ?
212 defaultAspectRatio : _remoteVideoSize;
213
214 CGRect remoteVideoFrame =
215 AVMakeRectWithAspectRatioInsideRect(remoteAspectRatio,
216 self.blackView.bounds);
217 self.remoteVideoView.frame = remoteVideoFrame;
218
219 CGRect localVideoFrame =
220 AVMakeRectWithAspectRatioInsideRect(localAspectRatio,
221 self.blackView.bounds);
222 localVideoFrame.size.width = localVideoFrame.size.width / 3;
223 localVideoFrame.size.height = localVideoFrame.size.height / 3;
224 localVideoFrame.origin.x = CGRectGetMaxX(self.blackView.bounds)
225 - localVideoFrame.size.width - kLocalViewPadding;
226 localVideoFrame.origin.y = CGRectGetMaxY(self.blackView.bounds)
227 - localVideoFrame.size.height - kLocalViewPadding;
228 self.localVideoView.frame = localVideoFrame;
229}
230
231@end