First draft for calling feature.

Signed-off-by: Ivan Sein <ivan@nextcloud.com>
This commit is contained in:
Ivan Sein 2017-08-07 21:11:39 +02:00
Родитель bf9691ca57
Коммит a5639e3d9e
24 изменённых файлов: 1966 добавлений и 2 удалений

24
ThirdParty/AppRTC/ARDCaptureController.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,24 @@
/*
* Copyright 2017 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.
*/
#include <WebRTC/RTCCameraVideoCapturer.h>
@class ARDSettingsModel;
// Controls the camera. Handles starting the capture, switching cameras etc.
@interface ARDCaptureController : NSObject
- (instancetype)initWithCapturer:(RTCCameraVideoCapturer *)capturer
settings:(ARDSettingsModel *)settings;
- (void)startCapture;
- (void)stopCapture;
- (void)switchCamera;
@end

92
ThirdParty/AppRTC/ARDCaptureController.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,92 @@
/*
* Copyright 2017 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 "ARDCaptureController.h"
#import "ARDSettingsModel.h"
@implementation ARDCaptureController {
RTCCameraVideoCapturer *_capturer;
ARDSettingsModel *_settings;
BOOL _usingFrontCamera;
}
- (instancetype)initWithCapturer:(RTCCameraVideoCapturer *)capturer
settings:(ARDSettingsModel *)settings {
if ([super init]) {
_capturer = capturer;
_settings = settings;
_usingFrontCamera = YES;
}
return self;
}
- (void)startCapture {
AVCaptureDevicePosition position =
_usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
AVCaptureDevice *device = [self findDeviceForPosition:position];
AVCaptureDeviceFormat *format = [self selectFormatForDevice:device];
NSInteger fps = [self selectFpsForFormat:format];
[_capturer startCaptureWithDevice:device format:format fps:fps];
}
- (void)stopCapture {
[_capturer stopCapture];
}
- (void)switchCamera {
_usingFrontCamera = !_usingFrontCamera;
[self startCapture];
}
#pragma mark - Private
- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position {
NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
for (AVCaptureDevice *device in captureDevices) {
if (device.position == position) {
return device;
}
}
return captureDevices[0];
}
- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device {
NSArray<AVCaptureDeviceFormat *> *formats =
[RTCCameraVideoCapturer supportedFormatsForDevice:device];
int targetWidth = [_settings currentVideoResolutionWidthFromStore];
int targetHeight = [_settings currentVideoResolutionHeightFromStore];
AVCaptureDeviceFormat *selectedFormat = nil;
int currentDiff = INT_MAX;
for (AVCaptureDeviceFormat *format in formats) {
CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height);
if (diff < currentDiff) {
selectedFormat = format;
currentDiff = diff;
}
}
NSAssert(selectedFormat != nil, @"No suitable capture format found.");
return selectedFormat;
}
- (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
Float64 maxFramerate = 0;
for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
maxFramerate = fmax(maxFramerate, fpsRange.maxFrameRate);
}
return maxFramerate;
}
@end

20
ThirdParty/AppRTC/ARDSettingsModel+Private.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,20 @@
/*
* Copyright 2016 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 <Foundation/Foundation.h>
#import "ARDSettingsModel.h"
@class ARDSettingsStore;
NS_ASSUME_NONNULL_BEGIN
@interface ARDSettingsModel ()
- (ARDSettingsStore *)settingsStore;
@end
NS_ASSUME_NONNULL_END

83
ThirdParty/AppRTC/ARDSettingsModel.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,83 @@
/*
* Copyright 2016 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Model class for user defined settings.
*
* Handles storing the settings and provides default values if setting is not
* set. Also provides list of available options for different settings. Stores
* for example video codec, video resolution and maximum bitrate.
*/
@interface ARDSettingsModel : NSObject
/**
* Returns array of available capture resoultions.
*
* The capture resolutions are represented as strings in the following format
* [width]x[height]
*/
- (NSArray<NSString *> *)availableVideoResolutions;
/**
* Returns current video resolution string.
* If no resolution is in store, default value of 640x480 is returned.
* When defaulting to value, the default is saved in store for consistency reasons.
*/
- (NSString *)currentVideoResolutionSettingFromStore;
- (int)currentVideoResolutionWidthFromStore;
- (int)currentVideoResolutionHeightFromStore;
/**
* Stores the provided video resolution string into the store.
*
* If the provided resolution is no part of the available video resolutions
* the store operation will not be executed and NO will be returned.
* @param resolution the string to be stored.
* @return YES/NO depending on success.
*/
- (BOOL)storeVideoResolutionSetting:(NSString *)resolution;
/**
* Returns array of available video codecs.
*/
- (NSArray<NSString *> *)availableVideoCodecs;
/**
* Returns current video codec setting from store if present or default (H264) otherwise.
*/
- (NSString *)currentVideoCodecSettingFromStore;
/**
* Stores the provided video codec setting into the store.
*
* If the provided video codec is not part of the available video codecs
* the store operation will not be executed and NO will be returned.
* @param video codec settings the string to be stored.
* @return YES/NO depending on success.
*/
- (BOOL)storeVideoCodecSetting:(NSString *)videoCodec;
/**
* Returns current max bitrate setting from store if present.
*/
- (nullable NSNumber *)currentMaxBitrateSettingFromStore;
/**
* Stores the provided bitrate value into the store.
*
* @param bitrate NSNumber representation of the max bitrate value.
*/
- (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate;
@end
NS_ASSUME_NONNULL_END

124
ThirdParty/AppRTC/ARDSettingsModel.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,124 @@
/*
* Copyright 2016 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 "ARDSettingsModel+Private.h"
#import "ARDSettingsStore.h"
#import "WebRTC/RTCMediaConstraints.h"
NS_ASSUME_NONNULL_BEGIN
static NSArray<NSString *> *videoResolutionsStaticValues() {
return @[ @"640x480", @"960x540", @"1280x720" ];
}
static NSArray<NSString *> *videoCodecsStaticValues() {
return @[ @"H264", @"VP8", @"VP9" ];
}
@interface ARDSettingsModel () {
ARDSettingsStore *_settingsStore;
}
@end
@implementation ARDSettingsModel
- (NSArray<NSString *> *)availableVideoResolutions {
return videoResolutionsStaticValues();
}
- (NSString *)currentVideoResolutionSettingFromStore {
NSString *resolution = [[self settingsStore] videoResolution];
if (!resolution) {
resolution = [self defaultVideoResolutionSetting];
// To ensure consistency add the default to the store.
[[self settingsStore] setVideoResolution:resolution];
}
return resolution;
}
- (BOOL)storeVideoResolutionSetting:(NSString *)resolution {
if (![[self availableVideoResolutions] containsObject:resolution]) {
return NO;
}
[[self settingsStore] setVideoResolution:resolution];
return YES;
}
- (NSArray<NSString *> *)availableVideoCodecs {
return videoCodecsStaticValues();
}
- (NSString *)currentVideoCodecSettingFromStore {
NSString *videoCodec = [[self settingsStore] videoCodec];
if (!videoCodec) {
videoCodec = [self defaultVideoCodecSetting];
[[self settingsStore] setVideoCodec:videoCodec];
}
return videoCodec;
}
- (BOOL)storeVideoCodecSetting:(NSString *)videoCodec {
if (![[self availableVideoCodecs] containsObject:videoCodec]) {
return NO;
}
[[self settingsStore] setVideoCodec:videoCodec];
return YES;
}
- (nullable NSNumber *)currentMaxBitrateSettingFromStore {
return [[self settingsStore] maxBitrate];
}
- (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate {
[[self settingsStore] setMaxBitrate:bitrate];
}
#pragma mark - Testable
- (ARDSettingsStore *)settingsStore {
if (!_settingsStore) {
_settingsStore = [[ARDSettingsStore alloc] init];
}
return _settingsStore;
}
- (int)currentVideoResolutionWidthFromStore {
NSString *resolution = [self currentVideoResolutionSettingFromStore];
return [self videoResolutionComponentAtIndex:0 inString:resolution];
}
- (int)currentVideoResolutionHeightFromStore {
NSString *resolution = [self currentVideoResolutionSettingFromStore];
return [self videoResolutionComponentAtIndex:1 inString:resolution];
}
#pragma mark -
- (NSString *)defaultVideoResolutionSetting {
return videoResolutionsStaticValues()[0];
}
- (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolution {
if (index != 0 && index != 1) {
return 0;
}
NSArray<NSString *> *components = [resolution componentsSeparatedByString:@"x"];
if (components.count != 2) {
return 0;
}
return components[index].intValue;
}
- (NSString *)defaultVideoCodecSetting {
return videoCodecsStaticValues()[0];
}
@end
NS_ASSUME_NONNULL_END

37
ThirdParty/AppRTC/ARDSettingsStore.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,37 @@
/*
* Copyright 2016 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Light-weight persistent store for user settings.
*
* It will persist between application launches and application updates.
*/
@interface ARDSettingsStore : NSObject
@property(nonatomic) NSString *videoResolution;
@property(nonatomic) NSString *videoCodec;
/**
* Returns current max bitrate number stored in the store.
*/
- (nullable NSNumber *)maxBitrate;
/**
* Stores the provided value as maximum bitrate setting.
* @param value the number to be stored
*/
- (void)setMaxBitrate:(nullable NSNumber *)value;
@end
NS_ASSUME_NONNULL_END

61
ThirdParty/AppRTC/ARDSettingsStore.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,61 @@
/*
* Copyright 2016 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 "ARDSettingsStore.h"
static NSString *const kVideoResolutionKey = @"rtc_video_resolution_key";
static NSString *const kVideoCodecKey = @"rtc_video_codec_key";
static NSString *const kBitrateKey = @"rtc_max_bitrate_key";
NS_ASSUME_NONNULL_BEGIN
@interface ARDSettingsStore () {
NSUserDefaults *_storage;
}
@property(nonatomic, strong, readonly) NSUserDefaults *storage;
@end
@implementation ARDSettingsStore
- (NSUserDefaults *)storage {
if (!_storage) {
_storage = [NSUserDefaults standardUserDefaults];
}
return _storage;
}
- (NSString *)videoResolution {
return [self.storage objectForKey:kVideoResolutionKey];
}
- (void)setVideoResolution:(NSString *)resolution {
[self.storage setObject:resolution forKey:kVideoResolutionKey];
[self.storage synchronize];
}
- (NSString *)videoCodec {
return [self.storage objectForKey:kVideoCodecKey];
}
- (void)setVideoCodec:(NSString *)videoCodec {
[self.storage setObject:videoCodec forKey:kVideoCodecKey];
[self.storage synchronize];
}
- (nullable NSNumber *)maxBitrate {
return [self.storage objectForKey:kBitrateKey];
}
- (void)setMaxBitrate:(nullable NSNumber *)value {
[self.storage setObject:value forKey:kBitrateKey];
[self.storage synchronize];
}
@end
NS_ASSUME_NONNULL_END

59
ThirdParty/AppRTC/ARDSignalingMessage.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,59 @@
/*
* 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 <Foundation/Foundation.h>
#import "WebRTC/RTCIceCandidate.h"
#import "WebRTC/RTCSessionDescription.h"
typedef enum {
kARDSignalingMessageTypeCandidate,
kARDSignalingMessageTypeCandidateRemoval,
kARDSignalingMessageTypeOffer,
kARDSignalingMessageTypeAnswer,
kARDSignalingMessageTypeBye,
} ARDSignalingMessageType;
@interface ARDSignalingMessage : NSObject
@property(nonatomic, readonly) ARDSignalingMessageType type;
+ (ARDSignalingMessage *)messageFromJSONString:(NSString *)jsonString;
- (NSData *)JSONData;
@end
@interface ARDICECandidateMessage : ARDSignalingMessage
@property(nonatomic, readonly) RTCIceCandidate *candidate;
- (instancetype)initWithCandidate:(RTCIceCandidate *)candidate;
@end
@interface ARDICECandidateRemovalMessage : ARDSignalingMessage
@property(nonatomic, readonly) NSArray<RTCIceCandidate *> *candidates;
- (instancetype)initWithRemovedCandidates:
(NSArray<RTCIceCandidate *> *)candidates;
@end
@interface ARDSessionDescriptionMessage : ARDSignalingMessage
@property(nonatomic, readonly) RTCSessionDescription *sessionDescription;
- (instancetype)initWithDescription:(RTCSessionDescription *)description;
@end
@interface ARDByeMessage : ARDSignalingMessage
@end

161
ThirdParty/AppRTC/ARDSignalingMessage.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,161 @@
/*
* 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 "ARDSignalingMessage.h"
#import "WebRTC/RTCLogging.h"
#import "ARDUtilities.h"
#import "RTCIceCandidate+JSON.h"
#import "RTCSessionDescription+JSON.h"
static NSString * const kARDSignalingMessageTypeKey = @"type";
static NSString * const kARDTypeValueRemoveCandidates = @"remove-candidates";
@implementation ARDSignalingMessage
@synthesize type = _type;
- (instancetype)initWithType:(ARDSignalingMessageType)type {
if (self = [super init]) {
_type = type;
}
return self;
}
- (NSString *)description {
return [[NSString alloc] initWithData:[self JSONData]
encoding:NSUTF8StringEncoding];
}
+ (ARDSignalingMessage *)messageFromJSONString:(NSString *)jsonString {
NSDictionary *values = [NSDictionary dictionaryWithJSONString:jsonString];
if (!values) {
RTCLogError(@"Error parsing signaling message JSON.");
return nil;
}
NSString *typeString = values[kARDSignalingMessageTypeKey];
ARDSignalingMessage *message = nil;
if ([typeString isEqualToString:@"candidate"]) {
RTCIceCandidate *candidate =
[RTCIceCandidate candidateFromJSONDictionary:values];
message = [[ARDICECandidateMessage alloc] initWithCandidate:candidate];
} else if ([typeString isEqualToString:kARDTypeValueRemoveCandidates]) {
RTCLogInfo(@"Received remove-candidates message");
NSArray<RTCIceCandidate *> *candidates =
[RTCIceCandidate candidatesFromJSONDictionary:values];
message = [[ARDICECandidateRemovalMessage alloc]
initWithRemovedCandidates:candidates];
} else if ([typeString isEqualToString:@"offer"] ||
[typeString isEqualToString:@"answer"]) {
RTCSessionDescription *description =
[RTCSessionDescription descriptionFromJSONDictionary:values];
message =
[[ARDSessionDescriptionMessage alloc] initWithDescription:description];
} else if ([typeString isEqualToString:@"bye"]) {
message = [[ARDByeMessage alloc] init];
} else {
RTCLogError(@"Unexpected type: %@", typeString);
}
return message;
}
- (NSData *)JSONData {
return nil;
}
@end
@implementation ARDICECandidateMessage
@synthesize candidate = _candidate;
- (instancetype)initWithCandidate:(RTCIceCandidate *)candidate {
if (self = [super initWithType:kARDSignalingMessageTypeCandidate]) {
_candidate = candidate;
}
return self;
}
- (NSData *)JSONData {
return [_candidate JSONData];
}
@end
@implementation ARDICECandidateRemovalMessage
@synthesize candidates = _candidates;
- (instancetype)initWithRemovedCandidates:(
NSArray<RTCIceCandidate *> *)candidates {
NSParameterAssert(candidates.count);
if (self = [super initWithType:kARDSignalingMessageTypeCandidateRemoval]) {
_candidates = candidates;
}
return self;
}
- (NSData *)JSONData {
return
[RTCIceCandidate JSONDataForIceCandidates:_candidates
withType:kARDTypeValueRemoveCandidates];
}
@end
@implementation ARDSessionDescriptionMessage
@synthesize sessionDescription = _sessionDescription;
- (instancetype)initWithDescription:(RTCSessionDescription *)description {
ARDSignalingMessageType messageType = kARDSignalingMessageTypeOffer;
RTCSdpType sdpType = description.type;
switch (sdpType) {
case RTCSdpTypeOffer:
messageType = kARDSignalingMessageTypeOffer;
break;
case RTCSdpTypeAnswer:
messageType = kARDSignalingMessageTypeAnswer;
break;
case RTCSdpTypePrAnswer:
NSAssert(NO, @"Unexpected type: %@",
[RTCSessionDescription stringForType:sdpType]);
break;
}
if (self = [super initWithType:messageType]) {
_sessionDescription = description;
}
return self;
}
- (NSData *)JSONData {
return [_sessionDescription JSONData];
}
@end
@implementation ARDByeMessage
- (instancetype)init {
return [super initWithType:kARDSignalingMessageTypeBye];
}
- (NSData *)JSONData {
NSDictionary *message = @{
@"type": @"bye"
};
return [NSJSONSerialization dataWithJSONObject:message
options:NSJSONWritingPrettyPrinted
error:NULL];
}
@end

38
ThirdParty/AppRTC/ARDUtilities.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
/*
* 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 <Foundation/Foundation.h>
@interface NSDictionary (ARDUtilites)
// Creates a dictionary with the keys and values in the JSON object.
+ (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString;
+ (NSDictionary *)dictionaryWithJSONData:(NSData *)jsonData;
@end
@interface NSURLConnection (ARDUtilities)
// Issues an asynchronous request that calls back on main queue.
+ (void)sendAsyncRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response,
NSData *data,
NSError *error))completionHandler;
// Posts data to the specified URL.
+ (void)sendAsyncPostToURL:(NSURL *)url
withData:(NSData *)data
completionHandler:(void (^)(BOOL succeeded,
NSData *data))completionHandler;
@end
NSInteger ARDGetCpuUsagePercentage();

126
ThirdParty/AppRTC/ARDUtilities.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,126 @@
/*
* 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 "ARDUtilities.h"
#import <mach/mach.h>
#import "WebRTC/RTCLogging.h"
@implementation NSDictionary (ARDUtilites)
+ (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString {
NSParameterAssert(jsonString.length > 0);
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSDictionary *dict =
[NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error) {
RTCLogError(@"Error parsing JSON: %@", error.localizedDescription);
}
return dict;
}
+ (NSDictionary *)dictionaryWithJSONData:(NSData *)jsonData {
NSError *error = nil;
NSDictionary *dict =
[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if (error) {
RTCLogError(@"Error parsing JSON: %@", error.localizedDescription);
}
return dict;
}
@end
@implementation NSURLConnection (ARDUtilities)
+ (void)sendAsyncRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response,
NSData *data,
NSError *error))completionHandler {
// Kick off an async request which will call back on main thread.
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (completionHandler) {
completionHandler(response, data, error);
}
}] resume];
}
// Posts data to the specified URL.
+ (void)sendAsyncPostToURL:(NSURL *)url
withData:(NSData *)data
completionHandler:(void (^)(BOOL succeeded,
NSData *data))completionHandler {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = data;
[[self class] sendAsyncRequest:request
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
if (error) {
RTCLogError(@"Error posting data: %@", error.localizedDescription);
if (completionHandler) {
completionHandler(NO, data);
}
return;
}
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode != 200) {
NSString *serverResponse = data.length > 0 ?
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] :
nil;
RTCLogError(@"Received bad response: %@", serverResponse);
if (completionHandler) {
completionHandler(NO, data);
}
return;
}
if (completionHandler) {
completionHandler(YES, data);
}
}];
}
@end
NSInteger ARDGetCpuUsagePercentage() {
// Create an array of thread ports for the current task.
const task_t task = mach_task_self();
thread_act_array_t thread_array;
mach_msg_type_number_t thread_count;
if (task_threads(task, &thread_array, &thread_count) != KERN_SUCCESS) {
return -1;
}
// Sum cpu usage from all threads.
float cpu_usage_percentage = 0;
thread_basic_info_data_t thread_info_data = {};
mach_msg_type_number_t thread_info_count;
for (size_t i = 0; i < thread_count; ++i) {
thread_info_count = THREAD_BASIC_INFO_COUNT;
kern_return_t ret = thread_info(thread_array[i],
THREAD_BASIC_INFO,
(thread_info_t)&thread_info_data,
&thread_info_count);
if (ret == KERN_SUCCESS) {
cpu_usage_percentage +=
100.f * (float)thread_info_data.cpu_usage / TH_USAGE_SCALE;
}
}
// Dealloc the created array.
vm_deallocate(task, (vm_address_t)thread_array,
sizeof(thread_act_t) * thread_count);
return lroundf(cpu_usage_percentage);
}

22
ThirdParty/AppRTC/RTCIceCandidate+JSON.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,22 @@
/*
* 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 "WebRTC/RTCIceCandidate.h"
@interface RTCIceCandidate (JSON)
+ (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary;
+ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:
(NSDictionary *)dictionary;
+ (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
withType:(NSString *)typeValue;
- (NSData *)JSONData;
@end

100
ThirdParty/AppRTC/RTCIceCandidate+JSON.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,100 @@
/*
* 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 "RTCIceCandidate+JSON.h"
#import "WebRTC/RTCLogging.h"
static NSString const *kRTCICECandidateTypeKey = @"type";
static NSString const *kRTCICECandidateTypeValue = @"candidate";
static NSString const *kRTCICECandidateMidKey = @"id";
static NSString const *kRTCICECandidateMLineIndexKey = @"label";
static NSString const *kRTCICECandidateSdpKey = @"candidate";
static NSString const *kRTCICECandidatesTypeKey = @"candidates";
@implementation RTCIceCandidate (JSON)
+ (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary {
NSString *mid = dictionary[kRTCICECandidateMidKey];
NSString *sdp = dictionary[kRTCICECandidateSdpKey];
NSNumber *num = dictionary[kRTCICECandidateMLineIndexKey];
NSInteger mLineIndex = [num integerValue];
return [[RTCIceCandidate alloc] initWithSdp:sdp
sdpMLineIndex:mLineIndex
sdpMid:mid];
}
+ (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
withType:(NSString *)typeValue {
NSMutableArray *jsonCandidates =
[NSMutableArray arrayWithCapacity:candidates.count];
for (RTCIceCandidate *candidate in candidates) {
NSDictionary *jsonCandidate = [candidate JSONDictionary];
[jsonCandidates addObject:jsonCandidate];
}
NSDictionary *json = @{
kRTCICECandidateTypeKey : typeValue,
kRTCICECandidatesTypeKey : jsonCandidates
};
NSError *error = nil;
NSData *data =
[NSJSONSerialization dataWithJSONObject:json
options:NSJSONWritingPrettyPrinted
error:&error];
if (error) {
RTCLogError(@"Error serializing JSON: %@", error);
return nil;
}
return data;
}
+ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:
(NSDictionary *)dictionary {
NSArray *jsonCandidates = dictionary[kRTCICECandidatesTypeKey];
NSMutableArray<RTCIceCandidate *> *candidates =
[NSMutableArray arrayWithCapacity:jsonCandidates.count];
for (NSDictionary *jsonCandidate in jsonCandidates) {
RTCIceCandidate *candidate =
[RTCIceCandidate candidateFromJSONDictionary:jsonCandidate];
[candidates addObject:candidate];
}
return candidates;
}
- (NSData *)JSONData {
NSDictionary *json = @{
kRTCICECandidateTypeKey : kRTCICECandidateTypeValue,
kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex),
kRTCICECandidateMidKey : self.sdpMid,
kRTCICECandidateSdpKey : self.sdp
};
NSError *error = nil;
NSData *data =
[NSJSONSerialization dataWithJSONObject:json
options:NSJSONWritingPrettyPrinted
error:&error];
if (error) {
RTCLogError(@"Error serializing JSON: %@", error);
return nil;
}
return data;
}
- (NSDictionary *)JSONDictionary{
NSDictionary *json = @{
kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex),
kRTCICECandidateMidKey : self.sdpMid,
kRTCICECandidateSdpKey : self.sdp
};
return json;
}
@end

19
ThirdParty/AppRTC/RTCSessionDescription+JSON.h поставляемый Normal file
Просмотреть файл

@ -0,0 +1,19 @@
/*
* 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 "WebRTC/RTCSessionDescription.h"
@interface RTCSessionDescription (JSON)
+ (RTCSessionDescription *)descriptionFromJSONDictionary:
(NSDictionary *)dictionary;
- (NSData *)JSONData;
@end

35
ThirdParty/AppRTC/RTCSessionDescription+JSON.m поставляемый Normal file
Просмотреть файл

@ -0,0 +1,35 @@
/*
* 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 "RTCSessionDescription+JSON.h"
static NSString const *kRTCSessionDescriptionTypeKey = @"type";
static NSString const *kRTCSessionDescriptionSdpKey = @"sdp";
@implementation RTCSessionDescription (JSON)
+ (RTCSessionDescription *)descriptionFromJSONDictionary:
(NSDictionary *)dictionary {
NSString *typeString = dictionary[kRTCSessionDescriptionTypeKey];
RTCSdpType type = [[self class] typeForString:typeString];
NSString *sdp = dictionary[kRTCSessionDescriptionSdpKey];
return [[RTCSessionDescription alloc] initWithType:type sdp:sdp];
}
- (NSData *)JSONData {
NSString *type = [[self class] stringForType:self.type];
NSDictionary *json = @{
kRTCSessionDescriptionTypeKey : type,
kRTCSessionDescriptionSdpKey : self.sdp
};
return [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
}
@end

Просмотреть файл

@ -13,6 +13,18 @@
2C0574931EDD9E8E00D9E7F2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C0574911EDD9E8E00D9E7F2 /* LaunchScreen.storyboard */; };
2C0574A41EDDA2E300D9E7F2 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C0574A21EDDA2E300D9E7F2 /* LoginViewController.m */; };
2C0574A51EDDA2E300D9E7F2 /* LoginViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C0574A31EDDA2E300D9E7F2 /* LoginViewController.xib */; };
2C2E64251F3462AF00D39CE8 /* NCSignalingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C2E64241F3462AF00D39CE8 /* NCSignalingMessage.m */; };
2C4D7D5A1F2F6D4500FF4A0D /* CallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D581F2F6D4500FF4A0D /* CallViewController.m */; };
2C4D7D5B1F2F6D4500FF4A0D /* CallViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C4D7D591F2F6D4500FF4A0D /* CallViewController.xib */; };
2C4D7D5D1F2F6E9600FF4A0D /* WebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C4D7D5C1F2F6E9600FF4A0D /* WebRTC.framework */; };
2C4D7D5E1F2F6E9600FF4A0D /* WebRTC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 2C4D7D5C1F2F6E9600FF4A0D /* WebRTC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
2C4D7D631F2F7C2C00FF4A0D /* ARDCaptureController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D621F2F7C2C00FF4A0D /* ARDCaptureController.m */; };
2C4D7D691F2F7DBC00FF4A0D /* ARDSettingsModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D651F2F7DBC00FF4A0D /* ARDSettingsModel.m */; };
2C4D7D6A1F2F7DBC00FF4A0D /* ARDSettingsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D681F2F7DBC00FF4A0D /* ARDSettingsStore.m */; };
2C4D7D711F309DA500FF4A0D /* ARDSignalingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D6C1F309DA500FF4A0D /* ARDSignalingMessage.m */; };
2C4D7D721F309DA500FF4A0D /* RTCIceCandidate+JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D6E1F309DA500FF4A0D /* RTCIceCandidate+JSON.m */; };
2C4D7D731F309DA500FF4A0D /* RTCSessionDescription+JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D701F309DA500FF4A0D /* RTCSessionDescription+JSON.m */; };
2C4D7D761F30F7B600FF4A0D /* ARDUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C4D7D751F30F7B600FF4A0D /* ARDUtilities.m */; };
2C90E5641EDDE0FB0093D85A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C90E5631EDDE0FB0093D85A /* Foundation.framework */; };
2C90E5671EDDE1340093D85A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C90E5661EDDE1340093D85A /* CoreGraphics.framework */; };
2C90E5691EDDE13A0093D85A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C90E5681EDDE13A0093D85A /* UIKit.framework */; };
@ -39,6 +51,20 @@
DB6A892B5CEBD4812F7C52EF /* libPods-VideoCalls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6267808DF11BEB859C0BE9F1 /* libPods-VideoCalls.a */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
2C4D7D5F1F2F6E9600FF4A0D /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
2C4D7D5E1F2F6E9600FF4A0D /* WebRTC.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2C05747D1EDD9E8E00D9E7F2 /* VideoCalls.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VideoCalls.app; sourceTree = BUILT_PRODUCTS_DIR; };
2C0574811EDD9E8E00D9E7F2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@ -50,6 +76,28 @@
2C0574A11EDDA2E300D9E7F2 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = "<group>"; };
2C0574A21EDDA2E300D9E7F2 /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = "<group>"; };
2C0574A31EDDA2E300D9E7F2 /* LoginViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LoginViewController.xib; sourceTree = "<group>"; };
2C2E64231F3462AF00D39CE8 /* NCSignalingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NCSignalingMessage.h; sourceTree = "<group>"; };
2C2E64241F3462AF00D39CE8 /* NCSignalingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NCSignalingMessage.m; sourceTree = "<group>"; };
2C4D7D551F2F607E00FF4A0D /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/WebRTC.framework; sourceTree = "<group>"; };
2C4D7D571F2F6D4500FF4A0D /* CallViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallViewController.h; sourceTree = "<group>"; };
2C4D7D581F2F6D4500FF4A0D /* CallViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallViewController.m; sourceTree = "<group>"; };
2C4D7D591F2F6D4500FF4A0D /* CallViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CallViewController.xib; sourceTree = "<group>"; };
2C4D7D5C1F2F6E9600FF4A0D /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = ThirdParty/WebRTC/WebRTC.framework; sourceTree = "<group>"; };
2C4D7D611F2F7C2C00FF4A0D /* ARDCaptureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARDCaptureController.h; sourceTree = "<group>"; };
2C4D7D621F2F7C2C00FF4A0D /* ARDCaptureController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARDCaptureController.m; sourceTree = "<group>"; };
2C4D7D641F2F7DBC00FF4A0D /* ARDSettingsModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARDSettingsModel.h; sourceTree = "<group>"; };
2C4D7D651F2F7DBC00FF4A0D /* ARDSettingsModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARDSettingsModel.m; sourceTree = "<group>"; };
2C4D7D661F2F7DBC00FF4A0D /* ARDSettingsModel+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARDSettingsModel+Private.h"; sourceTree = "<group>"; };
2C4D7D671F2F7DBC00FF4A0D /* ARDSettingsStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARDSettingsStore.h; sourceTree = "<group>"; };
2C4D7D681F2F7DBC00FF4A0D /* ARDSettingsStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARDSettingsStore.m; sourceTree = "<group>"; };
2C4D7D6B1F309DA500FF4A0D /* ARDSignalingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARDSignalingMessage.h; sourceTree = "<group>"; };
2C4D7D6C1F309DA500FF4A0D /* ARDSignalingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARDSignalingMessage.m; sourceTree = "<group>"; };
2C4D7D6D1F309DA500FF4A0D /* RTCIceCandidate+JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RTCIceCandidate+JSON.h"; sourceTree = "<group>"; };
2C4D7D6E1F309DA500FF4A0D /* RTCIceCandidate+JSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RTCIceCandidate+JSON.m"; sourceTree = "<group>"; };
2C4D7D6F1F309DA500FF4A0D /* RTCSessionDescription+JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RTCSessionDescription+JSON.h"; sourceTree = "<group>"; };
2C4D7D701F309DA500FF4A0D /* RTCSessionDescription+JSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RTCSessionDescription+JSON.m"; sourceTree = "<group>"; };
2C4D7D741F30F7B600FF4A0D /* ARDUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARDUtilities.h; sourceTree = "<group>"; };
2C4D7D751F30F7B600FF4A0D /* ARDUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARDUtilities.m; sourceTree = "<group>"; };
2C90E5631EDDE0FB0093D85A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
2C90E5661EDDE1340093D85A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
2C90E5681EDDE13A0093D85A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
@ -100,6 +148,7 @@
2CA1CCCA1F17C503002FE6A2 /* AudioToolbox.framework in Frameworks */,
2CA1CC971F016117002FE6A2 /* Security.framework in Frameworks */,
2C90E5CF1EDF23A00093D85A /* WebKit.framework in Frameworks */,
2C4D7D5D1F2F6E9600FF4A0D /* WebRTC.framework in Frameworks */,
2C90E5691EDDE13A0093D85A /* UIKit.framework in Frameworks */,
2C90E5671EDDE1340093D85A /* CoreGraphics.framework in Frameworks */,
2C90E5641EDDE0FB0093D85A /* Foundation.framework in Frameworks */,
@ -113,6 +162,7 @@
2C0574741EDD9E8E00D9E7F2 = {
isa = PBXGroup;
children = (
2C4D7D5C1F2F6E9600FF4A0D /* WebRTC.framework */,
2C05747E1EDD9E8E00D9E7F2 /* Products */,
2C05749C1EDDA01700D9E7F2 /* ThirdParty */,
2C05747F1EDD9E8E00D9E7F2 /* VideoCalls */,
@ -141,6 +191,9 @@
2CA1CCDA1F1F6FCA002FE6A2 /* CallsTableViewCell.xib */,
2CA1CCA21F025F64002FE6A2 /* CallsTableViewController.h */,
2CA1CCA31F025F64002FE6A2 /* CallsTableViewController.m */,
2C4D7D571F2F6D4500FF4A0D /* CallViewController.h */,
2C4D7D581F2F6D4500FF4A0D /* CallViewController.m */,
2C4D7D591F2F6D4500FF4A0D /* CallViewController.xib */,
2CA1CCD31F1E664C002FE6A2 /* ContactsTableViewCell.h */,
2CA1CCD41F1E664C002FE6A2 /* ContactsTableViewCell.m */,
2CA1CCD51F1E664C002FE6A2 /* ContactsTableViewCell.xib */,
@ -161,6 +214,8 @@
2CA1CCC21F166CC5002FE6A2 /* NCRoom.m */,
2CA1CC931F014EF9002FE6A2 /* NCSettingsController.h */,
2CA1CC941F014EF9002FE6A2 /* NCSettingsController.m */,
2C2E64231F3462AF00D39CE8 /* NCSignalingMessage.h */,
2C2E64241F3462AF00D39CE8 /* NCSignalingMessage.m */,
2CA1CCCB1F181741002FE6A2 /* NCUser.h */,
2CA1CCCC1F181741002FE6A2 /* NCUser.m */,
2CA1CCCE1F1E1779002FE6A2 /* SearchTableViewController.h */,
@ -184,14 +239,39 @@
isa = PBXGroup;
children = (
2C9219591F58530B008AC1A3 /* UIImageView+Letters */,
2C4D7D601F2F7C2C00FF4A0D /* AppRTC */,
2CA1CC9B1F0161FB002FE6A2 /* UICKeyChainStore */,
);
name = ThirdParty;
sourceTree = "<group>";
};
2C4D7D601F2F7C2C00FF4A0D /* AppRTC */ = {
isa = PBXGroup;
children = (
2C4D7D611F2F7C2C00FF4A0D /* ARDCaptureController.h */,
2C4D7D621F2F7C2C00FF4A0D /* ARDCaptureController.m */,
2C4D7D641F2F7DBC00FF4A0D /* ARDSettingsModel.h */,
2C4D7D651F2F7DBC00FF4A0D /* ARDSettingsModel.m */,
2C4D7D661F2F7DBC00FF4A0D /* ARDSettingsModel+Private.h */,
2C4D7D671F2F7DBC00FF4A0D /* ARDSettingsStore.h */,
2C4D7D681F2F7DBC00FF4A0D /* ARDSettingsStore.m */,
2C4D7D6B1F309DA500FF4A0D /* ARDSignalingMessage.h */,
2C4D7D6C1F309DA500FF4A0D /* ARDSignalingMessage.m */,
2C4D7D741F30F7B600FF4A0D /* ARDUtilities.h */,
2C4D7D751F30F7B600FF4A0D /* ARDUtilities.m */,
2C4D7D6D1F309DA500FF4A0D /* RTCIceCandidate+JSON.h */,
2C4D7D6E1F309DA500FF4A0D /* RTCIceCandidate+JSON.m */,
2C4D7D6F1F309DA500FF4A0D /* RTCSessionDescription+JSON.h */,
2C4D7D701F309DA500FF4A0D /* RTCSessionDescription+JSON.m */,
);
name = AppRTC;
path = ThirdParty/AppRTC;
sourceTree = "<group>";
};
2C90E5621EDDE0FB0093D85A /* Frameworks */ = {
isa = PBXGroup;
children = (
2C4D7D551F2F607E00FF4A0D /* WebRTC.framework */,
2CA1CCC91F17C503002FE6A2 /* AudioToolbox.framework */,
2CA1CC961F016117002FE6A2 /* Security.framework */,
2C90E5CE1EDF23A00093D85A /* WebKit.framework */,
@ -244,6 +324,7 @@
2C05747B1EDD9E8E00D9E7F2 /* Resources */,
29696B57B26EBF9C28436CE8 /* [CP] Embed Pods Frameworks */,
A3C686B1B84C4462F93441AB /* [CP] Copy Pods Resources */,
2C4D7D5F1F2F6E9600FF4A0D /* Embed Frameworks */,
);
buildRules = (
);
@ -297,6 +378,7 @@
2CA1CCDC1F1F6FCA002FE6A2 /* CallsTableViewCell.xib in Resources */,
2C0574931EDD9E8E00D9E7F2 /* LaunchScreen.storyboard in Resources */,
2CA1CCAC1F067F35002FE6A2 /* Images.xcassets in Resources */,
2C4D7D5B1F2F6D4500FF4A0D /* CallViewController.xib in Resources */,
2CA1CCD71F1E664C002FE6A2 /* ContactsTableViewCell.xib in Resources */,
2C05748E1EDD9E8E00D9E7F2 /* Main.storyboard in Resources */,
);
@ -361,18 +443,27 @@
2CA1CCDB1F1F6FCA002FE6A2 /* CallsTableViewCell.m in Sources */,
2CA1CCC31F166CC5002FE6A2 /* NCRoom.m in Sources */,
2CA1CCA71F026222002FE6A2 /* ContactsTableViewController.m in Sources */,
2C4D7D761F30F7B600FF4A0D /* ARDUtilities.m in Sources */,
2CA1CCAA1F02D1A4002FE6A2 /* NCAPIController.m in Sources */,
2C4D7D731F309DA500FF4A0D /* RTCSessionDescription+JSON.m in Sources */,
2C2E64251F3462AF00D39CE8 /* NCSignalingMessage.m in Sources */,
2C4D7D721F309DA500FF4A0D /* RTCIceCandidate+JSON.m in Sources */,
2C0574821EDD9E8E00D9E7F2 /* main.m in Sources */,
2CA1CCA41F025F64002FE6A2 /* CallsTableViewController.m in Sources */,
2C90E5D31EE80C870093D85A /* AuthenticationViewController.m in Sources */,
2CA1CCD01F1E1779002FE6A2 /* SearchTableViewController.m in Sources */,
2C0574A41EDDA2E300D9E7F2 /* LoginViewController.m in Sources */,
2CA1CCCD1F181741002FE6A2 /* NCUser.m in Sources */,
2C4D7D5A1F2F6D4500FF4A0D /* CallViewController.m in Sources */,
2CA1CCD61F1E664C002FE6A2 /* ContactsTableViewCell.m in Sources */,
2CA1CC911F014354002FE6A2 /* NCConnectionController.m in Sources */,
2C92195C1F58530B008AC1A3 /* UIImageView+Letters.m in Sources */,
2C4D7D691F2F7DBC00FF4A0D /* ARDSettingsModel.m in Sources */,
2CA1CCB51F0D0D5E002FE6A2 /* SettingsViewController.m in Sources */,
2C4D7D711F309DA500FF4A0D /* ARDSignalingMessage.m in Sources */,
2CA1CC951F014EF9002FE6A2 /* NCSettingsController.m in Sources */,
2C4D7D631F2F7C2C00FF4A0D /* ARDCaptureController.m in Sources */,
2C4D7D6A1F2F7DBC00FF4A0D /* ARDSettingsStore.m in Sources */,
2CA1CC9A1F0161EA002FE6A2 /* UICKeyChainStore.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -497,8 +588,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 7T56CJ62G4;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/ThirdParty/WebRTC",
);
INFOPLIST_FILE = VideoCalls/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.strukturag.VideoCalls;
PRODUCT_NAME = "$(TARGET_NAME)";
};
@ -510,8 +606,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 7T56CJ62G4;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/ThirdParty/WebRTC",
);
INFOPLIST_FILE = VideoCalls/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.strukturag.VideoCalls;
PRODUCT_NAME = "$(TARGET_NAME)";
};

Просмотреть файл

@ -0,0 +1,19 @@
//
// CallViewController.h
// VideoCalls
//
// Created by Ivan Sein on 31.07.17.
// Copyright © 2017 struktur AG. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <WebRTC/WebRTC.h>
@interface CallViewController : UIViewController
@property (strong, nonatomic) IBOutlet RTCCameraPreviewView *localVideoView;
@property (strong, nonatomic) IBOutlet UIView *remoteView;
- (instancetype)initWithSessionId:(NSString *)sessionId;
@end

Просмотреть файл

@ -0,0 +1,422 @@
//
// CallViewController.m
// VideoCalls
//
// Created by Ivan Sein on 31.07.17.
// Copyright © 2017 struktur AG. All rights reserved.
//
#import "CallViewController.h"
#import "ARDSettingsModel.h"
#import "ARDCaptureController.h"
#import "ARDSignalingMessage.h"
#import "NCAPIController.h"
#import "NCSignalingMessage.h"
static NSString * const kNCMediaStreamId = @"NCMS";
static NSString * const kNCAudioTrackId = @"NCa0";
static NSString * const kNCVideoTrackId = @"NCv0";
static NSString * const kNCVideoTrackKind = @"video";
@interface CallViewController () <RTCPeerConnectionDelegate, RTCEAGLVideoViewDelegate>
{
NSString *_sessionId;
RTCPeerConnectionFactory *_factory;
NSMapTable *_sessionIdMap;
NSMutableDictionary *_peerConnectionDict;
NSMutableArray *_usersInCall;
RTCVideoTrack *_localVideoTrack;
ARDCaptureController *_captureController;
UIView<RTCVideoRenderer> *_remoteVideoView;
CGSize _remoteVideoSize;
}
@end
@implementation CallViewController
- (instancetype)initWithSessionId:(NSString *)sessionId
{
self = [super init];
if (!self) {
return nil;
}
_sessionId = sessionId;
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_factory = [[RTCPeerConnectionFactory alloc] init];
_sessionIdMap = [[NSMapTable alloc] init];
_peerConnectionDict = [[NSMutableDictionary alloc] init];
_usersInCall = [[NSMutableArray alloc] init];
RTCEAGLVideoView *remoteView = [[RTCEAGLVideoView alloc] initWithFrame:_remoteView.layer.bounds];
remoteView.delegate = self;
_remoteVideoView = remoteView;
[_remoteView addSubview:_remoteVideoView];
[self startPullingSignallingMessages];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)videoView:(RTCEAGLVideoView*)videoView didChangeVideoSize:(CGSize)size
{
if (videoView == _remoteVideoView) {
_remoteVideoSize = size;
_remoteVideoView.bounds = _remoteView.bounds;
}
[_remoteView setNeedsLayout];
}
#pragma mark - RTCPeerConnectionDelegate
// Callbacks for this delegate occur on non-main thread and need to be
// dispatched back to main queue as needed.
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeSignalingState:(RTCSignalingState)stateChanged
{
NSLog(@"Signaling state changed: %ld", (long)stateChanged);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Received %lu video tracks and %lu audio tracks",
(unsigned long)stream.videoTracks.count,
(unsigned long)stream.audioTracks.count);
if (stream.videoTracks.count) {
RTCVideoTrack *videoTrack = stream.videoTracks[0];
[self setRemoteVideoTrack:videoTrack];
}
});
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveStream:(RTCMediaStream *)stream
{
NSLog(@"Stream was removed.");
}
- (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection
{
NSLog(@"WARNING: Renegotiation needed but unimplemented.");
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceConnectionState:(RTCIceConnectionState)newState
{
NSLog(@"ICE state changed: %ld", (long)newState);
dispatch_async(dispatch_get_main_queue(), ^{
// [_delegate appClient:self didChangeConnectionState:newState];
});
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceGatheringState:(RTCIceGatheringState)newState
{
NSLog(@"ICE gathering state changed: %ld", (long)newState);
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didGenerateIceCandidate:(RTCIceCandidate *)candidate
{
dispatch_async(dispatch_get_main_queue(), ^{
NSString *to = [_sessionIdMap objectForKey:peerConnection];
NCICECandidateMessage *message = [[NCICECandidateMessage alloc] initWithCandidate:candidate
from:_sessionId
to:to
sid:[NCSignalingMessage getMessageSid]
roomType:@"video"];
[self sendSignalingMessage:message];
});
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
{
NSLog(@"PeerConnection didRemoveIceCandidates delegate has been called.");
}
- (void)peerConnection:(RTCPeerConnection *)peerConnection didOpenDataChannel:(RTCDataChannel *)dataChannel
{
NSLog(@"Data channel was opened.");
}
#pragma mark - Audio & Video senders
- (RTCRtpSender *)createAudioSenderForPeerConnection:(RTCPeerConnection *)peerConnection
{
NSDictionary *mandatoryConstraints = @{ kRTCMediaConstraintsLevelControl : kRTCMediaConstraintsValueTrue };
RTCMediaConstraints *constraints =
[[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints
optionalConstraints:nil];
RTCAudioSource *source = [_factory audioSourceWithConstraints:constraints];
RTCAudioTrack *track = [_factory audioTrackWithSource:source trackId:kNCAudioTrackId];
RTCRtpSender *sender =
[peerConnection senderWithKind:kRTCMediaStreamTrackKindAudio
streamId:kNCMediaStreamId];
sender.track = track;
return sender;
}
- (RTCRtpSender *)createVideoSenderForPeerConnection:(RTCPeerConnection *)peerConnection
{
RTCRtpSender *sender =
[peerConnection senderWithKind:kRTCMediaStreamTrackKindVideo
streamId:kNCMediaStreamId];
RTCVideoSource *source = [_factory videoSource];
RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source];
ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
_localVideoView.captureSession = capturer.captureSession;
_captureController = [[ARDCaptureController alloc] initWithCapturer:capturer settings:settingsModel];
[_captureController startCapture];
_localVideoTrack = [_factory videoTrackWithSource:source trackId:kNCVideoTrackId];
return sender;
}
- (void)setRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack
{
[_remoteVideoView renderFrame:nil];
[remoteVideoTrack addRenderer:_remoteVideoView];
}
#pragma mark - Utils
- (RTCMediaConstraints *)defaultAnswerConstraints
{
return [self defaultOfferConstraints];
}
- (RTCMediaConstraints *)defaultOfferConstraints
{
NSDictionary *mandatoryConstraints = @{
@"OfferToReceiveAudio" : @"true",
@"OfferToReceiveVideo" : @"true"
};
RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc]
initWithMandatoryConstraints:mandatoryConstraints
optionalConstraints:nil];
return constraints;
}
#pragma mark - Signalling
- (void)startPullingSignallingMessages
{
[[NCAPIController sharedInstance] pullSignallingMessagesWithCompletionBlock:^(NSDictionary *messages, NSError *error, NSInteger errorCode) {
NSArray *messagesArray = [[messages objectForKey:@"ocs"] objectForKey:@"data"];
for (NSDictionary *message in messagesArray) {
NSString *messageType = [message objectForKey:@"type"];
if ([messageType isEqualToString:@"usersInRoom"]) {
[self processUsersInRoom:[message objectForKey:@"data"]];
} else if ([messageType isEqualToString:@"message"]) {
NCSignalingMessage *signalingMessage = [NCSignalingMessage messageFromJSONString:[message objectForKey:@"data"]];
[self processSignalingMessage:signalingMessage];
} else {
NSLog(@"Uknown message: %@", [message objectForKey:@"data"]);
}
}
[self startPullingSignallingMessages];
}];
}
- (void)sendSignalingMessages:(NSArray *)messages
{
[[NCAPIController sharedInstance] sendSignallingMessages:[self messagesJSONSerialization:messages] withCompletionBlock:^(NSError *error, NSInteger errorCode) {
NSLog(@"Sent %ld signalling messages", messages.count);
}];
}
- (void)sendSignalingMessage:(NCSignalingMessage *)message
{
NSArray *messagesArray = [NSArray arrayWithObjects:[message messageDict], nil];
NSString *JSONSerializedMessages = [self messagesJSONSerialization:messagesArray];
[[NCAPIController sharedInstance] sendSignallingMessages:JSONSerializedMessages withCompletionBlock:^(NSError *error, NSInteger errorCode) {
if (error) {
//TODO: Error handling
NSLog(@"Error sending signaling message.");
}
NSLog(@"Sent %@", JSONSerializedMessages);
}];
}
- (NSString *)messagesJSONSerialization:(NSArray *)messages
{
NSError *error;
NSString *jsonString = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:messages
options:0
error:&error];
if (! jsonData) {
NSLog(@"Got an error: %@", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return jsonString;
}
- (void)processUsersInRoom:(NSArray *)users
{
for (NSDictionary *user in users) {
NSString *sessionId = [user objectForKey:@"sessionId"];
if([_sessionId isEqualToString:sessionId]) {
return;
}
if (![_peerConnectionDict objectForKey:sessionId]) {
NSComparisonResult result = [sessionId compare:_sessionId];
if (result == NSOrderedAscending) {
NSLog(@"Creating offer...");
[self createPeerConnectionWithOfferForSessionId:sessionId];
} else {
NSLog(@"Waiting for offer...");
}
}
}
}
- (void)processSignalingMessage:(NCSignalingMessage *)message
{
switch (message.messageType) {
case kNCSignalingMessageTypeOffer:
case kNCSignalingMessageTypeAnswer: {
NCSessionDescriptionMessage *sdpMessage = (NCSessionDescriptionMessage *)message;
RTCSessionDescription *description = sdpMessage.sessionDescription;
RTCPeerConnection *peerConnection = [self getPeerConnectionForSessionId:message.from];
[peerConnection setRemoteDescription:description completionHandler:^(NSError *error) {
[self peerConnectionForSessionId:message.from didSetSessionDescriptionWithError:error];
}];
break;
}
case kNCSignalingMessageTypeCandidate: {
NCICECandidateMessage *candidateMessage = (NCICECandidateMessage *)message;
RTCPeerConnection *peerConnection = [self getPeerConnectionForSessionId:message.from];
[peerConnection addIceCandidate:candidateMessage.candidate];
break;
}
case kNCSignalingMessageTypeUknown:
NSLog(@"Trying to process an unkown type message.");
break;
}
}
#pragma mark - Peer Connection
- (RTCPeerConnection *)getPeerConnectionForSessionId:(NSString *)sessionId
{
RTCPeerConnection *peerConnection = [_peerConnectionDict objectForKey:sessionId];
if (!peerConnection) {
// Create peer connection.
RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc]
initWithMandatoryConstraints:nil
optionalConstraints:nil];
RTCConfiguration *config = [[RTCConfiguration alloc] init];
peerConnection = [_factory peerConnectionWithConfiguration:config
constraints:constraints
delegate:self];
[_sessionIdMap setObject:sessionId forKey:peerConnection];
[_peerConnectionDict setObject:peerConnection forKey:sessionId];
}
return peerConnection;
}
- (void)createPeerConnectionWithOfferForSessionId:(NSString *)sessionId
{
// Create peer connection.
RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc]
initWithMandatoryConstraints:nil
optionalConstraints:nil];
RTCConfiguration *config = [[RTCConfiguration alloc] init];
RTCPeerConnection *peerConnection = [_factory peerConnectionWithConfiguration:config
constraints:constraints
delegate:self];
[_sessionIdMap setObject:sessionId forKey:peerConnection];
[_peerConnectionDict setObject:peerConnection forKey:sessionId];
[peerConnection offerForConstraints:[self defaultOfferConstraints]
completionHandler:^(RTCSessionDescription *sdp,
NSError *error) {
[peerConnection setLocalDescription:sdp completionHandler:^(NSError *error) {
NCSessionDescriptionMessage *message = [[NCSessionDescriptionMessage alloc]
initWithSessionDescription:sdp
from:_sessionId
to:sessionId
sid:[NCSignalingMessage getMessageSid]
roomType:@"video"];
[self sendSignalingMessage:message];
}];
}];
}
#pragma mark - RTCSessionDescriptionDelegate
// Callbacks for this delegate occur on non-main thread and need to be
// dispatched back to main queue as needed.
- (void)peerConnectionForSessionId:(NSString *)sessionId
didCreateSessionDescription:(RTCSessionDescription *)sdp
error:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"didCreateSessionDescription: %ld", (long)sdp.type);
RTCPeerConnection *peerConnection = [self getPeerConnectionForSessionId:sessionId];
[peerConnection setLocalDescription:sdp completionHandler:^(NSError *error) {
[self peerConnectionForSessionId:sessionId didSetSessionDescriptionWithError:error];
}];
NCSessionDescriptionMessage *message = [[NCSessionDescriptionMessage alloc]
initWithSessionDescription:sdp
from:_sessionId to:sessionId
sid:[NCSignalingMessage getMessageSid]
roomType:@"video"];
[self sendSignalingMessage:message];
// [self setMaxBitrateForPeerConnectionVideoSender];
});
}
- (void)peerConnectionForSessionId:(NSString *)sessionId
didSetSessionDescriptionWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
// If we're answering and we've just set the remote offer we need to create
// an answer and set the local description.
NSLog(@"didSetSessionDescription");
RTCPeerConnection *peerConnection = [self getPeerConnectionForSessionId:sessionId];
if (!peerConnection.localDescription) {
NSLog(@"creating local description");
RTCMediaConstraints *constraints = [self defaultAnswerConstraints];
[peerConnection answerForConstraints:constraints completionHandler:^(RTCSessionDescription *sdp, NSError *error) {
[self peerConnectionForSessionId:sessionId didCreateSessionDescription:sdp error:error];
}];
}
});
}
@end

Просмотреть файл

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="CallViewController">
<connections>
<outlet property="localVideoView" destination="LVE-DF-0nt" id="9D4-Vw-5IK"/>
<outlet property="remoteView" destination="Xb2-0h-P58" id="d2H-d8-nnz"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xb2-0h-P58" userLabel="remoteVideo">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LVE-DF-0nt" userLabel="localVideo" customClass="RTCCameraPreviewView">
<rect key="frame" x="239" y="477" width="120" height="170"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<point key="canvasLocation" x="34.5" y="54.5"/>
</view>
</objects>
</document>

Просмотреть файл

@ -10,6 +10,7 @@
#import "AFNetworking.h"
#import "AuthenticationViewController.h"
#import "CallViewController.h"
#import "CallsTableViewCell.h"
#import "LoginViewController.h"
#import "NCAPIController.h"
@ -298,6 +299,8 @@
if (!error) {
_currentCallToken = room.token;
[self startPingCall];
CallViewController *callVC = [[CallViewController alloc] initWithSessionId:sessionId];
[self presentViewController:callVC animated:YES completion:nil];
}
}];

Просмотреть файл

@ -58,7 +58,7 @@ typedef void (^PullSignallingMessagesCompletionBlock)(NSDictionary *messages, NS
- (void)leaveCall:(NSString *)token withCompletionBlock:(LeaveCallCompletionBlock)block;
// Signalling Controller
- (void)sendSignallingMessages:(NSArray *)messages withCompletionBlock:(SendSignallingMessagesCompletionBlock)block;
- (void)sendSignallingMessages:(NSString *)messages withCompletionBlock:(SendSignallingMessagesCompletionBlock)block;
- (void)pullSignallingMessagesWithCompletionBlock:(PullSignallingMessagesCompletionBlock)block;
// User avatars

Просмотреть файл

@ -318,7 +318,7 @@ NSString * const kNCUserAgent = @"Video Calls iOS";
#pragma mark - Signalling Controller
- (void)sendSignallingMessages:(NSArray *)messages withCompletionBlock:(SendSignallingMessagesCompletionBlock)block
- (void)sendSignallingMessages:(NSString *)messages withCompletionBlock:(SendSignallingMessagesCompletionBlock)block
{
NSString *URLString = [self getRequestURLForSpreedEndpoint:@"signalling"];
NSDictionary *parameters = @{@"messages" : messages};

Просмотреть файл

@ -0,0 +1,64 @@
//
// NCSignalingMessage.h
// VideoCalls
//
// Created by Ivan Sein on 04.08.17.
// Copyright © 2017 struktur AG. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WebRTC/RTCIceCandidate.h"
#import "WebRTC/RTCSessionDescription.h"
typedef enum {
kNCSignalingMessageTypeUknown,
kNCSignalingMessageTypeCandidate,
kNCSignalingMessageTypeOffer,
kNCSignalingMessageTypeAnswer,
} NCSignalingMessageType;
@interface NCSignalingMessage : NSObject
@property(nonatomic, readonly) NSString *from;
@property(nonatomic, readonly) NSString *to;
@property(nonatomic, readonly) NSString *sid;
@property(nonatomic, readonly) NSString *type;
@property(nonatomic, readonly) NSDictionary *payload;
@property(nonatomic, readonly) NSString *roomType;
+ (NCSignalingMessage *)messageFromJSONString:(NSString *)jsonString;
+ (NSString *)getMessageSid;
- (NSDictionary *)messageDict;
- (NCSignalingMessageType)messageType;
@end
@interface NCICECandidateMessage : NCSignalingMessage
@property(nonatomic, readonly) RTCIceCandidate *candidate;
- (instancetype)initWithValues:(NSDictionary *)values;
- (instancetype)initWithCandidate:(RTCIceCandidate *)candidate
from:(NSString *)from
to:(NSString *)to
sid:(NSString *)sid
roomType:(NSString *)roomType;
@end
@interface NCSessionDescriptionMessage : NCSignalingMessage
@property(nonatomic, readonly) RTCSessionDescription *sessionDescription;
- (instancetype)initWithValues:(NSDictionary *)values;
- (instancetype)initWithSessionDescription:(RTCSessionDescription *)sessionDescription
from:(NSString *)from
to:(NSString *)to
sid:(NSString *)sid
roomType:(NSString *)roomType;
@end

Просмотреть файл

@ -0,0 +1,316 @@
//
// NCSignalingMessage.m
// VideoCalls
//
// Created by Ivan Sein on 04.08.17.
// Copyright © 2017 struktur AG. All rights reserved.
//
#import "NCSignalingMessage.h"
#import "WebRTC/RTCLogging.h"
#import "ARDUtilities.h"
#import "RTCIceCandidate+JSON.h"
#import "RTCSessionDescription+JSON.h"
static NSString * const kNCSignalingMessageEventKey = @"ev";
static NSString * const kNCSignalingMessageFunctionKey = @"fn";
static NSString * const kNCSignalingMessageSessionIdKey = @"sessionId";
static NSString * const kNCSignalingMessageKey = @"message";
static NSString * const kNCSignalingMessageDataKey = @"data";
static NSString * const kNCSignalingMessageFromKey = @"from";
static NSString * const kNCSignalingMessageToKey = @"to";
static NSString * const kNCSignalingMessageSidKey = @"sid";
static NSString * const kNCSignalingMessageTypeKey = @"type";
static NSString * const kNCSignalingMessagePayloadKey = @"payload";
static NSString * const kNCSignalingMessageRoomTypeKey = @"roomType";
static NSString * const kNCSignalingMessageTypeOfferKey = @"offer";
static NSString * const kNCSignalingMessageTypeAnswerKey = @"answer";
static NSString * const kNCSignalingMessageTypeCandidateKey = @"candidate";
static NSString * const kNCSignalingMessageTypeRemoveCandidatesKey = @"remove-candidates";
static NSString * const kNCSignalingMessageSdpKey = @"sdp";
@implementation NCSignalingMessage
@synthesize from = _from;
@synthesize to = _to;
@synthesize type = _type;
@synthesize payload = _payload;
@synthesize roomType = _roomType;
@synthesize sid = _sid;
- (instancetype)initWithFrom:(NSString *)from
to:(NSString *)to
sid:(NSString *)sid
type:(NSString *)type
payload:(NSDictionary *)payload
roomType:(NSString *)roomType
{
if (self = [super init]) {
_from = from;
_to = to;
_sid = sid;
_type = type;
_payload = payload;
_roomType = roomType;
}
return self;
}
- (NSString *)description {
return [[NSString alloc] initWithData:[self JSONData]
encoding:NSUTF8StringEncoding];
}
+ (NCSignalingMessage *)messageFromJSONString:(NSString *)jsonString {
NSDictionary *values = [NSDictionary dictionaryWithJSONString:jsonString];
if (!values) {
RTCLogError(@"Error parsing signaling message JSON.");
return nil;
}
NSString *typeString = values[kNCSignalingMessageTypeKey];
NCSignalingMessage *message = nil;
if ([typeString isEqualToString:kNCSignalingMessageTypeCandidateKey]) {
message = [[NCICECandidateMessage alloc] initWithValues:values];
} else if ([typeString isEqualToString:kNCSignalingMessageTypeOfferKey] ||
[typeString isEqualToString:kNCSignalingMessageTypeAnswerKey]) {
message = [[NCSessionDescriptionMessage alloc] initWithValues:values];
} else {
RTCLogError(@"Unexpected type: %@", typeString);
}
return message;
}
- (NSData *)JSONData {
return nil;
}
- (NSDictionary *)messageDict {
return nil;
}
- (NCSignalingMessageType)messageType {
return kNCSignalingMessageTypeUknown;
}
+ (NSString *)getMessageSid {
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
return [[NSNumber numberWithDouble: timeStamp] stringValue];
}
@end
@implementation NCICECandidateMessage
@synthesize candidate = _candidate;
- (instancetype)initWithValues:(NSDictionary *)values {
RTCIceCandidate *candidate = [RTCIceCandidate candidateFromJSONDictionary:[[values objectForKey:kNCSignalingMessagePayloadKey] objectForKey:kNCSignalingMessageTypeCandidateKey]];
return [self initWithCandidate:candidate
from:[values objectForKey:kNCSignalingMessageFromKey]
to:[values objectForKey:kNCSignalingMessageToKey]
sid:[values objectForKey:kNCSignalingMessageSidKey]
roomType:[values objectForKey:kNCSignalingMessageRoomTypeKey]];
}
- (NSData *)JSONData {
NSError *error = nil;
NSData *data =
[NSJSONSerialization dataWithJSONObject:[self functionDict]
options:NSJSONWritingPrettyPrinted
error:&error];
if (error) {
RTCLogError(@"Error serializing JSON: %@", error);
return nil;
}
return data;
}
- (NSString *)functionJSONSerialization
{
NSError *error;
NSString *jsonString = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self functionDict]
options:0
error:&error];
if (! jsonData) {
NSLog(@"Error serializing JSON: %@", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return jsonString;
}
- (NSDictionary *)messageDict {
return @{
kNCSignalingMessageEventKey: kNCSignalingMessageKey,
kNCSignalingMessageFunctionKey: [self functionJSONSerialization],
kNCSignalingMessageSessionIdKey: self.from
};
}
- (NSDictionary *)functionDict {
return @{
kNCSignalingMessageToKey: self.to,
kNCSignalingMessageSidKey: self.sid,
kNCSignalingMessageRoomTypeKey: self.roomType,
kNCSignalingMessageTypeKey: self.type,
kNCSignalingMessagePayloadKey: @{
kNCSignalingMessageTypeKey: self.type,
kNCSignalingMessageTypeCandidateKey: [self.candidate JSONDictionary]
},
};
}
- (NCSignalingMessageType)messageType {
return kNCSignalingMessageTypeCandidate;
}
- (instancetype)initWithCandidate:(RTCIceCandidate *)candidate
from:(NSString *)from
to:(NSString *)to
sid:(NSString *)sid
roomType:(NSString *)roomType
{
NSDictionary *payload = [[NSDictionary alloc] init];
self = [super initWithFrom:from
to:to
sid:sid
type:kNCSignalingMessageTypeCandidateKey
payload:payload
roomType:roomType];
if (!self) {
return nil;
}
_candidate = candidate;
return self;
}
@end
@implementation NCSessionDescriptionMessage
@synthesize sessionDescription = _sessionDescription;
- (instancetype)initWithValues:(NSDictionary *)values {
RTCSessionDescription *description = [RTCSessionDescription descriptionFromJSONDictionary:[values objectForKey:kNCSignalingMessagePayloadKey]];
return [self initWithSessionDescription:description
from:[values objectForKey:kNCSignalingMessageFromKey]
to:[values objectForKey:kNCSignalingMessageToKey]
sid:[values objectForKey:kNCSignalingMessageSidKey]
roomType:[values objectForKey:kNCSignalingMessageRoomTypeKey]];
}
- (NSData *)JSONData {
NSError *error = nil;
NSData *data =
[NSJSONSerialization dataWithJSONObject:[self messageDict]
options:0
error:&error];
if (error) {
RTCLogError(@"Error serializing JSON: %@", error);
return nil;
}
return data;
}
- (NSString *)functionJSONSerialization
{
NSError *error;
NSString *jsonString = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self functionDict]
options:0
error:&error];
if (! jsonData) {
NSLog(@"Error serializing JSON: %@", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return jsonString;
}
- (NSDictionary *)messageDict {
return @{
kNCSignalingMessageEventKey: kNCSignalingMessageKey,
kNCSignalingMessageFunctionKey: [self functionJSONSerialization],
kNCSignalingMessageSessionIdKey: self.from
};
}
- (NSDictionary *)functionDict {
return @{
kNCSignalingMessageToKey: self.to,
kNCSignalingMessageSidKey: self.sid,
kNCSignalingMessageRoomTypeKey: self.roomType,
kNCSignalingMessageTypeKey: self.type,
kNCSignalingMessagePayloadKey: @{
kNCSignalingMessageTypeKey: self.type,
kNCSignalingMessageSdpKey: self.sessionDescription.sdp
},
};
}
- (NCSignalingMessageType)messageType {
if ([self.type isEqualToString:kNCSignalingMessageTypeOfferKey]) {
return kNCSignalingMessageTypeOffer;
}
return kNCSignalingMessageTypeAnswer;
}
- (instancetype)initWithSessionDescription:(RTCSessionDescription *)sessionDescription
from:(NSString *)from
to:(NSString *)to
sid:(NSString *)sid
roomType:(NSString *)roomType {
RTCSdpType sdpType = sessionDescription.type;
NSString *type = nil;
switch (sdpType) {
case RTCSdpTypeOffer:
type = kNCSignalingMessageTypeOfferKey;
break;
case RTCSdpTypeAnswer:
type = kNCSignalingMessageTypeAnswerKey;
break;
case RTCSdpTypePrAnswer:
NSAssert(NO, @"Unexpected type: %@",
[RTCSessionDescription stringForType:sdpType]);
break;
}
NSMutableDictionary *payload = [[NSMutableDictionary alloc] init];
[payload setObject:type forKey:kNCSignalingMessageTypeKey];
[payload setObject:sessionDescription.sdp forKey:kNCSignalingMessageSdpKey];
self = [super initWithFrom:from
to:to
sid:sid
type:type
payload:payload
roomType:roomType];
if (!self) {
return nil;
}
_sessionDescription = sessionDescription;
return self;
}
@end