1 /* 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 16 NS_ASSUME_NONNULL_BEGIN 17 18 extern NSString *const kRTCAudioSessionErrorDomain; 19 /** Method that requires lock was called without lock. */ 20 extern NSInteger const kRTCAudioSessionErrorLockRequired; 21 /** Unknown configuration error occurred. */ 22 extern NSInteger const kRTCAudioSessionErrorConfiguration; 23 24 @class RTC_OBJC_TYPE(RTCAudioSession); 25 @class RTC_OBJC_TYPE(RTCAudioSessionConfiguration); 26 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. 30 RTC_OBJC_EXPORT 31 @protocol RTC_OBJC_TYPE 32 (RTCAudioSessionDelegate)<NSObject> 33 34 @optional 35 /** Called on a system notification thread when AVAudioSession starts an 36 * interruption event. 37 */ 38 - (void)audioSessionDidBeginInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session; 39 40 /** Called on a system notification thread when AVAudioSession ends an 41 * interruption event. 42 */ 43 - (void)audioSessionDidEndInterruption:(RTC_OBJC_TYPE(RTCAudioSession) *)session 44 shouldResumeSession:(BOOL)shouldResumeSession; 45 46 /** Called on a system notification thread when AVAudioSession changes the 47 * route. 48 */ 49 - (void)audioSessionDidChangeRoute:(RTC_OBJC_TYPE(RTCAudioSession) *)session 50 reason:(AVAudioSessionRouteChangeReason)reason 51 previousRoute:(AVAudioSessionRouteDescription *)previousRoute; 52 53 /** Called on a system notification thread when AVAudioSession media server 54 * terminates. 55 */ 56 - (void)audioSessionMediaServerTerminated:(RTC_OBJC_TYPE(RTCAudioSession) *)session; 57 58 /** Called on a system notification thread when AVAudioSession media server 59 * restarts. 60 */ 61 - (void)audioSessionMediaServerReset:(RTC_OBJC_TYPE(RTCAudioSession) *)session; 62 63 // TODO(tkchin): Maybe handle SilenceSecondaryAudioHintNotification. 64 65 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)session 66 didChangeCanPlayOrRecord:(BOOL)canPlayOrRecord; 67 68 /** Called on a WebRTC thread when the audio device is notified to begin 69 * playback or recording. 70 */ 71 - (void)audioSessionDidStartPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session; 72 73 /** Called on a WebRTC thread when the audio device is notified to stop 74 * playback or recording. 75 */ 76 - (void)audioSessionDidStopPlayOrRecord:(RTC_OBJC_TYPE(RTCAudioSession) *)session; 77 78 /** Called when the AVAudioSession output volume value changes. */ 79 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 80 didChangeOutputVolume:(float)outputVolume; 81 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 */ 85 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 86 didDetectPlayoutGlitch:(int64_t)totalNumberOfGlitches; 87 88 /** Called when the audio session is about to change the active state. 89 */ 90 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession willSetActive:(BOOL)active; 91 92 /** Called after the audio session sucessfully changed the active state. 93 */ 94 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession didSetActive:(BOOL)active; 95 96 /** Called after the audio session failed to change the active state. 97 */ 98 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 99 failedToSetActive:(BOOL)active 100 error:(NSError *)error; 101 102 - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession 103 audioUnitStartFailedWithError:(NSError *)error; 104 105 @end 106 107 /** This is a protocol used to inform RTCAudioSession when the audio session 108 * activation state has changed outside of RTCAudioSession. The current known use 109 * case of this is when CallKit activates the audio session for the application 110 */ 111 RTC_OBJC_EXPORT 112 @protocol RTC_OBJC_TYPE 113 (RTCAudioSessionActivationDelegate)<NSObject> 114 115 /** Called when the audio session is activated outside of the app by iOS. */ 116 - (void)audioSessionDidActivate : (AVAudioSession *)session; 117 118 /** Called when the audio session is deactivated outside of the app by iOS. */ 119 - (void)audioSessionDidDeactivate:(AVAudioSession *)session; 120 121 @end 122 123 /** Proxy class for AVAudioSession that adds a locking mechanism similar to 124 * AVCaptureDevice. This is used to that interleaving configurations between 125 * WebRTC and the application layer are avoided. 126 * 127 * RTCAudioSession also coordinates activation so that the audio session is 128 * activated only once. See `setActive:error:`. 129 */ 130 RTC_OBJC_EXPORT 131 @interface RTC_OBJC_TYPE (RTCAudioSession) : NSObject <RTC_OBJC_TYPE(RTCAudioSessionActivationDelegate)> 132 133 /** Convenience property to access the AVAudioSession singleton. Callers should 134 * not call setters on AVAudioSession directly, but other method invocations 135 * are fine. 136 */ 137 @property(nonatomic, readonly) AVAudioSession *session; 138 139 /** Our best guess at whether the session is active based on results of calls to 140 * AVAudioSession. 141 */ 142 @property(nonatomic, readonly) BOOL isActive; 143 144 /** If YES, WebRTC will not initialize the audio unit automatically when an 145 * audio track is ready for playout or recording. Instead, applications should 146 * call setIsAudioEnabled. If NO, WebRTC will initialize the audio unit 147 * as soon as an audio track is ready for playout or recording. 148 */ 149 @property(nonatomic, assign) BOOL useManualAudio; 150 151 /** This property is only effective if useManualAudio is YES. 152 * Represents permission for WebRTC to initialize the VoIP audio unit. 153 * When set to NO, if the VoIP audio unit used by WebRTC is active, it will be 154 * stopped and uninitialized. This will stop incoming and outgoing audio. 155 * When set to YES, WebRTC will initialize and start the audio unit when it is 156 * needed (e.g. due to establishing an audio connection). 157 * This property was introduced to work around an issue where if an AVPlayer is 158 * playing audio while the VoIP audio unit is initialized, its audio would be 159 * either cut off completely or played at a reduced volume. By preventing 160 * the audio unit from being initialized until after the audio has completed, 161 * we are able to prevent the abrupt cutoff. 162 */ 163 @property(nonatomic, assign) BOOL isAudioEnabled; 164 165 // Proxy properties. 166 @property(readonly) NSString *category; 167 @property(readonly) AVAudioSessionCategoryOptions categoryOptions; 168 @property(readonly) NSString *mode; 169 @property(readonly) BOOL secondaryAudioShouldBeSilencedHint; 170 @property(readonly) AVAudioSessionRouteDescription *currentRoute; 171 @property(readonly) NSInteger maximumInputNumberOfChannels; 172 @property(readonly) NSInteger maximumOutputNumberOfChannels; 173 @property(readonly) float inputGain; 174 @property(readonly) BOOL inputGainSettable; 175 @property(readonly) BOOL inputAvailable; 176 @property(readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *inputDataSources; 177 @property(readonly, nullable) AVAudioSessionDataSourceDescription *inputDataSource; 178 @property(readonly, nullable) NSArray<AVAudioSessionDataSourceDescription *> *outputDataSources; 179 @property(readonly, nullable) AVAudioSessionDataSourceDescription *outputDataSource; 180 @property(readonly) double sampleRate; 181 @property(readonly) double preferredSampleRate; 182 @property(readonly) NSInteger inputNumberOfChannels; 183 @property(readonly) NSInteger outputNumberOfChannels; 184 @property(readonly) float outputVolume; 185 @property(readonly) NSTimeInterval inputLatency; 186 @property(readonly) NSTimeInterval outputLatency; 187 @property(readonly) NSTimeInterval IOBufferDuration; 188 @property(readonly) NSTimeInterval preferredIOBufferDuration; 189 190 /** 191 When YES, calls to -setConfiguration:error: and -setConfiguration:active:error: ignore errors in 192 configuring the audio session's "preferred" attributes (e.g. preferredInputNumberOfChannels). 193 Typically, configurations to preferred attributes are optimizations, and ignoring this type of 194 configuration error allows code flow to continue along the happy path when these optimization are 195 not available. The default value of this property is NO. 196 */ 197 @property(nonatomic) BOOL ignoresPreferredAttributeConfigurationErrors; 198 199 /** Default constructor. */ 200 + (instancetype)sharedInstance; 201 - (instancetype)init NS_UNAVAILABLE; 202 203 /** Adds a delegate, which is held weakly. */ 204 - (void)addDelegate:(id<RTC_OBJC_TYPE(RTCAudioSessionDelegate)>)delegate; 205 /** Removes an added delegate. */ 206 - (void)removeDelegate:(id<RTC_OBJC_TYPE(RTCAudioSessionDelegate)>)delegate; 207 208 /** Request exclusive access to the audio session for configuration. This call 209 * will block if the lock is held by another object. 210 */ 211 - (void)lockForConfiguration; 212 /** Relinquishes exclusive access to the audio session. */ 213 - (void)unlockForConfiguration; 214 215 /** If `active`, activates the audio session if it isn't already active. 216 * Successful calls must be balanced with a setActive:NO when activation is no 217 * longer required. If not `active`, deactivates the audio session if one is 218 * active and this is the last balanced call. When deactivating, the 219 * AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation option is passed to 220 * AVAudioSession. 221 */ 222 - (BOOL)setActive:(BOOL)active error:(NSError **)outError; 223 224 // The following methods are proxies for the associated methods on 225 // AVAudioSession. `lockForConfiguration` must be called before using them 226 // otherwise they will fail with kRTCAudioSessionErrorLockRequired. 227 228 - (BOOL)setCategory:(NSString *)category 229 withOptions:(AVAudioSessionCategoryOptions)options 230 error:(NSError **)outError; 231 - (BOOL)setMode:(NSString *)mode error:(NSError **)outError; 232 - (BOOL)setInputGain:(float)gain error:(NSError **)outError; 233 - (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError; 234 - (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError **)outError; 235 - (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count error:(NSError **)outError; 236 - (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count error:(NSError **)outError; 237 - (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError **)outError; 238 - (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort error:(NSError **)outError; 239 - (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 240 error:(NSError **)outError; 241 - (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 242 error:(NSError **)outError; 243 @end 244 245 @interface RTC_OBJC_TYPE (RTCAudioSession) 246 (Configuration) 247 248 /** Applies the configuration to the current session. Attempts to set all 249 * properties even if previous ones fail. Only the last error will be 250 * returned. 251 * `lockForConfiguration` must be called first. 252 */ 253 - (BOOL)setConfiguration : (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration error 254 : (NSError **)outError; 255 256 /** Convenience method that calls both setConfiguration and setActive. 257 * `lockForConfiguration` must be called first. 258 */ 259 - (BOOL)setConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration 260 active:(BOOL)active 261 error:(NSError **)outError; 262 263 @end 264 265 NS_ASSUME_NONNULL_END 266