mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

This CL introduced 2 new macros that affect the WebRTC OBJC API symbols: - RTC_OBJC_TYPE_PREFIX: Macro used to prepend a prefix to the API types that are exported with RTC_OBJC_EXPORT. Clients can patch the definition of this macro locally and build WebRTC.framework with their own prefix in case symbol clashing is a problem. This macro must only be defined by changing the value in sdk/objc/base/RTCMacros.h and not on via compiler flag to ensure it has a unique value. - RCT_OBJC_TYPE: Macro used internally to reference API types. Declaring an API type without using this macro will not include the declared type in the set of types that will be affected by the configurable RTC_OBJC_TYPE_PREFIX. Manual changes: https://webrtc-review.googlesource.com/c/src/+/173781/5..10 The auto-generated changes in PS#5 have been done with: https://webrtc-review.googlesource.com/c/src/+/174061. Bug: None Change-Id: I0d54ca94db764fb3b6cb4365873f79e14cd879b8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/173781 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Kári Helgason <kthelgason@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31153}
438 lines
14 KiB
Objective-C
438 lines
14 KiB
Objective-C
/*
|
|
* 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/RTCMTLNSVideoView.h>
|
|
#import <WebRTC/RTCNSGLVideoView.h>
|
|
#import <WebRTC/RTCVideoTrack.h>
|
|
|
|
#import "ARDAppClient.h"
|
|
#import "ARDCaptureController.h"
|
|
#import "ARDSettingsModel.h"
|
|
|
|
static NSUInteger const kContentWidth = 900;
|
|
static NSUInteger const kRoomFieldWidth = 200;
|
|
static NSUInteger const kActionItemHeight = 30;
|
|
static NSUInteger const kBottomViewHeight = 200;
|
|
|
|
@class APPRTCMainView;
|
|
@protocol APPRTCMainViewDelegate
|
|
|
|
- (void)appRTCMainView:(APPRTCMainView*)mainView
|
|
didEnterRoomId:(NSString*)roomId
|
|
loopback:(BOOL)isLoopback;
|
|
|
|
@end
|
|
|
|
@interface APPRTCMainView : NSView
|
|
|
|
@property(nonatomic, weak) id<APPRTCMainViewDelegate> delegate;
|
|
@property(nonatomic, readonly) NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>* localVideoView;
|
|
@property(nonatomic, readonly) NSView<RTC_OBJC_TYPE(RTCVideoRenderer)>* remoteVideoView;
|
|
@property(nonatomic, readonly) NSTextView* logView;
|
|
|
|
- (void)displayLogMessage:(NSString*)message;
|
|
|
|
@end
|
|
|
|
@interface APPRTCMainView () <NSTextFieldDelegate, RTC_OBJC_TYPE (RTCNSGLVideoViewDelegate)>
|
|
@end
|
|
@implementation APPRTCMainView {
|
|
NSScrollView* _scrollView;
|
|
NSView* _actionItemsView;
|
|
NSButton* _connectButton;
|
|
NSButton* _loopbackButton;
|
|
NSTextField* _roomField;
|
|
CGSize _localVideoSize;
|
|
CGSize _remoteVideoSize;
|
|
}
|
|
|
|
@synthesize delegate = _delegate;
|
|
@synthesize localVideoView = _localVideoView;
|
|
@synthesize remoteVideoView = _remoteVideoView;
|
|
@synthesize logView = _logView;
|
|
|
|
- (void)displayLogMessage:(NSString *)message {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self.logView.string = [NSString stringWithFormat:@"%@%@\n", self.logView.string, message];
|
|
NSRange range = NSMakeRange(self.logView.string.length, 0);
|
|
[self.logView scrollRangeToVisible:range];
|
|
});
|
|
}
|
|
|
|
#pragma mark - Private
|
|
|
|
- (instancetype)initWithFrame:(NSRect)frame {
|
|
if (self = [super initWithFrame:frame]) {
|
|
[self setupViews];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
+ (BOOL)requiresConstraintBasedLayout {
|
|
return YES;
|
|
}
|
|
|
|
- (void)updateConstraints {
|
|
NSParameterAssert(
|
|
_roomField != nil &&
|
|
_scrollView != nil &&
|
|
_remoteVideoView != nil &&
|
|
_localVideoView != nil &&
|
|
_actionItemsView!= nil &&
|
|
_connectButton != nil &&
|
|
_loopbackButton != nil);
|
|
|
|
[self removeConstraints:[self constraints]];
|
|
NSDictionary* viewsDictionary =
|
|
NSDictionaryOfVariableBindings(_roomField,
|
|
_scrollView,
|
|
_remoteVideoView,
|
|
_localVideoView,
|
|
_actionItemsView,
|
|
_connectButton,
|
|
_loopbackButton);
|
|
|
|
NSSize remoteViewSize = [self remoteVideoViewSize];
|
|
NSDictionary* metrics = @{
|
|
@"remoteViewWidth" : @(remoteViewSize.width),
|
|
@"remoteViewHeight" : @(remoteViewSize.height),
|
|
@"kBottomViewHeight" : @(kBottomViewHeight),
|
|
@"localViewHeight" : @(remoteViewSize.height / 3),
|
|
@"localViewWidth" : @(remoteViewSize.width / 3),
|
|
@"kRoomFieldWidth" : @(kRoomFieldWidth),
|
|
@"kActionItemHeight" : @(kActionItemHeight)
|
|
};
|
|
// Declare this separately to avoid compiler warning about splitting string
|
|
// within an NSArray expression.
|
|
NSString* verticalConstraintLeft =
|
|
@"V:|-[_remoteVideoView(remoteViewHeight)]-[_scrollView(kBottomViewHeight)]-|";
|
|
NSString* verticalConstraintRight =
|
|
@"V:|-[_remoteVideoView(remoteViewHeight)]-[_actionItemsView(kBottomViewHeight)]-|";
|
|
NSArray* constraintFormats = @[
|
|
verticalConstraintLeft,
|
|
verticalConstraintRight,
|
|
@"H:|-[_remoteVideoView(remoteViewWidth)]-|",
|
|
@"V:|-[_localVideoView(localViewHeight)]",
|
|
@"H:|-[_localVideoView(localViewWidth)]",
|
|
@"H:|-[_scrollView(==_actionItemsView)]-[_actionItemsView]-|"
|
|
];
|
|
|
|
NSArray* actionItemsConstraints = @[
|
|
@"H:|-[_roomField(kRoomFieldWidth)]-[_loopbackButton(kRoomFieldWidth)]",
|
|
@"H:|-[_connectButton(kRoomFieldWidth)]",
|
|
@"V:|-[_roomField(kActionItemHeight)]-[_connectButton(kActionItemHeight)]",
|
|
@"V:|-[_loopbackButton(kActionItemHeight)]",
|
|
];
|
|
|
|
[APPRTCMainView addConstraints:constraintFormats
|
|
toView:self
|
|
viewsDictionary:viewsDictionary
|
|
metrics:metrics];
|
|
[APPRTCMainView addConstraints:actionItemsConstraints
|
|
toView:_actionItemsView
|
|
viewsDictionary:viewsDictionary
|
|
metrics:metrics];
|
|
[super updateConstraints];
|
|
}
|
|
|
|
#pragma mark - Constraints helper
|
|
|
|
+ (void)addConstraints:(NSArray*)constraints toView:(NSView*)view
|
|
viewsDictionary:(NSDictionary*)viewsDictionary
|
|
metrics:(NSDictionary*)metrics {
|
|
for (NSString* constraintFormat in constraints) {
|
|
NSArray* constraints =
|
|
[NSLayoutConstraint constraintsWithVisualFormat:constraintFormat
|
|
options:0
|
|
metrics:metrics
|
|
views:viewsDictionary];
|
|
for (NSLayoutConstraint* constraint in constraints) {
|
|
[view addConstraint:constraint];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark - Control actions
|
|
|
|
- (void)startCall:(id)sender {
|
|
NSString* roomString = _roomField.stringValue;
|
|
// Generate room id for loopback options.
|
|
if (_loopbackButton.intValue && [roomString isEqualToString:@""]) {
|
|
roomString = [NSUUID UUID].UUIDString;
|
|
roomString = [roomString stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
|
}
|
|
[self.delegate appRTCMainView:self
|
|
didEnterRoomId:roomString
|
|
loopback:_loopbackButton.intValue];
|
|
[self setNeedsUpdateConstraints:YES];
|
|
}
|
|
|
|
#pragma mark - RTC_OBJC_TYPE(RTCNSGLVideoViewDelegate)
|
|
|
|
- (void)videoView:(RTC_OBJC_TYPE(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);
|
|
|
|
_logView = [[NSTextView alloc] initWithFrame:NSZeroRect];
|
|
[_logView setMinSize:NSMakeSize(0, kBottomViewHeight)];
|
|
[_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];
|
|
|
|
[self setupActionItemsView];
|
|
|
|
_scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];
|
|
[_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
[_scrollView setHasVerticalScroller:YES];
|
|
[_scrollView setDocumentView:_logView];
|
|
[self addSubview:_scrollView];
|
|
|
|
// NOTE (daniela): Ignoring Clang diagonstic here.
|
|
// We're performing run time check to make sure class is available on runtime.
|
|
// If not we're providing sensible default.
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wpartial-availability"
|
|
if ([RTC_OBJC_TYPE(RTCMTLNSVideoView) class] &&
|
|
[RTC_OBJC_TYPE(RTCMTLNSVideoView) isMetalAvailable]) {
|
|
_remoteVideoView = [[RTC_OBJC_TYPE(RTCMTLNSVideoView) alloc] initWithFrame:NSZeroRect];
|
|
_localVideoView = [[RTC_OBJC_TYPE(RTCMTLNSVideoView) alloc] initWithFrame:NSZeroRect];
|
|
}
|
|
#pragma clang diagnostic pop
|
|
if (_remoteVideoView == nil) {
|
|
NSOpenGLPixelFormatAttribute attributes[] = {
|
|
NSOpenGLPFADoubleBuffer,
|
|
NSOpenGLPFADepthSize, 24,
|
|
NSOpenGLPFAOpenGLProfile,
|
|
NSOpenGLProfileVersion3_2Core,
|
|
0
|
|
};
|
|
NSOpenGLPixelFormat* pixelFormat =
|
|
[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
|
|
|
RTC_OBJC_TYPE(RTCNSGLVideoView)* remote =
|
|
[[RTC_OBJC_TYPE(RTCNSGLVideoView) alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];
|
|
remote.delegate = self;
|
|
_remoteVideoView = remote;
|
|
|
|
RTC_OBJC_TYPE(RTCNSGLVideoView)* local =
|
|
[[RTC_OBJC_TYPE(RTCNSGLVideoView) alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];
|
|
local.delegate = self;
|
|
_localVideoView = local;
|
|
}
|
|
|
|
[_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
[self addSubview:_remoteVideoView];
|
|
[_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
[self addSubview:_localVideoView];
|
|
}
|
|
|
|
- (void)setupActionItemsView {
|
|
_actionItemsView = [[NSView alloc] initWithFrame:NSZeroRect];
|
|
[_actionItemsView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
[self addSubview:_actionItemsView];
|
|
|
|
_roomField = [[NSTextField alloc] initWithFrame:NSZeroRect];
|
|
[_roomField setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
[[_roomField cell] setPlaceholderString: @"Enter AppRTC room id"];
|
|
[_actionItemsView addSubview:_roomField];
|
|
[_roomField setEditable:YES];
|
|
|
|
_connectButton = [[NSButton alloc] initWithFrame:NSZeroRect];
|
|
[_connectButton setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
_connectButton.title = @"Start call";
|
|
_connectButton.bezelStyle = NSRoundedBezelStyle;
|
|
_connectButton.target = self;
|
|
_connectButton.action = @selector(startCall:);
|
|
[_actionItemsView addSubview:_connectButton];
|
|
|
|
_loopbackButton = [[NSButton alloc] initWithFrame:NSZeroRect];
|
|
[_loopbackButton setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
_loopbackButton.title = @"Loopback";
|
|
[_loopbackButton setButtonType:NSSwitchButton];
|
|
[_actionItemsView addSubview:_loopbackButton];
|
|
}
|
|
|
|
- (NSSize)remoteVideoViewSize {
|
|
if (!_remoteVideoView.bounds.size.width) {
|
|
return NSMakeSize(kContentWidth, 0);
|
|
}
|
|
NSInteger width = MAX(_remoteVideoView.bounds.size.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;
|
|
RTC_OBJC_TYPE(RTCVideoTrack) * _localVideoTrack;
|
|
RTC_OBJC_TYPE(RTCVideoTrack) * _remoteVideoTrack;
|
|
ARDCaptureController* _captureController;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[self disconnect];
|
|
}
|
|
|
|
- (void)viewDidAppear {
|
|
[super viewDidAppear];
|
|
[self displayUsageInstructions];
|
|
}
|
|
|
|
- (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 - Usage
|
|
|
|
- (void)displayUsageInstructions {
|
|
[self.mainView displayLogMessage:
|
|
@"To start call:\n"
|
|
@"• Enter AppRTC room id (not neccessary for loopback)\n"
|
|
@"• Start call"];
|
|
}
|
|
|
|
#pragma mark - ARDAppClientDelegate
|
|
|
|
- (void)appClient:(ARDAppClient *)client
|
|
didChangeState:(ARDAppClientState)state {
|
|
switch (state) {
|
|
case kARDAppClientStateConnected:
|
|
[self.mainView displayLogMessage:@"Client connected."];
|
|
break;
|
|
case kARDAppClientStateConnecting:
|
|
[self.mainView displayLogMessage:@"Client connecting."];
|
|
break;
|
|
case kARDAppClientStateDisconnected:
|
|
[self.mainView displayLogMessage:@"Client disconnected."];
|
|
[self resetUI];
|
|
_client = nil;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)appClient:(ARDAppClient *)client
|
|
didChangeConnectionState:(RTCIceConnectionState)state {
|
|
}
|
|
|
|
- (void)appClient:(ARDAppClient*)client
|
|
didCreateLocalCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)localCapturer {
|
|
_captureController =
|
|
[[ARDCaptureController alloc] initWithCapturer:localCapturer
|
|
settings:[[ARDSettingsModel alloc] init]];
|
|
[_captureController startCapture];
|
|
}
|
|
|
|
- (void)appClient:(ARDAppClient*)client
|
|
didReceiveLocalVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)localVideoTrack {
|
|
_localVideoTrack = localVideoTrack;
|
|
[_localVideoTrack addRenderer:self.mainView.localVideoView];
|
|
}
|
|
|
|
- (void)appClient:(ARDAppClient*)client
|
|
didReceiveRemoteVideoTrack:(RTC_OBJC_TYPE(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
|
|
loopback:(BOOL)isLoopback {
|
|
|
|
if ([roomId isEqualToString:@""]) {
|
|
[self.mainView displayLogMessage:@"Missing room id"];
|
|
return;
|
|
}
|
|
|
|
[self disconnect];
|
|
ARDAppClient* client = [[ARDAppClient alloc] initWithDelegate:self];
|
|
[client connectToRoomWithId:roomId
|
|
settings:[[ARDSettingsModel alloc] init] // Use default settings.
|
|
isLoopback:isLoopback];
|
|
_client = client;
|
|
}
|
|
|
|
#pragma mark - Private
|
|
|
|
- (APPRTCMainView*)mainView {
|
|
return (APPRTCMainView*)self.view;
|
|
}
|
|
|
|
- (void)showAlertWithMessage:(NSString*)message {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
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];
|
|
[_captureController stopCapture];
|
|
_captureController = nil;
|
|
[_client disconnect];
|
|
}
|
|
|
|
@end
|