xref: /aosp_15_r20/external/webrtc/sdk/objc/unittests/RTCAudioSessionTest.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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