diff --git a/webrtc/examples/objc/AppRTCDemo/ARDAppClient+Internal.h b/webrtc/examples/objc/AppRTCDemo/ARDAppClient+Internal.h index f2da4136e7..cdcac966ae 100644 --- a/webrtc/examples/objc/AppRTCDemo/ARDAppClient+Internal.h +++ b/webrtc/examples/objc/AppRTCDemo/ARDAppClient+Internal.h @@ -43,6 +43,8 @@ @property(nonatomic, strong) NSURL *webSocketRestURL; @property(nonatomic, readonly) BOOL isLoopback; @property(nonatomic, readonly) BOOL isAudioOnly; +@property(nonatomic, readonly) BOOL shouldMakeAecDump; +@property(nonatomic, assign) BOOL isAecDumpActive; @property(nonatomic, strong) RTCMediaConstraints *defaultPeerConnectionConstraints; diff --git a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.h b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.h index b7f7546267..95e20d46a9 100644 --- a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.h +++ b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.h @@ -64,9 +64,11 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) { // Establishes a connection with the AppRTC servers for the given room id. // If |isLoopback| is true, the call will connect to itself. // If |isAudioOnly| is true, video will be disabled for the call. +// If |shouldMakeAecDump| is true, an aecdump will be created for the call. - (void)connectToRoomWithId:(NSString *)roomId isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly; + isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump; // Disconnects from the AppRTC servers and any connected clients. - (void)disconnect; diff --git a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m index 43eb6f4ad2..a9dd8b15fb 100644 --- a/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m +++ b/webrtc/examples/objc/AppRTCDemo/ARDAppClient.m @@ -129,6 +129,8 @@ static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB. _defaultPeerConnectionConstraints; @synthesize isLoopback = _isLoopback; @synthesize isAudioOnly = _isAudioOnly; +@synthesize shouldMakeAecDump = _shouldMakeAecDump; +@synthesize isAecDumpActive = _isAecDumpActive; - (instancetype)init { if (self = [super init]) { @@ -220,11 +222,13 @@ static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB. - (void)connectToRoomWithId:(NSString *)roomId isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly { + isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump { NSParameterAssert(roomId.length); NSParameterAssert(_state == kARDAppClientStateDisconnected); _isLoopback = isLoopback; _isAudioOnly = isAudioOnly; + _shouldMakeAecDump = shouldMakeAecDump; self.state = kARDAppClientStateConnecting; #if defined(WEBRTC_IOS) @@ -309,6 +313,10 @@ static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB. _hasReceivedSdp = NO; _messageQueue = [NSMutableArray array]; #if defined(WEBRTC_IOS) + if (_isAecDumpActive) { + [_factory stopAecDump]; + _isAecDumpActive = NO; + } [_peerConnection stopRtcEventLog]; #endif _peerConnection = nil; @@ -562,6 +570,22 @@ static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB. RTCLogError(@"Failed to start event logging."); } } + + // Start aecdump diagnostic recording. + if (_shouldMakeAecDump) { + _isAecDumpActive = YES; + NSString *filePath = [self documentsFilePathForFileName:@"audio.aecdump"]; + int fd = open(filePath.UTF8String, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd < 0) { + RTCLogError(@"Failed to create the aecdump file!"); + _isAecDumpActive = NO; + } else { + if (![_factory startAecDumpWithFileDescriptor:fd maxFileSizeInBytes:-1]) { + RTCLogError(@"Failed to create aecdump."); + _isAecDumpActive = NO; + } + } + } #endif } diff --git a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.h b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.h index a783ca1a1c..e9f4991d7c 100644 --- a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.h +++ b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.h @@ -15,10 +15,11 @@ @protocol ARDMainViewDelegate - (void)mainView:(ARDMainView *)mainView - didInputRoom:(NSString *)room - isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly - useManualAudio:(BOOL)useManualAudio; + didInputRoom:(NSString *)room + isLoopback:(BOOL)isLoopback + isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump + useManualAudio:(BOOL)useManualAudio; - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView; diff --git a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.m b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.m index ef555554c9..59b428a303 100644 --- a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.m +++ b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainView.m @@ -119,6 +119,8 @@ static CGFloat const kCallControlMargin = 8; UILabel *_callOptionsLabel; UISwitch *_audioOnlySwitch; UILabel *_audioOnlyLabel; + UISwitch *_aecdumpSwitch; + UILabel *_aecdumpLabel; UISwitch *_loopbackSwitch; UILabel *_loopbackLabel; UISwitch *_useManualAudioSwitch; @@ -174,6 +176,17 @@ static CGFloat const kCallControlMargin = 8; [_loopbackLabel sizeToFit]; [self addSubview:_loopbackLabel]; + _aecdumpSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; + [_aecdumpSwitch sizeToFit]; + [self addSubview:_aecdumpSwitch]; + + _aecdumpLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _aecdumpLabel.text = @"Create AecDump"; + _aecdumpLabel.font = controlFont; + _aecdumpLabel.textColor = controlFontColor; + [_aecdumpLabel sizeToFit]; + [self addSubview:_aecdumpLabel]; + _useManualAudioSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; [_useManualAudioSwitch sizeToFit]; _useManualAudioSwitch.on = YES; @@ -274,8 +287,21 @@ static CGFloat const kCallControlMargin = 8; _loopbackLabel.center = CGPointMake(loopbackModeLabelCenterX, CGRectGetMidY(loopbackModeRect)); - CGFloat useManualAudioTop = + CGFloat aecdumpModeTop = CGRectGetMaxY(_loopbackSwitch.frame) + kCallControlMargin; + CGRect aecdumpModeRect = CGRectMake(kCallControlMargin * 3, + aecdumpModeTop, + _aecdumpSwitch.frame.size.width, + _aecdumpSwitch.frame.size.height); + _aecdumpSwitch.frame = aecdumpModeRect; + CGFloat aecdumpModeLabelCenterX = CGRectGetMaxX(aecdumpModeRect) + + kCallControlMargin + _aecdumpLabel.frame.size.width / 2; + _aecdumpLabel.center = CGPointMake(aecdumpModeLabelCenterX, + CGRectGetMidY(aecdumpModeRect)); + + + CGFloat useManualAudioTop = + CGRectGetMaxY(_aecdumpSwitch.frame) + kCallControlMargin; CGRect useManualAudioRect = CGRectMake(kCallControlMargin * 3, useManualAudioTop, @@ -334,6 +360,7 @@ static CGFloat const kCallControlMargin = 8; didInputRoom:room isLoopback:_loopbackSwitch.isOn isAudioOnly:_audioOnlySwitch.isOn + shouldMakeAecDump:_aecdumpSwitch.isOn useManualAudio:_useManualAudioSwitch.isOn]; } diff --git a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainViewController.m b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainViewController.m index a684ba32b0..21f00cb4c0 100644 --- a/webrtc/examples/objc/AppRTCDemo/ios/ARDMainViewController.m +++ b/webrtc/examples/objc/AppRTCDemo/ios/ARDMainViewController.m @@ -54,9 +54,10 @@ #pragma mark - ARDMainViewDelegate - (void)mainView:(ARDMainView *)mainView - didInputRoom:(NSString *)room - isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly + didInputRoom:(NSString *)room + isLoopback:(BOOL)isLoopback + isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump useManualAudio:(BOOL)useManualAudio { if (!room.length) { [self showAlertWithMessage:@"Missing room name."]; @@ -96,6 +97,7 @@ [[ARDVideoCallViewController alloc] initForRoom:trimmedRoom isLoopback:isLoopback isAudioOnly:isAudioOnly + shouldMakeAecDump:shouldMakeAecDump delegate:self]; videoCallViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; diff --git a/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h b/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h index f3a9554820..ffffd12ce8 100644 --- a/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h +++ b/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.h @@ -24,6 +24,7 @@ - (instancetype)initForRoom:(NSString *)room isLoopback:(BOOL)isLoopback isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump delegate:(id)delegate; @end diff --git a/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m b/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m index d35e1e6b2d..bb49ca4a36 100644 --- a/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m +++ b/webrtc/examples/objc/AppRTCDemo/ios/ARDVideoCallViewController.m @@ -39,13 +39,15 @@ - (instancetype)initForRoom:(NSString *)room isLoopback:(BOOL)isLoopback isAudioOnly:(BOOL)isAudioOnly + shouldMakeAecDump:(BOOL)shouldMakeAecDump delegate:(id)delegate { if (self = [super init]) { _delegate = delegate; _client = [[ARDAppClient alloc] initWithDelegate:self]; [_client connectToRoomWithId:room isLoopback:isLoopback - isAudioOnly:isAudioOnly]; + isAudioOnly:isAudioOnly + shouldMakeAecDump:shouldMakeAecDump]; } return self; } diff --git a/webrtc/examples/objc/AppRTCDemo/mac/APPRTCViewController.m b/webrtc/examples/objc/AppRTCDemo/mac/APPRTCViewController.m index 914403619c..0f4a54e88e 100644 --- a/webrtc/examples/objc/AppRTCDemo/mac/APPRTCViewController.m +++ b/webrtc/examples/objc/AppRTCDemo/mac/APPRTCViewController.m @@ -284,7 +284,7 @@ static NSUInteger const kLogViewHeight = 280; didEnterRoomId:(NSString*)roomId { [_client disconnect]; ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self]; - [client connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO]; + [client connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO shouldMakeAecDump:NO]; _client = client; } diff --git a/webrtc/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm b/webrtc/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm index 169f9991e1..355031e398 100644 --- a/webrtc/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm +++ b/webrtc/examples/objc/AppRTCDemo/tests/ARDAppClientTest.mm @@ -283,8 +283,8 @@ weakAnswerer = answerer; // Kick off connection. - [caller connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO]; - [answerer connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO]; + [caller connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO shouldMakeAecDump:NO]; + [answerer connectToRoomWithId:roomId isLoopback:NO isAudioOnly:NO shouldMakeAecDump:NO]; [self waitForExpectationsWithTimeout:20 handler:^(NSError *error) { if (error) { NSLog(@"Expectations error: %@", error); diff --git a/webrtc/sdk/objc/Framework/Classes/RTCPeerConnectionFactory.mm b/webrtc/sdk/objc/Framework/Classes/RTCPeerConnectionFactory.mm index 9c9fd75ac0..0ac2ec4c8a 100644 --- a/webrtc/sdk/objc/Framework/Classes/RTCPeerConnectionFactory.mm +++ b/webrtc/sdk/objc/Framework/Classes/RTCPeerConnectionFactory.mm @@ -48,6 +48,19 @@ return self; } +- (BOOL)startAecDumpWithFileDescriptor:(int)fileDescriptor + maxFileSizeInBytes:(int)maxFileSizeInBytes { + // Pass the file to the recorder. The file ownership + // is passed to the recorder, and the recorder + // closes the file when needed. + return _nativeFactory->StartAecDump(fileDescriptor, maxFileSizeInBytes); +} + +- (void)stopAecDump { + // The file is closed by the call below. + _nativeFactory->StopAecDump(); +} + - (RTCAVFoundationVideoSource *)avFoundationVideoSourceWithConstraints: (nullable RTCMediaConstraints *)constraints { return [[RTCAVFoundationVideoSource alloc] initWithFactory:self diff --git a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnectionFactory.h b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnectionFactory.h index f21c107581..abf2373f3c 100644 --- a/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnectionFactory.h +++ b/webrtc/sdk/objc/Framework/Headers/WebRTC/RTCPeerConnectionFactory.h @@ -53,6 +53,16 @@ RTC_EXPORT delegate: (nullable id)delegate; +/** Start an aecdump recording with a file descriptor and + a specified maximum size limit (-1 specifies that no + limit should be used). + This API call will likely change in the future */ +- (BOOL)startAecDumpWithFileDescriptor:(int)fileDescriptor + maxFileSizeInBytes:(int)maxFileSizeInBytes; + +/* Stop an active aecdump recording */ +- (void)stopAecDump; + @end NS_ASSUME_NONNULL_END