| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2016 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 <Foundation/Foundation.h> | |
| 12 #import <OCMock/OCMock.h> | |
| 13 | |
| 14 #include "webrtc/test/gtest.h" | |
| 15 | |
| 16 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" | |
| 17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" | |
| 18 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h" | |
| 19 | |
| 20 @interface RTCAudioSessionTestDelegate : NSObject <RTCAudioSessionDelegate> | |
| 21 | |
| 22 @property (nonatomic, readonly) float outputVolume; | |
| 23 | |
| 24 @end | |
| 25 | |
| 26 @implementation RTCAudioSessionTestDelegate | |
| 27 | |
| 28 @synthesize outputVolume = _outputVolume; | |
| 29 | |
| 30 - (instancetype)init { | |
| 31 if (self = [super init]) { | |
| 32 _outputVolume = -1; | |
| 33 } | |
| 34 return self; | |
| 35 } | |
| 36 | |
| 37 - (void)audioSessionDidBeginInterruption:(RTCAudioSession *)session { | |
| 38 } | |
| 39 | |
| 40 - (void)audioSessionDidEndInterruption:(RTCAudioSession *)session | |
| 41 shouldResumeSession:(BOOL)shouldResumeSession { | |
| 42 } | |
| 43 | |
| 44 - (void)audioSessionDidChangeRoute:(RTCAudioSession *)session | |
| 45 reason:(AVAudioSessionRouteChangeReason)reason | |
| 46 previousRoute:(AVAudioSessionRouteDescription *)previousRoute { | |
| 47 } | |
| 48 | |
| 49 - (void)audioSessionMediaServerTerminated:(RTCAudioSession *)session { | |
| 50 } | |
| 51 | |
| 52 - (void)audioSessionMediaServerReset:(RTCAudioSession *)session { | |
| 53 } | |
| 54 | |
| 55 - (void)audioSessionShouldConfigure:(RTCAudioSession *)session { | |
| 56 } | |
| 57 | |
| 58 - (void)audioSessionShouldUnconfigure:(RTCAudioSession *)session { | |
| 59 } | |
| 60 | |
| 61 - (void)audioSession:(RTCAudioSession *)audioSession | |
| 62 didChangeOutputVolume:(float)outputVolume { | |
| 63 _outputVolume = outputVolume; | |
| 64 } | |
| 65 | |
| 66 @end | |
| 67 | |
| 68 // A delegate that adds itself to the audio session on init and removes itself | |
| 69 // in its dealloc. | |
| 70 @interface RTCTestRemoveOnDeallocDelegate : RTCAudioSessionTestDelegate | |
| 71 @end | |
| 72 | |
| 73 @implementation RTCTestRemoveOnDeallocDelegate | |
| 74 | |
| 75 - (instancetype)init { | |
| 76 if (self = [super init]) { | |
| 77 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 78 [session addDelegate:self]; | |
| 79 } | |
| 80 return self; | |
| 81 } | |
| 82 | |
| 83 - (void)dealloc { | |
| 84 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 85 [session removeDelegate:self]; | |
| 86 } | |
| 87 | |
| 88 @end | |
| 89 | |
| 90 | |
| 91 @interface RTCAudioSessionTest : NSObject | |
| 92 | |
| 93 - (void)testLockForConfiguration; | |
| 94 | |
| 95 @end | |
| 96 | |
| 97 @implementation RTCAudioSessionTest | |
| 98 | |
| 99 - (void)testLockForConfiguration { | |
| 100 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 101 | |
| 102 for (size_t i = 0; i < 2; i++) { | |
| 103 [session lockForConfiguration]; | |
| 104 EXPECT_TRUE(session.isLocked); | |
| 105 } | |
| 106 for (size_t i = 0; i < 2; i++) { | |
| 107 EXPECT_TRUE(session.isLocked); | |
| 108 [session unlockForConfiguration]; | |
| 109 } | |
| 110 EXPECT_FALSE(session.isLocked); | |
| 111 } | |
| 112 | |
| 113 - (void)testAddAndRemoveDelegates { | |
| 114 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 115 NSMutableArray *delegates = [NSMutableArray array]; | |
| 116 const size_t count = 5; | |
| 117 for (size_t i = 0; i < count; ++i) { | |
| 118 RTCAudioSessionTestDelegate *delegate = | |
| 119 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 120 [session addDelegate:delegate]; | |
| 121 [delegates addObject:delegate]; | |
| 122 EXPECT_EQ(i + 1, session.delegates.size()); | |
| 123 } | |
| 124 [delegates enumerateObjectsUsingBlock:^(RTCAudioSessionTestDelegate *obj, | |
| 125 NSUInteger idx, | |
| 126 BOOL *stop) { | |
| 127 [session removeDelegate:obj]; | |
| 128 }]; | |
| 129 EXPECT_EQ(0u, session.delegates.size()); | |
| 130 } | |
| 131 | |
| 132 - (void)testPushDelegate { | |
| 133 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 134 NSMutableArray *delegates = [NSMutableArray array]; | |
| 135 const size_t count = 2; | |
| 136 for (size_t i = 0; i < count; ++i) { | |
| 137 RTCAudioSessionTestDelegate *delegate = | |
| 138 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 139 [session addDelegate:delegate]; | |
| 140 [delegates addObject:delegate]; | |
| 141 } | |
| 142 // Test that it gets added to the front of the list. | |
| 143 RTCAudioSessionTestDelegate *pushedDelegate = | |
| 144 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 145 [session pushDelegate:pushedDelegate]; | |
| 146 EXPECT_TRUE(pushedDelegate == session.delegates[0]); | |
| 147 | |
| 148 // Test that it stays at the front of the list. | |
| 149 for (size_t i = 0; i < count; ++i) { | |
| 150 RTCAudioSessionTestDelegate *delegate = | |
| 151 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 152 [session addDelegate:delegate]; | |
| 153 [delegates addObject:delegate]; | |
| 154 } | |
| 155 EXPECT_TRUE(pushedDelegate == session.delegates[0]); | |
| 156 | |
| 157 // Test that the next one goes to the front too. | |
| 158 pushedDelegate = [[RTCAudioSessionTestDelegate alloc] init]; | |
| 159 [session pushDelegate:pushedDelegate]; | |
| 160 EXPECT_TRUE(pushedDelegate == session.delegates[0]); | |
| 161 } | |
| 162 | |
| 163 // Tests that delegates added to the audio session properly zero out. This is | |
| 164 // checking an implementation detail (that vectors of __weak work as expected). | |
| 165 - (void)testZeroingWeakDelegate { | |
| 166 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 167 @autoreleasepool { | |
| 168 // Add a delegate to the session. There should be one delegate at this | |
| 169 // point. | |
| 170 RTCAudioSessionTestDelegate *delegate = | |
| 171 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 172 [session addDelegate:delegate]; | |
| 173 EXPECT_EQ(1u, session.delegates.size()); | |
| 174 EXPECT_TRUE(session.delegates[0]); | |
| 175 } | |
| 176 // The previously created delegate should've de-alloced, leaving a nil ptr. | |
| 177 EXPECT_FALSE(session.delegates[0]); | |
| 178 RTCAudioSessionTestDelegate *delegate = | |
| 179 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 180 [session addDelegate:delegate]; | |
| 181 // On adding a new delegate, nil ptrs should've been cleared. | |
| 182 EXPECT_EQ(1u, session.delegates.size()); | |
| 183 EXPECT_TRUE(session.delegates[0]); | |
| 184 } | |
| 185 | |
| 186 // Tests that we don't crash when removing delegates in dealloc. | |
| 187 // Added as a regression test. | |
| 188 - (void)testRemoveDelegateOnDealloc { | |
| 189 @autoreleasepool { | |
| 190 RTCTestRemoveOnDeallocDelegate *delegate = | |
| 191 [[RTCTestRemoveOnDeallocDelegate alloc] init]; | |
| 192 EXPECT_TRUE(delegate); | |
| 193 } | |
| 194 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 195 EXPECT_EQ(0u, session.delegates.size()); | |
| 196 } | |
| 197 | |
| 198 - (void)testAudioSessionActivation { | |
| 199 RTCAudioSession *audioSession = [RTCAudioSession sharedInstance]; | |
| 200 EXPECT_EQ(0, audioSession.activationCount); | |
| 201 [audioSession audioSessionDidActivate:[AVAudioSession sharedInstance]]; | |
| 202 EXPECT_EQ(1, audioSession.activationCount); | |
| 203 [audioSession audioSessionDidDeactivate:[AVAudioSession sharedInstance]]; | |
| 204 EXPECT_EQ(0, audioSession.activationCount); | |
| 205 } | |
| 206 | |
| 207 // Hack - fixes OCMVerify link error | |
| 208 // Link error is: Undefined symbols for architecture i386: | |
| 209 // "OCMMakeLocation(objc_object*, char const*, int)", referenced from: | |
| 210 // -[RTCAudioSessionTest testConfigureWebRTCSession] in RTCAudioSessionTest.o | |
| 211 // ld: symbol(s) not found for architecture i386 | |
| 212 // REASON: https://github.com/erikdoe/ocmock/issues/238 | |
| 213 OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){ | |
| 214 return [OCMLocation locationWithTestCase:testCase | |
| 215 file:[NSString stringWithUTF8String:fileCS
tring] | |
| 216 line:line]; | |
| 217 } | |
| 218 | |
| 219 - (void)testConfigureWebRTCSession { | |
| 220 NSError *error = nil; | |
| 221 | |
| 222 void (^setActiveBlock)(NSInvocation *invocation) = ^(NSInvocation *invocation)
{ | |
| 223 __autoreleasing NSError **retError; | |
| 224 [invocation getArgument:&retError atIndex:4]; | |
| 225 *retError = [NSError errorWithDomain:@"AVAudioSession" | |
| 226 code:AVAudioSessionErrorInsufficientPriority | |
| 227 userInfo:nil]; | |
| 228 BOOL failure = NO; | |
| 229 [invocation setReturnValue:&failure]; | |
| 230 }; | |
| 231 | |
| 232 id mockAVAudioSession = OCMPartialMock([AVAudioSession sharedInstance]); | |
| 233 OCMStub([[mockAVAudioSession ignoringNonObjectArgs] | |
| 234 setActive:YES withOptions:0 error:((NSError __autoreleasing **)[OCMArg any
Pointer])]). | |
| 235 andDo(setActiveBlock); | |
| 236 | |
| 237 id mockAudioSession = OCMPartialMock([RTCAudioSession sharedInstance]); | |
| 238 OCMStub([mockAudioSession session]).andReturn(mockAVAudioSession); | |
| 239 | |
| 240 RTCAudioSession *audioSession = mockAudioSession; | |
| 241 EXPECT_EQ(0, audioSession.activationCount); | |
| 242 [audioSession lockForConfiguration]; | |
| 243 EXPECT_TRUE([audioSession checkLock:nil]); | |
| 244 // configureWebRTCSession is forced to fail in the above mock interface, | |
| 245 // so activationCount should remain 0 | |
| 246 OCMExpect([[mockAVAudioSession ignoringNonObjectArgs] | |
| 247 setActive:YES withOptions:0 error:((NSError __autoreleasing **)[OCMArg any
Pointer])]). | |
| 248 andDo(setActiveBlock); | |
| 249 OCMExpect([mockAudioSession session]).andReturn(mockAVAudioSession); | |
| 250 EXPECT_FALSE([audioSession configureWebRTCSession:&error]); | |
| 251 EXPECT_EQ(0, audioSession.activationCount); | |
| 252 | |
| 253 id session = audioSession.session; | |
| 254 EXPECT_EQ(session, mockAVAudioSession); | |
| 255 EXPECT_EQ(NO, [mockAVAudioSession setActive:YES withOptions:0 error:&error]); | |
| 256 [audioSession unlockForConfiguration]; | |
| 257 | |
| 258 OCMVerify([mockAudioSession session]); | |
| 259 OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES withOption
s:0 error:&error]); | |
| 260 OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:NO withOptions
:0 error:&error]); | |
| 261 | |
| 262 [mockAVAudioSession stopMocking]; | |
| 263 [mockAudioSession stopMocking]; | |
| 264 } | |
| 265 | |
| 266 - (void)testAudioVolumeDidNotify { | |
| 267 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 268 RTCAudioSessionTestDelegate *delegate = | |
| 269 [[RTCAudioSessionTestDelegate alloc] init]; | |
| 270 [session addDelegate:delegate]; | |
| 271 | |
| 272 [session observeValueForKeyPath:@"outputVolume" | |
| 273 ofObject:[AVAudioSession sharedInstance] | |
| 274 change: | |
| 275 @{NSKeyValueChangeNewKey : | |
| 276 @([AVAudioSession sharedInstance].outputVolume) } | |
| 277 context:nil]; | |
| 278 | |
| 279 EXPECT_NE(delegate.outputVolume, -1); | |
| 280 EXPECT_EQ([AVAudioSession sharedInstance].outputVolume, delegate.outputVolume)
; | |
| 281 } | |
| 282 | |
| 283 @end | |
| 284 | |
| 285 namespace webrtc { | |
| 286 | |
| 287 class AudioSessionTest : public ::testing::Test { | |
| 288 protected: | |
| 289 void TearDown() { | |
| 290 RTCAudioSession *session = [RTCAudioSession sharedInstance]; | |
| 291 for (id<RTCAudioSessionDelegate> delegate : session.delegates) { | |
| 292 [session removeDelegate:delegate]; | |
| 293 } | |
| 294 } | |
| 295 }; | |
| 296 | |
| 297 TEST_F(AudioSessionTest, LockForConfiguration) { | |
| 298 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 299 [test testLockForConfiguration]; | |
| 300 } | |
| 301 | |
| 302 TEST_F(AudioSessionTest, AddAndRemoveDelegates) { | |
| 303 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 304 [test testAddAndRemoveDelegates]; | |
| 305 } | |
| 306 | |
| 307 TEST_F(AudioSessionTest, PushDelegate) { | |
| 308 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 309 [test testPushDelegate]; | |
| 310 } | |
| 311 | |
| 312 TEST_F(AudioSessionTest, ZeroingWeakDelegate) { | |
| 313 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 314 [test testZeroingWeakDelegate]; | |
| 315 } | |
| 316 | |
| 317 TEST_F(AudioSessionTest, RemoveDelegateOnDealloc) { | |
| 318 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 319 [test testRemoveDelegateOnDealloc]; | |
| 320 } | |
| 321 | |
| 322 TEST_F(AudioSessionTest, AudioSessionActivation) { | |
| 323 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 324 [test testAudioSessionActivation]; | |
| 325 } | |
| 326 | |
| 327 TEST_F(AudioSessionTest, ConfigureWebRTCSession) { | |
| 328 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 329 [test testConfigureWebRTCSession]; | |
| 330 } | |
| 331 | |
| 332 TEST_F(AudioSessionTest, AudioVolumeDidNotify) { | |
| 333 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; | |
| 334 [test testAudioVolumeDidNotify]; | |
| 335 } | |
| 336 | |
| 337 } // namespace webrtc | |
| OLD | NEW |