blob: fa99d9038defdc2c2f2d8ad914cacb687a4c6f27 [file] [log] [blame]
Peter Hanspers8d95e3b2018-05-15 10:22:36 +02001/*
2 * Copyright 2018 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 <XCTest/XCTest.h>
12#import "sdk/objc/Framework/Native/src/audio/audio_device_ios.h"
13#import "sdk/objc/Framework/Native/api/audio_device_module.h"
14#import "sdk/objc/Framework/Classes/Audio/RTCAudioSession+Private.h"
15
16@interface RTCAudioDeviceTests: XCTestCase {
17 rtc::scoped_refptr<webrtc::AudioDeviceModule> _audioDeviceModule;
18 std::unique_ptr<webrtc::ios_adm::AudioDeviceIOS> _audio_device;
19}
20
21@property(nonatomic) RTCAudioSession *audioSession;
22
23@end
24
25@implementation RTCAudioDeviceTests
26
27@synthesize audioSession = _audioSession;
28
29- (void)setUp {
30 [super setUp];
31
32 _audioDeviceModule = webrtc::CreateAudioDeviceModule();
33 _audio_device.reset(new webrtc::ios_adm::AudioDeviceIOS());
34 self.audioSession = [RTCAudioSession sharedInstance];
35
36 NSError *error = nil;
37 [self.audioSession lockForConfiguration];
38 [self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
39 withOptions:0
40 error:&error];
41 XCTAssertNil(error);
42
43 [self.audioSession setMode:AVAudioSessionModeVoiceChat error:&error];
44 XCTAssertNil(error);
45
46 [self.audioSession setActive:YES error:&error];
47 XCTAssertNil(error);
48
49 [self.audioSession unlockForConfiguration];
50}
51
52- (void)tearDown {
53 _audio_device->Terminate();
54 _audio_device.reset(nullptr);
55 _audioDeviceModule = nullptr;
56 [self.audioSession notifyDidEndInterruptionWithShouldResumeSession:NO];
57
58 [super tearDown];
59}
60
61// Verifies that the AudioDeviceIOS is_interrupted_ flag is reset correctly
62// after an iOS AVAudioSessionInterruptionTypeEnded notification event.
63// AudioDeviceIOS listens to RTCAudioSession interrupted notifications by:
64// - In AudioDeviceIOS.InitPlayOrRecord registers its audio_session_observer_
65// callback with RTCAudioSession's delegate list.
66// - When RTCAudioSession receives an iOS audio interrupted notification, it
67// passes the notification to callbacks in its delegate list which sets
68// AudioDeviceIOS's is_interrupted_ flag to true.
69// - When AudioDeviceIOS.ShutdownPlayOrRecord is called, its
70// audio_session_observer_ callback is removed from RTCAudioSessions's
71// delegate list.
72// So if RTCAudioSession receives an iOS end audio interruption notification,
73// AudioDeviceIOS is not notified as its callback is not in RTCAudioSession's
74// delegate list. This causes AudioDeviceIOS's is_interrupted_ flag to be in
75// the wrong (true) state and the audio session will ignore audio changes.
76// As RTCAudioSession keeps its own interrupted state, the fix is to initialize
77// AudioDeviceIOS's is_interrupted_ flag to RTCAudioSession's isInterrupted
78// flag in AudioDeviceIOS.InitPlayOrRecord.
79- (void)testInterruptedAudioSession {
80 XCTAssertTrue(self.audioSession.isActive);
81 XCTAssertTrue([self.audioSession.category isEqual:AVAudioSessionCategoryPlayAndRecord] ||
82 [self.audioSession.category isEqual:AVAudioSessionCategoryPlayback]);
83 XCTAssertEqual(AVAudioSessionModeVoiceChat, self.audioSession.mode);
84
85 std::unique_ptr<webrtc::AudioDeviceBuffer> audio_buffer;
86 audio_buffer.reset(new webrtc::AudioDeviceBuffer());
87 _audio_device->AttachAudioBuffer(audio_buffer.get());
88 XCTAssertEqual(webrtc::AudioDeviceGeneric::InitStatus::OK, _audio_device->Init());
89 XCTAssertEqual(0, _audio_device->InitPlayout());
90 XCTAssertEqual(0, _audio_device->StartPlayout());
91
92 // Force interruption.
93 [self.audioSession notifyDidBeginInterruption];
94
95 // Wait for notification to propagate.
96 rtc::MessageQueueManager::ProcessAllMessageQueues();
97 XCTAssertTrue(_audio_device->IsInterrupted());
98
99 // Force it for testing.
100 _audio_device->StopPlayout();
101
102 [self.audioSession notifyDidEndInterruptionWithShouldResumeSession:YES];
103 // Wait for notification to propagate.
104 rtc::MessageQueueManager::ProcessAllMessageQueues();
105 XCTAssertTrue(_audio_device->IsInterrupted());
106
107 _audio_device->Init();
108 _audio_device->InitPlayout();
109 XCTAssertFalse(_audio_device->IsInterrupted());
110}
111
112@end