webrtc/sdk/objc/unittests/RTCAudioSessionTest.mm
Jeremy Leconte 2e7ed0d615 Roll chromium_revision 6ac7929166..eef62e8a0c (1190797:1197906)
Change log: 6ac7929166..eef62e8a0c
Full diff: 6ac7929166..eef62e8a0c

Changed dependencies
* fuchsia_version: version:14.20230826.1.1..version:15.20230909.2.1
* reclient_version: re_client_version:0.113.0.8b45b89-gomaip..re_client_version:0.114.2.81e819b-gomaip
* src/base: 609cafa975..10140da63a
* src/build: 115a707991..c5658c73de
* src/buildtools: b2043d4f43..a567506e78
* src/buildtools/linux64: git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4..git_revision:991530ce394efb58fcd848195469022fa17ae126
* src/buildtools/mac: git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4..git_revision:991530ce394efb58fcd848195469022fa17ae126
* src/buildtools/reclient: re_client_version:0.113.0.8b45b89-gomaip..re_client_version:0.114.2.81e819b-gomaip
* src/buildtools/win: git_revision:cc56a0f98bb34accd5323316e0292575ff17a5d4..git_revision:991530ce394efb58fcd848195469022fa17ae126
* src/ios: 17864bdc8f..91328c276e
* src/testing: ff8dee88bc..ac71f97e4a
* src/third_party: ee6367daea..935018fd37
* src/third_party/android_build_tools/manifest_merger: kkbYOGsVRXhtxBiXuTufY0puTnG5QAfyxvFTBHFWL08C..FlwnxEZ1wdjoQfedkF4MiZgo8pD48-_CJNA7RnU6as4C
* src/third_party/android_toolchain/ndk: R_8suM8m0oHbZ1awdxGXvKEFpAOETscbfZxkkMthyk8C..3vHltFqfgIw8wZ38ggGM9c7Eyw_AHZnwCgFIVtc9gngC
* src/third_party/androidx: 2n47PFweHFzGxPWjh9RANTrGhmSDWowZ-YhkOV4j11MC..zIMLlRAldYvFj1UOOB-KZX_1YKfWx4vfYoCYVyF1XUsC
* src/third_party/boringssl/src: https://boringssl.googlesource.com/boringssl.git/+log/b8e012e1ff..3aecf1d00b
* src/third_party/catapult: https://chromium.googlesource.com/catapult.git/+log/b8c4f2d99a..0dfa3b81d7
* src/third_party/depot_tools: 427f0f43ad..523537049c
* src/third_party/freetype/src: dd1ced4ee3..d7b63a966b
* src/third_party/kotlin_stdlib: 6cGkpHi3fSRhpRfq2b1mjmzfFmShvtQe6gy4g2nFQd0C..7XCiIAlSi36gvPwOn8N4Q1GE9sMLw6V1RljM9151cWIC
* src/third_party/libc++/src: 84fb809dd6..7cee6b00d3
* src/third_party/libc++abi/src: 3d83ca7bd2..f6a17c88dd
* src/third_party/libunwind/src: 76e621a897..d9b4abf6b6
* src/third_party/libvpx/source/libvpx: 24c0dcc851..6da1bd01d6
* src/third_party/perfetto: 00427277dd..9a3ec114fc
* src/third_party/r8: TBaeKaSTY2ttKx2JSFuWiQ8Na80KHZwLEgSAvT1DBJ0C..WptUn43oi_BkFPtEyZTdUD9wZo1yy8OPVqFwdP3jmqoC
* src/third_party/turbine: ZlMS4BOYyYmbU8BuBDGyW7QrkvZ_-pTkm4lH4jKjTi4C..laSnfZnTgkmZynERrjAlU3yeqB5rN446BctGmKQsZ64C
* src/tools: 3e78ed797e..723bed483d
* src/tools/luci-go: git_revision:fe3cfd422b1012c2c8cf00d65cdb11aa2c26cd66..git_revision:8b73cff3b780a7136c4904103f19124d2be3dee1
* src/tools/luci-go: git_revision:fe3cfd422b1012c2c8cf00d65cdb11aa2c26cd66..git_revision:8b73cff3b780a7136c4904103f19124d2be3dee1
DEPS diff: 6ac7929166..eef62e8a0c/DEPS

Clang version changed llvmorg-17-init-16420-g0c545a44:llvmorg-18-init-4631-gd50b56d1
Details: 6ac7929166..eef62e8a0c/tools/clang/scripts/update.py

BUG=chromium:1481493,chromium:1483216,b/298960678

Change-Id: I934c827a71d332242ff182de08ba145c8eb8ec04
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/320680
Reviewed-by: Jeremy Leconte <jleconte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Jeremy Leconte <jleconte@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40767}
2023-09-19 12:06:33 +00:00

317 lines
11 KiB
Text

