Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / app / webrtc / objctests / RTCPeerConnectionTest.mm
1 /*
2  * libjingle
3  * Copyright 2013, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #import <Foundation/Foundation.h>
29
30 #import "RTCICEServer.h"
31 #import "RTCMediaConstraints.h"
32 #import "RTCMediaStream.h"
33 #import "RTCPair.h"
34 #import "RTCPeerConnection.h"
35 #import "RTCPeerConnectionFactory.h"
36 #import "RTCPeerConnectionSyncObserver.h"
37 #import "RTCSessionDescription.h"
38 #import "RTCSessionDescriptionSyncObserver.h"
39 #import "RTCVideoRenderer.h"
40 #import "RTCVideoTrack.h"
41
42 #include "webrtc/base/gunit.h"
43 #include "webrtc/base/ssladapter.h"
44
45 #if !defined(__has_feature) || !__has_feature(objc_arc)
46 #error "This file requires ARC support."
47 #endif
48
49 @interface RTCFakeRenderer : NSObject <RTCVideoRenderer>
50 @end
51
52 @implementation RTCFakeRenderer
53
54 - (void)setSize:(CGSize)size {}
55 - (void)renderFrame:(RTCI420Frame*)frame {}
56
57 @end
58
59 @interface RTCPeerConnectionTest : NSObject
60
61 // Returns whether the two sessions are of the same type.
62 + (BOOL)isSession:(RTCSessionDescription*)session1
63     ofSameTypeAsSession:(RTCSessionDescription*)session2;
64
65 // Create and add tracks to pc, with the given source, label, and IDs
66 - (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
67                                  withFactory:(RTCPeerConnectionFactory*)factory
68                                  videoSource:(RTCVideoSource*)videoSource
69                                  streamLabel:(NSString*)streamLabel
70                                 videoTrackID:(NSString*)videoTrackID
71                                 audioTrackID:(NSString*)audioTrackID;
72
73 - (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory;
74
75 @end
76
77 @implementation RTCPeerConnectionTest
78
79 + (BOOL)isSession:(RTCSessionDescription*)session1
80     ofSameTypeAsSession:(RTCSessionDescription*)session2 {
81   return [session1.type isEqual:session2.type];
82 }
83
84 - (RTCMediaStream*)addTracksToPeerConnection:(RTCPeerConnection*)pc
85                                  withFactory:(RTCPeerConnectionFactory*)factory
86                                  videoSource:(RTCVideoSource*)videoSource
87                                  streamLabel:(NSString*)streamLabel
88                                 videoTrackID:(NSString*)videoTrackID
89                                 audioTrackID:(NSString*)audioTrackID {
90   RTCMediaStream* localMediaStream = [factory mediaStreamWithLabel:streamLabel];
91   RTCVideoTrack* videoTrack =
92       [factory videoTrackWithID:videoTrackID source:videoSource];
93   RTCFakeRenderer* videoRenderer = [[RTCFakeRenderer alloc] init];
94   [videoTrack addRenderer:videoRenderer];
95   [localMediaStream addVideoTrack:videoTrack];
96   // Test that removal/re-add works.
97   [localMediaStream removeVideoTrack:videoTrack];
98   [localMediaStream addVideoTrack:videoTrack];
99   RTCAudioTrack* audioTrack = [factory audioTrackWithID:audioTrackID];
100   [localMediaStream addAudioTrack:audioTrack];
101   [pc addStream:localMediaStream];
102   return localMediaStream;
103 }
104
105 - (void)testCompleteSessionWithFactory:(RTCPeerConnectionFactory*)factory {
106   NSArray* mandatory = @[
107     [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"],
108     [[RTCPair alloc] initWithKey:@"internalSctpDataChannels" value:@"true"],
109   ];
110   RTCMediaConstraints* constraints = [[RTCMediaConstraints alloc] init];
111   RTCMediaConstraints* pcConstraints =
112       [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory
113                                             optionalConstraints:nil];
114
115   RTCPeerConnectionSyncObserver* offeringExpectations =
116       [[RTCPeerConnectionSyncObserver alloc] init];
117   RTCPeerConnection* pcOffer =
118       [factory peerConnectionWithICEServers:nil
119                                 constraints:pcConstraints
120                                    delegate:offeringExpectations];
121
122   RTCPeerConnectionSyncObserver* answeringExpectations =
123       [[RTCPeerConnectionSyncObserver alloc] init];
124
125   RTCPeerConnection* pcAnswer =
126       [factory peerConnectionWithICEServers:nil
127                                 constraints:pcConstraints
128                                    delegate:answeringExpectations];
129   // TODO(hughv): Create video capturer
130   RTCVideoCapturer* capturer = nil;
131   RTCVideoSource* videoSource =
132       [factory videoSourceWithCapturer:capturer constraints:constraints];
133
134   // Here and below, "oLMS" refers to offerer's local media stream, and "aLMS"
135   // refers to the answerer's local media stream, with suffixes of "a0" and "v0"
136   // for audio and video tracks, resp.  These mirror chrome historical naming.
137   RTCMediaStream* oLMSUnused = [self addTracksToPeerConnection:pcOffer
138                                                    withFactory:factory
139                                                    videoSource:videoSource
140                                                    streamLabel:@"oLMS"
141                                                   videoTrackID:@"oLMSv0"
142                                                   audioTrackID:@"oLMSa0"];
143
144   RTCDataChannel* offerDC =
145       [pcOffer createDataChannelWithLabel:@"offerDC"
146                                    config:[[RTCDataChannelInit alloc] init]];
147   EXPECT_TRUE([offerDC.label isEqual:@"offerDC"]);
148   offerDC.delegate = offeringExpectations;
149   offeringExpectations.dataChannel = offerDC;
150
151   RTCSessionDescriptionSyncObserver* sdpObserver =
152       [[RTCSessionDescriptionSyncObserver alloc] init];
153   [pcOffer createOfferWithDelegate:sdpObserver constraints:constraints];
154   [sdpObserver wait];
155   EXPECT_TRUE(sdpObserver.success);
156   RTCSessionDescription* offerSDP = sdpObserver.sessionDescription;
157   EXPECT_EQ([@"offer" compare:offerSDP.type options:NSCaseInsensitiveSearch],
158             NSOrderedSame);
159   EXPECT_GT([offerSDP.description length], 0);
160
161   sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
162   [answeringExpectations expectSignalingChange:RTCSignalingHaveRemoteOffer];
163   [answeringExpectations expectAddStream:@"oLMS"];
164   [pcAnswer setRemoteDescriptionWithDelegate:sdpObserver
165                           sessionDescription:offerSDP];
166   [sdpObserver wait];
167
168   RTCMediaStream* aLMSUnused = [self addTracksToPeerConnection:pcAnswer
169                                                    withFactory:factory
170                                                    videoSource:videoSource
171                                                    streamLabel:@"aLMS"
172                                                   videoTrackID:@"aLMSv0"
173                                                   audioTrackID:@"aLMSa0"];
174
175   sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
176   [pcAnswer createAnswerWithDelegate:sdpObserver constraints:constraints];
177   [sdpObserver wait];
178   EXPECT_TRUE(sdpObserver.success);
179   RTCSessionDescription* answerSDP = sdpObserver.sessionDescription;
180   EXPECT_EQ([@"answer" compare:answerSDP.type options:NSCaseInsensitiveSearch],
181             NSOrderedSame);
182   EXPECT_GT([answerSDP.description length], 0);
183
184   [offeringExpectations expectICECandidates:2];
185   [answeringExpectations expectICECandidates:2];
186
187   sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
188   [answeringExpectations expectSignalingChange:RTCSignalingStable];
189   [pcAnswer setLocalDescriptionWithDelegate:sdpObserver
190                          sessionDescription:answerSDP];
191   [sdpObserver wait];
192   EXPECT_TRUE(sdpObserver.sessionDescription == NULL);
193
194   sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
195   [offeringExpectations expectSignalingChange:RTCSignalingHaveLocalOffer];
196   [pcOffer setLocalDescriptionWithDelegate:sdpObserver
197                         sessionDescription:offerSDP];
198   [sdpObserver wait];
199   EXPECT_TRUE(sdpObserver.sessionDescription == NULL);
200
201   [offeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
202   [offeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
203   // TODO(fischman): figure out why this is flaky and re-introduce (and remove
204   // special-casing from the observer!).
205   // [offeringExpectations expectICEConnectionChange:RTCICEConnectionCompleted];
206   [answeringExpectations expectICEConnectionChange:RTCICEConnectionChecking];
207   [answeringExpectations expectICEConnectionChange:RTCICEConnectionConnected];
208
209   [offeringExpectations expectStateChange:kRTCDataChannelStateOpen];
210   [answeringExpectations expectDataChannel:@"offerDC"];
211   [answeringExpectations expectStateChange:kRTCDataChannelStateOpen];
212
213   [offeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
214   [answeringExpectations expectICEGatheringChange:RTCICEGatheringComplete];
215
216   sdpObserver = [[RTCSessionDescriptionSyncObserver alloc] init];
217   [offeringExpectations expectSignalingChange:RTCSignalingStable];
218   [offeringExpectations expectAddStream:@"aLMS"];
219   [pcOffer setRemoteDescriptionWithDelegate:sdpObserver
220                          sessionDescription:answerSDP];
221   [sdpObserver wait];
222   EXPECT_TRUE(sdpObserver.sessionDescription == NULL);
223
224   EXPECT_TRUE([offerSDP.type isEqual:pcOffer.localDescription.type]);
225   EXPECT_TRUE([answerSDP.type isEqual:pcOffer.remoteDescription.type]);
226   EXPECT_TRUE([offerSDP.type isEqual:pcAnswer.remoteDescription.type]);
227   EXPECT_TRUE([answerSDP.type isEqual:pcAnswer.localDescription.type]);
228
229   for (RTCICECandidate* candidate in offeringExpectations
230            .releaseReceivedICECandidates) {
231     [pcAnswer addICECandidate:candidate];
232   }
233   for (RTCICECandidate* candidate in answeringExpectations
234            .releaseReceivedICECandidates) {
235     [pcOffer addICECandidate:candidate];
236   }
237
238   [offeringExpectations waitForAllExpectationsToBeSatisfied];
239   [answeringExpectations waitForAllExpectationsToBeSatisfied];
240
241   EXPECT_EQ(pcOffer.signalingState, RTCSignalingStable);
242   EXPECT_EQ(pcAnswer.signalingState, RTCSignalingStable);
243
244   // Test send and receive UTF-8 text
245   NSString* text = @"你好";
246   NSData* textData = [text dataUsingEncoding:NSUTF8StringEncoding];
247   RTCDataBuffer* buffer =
248       [[RTCDataBuffer alloc] initWithData:textData isBinary:NO];
249   [answeringExpectations expectMessage:[textData copy] isBinary:NO];
250   EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
251   [answeringExpectations waitForAllExpectationsToBeSatisfied];
252
253   // Test send and receive binary data
254   const size_t byteLength = 5;
255   char bytes[byteLength] = {1, 2, 3, 4, 5};
256   NSData* byteData = [NSData dataWithBytes:bytes length:byteLength];
257   buffer = [[RTCDataBuffer alloc] initWithData:byteData isBinary:YES];
258   [answeringExpectations expectMessage:[byteData copy] isBinary:YES];
259   EXPECT_TRUE([offeringExpectations.dataChannel sendData:buffer]);
260   [answeringExpectations waitForAllExpectationsToBeSatisfied];
261
262   [offeringExpectations expectStateChange:kRTCDataChannelStateClosing];
263   [answeringExpectations expectStateChange:kRTCDataChannelStateClosing];
264   [offeringExpectations expectStateChange:kRTCDataChannelStateClosed];
265   [answeringExpectations expectStateChange:kRTCDataChannelStateClosed];
266
267   [answeringExpectations.dataChannel close];
268   [offeringExpectations.dataChannel close];
269
270   [offeringExpectations waitForAllExpectationsToBeSatisfied];
271   [answeringExpectations waitForAllExpectationsToBeSatisfied];
272   // Don't need to listen to further state changes.
273   // TODO(tkchin): figure out why Closed->Closing without this.
274   offeringExpectations.dataChannel.delegate = nil;
275   answeringExpectations.dataChannel.delegate = nil;
276
277   // Let the audio feedback run for 2s to allow human testing and to ensure
278   // things stabilize.  TODO(fischman): replace seconds with # of video frames,
279   // when we have video flowing.
280   [[NSRunLoop currentRunLoop]
281       runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
282
283   [offeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
284   [answeringExpectations expectICEConnectionChange:RTCICEConnectionClosed];
285   [offeringExpectations expectSignalingChange:RTCSignalingClosed];
286   [answeringExpectations expectSignalingChange:RTCSignalingClosed];
287
288   [pcOffer close];
289   [pcAnswer close];
290
291   [offeringExpectations waitForAllExpectationsToBeSatisfied];
292   [answeringExpectations waitForAllExpectationsToBeSatisfied];
293
294   capturer = nil;
295   videoSource = nil;
296   pcOffer = nil;
297   pcAnswer = nil;
298   // TODO(fischman): be stricter about shutdown checks; ensure thread
299   // counts return to where they were before the test kicked off, and
300   // that all objects have in fact shut down.
301 }
302
303 @end
304
305 // TODO(fischman): move {Initialize,Cleanup}SSL into alloc/dealloc of
306 // RTCPeerConnectionTest and avoid the appearance of RTCPeerConnectionTest being
307 // a TestBase since it's not.
308 TEST(RTCPeerConnectionTest, SessionTest) {
309   @autoreleasepool {
310     rtc::InitializeSSL();
311     // Since |factory| will own the signaling & worker threads, it's important
312     // that it outlive the created PeerConnections since they self-delete on the
313     // signaling thread, and if |factory| is freed first then a last refcount on
314     // the factory will expire during this teardown, causing the signaling
315     // thread to try to Join() with itself.  This is a hack to ensure that the
316     // factory outlives RTCPeerConnection:dealloc.
317     // See https://code.google.com/p/webrtc/issues/detail?id=3100.
318     RTCPeerConnectionFactory* factory = [[RTCPeerConnectionFactory alloc] init];
319     @autoreleasepool {
320       RTCPeerConnectionTest* pcTest = [[RTCPeerConnectionTest alloc] init];
321       [pcTest testCompleteSessionWithFactory:factory];
322     }
323     rtc::CleanupSSL();
324   }
325 }