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