├── .github └── workflows │ └── ci.yml ├── .gitignore ├── AppRTCMobile.xcodeproj └── project.pbxproj ├── Default-568h@2x.png ├── Podfile ├── Podfile.lock ├── README.md └── webrtc ├── ARDAppClient+Internal.h ├── ARDAppClient.h ├── ARDAppClient.m ├── ARDAppEngineClient.h ├── ARDAppEngineClient.m ├── ARDBitrateTracker.h ├── ARDBitrateTracker.m ├── ARDCaptureController.h ├── ARDCaptureController.m ├── ARDExternalSampleCapturer.h ├── ARDExternalSampleCapturer.m ├── ARDJoinResponse+Internal.h ├── ARDJoinResponse.h ├── ARDJoinResponse.m ├── ARDMessageResponse+Internal.h ├── ARDMessageResponse.h ├── ARDMessageResponse.m ├── ARDRoomServerClient.h ├── ARDSettingsModel+Private.h ├── ARDSettingsModel.h ├── ARDSettingsModel.m ├── ARDSettingsStore.h ├── ARDSettingsStore.m ├── ARDSignalingChannel.h ├── ARDSignalingMessage.h ├── ARDSignalingMessage.m ├── ARDStatsBuilder.h ├── ARDStatsBuilder.m ├── ARDTURNClient+Internal.h ├── ARDTURNClient.h ├── ARDTURNClient.m ├── ARDWebSocketChannel.h ├── ARDWebSocketChannel.m ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Icon.png ├── RTCIceCandidate+JSON.h ├── RTCIceCandidate+JSON.m ├── RTCIceServer+JSON.h ├── RTCIceServer+JSON.m ├── RTCMediaConstraints+JSON.h ├── RTCMediaConstraints+JSON.m ├── RTCSessionDescription+JSON.h ├── RTCSessionDescription+JSON.m ├── common ├── ARDUtilities.h └── ARDUtilities.m ├── internal ├── RTCAudioSession+Private.h ├── RTCAudioSession.h ├── RTCAudioSessionConfiguration.h ├── RTCAudioSessionDelegateAdapter.h ├── RTCCertificate.h └── RTCH264ProfileLevelId.h ├── ios ├── ARDAppDelegate.h ├── ARDAppDelegate.m ├── ARDFileCaptureController.h ├── ARDFileCaptureController.m ├── ARDMainView.h ├── ARDMainView.m ├── ARDMainViewController.h ├── ARDMainViewController.m ├── ARDSettingsViewController.h ├── ARDSettingsViewController.m ├── ARDStatsView.h ├── ARDStatsView.m ├── ARDVideoCallView.h ├── ARDVideoCallView.m ├── ARDVideoCallViewController.h ├── ARDVideoCallViewController.m ├── Info.plist ├── RTCVideoCodecInfo+HumanReadable.h ├── RTCVideoCodecInfo+HumanReadable.m ├── UIImage+ARDUtilities.h ├── UIImage+ARDUtilities.m ├── broadcast_extension │ ├── ARDBroadcastSampleHandler.h │ ├── ARDBroadcastSampleHandler.m │ ├── ARDBroadcastSetupViewController.h │ ├── ARDBroadcastSetupViewController.m │ ├── BroadcastSetupUIInfo.plist │ └── BroadcastUploadInfo.plist ├── main.m └── resources │ ├── Roboto-Regular.ttf │ ├── foreman.mp4 │ ├── iPhone5@2x.png │ ├── iPhone6@2x.png │ ├── iPhone6p@3x.png │ ├── ic_call_end_black_24dp.png │ ├── ic_call_end_black_24dp@2x.png │ ├── ic_clear_black_24dp.png │ ├── ic_clear_black_24dp@2x.png │ ├── ic_settings_black_24dp.png │ ├── ic_settings_black_24dp@2x.png │ ├── ic_surround_sound_black_24dp.png │ ├── ic_surround_sound_black_24dp@2x.png │ ├── ic_switch_video_black_24dp.png │ ├── ic_switch_video_black_24dp@2x.png │ └── mozart.mp3 ├── mac ├── APPRTCAppDelegate.h ├── APPRTCAppDelegate.m ├── APPRTCViewController.h ├── APPRTCViewController.m ├── Info.plist └── main.m ├── tests ├── ARDAppClient_xctest.mm ├── ARDFileCaptureController_xctest.mm ├── ARDSettingsModel_xctest.mm └── main.mm └── third_party └── SocketRocket ├── LICENSE ├── SRWebSocket.h └── SRWebSocket.m /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | runs-on: macos-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - uses: actions/cache@v2 10 | with: 11 | path: Pods 12 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 13 | restore-keys: ${{ runner.os }}-pods- 14 | - run: pod install 15 | - run: open AppRTCMobile.xcworkspace 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ##### 2 | # OS X temporary files that should never be committed 3 | # 4 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 5 | .DS_Store 6 | 7 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 8 | .Trashes 9 | 10 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html 11 | *.swp 12 | 13 | # *.lock - this is used and abused by many editors for many different things. 14 | # For the main ones I use (e.g. Eclipse), it should be excluded 15 | # from source-control, but YMMV 16 | # *.lock 17 | 18 | # 19 | # profile - REMOVED temporarily (on double-checking, this seems incorrect; I can't find it in OS X docs?) 20 | #profile 21 | 22 | #### 23 | # Xcode temporary files that should never be committed 24 | # 25 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this... 26 | *~.nib 27 | 28 | #### 29 | # Xcode build files - 30 | # 31 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData" 32 | DerivedData/ 33 | 34 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build" 35 | build/ 36 | 37 | ##### 38 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) 39 | # 40 | # This is complicated: 41 | # 42 | # SOMETIMES you need to put this file in version control. 43 | # Apple designed it poorly - if you use "custom executables", they are 44 | # saved in this file. 45 | # 99% of projects do NOT use those, so they do NOT want to version control this file. 46 | # ..but if you're in the 1%, comment out the line "*.pbxuser" 47 | 48 | # .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html 49 | 50 | *.pbxuser 51 | 52 | # .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 53 | 54 | *.mode1v3 55 | 56 | # .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html 57 | 58 | *.mode2v3 59 | 60 | # .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file 61 | 62 | *.perspectivev3 63 | 64 | # NB: also, whitelist the default ones, some projects need to use these 65 | !default.pbxuser 66 | !default.mode1v3 67 | !default.mode2v3 68 | !default.perspectivev3 69 | 70 | 71 | #### 72 | # Xcode 4 - semi-personal settings 73 | # 74 | # 75 | # OPTION 1: --------------------------------- 76 | # throw away ALL personal settings (including custom schemes! 77 | # - unless they are "shared") 78 | # 79 | # NB: this is exclusive with OPTION 2 below 80 | xcuserdata 81 | 82 | # OPTION 2: --------------------------------- 83 | # get rid of ALL personal settings, but KEEP SOME OF THEM 84 | # - NB: you must manually uncomment the bits you want to keep 85 | # 86 | # NB: this is exclusive with OPTION 1 above 87 | # 88 | #xcuserdata/**/* 89 | 90 | # (requires option 2 above): Personal Schemes 91 | # 92 | #!xcuserdata/**/xcschemes/* 93 | 94 | #### 95 | # XCode 4 workspaces - more detailed 96 | # 97 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :) 98 | # 99 | # Workspace layout is quite spammy. For reference: 100 | # 101 | # /(root)/ 102 | # /(project-name).xcodeproj/ 103 | # project.pbxproj 104 | # /project.xcworkspace/ 105 | # contents.xcworkspacedata 106 | # /xcuserdata/ 107 | # /(your name)/xcuserdatad/ 108 | # UserInterfaceState.xcuserstate 109 | # /xcsshareddata/ 110 | # /xcschemes/ 111 | # (shared scheme name).xcscheme 112 | # /xcuserdata/ 113 | # /(your name)/xcuserdatad/ 114 | # (private scheme).xcscheme 115 | # xcschememanagement.plist 116 | # 117 | # 118 | 119 | #### 120 | # Xcode 4 - Deprecated classes 121 | # 122 | # Allegedly, if you manually "deprecate" your classes, they get moved here. 123 | # 124 | # We're using source-control, so this is a "feature" that we do not want! 125 | 126 | *.moved-aside 127 | 128 | Pods/ 129 | 130 | .svn 131 | 132 | .todo 133 | *.xcworkspace 134 | *.xccheckout 135 | *.xcuserstate 136 | *.playground/ 137 | */xcshareddata/ 138 | xcuserdata/* 139 | L10N 140 | -------------------------------------------------------------------------------- /Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/Default-568h@2x.png -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'AppRTCMobile' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | # Pods for AppRTCMobile 9 | pod 'GoogleWebRTC', '~> 1.1.29400' 10 | 11 | 12 | end 13 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - GoogleWebRTC (1.1.31999) 3 | 4 | DEPENDENCIES: 5 | - GoogleWebRTC (~> 1.1.29400) 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - GoogleWebRTC 10 | 11 | SPEC CHECKSUMS: 12 | GoogleWebRTC: b39a78c4f5cc6b0323415b9233db03a2faa7b0f0 13 | 14 | PODFILE CHECKSUM: a053d0f8c9417f0e3d9caf94c3f88e51d9692459 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AppRTCMobile [![Build](https://github.com/crossle/AppRTCMobile/actions/workflows/ci.yml/badge.svg)](https://github.com/crossle/AppRTCMobile/actions/workflows/ci.yml) 2 | 3 | use Xcode compile AppRTCMobile 4 | 5 | `pod install` 6 | `open AppRTCMobile.xcworkspace` 7 | -------------------------------------------------------------------------------- /webrtc/ARDAppClient+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDAppClient.h" 12 | 13 | #import 14 | 15 | #import "ARDRoomServerClient.h" 16 | #import "ARDSignalingChannel.h" 17 | #import "ARDTURNClient.h" 18 | 19 | @class RTC_OBJC_TYPE(RTCPeerConnectionFactory); 20 | 21 | @interface ARDAppClient () 22 | 23 | // All properties should only be mutated from the main queue. 24 | @property(nonatomic, strong) id roomServerClient; 25 | @property(nonatomic, strong) id channel; 26 | @property(nonatomic, strong) id loopbackChannel; 27 | @property(nonatomic, strong) id turnClient; 28 | 29 | @property(nonatomic, strong) RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection; 30 | @property(nonatomic, strong) RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory; 31 | @property(nonatomic, strong) NSMutableArray *messageQueue; 32 | 33 | @property(nonatomic, assign) BOOL isTurnComplete; 34 | @property(nonatomic, assign) BOOL hasReceivedSdp; 35 | @property(nonatomic, readonly) BOOL hasJoinedRoomServerRoom; 36 | 37 | @property(nonatomic, strong) NSString *roomId; 38 | @property(nonatomic, strong) NSString *clientId; 39 | @property(nonatomic, assign) BOOL isInitiator; 40 | @property(nonatomic, strong) NSMutableArray *iceServers; 41 | @property(nonatomic, strong) NSURL *webSocketURL; 42 | @property(nonatomic, strong) NSURL *webSocketRestURL; 43 | @property(nonatomic, readonly) BOOL isLoopback; 44 | 45 | @property(nonatomic, strong) RTC_OBJC_TYPE(RTCMediaConstraints) * defaultPeerConnectionConstraints; 46 | 47 | - (instancetype)initWithRoomServerClient:(id)rsClient 48 | signalingChannel:(id)channel 49 | turnClient:(id)turnClient 50 | delegate:(id)delegate; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /webrtc/ARDAppClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | typedef NS_ENUM(NSInteger, ARDAppClientState) { 17 | // Disconnected from servers. 18 | kARDAppClientStateDisconnected, 19 | // Connecting to servers. 20 | kARDAppClientStateConnecting, 21 | // Connected to servers. 22 | kARDAppClientStateConnected, 23 | }; 24 | 25 | @class ARDAppClient; 26 | @class ARDSettingsModel; 27 | @class ARDExternalSampleCapturer; 28 | @class RTC_OBJC_TYPE(RTCMediaConstraints); 29 | @class RTC_OBJC_TYPE(RTCCameraVideoCapturer); 30 | @class RTC_OBJC_TYPE(RTCFileVideoCapturer); 31 | 32 | // The delegate is informed of pertinent events and will be called on the 33 | // main queue. 34 | @protocol ARDAppClientDelegate 35 | 36 | - (void)appClient:(ARDAppClient *)client didChangeState:(ARDAppClientState)state; 37 | 38 | - (void)appClient:(ARDAppClient *)client didChangeConnectionState:(RTCIceConnectionState)state; 39 | 40 | - (void)appClient:(ARDAppClient *)client 41 | didCreateLocalCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)localCapturer; 42 | 43 | - (void)appClient:(ARDAppClient *)client 44 | didReceiveLocalVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)localVideoTrack; 45 | 46 | - (void)appClient:(ARDAppClient *)client 47 | didReceiveRemoteVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack; 48 | 49 | - (void)appClient:(ARDAppClient *)client didError:(NSError *)error; 50 | 51 | - (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats; 52 | 53 | @optional 54 | - (void)appClient:(ARDAppClient *)client 55 | didCreateLocalFileCapturer:(RTC_OBJC_TYPE(RTCFileVideoCapturer) *)fileCapturer; 56 | 57 | - (void)appClient:(ARDAppClient *)client 58 | didCreateLocalExternalSampleCapturer:(ARDExternalSampleCapturer *)externalSampleCapturer; 59 | 60 | @end 61 | 62 | // Handles connections to the AppRTC server for a given room. Methods on this 63 | // class should only be called from the main queue. 64 | @interface ARDAppClient : NSObject 65 | 66 | // If |shouldGetStats| is true, stats will be reported in 1s intervals through 67 | // the delegate. 68 | @property(nonatomic, assign) BOOL shouldGetStats; 69 | @property(nonatomic, readonly) ARDAppClientState state; 70 | @property(nonatomic, weak) id delegate; 71 | @property(nonatomic, assign, getter=isBroadcast) BOOL broadcast; 72 | 73 | // Convenience constructor since all expected use cases will need a delegate 74 | // in order to receive remote tracks. 75 | - (instancetype)initWithDelegate:(id)delegate; 76 | 77 | // Establishes a connection with the AppRTC servers for the given room id. 78 | // |settings| is an object containing settings such as video codec for the call. 79 | // If |isLoopback| is true, the call will connect to itself. 80 | - (void)connectToRoomWithId:(NSString *)roomId 81 | settings:(ARDSettingsModel *)settings 82 | isLoopback:(BOOL)isLoopback; 83 | 84 | // Disconnects from the AppRTC servers and any connected clients. 85 | - (void)disconnect; 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /webrtc/ARDAppEngineClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDRoomServerClient.h" 12 | 13 | @interface ARDAppEngineClient : NSObject 14 | @end 15 | -------------------------------------------------------------------------------- /webrtc/ARDAppEngineClient.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDAppEngineClient.h" 12 | 13 | #import 14 | 15 | #import "ARDJoinResponse.h" 16 | #import "ARDMessageResponse.h" 17 | #import "ARDSignalingMessage.h" 18 | #import "ARDUtilities.h" 19 | 20 | // TODO(tkchin): move these to a configuration object. 21 | static NSString * const kARDRoomServerHostUrl = 22 | @"https://appr.tc"; 23 | static NSString * const kARDRoomServerJoinFormat = 24 | @"https://appr.tc/join/%@"; 25 | static NSString * const kARDRoomServerJoinFormatLoopback = 26 | @"https://appr.tc/join/%@?debug=loopback"; 27 | static NSString * const kARDRoomServerMessageFormat = 28 | @"https://appr.tc/message/%@/%@"; 29 | static NSString * const kARDRoomServerLeaveFormat = 30 | @"https://appr.tc/leave/%@/%@"; 31 | 32 | static NSString * const kARDAppEngineClientErrorDomain = @"ARDAppEngineClient"; 33 | static NSInteger const kARDAppEngineClientErrorBadResponse = -1; 34 | 35 | @implementation ARDAppEngineClient 36 | 37 | #pragma mark - ARDRoomServerClient 38 | 39 | - (void)joinRoomWithRoomId:(NSString *)roomId 40 | isLoopback:(BOOL)isLoopback 41 | completionHandler:(void (^)(ARDJoinResponse *response, 42 | NSError *error))completionHandler { 43 | NSParameterAssert(roomId.length); 44 | 45 | NSString *urlString = nil; 46 | if (isLoopback) { 47 | urlString = 48 | [NSString stringWithFormat:kARDRoomServerJoinFormatLoopback, roomId]; 49 | } else { 50 | urlString = 51 | [NSString stringWithFormat:kARDRoomServerJoinFormat, roomId]; 52 | } 53 | 54 | NSURL *roomURL = [NSURL URLWithString:urlString]; 55 | RTCLog(@"Joining room:%@ on room server.", roomId); 56 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL]; 57 | request.HTTPMethod = @"POST"; 58 | [NSURLConnection sendAsyncRequest:request 59 | completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 60 | if (error) { 61 | if (completionHandler) { 62 | completionHandler(nil, error); 63 | } 64 | return; 65 | } 66 | ARDJoinResponse *joinResponse = [ARDJoinResponse responseFromJSONData:data]; 67 | if (!joinResponse) { 68 | if (completionHandler) { 69 | NSError *error = [[self class] badResponseError]; 70 | completionHandler(nil, error); 71 | } 72 | return; 73 | } 74 | if (completionHandler) { 75 | completionHandler(joinResponse, nil); 76 | } 77 | }]; 78 | } 79 | 80 | - (void)sendMessage:(ARDSignalingMessage *)message 81 | forRoomId:(NSString *)roomId 82 | clientId:(NSString *)clientId 83 | completionHandler:(void (^)(ARDMessageResponse *response, 84 | NSError *error))completionHandler { 85 | NSParameterAssert(message); 86 | NSParameterAssert(roomId.length); 87 | NSParameterAssert(clientId.length); 88 | 89 | NSData *data = [message JSONData]; 90 | NSString *urlString = 91 | [NSString stringWithFormat: 92 | kARDRoomServerMessageFormat, roomId, clientId]; 93 | NSURL *url = [NSURL URLWithString:urlString]; 94 | RTCLog(@"C->RS POST: %@", message); 95 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 96 | request.HTTPMethod = @"POST"; 97 | request.HTTPBody = data; 98 | [NSURLConnection sendAsyncRequest:request 99 | completionHandler:^(NSURLResponse *response, 100 | NSData *data, 101 | NSError *error) { 102 | if (error) { 103 | if (completionHandler) { 104 | completionHandler(nil, error); 105 | } 106 | return; 107 | } 108 | ARDMessageResponse *messageResponse = 109 | [ARDMessageResponse responseFromJSONData:data]; 110 | if (!messageResponse) { 111 | if (completionHandler) { 112 | NSError *error = [[self class] badResponseError]; 113 | completionHandler(nil, error); 114 | } 115 | return; 116 | } 117 | if (completionHandler) { 118 | completionHandler(messageResponse, nil); 119 | } 120 | }]; 121 | } 122 | 123 | - (void)leaveRoomWithRoomId:(NSString *)roomId 124 | clientId:(NSString *)clientId 125 | completionHandler:(void (^)(NSError *error))completionHandler { 126 | NSParameterAssert(roomId.length); 127 | NSParameterAssert(clientId.length); 128 | 129 | NSString *urlString = 130 | [NSString stringWithFormat:kARDRoomServerLeaveFormat, roomId, clientId]; 131 | NSURL *url = [NSURL URLWithString:urlString]; 132 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 133 | request.HTTPMethod = @"POST"; 134 | 135 | RTCLog(@"C->RS: BYE"); 136 | __block NSError *error = nil; 137 | 138 | // We want a synchronous request so that we know that we've left the room on 139 | // room server before we do any further work. 140 | dispatch_semaphore_t sem = dispatch_semaphore_create(0); 141 | [NSURLConnection sendAsyncRequest:request 142 | completionHandler:^(NSURLResponse *response, NSData *data, NSError *e) { 143 | if (e) { 144 | error = e; 145 | } 146 | dispatch_semaphore_signal(sem); 147 | }]; 148 | 149 | dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 150 | if (error) { 151 | RTCLogError(@"Error leaving room %@ on room server: %@", roomId, error.localizedDescription); 152 | if (completionHandler) { 153 | completionHandler(error); 154 | } 155 | return; 156 | } 157 | RTCLog(@"Left room:%@ on room server.", roomId); 158 | if (completionHandler) { 159 | completionHandler(nil); 160 | } 161 | } 162 | 163 | #pragma mark - Private 164 | 165 | + (NSError *)badResponseError { 166 | NSError *error = 167 | [[NSError alloc] initWithDomain:kARDAppEngineClientErrorDomain 168 | code:kARDAppEngineClientErrorBadResponse 169 | userInfo:@{ 170 | NSLocalizedDescriptionKey: @"Error parsing response.", 171 | }]; 172 | return error; 173 | } 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /webrtc/ARDBitrateTracker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | /** Class used to estimate bitrate based on byte count. It is expected that 14 | * byte count is monotonocially increasing. This class tracks the times that 15 | * byte count is updated, and measures the bitrate based on the byte difference 16 | * over the interval between updates. 17 | */ 18 | @interface ARDBitrateTracker : NSObject 19 | 20 | /** The bitrate in bits per second. */ 21 | @property(nonatomic, readonly) double bitrate; 22 | /** The bitrate as a formatted string in bps, Kbps or Mbps. */ 23 | @property(nonatomic, readonly) NSString *bitrateString; 24 | 25 | /** Converts the bitrate to a readable format in bps, Kbps or Mbps. */ 26 | + (NSString *)bitrateStringForBitrate:(double)bitrate; 27 | /** Updates the tracked bitrate with the new byte count. */ 28 | - (void)updateBitrateWithCurrentByteCount:(NSInteger)byteCount; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /webrtc/ARDBitrateTracker.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDBitrateTracker.h" 12 | 13 | #import 14 | 15 | @implementation ARDBitrateTracker { 16 | CFTimeInterval _prevTime; 17 | NSInteger _prevByteCount; 18 | } 19 | 20 | @synthesize bitrate = _bitrate; 21 | 22 | + (NSString *)bitrateStringForBitrate:(double)bitrate { 23 | if (bitrate > 1e6) { 24 | return [NSString stringWithFormat:@"%.2fMbps", bitrate * 1e-6]; 25 | } else if (bitrate > 1e3) { 26 | return [NSString stringWithFormat:@"%.0fKbps", bitrate * 1e-3]; 27 | } else { 28 | return [NSString stringWithFormat:@"%.0fbps", bitrate]; 29 | } 30 | } 31 | 32 | - (NSString *)bitrateString { 33 | return [[self class] bitrateStringForBitrate:_bitrate]; 34 | } 35 | 36 | - (void)updateBitrateWithCurrentByteCount:(NSInteger)byteCount { 37 | CFTimeInterval currentTime = CACurrentMediaTime(); 38 | if (_prevTime && (byteCount > _prevByteCount)) { 39 | _bitrate = (byteCount - _prevByteCount) * 8 / (currentTime - _prevTime); 40 | } 41 | _prevByteCount = byteCount; 42 | _prevTime = currentTime; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /webrtc/ARDCaptureController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @class ARDSettingsModel; 14 | 15 | // Controls the camera. Handles starting the capture, switching cameras etc. 16 | @interface ARDCaptureController : NSObject 17 | 18 | - (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer 19 | settings:(ARDSettingsModel *)settings; 20 | - (void)startCapture; 21 | - (void)startCapture:(void (^)(NSError *))completion; 22 | - (void)stopCapture; 23 | - (void)switchCamera; 24 | - (void)switchCamera:(void (^)(NSError *))completion; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /webrtc/ARDCaptureController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDCaptureController.h" 12 | 13 | #import 14 | 15 | #import "ARDSettingsModel.h" 16 | 17 | const Float64 kFramerateLimit = 30.0; 18 | 19 | @implementation ARDCaptureController { 20 | RTC_OBJC_TYPE(RTCCameraVideoCapturer) * _capturer; 21 | ARDSettingsModel *_settings; 22 | BOOL _usingFrontCamera; 23 | } 24 | 25 | - (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)capturer 26 | settings:(ARDSettingsModel *)settings { 27 | if (self = [super init]) { 28 | _capturer = capturer; 29 | _settings = settings; 30 | _usingFrontCamera = YES; 31 | } 32 | 33 | return self; 34 | } 35 | 36 | - (void)startCapture { 37 | [self startCapture:nil]; 38 | } 39 | 40 | - (void)startCapture:(void (^)(NSError *))completion { 41 | AVCaptureDevicePosition position = 42 | _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack; 43 | AVCaptureDevice *device = [self findDeviceForPosition:position]; 44 | AVCaptureDeviceFormat *format = [self selectFormatForDevice:device]; 45 | 46 | if (format == nil) { 47 | RTCLogError(@"No valid formats for device %@", device); 48 | NSAssert(NO, @""); 49 | 50 | return; 51 | } 52 | 53 | NSInteger fps = [self selectFpsForFormat:format]; 54 | 55 | [_capturer startCaptureWithDevice:device format:format fps:fps completionHandler:completion]; 56 | } 57 | 58 | - (void)stopCapture { 59 | [_capturer stopCapture]; 60 | } 61 | 62 | - (void)switchCamera { 63 | _usingFrontCamera = !_usingFrontCamera; 64 | [self startCapture:nil]; 65 | } 66 | 67 | - (void)switchCamera:(void (^)(NSError *))completion { 68 | _usingFrontCamera = !_usingFrontCamera; 69 | [self startCapture:completion]; 70 | } 71 | 72 | #pragma mark - Private 73 | 74 | - (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position { 75 | NSArray *captureDevices = 76 | [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]; 77 | for (AVCaptureDevice *device in captureDevices) { 78 | if (device.position == position) { 79 | return device; 80 | } 81 | } 82 | return captureDevices[0]; 83 | } 84 | 85 | - (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device { 86 | NSArray *formats = 87 | [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]; 88 | int targetWidth = [_settings currentVideoResolutionWidthFromStore]; 89 | int targetHeight = [_settings currentVideoResolutionHeightFromStore]; 90 | AVCaptureDeviceFormat *selectedFormat = nil; 91 | int currentDiff = INT_MAX; 92 | 93 | for (AVCaptureDeviceFormat *format in formats) { 94 | CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription); 95 | FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription); 96 | int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height); 97 | if (diff < currentDiff) { 98 | selectedFormat = format; 99 | currentDiff = diff; 100 | } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) { 101 | selectedFormat = format; 102 | } 103 | } 104 | 105 | return selectedFormat; 106 | } 107 | 108 | - (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format { 109 | Float64 maxSupportedFramerate = 0; 110 | for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { 111 | maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate); 112 | } 113 | return fmin(maxSupportedFramerate, kFramerateLimit); 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /webrtc/ARDExternalSampleCapturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @protocol ARDExternalSampleDelegate 14 | - (void)didCaptureSampleBuffer:(CMSampleBufferRef)sampleBuffer; 15 | @end 16 | 17 | @interface ARDExternalSampleCapturer : RTC_OBJC_TYPE 18 | (RTCVideoCapturer) @end 19 | -------------------------------------------------------------------------------- /webrtc/ARDExternalSampleCapturer.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDExternalSampleCapturer.h" 12 | 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | 22 | @implementation ARDExternalSampleCapturer 23 | 24 | - (instancetype)initWithDelegate:(__weak id)delegate { 25 | return [super initWithDelegate:delegate]; 26 | } 27 | 28 | #pragma mark - ARDExternalSampleDelegate 29 | 30 | - (void)didCaptureSampleBuffer:(CMSampleBufferRef)sampleBuffer { 31 | if (CMSampleBufferGetNumSamples(sampleBuffer) != 1 || !CMSampleBufferIsValid(sampleBuffer) || 32 | !CMSampleBufferDataIsReady(sampleBuffer)) { 33 | return; 34 | } 35 | 36 | CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 37 | if (pixelBuffer == nil) { 38 | return; 39 | } 40 | 41 | RTC_OBJC_TYPE(RTCCVPixelBuffer) *rtcPixelBuffer = 42 | [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBuffer]; 43 | int64_t timeStampNs = 44 | CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) * NSEC_PER_SEC; 45 | RTC_OBJC_TYPE(RTCVideoFrame) *videoFrame = 46 | [[RTC_OBJC_TYPE(RTCVideoFrame) alloc] initWithBuffer:rtcPixelBuffer 47 | rotation:RTCVideoRotation_0 48 | timeStampNs:timeStampNs]; 49 | [self.delegate capturer:self didCaptureVideoFrame:videoFrame]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /webrtc/ARDJoinResponse+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDJoinResponse.h" 12 | 13 | @interface ARDJoinResponse () 14 | 15 | @property(nonatomic, assign) ARDJoinResultType result; 16 | @property(nonatomic, assign) BOOL isInitiator; 17 | @property(nonatomic, strong) NSString* roomId; 18 | @property(nonatomic, strong) NSString* clientId; 19 | @property(nonatomic, strong) NSArray* messages; 20 | @property(nonatomic, strong) NSURL* webSocketURL; 21 | @property(nonatomic, strong) NSURL* webSocketRestURL; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /webrtc/ARDJoinResponse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | typedef NS_ENUM(NSInteger, ARDJoinResultType) { 14 | kARDJoinResultTypeUnknown, 15 | kARDJoinResultTypeSuccess, 16 | kARDJoinResultTypeFull 17 | }; 18 | 19 | // Result of joining a room on the room server. 20 | @interface ARDJoinResponse : NSObject 21 | 22 | @property(nonatomic, readonly) ARDJoinResultType result; 23 | @property(nonatomic, readonly) BOOL isInitiator; 24 | @property(nonatomic, readonly) NSString *roomId; 25 | @property(nonatomic, readonly) NSString *clientId; 26 | @property(nonatomic, readonly) NSArray *messages; 27 | @property(nonatomic, readonly) NSURL *webSocketURL; 28 | @property(nonatomic, readonly) NSURL *webSocketRestURL; 29 | 30 | + (ARDJoinResponse *)responseFromJSONData:(NSData *)data; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /webrtc/ARDJoinResponse.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDJoinResponse+Internal.h" 12 | 13 | #import "ARDSignalingMessage.h" 14 | #import "ARDUtilities.h" 15 | #import "RTCIceServer+JSON.h" 16 | 17 | static NSString const *kARDJoinResultKey = @"result"; 18 | static NSString const *kARDJoinResultParamsKey = @"params"; 19 | static NSString const *kARDJoinInitiatorKey = @"is_initiator"; 20 | static NSString const *kARDJoinRoomIdKey = @"room_id"; 21 | static NSString const *kARDJoinClientIdKey = @"client_id"; 22 | static NSString const *kARDJoinMessagesKey = @"messages"; 23 | static NSString const *kARDJoinWebSocketURLKey = @"wss_url"; 24 | static NSString const *kARDJoinWebSocketRestURLKey = @"wss_post_url"; 25 | 26 | @implementation ARDJoinResponse 27 | 28 | @synthesize result = _result; 29 | @synthesize isInitiator = _isInitiator; 30 | @synthesize roomId = _roomId; 31 | @synthesize clientId = _clientId; 32 | @synthesize messages = _messages; 33 | @synthesize webSocketURL = _webSocketURL; 34 | @synthesize webSocketRestURL = _webSocketRestURL; 35 | 36 | + (ARDJoinResponse *)responseFromJSONData:(NSData *)data { 37 | NSDictionary *responseJSON = [NSDictionary dictionaryWithJSONData:data]; 38 | if (!responseJSON) { 39 | return nil; 40 | } 41 | ARDJoinResponse *response = [[ARDJoinResponse alloc] init]; 42 | NSString *resultString = responseJSON[kARDJoinResultKey]; 43 | response.result = [[self class] resultTypeFromString:resultString]; 44 | NSDictionary *params = responseJSON[kARDJoinResultParamsKey]; 45 | 46 | response.isInitiator = [params[kARDJoinInitiatorKey] boolValue]; 47 | response.roomId = params[kARDJoinRoomIdKey]; 48 | response.clientId = params[kARDJoinClientIdKey]; 49 | 50 | // Parse messages. 51 | NSArray *messages = params[kARDJoinMessagesKey]; 52 | NSMutableArray *signalingMessages = 53 | [NSMutableArray arrayWithCapacity:messages.count]; 54 | for (NSString *message in messages) { 55 | ARDSignalingMessage *signalingMessage = 56 | [ARDSignalingMessage messageFromJSONString:message]; 57 | [signalingMessages addObject:signalingMessage]; 58 | } 59 | response.messages = signalingMessages; 60 | 61 | // Parse websocket urls. 62 | NSString *webSocketURLString = params[kARDJoinWebSocketURLKey]; 63 | response.webSocketURL = [NSURL URLWithString:webSocketURLString]; 64 | NSString *webSocketRestURLString = params[kARDJoinWebSocketRestURLKey]; 65 | response.webSocketRestURL = [NSURL URLWithString:webSocketRestURLString]; 66 | 67 | return response; 68 | } 69 | 70 | #pragma mark - Private 71 | 72 | + (ARDJoinResultType)resultTypeFromString:(NSString *)resultString { 73 | ARDJoinResultType result = kARDJoinResultTypeUnknown; 74 | if ([resultString isEqualToString:@"SUCCESS"]) { 75 | result = kARDJoinResultTypeSuccess; 76 | } else if ([resultString isEqualToString:@"FULL"]) { 77 | result = kARDJoinResultTypeFull; 78 | } 79 | return result; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /webrtc/ARDMessageResponse+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDMessageResponse.h" 12 | 13 | @interface ARDMessageResponse () 14 | 15 | @property(nonatomic, assign) ARDMessageResultType result; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/ARDMessageResponse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | typedef NS_ENUM(NSInteger, ARDMessageResultType) { 14 | kARDMessageResultTypeUnknown, 15 | kARDMessageResultTypeSuccess, 16 | kARDMessageResultTypeInvalidRoom, 17 | kARDMessageResultTypeInvalidClient 18 | }; 19 | 20 | @interface ARDMessageResponse : NSObject 21 | 22 | @property(nonatomic, readonly) ARDMessageResultType result; 23 | 24 | + (ARDMessageResponse *)responseFromJSONData:(NSData *)data; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /webrtc/ARDMessageResponse.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDMessageResponse+Internal.h" 12 | 13 | #import "ARDUtilities.h" 14 | 15 | static NSString const *kARDMessageResultKey = @"result"; 16 | 17 | @implementation ARDMessageResponse 18 | 19 | @synthesize result = _result; 20 | 21 | + (ARDMessageResponse *)responseFromJSONData:(NSData *)data { 22 | NSDictionary *responseJSON = [NSDictionary dictionaryWithJSONData:data]; 23 | if (!responseJSON) { 24 | return nil; 25 | } 26 | ARDMessageResponse *response = [[ARDMessageResponse alloc] init]; 27 | response.result = 28 | [[self class] resultTypeFromString:responseJSON[kARDMessageResultKey]]; 29 | return response; 30 | } 31 | 32 | #pragma mark - Private 33 | 34 | + (ARDMessageResultType)resultTypeFromString:(NSString *)resultString { 35 | ARDMessageResultType result = kARDMessageResultTypeUnknown; 36 | if ([resultString isEqualToString:@"SUCCESS"]) { 37 | result = kARDMessageResultTypeSuccess; 38 | } else if ([resultString isEqualToString:@"INVALID_CLIENT"]) { 39 | result = kARDMessageResultTypeInvalidClient; 40 | } else if ([resultString isEqualToString:@"INVALID_ROOM"]) { 41 | result = kARDMessageResultTypeInvalidRoom; 42 | } 43 | return result; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /webrtc/ARDRoomServerClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @class ARDJoinResponse; 14 | @class ARDMessageResponse; 15 | @class ARDSignalingMessage; 16 | 17 | @protocol ARDRoomServerClient 18 | 19 | - (void)joinRoomWithRoomId:(NSString *)roomId 20 | isLoopback:(BOOL)isLoopback 21 | completionHandler:(void (^)(ARDJoinResponse *response, NSError *error))completionHandler; 22 | 23 | - (void)sendMessage:(ARDSignalingMessage *)message 24 | forRoomId:(NSString *)roomId 25 | clientId:(NSString *)clientId 26 | completionHandler:(void (^)(ARDMessageResponse *response, NSError *error))completionHandler; 27 | 28 | - (void)leaveRoomWithRoomId:(NSString *)roomId 29 | clientId:(NSString *)clientId 30 | completionHandler:(void (^)(NSError *error))completionHandler; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /webrtc/ARDSettingsModel+Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import "ARDSettingsModel.h" 14 | 15 | @class ARDSettingsStore; 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | @interface ARDSettingsModel () 19 | - (ARDSettingsStore *)settingsStore; 20 | @end 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /webrtc/ARDSettingsModel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | /** 18 | * Model class for user defined settings. 19 | * 20 | * Handles storing the settings and provides default values if setting is not 21 | * set. Also provides list of available options for different settings. Stores 22 | * for example video codec, video resolution and maximum bitrate. 23 | */ 24 | @interface ARDSettingsModel : NSObject 25 | 26 | /** 27 | * Returns array of available capture resoultions. 28 | * 29 | * The capture resolutions are represented as strings in the following format 30 | * [width]x[height] 31 | */ 32 | - (NSArray *)availableVideoResolutions; 33 | 34 | /** 35 | * Returns current video resolution string. 36 | * If no resolution is in store, default value of 640x480 is returned. 37 | * When defaulting to value, the default is saved in store for consistency reasons. 38 | */ 39 | - (NSString *)currentVideoResolutionSettingFromStore; 40 | - (int)currentVideoResolutionWidthFromStore; 41 | - (int)currentVideoResolutionHeightFromStore; 42 | 43 | /** 44 | * Stores the provided video resolution string into the store. 45 | * 46 | * If the provided resolution is no part of the available video resolutions 47 | * the store operation will not be executed and NO will be returned. 48 | * @param resolution the string to be stored. 49 | * @return YES/NO depending on success. 50 | */ 51 | - (BOOL)storeVideoResolutionSetting:(NSString *)resolution; 52 | 53 | /** 54 | * Returns array of available video codecs. 55 | */ 56 | - (NSArray *)availableVideoCodecs; 57 | 58 | /** 59 | * Returns current video codec setting from store if present or default (H264) otherwise. 60 | */ 61 | - (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)currentVideoCodecSettingFromStore; 62 | 63 | /** 64 | * Stores the provided video codec setting into the store. 65 | * 66 | * If the provided video codec is not part of the available video codecs 67 | * the store operation will not be executed and NO will be returned. 68 | * @param video codec settings the string to be stored. 69 | * @return YES/NO depending on success. 70 | */ 71 | - (BOOL)storeVideoCodecSetting:(RTC_OBJC_TYPE(RTCVideoCodecInfo) *)videoCodec; 72 | 73 | /** 74 | * Returns current max bitrate setting from store if present. 75 | */ 76 | - (nullable NSNumber *)currentMaxBitrateSettingFromStore; 77 | 78 | /** 79 | * Stores the provided bitrate value into the store. 80 | * 81 | * @param bitrate NSNumber representation of the max bitrate value. 82 | */ 83 | - (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate; 84 | 85 | /** 86 | * Returns current audio only setting from store if present or default (NO) otherwise. 87 | */ 88 | - (BOOL)currentAudioOnlySettingFromStore; 89 | 90 | /** 91 | * Stores the provided audio only setting into the store. 92 | * 93 | * @param setting the boolean value to be stored. 94 | */ 95 | - (void)storeAudioOnlySetting:(BOOL)audioOnly; 96 | 97 | /** 98 | * Returns current create AecDump setting from store if present or default (NO) otherwise. 99 | */ 100 | - (BOOL)currentCreateAecDumpSettingFromStore; 101 | 102 | /** 103 | * Stores the provided create AecDump setting into the store. 104 | * 105 | * @param setting the boolean value to be stored. 106 | */ 107 | - (void)storeCreateAecDumpSetting:(BOOL)createAecDump; 108 | 109 | /** 110 | * Returns current setting whether to use manual audio config from store if present or default (YES) 111 | * otherwise. 112 | */ 113 | - (BOOL)currentUseManualAudioConfigSettingFromStore; 114 | 115 | /** 116 | * Stores the provided use manual audio config setting into the store. 117 | * 118 | * @param setting the boolean value to be stored. 119 | */ 120 | - (void)storeUseManualAudioConfigSetting:(BOOL)useManualAudioConfig; 121 | 122 | @end 123 | NS_ASSUME_NONNULL_END 124 | -------------------------------------------------------------------------------- /webrtc/ARDSettingsModel.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDSettingsModel+Private.h" 12 | #import "ARDSettingsStore.h" 13 | 14 | #import 15 | #import 16 | #import 17 | 18 | NS_ASSUME_NONNULL_BEGIN 19 | 20 | @interface ARDSettingsModel () { 21 | ARDSettingsStore *_settingsStore; 22 | } 23 | @end 24 | 25 | @implementation ARDSettingsModel 26 | 27 | - (NSArray *)availableVideoResolutions { 28 | NSMutableSet *> *resolutions = 29 | [[NSMutableSet *> alloc] init]; 30 | for (AVCaptureDevice *device in [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]) { 31 | for (AVCaptureDeviceFormat *format in 32 | [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]) { 33 | CMVideoDimensions resolution = 34 | CMVideoFormatDescriptionGetDimensions(format.formatDescription); 35 | NSArray *resolutionObject = @[ @(resolution.width), @(resolution.height) ]; 36 | [resolutions addObject:resolutionObject]; 37 | } 38 | } 39 | 40 | NSArray *> *sortedResolutions = 41 | [[resolutions allObjects] sortedArrayUsingComparator:^NSComparisonResult( 42 | NSArray *obj1, NSArray *obj2) { 43 | NSComparisonResult cmp = [obj1.firstObject compare:obj2.firstObject]; 44 | if (cmp != NSOrderedSame) { 45 | return cmp; 46 | } 47 | return [obj1.lastObject compare:obj2.lastObject]; 48 | }]; 49 | 50 | NSMutableArray *resolutionStrings = [[NSMutableArray alloc] init]; 51 | for (NSArray *resolution in sortedResolutions) { 52 | NSString *resolutionString = 53 | [NSString stringWithFormat:@"%@x%@", resolution.firstObject, resolution.lastObject]; 54 | [resolutionStrings addObject:resolutionString]; 55 | } 56 | 57 | return [resolutionStrings copy]; 58 | } 59 | 60 | - (NSString *)currentVideoResolutionSettingFromStore { 61 | [self registerStoreDefaults]; 62 | return [[self settingsStore] videoResolution]; 63 | } 64 | 65 | - (BOOL)storeVideoResolutionSetting:(NSString *)resolution { 66 | if (![[self availableVideoResolutions] containsObject:resolution]) { 67 | return NO; 68 | } 69 | [[self settingsStore] setVideoResolution:resolution]; 70 | return YES; 71 | } 72 | 73 | - (NSArray *)availableVideoCodecs { 74 | return [RTC_OBJC_TYPE(RTCDefaultVideoEncoderFactory) supportedCodecs]; 75 | } 76 | 77 | - (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)currentVideoCodecSettingFromStore { 78 | [self registerStoreDefaults]; 79 | NSData *codecData = [[self settingsStore] videoCodec]; 80 | return [NSKeyedUnarchiver unarchiveObjectWithData:codecData]; 81 | } 82 | 83 | - (BOOL)storeVideoCodecSetting:(RTC_OBJC_TYPE(RTCVideoCodecInfo) *)videoCodec { 84 | if (![[self availableVideoCodecs] containsObject:videoCodec]) { 85 | return NO; 86 | } 87 | NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:videoCodec]; 88 | [[self settingsStore] setVideoCodec:codecData]; 89 | return YES; 90 | } 91 | 92 | - (nullable NSNumber *)currentMaxBitrateSettingFromStore { 93 | [self registerStoreDefaults]; 94 | return [[self settingsStore] maxBitrate]; 95 | } 96 | 97 | - (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate { 98 | [[self settingsStore] setMaxBitrate:bitrate]; 99 | } 100 | 101 | - (BOOL)currentAudioOnlySettingFromStore { 102 | return [[self settingsStore] audioOnly]; 103 | } 104 | 105 | - (void)storeAudioOnlySetting:(BOOL)audioOnly { 106 | [[self settingsStore] setAudioOnly:audioOnly]; 107 | } 108 | 109 | - (BOOL)currentCreateAecDumpSettingFromStore { 110 | return [[self settingsStore] createAecDump]; 111 | } 112 | 113 | - (void)storeCreateAecDumpSetting:(BOOL)createAecDump { 114 | [[self settingsStore] setCreateAecDump:createAecDump]; 115 | } 116 | 117 | - (BOOL)currentUseManualAudioConfigSettingFromStore { 118 | return [[self settingsStore] useManualAudioConfig]; 119 | } 120 | 121 | - (void)storeUseManualAudioConfigSetting:(BOOL)useManualAudioConfig { 122 | [[self settingsStore] setUseManualAudioConfig:useManualAudioConfig]; 123 | } 124 | 125 | #pragma mark - Testable 126 | 127 | - (ARDSettingsStore *)settingsStore { 128 | if (!_settingsStore) { 129 | _settingsStore = [[ARDSettingsStore alloc] init]; 130 | [self registerStoreDefaults]; 131 | } 132 | return _settingsStore; 133 | } 134 | 135 | - (int)currentVideoResolutionWidthFromStore { 136 | NSString *resolution = [self currentVideoResolutionSettingFromStore]; 137 | 138 | return [self videoResolutionComponentAtIndex:0 inString:resolution]; 139 | } 140 | 141 | - (int)currentVideoResolutionHeightFromStore { 142 | NSString *resolution = [self currentVideoResolutionSettingFromStore]; 143 | return [self videoResolutionComponentAtIndex:1 inString:resolution]; 144 | } 145 | 146 | #pragma mark - 147 | 148 | - (NSString *)defaultVideoResolutionSetting { 149 | return [self availableVideoResolutions].firstObject; 150 | } 151 | 152 | - (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)defaultVideoCodecSetting { 153 | return [self availableVideoCodecs].firstObject; 154 | } 155 | 156 | - (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolution { 157 | if (index != 0 && index != 1) { 158 | return 0; 159 | } 160 | NSArray *components = [resolution componentsSeparatedByString:@"x"]; 161 | if (components.count != 2) { 162 | return 0; 163 | } 164 | return components[index].intValue; 165 | } 166 | 167 | - (void)registerStoreDefaults { 168 | NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:[self defaultVideoCodecSetting]]; 169 | [ARDSettingsStore setDefaultsForVideoResolution:[self defaultVideoResolutionSetting] 170 | videoCodec:codecData 171 | bitrate:nil 172 | audioOnly:NO 173 | createAecDump:NO 174 | useManualAudioConfig:YES]; 175 | } 176 | 177 | @end 178 | NS_ASSUME_NONNULL_END 179 | -------------------------------------------------------------------------------- /webrtc/ARDSettingsStore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /** 16 | * Light-weight persistent store for user settings. 17 | * 18 | * It will persist between application launches and application updates. 19 | */ 20 | @interface ARDSettingsStore : NSObject 21 | 22 | /** 23 | * Set fallback values in case the setting has not been written by the user. 24 | * @param dictionary of values to store 25 | */ 26 | + (void)setDefaultsForVideoResolution:(NSString *)videoResolution 27 | videoCodec:(NSData *)videoCodec 28 | bitrate:(nullable NSNumber *)bitrate 29 | audioOnly:(BOOL)audioOnly 30 | createAecDump:(BOOL)createAecDump 31 | useManualAudioConfig:(BOOL)useManualAudioConfig; 32 | 33 | @property(nonatomic) NSString *videoResolution; 34 | @property(nonatomic) NSData *videoCodec; 35 | 36 | /** 37 | * Returns current max bitrate number stored in the store. 38 | */ 39 | - (nullable NSNumber *)maxBitrate; 40 | 41 | /** 42 | * Stores the provided value as maximum bitrate setting. 43 | * @param value the number to be stored 44 | */ 45 | - (void)setMaxBitrate:(nullable NSNumber *)value; 46 | 47 | @property(nonatomic) BOOL audioOnly; 48 | @property(nonatomic) BOOL createAecDump; 49 | @property(nonatomic) BOOL useManualAudioConfig; 50 | 51 | @end 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /webrtc/ARDSettingsStore.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDSettingsStore.h" 12 | 13 | static NSString *const kVideoResolutionKey = @"rtc_video_resolution_key"; 14 | static NSString *const kVideoCodecKey = @"rtc_video_codec_info_key"; 15 | static NSString *const kBitrateKey = @"rtc_max_bitrate_key"; 16 | static NSString *const kAudioOnlyKey = @"rtc_audio_only_key"; 17 | static NSString *const kCreateAecDumpKey = @"rtc_create_aec_dump_key"; 18 | static NSString *const kUseManualAudioConfigKey = @"rtc_use_manual_audio_config_key"; 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | @interface ARDSettingsStore () { 22 | NSUserDefaults *_storage; 23 | } 24 | @property(nonatomic, strong, readonly) NSUserDefaults *storage; 25 | @end 26 | 27 | @implementation ARDSettingsStore 28 | 29 | + (void)setDefaultsForVideoResolution:(NSString *)videoResolution 30 | videoCodec:(NSData *)videoCodec 31 | bitrate:(nullable NSNumber *)bitrate 32 | audioOnly:(BOOL)audioOnly 33 | createAecDump:(BOOL)createAecDump 34 | useManualAudioConfig:(BOOL)useManualAudioConfig { 35 | NSMutableDictionary *defaultsDictionary = [@{ 36 | kAudioOnlyKey : @(audioOnly), 37 | kCreateAecDumpKey : @(createAecDump), 38 | kUseManualAudioConfigKey : @(useManualAudioConfig) 39 | } mutableCopy]; 40 | 41 | if (videoResolution) { 42 | defaultsDictionary[kVideoResolutionKey] = videoResolution; 43 | } 44 | if (videoCodec) { 45 | defaultsDictionary[kVideoCodecKey] = videoCodec; 46 | } 47 | if (bitrate) { 48 | defaultsDictionary[kBitrateKey] = bitrate; 49 | } 50 | [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary]; 51 | } 52 | 53 | - (NSUserDefaults *)storage { 54 | if (!_storage) { 55 | _storage = [NSUserDefaults standardUserDefaults]; 56 | } 57 | return _storage; 58 | } 59 | 60 | - (NSString *)videoResolution { 61 | return [self.storage objectForKey:kVideoResolutionKey]; 62 | } 63 | 64 | - (void)setVideoResolution:(NSString *)resolution { 65 | [self.storage setObject:resolution forKey:kVideoResolutionKey]; 66 | [self.storage synchronize]; 67 | } 68 | 69 | - (NSData *)videoCodec { 70 | return [self.storage objectForKey:kVideoCodecKey]; 71 | } 72 | 73 | - (void)setVideoCodec:(NSData *)videoCodec { 74 | [self.storage setObject:videoCodec forKey:kVideoCodecKey]; 75 | [self.storage synchronize]; 76 | } 77 | 78 | - (nullable NSNumber *)maxBitrate { 79 | return [self.storage objectForKey:kBitrateKey]; 80 | } 81 | 82 | - (void)setMaxBitrate:(nullable NSNumber *)value { 83 | [self.storage setObject:value forKey:kBitrateKey]; 84 | [self.storage synchronize]; 85 | } 86 | 87 | - (BOOL)audioOnly { 88 | return [self.storage boolForKey:kAudioOnlyKey]; 89 | } 90 | 91 | - (void)setAudioOnly:(BOOL)audioOnly { 92 | [self.storage setBool:audioOnly forKey:kAudioOnlyKey]; 93 | [self.storage synchronize]; 94 | } 95 | 96 | - (BOOL)createAecDump { 97 | return [self.storage boolForKey:kCreateAecDumpKey]; 98 | } 99 | 100 | - (void)setCreateAecDump:(BOOL)createAecDump { 101 | [self.storage setBool:createAecDump forKey:kCreateAecDumpKey]; 102 | [self.storage synchronize]; 103 | } 104 | 105 | - (BOOL)useManualAudioConfig { 106 | return [self.storage boolForKey:kUseManualAudioConfigKey]; 107 | } 108 | 109 | - (void)setUseManualAudioConfig:(BOOL)useManualAudioConfig { 110 | [self.storage setBool:useManualAudioConfig forKey:kUseManualAudioConfigKey]; 111 | [self.storage synchronize]; 112 | } 113 | 114 | @end 115 | NS_ASSUME_NONNULL_END 116 | -------------------------------------------------------------------------------- /webrtc/ARDSignalingChannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import "ARDSignalingMessage.h" 14 | 15 | typedef NS_ENUM(NSInteger, ARDSignalingChannelState) { 16 | // State when disconnected. 17 | kARDSignalingChannelStateClosed, 18 | // State when connection is established but not ready for use. 19 | kARDSignalingChannelStateOpen, 20 | // State when connection is established and registered. 21 | kARDSignalingChannelStateRegistered, 22 | // State when connection encounters a fatal error. 23 | kARDSignalingChannelStateError 24 | }; 25 | 26 | @protocol ARDSignalingChannel; 27 | @protocol ARDSignalingChannelDelegate 28 | 29 | - (void)channel:(id)channel didChangeState:(ARDSignalingChannelState)state; 30 | 31 | - (void)channel:(id)channel didReceiveMessage:(ARDSignalingMessage *)message; 32 | 33 | @end 34 | 35 | @protocol ARDSignalingChannel 36 | 37 | @property(nonatomic, readonly) NSString *roomId; 38 | @property(nonatomic, readonly) NSString *clientId; 39 | @property(nonatomic, readonly) ARDSignalingChannelState state; 40 | @property(nonatomic, weak) id delegate; 41 | 42 | // Registers the channel for the given room and client id. 43 | - (void)registerForRoomId:(NSString *)roomId clientId:(NSString *)clientId; 44 | 45 | // Sends signaling message over the channel. 46 | - (void)sendMessage:(ARDSignalingMessage *)message; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /webrtc/ARDSignalingMessage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | typedef enum { 17 | kARDSignalingMessageTypeCandidate, 18 | kARDSignalingMessageTypeCandidateRemoval, 19 | kARDSignalingMessageTypeOffer, 20 | kARDSignalingMessageTypeAnswer, 21 | kARDSignalingMessageTypeBye, 22 | } ARDSignalingMessageType; 23 | 24 | @interface ARDSignalingMessage : NSObject 25 | 26 | @property(nonatomic, readonly) ARDSignalingMessageType type; 27 | 28 | + (ARDSignalingMessage *)messageFromJSONString:(NSString *)jsonString; 29 | - (NSData *)JSONData; 30 | 31 | @end 32 | 33 | @interface ARDICECandidateMessage : ARDSignalingMessage 34 | 35 | @property(nonatomic, readonly) RTC_OBJC_TYPE(RTCIceCandidate) * candidate; 36 | 37 | - (instancetype)initWithCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)candidate; 38 | 39 | @end 40 | 41 | @interface ARDICECandidateRemovalMessage : ARDSignalingMessage 42 | 43 | @property(nonatomic, readonly) NSArray *candidates; 44 | 45 | - (instancetype)initWithRemovedCandidates:(NSArray *)candidates; 46 | 47 | @end 48 | 49 | @interface ARDSessionDescriptionMessage : ARDSignalingMessage 50 | 51 | @property(nonatomic, readonly) RTC_OBJC_TYPE(RTCSessionDescription) * sessionDescription; 52 | 53 | - (instancetype)initWithDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)description; 54 | 55 | @end 56 | 57 | @interface ARDByeMessage : ARDSignalingMessage 58 | @end 59 | -------------------------------------------------------------------------------- /webrtc/ARDSignalingMessage.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDSignalingMessage.h" 12 | 13 | #import 14 | 15 | #import "ARDUtilities.h" 16 | #import "RTCIceCandidate+JSON.h" 17 | #import "RTCSessionDescription+JSON.h" 18 | 19 | static NSString * const kARDSignalingMessageTypeKey = @"type"; 20 | static NSString * const kARDTypeValueRemoveCandidates = @"remove-candidates"; 21 | 22 | @implementation ARDSignalingMessage 23 | 24 | @synthesize type = _type; 25 | 26 | - (instancetype)initWithType:(ARDSignalingMessageType)type { 27 | if (self = [super init]) { 28 | _type = type; 29 | } 30 | return self; 31 | } 32 | 33 | - (NSString *)description { 34 | return [[NSString alloc] initWithData:[self JSONData] 35 | encoding:NSUTF8StringEncoding]; 36 | } 37 | 38 | + (ARDSignalingMessage *)messageFromJSONString:(NSString *)jsonString { 39 | NSDictionary *values = [NSDictionary dictionaryWithJSONString:jsonString]; 40 | if (!values) { 41 | RTCLogError(@"Error parsing signaling message JSON."); 42 | return nil; 43 | } 44 | 45 | NSString *typeString = values[kARDSignalingMessageTypeKey]; 46 | ARDSignalingMessage *message = nil; 47 | if ([typeString isEqualToString:@"candidate"]) { 48 | RTC_OBJC_TYPE(RTCIceCandidate) *candidate = 49 | [RTC_OBJC_TYPE(RTCIceCandidate) candidateFromJSONDictionary:values]; 50 | message = [[ARDICECandidateMessage alloc] initWithCandidate:candidate]; 51 | } else if ([typeString isEqualToString:kARDTypeValueRemoveCandidates]) { 52 | RTCLogInfo(@"Received remove-candidates message"); 53 | NSArray *candidates = 54 | [RTC_OBJC_TYPE(RTCIceCandidate) candidatesFromJSONDictionary:values]; 55 | message = [[ARDICECandidateRemovalMessage alloc] 56 | initWithRemovedCandidates:candidates]; 57 | } else if ([typeString isEqualToString:@"offer"] || 58 | [typeString isEqualToString:@"answer"]) { 59 | RTC_OBJC_TYPE(RTCSessionDescription) *description = 60 | [RTC_OBJC_TYPE(RTCSessionDescription) descriptionFromJSONDictionary:values]; 61 | message = 62 | [[ARDSessionDescriptionMessage alloc] initWithDescription:description]; 63 | } else if ([typeString isEqualToString:@"bye"]) { 64 | message = [[ARDByeMessage alloc] init]; 65 | } else { 66 | RTCLogError(@"Unexpected type: %@", typeString); 67 | } 68 | return message; 69 | } 70 | 71 | - (NSData *)JSONData { 72 | return nil; 73 | } 74 | 75 | @end 76 | 77 | @implementation ARDICECandidateMessage 78 | 79 | @synthesize candidate = _candidate; 80 | 81 | - (instancetype)initWithCandidate:(RTC_OBJC_TYPE(RTCIceCandidate) *)candidate { 82 | if (self = [super initWithType:kARDSignalingMessageTypeCandidate]) { 83 | _candidate = candidate; 84 | } 85 | return self; 86 | } 87 | 88 | - (NSData *)JSONData { 89 | return [_candidate JSONData]; 90 | } 91 | 92 | @end 93 | 94 | @implementation ARDICECandidateRemovalMessage 95 | 96 | @synthesize candidates = _candidates; 97 | 98 | - (instancetype)initWithRemovedCandidates:(NSArray *)candidates { 99 | NSParameterAssert(candidates.count); 100 | if (self = [super initWithType:kARDSignalingMessageTypeCandidateRemoval]) { 101 | _candidates = candidates; 102 | } 103 | return self; 104 | } 105 | 106 | - (NSData *)JSONData { 107 | return [RTC_OBJC_TYPE(RTCIceCandidate) JSONDataForIceCandidates:_candidates 108 | withType:kARDTypeValueRemoveCandidates]; 109 | } 110 | 111 | @end 112 | 113 | @implementation ARDSessionDescriptionMessage 114 | 115 | @synthesize sessionDescription = _sessionDescription; 116 | 117 | - (instancetype)initWithDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)description { 118 | ARDSignalingMessageType messageType = kARDSignalingMessageTypeOffer; 119 | RTCSdpType sdpType = description.type; 120 | switch (sdpType) { 121 | case RTCSdpTypeOffer: 122 | messageType = kARDSignalingMessageTypeOffer; 123 | break; 124 | case RTCSdpTypeAnswer: 125 | messageType = kARDSignalingMessageTypeAnswer; 126 | break; 127 | case RTCSdpTypePrAnswer: 128 | NSAssert( 129 | NO, @"Unexpected type: %@", [RTC_OBJC_TYPE(RTCSessionDescription) stringForType:sdpType]); 130 | break; 131 | } 132 | if (self = [super initWithType:messageType]) { 133 | _sessionDescription = description; 134 | } 135 | return self; 136 | } 137 | 138 | - (NSData *)JSONData { 139 | return [_sessionDescription JSONData]; 140 | } 141 | 142 | @end 143 | 144 | @implementation ARDByeMessage 145 | 146 | - (instancetype)init { 147 | return [super initWithType:kARDSignalingMessageTypeBye]; 148 | } 149 | 150 | - (NSData *)JSONData { 151 | NSDictionary *message = @{ 152 | @"type": @"bye" 153 | }; 154 | return [NSJSONSerialization dataWithJSONObject:message 155 | options:NSJSONWritingPrettyPrinted 156 | error:NULL]; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /webrtc/ARDStatsBuilder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | @class RTC_OBJC_TYPE(RTCLegacyStatsReport); 16 | 17 | /** Class used to accumulate stats information into a single displayable string. 18 | */ 19 | @interface ARDStatsBuilder : NSObject 20 | 21 | /** String that represents the accumulated stats reports passed into this 22 | * class. 23 | */ 24 | @property(nonatomic, readonly) NSString *statsString; 25 | 26 | /** Parses the information in the stats report into an appropriate internal 27 | * format used to generate the stats string. 28 | */ 29 | - (void)parseStatsReport:(RTC_OBJC_TYPE(RTCLegacyStatsReport) *)statsReport; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /webrtc/ARDTURNClient+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDTURNClient.h" 12 | 13 | @interface ARDTURNClient : NSObject 14 | 15 | - (instancetype)initWithURL:(NSURL *)url; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/ARDTURNClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | @class RTC_OBJC_TYPE(RTCIceServer); 16 | 17 | @protocol ARDTURNClient 18 | 19 | // Returns TURN server urls if successful. 20 | - (void)requestServersWithCompletionHandler:(void (^)(NSArray *turnServers, 21 | NSError *error))completionHandler; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /webrtc/ARDTURNClient.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDTURNClient+Internal.h" 12 | 13 | #import "ARDUtilities.h" 14 | #import "RTCIceServer+JSON.h" 15 | 16 | // TODO(tkchin): move this to a configuration object. 17 | static NSString *kTURNRefererURLString = @"https://appr.tc"; 18 | static NSString *kARDTURNClientErrorDomain = @"ARDTURNClient"; 19 | static NSInteger kARDTURNClientErrorBadResponse = -1; 20 | 21 | @implementation ARDTURNClient { 22 | NSURL *_url; 23 | } 24 | 25 | - (instancetype)initWithURL:(NSURL *)url { 26 | NSParameterAssert([url absoluteString].length); 27 | if (self = [super init]) { 28 | _url = url; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)requestServersWithCompletionHandler: 34 | (void (^)(NSArray *turnServers, NSError *error))completionHandler { 35 | 36 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; 37 | [NSURLConnection sendAsyncRequest:request 38 | completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 39 | if (error) { 40 | completionHandler(nil, error); 41 | return; 42 | } 43 | NSDictionary *responseDict = [NSDictionary dictionaryWithJSONData:data]; 44 | NSString *iceServerUrl = responseDict[@"ice_server_url"]; 45 | [self makeTurnServerRequestToURL:[NSURL URLWithString:iceServerUrl] 46 | WithCompletionHandler:completionHandler]; 47 | }]; 48 | } 49 | 50 | #pragma mark - Private 51 | 52 | - (void)makeTurnServerRequestToURL:(NSURL *)url 53 | WithCompletionHandler:(void (^)(NSArray *turnServers, 54 | NSError *error))completionHandler { 55 | NSMutableURLRequest *iceServerRequest = [NSMutableURLRequest requestWithURL:url]; 56 | iceServerRequest.HTTPMethod = @"POST"; 57 | [iceServerRequest addValue:kTURNRefererURLString forHTTPHeaderField:@"referer"]; 58 | [NSURLConnection sendAsyncRequest:iceServerRequest 59 | completionHandler:^(NSURLResponse *response, 60 | NSData *data, 61 | NSError *error) { 62 | if (error) { 63 | completionHandler(nil, error); 64 | return; 65 | } 66 | NSDictionary *turnResponseDict = [NSDictionary dictionaryWithJSONData:data]; 67 | NSMutableArray *turnServers = [NSMutableArray array]; 68 | [turnResponseDict[@"iceServers"] 69 | enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) { 70 | [turnServers addObject:[RTC_OBJC_TYPE(RTCIceServer) serverFromJSONDictionary:obj]]; 71 | }]; 72 | if (!turnServers) { 73 | NSError *responseError = 74 | [[NSError alloc] initWithDomain:kARDTURNClientErrorDomain 75 | code:kARDTURNClientErrorBadResponse 76 | userInfo:@{ 77 | NSLocalizedDescriptionKey: @"Bad TURN response.", 78 | }]; 79 | completionHandler(nil, responseError); 80 | return; 81 | } 82 | completionHandler(turnServers, nil); 83 | }]; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /webrtc/ARDWebSocketChannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import "ARDSignalingChannel.h" 14 | 15 | // Wraps a WebSocket connection to the AppRTC WebSocket server. 16 | @interface ARDWebSocketChannel : NSObject 17 | 18 | - (instancetype)initWithURL:(NSURL *)url 19 | restURL:(NSURL *)restURL 20 | delegate:(id)delegate; 21 | 22 | // Registers with the WebSocket server for the given room and client id once 23 | // the web socket connection is open. 24 | - (void)registerForRoomId:(NSString *)roomId clientId:(NSString *)clientId; 25 | 26 | // Sends message over the WebSocket connection if registered, otherwise POSTs to 27 | // the web socket server instead. 28 | - (void)sendMessage:(ARDSignalingMessage *)message; 29 | 30 | @end 31 | 32 | // Loopback mode is used to cause the client to connect to itself for testing. 33 | // A second web socket connection is established simulating the other client. 34 | // Any messages received are sent back to the WebSocket server after modifying 35 | // them as appropriate. 36 | @interface ARDLoopbackWebSocketChannel : ARDWebSocketChannel 37 | 38 | - (instancetype)initWithURL:(NSURL *)url restURL:(NSURL *)restURL; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /webrtc/ARDWebSocketChannel.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDWebSocketChannel.h" 12 | 13 | #import 14 | 15 | #import "SRWebSocket.h" 16 | 17 | #import "ARDSignalingMessage.h" 18 | #import "ARDUtilities.h" 19 | 20 | // TODO(tkchin): move these to a configuration object. 21 | static NSString const *kARDWSSMessageErrorKey = @"error"; 22 | static NSString const *kARDWSSMessagePayloadKey = @"msg"; 23 | 24 | @interface ARDWebSocketChannel () 25 | @end 26 | 27 | @implementation ARDWebSocketChannel { 28 | NSURL *_url; 29 | NSURL *_restURL; 30 | SRWebSocket *_socket; 31 | } 32 | 33 | @synthesize delegate = _delegate; 34 | @synthesize state = _state; 35 | @synthesize roomId = _roomId; 36 | @synthesize clientId = _clientId; 37 | 38 | - (instancetype)initWithURL:(NSURL *)url 39 | restURL:(NSURL *)restURL 40 | delegate:(id)delegate { 41 | if (self = [super init]) { 42 | _url = url; 43 | _restURL = restURL; 44 | _delegate = delegate; 45 | _socket = [[SRWebSocket alloc] initWithURL:url]; 46 | _socket.delegate = self; 47 | RTCLog(@"Opening WebSocket."); 48 | [_socket open]; 49 | } 50 | return self; 51 | } 52 | 53 | - (void)dealloc { 54 | [self disconnect]; 55 | } 56 | 57 | - (void)setState:(ARDSignalingChannelState)state { 58 | if (_state == state) { 59 | return; 60 | } 61 | _state = state; 62 | [_delegate channel:self didChangeState:_state]; 63 | } 64 | 65 | - (void)registerForRoomId:(NSString *)roomId 66 | clientId:(NSString *)clientId { 67 | NSParameterAssert(roomId.length); 68 | NSParameterAssert(clientId.length); 69 | _roomId = roomId; 70 | _clientId = clientId; 71 | if (_state == kARDSignalingChannelStateOpen) { 72 | [self registerWithCollider]; 73 | } 74 | } 75 | 76 | - (void)sendMessage:(ARDSignalingMessage *)message { 77 | NSParameterAssert(_clientId.length); 78 | NSParameterAssert(_roomId.length); 79 | NSData *data = [message JSONData]; 80 | if (_state == kARDSignalingChannelStateRegistered) { 81 | NSString *payload = 82 | [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 83 | NSDictionary *message = @{ 84 | @"cmd": @"send", 85 | @"msg": payload, 86 | }; 87 | NSData *messageJSONObject = 88 | [NSJSONSerialization dataWithJSONObject:message 89 | options:NSJSONWritingPrettyPrinted 90 | error:nil]; 91 | NSString *messageString = 92 | [[NSString alloc] initWithData:messageJSONObject 93 | encoding:NSUTF8StringEncoding]; 94 | RTCLog(@"C->WSS: %@", messageString); 95 | [_socket send:messageString]; 96 | } else { 97 | NSString *dataString = 98 | [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 99 | RTCLog(@"C->WSS POST: %@", dataString); 100 | NSString *urlString = 101 | [NSString stringWithFormat:@"%@/%@/%@", 102 | [_restURL absoluteString], _roomId, _clientId]; 103 | NSURL *url = [NSURL URLWithString:urlString]; 104 | [NSURLConnection sendAsyncPostToURL:url 105 | withData:data 106 | completionHandler:nil]; 107 | } 108 | } 109 | 110 | - (void)disconnect { 111 | if (_state == kARDSignalingChannelStateClosed || 112 | _state == kARDSignalingChannelStateError) { 113 | return; 114 | } 115 | [_socket close]; 116 | RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId); 117 | NSString *urlString = 118 | [NSString stringWithFormat:@"%@/%@/%@", 119 | [_restURL absoluteString], _roomId, _clientId]; 120 | NSURL *url = [NSURL URLWithString:urlString]; 121 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 122 | request.HTTPMethod = @"DELETE"; 123 | request.HTTPBody = nil; 124 | [NSURLConnection sendAsyncRequest:request completionHandler:nil]; 125 | } 126 | 127 | #pragma mark - SRWebSocketDelegate 128 | 129 | - (void)webSocketDidOpen:(SRWebSocket *)webSocket { 130 | RTCLog(@"WebSocket connection opened."); 131 | self.state = kARDSignalingChannelStateOpen; 132 | if (_roomId.length && _clientId.length) { 133 | [self registerWithCollider]; 134 | } 135 | } 136 | 137 | - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message { 138 | NSString *messageString = message; 139 | NSData *messageData = [messageString dataUsingEncoding:NSUTF8StringEncoding]; 140 | id jsonObject = [NSJSONSerialization JSONObjectWithData:messageData 141 | options:0 142 | error:nil]; 143 | if (![jsonObject isKindOfClass:[NSDictionary class]]) { 144 | RTCLogError(@"Unexpected message: %@", jsonObject); 145 | return; 146 | } 147 | NSDictionary *wssMessage = jsonObject; 148 | NSString *errorString = wssMessage[kARDWSSMessageErrorKey]; 149 | if (errorString.length) { 150 | RTCLogError(@"WSS error: %@", errorString); 151 | return; 152 | } 153 | NSString *payload = wssMessage[kARDWSSMessagePayloadKey]; 154 | ARDSignalingMessage *signalingMessage = 155 | [ARDSignalingMessage messageFromJSONString:payload]; 156 | RTCLog(@"WSS->C: %@", payload); 157 | [_delegate channel:self didReceiveMessage:signalingMessage]; 158 | } 159 | 160 | - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error { 161 | RTCLogError(@"WebSocket error: %@", error); 162 | self.state = kARDSignalingChannelStateError; 163 | } 164 | 165 | - (void)webSocket:(SRWebSocket *)webSocket 166 | didCloseWithCode:(NSInteger)code 167 | reason:(NSString *)reason 168 | wasClean:(BOOL)wasClean { 169 | RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d", 170 | (long)code, reason, wasClean); 171 | NSParameterAssert(_state != kARDSignalingChannelStateError); 172 | self.state = kARDSignalingChannelStateClosed; 173 | } 174 | 175 | #pragma mark - Private 176 | 177 | - (void)registerWithCollider { 178 | if (_state == kARDSignalingChannelStateRegistered) { 179 | return; 180 | } 181 | NSParameterAssert(_roomId.length); 182 | NSParameterAssert(_clientId.length); 183 | NSDictionary *registerMessage = @{ 184 | @"cmd": @"register", 185 | @"roomid" : _roomId, 186 | @"clientid" : _clientId, 187 | }; 188 | NSData *message = 189 | [NSJSONSerialization dataWithJSONObject:registerMessage 190 | options:NSJSONWritingPrettyPrinted 191 | error:nil]; 192 | NSString *messageString = 193 | [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding]; 194 | RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId); 195 | // Registration can fail if server rejects it. For example, if the room is 196 | // full. 197 | [_socket send:messageString]; 198 | self.state = kARDSignalingChannelStateRegistered; 199 | } 200 | 201 | @end 202 | 203 | @interface ARDLoopbackWebSocketChannel () 204 | @end 205 | 206 | @implementation ARDLoopbackWebSocketChannel 207 | 208 | - (instancetype)initWithURL:(NSURL *)url restURL:(NSURL *)restURL { 209 | return [super initWithURL:url restURL:restURL delegate:self]; 210 | } 211 | 212 | #pragma mark - ARDSignalingChannelDelegate 213 | 214 | - (void)channel:(id)channel 215 | didReceiveMessage:(ARDSignalingMessage *)message { 216 | switch (message.type) { 217 | case kARDSignalingMessageTypeOffer: { 218 | // Change message to answer, send back to server. 219 | ARDSessionDescriptionMessage *sdpMessage = 220 | (ARDSessionDescriptionMessage *)message; 221 | RTC_OBJC_TYPE(RTCSessionDescription) *description = sdpMessage.sessionDescription; 222 | NSString *dsc = description.sdp; 223 | dsc = [dsc stringByReplacingOccurrencesOfString:@"offer" 224 | withString:@"answer"]; 225 | RTC_OBJC_TYPE(RTCSessionDescription) *answerDescription = 226 | [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithType:RTCSdpTypeAnswer sdp:dsc]; 227 | ARDSignalingMessage *answer = 228 | [[ARDSessionDescriptionMessage alloc] 229 | initWithDescription:answerDescription]; 230 | [self sendMessage:answer]; 231 | break; 232 | } 233 | case kARDSignalingMessageTypeAnswer: 234 | // Should not receive answer in loopback scenario. 235 | break; 236 | case kARDSignalingMessageTypeCandidate: 237 | case kARDSignalingMessageTypeCandidateRemoval: 238 | // Send back to server. 239 | [self sendMessage:message]; 240 | break; 241 | case kARDSignalingMessageTypeBye: 242 | // Nothing to do. 243 | return; 244 | } 245 | } 246 | 247 | - (void)channel:(id)channel 248 | didChangeState:(ARDSignalingChannelState)state { 249 | } 250 | 251 | @end 252 | 253 | -------------------------------------------------------------------------------- /webrtc/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /webrtc/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/Icon.png -------------------------------------------------------------------------------- /webrtc/RTCIceCandidate+JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface RTC_OBJC_TYPE (RTCIceCandidate) 14 | (JSON) 15 | 16 | + (RTC_OBJC_TYPE(RTCIceCandidate) *)candidateFromJSONDictionary : (NSDictionary *)dictionary; 17 | + (NSArray *)candidatesFromJSONDictionary: 18 | (NSDictionary *)dictionary; 19 | + (NSData *)JSONDataForIceCandidates:(NSArray *)candidates 20 | withType:(NSString *)typeValue; 21 | - (NSData *)JSONData; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /webrtc/RTCIceCandidate+JSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "RTCIceCandidate+JSON.h" 12 | 13 | #import 14 | 15 | static NSString const *kRTCICECandidateTypeKey = @"type"; 16 | static NSString const *kRTCICECandidateTypeValue = @"candidate"; 17 | static NSString const *kRTCICECandidateMidKey = @"id"; 18 | static NSString const *kRTCICECandidateMLineIndexKey = @"label"; 19 | static NSString const *kRTCICECandidateSdpKey = @"candidate"; 20 | static NSString const *kRTCICECandidatesTypeKey = @"candidates"; 21 | 22 | @implementation RTC_OBJC_TYPE (RTCIceCandidate) 23 | (JSON) 24 | 25 | + (RTC_OBJC_TYPE(RTCIceCandidate) *)candidateFromJSONDictionary : (NSDictionary *)dictionary { 26 | NSString *mid = dictionary[kRTCICECandidateMidKey]; 27 | NSString *sdp = dictionary[kRTCICECandidateSdpKey]; 28 | NSNumber *num = dictionary[kRTCICECandidateMLineIndexKey]; 29 | NSInteger mLineIndex = [num integerValue]; 30 | return [[RTC_OBJC_TYPE(RTCIceCandidate) alloc] initWithSdp:sdp 31 | sdpMLineIndex:mLineIndex 32 | sdpMid:mid]; 33 | } 34 | 35 | + (NSData *)JSONDataForIceCandidates:(NSArray *)candidates 36 | withType:(NSString *)typeValue { 37 | NSMutableArray *jsonCandidates = 38 | [NSMutableArray arrayWithCapacity:candidates.count]; 39 | for (RTC_OBJC_TYPE(RTCIceCandidate) * candidate in candidates) { 40 | NSDictionary *jsonCandidate = [candidate JSONDictionary]; 41 | [jsonCandidates addObject:jsonCandidate]; 42 | } 43 | NSDictionary *json = @{ 44 | kRTCICECandidateTypeKey : typeValue, 45 | kRTCICECandidatesTypeKey : jsonCandidates 46 | }; 47 | NSError *error = nil; 48 | NSData *data = 49 | [NSJSONSerialization dataWithJSONObject:json 50 | options:NSJSONWritingPrettyPrinted 51 | error:&error]; 52 | if (error) { 53 | RTCLogError(@"Error serializing JSON: %@", error); 54 | return nil; 55 | } 56 | return data; 57 | } 58 | 59 | + (NSArray *)candidatesFromJSONDictionary: 60 | (NSDictionary *)dictionary { 61 | NSArray *jsonCandidates = dictionary[kRTCICECandidatesTypeKey]; 62 | NSMutableArray *candidates = 63 | [NSMutableArray arrayWithCapacity:jsonCandidates.count]; 64 | for (NSDictionary *jsonCandidate in jsonCandidates) { 65 | RTC_OBJC_TYPE(RTCIceCandidate) *candidate = 66 | [RTC_OBJC_TYPE(RTCIceCandidate) candidateFromJSONDictionary:jsonCandidate]; 67 | [candidates addObject:candidate]; 68 | } 69 | return candidates; 70 | } 71 | 72 | - (NSData *)JSONData { 73 | NSDictionary *json = @{ 74 | kRTCICECandidateTypeKey : kRTCICECandidateTypeValue, 75 | kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex), 76 | kRTCICECandidateMidKey : self.sdpMid, 77 | kRTCICECandidateSdpKey : self.sdp 78 | }; 79 | NSError *error = nil; 80 | NSData *data = 81 | [NSJSONSerialization dataWithJSONObject:json 82 | options:NSJSONWritingPrettyPrinted 83 | error:&error]; 84 | if (error) { 85 | RTCLogError(@"Error serializing JSON: %@", error); 86 | return nil; 87 | } 88 | return data; 89 | } 90 | 91 | - (NSDictionary *)JSONDictionary{ 92 | NSDictionary *json = @{ 93 | kRTCICECandidateMLineIndexKey : @(self.sdpMLineIndex), 94 | kRTCICECandidateMidKey : self.sdpMid, 95 | kRTCICECandidateSdpKey : self.sdp 96 | }; 97 | return json; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /webrtc/RTCIceServer+JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface RTC_OBJC_TYPE (RTCIceServer) 14 | (JSON) 15 | 16 | + (RTC_OBJC_TYPE(RTCIceServer) *)serverFromJSONDictionary : (NSDictionary *)dictionary; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /webrtc/RTCIceServer+JSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "RTCIceServer+JSON.h" 12 | 13 | @implementation RTC_OBJC_TYPE (RTCIceServer) 14 | (JSON) 15 | 16 | + (RTC_OBJC_TYPE(RTCIceServer) *)serverFromJSONDictionary : (NSDictionary *)dictionary { 17 | NSArray *turnUrls = dictionary[@"urls"]; 18 | NSString *username = dictionary[@"username"] ?: @""; 19 | NSString *credential = dictionary[@"credential"] ?: @""; 20 | return [[RTC_OBJC_TYPE(RTCIceServer) alloc] initWithURLStrings:turnUrls 21 | username:username 22 | credential:credential]; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /webrtc/RTCMediaConstraints+JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface RTCMediaConstraints (JSON) 14 | 15 | + (RTCMediaConstraints *)constraintsFromJSONDictionary:(NSDictionary *)dictionary; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/RTCMediaConstraints+JSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "RTCMediaConstraints+JSON.h" 12 | 13 | static NSString const *kRTCMediaConstraintsMandatoryKey = @"mandatory"; 14 | 15 | @implementation RTCMediaConstraints (JSON) 16 | 17 | + (RTCMediaConstraints *)constraintsFromJSONDictionary: 18 | (NSDictionary *)dictionary { 19 | NSDictionary *mandatory = dictionary[kRTCMediaConstraintsMandatoryKey]; 20 | NSMutableDictionary *mandatoryContraints = 21 | [NSMutableDictionary dictionaryWithCapacity:[mandatory count]]; 22 | [mandatory enumerateKeysAndObjectsUsingBlock:^( 23 | id key, id obj, BOOL *stop) { 24 | mandatoryContraints[key] = obj; 25 | }]; 26 | // TODO(tkchin): figure out json formats for optional constraints. 27 | RTCMediaConstraints *constraints = 28 | [[RTCMediaConstraints alloc] 29 | initWithMandatoryConstraints:mandatoryContraints 30 | optionalConstraints:nil]; 31 | return constraints; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /webrtc/RTCSessionDescription+JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface RTC_OBJC_TYPE (RTCSessionDescription) 14 | (JSON) 15 | 16 | + (RTC_OBJC_TYPE(RTCSessionDescription) *)descriptionFromJSONDictionary 17 | : (NSDictionary *)dictionary; 18 | - (NSData *)JSONData; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /webrtc/RTCSessionDescription+JSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "RTCSessionDescription+JSON.h" 12 | 13 | static NSString const *kRTCSessionDescriptionTypeKey = @"type"; 14 | static NSString const *kRTCSessionDescriptionSdpKey = @"sdp"; 15 | 16 | @implementation RTC_OBJC_TYPE (RTCSessionDescription) 17 | (JSON) 18 | 19 | + (RTC_OBJC_TYPE(RTCSessionDescription) *)descriptionFromJSONDictionary 20 | : (NSDictionary *)dictionary { 21 | NSString *typeString = dictionary[kRTCSessionDescriptionTypeKey]; 22 | RTCSdpType type = [[self class] typeForString:typeString]; 23 | NSString *sdp = dictionary[kRTCSessionDescriptionSdpKey]; 24 | return [[RTC_OBJC_TYPE(RTCSessionDescription) alloc] initWithType:type sdp:sdp]; 25 | } 26 | 27 | - (NSData *)JSONData { 28 | NSString *type = [[self class] stringForType:self.type]; 29 | NSDictionary *json = @{ 30 | kRTCSessionDescriptionTypeKey : type, 31 | kRTCSessionDescriptionSdpKey : self.sdp 32 | }; 33 | return [NSJSONSerialization dataWithJSONObject:json options:0 error:nil]; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /webrtc/common/ARDUtilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface NSDictionary (ARDUtilites) 14 | 15 | // Creates a dictionary with the keys and values in the JSON object. 16 | + (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString; 17 | + (NSDictionary *)dictionaryWithJSONData:(NSData *)jsonData; 18 | 19 | @end 20 | 21 | @interface NSURLConnection (ARDUtilities) 22 | 23 | // Issues an asynchronous request that calls back on main queue. 24 | + (void)sendAsyncRequest:(NSURLRequest *)request 25 | completionHandler: 26 | (void (^)(NSURLResponse *response, NSData *data, NSError *error))completionHandler; 27 | 28 | // Posts data to the specified URL. 29 | + (void)sendAsyncPostToURL:(NSURL *)url 30 | withData:(NSData *)data 31 | completionHandler:(void (^)(BOOL succeeded, NSData *data))completionHandler; 32 | 33 | @end 34 | 35 | NSInteger ARDGetCpuUsagePercentage(void); 36 | -------------------------------------------------------------------------------- /webrtc/common/ARDUtilities.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDUtilities.h" 12 | 13 | #import 14 | 15 | #import 16 | 17 | @implementation NSDictionary (ARDUtilites) 18 | 19 | + (NSDictionary *)dictionaryWithJSONString:(NSString *)jsonString { 20 | NSParameterAssert(jsonString.length > 0); 21 | NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; 22 | NSError *error = nil; 23 | NSDictionary *dict = 24 | [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; 25 | if (error) { 26 | RTCLogError(@"Error parsing JSON: %@", error.localizedDescription); 27 | } 28 | return dict; 29 | } 30 | 31 | + (NSDictionary *)dictionaryWithJSONData:(NSData *)jsonData { 32 | NSError *error = nil; 33 | NSDictionary *dict = 34 | [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; 35 | if (error) { 36 | RTCLogError(@"Error parsing JSON: %@", error.localizedDescription); 37 | } 38 | return dict; 39 | } 40 | 41 | @end 42 | 43 | @implementation NSURLConnection (ARDUtilities) 44 | 45 | + (void)sendAsyncRequest:(NSURLRequest *)request 46 | completionHandler:(void (^)(NSURLResponse *response, 47 | NSData *data, 48 | NSError *error))completionHandler { 49 | // Kick off an async request which will call back on main thread. 50 | NSURLSession *session = [NSURLSession sharedSession]; 51 | [[session dataTaskWithRequest:request 52 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 53 | if (completionHandler) { 54 | completionHandler(response, data, error); 55 | } 56 | }] resume]; 57 | } 58 | 59 | // Posts data to the specified URL. 60 | + (void)sendAsyncPostToURL:(NSURL *)url 61 | withData:(NSData *)data 62 | completionHandler:(void (^)(BOOL succeeded, 63 | NSData *data))completionHandler { 64 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 65 | request.HTTPMethod = @"POST"; 66 | request.HTTPBody = data; 67 | [[self class] sendAsyncRequest:request 68 | completionHandler:^(NSURLResponse *response, 69 | NSData *data, 70 | NSError *error) { 71 | if (error) { 72 | RTCLogError(@"Error posting data: %@", error.localizedDescription); 73 | if (completionHandler) { 74 | completionHandler(NO, data); 75 | } 76 | return; 77 | } 78 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 79 | if (httpResponse.statusCode != 200) { 80 | NSString *serverResponse = data.length > 0 ? 81 | [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] : 82 | nil; 83 | RTCLogError(@"Received bad response: %@", serverResponse); 84 | if (completionHandler) { 85 | completionHandler(NO, data); 86 | } 87 | return; 88 | } 89 | if (completionHandler) { 90 | completionHandler(YES, data); 91 | } 92 | }]; 93 | } 94 | 95 | @end 96 | 97 | NSInteger ARDGetCpuUsagePercentage() { 98 | // Create an array of thread ports for the current task. 99 | const task_t task = mach_task_self(); 100 | thread_act_array_t thread_array; 101 | mach_msg_type_number_t thread_count; 102 | if (task_threads(task, &thread_array, &thread_count) != KERN_SUCCESS) { 103 | return -1; 104 | } 105 | 106 | // Sum cpu usage from all threads. 107 | float cpu_usage_percentage = 0; 108 | thread_basic_info_data_t thread_info_data = {}; 109 | mach_msg_type_number_t thread_info_count; 110 | for (size_t i = 0; i < thread_count; ++i) { 111 | thread_info_count = THREAD_BASIC_INFO_COUNT; 112 | kern_return_t ret = thread_info(thread_array[i], 113 | THREAD_BASIC_INFO, 114 | (thread_info_t)&thread_info_data, 115 | &thread_info_count); 116 | if (ret == KERN_SUCCESS) { 117 | cpu_usage_percentage += 118 | 100.f * (float)thread_info_data.cpu_usage / TH_USAGE_SCALE; 119 | } 120 | } 121 | 122 | // Dealloc the created array. 123 | vm_deallocate(task, (vm_address_t)thread_array, 124 | sizeof(thread_act_t) * thread_count); 125 | return lroundf(cpu_usage_percentage); 126 | } 127 | -------------------------------------------------------------------------------- /webrtc/internal/RTCAudioSession+Private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" 12 | 13 | #include 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @class RTCAudioSessionConfiguration; 18 | 19 | @interface RTCAudioSession () 20 | 21 | /** Number of times setActive:YES has succeeded without a balanced call to 22 | * setActive:NO. 23 | */ 24 | @property(nonatomic, readonly) int activationCount; 25 | 26 | /** The number of times |beginWebRTCSession| was called without a balanced call 27 | * to |endWebRTCSession|. 28 | */ 29 | @property(nonatomic, readonly) int webRTCSessionCount; 30 | 31 | /** Convenience BOOL that checks useManualAudio and isAudioEnebled. */ 32 | @property(readonly) BOOL canPlayOrRecord; 33 | 34 | /** Tracks whether we have been sent an interruption event that hasn't been matched by either an 35 | * interrupted end event or a foreground event. 36 | */ 37 | @property(nonatomic, assign) BOOL isInterrupted; 38 | 39 | - (BOOL)checkLock:(NSError **)outError; 40 | 41 | /** Adds the delegate to the list of delegates, and places it at the front of 42 | * the list. This delegate will be notified before other delegates of 43 | * audio events. 44 | */ 45 | - (void)pushDelegate:(id)delegate; 46 | 47 | /** Signals RTCAudioSession that a WebRTC session is about to begin and 48 | * audio configuration is needed. Will configure the audio session for WebRTC 49 | * if not already configured and if configuration is not delayed. 50 | * Successful calls must be balanced by a call to endWebRTCSession. 51 | */ 52 | - (BOOL)beginWebRTCSession:(NSError **)outError; 53 | 54 | /** Signals RTCAudioSession that a WebRTC session is about to end and audio 55 | * unconfiguration is needed. Will unconfigure the audio session for WebRTC 56 | * if this is the last unmatched call and if configuration is not delayed. 57 | */ 58 | - (BOOL)endWebRTCSession:(NSError **)outError; 59 | 60 | /** Configure the audio session for WebRTC. This call will fail if the session 61 | * is already configured. On other failures, we will attempt to restore the 62 | * previously used audio session configuration. 63 | * |lockForConfiguration| must be called first. 64 | * Successful calls to configureWebRTCSession must be matched by calls to 65 | * |unconfigureWebRTCSession|. 66 | */ 67 | - (BOOL)configureWebRTCSession:(NSError **)outError; 68 | 69 | /** Unconfigures the session for WebRTC. This will attempt to restore the 70 | * audio session to the settings used before |configureWebRTCSession| was 71 | * called. 72 | * |lockForConfiguration| must be called first. 73 | */ 74 | - (BOOL)unconfigureWebRTCSession:(NSError **)outError; 75 | 76 | /** Returns a configuration error with the given description. */ 77 | - (NSError *)configurationErrorWithDescription:(NSString *)description; 78 | 79 | // Properties and methods for tests. 80 | @property(nonatomic, readonly) 81 | std::vector<__weak id > delegates; 82 | 83 | - (void)notifyDidBeginInterruption; 84 | - (void)notifyDidEndInterruptionWithShouldResumeSession: 85 | (BOOL)shouldResumeSession; 86 | - (void)notifyDidChangeRouteWithReason:(AVAudioSessionRouteChangeReason)reason 87 | previousRoute:(AVAudioSessionRouteDescription *)previousRoute; 88 | - (void)notifyMediaServicesWereLost; 89 | - (void)notifyMediaServicesWereReset; 90 | - (void)notifyDidChangeCanPlayOrRecord:(BOOL)canPlayOrRecord; 91 | - (void)notifyDidStartPlayOrRecord; 92 | - (void)notifyDidStopPlayOrRecord; 93 | 94 | @end 95 | 96 | NS_ASSUME_NONNULL_END 97 | -------------------------------------------------------------------------------- /webrtc/internal/RTCAudioSession.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | #import "WebRTC/RTCMacros.h" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | extern NSString * const kRTCAudioSessionErrorDomain; 19 | /** Method that requires lock was called without lock. */ 20 | extern NSInteger const kRTCAudioSessionErrorLockRequired; 21 | /** Unknown configuration error occurred. */ 22 | extern NSInteger const kRTCAudioSessionErrorConfiguration; 23 | 24 | @class RTCAudioSession; 25 | @class RTCAudioSessionConfiguration; 26 | 27 | // Surfaces AVAudioSession events. WebRTC will listen directly for notifications 28 | // from AVAudioSession and handle them before calling these delegate methods, 29 | // at which point applications can perform additional processing if required. 30 | RTC_EXPORT 31 | @protocol RTCAudioSessionDelegate 32 | 33 | @optional 34 | /** Called on a system notification thread when AVAudioSession starts an 35 | * interruption event. 36 | */ 37 | - (void)audioSessionDidBeginInterruption:(RTCAudioSession *)session; 38 | 39 | /** Called on a system notification thread when AVAudioSession ends an 40 | * interruption event. 41 | */ 42 | - (void)audioSessionDidEndInterruption:(RTCAudioSession *)session 43 | shouldResumeSession:(BOOL)shouldResumeSession; 44 | 45 | /** Called on a system notification thread when AVAudioSession changes the 46 | * route. 47 | */ 48 | - (void)audioSessionDidChangeRoute:(RTCAudioSession *)session 49 | reason:(AVAudioSessionRouteChangeReason)reason 50 | previousRoute:(AVAudioSessionRouteDescription *)previousRoute; 51 | 52 | /** Called on a system notification thread when AVAudioSession media server 53 | * terminates. 54 | */ 55 | - (void)audioSessionMediaServicesWereLost:(RTCAudioSession *)session; 56 | 57 | /** Called on a system notification thread when AVAudioSession media server 58 | * restarts. 59 | */ 60 | - (void)audioSessionMediaServicesWereReset:(RTCAudioSession *)session; 61 | 62 | // TODO(tkchin): Maybe handle SilenceSecondaryAudioHintNotification. 63 | 64 | - (void)audioSession:(RTCAudioSession *)session 65 | didChangeCanPlayOrRecord:(BOOL)canPlayOrRecord; 66 | 67 | /** Called on a WebRTC thread when the audio device is notified to begin 68 | * playback or recording. 69 | */ 70 | - (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session; 71 | 72 | /** Called on a WebRTC thread when the audio device is notified to stop 73 | * playback or recording. 74 | */ 75 | - (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session; 76 | 77 | @end 78 | 79 | /** Proxy class for AVAudioSession that adds a locking mechanism similar to 80 | * AVCaptureDevice. This is used to that interleaving configurations between 81 | * WebRTC and the application layer are avoided. 82 | * 83 | * RTCAudioSession also coordinates activation so that the audio session is 84 | * activated only once. See |setActive:error:|. 85 | */ 86 | RTC_EXPORT 87 | @interface RTCAudioSession : NSObject 88 | 89 | /** Convenience property to access the AVAudioSession singleton. Callers should 90 | * not call setters on AVAudioSession directly, but other method invocations 91 | * are fine. 92 | */ 93 | @property(nonatomic, readonly) AVAudioSession *session; 94 | 95 | /** Our best guess at whether the session is active based on results of calls to 96 | * AVAudioSession. 97 | */ 98 | @property(nonatomic, readonly) BOOL isActive; 99 | /** Whether RTCAudioSession is currently locked for configuration. */ 100 | @property(nonatomic, readonly) BOOL isLocked; 101 | 102 | /** If YES, WebRTC will not initialize the audio unit automatically when an 103 | * audio track is ready for playout or recording. Instead, applications should 104 | * call setIsAudioEnabled. If NO, WebRTC will initialize the audio unit 105 | * as soon as an audio track is ready for playout or recording. 106 | */ 107 | @property(nonatomic, assign) BOOL useManualAudio; 108 | 109 | /** This property is only effective if useManualAudio is YES. 110 | * Represents permission for WebRTC to initialize the VoIP audio unit. 111 | * When set to NO, if the VoIP audio unit used by WebRTC is active, it will be 112 | * stopped and uninitialized. This will stop incoming and outgoing audio. 113 | * When set to YES, WebRTC will initialize and start the audio unit when it is 114 | * needed (e.g. due to establishing an audio connection). 115 | * This property was introduced to work around an issue where if an AVPlayer is 116 | * playing audio while the VoIP audio unit is initialized, its audio would be 117 | * either cut off completely or played at a reduced volume. By preventing 118 | * the audio unit from being initialized until after the audio has completed, 119 | * we are able to prevent the abrupt cutoff. 120 | */ 121 | @property(nonatomic, assign) BOOL isAudioEnabled; 122 | 123 | // Proxy properties. 124 | @property(readonly) NSString *category; 125 | @property(readonly) AVAudioSessionCategoryOptions categoryOptions; 126 | @property(readonly) NSString *mode; 127 | @property(readonly) BOOL secondaryAudioShouldBeSilencedHint; 128 | @property(readonly) AVAudioSessionRouteDescription *currentRoute; 129 | @property(readonly) NSInteger maximumInputNumberOfChannels; 130 | @property(readonly) NSInteger maximumOutputNumberOfChannels; 131 | @property(readonly) float inputGain; 132 | @property(readonly) BOOL inputGainSettable; 133 | @property(readonly) BOOL inputAvailable; 134 | @property(readonly, nullable) 135 | NSArray * inputDataSources; 136 | @property(readonly, nullable) 137 | AVAudioSessionDataSourceDescription *inputDataSource; 138 | @property(readonly, nullable) 139 | NSArray * outputDataSources; 140 | @property(readonly, nullable) 141 | AVAudioSessionDataSourceDescription *outputDataSource; 142 | @property(readonly) double sampleRate; 143 | @property(readonly) double preferredSampleRate; 144 | @property(readonly) NSInteger inputNumberOfChannels; 145 | @property(readonly) NSInteger outputNumberOfChannels; 146 | @property(readonly) float outputVolume; 147 | @property(readonly) NSTimeInterval inputLatency; 148 | @property(readonly) NSTimeInterval outputLatency; 149 | @property(readonly) NSTimeInterval IOBufferDuration; 150 | @property(readonly) NSTimeInterval preferredIOBufferDuration; 151 | 152 | /** Default constructor. */ 153 | + (instancetype)sharedInstance; 154 | - (instancetype)init NS_UNAVAILABLE; 155 | 156 | /** Adds a delegate, which is held weakly. */ 157 | - (void)addDelegate:(id)delegate; 158 | /** Removes an added delegate. */ 159 | - (void)removeDelegate:(id)delegate; 160 | 161 | /** Request exclusive access to the audio session for configuration. This call 162 | * will block if the lock is held by another object. 163 | */ 164 | - (void)lockForConfiguration; 165 | /** Relinquishes exclusive access to the audio session. */ 166 | - (void)unlockForConfiguration; 167 | 168 | /** If |active|, activates the audio session if it isn't already active. 169 | * Successful calls must be balanced with a setActive:NO when activation is no 170 | * longer required. If not |active|, deactivates the audio session if one is 171 | * active and this is the last balanced call. When deactivating, the 172 | * AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation option is passed to 173 | * AVAudioSession. 174 | */ 175 | - (BOOL)setActive:(BOOL)active 176 | error:(NSError **)outError; 177 | 178 | // The following methods are proxies for the associated methods on 179 | // AVAudioSession. |lockForConfiguration| must be called before using them 180 | // otherwise they will fail with kRTCAudioSessionErrorLockRequired. 181 | 182 | - (BOOL)setCategory:(NSString *)category 183 | withOptions:(AVAudioSessionCategoryOptions)options 184 | error:(NSError **)outError; 185 | - (BOOL)setMode:(NSString *)mode error:(NSError **)outError; 186 | - (BOOL)setInputGain:(float)gain error:(NSError **)outError; 187 | - (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError; 188 | - (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration 189 | error:(NSError **)outError; 190 | - (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count 191 | error:(NSError **)outError; 192 | - (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count 193 | error:(NSError **)outError; 194 | - (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride 195 | error:(NSError **)outError; 196 | - (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort 197 | error:(NSError **)outError; 198 | - (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 199 | error:(NSError **)outError; 200 | - (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 201 | error:(NSError **)outError; 202 | 203 | @end 204 | 205 | @interface RTCAudioSession (Configuration) 206 | 207 | /** Applies the configuration to the current session. Attempts to set all 208 | * properties even if previous ones fail. Only the last error will be 209 | * returned. 210 | * |lockForConfiguration| must be called first. 211 | */ 212 | - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration 213 | error:(NSError **)outError; 214 | 215 | /** Convenience method that calls both setConfiguration and setActive. 216 | * |lockForConfiguration| must be called first. 217 | */ 218 | - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration 219 | active:(BOOL)active 220 | error:(NSError **)outError; 221 | 222 | @end 223 | 224 | NS_ASSUME_NONNULL_END 225 | -------------------------------------------------------------------------------- /webrtc/internal/RTCAudioSessionConfiguration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | #import "WebRTC/RTCMacros.h" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | extern const int kRTCAudioSessionPreferredNumberOfChannels; 19 | extern const double kRTCAudioSessionHighPerformanceSampleRate; 20 | extern const double kRTCAudioSessionLowComplexitySampleRate; 21 | extern const double kRTCAudioSessionHighPerformanceIOBufferDuration; 22 | extern const double kRTCAudioSessionLowComplexityIOBufferDuration; 23 | 24 | // Struct to hold configuration values. 25 | RTC_EXPORT 26 | @interface RTCAudioSessionConfiguration : NSObject 27 | 28 | @property(nonatomic, strong) NSString *category; 29 | @property(nonatomic, assign) AVAudioSessionCategoryOptions categoryOptions; 30 | @property(nonatomic, strong) NSString *mode; 31 | @property(nonatomic, assign) double sampleRate; 32 | @property(nonatomic, assign) NSTimeInterval ioBufferDuration; 33 | @property(nonatomic, assign) NSInteger inputNumberOfChannels; 34 | @property(nonatomic, assign) NSInteger outputNumberOfChannels; 35 | 36 | /** Initializes configuration to defaults. */ 37 | - (instancetype)init NS_DESIGNATED_INITIALIZER; 38 | 39 | /** Returns the current configuration of the audio session. */ 40 | + (instancetype)currentConfiguration; 41 | /** Returns the configuration that WebRTC needs. */ 42 | + (instancetype)webRTCConfiguration; 43 | /** Provide a way to override the default configuration. */ 44 | + (void)setWebRTCConfiguration:(RTCAudioSessionConfiguration *)configuration; 45 | 46 | @end 47 | 48 | NS_ASSUME_NONNULL_END 49 | -------------------------------------------------------------------------------- /webrtc/internal/RTCAudioSessionDelegateAdapter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" 12 | 13 | namespace webrtc { 14 | class AudioSessionObserver; 15 | } 16 | 17 | /** Adapter that forwards RTCAudioSessionDelegate calls to the appropriate 18 | * methods on the AudioSessionObserver. 19 | */ 20 | @interface RTCAudioSessionDelegateAdapter : NSObject 21 | 22 | - (instancetype)init NS_UNAVAILABLE; 23 | 24 | /** |observer| is a raw pointer and should be kept alive 25 | * for this object's lifetime. 26 | */ 27 | - (instancetype)initWithObserver:(webrtc::AudioSessionObserver *)observer 28 | NS_DESIGNATED_INITIALIZER; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /webrtc/internal/RTCCertificate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @interface RTCCertificate : NSObject 18 | 19 | /** Private key in PEM. */ 20 | @property(nonatomic, readonly, copy) NSString *private_key; 21 | 22 | /** Public key in an x509 cert encoded in PEM. */ 23 | @property(nonatomic, readonly, copy) NSString *certificate; 24 | 25 | /** 26 | * Initialize an RTCCertificate with PEM strings for private_key and certificate. 27 | */ 28 | - (instancetype)initWithPrivateKey:(NSString *)private_key 29 | certificate:(NSString *)certificate NS_DESIGNATED_INITIALIZER; 30 | 31 | - (instancetype)init NS_UNAVAILABLE; 32 | 33 | /** Generate a new certificate for 're' use. 34 | * 35 | * Optional dictionary of parameters. Defaults to KeyType ECDSA if none are 36 | * provided. 37 | * - name: "ECDSA" or "RSASSA-PKCS1-v1_5" 38 | */ 39 | + (nullable RTCCertificate *)generateCertificateWithParams:(NSDictionary *)params; 40 | 41 | @end 42 | 43 | NS_ASSUME_NONNULL_END 44 | -------------------------------------------------------------------------------- /webrtc/internal/RTCH264ProfileLevelId.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | extern NSString *const kRTCVideoCodecH264Name; 16 | extern NSString *const kRTCLevel31ConstrainedHigh; 17 | extern NSString *const kRTCLevel31ConstrainedBaseline; 18 | extern NSString *const kRTCMaxSupportedH264ProfileLevelConstrainedHigh; 19 | extern NSString *const kRTCMaxSupportedH264ProfileLevelConstrainedBaseline; 20 | 21 | /** H264 Profiles and levels. */ 22 | typedef NS_ENUM(NSUInteger, RTCH264Profile) { 23 | RTCH264ProfileConstrainedBaseline, 24 | RTCH264ProfileBaseline, 25 | RTCH264ProfileMain, 26 | RTCH264ProfileConstrainedHigh, 27 | RTCH264ProfileHigh, 28 | }; 29 | 30 | typedef NS_ENUM(NSUInteger, RTCH264Level) { 31 | RTCH264Level1_b = 0, 32 | RTCH264Level1 = 10, 33 | RTCH264Level1_1 = 11, 34 | RTCH264Level1_2 = 12, 35 | RTCH264Level1_3 = 13, 36 | RTCH264Level2 = 20, 37 | RTCH264Level2_1 = 21, 38 | RTCH264Level2_2 = 22, 39 | RTCH264Level3 = 30, 40 | RTCH264Level3_1 = 31, 41 | RTCH264Level3_2 = 32, 42 | RTCH264Level4 = 40, 43 | RTCH264Level4_1 = 41, 44 | RTCH264Level4_2 = 42, 45 | RTCH264Level5 = 50, 46 | RTCH264Level5_1 = 51, 47 | RTCH264Level5_2 = 52 48 | }; 49 | 50 | 51 | @interface RTCH264ProfileLevelId : NSObject 52 | 53 | @property(nonatomic, readonly) RTCH264Profile profile; 54 | @property(nonatomic, readonly) RTCH264Level level; 55 | @property(nonatomic, readonly) NSString *hexString; 56 | 57 | - (instancetype)initWithHexString:(NSString *)hexString; 58 | - (instancetype)initWithProfile:(RTCH264Profile)profile level:(RTCH264Level)level; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /webrtc/ios/ARDAppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | // The main application class of the AppRTCMobile iOS app demonstrating 14 | // interoperability between the Objective C implementation of PeerConnection 15 | // and the appr.tc demo webapp. 16 | @interface ARDAppDelegate : NSObject 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/ios/ARDAppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDAppDelegate.h" 12 | 13 | #import 14 | #import 15 | #import 16 | #import 17 | 18 | #import "ARDMainViewController.h" 19 | 20 | @implementation ARDAppDelegate { 21 | UIWindow *_window; 22 | } 23 | 24 | #pragma mark - UIApplicationDelegate methods 25 | 26 | - (BOOL)application:(UIApplication *)application 27 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 28 | NSDictionary *fieldTrials = @{}; 29 | RTCInitFieldTrialDictionary(fieldTrials); 30 | RTCInitializeSSL(); 31 | RTCSetupInternalTracer(); 32 | _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 33 | [_window makeKeyAndVisible]; 34 | ARDMainViewController *viewController = [[ARDMainViewController alloc] init]; 35 | 36 | UINavigationController *root = 37 | [[UINavigationController alloc] initWithRootViewController:viewController]; 38 | root.navigationBar.translucent = NO; 39 | _window.rootViewController = root; 40 | 41 | #if defined(NDEBUG) 42 | // In debug builds the default level is LS_INFO and in non-debug builds it is 43 | // disabled. Continue to log to console in non-debug builds, but only 44 | // warnings and errors. 45 | RTCSetMinDebugLogLevel(RTCLoggingSeverityWarning); 46 | #endif 47 | 48 | return YES; 49 | } 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application { 52 | RTCShutdownInternalTracer(); 53 | RTCCleanupSSL(); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /webrtc/ios/ARDFileCaptureController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | @class RTC_OBJC_TYPE(RTCFileVideoCapturer); 16 | 17 | /** 18 | * Controls a file capturer. 19 | */ 20 | NS_CLASS_AVAILABLE_IOS(10) 21 | @interface ARDFileCaptureController : NSObject 22 | 23 | /** 24 | * Creates instance of the controller. 25 | * 26 | * @param capturer The capturer to be controlled. 27 | */ 28 | - (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCFileVideoCapturer) *)capturer; 29 | 30 | /** 31 | * Starts the file capturer. 32 | * 33 | * Possible errors produced by the capturer will be logged. 34 | */ 35 | - (void)startCapture; 36 | 37 | /** 38 | * Immediately stops capturer. 39 | */ 40 | - (void)stopCapture; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /webrtc/ios/ARDFileCaptureController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDFileCaptureController.h" 12 | 13 | #import 14 | 15 | @interface ARDFileCaptureController () 16 | 17 | @property(nonatomic, strong) RTC_OBJC_TYPE(RTCFileVideoCapturer) * fileCapturer; 18 | 19 | @end 20 | 21 | @implementation ARDFileCaptureController 22 | @synthesize fileCapturer = _fileCapturer; 23 | 24 | - (instancetype)initWithCapturer:(RTC_OBJC_TYPE(RTCFileVideoCapturer) *)capturer { 25 | if (self = [super init]) { 26 | _fileCapturer = capturer; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)startCapture { 32 | [self startFileCapture]; 33 | } 34 | 35 | - (void)startFileCapture { 36 | [self.fileCapturer startCapturingFromFileNamed:@"foreman.mp4" 37 | onError:^(NSError *_Nonnull error) { 38 | NSLog(@"Error %@", error.userInfo); 39 | }]; 40 | } 41 | 42 | - (void)stopCapture { 43 | [self.fileCapturer stopCapture]; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /webrtc/ios/ARDMainView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @class ARDMainView; 14 | 15 | @protocol ARDMainViewDelegate 16 | 17 | - (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback; 18 | - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView; 19 | 20 | @end 21 | 22 | // The main view of AppRTCMobile. It contains an input field for entering a room 23 | // name on apprtc to connect to. 24 | @interface ARDMainView : UIView 25 | 26 | @property(nonatomic, weak) id delegate; 27 | // Updates the audio loop button as needed. 28 | @property(nonatomic, assign) BOOL isAudioLoopPlaying; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /webrtc/ios/ARDMainView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDMainView.h" 12 | 13 | #import "UIImage+ARDUtilities.h" 14 | 15 | static CGFloat const kRoomTextFieldHeight = 40; 16 | static CGFloat const kRoomTextFieldMargin = 8; 17 | static CGFloat const kCallControlMargin = 8; 18 | 19 | // Helper view that contains a text field and a clear button. 20 | @interface ARDRoomTextField : UIView 21 | @property(nonatomic, readonly) NSString *roomText; 22 | @end 23 | 24 | @implementation ARDRoomTextField { 25 | UITextField *_roomText; 26 | } 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame { 29 | if (self = [super initWithFrame:frame]) { 30 | _roomText = [[UITextField alloc] initWithFrame:CGRectZero]; 31 | _roomText.borderStyle = UITextBorderStyleNone; 32 | _roomText.font = [UIFont systemFontOfSize:12]; 33 | _roomText.placeholder = @"Room name"; 34 | _roomText.autocorrectionType = UITextAutocorrectionTypeNo; 35 | _roomText.autocapitalizationType = UITextAutocapitalizationTypeNone; 36 | _roomText.clearButtonMode = UITextFieldViewModeAlways; 37 | _roomText.delegate = self; 38 | [self addSubview:_roomText]; 39 | 40 | // Give rounded corners and a light gray border. 41 | self.layer.borderWidth = 1; 42 | self.layer.borderColor = [[UIColor lightGrayColor] CGColor]; 43 | self.layer.cornerRadius = 2; 44 | } 45 | return self; 46 | } 47 | 48 | - (void)layoutSubviews { 49 | _roomText.frame = 50 | CGRectMake(kRoomTextFieldMargin, 0, CGRectGetWidth(self.bounds) - kRoomTextFieldMargin, 51 | kRoomTextFieldHeight); 52 | } 53 | 54 | - (CGSize)sizeThatFits:(CGSize)size { 55 | size.height = kRoomTextFieldHeight; 56 | return size; 57 | } 58 | 59 | - (NSString *)roomText { 60 | return _roomText.text; 61 | } 62 | 63 | #pragma mark - UITextFieldDelegate 64 | 65 | - (BOOL)textFieldShouldReturn:(UITextField *)textField { 66 | // There is no other control that can take focus, so manually resign focus 67 | // when return (Join) is pressed to trigger |textFieldDidEndEditing|. 68 | [textField resignFirstResponder]; 69 | return YES; 70 | } 71 | 72 | @end 73 | 74 | @implementation ARDMainView { 75 | ARDRoomTextField *_roomText; 76 | UIButton *_startRegularCallButton; 77 | UIButton *_startLoopbackCallButton; 78 | UIButton *_audioLoopButton; 79 | } 80 | 81 | @synthesize delegate = _delegate; 82 | @synthesize isAudioLoopPlaying = _isAudioLoopPlaying; 83 | 84 | - (instancetype)initWithFrame:(CGRect)frame { 85 | if (self = [super initWithFrame:frame]) { 86 | _roomText = [[ARDRoomTextField alloc] initWithFrame:CGRectZero]; 87 | [self addSubview:_roomText]; 88 | 89 | UIFont *controlFont = [UIFont boldSystemFontOfSize:18.0]; 90 | UIColor *controlFontColor = [UIColor whiteColor]; 91 | 92 | _startRegularCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; 93 | _startRegularCallButton.titleLabel.font = controlFont; 94 | [_startRegularCallButton setTitleColor:controlFontColor forState:UIControlStateNormal]; 95 | _startRegularCallButton.backgroundColor 96 | = [UIColor colorWithRed:66.0/255.0 green:200.0/255.0 blue:90.0/255.0 alpha:1.0]; 97 | [_startRegularCallButton setTitle:@"Call room" forState:UIControlStateNormal]; 98 | [_startRegularCallButton addTarget:self 99 | action:@selector(onStartRegularCall:) 100 | forControlEvents:UIControlEventTouchUpInside]; 101 | [self addSubview:_startRegularCallButton]; 102 | 103 | _startLoopbackCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; 104 | _startLoopbackCallButton.titleLabel.font = controlFont; 105 | [_startLoopbackCallButton setTitleColor:controlFontColor forState:UIControlStateNormal]; 106 | _startLoopbackCallButton.backgroundColor = 107 | [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0]; 108 | [_startLoopbackCallButton setTitle:@"Loopback call" forState:UIControlStateNormal]; 109 | [_startLoopbackCallButton addTarget:self 110 | action:@selector(onStartLoopbackCall:) 111 | forControlEvents:UIControlEventTouchUpInside]; 112 | [self addSubview:_startLoopbackCallButton]; 113 | 114 | 115 | // Used to test what happens to sounds when calls are in progress. 116 | _audioLoopButton = [UIButton buttonWithType:UIButtonTypeSystem]; 117 | _audioLoopButton.titleLabel.font = controlFont; 118 | [_audioLoopButton setTitleColor:controlFontColor forState:UIControlStateNormal]; 119 | _audioLoopButton.backgroundColor = 120 | [UIColor colorWithRed:1.0 green:149.0/255.0 blue:0.0 alpha:1.0]; 121 | [self updateAudioLoopButton]; 122 | [_audioLoopButton addTarget:self 123 | action:@selector(onToggleAudioLoop:) 124 | forControlEvents:UIControlEventTouchUpInside]; 125 | [self addSubview:_audioLoopButton]; 126 | 127 | self.backgroundColor = [UIColor whiteColor]; 128 | } 129 | return self; 130 | } 131 | 132 | - (void)setIsAudioLoopPlaying:(BOOL)isAudioLoopPlaying { 133 | if (_isAudioLoopPlaying == isAudioLoopPlaying) { 134 | return; 135 | } 136 | _isAudioLoopPlaying = isAudioLoopPlaying; 137 | [self updateAudioLoopButton]; 138 | } 139 | 140 | - (void)layoutSubviews { 141 | CGRect bounds = self.bounds; 142 | CGFloat roomTextWidth = bounds.size.width - 2 * kRoomTextFieldMargin; 143 | CGFloat roomTextHeight = [_roomText sizeThatFits:bounds.size].height; 144 | _roomText.frame = 145 | CGRectMake(kRoomTextFieldMargin, kRoomTextFieldMargin, roomTextWidth, 146 | roomTextHeight); 147 | 148 | CGFloat buttonHeight = 149 | (CGRectGetMaxY(self.bounds) - CGRectGetMaxY(_roomText.frame) - kCallControlMargin * 4) / 3; 150 | 151 | CGFloat regularCallFrameTop = CGRectGetMaxY(_roomText.frame) + kCallControlMargin; 152 | CGRect regularCallFrame = CGRectMake(kCallControlMargin, 153 | regularCallFrameTop, 154 | bounds.size.width - 2*kCallControlMargin, 155 | buttonHeight); 156 | 157 | CGFloat loopbackCallFrameTop = CGRectGetMaxY(regularCallFrame) + kCallControlMargin; 158 | CGRect loopbackCallFrame = CGRectMake(kCallControlMargin, 159 | loopbackCallFrameTop, 160 | bounds.size.width - 2*kCallControlMargin, 161 | buttonHeight); 162 | 163 | CGFloat audioLoopTop = CGRectGetMaxY(loopbackCallFrame) + kCallControlMargin; 164 | CGRect audioLoopFrame = CGRectMake(kCallControlMargin, 165 | audioLoopTop, 166 | bounds.size.width - 2*kCallControlMargin, 167 | buttonHeight); 168 | 169 | _startRegularCallButton.frame = regularCallFrame; 170 | _startLoopbackCallButton.frame = loopbackCallFrame; 171 | _audioLoopButton.frame = audioLoopFrame; 172 | } 173 | 174 | #pragma mark - Private 175 | 176 | - (void)updateAudioLoopButton { 177 | if (_isAudioLoopPlaying) { 178 | [_audioLoopButton setTitle:@"Stop sound" forState:UIControlStateNormal]; 179 | } else { 180 | [_audioLoopButton setTitle:@"Play sound" forState:UIControlStateNormal]; 181 | } 182 | } 183 | 184 | - (void)onToggleAudioLoop:(id)sender { 185 | [_delegate mainViewDidToggleAudioLoop:self]; 186 | } 187 | 188 | - (void)onStartRegularCall:(id)sender { 189 | [_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:NO]; 190 | } 191 | 192 | - (void)onStartLoopbackCall:(id)sender { 193 | [_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:YES]; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /webrtc/ios/ARDMainViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface ARDMainViewController : UIViewController 14 | @end 15 | -------------------------------------------------------------------------------- /webrtc/ios/ARDMainViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDMainViewController.h" 12 | 13 | #import 14 | 15 | #import 16 | #import 17 | #import 18 | #import 19 | 20 | #import "ARDAppClient.h" 21 | #import "ARDMainView.h" 22 | #import "ARDSettingsModel.h" 23 | #import "ARDSettingsViewController.h" 24 | #import "ARDVideoCallViewController.h" 25 | 26 | static NSString *const barButtonImageString = @"ic_settings_black_24dp.png"; 27 | 28 | // Launch argument to be passed to indicate that the app should start loopback immediatly 29 | static NSString *const loopbackLaunchProcessArgument = @"loopback"; 30 | 31 | @interface ARDMainViewController () 34 | @property(nonatomic, strong) ARDMainView *mainView; 35 | @property(nonatomic, strong) AVAudioPlayer *audioPlayer; 36 | @end 37 | 38 | @implementation ARDMainViewController { 39 | BOOL _useManualAudio; 40 | } 41 | 42 | @synthesize mainView = _mainView; 43 | @synthesize audioPlayer = _audioPlayer; 44 | 45 | - (void)viewDidLoad { 46 | [super viewDidLoad]; 47 | if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) { 48 | [self mainView:nil didInputRoom:@"" isLoopback:YES]; 49 | } 50 | } 51 | 52 | - (void)loadView { 53 | self.title = @"AppRTC Mobile"; 54 | _mainView = [[ARDMainView alloc] initWithFrame:CGRectZero]; 55 | _mainView.delegate = self; 56 | self.view = _mainView; 57 | [self addSettingsBarButton]; 58 | 59 | RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *webRTCConfig = 60 | [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) webRTCConfiguration]; 61 | webRTCConfig.categoryOptions = webRTCConfig.categoryOptions | 62 | AVAudioSessionCategoryOptionDefaultToSpeaker; 63 | [RTC_OBJC_TYPE(RTCAudioSessionConfiguration) setWebRTCConfiguration:webRTCConfig]; 64 | 65 | RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 66 | [session addDelegate:self]; 67 | 68 | [self configureAudioSession]; 69 | [self setupAudioPlayer]; 70 | } 71 | 72 | - (void)addSettingsBarButton { 73 | UIBarButtonItem *settingsButton = 74 | [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:barButtonImageString] 75 | style:UIBarButtonItemStylePlain 76 | target:self 77 | action:@selector(showSettings:)]; 78 | self.navigationItem.rightBarButtonItem = settingsButton; 79 | } 80 | 81 | + (NSString *)loopbackRoomString { 82 | NSString *loopbackRoomString = 83 | [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; 84 | return loopbackRoomString; 85 | } 86 | 87 | #pragma mark - ARDMainViewDelegate 88 | 89 | - (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback { 90 | if (!room.length) { 91 | if (isLoopback) { 92 | // If this is a loopback call, allow a generated room name. 93 | room = [[self class] loopbackRoomString]; 94 | } else { 95 | [self showAlertWithMessage:@"Missing room name."]; 96 | return; 97 | } 98 | } 99 | // Trim whitespaces. 100 | NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceCharacterSet]; 101 | NSString *trimmedRoom = [room stringByTrimmingCharactersInSet:whitespaceSet]; 102 | 103 | // Check that room name is valid. 104 | NSError *error = nil; 105 | NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive; 106 | NSRegularExpression *regex = 107 | [NSRegularExpression regularExpressionWithPattern:@"\\w+" 108 | options:options 109 | error:&error]; 110 | if (error) { 111 | [self showAlertWithMessage:error.localizedDescription]; 112 | return; 113 | } 114 | NSRange matchRange = 115 | [regex rangeOfFirstMatchInString:trimmedRoom 116 | options:0 117 | range:NSMakeRange(0, trimmedRoom.length)]; 118 | if (matchRange.location == NSNotFound || 119 | matchRange.length != trimmedRoom.length) { 120 | [self showAlertWithMessage:@"Invalid room name."]; 121 | return; 122 | } 123 | 124 | ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 125 | 126 | RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 127 | session.useManualAudio = [settingsModel currentUseManualAudioConfigSettingFromStore]; 128 | session.isAudioEnabled = NO; 129 | 130 | // Kick off the video call. 131 | ARDVideoCallViewController *videoCallViewController = 132 | [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom 133 | isLoopback:isLoopback 134 | delegate:self]; 135 | videoCallViewController.modalTransitionStyle = 136 | UIModalTransitionStyleCrossDissolve; 137 | videoCallViewController.modalPresentationStyle = UIModalPresentationFullScreen; 138 | [self presentViewController:videoCallViewController 139 | animated:YES 140 | completion:nil]; 141 | } 142 | 143 | - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView { 144 | if (mainView.isAudioLoopPlaying) { 145 | [_audioPlayer stop]; 146 | } else { 147 | [_audioPlayer play]; 148 | } 149 | mainView.isAudioLoopPlaying = _audioPlayer.playing; 150 | } 151 | 152 | #pragma mark - ARDVideoCallViewControllerDelegate 153 | 154 | - (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController { 155 | if (![viewController isBeingDismissed]) { 156 | RTCLog(@"Dismissing VC"); 157 | [self dismissViewControllerAnimated:YES completion:^{ 158 | [self restartAudioPlayerIfNeeded]; 159 | }]; 160 | } 161 | RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 162 | session.isAudioEnabled = NO; 163 | } 164 | 165 | #pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate) 166 | 167 | - (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session { 168 | // Stop playback on main queue and then configure WebRTC. 169 | [RTC_OBJC_TYPE(RTCDispatcher) 170 | dispatchAsyncOnType:RTCDispatcherTypeMain 171 | block:^{ 172 | if (self.mainView.isAudioLoopPlaying) { 173 | RTCLog(@"Stopping audio loop due to WebRTC start."); 174 | [self.audioPlayer stop]; 175 | } 176 | RTCLog(@"Setting isAudioEnabled to YES."); 177 | session.isAudioEnabled = YES; 178 | }]; 179 | } 180 | 181 | - (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session { 182 | // WebRTC is done with the audio session. Restart playback. 183 | [RTC_OBJC_TYPE(RTCDispatcher) dispatchAsyncOnType:RTCDispatcherTypeMain 184 | block:^{ 185 | RTCLog(@"audioSessionDidStopPlayOrRecord"); 186 | [self restartAudioPlayerIfNeeded]; 187 | }]; 188 | } 189 | 190 | #pragma mark - Private 191 | - (void)showSettings:(id)sender { 192 | ARDSettingsViewController *settingsController = 193 | [[ARDSettingsViewController alloc] initWithStyle:UITableViewStyleGrouped 194 | settingsModel:[[ARDSettingsModel alloc] init]]; 195 | 196 | UINavigationController *navigationController = 197 | [[UINavigationController alloc] initWithRootViewController:settingsController]; 198 | [self presentViewControllerAsModal:navigationController]; 199 | } 200 | 201 | - (void)presentViewControllerAsModal:(UIViewController *)viewController { 202 | [self presentViewController:viewController animated:YES completion:nil]; 203 | } 204 | 205 | - (void)configureAudioSession { 206 | RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *configuration = 207 | [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init]; 208 | configuration.category = AVAudioSessionCategoryAmbient; 209 | configuration.categoryOptions = AVAudioSessionCategoryOptionDuckOthers; 210 | configuration.mode = AVAudioSessionModeDefault; 211 | 212 | RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 213 | [session lockForConfiguration]; 214 | BOOL hasSucceeded = NO; 215 | NSError *error = nil; 216 | if (session.isActive) { 217 | hasSucceeded = [session setConfiguration:configuration error:&error]; 218 | } else { 219 | hasSucceeded = [session setConfiguration:configuration 220 | active:YES 221 | error:&error]; 222 | } 223 | if (!hasSucceeded) { 224 | RTCLogError(@"Error setting configuration: %@", error.localizedDescription); 225 | } 226 | [session unlockForConfiguration]; 227 | } 228 | 229 | - (void)setupAudioPlayer { 230 | NSString *audioFilePath = 231 | [[NSBundle mainBundle] pathForResource:@"mozart" ofType:@"mp3"]; 232 | NSURL *audioFileURL = [NSURL URLWithString:audioFilePath]; 233 | _audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL 234 | error:nil]; 235 | _audioPlayer.numberOfLoops = -1; 236 | _audioPlayer.volume = 1.0; 237 | [_audioPlayer prepareToPlay]; 238 | } 239 | 240 | - (void)restartAudioPlayerIfNeeded { 241 | [self configureAudioSession]; 242 | if (_mainView.isAudioLoopPlaying && !self.presentedViewController) { 243 | RTCLog(@"Starting audio loop due to WebRTC end."); 244 | [_audioPlayer play]; 245 | } 246 | } 247 | 248 | - (void)showAlertWithMessage:(NSString*)message { 249 | UIAlertController *alert = 250 | [UIAlertController alertControllerWithTitle:nil 251 | message:message 252 | preferredStyle:UIAlertControllerStyleAlert]; 253 | 254 | UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" 255 | style:UIAlertActionStyleDefault 256 | handler:^(UIAlertAction *action){ 257 | }]; 258 | 259 | [alert addAction:defaultAction]; 260 | [self presentViewController:alert animated:YES completion:nil]; 261 | } 262 | 263 | @end 264 | -------------------------------------------------------------------------------- /webrtc/ios/ARDSettingsViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @class ARDSettingsModel; 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | /** 17 | * Displays settings options. 18 | */ 19 | @interface ARDSettingsViewController : UITableViewController 20 | 21 | /** 22 | * Creates new instance. 23 | * 24 | * @param style the table view style that should be used 25 | * @param settingsModel model class for the user settings. 26 | */ 27 | - (instancetype)initWithStyle:(UITableViewStyle)style 28 | settingsModel:(ARDSettingsModel *)settingsModel; 29 | 30 | #pragma mark - Unavailable 31 | 32 | - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE; 33 | - (instancetype)init NS_UNAVAILABLE; 34 | + (instancetype)new NS_UNAVAILABLE; 35 | 36 | @end 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /webrtc/ios/ARDStatsView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface ARDStatsView : UIView 14 | 15 | - (void)setStats:(NSArray *)stats; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/ios/ARDStatsView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDStatsView.h" 12 | 13 | #import 14 | 15 | #import "ARDStatsBuilder.h" 16 | 17 | @implementation ARDStatsView { 18 | UILabel *_statsLabel; 19 | ARDStatsBuilder *_statsBuilder; 20 | } 21 | 22 | - (instancetype)initWithFrame:(CGRect)frame { 23 | if (self = [super initWithFrame:frame]) { 24 | _statsLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 25 | _statsLabel.numberOfLines = 0; 26 | _statsLabel.font = [UIFont fontWithName:@"Roboto" size:12]; 27 | _statsLabel.adjustsFontSizeToFitWidth = YES; 28 | _statsLabel.minimumScaleFactor = 0.6; 29 | _statsLabel.textColor = [UIColor greenColor]; 30 | [self addSubview:_statsLabel]; 31 | self.backgroundColor = [UIColor colorWithWhite:0 alpha:.6]; 32 | _statsBuilder = [[ARDStatsBuilder alloc] init]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)setStats:(NSArray *)stats { 38 | for (RTC_OBJC_TYPE(RTCLegacyStatsReport) * report in stats) { 39 | [_statsBuilder parseStatsReport:report]; 40 | } 41 | _statsLabel.text = _statsBuilder.statsString; 42 | } 43 | 44 | - (void)layoutSubviews { 45 | _statsLabel.frame = self.bounds; 46 | } 47 | 48 | - (CGSize)sizeThatFits:(CGSize)size { 49 | return [_statsLabel sizeThatFits:size]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /webrtc/ios/ARDVideoCallView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | #import "ARDStatsView.h" 17 | 18 | @class ARDVideoCallView; 19 | @protocol ARDVideoCallViewDelegate 20 | 21 | // Called when the camera switch button is pressed. 22 | - (void)videoCallView:(ARDVideoCallView *)view 23 | shouldSwitchCameraWithCompletion:(void (^)(NSError *))completion; 24 | 25 | // Called when the route change button is pressed. 26 | - (void)videoCallView:(ARDVideoCallView *)view 27 | shouldChangeRouteWithCompletion:(void (^)(void))completion; 28 | 29 | // Called when the hangup button is pressed. 30 | - (void)videoCallViewDidHangup:(ARDVideoCallView *)view; 31 | 32 | // Called when stats are enabled by triple tapping. 33 | - (void)videoCallViewDidEnableStats:(ARDVideoCallView *)view; 34 | 35 | @end 36 | 37 | // Video call view that shows local and remote video, provides a label to 38 | // display status, and also a hangup button. 39 | @interface ARDVideoCallView : UIView 40 | 41 | @property(nonatomic, readonly) UILabel *statusLabel; 42 | @property(nonatomic, readonly) RTC_OBJC_TYPE(RTCCameraPreviewView) * localVideoView; 43 | @property(nonatomic, readonly) __kindof UIView *remoteVideoView; 44 | @property(nonatomic, readonly) ARDStatsView *statsView; 45 | @property(nonatomic, weak) id delegate; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /webrtc/ios/ARDVideoCallView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDVideoCallView.h" 12 | 13 | #import 14 | 15 | #import 16 | #if defined(RTC_SUPPORTS_METAL) 17 | #import // nogncheck 18 | #endif 19 | 20 | #import "UIImage+ARDUtilities.h" 21 | 22 | static CGFloat const kButtonPadding = 16; 23 | static CGFloat const kButtonSize = 48; 24 | static CGFloat const kLocalVideoViewSize = 120; 25 | static CGFloat const kLocalVideoViewPadding = 8; 26 | static CGFloat const kStatusBarHeight = 20; 27 | 28 | @interface ARDVideoCallView () 29 | @end 30 | 31 | @implementation ARDVideoCallView { 32 | UIButton *_routeChangeButton; 33 | UIButton *_cameraSwitchButton; 34 | UIButton *_hangupButton; 35 | CGSize _remoteVideoSize; 36 | } 37 | 38 | @synthesize statusLabel = _statusLabel; 39 | @synthesize localVideoView = _localVideoView; 40 | @synthesize remoteVideoView = _remoteVideoView; 41 | @synthesize statsView = _statsView; 42 | @synthesize delegate = _delegate; 43 | 44 | - (instancetype)initWithFrame:(CGRect)frame { 45 | if (self = [super initWithFrame:frame]) { 46 | 47 | #if defined(RTC_SUPPORTS_METAL) 48 | _remoteVideoView = [[RTC_OBJC_TYPE(RTCMTLVideoView) alloc] initWithFrame:CGRectZero]; 49 | #else 50 | RTC_OBJC_TYPE(RTCEAGLVideoView) *remoteView = 51 | [[RTC_OBJC_TYPE(RTCEAGLVideoView) alloc] initWithFrame:CGRectZero]; 52 | remoteView.delegate = self; 53 | _remoteVideoView = remoteView; 54 | #endif 55 | 56 | [self addSubview:_remoteVideoView]; 57 | 58 | _localVideoView = [[RTC_OBJC_TYPE(RTCCameraPreviewView) alloc] initWithFrame:CGRectZero]; 59 | [self addSubview:_localVideoView]; 60 | 61 | _statsView = [[ARDStatsView alloc] initWithFrame:CGRectZero]; 62 | _statsView.hidden = YES; 63 | [self addSubview:_statsView]; 64 | 65 | _routeChangeButton = [UIButton buttonWithType:UIButtonTypeCustom]; 66 | _routeChangeButton.backgroundColor = [UIColor grayColor]; 67 | _routeChangeButton.layer.cornerRadius = kButtonSize / 2; 68 | _routeChangeButton.layer.masksToBounds = YES; 69 | UIImage *image = [UIImage imageForName:@"ic_surround_sound_black_24dp.png" 70 | color:[UIColor whiteColor]]; 71 | [_routeChangeButton setImage:image forState:UIControlStateNormal]; 72 | [_routeChangeButton addTarget:self 73 | action:@selector(onRouteChange:) 74 | forControlEvents:UIControlEventTouchUpInside]; 75 | [self addSubview:_routeChangeButton]; 76 | 77 | // TODO(tkchin): don't display this if we can't actually do camera switch. 78 | _cameraSwitchButton = [UIButton buttonWithType:UIButtonTypeCustom]; 79 | _cameraSwitchButton.backgroundColor = [UIColor grayColor]; 80 | _cameraSwitchButton.layer.cornerRadius = kButtonSize / 2; 81 | _cameraSwitchButton.layer.masksToBounds = YES; 82 | image = [UIImage imageForName:@"ic_switch_video_black_24dp.png" color:[UIColor whiteColor]]; 83 | [_cameraSwitchButton setImage:image forState:UIControlStateNormal]; 84 | [_cameraSwitchButton addTarget:self 85 | action:@selector(onCameraSwitch:) 86 | forControlEvents:UIControlEventTouchUpInside]; 87 | [self addSubview:_cameraSwitchButton]; 88 | 89 | _hangupButton = [UIButton buttonWithType:UIButtonTypeCustom]; 90 | _hangupButton.backgroundColor = [UIColor redColor]; 91 | _hangupButton.layer.cornerRadius = kButtonSize / 2; 92 | _hangupButton.layer.masksToBounds = YES; 93 | image = [UIImage imageForName:@"ic_call_end_black_24dp.png" 94 | color:[UIColor whiteColor]]; 95 | [_hangupButton setImage:image forState:UIControlStateNormal]; 96 | [_hangupButton addTarget:self 97 | action:@selector(onHangup:) 98 | forControlEvents:UIControlEventTouchUpInside]; 99 | [self addSubview:_hangupButton]; 100 | 101 | _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 102 | _statusLabel.font = [UIFont fontWithName:@"Roboto" size:16]; 103 | _statusLabel.textColor = [UIColor whiteColor]; 104 | [self addSubview:_statusLabel]; 105 | 106 | UITapGestureRecognizer *tapRecognizer = 107 | [[UITapGestureRecognizer alloc] 108 | initWithTarget:self 109 | action:@selector(didTripleTap:)]; 110 | tapRecognizer.numberOfTapsRequired = 3; 111 | [self addGestureRecognizer:tapRecognizer]; 112 | } 113 | return self; 114 | } 115 | 116 | - (void)layoutSubviews { 117 | CGRect bounds = self.bounds; 118 | if (_remoteVideoSize.width > 0 && _remoteVideoSize.height > 0) { 119 | // Aspect fill remote video into bounds. 120 | CGRect remoteVideoFrame = 121 | AVMakeRectWithAspectRatioInsideRect(_remoteVideoSize, bounds); 122 | CGFloat scale = 1; 123 | if (remoteVideoFrame.size.width > remoteVideoFrame.size.height) { 124 | // Scale by height. 125 | scale = bounds.size.height / remoteVideoFrame.size.height; 126 | } else { 127 | // Scale by width. 128 | scale = bounds.size.width / remoteVideoFrame.size.width; 129 | } 130 | remoteVideoFrame.size.height *= scale; 131 | remoteVideoFrame.size.width *= scale; 132 | _remoteVideoView.frame = remoteVideoFrame; 133 | _remoteVideoView.center = 134 | CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); 135 | } else { 136 | _remoteVideoView.frame = bounds; 137 | } 138 | 139 | // Aspect fit local video view into a square box. 140 | CGRect localVideoFrame = 141 | CGRectMake(0, 0, kLocalVideoViewSize, kLocalVideoViewSize); 142 | // Place the view in the bottom right. 143 | localVideoFrame.origin.x = CGRectGetMaxX(bounds) 144 | - localVideoFrame.size.width - kLocalVideoViewPadding; 145 | localVideoFrame.origin.y = CGRectGetMaxY(bounds) 146 | - localVideoFrame.size.height - kLocalVideoViewPadding; 147 | _localVideoView.frame = localVideoFrame; 148 | 149 | // Place stats at the top. 150 | CGSize statsSize = [_statsView sizeThatFits:bounds.size]; 151 | _statsView.frame = CGRectMake(CGRectGetMinX(bounds), 152 | CGRectGetMinY(bounds) + kStatusBarHeight, 153 | statsSize.width, statsSize.height); 154 | 155 | // Place hangup button in the bottom left. 156 | _hangupButton.frame = 157 | CGRectMake(CGRectGetMinX(bounds) + kButtonPadding, 158 | CGRectGetMaxY(bounds) - kButtonPadding - 159 | kButtonSize, 160 | kButtonSize, 161 | kButtonSize); 162 | 163 | // Place button to the right of hangup button. 164 | CGRect cameraSwitchFrame = _hangupButton.frame; 165 | cameraSwitchFrame.origin.x = 166 | CGRectGetMaxX(cameraSwitchFrame) + kButtonPadding; 167 | _cameraSwitchButton.frame = cameraSwitchFrame; 168 | 169 | // Place route button to the right of camera button. 170 | CGRect routeChangeFrame = _cameraSwitchButton.frame; 171 | routeChangeFrame.origin.x = 172 | CGRectGetMaxX(routeChangeFrame) + kButtonPadding; 173 | _routeChangeButton.frame = routeChangeFrame; 174 | 175 | [_statusLabel sizeToFit]; 176 | _statusLabel.center = 177 | CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); 178 | } 179 | 180 | #pragma mark - RTC_OBJC_TYPE(RTCVideoViewDelegate) 181 | 182 | - (void)videoView:(id)videoView didChangeVideoSize:(CGSize)size { 183 | if (videoView == _remoteVideoView) { 184 | _remoteVideoSize = size; 185 | } 186 | [self setNeedsLayout]; 187 | } 188 | 189 | #pragma mark - Private 190 | 191 | - (void)onCameraSwitch:(UIButton *)sender { 192 | sender.enabled = false; 193 | [_delegate videoCallView:self 194 | shouldSwitchCameraWithCompletion:^(NSError *error) { 195 | dispatch_async(dispatch_get_main_queue(), ^(void) { 196 | sender.enabled = true; 197 | }); 198 | }]; 199 | } 200 | 201 | - (void)onRouteChange:(UIButton *)sender { 202 | sender.enabled = false; 203 | __weak ARDVideoCallView *weakSelf = self; 204 | [_delegate videoCallView:self 205 | shouldChangeRouteWithCompletion:^(void) { 206 | ARDVideoCallView *strongSelf = weakSelf; 207 | if (strongSelf) { 208 | dispatch_async(dispatch_get_main_queue(), ^(void) { 209 | sender.enabled = true; 210 | }); 211 | } 212 | }]; 213 | } 214 | 215 | - (void)onHangup:(id)sender { 216 | [_delegate videoCallViewDidHangup:self]; 217 | } 218 | 219 | - (void)didTripleTap:(UITapGestureRecognizer *)recognizer { 220 | [_delegate videoCallViewDidEnableStats:self]; 221 | } 222 | 223 | @end 224 | -------------------------------------------------------------------------------- /webrtc/ios/ARDVideoCallViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @class ARDVideoCallViewController; 14 | @protocol ARDVideoCallViewControllerDelegate 15 | 16 | - (void)viewControllerDidFinish:(ARDVideoCallViewController *)viewController; 17 | 18 | @end 19 | 20 | @interface ARDVideoCallViewController : UIViewController 21 | 22 | @property(nonatomic, weak) id delegate; 23 | 24 | - (instancetype)initForRoom:(NSString *)room 25 | isLoopback:(BOOL)isLoopback 26 | delegate:(id)delegate; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /webrtc/ios/ARDVideoCallViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDVideoCallViewController.h" 12 | 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | 19 | #import "ARDAppClient.h" 20 | #import "ARDCaptureController.h" 21 | #import "ARDFileCaptureController.h" 22 | #import "ARDSettingsModel.h" 23 | #import "ARDVideoCallView.h" 24 | 25 | @interface ARDVideoCallViewController () 28 | @property(nonatomic, strong) RTC_OBJC_TYPE(RTCVideoTrack) * remoteVideoTrack; 29 | @property(nonatomic, readonly) ARDVideoCallView *videoCallView; 30 | @property(nonatomic, assign) AVAudioSessionPortOverride portOverride; 31 | @end 32 | 33 | @implementation ARDVideoCallViewController { 34 | ARDAppClient *_client; 35 | RTC_OBJC_TYPE(RTCVideoTrack) * _remoteVideoTrack; 36 | ARDCaptureController *_captureController; 37 | ARDFileCaptureController *_fileCaptureController NS_AVAILABLE_IOS(10); 38 | } 39 | 40 | @synthesize videoCallView = _videoCallView; 41 | @synthesize remoteVideoTrack = _remoteVideoTrack; 42 | @synthesize delegate = _delegate; 43 | @synthesize portOverride = _portOverride; 44 | 45 | - (instancetype)initForRoom:(NSString *)room 46 | isLoopback:(BOOL)isLoopback 47 | delegate:(id)delegate { 48 | if (self = [super init]) { 49 | ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 50 | _delegate = delegate; 51 | 52 | _client = [[ARDAppClient alloc] initWithDelegate:self]; 53 | [_client connectToRoomWithId:room settings:settingsModel isLoopback:isLoopback]; 54 | } 55 | return self; 56 | } 57 | 58 | - (void)loadView { 59 | _videoCallView = [[ARDVideoCallView alloc] initWithFrame:CGRectZero]; 60 | _videoCallView.delegate = self; 61 | _videoCallView.statusLabel.text = 62 | [self statusTextForState:RTCIceConnectionStateNew]; 63 | self.view = _videoCallView; 64 | 65 | RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 66 | [session addDelegate:self]; 67 | } 68 | 69 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations { 70 | return UIInterfaceOrientationMaskAll; 71 | } 72 | 73 | #pragma mark - ARDAppClientDelegate 74 | 75 | - (void)appClient:(ARDAppClient *)client 76 | didChangeState:(ARDAppClientState)state { 77 | switch (state) { 78 | case kARDAppClientStateConnected: 79 | RTCLog(@"Client connected."); 80 | break; 81 | case kARDAppClientStateConnecting: 82 | RTCLog(@"Client connecting."); 83 | break; 84 | case kARDAppClientStateDisconnected: 85 | RTCLog(@"Client disconnected."); 86 | [self hangup]; 87 | break; 88 | } 89 | } 90 | 91 | - (void)appClient:(ARDAppClient *)client 92 | didChangeConnectionState:(RTCIceConnectionState)state { 93 | RTCLog(@"ICE state changed: %ld", (long)state); 94 | __weak ARDVideoCallViewController *weakSelf = self; 95 | dispatch_async(dispatch_get_main_queue(), ^{ 96 | ARDVideoCallViewController *strongSelf = weakSelf; 97 | strongSelf.videoCallView.statusLabel.text = 98 | [strongSelf statusTextForState:state]; 99 | }); 100 | } 101 | 102 | - (void)appClient:(ARDAppClient *)client 103 | didCreateLocalCapturer:(RTC_OBJC_TYPE(RTCCameraVideoCapturer) *)localCapturer { 104 | _videoCallView.localVideoView.captureSession = localCapturer.captureSession; 105 | ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 106 | _captureController = 107 | [[ARDCaptureController alloc] initWithCapturer:localCapturer settings:settingsModel]; 108 | [_captureController startCapture]; 109 | } 110 | 111 | - (void)appClient:(ARDAppClient *)client 112 | didCreateLocalFileCapturer:(RTC_OBJC_TYPE(RTCFileVideoCapturer) *)fileCapturer { 113 | #if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) 114 | if (@available(iOS 10, *)) { 115 | _fileCaptureController = [[ARDFileCaptureController alloc] initWithCapturer:fileCapturer]; 116 | [_fileCaptureController startCapture]; 117 | } 118 | #endif 119 | } 120 | 121 | - (void)appClient:(ARDAppClient *)client 122 | didReceiveLocalVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)localVideoTrack { 123 | } 124 | 125 | - (void)appClient:(ARDAppClient *)client 126 | didReceiveRemoteVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack { 127 | self.remoteVideoTrack = remoteVideoTrack; 128 | __weak ARDVideoCallViewController *weakSelf = self; 129 | dispatch_async(dispatch_get_main_queue(), ^{ 130 | ARDVideoCallViewController *strongSelf = weakSelf; 131 | strongSelf.videoCallView.statusLabel.hidden = YES; 132 | }); 133 | } 134 | 135 | - (void)appClient:(ARDAppClient *)client 136 | didGetStats:(NSArray *)stats { 137 | _videoCallView.statsView.stats = stats; 138 | [_videoCallView setNeedsLayout]; 139 | } 140 | 141 | - (void)appClient:(ARDAppClient *)client 142 | didError:(NSError *)error { 143 | NSString *message = 144 | [NSString stringWithFormat:@"%@", error.localizedDescription]; 145 | [self hangup]; 146 | [self showAlertWithMessage:message]; 147 | } 148 | 149 | #pragma mark - ARDVideoCallViewDelegate 150 | 151 | - (void)videoCallViewDidHangup:(ARDVideoCallView *)view { 152 | [self hangup]; 153 | } 154 | 155 | - (void)videoCallView:(ARDVideoCallView *)view 156 | shouldSwitchCameraWithCompletion:(void (^)(NSError *))completion { 157 | [_captureController switchCamera:completion]; 158 | } 159 | 160 | - (void)videoCallView:(ARDVideoCallView *)view 161 | shouldChangeRouteWithCompletion:(void (^)(void))completion { 162 | NSParameterAssert(completion); 163 | AVAudioSessionPortOverride override = AVAudioSessionPortOverrideNone; 164 | if (_portOverride == AVAudioSessionPortOverrideNone) { 165 | override = AVAudioSessionPortOverrideSpeaker; 166 | } 167 | [RTC_OBJC_TYPE(RTCDispatcher) dispatchAsyncOnType:RTCDispatcherTypeAudioSession 168 | block:^{ 169 | RTC_OBJC_TYPE(RTCAudioSession) *session = 170 | [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; 171 | [session lockForConfiguration]; 172 | NSError *error = nil; 173 | if ([session overrideOutputAudioPort:override 174 | error:&error]) { 175 | self.portOverride = override; 176 | } else { 177 | RTCLogError(@"Error overriding output port: %@", 178 | error.localizedDescription); 179 | } 180 | [session unlockForConfiguration]; 181 | completion(); 182 | }]; 183 | } 184 | 185 | - (void)videoCallViewDidEnableStats:(ARDVideoCallView *)view { 186 | _client.shouldGetStats = YES; 187 | _videoCallView.statsView.hidden = NO; 188 | } 189 | 190 | #pragma mark - RTC_OBJC_TYPE(RTCAudioSessionDelegate) 191 | 192 | - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 193 | didDetectPlayoutGlitch:(int64_t)totalNumberOfGlitches { 194 | RTCLog(@"Audio session detected glitch, total: %lld", totalNumberOfGlitches); 195 | } 196 | 197 | #pragma mark - Private 198 | 199 | - (void)setRemoteVideoTrack:(RTC_OBJC_TYPE(RTCVideoTrack) *)remoteVideoTrack { 200 | if (_remoteVideoTrack == remoteVideoTrack) { 201 | return; 202 | } 203 | [_remoteVideoTrack removeRenderer:_videoCallView.remoteVideoView]; 204 | _remoteVideoTrack = nil; 205 | [_videoCallView.remoteVideoView renderFrame:nil]; 206 | _remoteVideoTrack = remoteVideoTrack; 207 | [_remoteVideoTrack addRenderer:_videoCallView.remoteVideoView]; 208 | } 209 | 210 | - (void)hangup { 211 | self.remoteVideoTrack = nil; 212 | _videoCallView.localVideoView.captureSession = nil; 213 | [_captureController stopCapture]; 214 | _captureController = nil; 215 | [_fileCaptureController stopCapture]; 216 | _fileCaptureController = nil; 217 | [_client disconnect]; 218 | [_delegate viewControllerDidFinish:self]; 219 | } 220 | 221 | - (NSString *)statusTextForState:(RTCIceConnectionState)state { 222 | switch (state) { 223 | case RTCIceConnectionStateNew: 224 | case RTCIceConnectionStateChecking: 225 | return @"Connecting..."; 226 | case RTCIceConnectionStateConnected: 227 | case RTCIceConnectionStateCompleted: 228 | case RTCIceConnectionStateFailed: 229 | case RTCIceConnectionStateDisconnected: 230 | case RTCIceConnectionStateClosed: 231 | case RTCIceConnectionStateCount: 232 | return nil; 233 | } 234 | } 235 | 236 | - (void)showAlertWithMessage:(NSString*)message { 237 | UIAlertController *alert = 238 | [UIAlertController alertControllerWithTitle:nil 239 | message:message 240 | preferredStyle:UIAlertControllerStyleAlert]; 241 | 242 | UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" 243 | style:UIAlertActionStyleDefault 244 | handler:^(UIAlertAction *action){ 245 | }]; 246 | 247 | [alert addAction:defaultAction]; 248 | [self presentViewController:alert animated:YES completion:nil]; 249 | } 250 | 251 | @end 252 | -------------------------------------------------------------------------------- /webrtc/ios/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 12E55 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | AppRTCMobile 11 | CFBundleExecutable 12 | ${EXECUTABLE_NAME} 13 | CFBundleIcons 14 | 15 | CFBundlePrimaryIcon 16 | 17 | CFBundleIconFiles 18 | 19 | Icon.png 20 | Icon-120.png 21 | Icon-180.png 22 | 23 | 24 | 25 | CFBundleIdentifier 26 | com.google.AppRTCMobile 27 | CFBundleInfoDictionaryVersion 28 | 6.0 29 | CFBundleName 30 | ${EXECUTABLE_NAME} 31 | CFBundlePackageType 32 | APPL 33 | CFBundleShortVersionString 34 | 1.0 35 | CFBundleSignature 36 | ???? 37 | CFBundleSupportedPlatforms 38 | 39 | iPhoneOS 40 | 41 | CFBundleVersion 42 | 1.0 43 | UIStatusBarTintParameters 44 | 45 | UINavigationBar 46 | 47 | Style 48 | UIBarStyleDefault 49 | Translucent 50 | 51 | 52 | 53 | UISupportedInterfaceOrientations 54 | 55 | UIInterfaceOrientationPortrait 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | UIInterfaceOrientationPortraitUpsideDown 59 | 60 | UIAppFonts 61 | 62 | Roboto-Regular.ttf 63 | 64 | UIBackgroundModes 65 | 66 | audio 67 | voip 68 | 69 | NSCameraUsageDescription 70 | Camera access needed for video calling 71 | NSMicrophoneUsageDescription 72 | Microphone access needed for video calling 73 | UIFileSharingEnabled 74 | 75 | UILaunchImages 76 | 77 | 78 | UILaunchImageMinimumOSVersion 79 | 7.0 80 | UILaunchImageName 81 | iPhone5 82 | UILaunchImageOrientation 83 | Portrait 84 | UILaunchImageSize 85 | {320, 568} 86 | 87 | 88 | UILaunchImageMinimumOSVersion 89 | 8.0 90 | UILaunchImageName 91 | iPhone6 92 | UILaunchImageOrientation 93 | Portrait 94 | UILaunchImageSize 95 | {375, 667} 96 | 97 | 98 | UILaunchImageMinimumOSVersion 99 | 8.0 100 | UILaunchImageName 101 | iPhone6p 102 | UILaunchImageOrientation 103 | Portrait 104 | UILaunchImageSize 105 | {414, 736} 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /webrtc/ios/RTCVideoCodecInfo+HumanReadable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface RTC_OBJC_TYPE (RTCVideoCodecInfo) 14 | (HumanReadable) 15 | 16 | - (NSString *)humanReadableDescription; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /webrtc/ios/RTCVideoCodecInfo+HumanReadable.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "RTCVideoCodecInfo+HumanReadable.h" 12 | 13 | #import 14 | 15 | @implementation RTC_OBJC_TYPE (RTCVideoCodecInfo) 16 | (HumanReadable) 17 | 18 | - (NSString *)humanReadableDescription { 19 | if ([self.name isEqualToString:@"H264"]) { 20 | NSString *profileId = self.parameters[@"profile-level-id"]; 21 | RTC_OBJC_TYPE(RTCH264ProfileLevelId) *profileLevelId = 22 | [[RTC_OBJC_TYPE(RTCH264ProfileLevelId) alloc] initWithHexString:profileId]; 23 | if (profileLevelId.profile == RTCH264ProfileConstrainedHigh || 24 | profileLevelId.profile == RTCH264ProfileHigh) { 25 | return @"H264 (High)"; 26 | } else if (profileLevelId.profile == RTCH264ProfileConstrainedBaseline || 27 | profileLevelId.profile == RTCH264ProfileBaseline) { 28 | return @"H264 (Baseline)"; 29 | } else { 30 | return [NSString stringWithFormat:@"H264 (%@)", profileId]; 31 | } 32 | } else { 33 | return self.name; 34 | } 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /webrtc/ios/UIImage+ARDUtilities.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface UIImage (ARDUtilities) 14 | 15 | // Returns an color tinted version for the given image resource. 16 | + (UIImage *)imageForName:(NSString *)name color:(UIColor *)color; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /webrtc/ios/UIImage+ARDUtilities.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "UIImage+ARDUtilities.h" 12 | 13 | @implementation UIImage (ARDUtilities) 14 | 15 | + (UIImage *)imageForName:(NSString *)name color:(UIColor *)color { 16 | UIImage *image = [UIImage imageNamed:name]; 17 | if (!image) { 18 | return nil; 19 | } 20 | UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0f); 21 | [color setFill]; 22 | CGRect bounds = CGRectMake(0, 0, image.size.width, image.size.height); 23 | UIRectFill(bounds); 24 | [image drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f]; 25 | UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext(); 26 | UIGraphicsEndImageContext(); 27 | 28 | return coloredImage; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/ARDBroadcastSampleHandler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import 14 | 15 | #import "ARDAppClient.h" 16 | 17 | @protocol ARDExternalSampleDelegate; 18 | 19 | API_AVAILABLE(ios(10.0)) 20 | @interface ARDBroadcastSampleHandler : RPBroadcastSampleHandler 21 | 22 | @property(nonatomic, strong) id capturer; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/ARDBroadcastSampleHandler.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDBroadcastSampleHandler.h" 12 | 13 | #import 14 | 15 | #import "ARDExternalSampleCapturer.h" 16 | #import "ARDSettingsModel.h" 17 | 18 | #import 19 | #import 20 | 21 | @implementation ARDBroadcastSampleHandler { 22 | ARDAppClient *_client; 23 | RTCCallbackLogger *_callbackLogger; 24 | } 25 | 26 | @synthesize capturer = _capturer; 27 | 28 | - (instancetype)init { 29 | if (self = [super init]) { 30 | _callbackLogger = [[RTCCallbackLogger alloc] init]; 31 | os_log_t rtc_os_log = os_log_create("com.google.AppRTCMobile", "RTCLog"); 32 | [_callbackLogger start:^(NSString *logMessage) { 33 | os_log(rtc_os_log, "%{public}s", [logMessage cStringUsingEncoding:NSUTF8StringEncoding]); 34 | }]; 35 | } 36 | return self; 37 | } 38 | 39 | - (void)broadcastStartedWithSetupInfo:(NSDictionary *)setupInfo { 40 | // User has requested to start the broadcast. Setup info from the UI extension can be supplied but 41 | // optional. 42 | ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; 43 | 44 | _client = [[ARDAppClient alloc] initWithDelegate:self]; 45 | _client.broadcast = YES; 46 | 47 | NSString *roomName = nil; 48 | if (setupInfo[@"roomName"]) { 49 | roomName = (NSString *)setupInfo[@"roomName"]; 50 | } else { 51 | u_int32_t randomRoomSuffix = arc4random_uniform(1000); 52 | roomName = [NSString stringWithFormat:@"broadcast_%d", randomRoomSuffix]; 53 | } 54 | [_client connectToRoomWithId:roomName settings:settingsModel isLoopback:NO]; 55 | RTCLog(@"Broadcast started."); 56 | } 57 | 58 | - (void)broadcastPaused { 59 | // User has requested to pause the broadcast. Samples will stop being delivered. 60 | } 61 | 62 | - (void)broadcastResumed { 63 | // User has requested to resume the broadcast. Samples delivery will resume. 64 | } 65 | 66 | - (void)broadcastFinished { 67 | // User has requested to finish the broadcast. 68 | [_client disconnect]; 69 | } 70 | 71 | - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer 72 | withType:(RPSampleBufferType)sampleBufferType { 73 | switch (sampleBufferType) { 74 | case RPSampleBufferTypeVideo: 75 | [self.capturer didCaptureSampleBuffer:sampleBuffer]; 76 | break; 77 | case RPSampleBufferTypeAudioApp: 78 | break; 79 | case RPSampleBufferTypeAudioMic: 80 | break; 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | #pragma mark - ARDAppClientDelegate 87 | 88 | - (void)appClient:(ARDAppClient *)client didChangeState:(ARDAppClientState)state { 89 | switch (state) { 90 | case kARDAppClientStateConnected: 91 | RTCLog(@"Client connected."); 92 | break; 93 | case kARDAppClientStateConnecting: 94 | RTCLog("Client connecting."); 95 | break; 96 | case kARDAppClientStateDisconnected: 97 | RTCLog(@"Client disconnected."); 98 | break; 99 | } 100 | } 101 | 102 | - (void)appClient:(ARDAppClient *)client didChangeConnectionState:(RTCIceConnectionState)state { 103 | RTCLog(@"ICE state changed: %ld", (long)state); 104 | } 105 | 106 | - (void)appClient:(ARDAppClient *)client 107 | didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer { 108 | } 109 | 110 | - (void)appClient:(ARDAppClient *)client 111 | didCreateLocalExternalSampleCapturer:(ARDExternalSampleCapturer *)externalSampleCapturer { 112 | self.capturer = externalSampleCapturer; 113 | } 114 | 115 | - (void)appClient:(ARDAppClient *)client 116 | didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack { 117 | } 118 | 119 | - (void)appClient:(ARDAppClient *)client 120 | didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { 121 | } 122 | 123 | - (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats { 124 | } 125 | 126 | - (void)appClient:(ARDAppClient *)client didError:(NSError *)error { 127 | RTCLog(@"Error: %@", error); 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/ARDBroadcastSetupViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | #import 13 | 14 | API_AVAILABLE(ios(11.0)) 15 | @interface ARDBroadcastSetupViewController : UIViewController 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/ARDBroadcastSetupViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "ARDBroadcastSetupViewController.h" 12 | 13 | @implementation ARDBroadcastSetupViewController { 14 | UITextField *_roomNameField; 15 | } 16 | 17 | - (void)loadView { 18 | UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; 19 | view.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.7]; 20 | 21 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Icon-180"]]; 22 | imageView.translatesAutoresizingMaskIntoConstraints = NO; 23 | [view addSubview:imageView]; 24 | 25 | _roomNameField = [[UITextField alloc] initWithFrame:CGRectZero]; 26 | _roomNameField.borderStyle = UITextBorderStyleRoundedRect; 27 | _roomNameField.font = [UIFont systemFontOfSize:14.0]; 28 | _roomNameField.translatesAutoresizingMaskIntoConstraints = NO; 29 | _roomNameField.placeholder = @"Room name"; 30 | _roomNameField.returnKeyType = UIReturnKeyDone; 31 | _roomNameField.delegate = self; 32 | [view addSubview:_roomNameField]; 33 | 34 | UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem]; 35 | doneButton.translatesAutoresizingMaskIntoConstraints = NO; 36 | doneButton.titleLabel.font = [UIFont systemFontOfSize:20.0]; 37 | [doneButton setTitle:@"Done" forState:UIControlStateNormal]; 38 | [doneButton addTarget:self 39 | action:@selector(userDidFinishSetup) 40 | forControlEvents:UIControlEventTouchUpInside]; 41 | [view addSubview:doneButton]; 42 | 43 | UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeSystem]; 44 | cancelButton.translatesAutoresizingMaskIntoConstraints = NO; 45 | cancelButton.titleLabel.font = [UIFont systemFontOfSize:20.0]; 46 | [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; 47 | [cancelButton addTarget:self 48 | action:@selector(userDidCancelSetup) 49 | forControlEvents:UIControlEventTouchUpInside]; 50 | [view addSubview:cancelButton]; 51 | 52 | UILayoutGuide *margin = view.layoutMarginsGuide; 53 | [imageView.widthAnchor constraintEqualToConstant:60.0].active = YES; 54 | [imageView.heightAnchor constraintEqualToConstant:60.0].active = YES; 55 | [imageView.topAnchor constraintEqualToAnchor:margin.topAnchor constant:20].active = YES; 56 | [imageView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor].active = YES; 57 | 58 | [_roomNameField.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor].active = YES; 59 | [_roomNameField.topAnchor constraintEqualToAnchor:imageView.bottomAnchor constant:20].active = 60 | YES; 61 | [_roomNameField.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor].active = YES; 62 | 63 | [doneButton.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor].active = YES; 64 | [doneButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:-20].active = YES; 65 | 66 | [cancelButton.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor].active = YES; 67 | [cancelButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:-20].active = YES; 68 | 69 | UITapGestureRecognizer *tgr = 70 | [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; 71 | [view addGestureRecognizer:tgr]; 72 | 73 | self.view = view; 74 | } 75 | 76 | - (IBAction)didTap:(id)sender { 77 | [self.view endEditing:YES]; 78 | } 79 | 80 | - (void)userDidFinishSetup { 81 | // URL of the resource where broadcast can be viewed that will be returned to the application 82 | NSURL *broadcastURL = [NSURL 83 | URLWithString:[NSString stringWithFormat:@"https://appr.tc/r/%@", _roomNameField.text]]; 84 | 85 | // Dictionary with setup information that will be provided to broadcast extension when broadcast 86 | // is started 87 | NSDictionary *setupInfo = @{@"roomName" : _roomNameField.text}; 88 | 89 | // Tell ReplayKit that the extension is finished setting up and can begin broadcasting 90 | [self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo]; 91 | } 92 | 93 | - (void)userDidCancelSetup { 94 | // Tell ReplayKit that the extension was cancelled by the user 95 | [self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"com.google.AppRTCMobile" 96 | code:-1 97 | userInfo:nil]]; 98 | } 99 | 100 | #pragma mark - UITextFieldDelegate 101 | 102 | - (BOOL)textFieldShouldReturn:(UITextField *)textField { 103 | [self userDidFinishSetup]; 104 | return YES; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/BroadcastSetupUIInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AppRTCMobile 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | com.google.AppRTCMobile.BroadcastSetupUI 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | NSExtensionActivationRule 28 | 29 | NSExtensionActivationSupportsReplayKitStreaming 30 | 31 | 32 | 33 | NSExtensionPointIdentifier 34 | com.apple.broadcast-services-setupui 35 | NSExtensionPrincipalClass 36 | ARDBroadcastSetupViewController 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /webrtc/ios/broadcast_extension/BroadcastUploadInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AppRTCMobile 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | com.google.AppRTCMobile.BroadcastUpload 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.broadcast-services-upload 27 | NSExtensionPrincipalClass 28 | ARDBroadcastSampleHandler 29 | RPBroadcastProcessMode 30 | RPBroadcastProcessModeSampleBuffer 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /webrtc/ios/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import "ARDAppDelegate.h" 14 | 15 | int main(int argc, char* argv[]) { 16 | @autoreleasepool { 17 | return UIApplicationMain( 18 | argc, argv, nil, NSStringFromClass([ARDAppDelegate class])); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /webrtc/ios/resources/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/Roboto-Regular.ttf -------------------------------------------------------------------------------- /webrtc/ios/resources/foreman.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/foreman.mp4 -------------------------------------------------------------------------------- /webrtc/ios/resources/iPhone5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/iPhone5@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/iPhone6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/iPhone6@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/iPhone6p@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/iPhone6p@3x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_call_end_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_call_end_black_24dp.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_call_end_black_24dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_call_end_black_24dp@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_clear_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_clear_black_24dp.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_clear_black_24dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_clear_black_24dp@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_settings_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_settings_black_24dp.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_settings_black_24dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_settings_black_24dp@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_surround_sound_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_surround_sound_black_24dp.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_surround_sound_black_24dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_surround_sound_black_24dp@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_switch_video_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_switch_video_black_24dp.png -------------------------------------------------------------------------------- /webrtc/ios/resources/ic_switch_video_black_24dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/ic_switch_video_black_24dp@2x.png -------------------------------------------------------------------------------- /webrtc/ios/resources/mozart.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crossle/AppRTCMobile/5a4ab783b739e1145e79472206c7fc5b0770b842/webrtc/ios/resources/mozart.mp3 -------------------------------------------------------------------------------- /webrtc/mac/APPRTCAppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface APPRTCAppDelegate : NSObject 14 | @end 15 | -------------------------------------------------------------------------------- /webrtc/mac/APPRTCAppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import "APPRTCAppDelegate.h" 12 | #import "APPRTCViewController.h" 13 | #import 14 | 15 | @interface APPRTCAppDelegate () 16 | @end 17 | 18 | @implementation APPRTCAppDelegate { 19 | APPRTCViewController* _viewController; 20 | NSWindow* _window; 21 | } 22 | 23 | #pragma mark - NSApplicationDelegate 24 | 25 | - (void)applicationDidFinishLaunching:(NSNotification*)notification { 26 | RTCInitializeSSL(); 27 | NSScreen* screen = [NSScreen mainScreen]; 28 | NSRect visibleRect = [screen visibleFrame]; 29 | NSRect windowRect = NSMakeRect(NSMidX(visibleRect), 30 | NSMidY(visibleRect), 31 | 1320, 32 | 1140); 33 | NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask; 34 | _window = [[NSWindow alloc] initWithContentRect:windowRect 35 | styleMask:styleMask 36 | backing:NSBackingStoreBuffered 37 | defer:NO]; 38 | _window.delegate = self; 39 | [_window makeKeyAndOrderFront:self]; 40 | [_window makeMainWindow]; 41 | _viewController = [[APPRTCViewController alloc] initWithNibName:nil 42 | bundle:nil]; 43 | [_window setContentView:[_viewController view]]; 44 | } 45 | 46 | #pragma mark - NSWindow 47 | 48 | - (void)windowWillClose:(NSNotification*)notification { 49 | [_viewController windowWillClose:notification]; 50 | RTCCleanupSSL(); 51 | [NSApp terminate:self]; 52 | } 53 | 54 | @end 55 | 56 | -------------------------------------------------------------------------------- /webrtc/mac/APPRTCViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | @interface APPRTCViewController : NSViewController 14 | 15 | - (void)windowWillClose:(NSNotification*)notification; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /webrtc/mac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CFBundleDevelopmentRegion 7 | en 8 | CFBundleDisplayName 9 | ${PRODUCT_NAME} 10 | CFBundleExecutable 11 | ${EXECUTABLE_NAME} 12 | CFBundleIdentifier 13 | com.Google.${PRODUCT_NAME:rfc1034identifier} 14 | CFBundleInfoDictionaryVersion 15 | 6.0 16 | CFBundleName 17 | ${PRODUCT_NAME} 18 | CFBundlePackageType 19 | APPL 20 | CFBundleShortVersionString 21 | 1.0 22 | CFBundleVersion 23 | 1.0 24 | LSMinimumSystemVersion 25 | ${MACOSX_DEPLOYMENT_TARGET} 26 | NSPrincipalClass 27 | NSApplication 28 | NSCameraUsageDescription 29 | Camera access needed for video calling 30 | NSMicrophoneUsageDescription 31 | Microphone access needed for video calling 32 | 33 | -------------------------------------------------------------------------------- /webrtc/mac/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #import "APPRTCAppDelegate.h" 14 | 15 | int main(int argc, char* argv[]) { 16 | @autoreleasepool { 17 | [NSApplication sharedApplication]; 18 | APPRTCAppDelegate* delegate = [[APPRTCAppDelegate alloc] init]; 19 | [NSApp setDelegate:delegate]; 20 | [NSApp run]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /webrtc/tests/ARDFileCaptureController_xctest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | #import "ARDFileCaptureController.h" 16 | 17 | #import 18 | 19 | NS_CLASS_AVAILABLE_IOS(10) 20 | @interface ARDFileCaptureControllerTests : XCTestCase 21 | 22 | @property(nonatomic, strong) ARDFileCaptureController *fileCaptureController; 23 | @property(nonatomic, strong) id fileCapturerMock; 24 | 25 | @end 26 | 27 | @implementation ARDFileCaptureControllerTests 28 | 29 | @synthesize fileCaptureController = _fileCaptureController; 30 | @synthesize fileCapturerMock = _fileCapturerMock; 31 | 32 | - (void)setUp { 33 | [super setUp]; 34 | self.fileCapturerMock = OCMClassMock([RTCFileVideoCapturer class]); 35 | self.fileCaptureController = 36 | [[ARDFileCaptureController alloc] initWithCapturer:self.fileCapturerMock]; 37 | } 38 | 39 | - (void)tearDown { 40 | self.fileCaptureController = nil; 41 | [self.fileCapturerMock stopMocking]; 42 | self.fileCapturerMock = nil; 43 | [super tearDown]; 44 | } 45 | 46 | - (void)testCaptureIsStarted { 47 | [[self.fileCapturerMock expect] startCapturingFromFileNamed:[OCMArg any] onError:[OCMArg any]]; 48 | 49 | [self.fileCaptureController startCapture]; 50 | 51 | [self.fileCapturerMock verify]; 52 | } 53 | 54 | - (void)testCaptureIsStoped { 55 | [[self.fileCapturerMock expect] stopCapture]; 56 | 57 | [self.fileCaptureController stopCapture]; 58 | 59 | [self.fileCapturerMock verify]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /webrtc/tests/ARDSettingsModel_xctest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | #import 16 | 17 | #import "ARDSettingsModel+Private.h" 18 | #import "ARDSettingsStore.h" 19 | 20 | 21 | @interface ARDSettingsModelTests : XCTestCase { 22 | ARDSettingsModel *_model; 23 | } 24 | @end 25 | 26 | @implementation ARDSettingsModelTests 27 | 28 | - (id)setupMockStore { 29 | id storeMock = [OCMockObject mockForClass:[ARDSettingsStore class]]; 30 | 31 | id partialMock = [OCMockObject partialMockForObject:_model]; 32 | [[[partialMock stub] andReturn:storeMock] settingsStore]; 33 | [[[partialMock stub] andReturn:@[ @"640x480", @"960x540", @"1280x720" ]] 34 | availableVideoResolutions]; 35 | 36 | return storeMock; 37 | } 38 | 39 | - (void)setUp { 40 | _model = [[ARDSettingsModel alloc] init]; 41 | } 42 | 43 | - (void)testRetrievingSetting { 44 | id storeMock = [self setupMockStore]; 45 | [[[storeMock expect] andReturn:@"640x480"] videoResolution]; 46 | NSString *string = [_model currentVideoResolutionSettingFromStore]; 47 | 48 | XCTAssertEqualObjects(string, @"640x480"); 49 | } 50 | 51 | - (void)testStoringInvalidConstraintReturnsNo { 52 | id storeMock = [self setupMockStore]; 53 | [([[storeMock stub] andReturn:@"960x480"])videoResolution]; 54 | XCTAssertFalse([_model storeVideoResolutionSetting:@"960x480"]); 55 | } 56 | 57 | - (void)testWidthConstraintFromStore { 58 | id storeMock = [self setupMockStore]; 59 | [([[storeMock stub] andReturn:@"1270x480"])videoResolution]; 60 | int width = [_model currentVideoResolutionWidthFromStore]; 61 | 62 | XCTAssertEqual(width, 1270); 63 | } 64 | 65 | - (void)testHeightConstraintFromStore { 66 | id storeMock = [self setupMockStore]; 67 | [([[storeMock stub] andReturn:@"960x540"])videoResolution]; 68 | int height = [_model currentVideoResolutionHeightFromStore]; 69 | 70 | XCTAssertEqual(height, 540); 71 | } 72 | 73 | - (void)testConstraintComponentIsNilWhenInvalidConstraintString { 74 | id storeMock = [self setupMockStore]; 75 | [([[storeMock stub] andReturn:@"invalid"])videoResolution]; 76 | int width = [_model currentVideoResolutionWidthFromStore]; 77 | 78 | XCTAssertEqual(width, 0); 79 | } 80 | 81 | - (void)testStoringAudioSetting { 82 | id storeMock = [self setupMockStore]; 83 | [[storeMock expect] setAudioOnly:YES]; 84 | 85 | [_model storeAudioOnlySetting:YES]; 86 | [storeMock verify]; 87 | } 88 | 89 | - (void)testReturningDefaultCallOption { 90 | id storeMock = [self setupMockStore]; 91 | [[[storeMock stub] andReturnValue:@YES] useManualAudioConfig]; 92 | 93 | XCTAssertTrue([_model currentUseManualAudioConfigSettingFromStore]); 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /webrtc/tests/main.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #import 12 | 13 | #include "test/ios/coverage_util_ios.h" 14 | 15 | int main(int argc, char* argv[]) { 16 | rtc::test::ConfigureCoverageReportPath(); 17 | 18 | @autoreleasepool { 19 | return UIApplicationMain(argc, argv, nil, nil); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /webrtc/third_party/SocketRocket/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2012 Square Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | -------------------------------------------------------------------------------- /webrtc/third_party/SocketRocket/SRWebSocket.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2012 Square Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import 18 | #import 19 | 20 | typedef enum { 21 | SR_CONNECTING = 0, 22 | SR_OPEN = 1, 23 | SR_CLOSING = 2, 24 | SR_CLOSED = 3, 25 | } SRReadyState; 26 | 27 | typedef enum SRStatusCode : NSInteger { 28 | SRStatusCodeNormal = 1000, 29 | SRStatusCodeGoingAway = 1001, 30 | SRStatusCodeProtocolError = 1002, 31 | SRStatusCodeUnhandledType = 1003, 32 | // 1004 reserved. 33 | SRStatusNoStatusReceived = 1005, 34 | // 1004-1006 reserved. 35 | SRStatusCodeInvalidUTF8 = 1007, 36 | SRStatusCodePolicyViolated = 1008, 37 | SRStatusCodeMessageTooBig = 1009, 38 | } SRStatusCode; 39 | 40 | @class SRWebSocket; 41 | 42 | extern NSString *const SRWebSocketErrorDomain; 43 | extern NSString *const SRHTTPResponseErrorKey; 44 | 45 | #pragma mark - SRWebSocketDelegate 46 | 47 | @protocol SRWebSocketDelegate; 48 | 49 | #pragma mark - SRWebSocket 50 | 51 | @interface SRWebSocket : NSObject 52 | 53 | @property(nonatomic, weak) id delegate; 54 | 55 | @property(nonatomic, readonly) SRReadyState readyState; 56 | @property(nonatomic, readonly, retain) NSURL *url; 57 | 58 | // This returns the negotiated protocol. 59 | // It will be nil until after the handshake completes. 60 | @property(nonatomic, readonly, copy) NSString *protocol; 61 | 62 | // Protocols should be an array of strings that turn into Sec-WebSocket-Protocol. 63 | - (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; 64 | - (id)initWithURLRequest:(NSURLRequest *)request; 65 | 66 | // Some helper constructors. 67 | - (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols; 68 | - (id)initWithURL:(NSURL *)url; 69 | 70 | // Delegate queue will be dispatch_main_queue by default. 71 | // You cannot set both OperationQueue and dispatch_queue. 72 | - (void)setDelegateOperationQueue:(NSOperationQueue *)queue; 73 | - (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; 74 | 75 | // By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes. 76 | - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; 77 | - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; 78 | 79 | // SRWebSockets are intended for one-time-use only. Open should be called once and only once. 80 | - (void)open; 81 | 82 | - (void)close; 83 | - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; 84 | 85 | // Send a UTF8 String or Data. 86 | - (void)send:(id)data; 87 | 88 | // Send Data (can be nil) in a ping message. 89 | - (void)sendPing:(NSData *)data; 90 | 91 | @end 92 | 93 | #pragma mark - SRWebSocketDelegate 94 | 95 | @protocol SRWebSocketDelegate 96 | 97 | // message will either be an NSString if the server is using text 98 | // or NSData if the server is using binary. 99 | - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message; 100 | 101 | @optional 102 | 103 | - (void)webSocketDidOpen:(SRWebSocket *)webSocket; 104 | - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error; 105 | - (void)webSocket:(SRWebSocket *)webSocket 106 | didCloseWithCode:(NSInteger)code 107 | reason:(NSString *)reason 108 | wasClean:(BOOL)wasClean; 109 | - (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload; 110 | 111 | @end 112 | 113 | #pragma mark - NSURLRequest (CertificateAdditions) 114 | 115 | @interface NSURLRequest (CertificateAdditions) 116 | 117 | @property(nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates; 118 | 119 | @end 120 | 121 | #pragma mark - NSMutableURLRequest (CertificateAdditions) 122 | 123 | @interface NSMutableURLRequest (CertificateAdditions) 124 | 125 | @property(nonatomic, retain) NSArray *SR_SSLPinnedCertificates; 126 | 127 | @end 128 | 129 | #pragma mark - NSRunLoop (SRWebSocket) 130 | 131 | @interface NSRunLoop (SRWebSocket) 132 | 133 | + (NSRunLoop *)SR_networkRunLoop; 134 | 135 | @end 136 | --------------------------------------------------------------------------------