summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm')
-rw-r--r--chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm229
1 files changed, 155 insertions, 74 deletions
diff --git a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
index 0ce8822fd1e..7a178f39fcd 100644
--- a/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
+++ b/chromium/third_party/libjingle/source/talk/app/webrtc/objctests/RTCPeerConnectionTest.mm
@@ -30,6 +30,7 @@
#import "RTCICEServer.h"
#import "RTCMediaConstraints.h"
#import "RTCMediaStream.h"
+#import "RTCPair.h"
#import "RTCPeerConnection.h"
#import "RTCPeerConnectionFactory.h"
#import "RTCPeerConnectionSyncObserver.h"
@@ -39,6 +40,7 @@
#import "RTCVideoTrack.h"
#include "talk/base/gunit.h"
+#include "talk/base/ssladapter.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
@@ -47,123 +49,126 @@
@interface RTCPeerConnectionTest : NSObject
// Returns whether the two sessions are of the same type.
-+ (BOOL)isSession:(RTCSessionDescription *)session1
- ofSameTypeAsSession:(RTCSessionDescription *)session2;
++ (BOOL)isSession:(RTCSessionDescription*)session1
+ ofSameTypeAsSession:(RTCSessionDescription*)session2;
// Create and add tracks to pc, with the given source, label, and IDs
-- (RTCMediaStream *)
- addTracksToPeerConnection:(RTCPeerConnection *)pc
- withFactory:(RTCPeerConnectionFactory *)factory
- videoSource:(RTCVideoSource *)videoSource
- streamLabel:(NSString *)streamLabel
- videoTrackID:(NSString *)videoTrackID
- audioTrackID:(NSString *)audioTrackID;
+- (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
+ withFactory:(RTCPeerConnectionFactory*)factory
+ videoSource:(RTCVideoSource*)videoSource
+ streamLabel:(NSString*)streamLabel
+ videoTrackID:(NSString*)videoTrackID
+ audioTrackID:(NSString*)audioTrackID;
-- (void)testCompleteSession;
+- (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory;
@end
@implementation RTCPeerConnectionTest
-+ (BOOL)isSession:(RTCSessionDescription *)session1
- ofSameTypeAsSession:(RTCSessionDescription *)session2 {
++ (BOOL)isSession:(RTCSessionDescription*)session1
+ ofSameTypeAsSession:(RTCSessionDescription*)session2 {
return [session1.type isEqual:session2.type];
}
-- (RTCMediaStream *)
- addTracksToPeerConnection:(RTCPeerConnection *)pc
- withFactory:(RTCPeerConnectionFactory *)factory
- videoSource:(RTCVideoSource *)videoSource
- streamLabel:(NSString *)streamLabel
- videoTrackID:(NSString *)videoTrackID
- audioTrackID:(NSString *)audioTrackID {
- RTCMediaStream *localMediaStream = [factory mediaStreamWithLabel:streamLabel];
- RTCVideoTrack *videoTrack =
+- (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
+ withFactory:(RTCPeerConnectionFactory*)factory
+ videoSource:(RTCVideoSource*)videoSource
+ streamLabel:(NSString*)streamLabel
+ videoTrackID:(NSString*)videoTrackID
+ audioTrackID:(NSString*)audioTrackID {
+ RTCMediaStream* localMediaStream = [factory mediaStreamWithLabel:streamLabel];
+ RTCVideoTrack* videoTrack =
[factory videoTrackWithID:videoTrackID source:videoSource];
- RTCVideoRenderer *videoRenderer =
+ RTCVideoRenderer* videoRenderer =
[[RTCVideoRenderer alloc] initWithDelegate:nil];
[videoTrack addRenderer:videoRenderer];
[localMediaStream addVideoTrack:videoTrack];
// Test that removal/re-add works.
[localMediaStream removeVideoTrack:videoTrack];
[localMediaStream addVideoTrack:videoTrack];
- RTCAudioTrack *audioTrack = [factory audioTrackWithID:audioTrackID];
+ RTCAudioTrack* audioTrack = [factory audioTrackWithID:audioTrackID];
[localMediaStream addAudioTrack:audioTrack];
- RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
[pc addStream:localMediaStream constraints:constraints];
return localMediaStream;
}
-- (void)testCompleteSession {
- RTCPeerConnectionFactory *factory = [[RTCPeerConnectionFactory alloc] init];
- NSString *stunURL = @"stun:stun.l.google.com:19302";
- RTCICEServer *stunServer =
- [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:stunURL]
- username:@""
- password:@""];
- NSArray *iceServers = @[stunServer];
-
- RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] init];
- RTCPeerConnectionSyncObserver *offeringExpectations =
+- (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory {
+ NSArray* mandatory = @[
+ [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"],
+ [[RTCPair alloc] initWithKey:@"internalSctpDataChannels" value:@"true"],
+ ];
+ RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
+ RTCMediaConstraints* pcConstraints =
+ [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
+ optionalConstraints:nil];
+
+ RTCPeerConnectionSyncObserver* offeringExpectations =
[[RTCPeerConnectionSyncObserver alloc] init];
- RTCPeerConnection *pcOffer =
- [factory peerConnectionWithICEServers:iceServers
- constraints:constraints
+ RTCPeerConnection* pcOffer =
+ [factory peerConnectionWithICEServers:nil
+ constraints:pcConstraints
delegate:offeringExpectations];
- RTCPeerConnectionSyncObserver *answeringExpectations =
+ RTCPeerConnectionSyncObserver* answeringExpectations =
[[RTCPeerConnectionSyncObserver alloc] init];
- RTCPeerConnection *pcAnswer =
- [factory peerConnectionWithICEServers:iceServers
- constraints:constraints
- delegate:answeringExpectations];
+ RTCPeerConnection* pcAnswer =
+ [factory peerConnectionWithICEServers:nil
+ constraints:pcConstraints
+ delegate:answeringExpectations];
// TODO(hughv): Create video capturer
- RTCVideoCapturer *capturer = nil;
- RTCVideoSource *videoSource =
+ RTCVideoCapturer* capturer = nil;
+ RTCVideoSource* videoSource =
[factory videoSourceWithCapturer:capturer constraints:constraints];
// Here and below, "oLMS" refers to offerer's local media stream, and "aLMS"
// refers to the answerer's local media stream, with suffixes of "a0" and "v0"
// for audio and video tracks, resp. These mirror chrome historical naming.
- RTCMediaStream *oLMSUnused =
- [self addTracksToPeerConnection:pcOffer
- withFactory:factory
- videoSource:videoSource
- streamLabel:@"oLMS"
- videoTrackID:@"oLMSv0"
- audioTrackID:@"oLMSa0"];
- RTCSessionDescriptionSyncObserver *sdpObserver =
+ RTCMediaStream* oLMSUnused = [self addTracksToPeerConnection:pcOffer
+ withFactory:factory
+ videoSource:videoSource
+ streamLabel:@"oLMS"
+ videoTrackID:@"oLMSv0"
+ audioTrackID:@"oLMSa0"];
+
+ RTCDataChannel* offerDC =
+ [pcOffer createDataChannelWithLabel:@"offerDC"
+ config:[[RTCDataChannelInit alloc] init]];
+ EXPECT_TRUE([offerDC.label isEqual:@"offerDC"]);
+ offerDC.delegate = offeringExpectations;
+ offeringExpectations.dataChannel = offerDC;
+
+ RTCSessionDescriptionSyncObserver* sdpObserver =
[[RTCSessionDescriptionSyncObserver alloc] init];
[pcOffer createOfferWithDelegate:sdpObserver constraints:constraints];
[sdpObserver wait];
EXPECT_TRUE(sdpObserver.success);
- RTCSessionDescription *offerSDP = sdpObserver.sessionDescription;
+ RTCSessionDescription* offerSDP = sdpObserver.sessionDescription;
EXPECT_EQ([@"offer" compare:offerSDP.type options:NSCaseInsensitiveSearch],
NSOrderedSame);
EXPECT_GT([offerSDP.description length], 0);
sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
- [answeringExpectations
- expectSignalingChange:RTCSignalingHaveRemoteOffer];
+ [answeringExpectations expectSignalingChange:RTCSignalingHaveRemoteOffer];
[answeringExpectations expectAddStream:@"oLMS"];
[pcAnswer setRemoteDescriptionWithDelegate:sdpObserver
sessionDescription:offerSDP];
[sdpObserver wait];
- RTCMediaStream *aLMSUnused =
- [self addTracksToPeerConnection:pcAnswer
- withFactory:factory
- videoSource:videoSource
- streamLabel:@"aLMS"
- videoTrackID:@"aLMSv0"
- audioTrackID:@"aLMSa0"];
+ RTCMediaStream* aLMSUnused = [self addTracksToPeerConnection:pcAnswer
+ withFactory:factory
+ videoSource:videoSource
+ streamLabel:@"aLMS"
+ videoTrackID:@"aLMSv0"
+ audioTrackID:@"aLMSa0"];
sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
[pcAnswer createAnswerWithDelegate:sdpObserver constraints:constraints];
[sdpObserver wait];
EXPECT_TRUE(sdpObserver.success);
- RTCSessionDescription *answerSDP = sdpObserver.sessionDescription;
+ RTCSessionDescription* answerSDP = sdpObserver.sessionDescription;
EXPECT_EQ([@"answer" compare:answerSDP.type options:NSCaseInsensitiveSearch],
NSOrderedSame);
EXPECT_GT([answerSDP.description length], 0);
@@ -187,9 +192,16 @@
[offeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
[offeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
+ // TODO(fischman): figure out why this is flaky and re-introduce (and remove
+ // special-casing from the observer!).
+ // [offeringExpectations expectICEConnectionChange:RTCICEConnectionCompleted];
[answeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
[answeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
+ [offeringExpectations expectStateChange:kRTCDataChannelStateOpen];
+ [answeringExpectations expectDataChannel:@"offerDC"];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateOpen];
+
[offeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
[answeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
@@ -206,31 +218,100 @@
EXPECT_TRUE([offerSDP.type isEqual:pcAnswer.remoteDescription.type]);
EXPECT_TRUE([answerSDP.type isEqual:pcAnswer.localDescription.type]);
- for (RTCICECandidate *candidate in
- offeringExpectations.releaseReceivedICECandidates) {
+ for (RTCICECandidate* candidate in offeringExpectations
+ .releaseReceivedICECandidates) {
[pcAnswer addICECandidate:candidate];
}
- for (RTCICECandidate *candidate in
- answeringExpectations.releaseReceivedICECandidates) {
+ for (RTCICECandidate* candidate in answeringExpectations
+ .releaseReceivedICECandidates) {
[pcOffer addICECandidate:candidate];
}
[offeringExpectations waitForAllExpectationsToBeSatisfied];
[answeringExpectations waitForAllExpectationsToBeSatisfied];
- // Let the audio feedback run for 10s to allow human testing and to ensure
+ EXPECT_EQ(pcOffer.signalingState, RTCSignalingStable);
+ EXPECT_EQ(pcAnswer.signalingState, RTCSignalingStable);
+
+ // Test send and receive UTF-8 text
+ NSString* text = @"你好";
+ NSData* textData = [text dataUsingEncoding:NSUTF8StringEncoding];
+ RTCDataBuffer* buffer =
+ [[RTCDataBuffer alloc] initWithData:textData isBinary:NO];
+ [answeringExpectations expectMessage:[textData copy] isBinary:NO];
+ EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ // Test send and receive binary data
+ const size_t byteLength = 5;
+ char bytes[byteLength] = {1, 2, 3, 4, 5};
+ NSData* byteData = [NSData dataWithBytes:bytes length:byteLength];
+ buffer = [[RTCDataBuffer alloc] initWithData:byteData isBinary:YES];
+ [answeringExpectations expectMessage:[byteData copy] isBinary:YES];
+ EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ [offeringExpectations expectStateChange:kRTCDataChannelStateClosing];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateClosing];
+ [offeringExpectations expectStateChange:kRTCDataChannelStateClosed];
+ [answeringExpectations expectStateChange:kRTCDataChannelStateClosed];
+
+ [answeringExpectations.dataChannel close];
+ [offeringExpectations.dataChannel close];
+
+ [offeringExpectations waitForAllExpectationsToBeSatisfied];
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+ // Don't need to listen to further state changes.
+ // TODO(tkchin): figure out why Closed->Closing without this.
+ offeringExpectations.dataChannel.delegate = nil;
+ answeringExpectations.dataChannel.delegate = nil;
+
+ // Let the audio feedback run for 2s to allow human testing and to ensure
// things stabilize. TODO(fischman): replace seconds with # of video frames,
// when we have video flowing.
[[NSRunLoop currentRunLoop]
- runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
+ runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
+
+ [offeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
+ [answeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
+ [offeringExpectations expectSignalingChange:RTCSignalingClosed];
+ [answeringExpectations expectSignalingChange:RTCSignalingClosed];
+
+ [pcOffer close];
+ [pcAnswer close];
- // TODO(hughv): Implement orderly shutdown.
+ [offeringExpectations waitForAllExpectationsToBeSatisfied];
+ [answeringExpectations waitForAllExpectationsToBeSatisfied];
+
+ capturer = nil;
+ videoSource = nil;
+ pcOffer = nil;
+ pcAnswer = nil;
+ // TODO(fischman): be stricter about shutdown checks; ensure thread
+ // counts return to where they were before the test kicked off, and
+ // that all objects have in fact shut down.
}
@end
-
+// TODO(fischman): move {Initialize,Cleanup}SSL into alloc/dealloc of
+// RTCPeerConnectionTest and avoid the appearance of RTCPeerConnectionTest being
+// a TestBase since it's not.
TEST(RTCPeerConnectionTest, SessionTest) {
- RTCPeerConnectionTest *pcTest = [[RTCPeerConnectionTest alloc] init];
- [pcTest testCompleteSession];
+ @autoreleasepool {
+ talk_base::InitializeSSL();
+ // Since |factory| will own the signaling & worker threads, it's important
+ // that it outlive the created PeerConnections since they self-delete on the
+ // signaling thread, and if |factory| is freed first then a last refcount on
+ // the factory will expire during this teardown, causing the signaling
+ // thread to try to Join() with itself. This is a hack to ensure that the
+ // factory outlives RTCPeerConnection:dealloc.
+ // See https://code.google.com/p/webrtc/issues/detail?id=3100.
+ RTCPeerConnectionFactory* factory = [[RTCPeerConnectionFactory alloc] init];
+ @autoreleasepool {
+ RTCPeerConnectionTest* pcTest = [[RTCPeerConnectionTest alloc] init];
+ [pcTest testCompleteSessionWithFactory:factory];
+ }
+ talk_base::CleanupSSL();
+ }
}