• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#if !defined(__has_feature) || !__has_feature(objc_arc)
29#error "This file requires ARC support."
30#endif
31
32#import "RTCPeerConnectionSyncObserver.h"
33
34#import "RTCMediaStream.h"
35
36@implementation RTCPeerConnectionSyncObserver {
37  int _expectedErrors;
38  NSMutableArray* _expectedSignalingChanges;
39  NSMutableArray* _expectedAddStreamLabels;
40  NSMutableArray* _expectedRemoveStreamLabels;
41  int _expectedICECandidates;
42  NSMutableArray* _receivedICECandidates;
43  NSMutableArray* _expectedICEConnectionChanges;
44  NSMutableArray* _expectedICEGatheringChanges;
45  NSMutableArray* _expectedDataChannels;
46  NSMutableArray* _expectedStateChanges;
47  NSMutableArray* _expectedMessages;
48}
49
50- (id)init {
51  self = [super init];
52  if (self) {
53    _expectedSignalingChanges = [NSMutableArray array];
54    _expectedSignalingChanges = [NSMutableArray array];
55    _expectedAddStreamLabels = [NSMutableArray array];
56    _expectedRemoveStreamLabels = [NSMutableArray array];
57    _receivedICECandidates = [NSMutableArray array];
58    _expectedICEConnectionChanges = [NSMutableArray array];
59    _expectedICEGatheringChanges = [NSMutableArray array];
60    _expectedDataChannels = [NSMutableArray array];
61    _expectedMessages = [NSMutableArray array];
62    _expectedStateChanges = [NSMutableArray array];
63  }
64  return self;
65}
66
67- (int)popFirstElementAsInt:(NSMutableArray*)array {
68  NSAssert([array count] > 0, @"Empty array");
69  NSNumber* boxedState = [array objectAtIndex:0];
70  [array removeObjectAtIndex:0];
71  return [boxedState intValue];
72}
73
74- (NSString*)popFirstElementAsNSString:(NSMutableArray*)array {
75  NSAssert([array count] > 0, @"Empty expectation array");
76  NSString* string = [array objectAtIndex:0];
77  [array removeObjectAtIndex:0];
78  return string;
79}
80
81- (BOOL)areAllExpectationsSatisfied {
82  return _expectedICECandidates <= 0 &&  // See comment in gotICECandidate.
83         _expectedErrors == 0 && [_expectedSignalingChanges count] == 0 &&
84         [_expectedICEConnectionChanges count] == 0 &&
85         [_expectedICEGatheringChanges count] == 0 &&
86         [_expectedAddStreamLabels count] == 0 &&
87         [_expectedRemoveStreamLabels count] == 0 &&
88         [_expectedDataChannels count] == 0 &&
89         [_expectedStateChanges count] == 0 &&
90         [_expectedMessages count] == 0;
91  // TODO(hughv): Test video state here too.
92}
93
94- (NSArray*)releaseReceivedICECandidates {
95  NSArray* ret = _receivedICECandidates;
96  _receivedICECandidates = [NSMutableArray array];
97  return ret;
98}
99
100- (void)expectError {
101  ++_expectedErrors;
102}
103
104- (void)expectSignalingChange:(RTCSignalingState)state {
105  [_expectedSignalingChanges addObject:@((int)state)];
106}
107
108- (void)expectAddStream:(NSString*)label {
109  [_expectedAddStreamLabels addObject:label];
110}
111
112- (void)expectRemoveStream:(NSString*)label {
113  [_expectedRemoveStreamLabels addObject:label];
114}
115
116- (void)expectICECandidates:(int)count {
117  _expectedICECandidates += count;
118}
119
120- (void)expectICEConnectionChange:(RTCICEConnectionState)state {
121  [_expectedICEConnectionChanges addObject:@((int)state)];
122}
123
124- (void)expectICEGatheringChange:(RTCICEGatheringState)state {
125  [_expectedICEGatheringChanges addObject:@((int)state)];
126}
127
128- (void)expectDataChannel:(NSString*)label {
129  [_expectedDataChannels addObject:label];
130}
131
132- (void)expectStateChange:(RTCDataChannelState)state {
133  [_expectedStateChanges addObject:@(state)];
134}
135
136- (void)expectMessage:(NSData*)message isBinary:(BOOL)isBinary {
137  RTCDataBuffer* buffer = [[RTCDataBuffer alloc] initWithData:message
138                                                     isBinary:isBinary];
139  [_expectedMessages addObject:buffer];
140}
141
142- (BOOL)waitForAllExpectationsToBeSatisfiedWithTimeout:(NSTimeInterval)timeout {
143  NSParameterAssert(timeout >= 0);
144  // TODO (fischman):  Revisit.  Keeping in sync with the Java version, but
145  // polling is not optimal.
146  // https://code.google.com/p/libjingle/source/browse/trunk/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java?line=212#212
147  NSDate *startTime = [NSDate date];
148  while (![self areAllExpectationsSatisfied]) {
149    if (startTime.timeIntervalSinceNow < -timeout) {
150      return NO;
151    }
152    [[NSRunLoop currentRunLoop]
153        runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
154  }
155  return YES;
156}
157
158#pragma mark - RTCPeerConnectionDelegate methods
159
160- (void)peerConnection:(RTCPeerConnection*)peerConnection
161    signalingStateChanged:(RTCSignalingState)stateChanged {
162  int expectedState = [self popFirstElementAsInt:_expectedSignalingChanges];
163  NSString* message =
164      [NSString stringWithFormat:@"RTCPeerConnectionDelegate::"
165                                 @"onSignalingStateChange [%d] expected[%d]",
166                                 stateChanged,
167                                 expectedState];
168  NSAssert(expectedState == (int)stateChanged, message);
169}
170
171- (void)peerConnection:(RTCPeerConnection*)peerConnection
172           addedStream:(RTCMediaStream*)stream {
173  NSString* expectedLabel =
174      [self popFirstElementAsNSString:_expectedAddStreamLabels];
175  NSAssert([expectedLabel isEqual:stream.label], @"Stream not expected");
176}
177
178- (void)peerConnection:(RTCPeerConnection*)peerConnection
179         removedStream:(RTCMediaStream*)stream {
180  NSString* expectedLabel =
181      [self popFirstElementAsNSString:_expectedRemoveStreamLabels];
182  NSAssert([expectedLabel isEqual:stream.label], @"Stream not expected");
183}
184
185- (void)peerConnectionOnRenegotiationNeeded:(RTCPeerConnection*)peerConnection {
186}
187
188- (void)peerConnection:(RTCPeerConnection*)peerConnection
189       gotICECandidate:(RTCICECandidate*)candidate {
190  --_expectedICECandidates;
191  // We don't assert expectedICECandidates >= 0 because it's hard to know
192  // how many to expect, in general.  We only use expectICECandidates to
193  // assert a minimal count.
194  [_receivedICECandidates addObject:candidate];
195}
196
197- (void)peerConnection:(RTCPeerConnection*)peerConnection
198    iceGatheringChanged:(RTCICEGatheringState)newState {
199  // It's fine to get a variable number of GATHERING messages before
200  // COMPLETE fires (depending on how long the test runs) so we don't assert
201  // any particular count.
202  if (newState == RTCICEGatheringGathering) {
203    return;
204  }
205  NSAssert([_expectedICEGatheringChanges count] > 0,
206           @"Unexpected ICE gathering state change");
207  int expectedState = [self popFirstElementAsInt:_expectedICEGatheringChanges];
208  NSAssert(expectedState == (int)newState,
209           @"ICE gathering state should match expectation");
210}
211
212- (void)peerConnection:(RTCPeerConnection*)peerConnection
213  iceConnectionChanged:(RTCICEConnectionState)newState {
214  // See TODO(fischman) in RTCPeerConnectionTest.mm about Completed.
215  if (newState == RTCICEConnectionCompleted)
216    return;
217  NSAssert([_expectedICEConnectionChanges count] > 0,
218           @"Unexpected ICE connection state change");
219  int expectedState = [self popFirstElementAsInt:_expectedICEConnectionChanges];
220  NSAssert(expectedState == (int)newState,
221           @"ICE connection state should match expectation");
222}
223
224- (void)peerConnection:(RTCPeerConnection*)peerConnection
225    didOpenDataChannel:(RTCDataChannel*)dataChannel {
226  NSString* expectedLabel =
227      [self popFirstElementAsNSString:_expectedDataChannels];
228  NSAssert([expectedLabel isEqual:dataChannel.label],
229           @"Data channel not expected");
230  self.dataChannel = dataChannel;
231  dataChannel.delegate = self;
232  NSAssert(kRTCDataChannelStateConnecting == dataChannel.state,
233           @"Unexpected state");
234}
235
236#pragma mark - RTCDataChannelDelegate
237
238- (void)channelDidChangeState:(RTCDataChannel*)channel {
239  NSAssert([_expectedStateChanges count] > 0,
240           @"Unexpected state change");
241  int expectedState = [self popFirstElementAsInt:_expectedStateChanges];
242  NSAssert(expectedState == channel.state, @"Channel state should match");
243}
244
245- (void)channel:(RTCDataChannel*)channel
246    didChangeBufferedAmount:(NSUInteger)previousAmount {
247  NSAssert(channel.bufferedAmount != previousAmount,
248           @"Invalid bufferedAmount change");
249}
250
251- (void)channel:(RTCDataChannel*)channel
252    didReceiveMessageWithBuffer:(RTCDataBuffer*)buffer {
253  NSAssert([_expectedMessages count] > 0,
254           @"Unexpected message received");
255  RTCDataBuffer* expectedBuffer = [_expectedMessages objectAtIndex:0];
256  NSAssert(expectedBuffer.isBinary == buffer.isBinary,
257           @"Buffer isBinary should match");
258  NSAssert([expectedBuffer.data isEqual:buffer.data],
259           @"Buffer data should match");
260  [_expectedMessages removeObjectAtIndex:0];
261}
262
263@end
264