diff --git a/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm b/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm index 845a5f8f8f..fbaea62fd8 100644 --- a/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm +++ b/talk/app/webrtc/objc/RTCPeerConnectionFactory.mm @@ -82,9 +82,11 @@ - (id)init { if ((self = [super init])) { _signalingThread.reset(new rtc::Thread()); - NSAssert(_signalingThread->Start(), @"Failed to start signaling thread."); + BOOL result = _signalingThread->Start(); + NSAssert(result, @"Failed to start signaling thread."); _workerThread.reset(new rtc::Thread()); - NSAssert(_workerThread->Start(), @"Failed to start worker thread."); + result = _workerThread->Start(); + NSAssert(result, @"Failed to start worker thread."); _nativeFactory = webrtc::CreatePeerConnectionFactory( _signalingThread.get(), _workerThread.get(), NULL, NULL, NULL); NSAssert(_nativeFactory, @"Failed to initialize PeerConnectionFactory!"); diff --git a/talk/app/webrtc/objc/RTCVideoTrack.mm b/talk/app/webrtc/objc/RTCVideoTrack.mm index 959bc6d05c..fd5fb8cb1a 100644 --- a/talk/app/webrtc/objc/RTCVideoTrack.mm +++ b/talk/app/webrtc/objc/RTCVideoTrack.mm @@ -47,6 +47,12 @@ return self; } +- (void)dealloc { + for (RTCVideoRendererAdapter *adapter in _adapters) { + self.nativeVideoTrack->RemoveRenderer(adapter.nativeVideoRenderer); + } +} + - (void)addRenderer:(id)renderer { // Make sure we don't have this renderer yet. for (RTCVideoRendererAdapter* adapter in _adapters) { diff --git a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m b/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m deleted file mode 100644 index e6e19b0f97..0000000000 --- a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.m +++ /dev/null @@ -1,237 +0,0 @@ -/* - * libjingle - * Copyright 2013, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -#import "APPRTCViewController.h" - -#import -#import "ARDAppClient.h" -#import "RTCEAGLVideoView.h" -#import "RTCVideoTrack.h" - -// Padding space for local video view with its parent. -static CGFloat const kLocalViewPadding = 20; - -@interface APPRTCViewController () -@property(nonatomic, assign) UIInterfaceOrientation statusBarOrientation; -@property(nonatomic, strong) RTCEAGLVideoView* localVideoView; -@property(nonatomic, strong) RTCEAGLVideoView* remoteVideoView; -@end - -@implementation APPRTCViewController { - ARDAppClient *_client; - RTCVideoTrack* _localVideoTrack; - RTCVideoTrack* _remoteVideoTrack; - CGSize _localVideoSize; - CGSize _remoteVideoSize; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.remoteVideoView = - [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds]; - self.remoteVideoView.delegate = self; - self.remoteVideoView.transform = CGAffineTransformMakeScale(-1, 1); - [self.blackView addSubview:self.remoteVideoView]; - - self.localVideoView = - [[RTCEAGLVideoView alloc] initWithFrame:self.blackView.bounds]; - self.localVideoView.delegate = self; - [self.blackView addSubview:self.localVideoView]; - - self.statusBarOrientation = - [UIApplication sharedApplication].statusBarOrientation; - self.roomInput.delegate = self; - [self.roomInput becomeFirstResponder]; -} - -- (void)viewDidLayoutSubviews { - if (self.statusBarOrientation != - [UIApplication sharedApplication].statusBarOrientation) { - self.statusBarOrientation = - [UIApplication sharedApplication].statusBarOrientation; - [[NSNotificationCenter defaultCenter] - postNotificationName:@"StatusBarOrientationDidChange" - object:nil]; - } -} - -- (void)applicationWillResignActive:(UIApplication*)application { - [self disconnect]; -} - -#pragma mark - ARDAppClientDelegate - -- (void)appClient:(ARDAppClient *)client - didChangeState:(ARDAppClientState)state { - switch (state) { - case kARDAppClientStateConnected: - NSLog(@"Client connected."); - break; - case kARDAppClientStateConnecting: - NSLog(@"Client connecting."); - break; - case kARDAppClientStateDisconnected: - NSLog(@"Client disconnected."); - [self resetUI]; - break; - } -} - -- (void)appClient:(ARDAppClient *)client - didChangeConnectionState:(RTCICEConnectionState)state { -} - -- (void)appClient:(ARDAppClient *)client - didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack { - _localVideoTrack = localVideoTrack; - [_localVideoTrack addRenderer:self.localVideoView]; - self.localVideoView.hidden = NO; -} - -- (void)appClient:(ARDAppClient *)client - didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { - _remoteVideoTrack = remoteVideoTrack; - [_remoteVideoTrack addRenderer:self.remoteVideoView]; -} - -- (void)appClient:(ARDAppClient *)client - didError:(NSError *)error { - [self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]]; - [self disconnect]; -} - -#pragma mark - RTCEAGLVideoViewDelegate - -- (void)videoView:(RTCEAGLVideoView*)videoView - didChangeVideoSize:(CGSize)size { - if (videoView == self.localVideoView) { - _localVideoSize = size; - } else if (videoView == self.remoteVideoView) { - _remoteVideoSize = size; - } else { - NSParameterAssert(NO); - } - [self updateVideoViewLayout]; -} - -#pragma mark - UITextFieldDelegate - -- (void)textFieldDidEndEditing:(UITextField*)textField { - NSString* room = textField.text; - if ([room length] == 0) { - return; - } - textField.hidden = YES; - self.instructionsView.hidden = YES; - self.logView.hidden = NO; - [_client disconnect]; - // TODO(tkchin): support reusing the same client object. - _client = [[ARDAppClient alloc] initWithDelegate:self]; - [_client connectToRoomWithId:room options:nil]; - [self setupCaptureSession]; -} - -- (BOOL)textFieldShouldReturn:(UITextField*)textField { - // There is no other control that can take focus, so manually resign focus - // when return (Join) is pressed to trigger |textFieldDidEndEditing|. - [textField resignFirstResponder]; - return YES; -} - -#pragma mark - Private - -- (void)disconnect { - [self resetUI]; - [_client disconnect]; -} - -- (void)showAlertWithMessage:(NSString*)message { - UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil - message:message - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alertView show]; -} - -- (void)resetUI { - [self.roomInput resignFirstResponder]; - self.roomInput.text = nil; - self.roomInput.hidden = NO; - self.instructionsView.hidden = NO; - self.logView.hidden = YES; - self.logView.text = nil; - if (_localVideoTrack) { - [_localVideoTrack removeRenderer:self.localVideoView]; - _localVideoTrack = nil; - [self.localVideoView renderFrame:nil]; - } - if (_remoteVideoTrack) { - [_remoteVideoTrack removeRenderer:self.remoteVideoView]; - _remoteVideoTrack = nil; - [self.remoteVideoView renderFrame:nil]; - } - self.blackView.hidden = YES; -} - -- (void)setupCaptureSession { - self.blackView.hidden = NO; - [self updateVideoViewLayout]; -} - -- (void)updateVideoViewLayout { - // TODO(tkchin): handle rotation. - CGSize defaultAspectRatio = CGSizeMake(4, 3); - CGSize localAspectRatio = CGSizeEqualToSize(_localVideoSize, CGSizeZero) ? - defaultAspectRatio : _localVideoSize; - CGSize remoteAspectRatio = CGSizeEqualToSize(_remoteVideoSize, CGSizeZero) ? - defaultAspectRatio : _remoteVideoSize; - - CGRect remoteVideoFrame = - AVMakeRectWithAspectRatioInsideRect(remoteAspectRatio, - self.blackView.bounds); - self.remoteVideoView.frame = remoteVideoFrame; - - CGRect localVideoFrame = - AVMakeRectWithAspectRatioInsideRect(localAspectRatio, - self.blackView.bounds); - localVideoFrame.size.width = localVideoFrame.size.width / 3; - localVideoFrame.size.height = localVideoFrame.size.height / 3; - localVideoFrame.origin.x = CGRectGetMaxX(self.blackView.bounds) - - localVideoFrame.size.width - kLocalViewPadding; - localVideoFrame.origin.y = CGRectGetMaxY(self.blackView.bounds) - - localVideoFrame.size.height - kLocalViewPadding; - self.localVideoView.frame = localVideoFrame; -} - -@end diff --git a/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h b/talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.h similarity index 96% rename from talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h rename to talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.h index 196b39fd9d..9357425970 100644 --- a/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h +++ b/talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.h @@ -30,5 +30,5 @@ // The main application class of the AppRTCDemo iOS app demonstrating // interoperability between the Objective C implementation of PeerConnection // and the apprtc.appspot.com demo webapp. -@interface APPRTCAppDelegate : NSObject +@interface ARDAppDelegate : NSObject @end diff --git a/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m b/talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.m similarity index 71% rename from talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m rename to talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.m index 58963d53e9..4705a63a7a 100644 --- a/talk/examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m +++ b/talk/examples/objc/AppRTCDemo/ios/ARDAppDelegate.m @@ -25,41 +25,35 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import "APPRTCAppDelegate.h" +#import "ARDAppDelegate.h" -#import "APPRTCViewController.h" +#import "ARDMainViewController.h" #import "RTCPeerConnectionFactory.h" -@implementation APPRTCAppDelegate { - UIWindow* _window; +@implementation ARDAppDelegate { + UIWindow *_window; } #pragma mark - UIApplicationDelegate methods -- (BOOL)application:(UIApplication*)application - didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [RTCPeerConnectionFactory initializeSSL]; _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - APPRTCViewController* viewController = - [[APPRTCViewController alloc] initWithNibName:@"APPRTCViewController" - bundle:nil]; - _window.rootViewController = viewController; [_window makeKeyAndVisible]; + ARDMainViewController *viewController = [[ARDMainViewController alloc] init]; + _window.rootViewController = viewController; return YES; } -- (void)applicationWillResignActive:(UIApplication*)application { - [[self appRTCViewController] applicationWillResignActive:application]; +- (void)applicationWillResignActive:(UIApplication *)application { + ARDMainViewController *viewController = + (ARDMainViewController *)_window.rootViewController; + [viewController applicationWillResignActive:application]; } -- (void)applicationWillTerminate:(UIApplication*)application { +- (void)applicationWillTerminate:(UIApplication *)application { [RTCPeerConnectionFactory deinitializeSSL]; } -#pragma mark - Private - -- (APPRTCViewController*)appRTCViewController { - return (APPRTCViewController*)_window.rootViewController; -} - @end diff --git a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h b/talk/examples/objc/AppRTCDemo/ios/ARDMainView.h similarity index 75% rename from talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h rename to talk/examples/objc/AppRTCDemo/ios/ARDMainView.h index 5b10199c2c..da776021a4 100644 --- a/talk/examples/objc/AppRTCDemo/ios/APPRTCViewController.h +++ b/talk/examples/objc/AppRTCDemo/ios/ARDMainView.h @@ -1,6 +1,6 @@ /* * libjingle - * Copyright 2013, Google Inc. + * Copyright 2015, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -27,14 +27,18 @@ #import -// The view controller that is displayed when AppRTCDemo is loaded. -@interface APPRTCViewController : UIViewController +@class ARDMainView; -@property(weak, nonatomic) IBOutlet UITextField* roomInput; -@property(weak, nonatomic) IBOutlet UITextView* instructionsView; -@property(weak, nonatomic) IBOutlet UITextView* logView; -@property(weak, nonatomic) IBOutlet UIView* blackView; +@protocol ARDMainViewDelegate -- (void)applicationWillResignActive:(UIApplication*)application; +- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room; + +@end + +// The main view of AppRTCDemo. It contains an input field for entering a room +// name on apprtc to connect to. +@interface ARDMainView : UIView + +@property(nonatomic, weak) id delegate; @end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDMainView.m b/talk/examples/objc/AppRTCDemo/ios/ARDMainView.m new file mode 100644 index 0000000000..9fa0df0d3d --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDMainView.m @@ -0,0 +1,185 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ARDMainView.h" + +#import "UIImage+ARDUtilities.h" + +// TODO(tkchin): retrieve status bar height dynamically. +static CGFloat const kStatusBarHeight = 20; + +static CGFloat const kRoomTextButtonSize = 40; +static CGFloat const kRoomTextFieldHeight = 40; +static CGFloat const kRoomTextFieldMargin = 8; +static CGFloat const kAppLabelHeight = 20; + +@class ARDRoomTextField; +@protocol ARDRoomTextFieldDelegate +- (void)roomTextField:(ARDRoomTextField *)roomTextField + didInputRoom:(NSString *)room; +@end + +// Helper view that contains a text field and a clear button. +@interface ARDRoomTextField : UIView +@property(nonatomic, weak) id delegate; +@end + +@implementation ARDRoomTextField { + UITextField *_roomText; + UIButton *_clearButton; +} + +@synthesize delegate = _delegate; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + _roomText = [[UITextField alloc] initWithFrame:CGRectZero]; + _roomText.borderStyle = UITextBorderStyleNone; + _roomText.font = [UIFont fontWithName:@"Roboto" size:12]; + _roomText.placeholder = @"Room name"; + _roomText.delegate = self; + [_roomText addTarget:self + action:@selector(textFieldDidChange:) + forControlEvents:UIControlEventEditingChanged]; + [self addSubview:_roomText]; + + _clearButton = [UIButton buttonWithType:UIButtonTypeCustom]; + UIImage *image = [UIImage imageForName:@"ic_clear_black_24dp.png" + color:[UIColor colorWithWhite:0 alpha:.4]]; + + [_clearButton setImage:image forState:UIControlStateNormal]; + [_clearButton addTarget:self + action:@selector(onClear:) + forControlEvents:UIControlEventTouchUpInside]; + _clearButton.hidden = YES; + [self addSubview:_clearButton]; + + // Give rounded corners and a light gray border. + self.layer.borderWidth = 1; + self.layer.borderColor = [[UIColor lightGrayColor] CGColor]; + self.layer.cornerRadius = 2; + } + return self; +} + +- (void)layoutSubviews { + CGRect bounds = self.bounds; + _clearButton.frame = CGRectMake(CGRectGetMaxX(bounds) - kRoomTextButtonSize, + CGRectGetMinY(bounds), + kRoomTextButtonSize, + kRoomTextButtonSize); + _roomText.frame = CGRectMake( + CGRectGetMinX(bounds) + kRoomTextFieldMargin, + CGRectGetMinY(bounds), + CGRectGetMinX(_clearButton.frame) - CGRectGetMinX(bounds) - + kRoomTextFieldMargin, + kRoomTextFieldHeight); +} + +- (CGSize)sizeThatFits:(CGSize)size { + size.height = kRoomTextFieldHeight; + return size; +} + +#pragma mark - UITextFieldDelegate + +- (void)textFieldDidEndEditing:(UITextField *)textField { + [_delegate roomTextField:self didInputRoom:textField.text]; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + // There is no other control that can take focus, so manually resign focus + // when return (Join) is pressed to trigger |textFieldDidEndEditing|. + [textField resignFirstResponder]; + return YES; +} + +#pragma mark - Private + +- (void)textFieldDidChange:(id)sender { + [self updateClearButton]; +} + +- (void)onClear:(id)sender { + _roomText.text = @""; + [self updateClearButton]; + [_roomText resignFirstResponder]; +} + +- (void)updateClearButton { + _clearButton.hidden = _roomText.text.length == 0; +} + +@end + +@interface ARDMainView () +@end + +@implementation ARDMainView { + UILabel *_appLabel; + ARDRoomTextField *_roomText; +} + +@synthesize delegate = _delegate; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + _appLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _appLabel.text = @"AppRTCDemo"; + _appLabel.font = [UIFont fontWithName:@"Roboto" size:34]; + _appLabel.textColor = [UIColor colorWithWhite:0 alpha:.2]; + [_appLabel sizeToFit]; + [self addSubview:_appLabel]; + + _roomText = [[ARDRoomTextField alloc] initWithFrame:CGRectZero]; + _roomText.delegate = self; + [self addSubview:_roomText]; + + self.backgroundColor = [UIColor whiteColor]; + } + return self; +} + +- (void)layoutSubviews { + CGRect bounds = self.bounds; + CGFloat roomTextWidth = bounds.size.width - 2 * kRoomTextFieldMargin; + CGFloat roomTextHeight = [_roomText sizeThatFits:bounds.size].height; + _roomText.frame = CGRectMake(kRoomTextFieldMargin, + kStatusBarHeight + kRoomTextFieldMargin, + roomTextWidth, + roomTextHeight); + _appLabel.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); +} + +#pragma mark - ARDRoomTextFieldDelegate + +- (void)roomTextField:(ARDRoomTextField *)roomTextField + didInputRoom:(NSString *)room { + [_delegate mainView:self didInputRoom:room]; +} + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.h b/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.h new file mode 100644 index 0000000000..244058bfd6 --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.h @@ -0,0 +1,34 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@interface ARDMainViewController : UIViewController + +- (void)applicationWillResignActive:(UIApplication *)application; + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.m b/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.m new file mode 100644 index 0000000000..c53d91c7f2 --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDMainViewController.m @@ -0,0 +1,102 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ARDMainViewController.h" + +#import "ARDAppClient.h" +#import "ARDMainView.h" +#import "ARDVideoCallViewController.h" + +@interface ARDMainViewController () +@end + +@implementation ARDMainViewController + +- (void)loadView { + ARDMainView *mainView = [[ARDMainView alloc] initWithFrame:CGRectZero]; + mainView.delegate = self; + self.view = mainView; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Terminate any calls when we aren't active. + [self dismissViewControllerAnimated:NO completion:nil]; +} + +#pragma mark - ARDMainViewDelegate + +- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room { + if (!room.length) { + return; + } + // Trim whitespaces. + NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet]; + NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet]; + + // Check that room name is valid. + NSError *error = nil; + NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive; + NSRegularExpression *regex = + [NSRegularExpression regularExpressionWithPattern:@"\\w+" + options:options + error:&error]; + if (error) { + [self showAlertWithMessage:error.localizedDescription]; + return; + } + NSRange matchRange = + [regex rangeOfFirstMatchInString:trimmedRoom + options:0 + range:NSMakeRange(0, trimmedRoom.length)]; + if (matchRange.location == NSNotFound || + matchRange.length != trimmedRoom.length) { + [self showAlertWithMessage:@"Invalid room name."]; + return; + } + + // Kick off the video call. + ARDVideoCallViewController *videoCallViewController = + [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom]; + videoCallViewController.modalTransitionStyle = + UIModalTransitionStyleCrossDissolve; + [self presentViewController:videoCallViewController + animated:YES + completion:nil]; +} + +#pragma mark - Private + +- (void)showAlertWithMessage:(NSString*)message { + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil + message:message + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alertView show]; +} + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.h b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.h new file mode 100644 index 0000000000..98ef0e3091 --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.h @@ -0,0 +1,49 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import "RTCEAGLVideoView.h" + +@class ARDVideoCallView; +@protocol ARDVideoCallViewDelegate + +// Called when the hangup button is pressed. +- (void)videoCallViewDidHangup:(ARDVideoCallView *)view; + +@end + +// Video call view that shows local and remote video, provides a label to +// display status, and also a hangup button. +@interface ARDVideoCallView : UIView + +@property(nonatomic, readonly) UILabel *statusLabel; +@property(nonatomic, readonly) RTCEAGLVideoView *localVideoView; +@property(nonatomic, readonly) RTCEAGLVideoView *remoteVideoView; +@property(nonatomic, weak) id delegate; + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.m b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.m new file mode 100644 index 0000000000..3510d4fd0f --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallView.m @@ -0,0 +1,145 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ARDVideoCallView.h" + +#import +#import "UIImage+ARDUtilities.h" + +static CGFloat const kHangupButtonPadding = 16; +static CGFloat const kHangupButtonSize = 48; +static CGFloat const kLocalVideoViewWidth = 90; +static CGFloat const kLocalVideoViewHeight = 120; +static CGFloat const kLocalVideoViewPadding = 8; + +@interface ARDVideoCallView () +@end + +@implementation ARDVideoCallView { + UIButton *_hangupButton; + CGSize _localVideoSize; + CGSize _remoteVideoSize; +} + +@synthesize statusLabel = _statusLabel; +@synthesize localVideoView = _localVideoView; +@synthesize remoteVideoView = _remoteVideoView; +@synthesize delegate = _delegate; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + _remoteVideoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero]; + _remoteVideoView.delegate = self; + [self addSubview:_remoteVideoView]; + + _localVideoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero]; + _localVideoView.transform = CGAffineTransformMakeScale(-1, 1); + _localVideoView.delegate = self; + [self addSubview:_localVideoView]; + + _hangupButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _hangupButton.backgroundColor = [UIColor redColor]; + _hangupButton.layer.cornerRadius = kHangupButtonSize / 2; + _hangupButton.layer.masksToBounds = YES; + UIImage *image = [UIImage imageForName:@"ic_call_end_black_24dp.png" + color:[UIColor whiteColor]]; + [_hangupButton setImage:image forState:UIControlStateNormal]; + [_hangupButton addTarget:self + action:@selector(onHangup:) + forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_hangupButton]; + + _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _statusLabel.font = [UIFont fontWithName:@"Roboto" size:16]; + _statusLabel.textColor = [UIColor whiteColor]; + [self addSubview:_statusLabel]; + } + return self; +} + +- (void)layoutSubviews { + CGRect bounds = self.bounds; + if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) { + // Aspect fill remote video into bounds. + CGRect remoteVideoFrame = + AVMakeRectWithAspectRatioInsideRect(_remoteVideoSize, bounds); + CGFloat scale = 1; + if (remoteVideoFrame.size.width > remoteVideoFrame.size.height) { + // Scale by height. + scale = bounds.size.height / remoteVideoFrame.size.height; + } else { + // Scale by width. + scale = bounds.size.width / remoteVideoFrame.size.width; + } + remoteVideoFrame.size.height *= scale; + remoteVideoFrame.size.width *= scale; + _remoteVideoView.frame = remoteVideoFrame; + _remoteVideoView.center = + CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); + } else { + _remoteVideoView.frame = bounds; + } + + CGRect localVideoFrame = CGRectZero; + localVideoFrame.origin.x = + CGRectGetMaxX(bounds) - kLocalVideoViewWidth - kLocalVideoViewPadding; + localVideoFrame.origin.y = + CGRectGetMaxY(bounds) - kLocalVideoViewHeight - kLocalVideoViewPadding; + localVideoFrame.size.width = kLocalVideoViewWidth; + localVideoFrame.size.height = kLocalVideoViewHeight; + _localVideoView.frame = localVideoFrame; + + _hangupButton.frame = + CGRectMake(CGRectGetMinX(bounds) + kHangupButtonPadding, + CGRectGetMaxY(bounds) - kHangupButtonPadding - + kHangupButtonSize, + kHangupButtonSize, + kHangupButtonSize); + + [_statusLabel sizeToFit]; + _statusLabel.center = + CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); +} + +#pragma mark - RTCEAGLVideoViewDelegate + +- (void)videoView:(RTCEAGLVideoView*)videoView didChangeVideoSize:(CGSize)size { + if (videoView == _localVideoView) { + _localVideoSize = size; + } else if (videoView == _remoteVideoView) { + _remoteVideoSize = size; + } + [self setNeedsLayout]; +} + +#pragma mark - Private + +- (void)onHangup:(id)sender { + [_delegate videoCallViewDidHangup:self]; +} + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h new file mode 100644 index 0000000000..5f3dfc4edd --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h @@ -0,0 +1,34 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@interface ARDVideoCallViewController : UIViewController + +- (instancetype)initForRoom:(NSString *)room; + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m new file mode 100644 index 0000000000..352cb437e6 --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m @@ -0,0 +1,163 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "ARDVideoCallViewController.h" + +#import "ARDAppClient.h" +#import "ARDVideoCallView.h" + +@interface ARDVideoCallViewController () +@property(nonatomic, readonly) ARDVideoCallView *videoCallView; +@end + +@implementation ARDVideoCallViewController { + ARDAppClient *_client; + RTCVideoTrack *_remoteVideoTrack; + RTCVideoTrack *_localVideoTrack; +} + +@synthesize videoCallView = _videoCallView; + +- (instancetype)initForRoom:(NSString *)room { + if (self = [super init]) { + _client = [[ARDAppClient alloc] initWithDelegate:self]; + [_client connectToRoomWithId:room options:nil]; + } + return self; +} + +- (void)loadView { + _videoCallView = [[ARDVideoCallView alloc] initWithFrame:CGRectZero]; + _videoCallView.delegate = self; + _videoCallView.statusLabel.text = + [self statusTextForState:RTCICEConnectionNew]; + self.view = _videoCallView; +} + +#pragma mark - ARDAppClientDelegate + +- (void)appClient:(ARDAppClient *)client + didChangeState:(ARDAppClientState)state { + switch (state) { + case kARDAppClientStateConnected: + NSLog(@"Client connected."); + break; + case kARDAppClientStateConnecting: + NSLog(@"Client connecting."); + break; + case kARDAppClientStateDisconnected: + NSLog(@"Client disconnected."); + [self hangup]; + break; + } +} + +- (void)appClient:(ARDAppClient *)client + didChangeConnectionState:(RTCICEConnectionState)state { + NSLog(@"ICE state changed: %d", state); + __weak ARDVideoCallViewController *weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + ARDVideoCallViewController *strongSelf = weakSelf; + strongSelf.videoCallView.statusLabel.text = + [strongSelf statusTextForState:state]; + }); +} + +- (void)appClient:(ARDAppClient *)client + didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack { + if (!_localVideoTrack) { + _localVideoTrack = localVideoTrack; + [_localVideoTrack addRenderer:_videoCallView.localVideoView]; + } +} + +- (void)appClient:(ARDAppClient *)client + didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { + if (!_remoteVideoTrack) { + _remoteVideoTrack = remoteVideoTrack; + [_remoteVideoTrack addRenderer:_videoCallView.remoteVideoView]; + _videoCallView.statusLabel.hidden = YES; + } +} + +- (void)appClient:(ARDAppClient *)client + didError:(NSError *)error { + NSString *message = + [NSString stringWithFormat:@"%@", error.localizedDescription]; + [self showAlertWithMessage:message]; + [self hangup]; +} + +#pragma mark - ARDVideoCallViewDelegate + +- (void)videoCallViewDidHangup:(ARDVideoCallView *)view { + [self hangup]; +} + +#pragma mark - Private + +- (void)hangup { + if (_remoteVideoTrack) { + [_remoteVideoTrack removeRenderer:_videoCallView.remoteVideoView]; + _remoteVideoTrack = nil; + [_videoCallView.remoteVideoView renderFrame:nil]; + } + if (_localVideoTrack) { + [_localVideoTrack removeRenderer:_videoCallView.localVideoView]; + _localVideoTrack = nil; + [_videoCallView.localVideoView renderFrame:nil]; + } + [_client disconnect]; + [self.presentingViewController dismissViewControllerAnimated:YES + completion:nil]; +} + +- (NSString *)statusTextForState:(RTCICEConnectionState)state { + switch (state) { + case RTCICEConnectionNew: + case RTCICEConnectionChecking: + return @"Connecting..."; + case RTCICEConnectionConnected: + case RTCICEConnectionCompleted: + case RTCICEConnectionFailed: + case RTCICEConnectionDisconnected: + case RTCICEConnectionClosed: + return nil; + } +} + +- (void)showAlertWithMessage:(NSString*)message { + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:nil + message:message + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alertView show]; +} + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/Default.png b/talk/examples/objc/AppRTCDemo/ios/Default.png deleted file mode 100644 index 4c8ca6f693..0000000000 Binary files a/talk/examples/objc/AppRTCDemo/ios/Default.png and /dev/null differ diff --git a/talk/examples/objc/AppRTCDemo/ios/Info.plist b/talk/examples/objc/AppRTCDemo/ios/Info.plist index b61648057c..0b66b1c68d 100644 --- a/talk/examples/objc/AppRTCDemo/ios/Info.plist +++ b/talk/examples/objc/AppRTCDemo/ios/Info.plist @@ -58,5 +58,13 @@ UIInterfaceOrientationPortrait + UIAppFonts + + Roboto-Regular.ttf + + UIBackgroundModes + + voip + diff --git a/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist b/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist deleted file mode 100644 index e7ec329dcc..0000000000 --- a/talk/examples/objc/AppRTCDemo/ios/ResourceRules.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - rules - - .* - - Info.plist - - omit - - weight - 10 - - ResourceRules.plist - - omit - - weight - 100 - - - - diff --git a/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.h b/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.h new file mode 100644 index 0000000000..0b7ce5c687 --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.h @@ -0,0 +1,35 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@interface UIImage (ARDUtilities) + +// Returns an color tinted version for the given image resource. ++ (UIImage *)imageForName:(NSString *)name color:(UIColor *)color; + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.m b/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.m new file mode 100644 index 0000000000..d6094f5a5d --- /dev/null +++ b/talk/examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.m @@ -0,0 +1,48 @@ +/* + * libjingle + * Copyright 2015, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "UIImage+ARDUtilities.h" + +@implementation UIImage (ARDUtilities) + ++ (UIImage *)imageForName:(NSString *)name color:(UIColor *)color { + UIImage *image = [UIImage imageNamed:name]; + if (!image) { + return nil; + } + UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0f); + [color setFill]; + CGRect bounds = CGRectMake(0, 0, image.size.width, image.size.height); + UIRectFill(bounds); + [image drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f]; + UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return coloredImage; +} + +@end diff --git a/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib b/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib deleted file mode 100644 index cb2dc8394e..0000000000 --- a/talk/examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib +++ /dev/null @@ -1,716 +0,0 @@ - - - - 1536 - 13B42 - 4514 - 1265 - 696.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 3747 - - - IBNSLayoutConstraint - IBProxyObject - IBUITextField - IBUITextView - IBUIView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 292 - {{20, 20}, {280, 141}} - - - - _NS:9 - - 1 - MSAxIDEAA - - YES - NO - IBCocoaTouchFramework - Enter the room below to connect to apprtc. - - 2 - IBCocoaTouchFramework - - - 1 - 14 - - - HelveticaNeue - 14 - 16 - - - - - 292 - {{20, 180}, {280, 30}} - - - - _NS:9 - NO - YES - IBCocoaTouchFramework - 0 - - 3 - apprtc room - - 3 - MAA - - 2 - - - YES - 17 - - 2 - 3 - IBCocoaTouchFramework - - - - - - - -2147483356 - {{20, 20}, {280, 190}} - - - - _NS:9 - - YES - YES - IBCocoaTouchFramework - NO - - - 2 - IBCocoaTouchFramework - - - - - - - -2147483356 - {{20, 228}, {280, 300}} - - - - _NS:9 - - 3 - MAA - - IBCocoaTouchFramework - - - {{0, 20}, {320, 548}} - - - - - 3 - MC43NQA - - - NO - - - IBUIScreenMetrics - - YES - - - - - - {320, 568} - {568, 320} - - - IBCocoaTouchFramework - Retina 4-inch Full Screen - 2 - - IBCocoaTouchFramework - - - - - - - view - - - - 7 - - - - roomInput - - - - 108 - - - - instructionsView - - - - 127 - - - - logView - - - - 138 - - - - blackView - - - - 151 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 6 - - - - - 4 - 0 - - 4 - 1 - - 20 - - 1000 - - 8 - 23 - 3 - NO - - - - 3 - 0 - - 3 - 1 - - 228 - - 1000 - - 3 - 9 - 3 - NO - - - - 5 - 0 - - 5 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - NO - - - - 6 - 0 - - 6 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - NO - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 4 - 0 - - 4 - 1 - - 0.0 - - 1000 - - 6 - 24 - 2 - NO - - - - 3 - 0 - - 3 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 6 - 0 - - 6 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 3 - 0 - - 3 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - 5 - 0 - - 5 - 1 - - 20 - - 1000 - - 0 - 29 - 3 - NO - - - - - - - - - - 57 - - - - - 8 - 0 - - 0 - 1 - - 141 - - 1000 - - 3 - 9 - 1 - NO - - - - - - 62 - - - - - 63 - - - - - 66 - - - - - 104 - - - - - - 107 - - - - - 123 - - - - - 126 - - - - - 128 - - - - - 8 - 0 - - 0 - 1 - - 190 - - 1000 - - 3 - 9 - 1 - NO - - - - - - 133 - - - - - 137 - - - - - 139 - - - - - 141 - - - - - 142 - - - - - 148 - - - - - 149 - - - - - 153 - - - - - 154 - - - - - 155 - - - - - - - APPRTCViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - - - - - - - - - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 155 - - - - - APPRTCViewController - UIViewController - - UIView - UITextField - UITextView - UITextView - - - - blackView - UIView - - - roomInput - UITextField - - - instructionsView - UITextView - - - logView - UITextView - - - - IBProjectSource - ./Classes/APPRTCViewController.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - - 0 - IBCocoaTouchFramework - YES - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - - com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 - - - YES - 3 - YES - 3747 - - diff --git a/talk/examples/objc/AppRTCDemo/ios/main.m b/talk/examples/objc/AppRTCDemo/ios/main.m index e9a1f63efb..17a008d475 100644 --- a/talk/examples/objc/AppRTCDemo/ios/main.m +++ b/talk/examples/objc/AppRTCDemo/ios/main.m @@ -27,11 +27,11 @@ #import -#import "APPRTCAppDelegate.h" +#import "ARDAppDelegate.h" int main(int argc, char* argv[]) { @autoreleasepool { return UIApplicationMain( - argc, argv, nil, NSStringFromClass([APPRTCAppDelegate class])); + argc, argv, nil, NSStringFromClass([ARDAppDelegate class])); } } diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/Default-568h.png b/talk/examples/objc/AppRTCDemo/ios/resources/Default-568h.png new file mode 100644 index 0000000000..2735148c93 Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/Default-568h.png differ diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/Roboto-Regular.ttf b/talk/examples/objc/AppRTCDemo/ios/resources/Roboto-Regular.ttf new file mode 100644 index 0000000000..0e58508a64 Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/Roboto-Regular.ttf differ diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp.png b/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp.png new file mode 100755 index 0000000000..531cb0f280 Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp.png differ diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp@2x.png b/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp@2x.png new file mode 100755 index 0000000000..03dd381c10 Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp@2x.png differ diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp.png b/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp.png new file mode 100755 index 0000000000..4ebf8a2270 Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp.png differ diff --git a/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp@2x.png b/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp@2x.png new file mode 100755 index 0000000000..ed2b2525fd Binary files /dev/null and b/talk/examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp@2x.png differ diff --git a/talk/libjingle_examples.gyp b/talk/libjingle_examples.gyp index 27b0b8aec9..a4959e966f 100755 --- a/talk/libjingle_examples.gyp +++ b/talk/libjingle_examples.gyp @@ -216,16 +216,28 @@ 'conditions': [ ['OS=="ios"', { 'mac_bundle_resources': [ - 'examples/objc/AppRTCDemo/ios/ResourceRules.plist', - 'examples/objc/AppRTCDemo/ios/en.lproj/APPRTCViewController.xib', + 'examples/objc/AppRTCDemo/ios/resources/Default-568h.png', + 'examples/objc/AppRTCDemo/ios/resources/Roboto-Regular.ttf', + 'examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp.png', + 'examples/objc/AppRTCDemo/ios/resources/ic_call_end_black_24dp@2x.png', + 'examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp.png', + 'examples/objc/AppRTCDemo/ios/resources/ic_clear_black_24dp@2x.png', 'examples/objc/Icon.png', ], 'sources': [ - 'examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.h', - 'examples/objc/AppRTCDemo/ios/APPRTCAppDelegate.m', - 'examples/objc/AppRTCDemo/ios/APPRTCViewController.h', - 'examples/objc/AppRTCDemo/ios/APPRTCViewController.m', + 'examples/objc/AppRTCDemo/ios/ARDAppDelegate.h', + 'examples/objc/AppRTCDemo/ios/ARDAppDelegate.m', + 'examples/objc/AppRTCDemo/ios/ARDMainView.h', + 'examples/objc/AppRTCDemo/ios/ARDMainView.m', + 'examples/objc/AppRTCDemo/ios/ARDMainViewController.h', + 'examples/objc/AppRTCDemo/ios/ARDMainViewController.m', + 'examples/objc/AppRTCDemo/ios/ARDVideoCallView.h', + 'examples/objc/AppRTCDemo/ios/ARDVideoCallView.m', + 'examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h', + 'examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m', 'examples/objc/AppRTCDemo/ios/AppRTCDemo-Prefix.pch', + 'examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.h', + 'examples/objc/AppRTCDemo/ios/UIImage+ARDUtilities.m', 'examples/objc/AppRTCDemo/ios/main.m', ], 'xcode_settings': {