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 "api/peerconnection/RTCAudioSource.h"
12#import "api/peerconnection/RTCConfiguration.h"
13#import "api/peerconnection/RTCDataChannel.h"
14#import "api/peerconnection/RTCDataChannelConfiguration.h"
15#import "api/peerconnection/RTCMediaConstraints.h"
16#import "api/peerconnection/RTCMediaStreamTrack.h"
17#import "api/peerconnection/RTCPeerConnection.h"
18#import "api/peerconnection/RTCPeerConnectionFactory.h"
19#import "api/peerconnection/RTCRtpReceiver.h"
20#import "api/peerconnection/RTCRtpSender.h"
21#import "api/peerconnection/RTCRtpTransceiver.h"
22#import "api/peerconnection/RTCVideoSource.h"
23
24#import <XCTest/XCTest.h>
25
26@interface RTCPeerConnectionFactoryTests : XCTestCase
27@end
28
29@implementation RTCPeerConnectionFactoryTests
30
31- (void)testPeerConnectionLifetime {
32  @autoreleasepool {
33    RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
34
35    RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
36        [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{}
37                                                             optionalConstraints:nil];
38
39    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
40    RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection;
41
42    @autoreleasepool {
43      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
44      peerConnection =
45          [factory peerConnectionWithConfiguration:config constraints:constraints delegate:nil];
46      [peerConnection close];
47      factory = nil;
48    }
49    peerConnection = nil;
50  }
51
52  XCTAssertTrue(true, @"Expect test does not crash");
53}
54
55- (void)testMediaStreamLifetime {
56  @autoreleasepool {
57    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
58    RTC_OBJC_TYPE(RTCMediaStream) * mediaStream;
59
60    @autoreleasepool {
61      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
62      mediaStream = [factory mediaStreamWithStreamId:@"mediaStream"];
63      factory = nil;
64    }
65    mediaStream = nil;
66  }
67
68  XCTAssertTrue(true, "Expect test does not crash");
69}
70
71- (void)testDataChannelLifetime {
72  @autoreleasepool {
73    RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
74    RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
75        [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{}
76                                                             optionalConstraints:nil];
77    RTC_OBJC_TYPE(RTCDataChannelConfiguration) *dataChannelConfig =
78        [[RTC_OBJC_TYPE(RTCDataChannelConfiguration) alloc] init];
79
80    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
81    RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection;
82    RTC_OBJC_TYPE(RTCDataChannel) * dataChannel;
83
84    @autoreleasepool {
85      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
86      peerConnection =
87          [factory peerConnectionWithConfiguration:config constraints:constraints delegate:nil];
88      dataChannel =
89          [peerConnection dataChannelForLabel:@"test_channel" configuration:dataChannelConfig];
90      XCTAssertNotNil(dataChannel);
91      [peerConnection close];
92      peerConnection = nil;
93      factory = nil;
94    }
95    dataChannel = nil;
96  }
97
98  XCTAssertTrue(true, "Expect test does not crash");
99}
100
101- (void)testRTCRtpTransceiverLifetime {
102  @autoreleasepool {
103    RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
104    config.sdpSemantics = RTCSdpSemanticsUnifiedPlan;
105    RTC_OBJC_TYPE(RTCMediaConstraints) *contraints =
106        [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{}
107                                                             optionalConstraints:nil];
108    RTC_OBJC_TYPE(RTCRtpTransceiverInit) *init =
109        [[RTC_OBJC_TYPE(RTCRtpTransceiverInit) alloc] init];
110
111    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
112    RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection;
113    RTC_OBJC_TYPE(RTCRtpTransceiver) * tranceiver;
114
115    @autoreleasepool {
116      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
117      peerConnection =
118          [factory peerConnectionWithConfiguration:config constraints:contraints delegate:nil];
119      tranceiver = [peerConnection addTransceiverOfType:RTCRtpMediaTypeAudio init:init];
120      XCTAssertNotNil(tranceiver);
121      [peerConnection close];
122      peerConnection = nil;
123      factory = nil;
124    }
125    tranceiver = nil;
126  }
127
128  XCTAssertTrue(true, "Expect test does not crash");
129}
130
131- (void)testRTCRtpSenderLifetime {
132  @autoreleasepool {
133    RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
134    RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
135        [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{}
136                                                             optionalConstraints:nil];
137
138    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
139    RTC_OBJC_TYPE(RTCPeerConnection) * peerConnection;
140    RTC_OBJC_TYPE(RTCRtpSender) * sender;
141
142    @autoreleasepool {
143      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
144      peerConnection =
145          [factory peerConnectionWithConfiguration:config constraints:constraints delegate:nil];
146      sender = [peerConnection senderWithKind:kRTCMediaStreamTrackKindVideo streamId:@"stream"];
147      XCTAssertNotNil(sender);
148      [peerConnection close];
149      peerConnection = nil;
150      factory = nil;
151    }
152    sender = nil;
153  }
154
155  XCTAssertTrue(true, "Expect test does not crash");
156}
157
158- (void)testRTCRtpReceiverLifetime {
159  @autoreleasepool {
160    RTC_OBJC_TYPE(RTCConfiguration) *config = [[RTC_OBJC_TYPE(RTCConfiguration) alloc] init];
161    RTC_OBJC_TYPE(RTCMediaConstraints) *constraints =
162        [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{}
163                                                             optionalConstraints:nil];
164
165    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
166    RTC_OBJC_TYPE(RTCPeerConnection) * pc1;
167    RTC_OBJC_TYPE(RTCPeerConnection) * pc2;
168
169    NSArray<RTC_OBJC_TYPE(RTCRtpReceiver) *> *receivers1;
170    NSArray<RTC_OBJC_TYPE(RTCRtpReceiver) *> *receivers2;
171
172    @autoreleasepool {
173      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
174      pc1 = [factory peerConnectionWithConfiguration:config constraints:constraints delegate:nil];
175      [pc1 senderWithKind:kRTCMediaStreamTrackKindAudio streamId:@"stream"];
176
177      pc2 = [factory peerConnectionWithConfiguration:config constraints:constraints delegate:nil];
178      [pc2 senderWithKind:kRTCMediaStreamTrackKindAudio streamId:@"stream"];
179
180      NSTimeInterval negotiationTimeout = 15;
181      XCTAssertTrue([self negotiatePeerConnection:pc1
182                               withPeerConnection:pc2
183                               negotiationTimeout:negotiationTimeout]);
184
185      XCTAssertEqual(pc1.signalingState, RTCSignalingStateStable);
186      XCTAssertEqual(pc2.signalingState, RTCSignalingStateStable);
187
188      receivers1 = pc1.receivers;
189      receivers2 = pc2.receivers;
190      XCTAssertTrue(receivers1.count > 0);
191      XCTAssertTrue(receivers2.count > 0);
192      [pc1 close];
193      [pc2 close];
194      pc1 = nil;
195      pc2 = nil;
196      factory = nil;
197    }
198    receivers1 = nil;
199    receivers2 = nil;
200  }
201
202  XCTAssertTrue(true, "Expect test does not crash");
203}
204
205- (void)testAudioSourceLifetime {
206  @autoreleasepool {
207    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
208    RTC_OBJC_TYPE(RTCAudioSource) * audioSource;
209
210    @autoreleasepool {
211      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
212      audioSource = [factory audioSourceWithConstraints:nil];
213      XCTAssertNotNil(audioSource);
214      factory = nil;
215    }
216    audioSource = nil;
217  }
218
219  XCTAssertTrue(true, "Expect test does not crash");
220}
221
222- (void)testVideoSourceLifetime {
223  @autoreleasepool {
224    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
225    RTC_OBJC_TYPE(RTCVideoSource) * videoSource;
226
227    @autoreleasepool {
228      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
229      videoSource = [factory videoSource];
230      XCTAssertNotNil(videoSource);
231      factory = nil;
232    }
233    videoSource = nil;
234  }
235
236  XCTAssertTrue(true, "Expect test does not crash");
237}
238
239- (void)testAudioTrackLifetime {
240  @autoreleasepool {
241    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
242    RTC_OBJC_TYPE(RTCAudioTrack) * audioTrack;
243
244    @autoreleasepool {
245      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
246      audioTrack = [factory audioTrackWithTrackId:@"audioTrack"];
247      XCTAssertNotNil(audioTrack);
248      factory = nil;
249    }
250    audioTrack = nil;
251  }
252
253  XCTAssertTrue(true, "Expect test does not crash");
254}
255
256- (void)testVideoTrackLifetime {
257  @autoreleasepool {
258    RTC_OBJC_TYPE(RTCPeerConnectionFactory) * factory;
259    RTC_OBJC_TYPE(RTCVideoTrack) * videoTrack;
260
261    @autoreleasepool {
262      factory = [[RTC_OBJC_TYPE(RTCPeerConnectionFactory) alloc] init];
263      videoTrack = [factory videoTrackWithSource:[factory videoSource] trackId:@"videoTrack"];
264      XCTAssertNotNil(videoTrack);
265      factory = nil;
266    }
267    videoTrack = nil;
268  }
269
270  XCTAssertTrue(true, "Expect test does not crash");
271}
272
273- (bool)negotiatePeerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)pc1
274             withPeerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)pc2
275             negotiationTimeout:(NSTimeInterval)timeout {
276  __weak RTC_OBJC_TYPE(RTCPeerConnection) *weakPC1 = pc1;
277  __weak RTC_OBJC_TYPE(RTCPeerConnection) *weakPC2 = pc2;
278  RTC_OBJC_TYPE(RTCMediaConstraints) *sdpConstraints =
279      [[RTC_OBJC_TYPE(RTCMediaConstraints) alloc] initWithMandatoryConstraints:@{
280        kRTCMediaConstraintsOfferToReceiveAudio : kRTCMediaConstraintsValueTrue
281      }
282                                                           optionalConstraints:nil];
283
284  dispatch_semaphore_t negotiatedSem = dispatch_semaphore_create(0);
285  [weakPC1 offerForConstraints:sdpConstraints
286             completionHandler:^(RTC_OBJC_TYPE(RTCSessionDescription) * offer, NSError * error) {
287               XCTAssertNil(error);
288               XCTAssertNotNil(offer);
289               [weakPC1
290                   setLocalDescription:offer
291                     completionHandler:^(NSError *error) {
292                       XCTAssertNil(error);
293                       [weakPC2
294                           setRemoteDescription:offer
295                              completionHandler:^(NSError *error) {
296                                XCTAssertNil(error);
297                                [weakPC2
298                                    answerForConstraints:sdpConstraints
299                                       completionHandler:^(
300                                           RTC_OBJC_TYPE(RTCSessionDescription) * answer,
301                                           NSError * error) {
302                                         XCTAssertNil(error);
303                                         XCTAssertNotNil(answer);
304                                         [weakPC2
305                                             setLocalDescription:answer
306                                               completionHandler:^(NSError *error) {
307                                                 XCTAssertNil(error);
308                                                 [weakPC1
309                                                     setRemoteDescription:answer
310                                                        completionHandler:^(NSError *error) {
311                                                          XCTAssertNil(error);
312                                                          dispatch_semaphore_signal(negotiatedSem);
313                                                        }];
314                                               }];
315                                       }];
316                              }];
317                     }];
318             }];
319
320  return 0 ==
321      dispatch_semaphore_wait(negotiatedSem,
322                              dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)));
323}
324
325@end
326