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 13#include "webrtc/test/gtest.h" 14 15#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" 16#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" 17 18@interface RTCAudioSessionTestDelegate : NSObject <RTCAudioSessionDelegate> 19@end 20 21@implementation RTCAudioSessionTestDelegate 22 23- (void)audioSessionDidBeginInterruption:(RTCAudioSession *)session { 24} 25 26- (void)audioSessionDidEndInterruption:(RTCAudioSession *)session 27 shouldResumeSession:(BOOL)shouldResumeSession { 28} 29 30- (void)audioSessionDidChangeRoute:(RTCAudioSession *)session 31 reason:(AVAudioSessionRouteChangeReason)reason 32 previousRoute:(AVAudioSessionRouteDescription *)previousRoute { 33} 34 35- (void)audioSessionMediaServicesWereLost:(RTCAudioSession *)session { 36} 37 38- (void)audioSessionMediaServicesWereReset:(RTCAudioSession *)session { 39} 40 41- (void)audioSessionShouldConfigure:(RTCAudioSession *)session { 42} 43 44- (void)audioSessionShouldUnconfigure:(RTCAudioSession *)session { 45} 46 47@end 48 49// A delegate that adds itself to the audio session on init and removes itself 50// in its dealloc. 51@interface RTCTestRemoveOnDeallocDelegate : RTCAudioSessionTestDelegate 52@end 53 54@implementation RTCTestRemoveOnDeallocDelegate 55 56- (instancetype)init { 57 if (self = [super init]) { 58 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 59 [session addDelegate:self]; 60 } 61 return self; 62} 63 64- (void)dealloc { 65 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 66 [session removeDelegate:self]; 67} 68 69@end 70 71 72@interface RTCAudioSessionTest : NSObject 73 74- (void)testLockForConfiguration; 75 76@end 77 78@implementation RTCAudioSessionTest 79 80- (void)testLockForConfiguration { 81 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 82 83 for (size_t i = 0; i < 2; i++) { 84 [session lockForConfiguration]; 85 EXPECT_TRUE(session.isLocked); 86 } 87 for (size_t i = 0; i < 2; i++) { 88 EXPECT_TRUE(session.isLocked); 89 [session unlockForConfiguration]; 90 } 91 EXPECT_FALSE(session.isLocked); 92} 93 94- (void)testAddAndRemoveDelegates { 95 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 96 NSMutableArray *delegates = [NSMutableArray array]; 97 const size_t count = 5; 98 for (size_t i = 0; i < count; ++i) { 99 RTCAudioSessionTestDelegate *delegate = 100 [[RTCAudioSessionTestDelegate alloc] init]; 101 [session addDelegate:delegate]; 102 [delegates addObject:delegate]; 103 EXPECT_EQ(i + 1, session.delegates.size()); 104 } 105 [delegates enumerateObjectsUsingBlock:^(RTCAudioSessionTestDelegate *obj, 106 NSUInteger idx, 107 BOOL *stop) { 108 [session removeDelegate:obj]; 109 }]; 110 EXPECT_EQ(0u, session.delegates.size()); 111} 112 113- (void)testPushDelegate { 114 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 115 NSMutableArray *delegates = [NSMutableArray array]; 116 const size_t count = 2; 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 } 123 // Test that it gets added to the front of the list. 124 RTCAudioSessionTestDelegate *pushedDelegate = 125 [[RTCAudioSessionTestDelegate alloc] init]; 126 [session pushDelegate:pushedDelegate]; 127 EXPECT_TRUE(pushedDelegate == session.delegates[0]); 128 129 // Test that it stays at the front of the list. 130 for (size_t i = 0; i < count; ++i) { 131 RTCAudioSessionTestDelegate *delegate = 132 [[RTCAudioSessionTestDelegate alloc] init]; 133 [session addDelegate:delegate]; 134 [delegates addObject:delegate]; 135 } 136 EXPECT_TRUE(pushedDelegate == session.delegates[0]); 137 138 // Test that the next one goes to the front too. 139 pushedDelegate = [[RTCAudioSessionTestDelegate alloc] init]; 140 [session pushDelegate:pushedDelegate]; 141 EXPECT_TRUE(pushedDelegate == session.delegates[0]); 142} 143 144// Tests that delegates added to the audio session properly zero out. This is 145// checking an implementation detail (that vectors of __weak work as expected). 146- (void)testZeroingWeakDelegate { 147 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 148 @autoreleasepool { 149 // Add a delegate to the session. There should be one delegate at this 150 // point. 151 RTCAudioSessionTestDelegate *delegate = 152 [[RTCAudioSessionTestDelegate alloc] init]; 153 [session addDelegate:delegate]; 154 EXPECT_EQ(1u, session.delegates.size()); 155 EXPECT_TRUE(session.delegates[0]); 156 } 157 // The previously created delegate should've de-alloced, leaving a nil ptr. 158 EXPECT_FALSE(session.delegates[0]); 159 RTCAudioSessionTestDelegate *delegate = 160 [[RTCAudioSessionTestDelegate alloc] init]; 161 [session addDelegate:delegate]; 162 // On adding a new delegate, nil ptrs should've been cleared. 163 EXPECT_EQ(1u, session.delegates.size()); 164 EXPECT_TRUE(session.delegates[0]); 165} 166 167// Tests that we don't crash when removing delegates in dealloc. 168// Added as a regression test. 169- (void)testRemoveDelegateOnDealloc { 170 @autoreleasepool { 171 RTCTestRemoveOnDeallocDelegate *delegate = 172 [[RTCTestRemoveOnDeallocDelegate alloc] init]; 173 EXPECT_TRUE(delegate); 174 } 175 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 176 EXPECT_EQ(0u, session.delegates.size()); 177} 178 179@end 180 181namespace webrtc { 182 183class AudioSessionTest : public ::testing::Test { 184 protected: 185 void TearDown() { 186 RTCAudioSession *session = [RTCAudioSession sharedInstance]; 187 for (id<RTCAudioSessionDelegate> delegate : session.delegates) { 188 [session removeDelegate:delegate]; 189 } 190 } 191}; 192 193TEST_F(AudioSessionTest, LockForConfiguration) { 194 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; 195 [test testLockForConfiguration]; 196} 197 198TEST_F(AudioSessionTest, AddAndRemoveDelegates) { 199 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; 200 [test testAddAndRemoveDelegates]; 201} 202 203TEST_F(AudioSessionTest, PushDelegate) { 204 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; 205 [test testPushDelegate]; 206} 207 208TEST_F(AudioSessionTest, ZeroingWeakDelegate) { 209 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; 210 [test testZeroingWeakDelegate]; 211} 212 213TEST_F(AudioSessionTest, RemoveDelegateOnDealloc) { 214 RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; 215 [test testRemoveDelegateOnDealloc]; 216} 217 218} // namespace webrtc 219