webrtc/talk/examples/objc/AppRTCDemo/mac/APPRTCViewController.m
tkchin@webrtc.org 87776a8935 iAppRTCDemo: WebSocket based signaling.
Updates the iOS code to use the new signaling model. Removes old Channel API
code. Note that this no longer logs messages to UI. UI update forthcoming.

BUG=
R=glaznev@webrtc.org, jiayl@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/35369004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7852 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-12-09 19:32:35 +00:00

320 lines
9.9 KiB
Objective-C

/*
* libjingle
* Copyright 2014, 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 "APPRTCViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "ARDAppClient.h"
#import "RTCNSGLVideoView.h"
#import "RTCVideoTrack.h"
static NSUInteger const kContentWidth = 1280;
static NSUInteger const kContentHeight = 720;
static NSUInteger const kRoomFieldWidth = 80;
static NSUInteger const kLogViewHeight = 280;
@class APPRTCMainView;
@protocol APPRTCMainViewDelegate
- (void)appRTCMainView:(APPRTCMainView*)mainView
didEnterRoomId:(NSString*)roomId;
@end
@interface APPRTCMainView : NSView
@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
@property(nonatomic, readonly) RTCNSGLVideoView* localVideoView;
@property(nonatomic, readonly) RTCNSGLVideoView* remoteVideoView;
- (void)displayLogMessage:(NSString*)message;
@end
@interface APPRTCMainView () <NSTextFieldDelegate, RTCNSGLVideoViewDelegate>
@end
@implementation APPRTCMainView {
NSScrollView* _scrollView;
NSTextField* _roomLabel;
NSTextField* _roomField;
NSTextView* _logView;
RTCNSGLVideoView* _localVideoView;
RTCNSGLVideoView* _remoteVideoView;
CGSize _localVideoSize;
CGSize _remoteVideoSize;
}
+ (BOOL)requiresConstraintBasedLayout {
return YES;
}
- (instancetype)initWithFrame:(NSRect)frame {
if (self = [super initWithFrame:frame]) {
[self setupViews];
}
return self;
}
- (void)updateConstraints {
NSParameterAssert(
_roomField != nil && _scrollView != nil && _remoteVideoView != nil);
[self removeConstraints:[self constraints]];
NSDictionary* viewsDictionary =
NSDictionaryOfVariableBindings(_roomLabel,
_roomField,
_scrollView,
_remoteVideoView);
NSSize remoteViewSize = [self remoteVideoViewSize];
NSDictionary* metrics = @{
@"kLogViewHeight" : @(kLogViewHeight),
@"kRoomFieldWidth" : @(kRoomFieldWidth),
@"remoteViewWidth" : @(remoteViewSize.width),
@"remoteViewHeight" : @(remoteViewSize.height),
};
// Declare this separately to avoid compiler warning about splitting string
// within an NSArray expression.
NSString* verticalConstraint =
@"V:|-[_roomLabel]-[_roomField]-[_scrollView(kLogViewHeight)]"
"-[_remoteVideoView(remoteViewHeight)]-|";
NSArray* constraintFormats = @[
verticalConstraint,
@"|-[_roomLabel]",
@"|-[_roomField(kRoomFieldWidth)]",
@"|-[_scrollView(remoteViewWidth)]-|",
@"|-[_remoteVideoView(remoteViewWidth)]-|",
];
for (NSString* constraintFormat in constraintFormats) {
NSArray* constraints =
[NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
options:0
metrics:metrics
views:viewsDictionary];
for (NSLayoutConstraint* constraint in constraints) {
[self addConstraint:constraint];
}
}
[super updateConstraints];
}
- (void)displayLogMessage:(NSString*)message {
_logView.string =
[NSString stringWithFormat:@"%@%@\n", _logView.string, message];
NSRange range = NSMakeRange([_logView.string length], 0);
[_logView scrollRangeToVisible:range];
}
#pragma mark - NSControl delegate
- (void)controlTextDidEndEditing:(NSNotification*)notification {
NSDictionary* userInfo = [notification userInfo];
NSInteger textMovement = [userInfo[@"NSTextMovement"] intValue];
if (textMovement == NSReturnTextMovement) {
[self.delegate appRTCMainView:self didEnterRoomId:_roomField.stringValue];
}
}
#pragma mark - RTCNSGLVideoViewDelegate
- (void)videoView:(RTCNSGLVideoView*)videoView
didChangeVideoSize:(NSSize)size {
if (videoView == _remoteVideoView) {
_remoteVideoSize = size;
} else if (videoView == _localVideoView) {
_localVideoSize = size;
} else {
return;
}
[self setNeedsUpdateConstraints:YES];
}
#pragma mark - Private
- (void)setupViews {
NSParameterAssert([[self subviews] count] == 0);
_roomLabel = [[NSTextField alloc] initWithFrame:NSZeroRect];
[_roomLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[_roomLabel setBezeled:NO];
[_roomLabel setDrawsBackground:NO];
[_roomLabel setEditable:NO];
[_roomLabel setStringValue:@"Enter AppRTC room id:"];
[self addSubview:_roomLabel];
_roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
[_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:_roomField];
[_roomField setEditable:YES];
[_roomField setDelegate:self];
_logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
[_logView setMinSize:NSMakeSize(0, kLogViewHeight)];
[_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[_logView setVerticallyResizable:YES];
[_logView setAutoresizingMask:NSViewWidthSizable];
NSTextContainer* textContainer = [_logView textContainer];
NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);
[textContainer setContainerSize:containerSize];
[textContainer setWidthTracksTextView:YES];
[_logView setEditable:NO];
_scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
[_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_scrollView setHasVerticalScroller:YES];
[_scrollView setDocumentView:_logView];
[self addSubview:_scrollView];
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAOpenGLProfile,
NSOpenGLProfileVersion3_2Core,
0
};
NSOpenGLPixelFormat* pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
_remoteVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
pixelFormat:pixelFormat];
[_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
_remoteVideoView.delegate = self;
[self addSubview:_remoteVideoView];
// TODO(tkchin): create local video view.
// https://code.google.com/p/webrtc/issues/detail?id=3417.
}
- (NSSize)remoteVideoViewSize {
if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) {
return _remoteVideoSize;
} else {
return NSMakeSize(kContentWidth, kContentHeight);
}
}
- (NSSize)localVideoViewSize {
return NSZeroSize;
}
@end
@interface APPRTCViewController ()
<ARDAppClientDelegate, APPRTCMainViewDelegate>
@property(nonatomic, readonly) APPRTCMainView* mainView;
@end
@implementation APPRTCViewController {
ARDAppClient* _client;
RTCVideoTrack* _localVideoTrack;
RTCVideoTrack* _remoteVideoTrack;
}
- (void)dealloc {
[self disconnect];
}
- (void)loadView {
APPRTCMainView* view = [[APPRTCMainView alloc] initWithFrame:NSZeroRect];
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
view.delegate = self;
self.view = view;
}
- (void)windowWillClose:(NSNotification*)notification {
[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];
_client = nil;
break;
}
}
- (void)appClient:(ARDAppClient *)client
didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
_localVideoTrack = localVideoTrack;
}
- (void)appClient:(ARDAppClient *)client
didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
_remoteVideoTrack = remoteVideoTrack;
[_remoteVideoTrack addRenderer:self.mainView.remoteVideoView];
}
- (void)appClient:(ARDAppClient *)client
didError:(NSError *)error {
[self showAlertWithMessage:[NSString stringWithFormat:@"%@", error]];
[self disconnect];
}
#pragma mark - APPRTCMainViewDelegate
- (void)appRTCMainView:(APPRTCMainView*)mainView
didEnterRoomId:(NSString*)roomId {
[_client disconnect];
ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self];
[client connectToRoomWithId:roomId options:nil];
_client = client;
}
#pragma mark - Private
- (APPRTCMainView*)mainView {
return (APPRTCMainView*)self.view;
}
- (void)showAlertWithMessage:(NSString*)message {
NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:message];
[alert runModal];
}
- (void)resetUI {
[_remoteVideoTrack removeRenderer:self.mainView.remoteVideoView];
_remoteVideoTrack = nil;
[self.mainView.remoteVideoView renderFrame:nil];
}
- (void)disconnect {
[self resetUI];
[_client disconnect];
}
@end