diff options
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.mm | 229 |
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(); + } } |