blob: 58811553b3551bd8f6f8c2833ff8b281b807fcfc [file] [log] [blame]
Anders Carlsson7bca8ca2018-08-30 09:30:29 +02001/*
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 <AVFoundation/AVFoundation.h>
12#import <Foundation/Foundation.h>
13
14#import "RTCMacros.h"
15
16NS_ASSUME_NONNULL_BEGIN
17
18extern NSString *const kRTCAudioSessionErrorDomain;
19/** Method that requires lock was called without lock. */
20extern NSInteger const kRTCAudioSessionErrorLockRequired;
21/** Unknown configuration error occurred. */
22extern NSInteger const kRTCAudioSessionErrorConfiguration;
23
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020024@class RTC_OBJC_TYPE(RTCAudioSession);
25@class RTC_OBJC_TYPE(RTCAudioSessionConfiguration);
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020026
27// Surfaces AVAudioSession events. WebRTC will listen directly for notifications
28// from AVAudioSession and handle them before calling these delegate methods,
29// at which point applications can perform additional processing if required.
Mirko Bonadeie8d57242018-09-17 10:22:56 +020030RTC_OBJC_EXPORT
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020031@protocol RTC_OBJC_TYPE
32(RTCAudioSessionDelegate)<NSObject>
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020033
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020034 @optional
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020035/** Called on a system notification thread when AVAudioSession starts an
36 * interruption event.
37 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020038- (void)audioSessionDidBeginInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020039
40/** Called on a system notification thread when AVAudioSession ends an
41 * interruption event.
42 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020043- (void)audioSessionDidEndInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020044 shouldResumeSession:(BOOL)shouldResumeSession;
45
46/** Called on a system notification thread when AVAudioSession changes the
47 * route.
48 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020049- (void)audioSessionDidChangeRoute:(RTC_OBJC_TYPE(RTCAudioSession) *)session
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020050 reason:(AVAudioSessionRouteChangeReason)reason
51 previousRoute:(AVAudioSessionRouteDescription *)previousRoute;
52
53/** Called on a system notification thread when AVAudioSession media server
54 * terminates.
55 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020056- (void)audioSessionMediaServerTerminated:(RTC_OBJC_TYPE(RTCAudioSession) *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020057
58/** Called on a system notification thread when AVAudioSession media server
59 * restarts.
60 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020061- (void)audioSessionMediaServerReset:(RTC_OBJC_TYPE(RTCAudioSession) *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020062
63// TODO(tkchin): Maybe handle SilenceSecondaryAudioHintNotification.
64
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020065- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)session
66 didChangeCanPlayOrRecord:(BOOL)canPlayOrRecord;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020067
68/** Called on a WebRTC thread when the audio device is notified to begin
69 * playback or recording.
70 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020071- (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020072
73/** Called on a WebRTC thread when the audio device is notified to stop
74 * playback or recording.
75 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020076- (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020077
78/** Called when the AVAudioSession output volume value changes. */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020079- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
80 didChangeOutputVolume:(float)outputVolume;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020081
82/** Called when the audio device detects a playout glitch. The argument is the
83 * number of glitches detected so far in the current audio playout session.
84 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020085- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020086 didDetectPlayoutGlitch:(int64_t)totalNumberOfGlitches;
87
88/** Called when the audio session is about to change the active state.
89 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020090- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession willSetActive:(BOOL)active;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020091
92/** Called after the audio session sucessfully changed the active state.
93 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020094- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession didSetActive:(BOOL)active;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020095
96/** Called after the audio session failed to change the active state.
97 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +020098- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
Anders Carlsson7bca8ca2018-08-30 09:30:29 +020099 failedToSetActive:(BOOL)active
100 error:(NSError *)error;
101
102@end
103
104/** This is a protocol used to inform RTCAudioSession when the audio session
105 * activation state has changed outside of RTCAudioSession. The current known use
106 * case of this is when CallKit activates the audio session for the application
107 */
Mirko Bonadeie8d57242018-09-17 10:22:56 +0200108RTC_OBJC_EXPORT
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200109@protocol RTC_OBJC_TYPE
110(RTCAudioSessionActivationDelegate)<NSObject>
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200111
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200112 /** Called when the audio session is activated outside of the app by iOS. */
113 - (void)audioSessionDidActivate : (AVAudioSession *)session;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200114
115/** Called when the audio session is deactivated outside of the app by iOS. */
116- (void)audioSessionDidDeactivate:(AVAudioSession *)session;
117
118@end
119
120/** Proxy class for AVAudioSession that adds a locking mechanism similar to
121 * AVCaptureDevice. This is used to that interleaving configurations between
122 * WebRTC and the application layer are avoided.
123 *
124 * RTCAudioSession also coordinates activation so that the audio session is
Artem Titovcfea2182021-08-10 01:22:31 +0200125 * activated only once. See `setActive:error:`.
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200126 */
Mirko Bonadeie8d57242018-09-17 10:22:56 +0200127RTC_OBJC_EXPORT
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200128@interface RTC_OBJC_TYPE (RTCAudioSession) : NSObject <RTC_OBJC_TYPE(RTCAudioSessionActivationDelegate)>
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200129
130/** Convenience property to access the AVAudioSession singleton. Callers should
131 * not call setters on AVAudioSession directly, but other method invocations
132 * are fine.
133 */
134@property(nonatomic, readonly) AVAudioSession *session;
135
136/** Our best guess at whether the session is active based on results of calls to
137 * AVAudioSession.
138 */
139@property(nonatomic, readonly) BOOL isActive;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200140
141/** If YES, WebRTC will not initialize the audio unit automatically when an
142 * audio track is ready for playout or recording. Instead, applications should
143 * call setIsAudioEnabled. If NO, WebRTC will initialize the audio unit
144 * as soon as an audio track is ready for playout or recording.
145 */
146@property(nonatomic, assign) BOOL useManualAudio;
147
148/** This property is only effective if useManualAudio is YES.
149 * Represents permission for WebRTC to initialize the VoIP audio unit.
150 * When set to NO, if the VoIP audio unit used by WebRTC is active, it will be
151 * stopped and uninitialized. This will stop incoming and outgoing audio.
152 * When set to YES, WebRTC will initialize and start the audio unit when it is
153 * needed (e.g. due to establishing an audio connection).
154 * This property was introduced to work around an issue where if an AVPlayer is
155 * playing audio while the VoIP audio unit is initialized, its audio would be
156 * either cut off completely or played at a reduced volume. By preventing
157 * the audio unit from being initialized until after the audio has completed,
158 * we are able to prevent the abrupt cutoff.
159 */
160@property(nonatomic, assign) BOOL isAudioEnabled;
161
162// Proxy properties.
163@property(readonly) NSString *category;
164@property(readonly) AVAudioSessionCategoryOptions categoryOptions;
165@property(readonly) NSString *mode;
166@property(readonly) BOOL secondaryAudioShouldBeSilencedHint;
167@property(readonly) AVAudioSessionRouteDescription *currentRoute;
168@property(readonly) NSInteger maximumInputNumberOfChannels;
169@property(readonly) NSInteger maximumOutputNumberOfChannels;
170@property(readonly) float inputGain;
171@property(readonly) BOOL inputGainSettable;
172@property(readonly) BOOL inputAvailable;
173@property(readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *inputDataSources;
174@property(readonly, nullable) AVAudioSessionDataSourceDescription *inputDataSource;
175@property(readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *outputDataSources;
176@property(readonly, nullable) AVAudioSessionDataSourceDescription *outputDataSource;
177@property(readonly) double sampleRate;
178@property(readonly) double preferredSampleRate;
179@property(readonly) NSInteger inputNumberOfChannels;
180@property(readonly) NSInteger outputNumberOfChannels;
181@property(readonly) float outputVolume;
182@property(readonly) NSTimeInterval inputLatency;
183@property(readonly) NSTimeInterval outputLatency;
184@property(readonly) NSTimeInterval IOBufferDuration;
185@property(readonly) NSTimeInterval preferredIOBufferDuration;
186
Joe Chen0c05b1a2019-05-07 10:46:22 -0700187/**
188 When YES, calls to -setConfiguration:error: and -setConfiguration:active:error: ignore errors in
189 configuring the audio session's "preferred" attributes (e.g. preferredInputNumberOfChannels).
190 Typically, configurations to preferred attributes are optimizations, and ignoring this type of
191 configuration error allows code flow to continue along the happy path when these optimization are
192 not available. The default value of this property is NO.
193 */
194@property(nonatomic) BOOL ignoresPreferredAttributeConfigurationErrors;
195
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200196/** Default constructor. */
197+ (instancetype)sharedInstance;
198- (instancetype)init NS_UNAVAILABLE;
199
200/** Adds a delegate, which is held weakly. */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200201- (void)addDelegate:(id<RTC_OBJC_TYPE(RTCAudioSessionDelegate)>)delegate;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200202/** Removes an added delegate. */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200203- (void)removeDelegate:(id<RTC_OBJC_TYPE(RTCAudioSessionDelegate)>)delegate;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200204
205/** Request exclusive access to the audio session for configuration. This call
206 * will block if the lock is held by another object.
207 */
208- (void)lockForConfiguration;
209/** Relinquishes exclusive access to the audio session. */
210- (void)unlockForConfiguration;
211
Artem Titovd7ac5812021-07-27 12:23:39 +0200212/** If `active`, activates the audio session if it isn't already active.
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200213 * Successful calls must be balanced with a setActive:NO when activation is no
Artem Titovd7ac5812021-07-27 12:23:39 +0200214 * longer required. If not `active`, deactivates the audio session if one is
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200215 * active and this is the last balanced call. When deactivating, the
216 * AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation option is passed to
217 * AVAudioSession.
218 */
219- (BOOL)setActive:(BOOL)active error:(NSError **)outError;
220
221// The following methods are proxies for the associated methods on
Artem Titovd7ac5812021-07-27 12:23:39 +0200222// AVAudioSession. `lockForConfiguration` must be called before using them
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200223// otherwise they will fail with kRTCAudioSessionErrorLockRequired.
224
225- (BOOL)setCategory:(NSString *)category
226 withOptions:(AVAudioSessionCategoryOptions)options
227 error:(NSError **)outError;
228- (BOOL)setMode:(NSString *)mode error:(NSError **)outError;
229- (BOOL)setInputGain:(float)gain error:(NSError **)outError;
230- (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError;
231- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError **)outError;
232- (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count error:(NSError **)outError;
233- (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count error:(NSError **)outError;
234- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError **)outError;
235- (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort error:(NSError **)outError;
236- (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource
237 error:(NSError **)outError;
238- (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource
239 error:(NSError **)outError;
240@end
241
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200242@interface RTC_OBJC_TYPE (RTCAudioSession)
243(Configuration)
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200244
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200245 /** Applies the configuration to the current session. Attempts to set all
246 * properties even if previous ones fail. Only the last error will be
247 * returned.
Artem Titovd7ac5812021-07-27 12:23:39 +0200248 * `lockForConfiguration` must be called first.
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200249 */
250 - (BOOL)setConfiguration : (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration error
251 : (NSError **)outError;
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200252
253/** Convenience method that calls both setConfiguration and setActive.
Artem Titovd7ac5812021-07-27 12:23:39 +0200254 * `lockForConfiguration` must be called first.
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200255 */
Mirko Bonadeia81e9c82020-05-04 16:14:32 +0200256- (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration
Anders Carlsson7bca8ca2018-08-30 09:30:29 +0200257 active:(BOOL)active
258 error:(NSError **)outError;
259
260@end
261
262NS_ASSUME_NONNULL_END