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