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 "WebRTC/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. 30 RTC_EXPORT 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)audioSessionMediaServicesWereLost:(RTCAudioSession *)session; 56 57 /** Called on a system notification thread when AVAudioSession media server 58 * restarts. 59 */ 60 - (void)audioSessionMediaServicesWereReset:(RTCAudioSession *)session; 61 62 // TODO(tkchin): Maybe handle SilenceSecondaryAudioHintNotification. 63 64 - (void)audioSession:(RTCAudioSession *)session 65 didChangeCanPlayOrRecord:(BOOL)canPlayOrRecord; 66 67 /** Called on a WebRTC thread when the audio device is notified to begin 68 * playback or recording. 69 */ 70 - (void)audioSessionDidStartPlayOrRecord:(RTCAudioSession *)session; 71 72 /** Called on a WebRTC thread when the audio device is notified to stop 73 * playback or recording. 74 */ 75 - (void)audioSessionDidStopPlayOrRecord:(RTCAudioSession *)session; 76 77 @end 78 79 /** Proxy class for AVAudioSession that adds a locking mechanism similar to 80 * AVCaptureDevice. This is used to that interleaving configurations between 81 * WebRTC and the application layer are avoided. 82 * 83 * RTCAudioSession also coordinates activation so that the audio session is 84 * activated only once. See |setActive:error:|. 85 */ 86 RTC_EXPORT 87 @interface RTCAudioSession : NSObject 88 89 /** Convenience property to access the AVAudioSession singleton. Callers should 90 * not call setters on AVAudioSession directly, but other method invocations 91 * are fine. 92 */ 93 @property(nonatomic, readonly) AVAudioSession *session; 94 95 /** Our best guess at whether the session is active based on results of calls to 96 * AVAudioSession. 97 */ 98 @property(nonatomic, readonly) BOOL isActive; 99 /** Whether RTCAudioSession is currently locked for configuration. */ 100 @property(nonatomic, readonly) BOOL isLocked; 101 102 /** If YES, WebRTC will not initialize the audio unit automatically when an 103 * audio track is ready for playout or recording. Instead, applications should 104 * call setIsAudioEnabled. If NO, WebRTC will initialize the audio unit 105 * as soon as an audio track is ready for playout or recording. 106 */ 107 @property(nonatomic, assign) BOOL useManualAudio; 108 109 /** This property is only effective if useManualAudio is YES. 110 * Represents permission for WebRTC to initialize the VoIP audio unit. 111 * When set to NO, if the VoIP audio unit used by WebRTC is active, it will be 112 * stopped and uninitialized. This will stop incoming and outgoing audio. 113 * When set to YES, WebRTC will initialize and start the audio unit when it is 114 * needed (e.g. due to establishing an audio connection). 115 * This property was introduced to work around an issue where if an AVPlayer is 116 * playing audio while the VoIP audio unit is initialized, its audio would be 117 * either cut off completely or played at a reduced volume. By preventing 118 * the audio unit from being initialized until after the audio has completed, 119 * we are able to prevent the abrupt cutoff. 120 */ 121 @property(nonatomic, assign) BOOL isAudioEnabled; 122 123 // Proxy properties. 124 @property(readonly) NSString *category; 125 @property(readonly) AVAudioSessionCategoryOptions categoryOptions; 126 @property(readonly) NSString *mode; 127 @property(readonly) BOOL secondaryAudioShouldBeSilencedHint; 128 @property(readonly) AVAudioSessionRouteDescription *currentRoute; 129 @property(readonly) NSInteger maximumInputNumberOfChannels; 130 @property(readonly) NSInteger maximumOutputNumberOfChannels; 131 @property(readonly) float inputGain; 132 @property(readonly) BOOL inputGainSettable; 133 @property(readonly) BOOL inputAvailable; 134 @property(readonly, nullable) 135 NSArray<AVAudioSessionDataSourceDescription *> * inputDataSources; 136 @property(readonly, nullable) 137 AVAudioSessionDataSourceDescription *inputDataSource; 138 @property(readonly, nullable) 139 NSArray<AVAudioSessionDataSourceDescription *> * outputDataSources; 140 @property(readonly, nullable) 141 AVAudioSessionDataSourceDescription *outputDataSource; 142 @property(readonly) double sampleRate; 143 @property(readonly) double preferredSampleRate; 144 @property(readonly) NSInteger inputNumberOfChannels; 145 @property(readonly) NSInteger outputNumberOfChannels; 146 @property(readonly) float outputVolume; 147 @property(readonly) NSTimeInterval inputLatency; 148 @property(readonly) NSTimeInterval outputLatency; 149 @property(readonly) NSTimeInterval IOBufferDuration; 150 @property(readonly) NSTimeInterval preferredIOBufferDuration; 151 152 /** Default constructor. */ 153 + (instancetype)sharedInstance; 154 - (instancetype)init NS_UNAVAILABLE; 155 156 /** Adds a delegate, which is held weakly. */ 157 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate; 158 /** Removes an added delegate. */ 159 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate; 160 161 /** Request exclusive access to the audio session for configuration. This call 162 * will block if the lock is held by another object. 163 */ 164 - (void)lockForConfiguration; 165 /** Relinquishes exclusive access to the audio session. */ 166 - (void)unlockForConfiguration; 167 168 /** If |active|, activates the audio session if it isn't already active. 169 * Successful calls must be balanced with a setActive:NO when activation is no 170 * longer required. If not |active|, deactivates the audio session if one is 171 * active and this is the last balanced call. When deactivating, the 172 * AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation option is passed to 173 * AVAudioSession. 174 */ 175 - (BOOL)setActive:(BOOL)active 176 error:(NSError **)outError; 177 178 // The following methods are proxies for the associated methods on 179 // AVAudioSession. |lockForConfiguration| must be called before using them 180 // otherwise they will fail with kRTCAudioSessionErrorLockRequired. 181 182 - (BOOL)setCategory:(NSString *)category 183 withOptions:(AVAudioSessionCategoryOptions)options 184 error:(NSError **)outError; 185 - (BOOL)setMode:(NSString *)mode error:(NSError **)outError; 186 - (BOOL)setInputGain:(float)gain error:(NSError **)outError; 187 - (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError; 188 - (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration 189 error:(NSError **)outError; 190 - (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count 191 error:(NSError **)outError; 192 - (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count 193 error:(NSError **)outError; 194 - (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride 195 error:(NSError **)outError; 196 - (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort 197 error:(NSError **)outError; 198 - (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 199 error:(NSError **)outError; 200 - (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource 201 error:(NSError **)outError; 202 203 @end 204 205 @interface RTCAudioSession (Configuration) 206 207 /** Applies the configuration to the current session. Attempts to set all 208 * properties even if previous ones fail. Only the last error will be 209 * returned. 210 * |lockForConfiguration| must be called first. 211 */ 212 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration 213 error:(NSError **)outError; 214 215 /** Convenience method that calls both setConfiguration and setActive. 216 * |lockForConfiguration| must be called first. 217 */ 218 - (BOOL)setConfiguration:(RTCAudioSessionConfiguration *)configuration 219 active:(BOOL)active 220 error:(NSError **)outError; 221 222 @end 223 224 NS_ASSUME_NONNULL_END 225