/*
* Copyright 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#include <vector>
#include "rtc_base/event.h"
#include "rtc_base/gunit.h"
#import "components/audio/RTCAudioSession+Private.h"
#import "components/audio/RTCAudioSession.h"
#import "components/audio/RTCAudioSessionConfiguration.h"
@interface RTC_OBJC_TYPE (RTCAudioSession)
(UnitTesting)
@property(nonatomic,
readonly) std::vector<__weak id<RTC_OBJC_TYPE(RTCAudioSessionDelegate)> > delegates;
- (instancetype)initWithAudioSession:(id)audioSession;
@end
@interface MockAVAudioSession : NSObject
@property (nonatomic, readwrite, assign) float outputVolume;
@end
@implementation MockAVAudioSession
@synthesize outputVolume = _outputVolume;
@end
@interface RTCAudioSessionTestDelegate : NSObject <RTC_OBJC_TYPE (RTCAudioSessionDelegate)>
@property (nonatomic, readonly) float outputVolume;
@end
@implementation RTCAudioSessionTestDelegate
@synthesize outputVolume = _outputVolume;
- (instancetype)init {
if (self = [super init]) {
_outputVolume = -1;
}
return self;
}
- (void)audioSessionDidBeginInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
}
- (void)audioSessionDidEndInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session
shouldResumeSession:(BOOL)shouldResumeSession {
}
- (void)audioSessionDidChangeRoute:(RTC_OBJC_TYPE(RTCAudioSession) *)session
reason:(AVAudioSessionRouteChangeReason)reason
previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
}
- (void)audioSessionMediaServerTerminated:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
}
- (void)audioSessionMediaServerReset:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
}
- (void)audioSessionShouldConfigure:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
}
- (void)audioSessionShouldUnconfigure:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
}
- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
didChangeOutputVolume:(float)outputVolume {
_outputVolume = outputVolume;
}
@end
// A delegate that adds itself to the audio session on init and removes itself
// in its dealloc.
@interface RTCTestRemoveOnDeallocDelegate : RTCAudioSessionTestDelegate
@end
@implementation RTCTestRemoveOnDeallocDelegate
- (instancetype)init {
if (self = [super init]) {
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
[session addDelegate:self];
}
return self;
}
- (void)dealloc {
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
[session removeDelegate:self];
}
@end
@interface RTCAudioSessionTest : XCTestCase
@end
@implementation RTCAudioSessionTest
- (void)testAddAndRemoveDelegates {
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
NSMutableArray *delegates = [NSMutableArray array];
const size_t count = 5;
for (size_t i = 0; i < count; ++i) {
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
[delegates addObject:delegate];
EXPECT_EQ(i + 1, session.delegates.size());
}
[delegates enumerateObjectsUsingBlock:^(RTCAudioSessionTestDelegate *obj,
NSUInteger idx,
BOOL *stop) {
[session removeDelegate:obj];
}];
EXPECT_EQ(0u, session.delegates.size());
}
- (void)testPushDelegate {
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
NSMutableArray *delegates = [NSMutableArray array];
const size_t count = 2;
for (size_t i = 0; i < count; ++i) {
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
[delegates addObject:delegate];
}
// Test that it gets added to the front of the list.
RTCAudioSessionTestDelegate *pushedDelegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session pushDelegate:pushedDelegate];
EXPECT_TRUE(pushedDelegate == session.delegates[0]);
// Test that it stays at the front of the list.
for (size_t i = 0; i < count; ++i) {
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
[delegates addObject:delegate];
}
EXPECT_TRUE(pushedDelegate == session.delegates[0]);
// Test that the next one goes to the front too.
pushedDelegate = [[RTCAudioSessionTestDelegate alloc] init];
[session pushDelegate:pushedDelegate];
EXPECT_TRUE(pushedDelegate == session.delegates[0]);
}
// Tests that delegates added to the audio session properly zero out. This is
// checking an implementation detail (that vectors of __weak work as expected).
- (void)testZeroingWeakDelegate {
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
@autoreleasepool {
// Add a delegate to the session. There should be one delegate at this
// point.
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
EXPECT_EQ(1u, session.delegates.size());
EXPECT_TRUE(session.delegates[0]);
}
// The previously created delegate should've de-alloced, leaving a nil ptr.
EXPECT_FALSE(session.delegates[0]);
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
// On adding a new delegate, nil ptrs should've been cleared.
EXPECT_EQ(1u, session.delegates.size());
EXPECT_TRUE(session.delegates[0]);
}
// Tests that we don't crash when removing delegates in dealloc.
// Added as a regression test.
- (void)testRemoveDelegateOnDealloc {
@autoreleasepool {
RTCTestRemoveOnDeallocDelegate *delegate =
[[RTCTestRemoveOnDeallocDelegate alloc] init];
EXPECT_TRUE(delegate);
}
RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
EXPECT_EQ(0u, session.delegates.size());
}
- (void)testAudioSessionActivation {
RTC_OBJC_TYPE(RTCAudioSession) *audioSession = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
EXPECT_EQ(0, audioSession.activationCount);
[audioSession audioSessionDidActivate:[AVAudioSession sharedInstance]];
EXPECT_EQ(1, audioSession.activationCount);
[audioSession audioSessionDidDeactivate:[AVAudioSession sharedInstance]];
EXPECT_EQ(0, audioSession.activationCount);
}
// TODO(b/298960678): Fix crash when running the test on simulators.
- (void)DISABLED_testConfigureWebRTCSession {
NSError *error = nil;
void (^setActiveBlock)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
__autoreleasing NSError **retError;
[invocation getArgument:&retError atIndex:4];
*retError = [NSError errorWithDomain:@"AVAudioSession"
code:AVAudioSessionErrorCodeCannotInterruptOthers
userInfo:nil];
BOOL failure = NO;
[invocation setReturnValue:&failure];
};
id mockAVAudioSession = OCMPartialMock([AVAudioSession sharedInstance]);
OCMStub([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES
withOptions:0
error:([OCMArg anyObjectRef])])
.andDo(setActiveBlock);
id mockAudioSession = OCMPartialMock([RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]);
OCMStub([mockAudioSession session]).andReturn(mockAVAudioSession);
RTC_OBJC_TYPE(RTCAudioSession) *audioSession = mockAudioSession;
EXPECT_EQ(0, audioSession.activationCount);
[audioSession lockForConfiguration];
// configureWebRTCSession is forced to fail in the above mock interface,
// so activationCount should remain 0
OCMExpect([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES
withOptions:0
error:([OCMArg anyObjectRef])])
.andDo(setActiveBlock);
OCMExpect([mockAudioSession session]).andReturn(mockAVAudioSession);
EXPECT_FALSE([audioSession configureWebRTCSession:&error]);
EXPECT_EQ(0, audioSession.activationCount);
id session = audioSession.session;
EXPECT_EQ(session, mockAVAudioSession);
EXPECT_EQ(NO, [mockAVAudioSession setActive:YES withOptions:0 error:&error]);
[audioSession unlockForConfiguration];
// The -Wunused-value is a workaround for https://bugs.llvm.org/show_bug.cgi?id=45245
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-value\"");
OCMVerify([mockAudioSession session]);
OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES withOptions:0 error:&error]);
OCMVerify([[mockAVAudioSession ignoringNonObjectArgs] setActive:NO withOptions:0 error:&error]);
_Pragma("clang diagnostic pop");
[mockAVAudioSession stopMocking];
[mockAudioSession stopMocking];
}
// TODO(b/298960678): Fix crash when running the test on simulators.
- (void)DISABLED_testConfigureWebRTCSessionWithoutLocking {
NSError *error = nil;
id mockAVAudioSession = OCMPartialMock([AVAudioSession sharedInstance]);
id mockAudioSession = OCMPartialMock([RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]);
OCMStub([mockAudioSession session]).andReturn(mockAVAudioSession);
RTC_OBJC_TYPE(RTCAudioSession) *audioSession = mockAudioSession;
std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
EXPECT_TRUE(thread);
EXPECT_TRUE(thread->Start());
rtc::Event waitLock;
rtc::Event waitCleanup;
constexpr webrtc::TimeDelta timeout = webrtc::TimeDelta::Seconds(5);
thread->PostTask([audioSession, &waitLock, &waitCleanup, timeout] {
[audioSession lockForConfiguration];
waitLock.Set();
waitCleanup.Wait(timeout);
[audioSession unlockForConfiguration];
});
waitLock.Wait(timeout);
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:0 error:&error];
EXPECT_TRUE(error != nil);
EXPECT_EQ(error.domain, kRTCAudioSessionErrorDomain);
EXPECT_EQ(error.code, kRTCAudioSessionErrorLockRequired);
waitCleanup.Set();
thread->Stop();
[mockAVAudioSession stopMocking];
[mockAudioSession stopMocking];
}
- (void)testAudioVolumeDidNotify {
MockAVAudioSession *mockAVAudioSession = [[MockAVAudioSession alloc] init];
RTC_OBJC_TYPE(RTCAudioSession) *session =
[[RTC_OBJC_TYPE(RTCAudioSession) alloc] initWithAudioSession:mockAVAudioSession];
RTCAudioSessionTestDelegate *delegate =
[[RTCAudioSessionTestDelegate alloc] init];
[session addDelegate:delegate];
float expectedVolume = 0.75;
mockAVAudioSession.outputVolume = expectedVolume;
EXPECT_EQ(expectedVolume, delegate.outputVolume);
}
@end