Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(930)

Unified Diff: webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm

Issue 2855023003: Move RTCAudioSession* files modules/audio_device/ -> sdk/Framework. (Closed)
Patch Set: Address comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm
diff --git a/webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm b/webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm
deleted file mode 100644
index 763f1fae54d4b41f4679e4dcbba16702d6284dfb..0000000000000000000000000000000000000000
--- a/webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm
+++ /dev/null
@@ -1,915 +0,0 @@
-/*
- * Copyright 2016 The WebRTC Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h"
-
-#import <UIKit/UIKit.h>
-
-#include "webrtc/base/atomicops.h"
-#include "webrtc/base/checks.h"
-#include "webrtc/base/criticalsection.h"
-#include "webrtc/modules/audio_device/ios/audio_device_ios.h"
-
-#import "WebRTC/RTCLogging.h"
-#import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h"
-#import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h"
-
-NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession";
-NSInteger const kRTCAudioSessionErrorLockRequired = -1;
-NSInteger const kRTCAudioSessionErrorConfiguration = -2;
-NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume";
-
-// This class needs to be thread-safe because it is accessed from many threads.
-// TODO(tkchin): Consider more granular locking. We're not expecting a lot of
-// lock contention so coarse locks should be fine for now.
-@implementation RTCAudioSession {
- rtc::CriticalSection _crit;
- AVAudioSession *_session;
- volatile int _activationCount;
- volatile int _lockRecursionCount;
- volatile int _webRTCSessionCount;
- BOOL _isActive;
- BOOL _useManualAudio;
- BOOL _isAudioEnabled;
- BOOL _canPlayOrRecord;
- BOOL _isInterrupted;
-}
-
-@synthesize session = _session;
-@synthesize delegates = _delegates;
-
-+ (instancetype)sharedInstance {
- static dispatch_once_t onceToken;
- static RTCAudioSession *sharedInstance = nil;
- dispatch_once(&onceToken, ^{
- sharedInstance = [[self alloc] init];
- });
- return sharedInstance;
-}
-
-- (instancetype)init {
- if (self = [super init]) {
- _session = [AVAudioSession sharedInstance];
-
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserver:self
- selector:@selector(handleInterruptionNotification:)
- name:AVAudioSessionInterruptionNotification
- object:nil];
- [center addObserver:self
- selector:@selector(handleRouteChangeNotification:)
- name:AVAudioSessionRouteChangeNotification
- object:nil];
- [center addObserver:self
- selector:@selector(handleMediaServicesWereLost:)
- name:AVAudioSessionMediaServicesWereLostNotification
- object:nil];
- [center addObserver:self
- selector:@selector(handleMediaServicesWereReset:)
- name:AVAudioSessionMediaServicesWereResetNotification
- object:nil];
- // Posted on the main thread when the primary audio from other applications
- // starts and stops. Foreground applications may use this notification as a
- // hint to enable or disable audio that is secondary.
- [center addObserver:self
- selector:@selector(handleSilenceSecondaryAudioHintNotification:)
- name:AVAudioSessionSilenceSecondaryAudioHintNotification
- object:nil];
- // Also track foreground event in order to deal with interruption ended situation.
- [center addObserver:self
- selector:@selector(handleApplicationDidBecomeActive:)
- name:UIApplicationDidBecomeActiveNotification
- object:nil];
- [_session addObserver:self
- forKeyPath:kRTCAudioSessionOutputVolumeSelector
- options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
- context:nil];
-
- RTCLog(@"RTCAudioSession (%p): init.", self);
- }
- return self;
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [_session removeObserver:self forKeyPath:kRTCAudioSessionOutputVolumeSelector context:nil];
- RTCLog(@"RTCAudioSession (%p): dealloc.", self);
-}
-
-- (NSString *)description {
- NSString *format =
- @"RTCAudioSession: {\n"
- " category: %@\n"
- " categoryOptions: %ld\n"
- " mode: %@\n"
- " isActive: %d\n"
- " sampleRate: %.2f\n"
- " IOBufferDuration: %f\n"
- " outputNumberOfChannels: %ld\n"
- " inputNumberOfChannels: %ld\n"
- " outputLatency: %f\n"
- " inputLatency: %f\n"
- " outputVolume: %f\n"
- "}";
- NSString *description = [NSString stringWithFormat:format,
- self.category, (long)self.categoryOptions, self.mode,
- self.isActive, self.sampleRate, self.IOBufferDuration,
- self.outputNumberOfChannels, self.inputNumberOfChannels,
- self.outputLatency, self.inputLatency, self.outputVolume];
- return description;
-}
-
-- (void)setIsActive:(BOOL)isActive {
- @synchronized(self) {
- _isActive = isActive;
- }
-}
-
-- (BOOL)isActive {
- @synchronized(self) {
- return _isActive;
- }
-}
-
-- (BOOL)isLocked {
- return _lockRecursionCount > 0;
-}
-
-- (void)setUseManualAudio:(BOOL)useManualAudio {
- @synchronized(self) {
- if (_useManualAudio == useManualAudio) {
- return;
- }
- _useManualAudio = useManualAudio;
- }
- [self updateCanPlayOrRecord];
-}
-
-- (BOOL)useManualAudio {
- @synchronized(self) {
- return _useManualAudio;
- }
-}
-
-- (void)setIsAudioEnabled:(BOOL)isAudioEnabled {
- @synchronized(self) {
- if (_isAudioEnabled == isAudioEnabled) {
- return;
- }
- _isAudioEnabled = isAudioEnabled;
- }
- [self updateCanPlayOrRecord];
-}
-
-- (BOOL)isAudioEnabled {
- @synchronized(self) {
- return _isAudioEnabled;
- }
-}
-
-// TODO(tkchin): Check for duplicates.
-- (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate {
- RTCLog(@"Adding delegate: (%p)", delegate);
- if (!delegate) {
- return;
- }
- @synchronized(self) {
- _delegates.push_back(delegate);
- [self removeZeroedDelegates];
- }
-}
-
-- (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate {
- RTCLog(@"Removing delegate: (%p)", delegate);
- if (!delegate) {
- return;
- }
- @synchronized(self) {
- _delegates.erase(std::remove(_delegates.begin(),
- _delegates.end(),
- delegate),
- _delegates.end());
- [self removeZeroedDelegates];
- }
-}
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wthread-safety-analysis"
-
-- (void)lockForConfiguration {
- _crit.Enter();
- rtc::AtomicOps::Increment(&_lockRecursionCount);
-}
-
-- (void)unlockForConfiguration {
- // Don't let threads other than the one that called lockForConfiguration
- // unlock.
- if (_crit.TryEnter()) {
- rtc::AtomicOps::Decrement(&_lockRecursionCount);
- // One unlock for the tryLock, and another one to actually unlock. If this
- // was called without anyone calling lock, we will hit an assertion.
- _crit.Leave();
- _crit.Leave();
- }
-}
-
-#pragma clang diagnostic pop
-
-#pragma mark - AVAudioSession proxy methods
-
-- (NSString *)category {
- return self.session.category;
-}
-
-- (AVAudioSessionCategoryOptions)categoryOptions {
- return self.session.categoryOptions;
-}
-
-- (NSString *)mode {
- return self.session.mode;
-}
-
-- (BOOL)secondaryAudioShouldBeSilencedHint {
- return self.session.secondaryAudioShouldBeSilencedHint;
-}
-
-- (AVAudioSessionRouteDescription *)currentRoute {
- return self.session.currentRoute;
-}
-
-- (NSInteger)maximumInputNumberOfChannels {
- return self.session.maximumInputNumberOfChannels;
-}
-
-- (NSInteger)maximumOutputNumberOfChannels {
- return self.session.maximumOutputNumberOfChannels;
-}
-
-- (float)inputGain {
- return self.session.inputGain;
-}
-
-- (BOOL)inputGainSettable {
- return self.session.inputGainSettable;
-}
-
-- (BOOL)inputAvailable {
- return self.session.inputAvailable;
-}
-
-- (NSArray<AVAudioSessionDataSourceDescription *> *)inputDataSources {
- return self.session.inputDataSources;
-}
-
-- (AVAudioSessionDataSourceDescription *)inputDataSource {
- return self.session.inputDataSource;
-}
-
-- (NSArray<AVAudioSessionDataSourceDescription *> *)outputDataSources {
- return self.session.outputDataSources;
-}
-
-- (AVAudioSessionDataSourceDescription *)outputDataSource {
- return self.session.outputDataSource;
-}
-
-- (double)sampleRate {
- return self.session.sampleRate;
-}
-
-- (double)preferredSampleRate {
- return self.session.preferredSampleRate;
-}
-
-- (NSInteger)inputNumberOfChannels {
- return self.session.inputNumberOfChannels;
-}
-
-- (NSInteger)outputNumberOfChannels {
- return self.session.outputNumberOfChannels;
-}
-
-- (float)outputVolume {
- return self.session.outputVolume;
-}
-
-- (NSTimeInterval)inputLatency {
- return self.session.inputLatency;
-}
-
-- (NSTimeInterval)outputLatency {
- return self.session.outputLatency;
-}
-
-- (NSTimeInterval)IOBufferDuration {
- return self.session.IOBufferDuration;
-}
-
-- (NSTimeInterval)preferredIOBufferDuration {
- return self.session.preferredIOBufferDuration;
-}
-
-// TODO(tkchin): Simplify the amount of locking happening here. Likely that we
-// can just do atomic increments / decrements.
-- (BOOL)setActive:(BOOL)active
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- int activationCount = _activationCount;
- if (!active && activationCount == 0) {
- RTCLogWarning(@"Attempting to deactivate without prior activation.");
- }
- BOOL success = YES;
- BOOL isActive = self.isActive;
- // Keep a local error so we can log it.
- NSError *error = nil;
- BOOL shouldSetActive =
- (active && !isActive) || (!active && isActive && activationCount == 1);
- // Attempt to activate if we're not active.
- // Attempt to deactivate if we're active and it's the last unbalanced call.
- if (shouldSetActive) {
- AVAudioSession *session = self.session;
- // AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation is used to ensure
- // that other audio sessions that were interrupted by our session can return
- // to their active state. It is recommended for VoIP apps to use this
- // option.
- AVAudioSessionSetActiveOptions options =
- active ? 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation;
- success = [session setActive:active
- withOptions:options
- error:&error];
- if (outError) {
- *outError = error;
- }
- }
- if (success) {
- if (shouldSetActive) {
- self.isActive = active;
- }
- if (active) {
- [self incrementActivationCount];
- }
- } else {
- RTCLogError(@"Failed to setActive:%d. Error: %@",
- active, error.localizedDescription);
- }
- // Decrement activation count on deactivation whether or not it succeeded.
- if (!active) {
- [self decrementActivationCount];
- }
- RTCLog(@"Number of current activations: %d", _activationCount);
- return success;
-}
-
-- (BOOL)setCategory:(NSString *)category
- withOptions:(AVAudioSessionCategoryOptions)options
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setCategory:category withOptions:options error:outError];
-}
-
-- (BOOL)setMode:(NSString *)mode error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setMode:mode error:outError];
-}
-
-- (BOOL)setInputGain:(float)gain error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setInputGain:gain error:outError];
-}
-
-- (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setPreferredSampleRate:sampleRate error:outError];
-}
-
-- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setPreferredIOBufferDuration:duration error:outError];
-}
-
-- (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setPreferredInputNumberOfChannels:count error:outError];
-}
-- (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setPreferredOutputNumberOfChannels:count error:outError];
-}
-
-- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session overrideOutputAudioPort:portOverride error:outError];
-}
-
-- (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setPreferredInput:inPort error:outError];
-}
-
-- (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setInputDataSource:dataSource error:outError];
-}
-
-- (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource
- error:(NSError **)outError {
- if (![self checkLock:outError]) {
- return NO;
- }
- return [self.session setOutputDataSource:dataSource error:outError];
-}
-
-#pragma mark - Notifications
-
-- (void)handleInterruptionNotification:(NSNotification *)notification {
- NSNumber* typeNumber =
- notification.userInfo[AVAudioSessionInterruptionTypeKey];
- AVAudioSessionInterruptionType type =
- (AVAudioSessionInterruptionType)typeNumber.unsignedIntegerValue;
- switch (type) {
- case AVAudioSessionInterruptionTypeBegan:
- RTCLog(@"Audio session interruption began.");
- self.isActive = NO;
- self.isInterrupted = YES;
- [self notifyDidBeginInterruption];
- break;
- case AVAudioSessionInterruptionTypeEnded: {
- RTCLog(@"Audio session interruption ended.");
- self.isInterrupted = NO;
- [self updateAudioSessionAfterEvent];
- NSNumber *optionsNumber =
- notification.userInfo[AVAudioSessionInterruptionOptionKey];
- AVAudioSessionInterruptionOptions options =
- optionsNumber.unsignedIntegerValue;
- BOOL shouldResume =
- options & AVAudioSessionInterruptionOptionShouldResume;
- [self notifyDidEndInterruptionWithShouldResumeSession:shouldResume];
- break;
- }
- }
-}
-
-- (void)handleRouteChangeNotification:(NSNotification *)notification {
- // Get reason for current route change.
- NSNumber* reasonNumber =
- notification.userInfo[AVAudioSessionRouteChangeReasonKey];
- AVAudioSessionRouteChangeReason reason =
- (AVAudioSessionRouteChangeReason)reasonNumber.unsignedIntegerValue;
- RTCLog(@"Audio route changed:");
- switch (reason) {
- case AVAudioSessionRouteChangeReasonUnknown:
- RTCLog(@"Audio route changed: ReasonUnknown");
- break;
- case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
- RTCLog(@"Audio route changed: NewDeviceAvailable");
- break;
- case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
- RTCLog(@"Audio route changed: OldDeviceUnavailable");
- break;
- case AVAudioSessionRouteChangeReasonCategoryChange:
- RTCLog(@"Audio route changed: CategoryChange to :%@",
- self.session.category);
- break;
- case AVAudioSessionRouteChangeReasonOverride:
- RTCLog(@"Audio route changed: Override");
- break;
- case AVAudioSessionRouteChangeReasonWakeFromSleep:
- RTCLog(@"Audio route changed: WakeFromSleep");
- break;
- case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
- RTCLog(@"Audio route changed: NoSuitableRouteForCategory");
- break;
- case AVAudioSessionRouteChangeReasonRouteConfigurationChange:
- RTCLog(@"Audio route changed: RouteConfigurationChange");
- break;
- }
- AVAudioSessionRouteDescription* previousRoute =
- notification.userInfo[AVAudioSessionRouteChangePreviousRouteKey];
- // Log previous route configuration.
- RTCLog(@"Previous route: %@\nCurrent route:%@",
- previousRoute, self.session.currentRoute);
- [self notifyDidChangeRouteWithReason:reason previousRoute:previousRoute];
-}
-
-- (void)handleMediaServicesWereLost:(NSNotification *)notification {
- RTCLog(@"Media services were lost.");
- [self updateAudioSessionAfterEvent];
- [self notifyMediaServicesWereLost];
-}
-
-- (void)handleMediaServicesWereReset:(NSNotification *)notification {
- RTCLog(@"Media services were reset.");
- [self updateAudioSessionAfterEvent];
- [self notifyMediaServicesWereReset];
-}
-
-- (void)handleSilenceSecondaryAudioHintNotification:(NSNotification *)notification {
- // TODO(henrika): just adding logs here for now until we know if we are ever
- // see this notification and might be affected by it or if further actions
- // are required.
- NSNumber *typeNumber =
- notification.userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];
- AVAudioSessionSilenceSecondaryAudioHintType type =
- (AVAudioSessionSilenceSecondaryAudioHintType)typeNumber.unsignedIntegerValue;
- switch (type) {
- case AVAudioSessionSilenceSecondaryAudioHintTypeBegin:
- RTCLog(@"Another application's primary audio has started.");
- break;
- case AVAudioSessionSilenceSecondaryAudioHintTypeEnd:
- RTCLog(@"Another application's primary audio has stopped.");
- break;
- }
-}
-
-- (void)handleApplicationDidBecomeActive:(NSNotification *)notification {
- RTCLog(@"Application became active after an interruption. Treating as interruption "
- " end. isInterrupted changed from %d to 0.", self.isInterrupted);
- if (self.isInterrupted) {
- self.isInterrupted = NO;
- [self updateAudioSessionAfterEvent];
- }
- // Always treat application becoming active as an interruption end event.
- [self notifyDidEndInterruptionWithShouldResumeSession:YES];
-}
-
-#pragma mark - Private
-
-+ (NSError *)lockError {
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey:
- @"Must call lockForConfiguration before calling this method."
- };
- NSError *error =
- [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain
- code:kRTCAudioSessionErrorLockRequired
- userInfo:userInfo];
- return error;
-}
-
-- (std::vector<__weak id<RTCAudioSessionDelegate> >)delegates {
- @synchronized(self) {
- // Note: this returns a copy.
- return _delegates;
- }
-}
-
-// TODO(tkchin): check for duplicates.
-- (void)pushDelegate:(id<RTCAudioSessionDelegate>)delegate {
- @synchronized(self) {
- _delegates.insert(_delegates.begin(), delegate);
- }
-}
-
-- (void)removeZeroedDelegates {
- @synchronized(self) {
- _delegates.erase(
- std::remove_if(_delegates.begin(),
- _delegates.end(),
- [](id delegate) -> bool { return delegate == nil; }),
- _delegates.end());
- }
-}
-
-- (int)activationCount {
- return _activationCount;
-}
-
-- (int)incrementActivationCount {
- RTCLog(@"Incrementing activation count.");
- return rtc::AtomicOps::Increment(&_activationCount);
-}
-
-- (NSInteger)decrementActivationCount {
- RTCLog(@"Decrementing activation count.");
- return rtc::AtomicOps::Decrement(&_activationCount);
-}
-
-- (int)webRTCSessionCount {
- return _webRTCSessionCount;
-}
-
-- (BOOL)canPlayOrRecord {
- return !self.useManualAudio || self.isAudioEnabled;
-}
-
-- (BOOL)isInterrupted {
- @synchronized(self) {
- return _isInterrupted;
- }
-}
-
-- (void)setIsInterrupted:(BOOL)isInterrupted {
- @synchronized(self) {
- if (_isInterrupted == isInterrupted) {
- return;
- }
- _isInterrupted = isInterrupted;
- }
-}
-
-- (BOOL)checkLock:(NSError **)outError {
- // Check ivar instead of trying to acquire lock so that we won't accidentally
- // acquire lock if it hasn't already been called.
- if (!self.isLocked) {
- if (outError) {
- *outError = [RTCAudioSession lockError];
- }
- return NO;
- }
- return YES;
-}
-
-- (BOOL)beginWebRTCSession:(NSError **)outError {
- if (outError) {
- *outError = nil;
- }
- if (![self checkLock:outError]) {
- return NO;
- }
- rtc::AtomicOps::Increment(&_webRTCSessionCount);
- [self notifyDidStartPlayOrRecord];
- return YES;
-}
-
-- (BOOL)endWebRTCSession:(NSError **)outError {
- if (outError) {
- *outError = nil;
- }
- if (![self checkLock:outError]) {
- return NO;
- }
- rtc::AtomicOps::Decrement(&_webRTCSessionCount);
- [self notifyDidStopPlayOrRecord];
- return YES;
-}
-
-- (BOOL)configureWebRTCSession:(NSError **)outError {
- if (outError) {
- *outError = nil;
- }
- if (![self checkLock:outError]) {
- return NO;
- }
- RTCLog(@"Configuring audio session for WebRTC.");
-
- // Configure the AVAudioSession and activate it.
- // Provide an error even if there isn't one so we can log it.
- NSError *error = nil;
- RTCAudioSessionConfiguration *webRTCConfig =
- [RTCAudioSessionConfiguration webRTCConfiguration];
- if (![self setConfiguration:webRTCConfig active:YES error:&error]) {
- RTCLogError(@"Failed to set WebRTC audio configuration: %@",
- error.localizedDescription);
- // Do not call setActive:NO if setActive:YES failed.
- if (outError) {
- *outError = error;
- }
- return NO;
- }
-
- // Ensure that the device currently supports audio input.
- // TODO(tkchin): Figure out if this is really necessary.
- if (!self.inputAvailable) {
- RTCLogError(@"No audio input path is available!");
- [self unconfigureWebRTCSession:nil];
- if (outError) {
- *outError = [self configurationErrorWithDescription:@"No input path."];
- }
- return NO;
- }
-
- // It can happen (e.g. in combination with BT devices) that the attempt to set
- // the preferred sample rate for WebRTC (48kHz) fails. If so, make a new
- // configuration attempt using the sample rate that worked using the active
- // audio session. A typical case is that only 8 or 16kHz can be set, e.g. in
- // combination with BT headsets. Using this "trick" seems to avoid a state
- // where Core Audio asks for a different number of audio frames than what the
- // session's I/O buffer duration corresponds to.
- // TODO(henrika): this fix resolves bugs.webrtc.org/6004 but it has only been
- // tested on a limited set of iOS devices and BT devices.
- double sessionSampleRate = self.sampleRate;
- double preferredSampleRate = webRTCConfig.sampleRate;
- if (sessionSampleRate != preferredSampleRate) {
- RTCLogWarning(
- @"Current sample rate (%.2f) is not the preferred rate (%.2f)",
- sessionSampleRate, preferredSampleRate);
- if (![self setPreferredSampleRate:sessionSampleRate
- error:&error]) {
- RTCLogError(@"Failed to set preferred sample rate: %@",
- error.localizedDescription);
- if (outError) {
- *outError = error;
- }
- }
- }
-
- return YES;
-}
-
-- (BOOL)unconfigureWebRTCSession:(NSError **)outError {
- if (outError) {
- *outError = nil;
- }
- if (![self checkLock:outError]) {
- return NO;
- }
- RTCLog(@"Unconfiguring audio session for WebRTC.");
- [self setActive:NO error:outError];
-
- return YES;
-}
-
-- (NSError *)configurationErrorWithDescription:(NSString *)description {
- NSDictionary* userInfo = @{
- NSLocalizedDescriptionKey: description,
- };
- return [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain
- code:kRTCAudioSessionErrorConfiguration
- userInfo:userInfo];
-}
-
-- (void)updateAudioSessionAfterEvent {
- BOOL shouldActivate = self.activationCount > 0;
- AVAudioSessionSetActiveOptions options = shouldActivate ?
- 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation;
- NSError *error = nil;
- if ([self.session setActive:shouldActivate
- withOptions:options
- error:&error]) {
- self.isActive = shouldActivate;
- } else {
- RTCLogError(@"Failed to set session active to %d. Error:%@",
- shouldActivate, error.localizedDescription);
- }
-}
-
-- (void)updateCanPlayOrRecord {
- BOOL canPlayOrRecord = NO;
- BOOL shouldNotify = NO;
- @synchronized(self) {
- canPlayOrRecord = !self.useManualAudio || self.isAudioEnabled;
- if (_canPlayOrRecord == canPlayOrRecord) {
- return;
- }
- _canPlayOrRecord = canPlayOrRecord;
- shouldNotify = YES;
- }
- if (shouldNotify) {
- [self notifyDidChangeCanPlayOrRecord:canPlayOrRecord];
- }
-}
-
-- (void)audioSessionDidActivate:(AVAudioSession *)session {
- if (_session != session) {
- RTCLogError(@"audioSessionDidActivate called on different AVAudioSession");
- }
- [self incrementActivationCount];
- self.isActive = YES;
-}
-
-- (void)audioSessionDidDeactivate:(AVAudioSession *)session {
- if (_session != session) {
- RTCLogError(@"audioSessionDidDeactivate called on different AVAudioSession");
- }
- self.isActive = NO;
- [self decrementActivationCount];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath
- ofObject:(id)object
- change:(NSDictionary *)change
- context:(void *)context {
- if (object == _session) {
- NSNumber *newVolume = change[NSKeyValueChangeNewKey];
- RTCLog(@"OutputVolumeDidChange to %f", newVolume.floatValue);
- [self notifyDidChangeOutputVolume:newVolume.floatValue];
- } else {
- [super observeValueForKeyPath:keyPath
- ofObject:object
- change:change
- context:context];
- }
-}
-
-- (void)notifyDidBeginInterruption {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionDidBeginInterruption:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionDidBeginInterruption:self];
- }
- }
-}
-
-- (void)notifyDidEndInterruptionWithShouldResumeSession:
- (BOOL)shouldResumeSession {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionDidEndInterruption:shouldResumeSession:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionDidEndInterruption:self
- shouldResumeSession:shouldResumeSession];
- }
- }
-}
-
-- (void)notifyDidChangeRouteWithReason:(AVAudioSessionRouteChangeReason)reason
- previousRoute:(AVAudioSessionRouteDescription *)previousRoute {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionDidChangeRoute:reason:previousRoute:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionDidChangeRoute:self
- reason:reason
- previousRoute:previousRoute];
- }
- }
-}
-
-- (void)notifyMediaServicesWereLost {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionMediaServerTerminated:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionMediaServerTerminated:self];
- }
- }
-}
-
-- (void)notifyMediaServicesWereReset {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionMediaServerReset:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionMediaServerReset:self];
- }
- }
-}
-
-- (void)notifyDidChangeCanPlayOrRecord:(BOOL)canPlayOrRecord {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSession:didChangeCanPlayOrRecord:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSession:self didChangeCanPlayOrRecord:canPlayOrRecord];
- }
- }
-}
-
-- (void)notifyDidStartPlayOrRecord {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionDidStartPlayOrRecord:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionDidStartPlayOrRecord:self];
- }
- }
-}
-
-- (void)notifyDidStopPlayOrRecord {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSessionDidStopPlayOrRecord:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSessionDidStopPlayOrRecord:self];
- }
- }
-}
-
-- (void)notifyDidChangeOutputVolume:(float)volume {
- for (auto delegate : self.delegates) {
- SEL sel = @selector(audioSession:didChangeOutputVolume:);
- if ([delegate respondsToSelector:sel]) {
- [delegate audioSession:self didChangeOutputVolume:volume];
- }
- }
-}
-
-@end

Powered by Google App Engine
This is Rietveld 408576698