blob: 710b8a5ea40e1264c73d60d2c9be953e84111d93 [file] [log] [blame]
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "APPRTCViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "WebRTC/RTCNSGLVideoView.h"
#import "WebRTC/RTCVideoTrack.h"
#import "ARDAppClient.h"
static NSUInteger const kContentWidth = 1280;
static NSUInteger const kContentHeight = 720;
static NSUInteger const kRoomFieldWidth = 80;
static NSUInteger const kLogViewHeight = 280;
static NSUInteger const kPreviewWidth = 490;
@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;
CGSize _localVideoSize;
CGSize _remoteVideoSize;
}
@synthesize delegate = _delegate;
@synthesize localVideoView = _localVideoView;
@synthesize remoteVideoView = _remoteVideoView;
+ (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,
_localVideoView);
NSSize remoteViewSize = [self remoteVideoViewSize];
NSDictionary* metrics = @{
@"kLogViewHeight" : @(kLogViewHeight),
@"kPreviewWidth" : @(kPreviewWidth),
@"kRoomFieldWidth" : @(kRoomFieldWidth),
@"remoteViewWidth" : @(remoteViewSize.width),
@"remoteViewHeight" : @(remoteViewSize.height),
@"localViewHeight" : @(remoteViewSize.height),
@"scrollViewWidth" : @(kContentWidth - kPreviewWidth),
};
// 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,
@"V:[_localVideoView]-[_remoteVideoView]",
@"V:[_localVideoView(kLogViewHeight)]",
@"|-[_roomLabel]",
@"|-[_roomField(kRoomFieldWidth)]",
@"|-[_scrollView(scrollViewWidth)]",
@"[_scrollView]-[_localVideoView]",
@"|-[_remoteVideoView(remoteViewWidth)]-|",
@"[_localVideoView(kPreviewWidth)]-|",
];
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];
_localVideoView = [[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect
pixelFormat:pixelFormat];
[_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
_localVideoView.delegate = self;
[self addSubview:_localVideoView];
}
- (NSSize)remoteVideoViewSize {
NSInteger width = MAX(_remoteVideoSize.width, kContentWidth);
NSInteger height = (width/16) * 9;
return NSMakeSize(width, height);
}
@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
didChangeConnectionState:(RTCIceConnectionState)state {
}
- (void)appClient:(ARDAppClient *)client
didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
_localVideoTrack = localVideoTrack;
[_localVideoTrack addRenderer:self.mainView.localVideoView];
}
- (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];
}
- (void)appClient:(ARDAppClient *)client
didGetStats:(NSArray *)stats {
}
#pragma mark - APPRTCMainViewDelegate
- (void)appRTCMainView:(APPRTCMainView*)mainView
didEnterRoomId:(NSString*)roomId {
[_client disconnect];
ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self];
[client connectToRoomWithId:roomId
isLoopback:NO
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO];
_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];
[_localVideoTrack removeRenderer:self.mainView.localVideoView];
_remoteVideoTrack = nil;
_localVideoTrack = nil;
[self.mainView.remoteVideoView renderFrame:nil];
[self.mainView.localVideoView renderFrame:nil];
}
- (void)disconnect {
[self resetUI];
[_client disconnect];
}
@end