OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" | 11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" |
12 | 12 |
13 #include "webrtc/base/checks.h" | 13 #include "webrtc/base/checks.h" |
14 #include "webrtc/base/criticalsection.h" | 14 #include "webrtc/base/criticalsection.h" |
15 | 15 |
16 #import "webrtc/base/objc/RTCLogging.h" | 16 #import "webrtc/base/objc/RTCLogging.h" |
17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" | 17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" |
18 | 18 |
19 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; | 19 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; |
20 NSInteger const kRTCAudioSessionErrorLockRequired = -1; | 20 NSInteger const kRTCAudioSessionErrorLockRequired = -1; |
| 21 NSInteger const kRTCAudioSessionErrorConfiguration = -2; |
21 | 22 |
22 // This class needs to be thread-safe because it is accessed from many threads. | 23 // This class needs to be thread-safe because it is accessed from many threads. |
23 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of | 24 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of |
24 // lock contention so coarse locks should be fine for now. | 25 // lock contention so coarse locks should be fine for now. |
25 @implementation RTCAudioSession { | 26 @implementation RTCAudioSession { |
26 rtc::CriticalSection _crit; | 27 rtc::CriticalSection _crit; |
27 AVAudioSession *_session; | 28 AVAudioSession *_session; |
28 NSHashTable *_delegates; | 29 NSHashTable *_delegates; |
29 NSInteger _activationCount; | 30 NSInteger _activationCount; |
30 NSInteger _lockRecursionCount; | 31 NSInteger _lockRecursionCount; |
31 BOOL _isActive; | 32 BOOL _isActive; |
| 33 BOOL _shouldDelayAudioConfiguration; |
32 } | 34 } |
33 | 35 |
34 @synthesize session = _session; | 36 @synthesize session = _session; |
35 | 37 |
36 + (instancetype)sharedInstance { | 38 + (instancetype)sharedInstance { |
37 static dispatch_once_t onceToken; | 39 static dispatch_once_t onceToken; |
38 static RTCAudioSession *sharedInstance = nil; | 40 static RTCAudioSession *sharedInstance = nil; |
39 dispatch_once(&onceToken, ^{ | 41 dispatch_once(&onceToken, ^{ |
40 sharedInstance = [[RTCAudioSession alloc] init]; | 42 sharedInstance = [[RTCAudioSession alloc] init]; |
41 }); | 43 }); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 return _isActive; | 86 return _isActive; |
85 } | 87 } |
86 } | 88 } |
87 | 89 |
88 - (BOOL)isLocked { | 90 - (BOOL)isLocked { |
89 @synchronized(self) { | 91 @synchronized(self) { |
90 return _lockRecursionCount > 0; | 92 return _lockRecursionCount > 0; |
91 } | 93 } |
92 } | 94 } |
93 | 95 |
| 96 - (void)setShouldDelayAudioConfiguration:(BOOL)shouldDelayAudioConfiguration { |
| 97 @synchronized(self) { |
| 98 if (_shouldDelayAudioConfiguration == shouldDelayAudioConfiguration) { |
| 99 return; |
| 100 } |
| 101 _shouldDelayAudioConfiguration = shouldDelayAudioConfiguration; |
| 102 } |
| 103 } |
| 104 |
| 105 - (BOOL)shouldDelayAudioConfiguration { |
| 106 @synchronized(self) { |
| 107 return _shouldDelayAudioConfiguration; |
| 108 } |
| 109 } |
| 110 |
94 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { | 111 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { |
95 @synchronized(self) { | 112 @synchronized(self) { |
96 [_delegates addObject:delegate]; | 113 [_delegates addObject:delegate]; |
97 } | 114 } |
98 } | 115 } |
99 | 116 |
100 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { | 117 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { |
101 @synchronized(self) { | 118 @synchronized(self) { |
102 [_delegates removeObject:delegate]; | 119 [_delegates removeObject:delegate]; |
103 } | 120 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 } | 260 } |
244 } | 261 } |
245 if (success) { | 262 if (success) { |
246 if (shouldSetActive) { | 263 if (shouldSetActive) { |
247 self.isActive = active; | 264 self.isActive = active; |
248 } | 265 } |
249 if (active) { | 266 if (active) { |
250 [self incrementActivationCount]; | 267 [self incrementActivationCount]; |
251 } | 268 } |
252 } else { | 269 } else { |
253 RTCLogError(@"Failed to setActive:%d. Error: %@", active, error); | 270 RTCLogError(@"Failed to setActive:%d. Error: %@", |
| 271 active, error.localizedDescription); |
254 } | 272 } |
255 // Decrement activation count on deactivation whether or not it succeeded. | 273 // Decrement activation count on deactivation whether or not it succeeded. |
256 if (!active) { | 274 if (!active) { |
257 [self decrementActivationCount]; | 275 [self decrementActivationCount]; |
258 } | 276 } |
259 RTCLog(@"Number of current activations: %ld", (long)self.activationCount); | 277 RTCLog(@"Number of current activations: %ld", (long)self.activationCount); |
260 return success; | 278 return success; |
261 } | 279 } |
262 | 280 |
263 - (BOOL)setCategory:(NSString *)category | 281 - (BOOL)setCategory:(NSString *)category |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 NSLocalizedDescriptionKey: | 452 NSLocalizedDescriptionKey: |
435 @"Must call lockForConfiguration before calling this method." | 453 @"Must call lockForConfiguration before calling this method." |
436 }; | 454 }; |
437 NSError *error = | 455 NSError *error = |
438 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain | 456 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain |
439 code:kRTCAudioSessionErrorLockRequired | 457 code:kRTCAudioSessionErrorLockRequired |
440 userInfo:userInfo]; | 458 userInfo:userInfo]; |
441 return error; | 459 return error; |
442 } | 460 } |
443 | 461 |
444 - (BOOL)checkLock:(NSError **)outError { | |
445 // Check ivar instead of trying to acquire lock so that we won't accidentally | |
446 // acquire lock if it hasn't already been called. | |
447 if (!self.isLocked) { | |
448 if (outError) { | |
449 *outError = [RTCAudioSession lockError]; | |
450 } | |
451 return NO; | |
452 } | |
453 return YES; | |
454 } | |
455 | |
456 - (NSSet *)delegates { | 462 - (NSSet *)delegates { |
457 @synchronized(self) { | 463 @synchronized(self) { |
458 return _delegates.setRepresentation; | 464 return _delegates.setRepresentation; |
459 } | 465 } |
460 } | 466 } |
461 | 467 |
462 - (NSInteger)activationCount { | 468 - (NSInteger)activationCount { |
463 @synchronized(self) { | 469 @synchronized(self) { |
464 return _activationCount; | 470 return _activationCount; |
465 } | 471 } |
466 } | 472 } |
467 | 473 |
468 - (NSInteger)incrementActivationCount { | 474 - (NSInteger)incrementActivationCount { |
469 RTCLog(@"Incrementing activation count."); | 475 RTCLog(@"Incrementing activation count."); |
470 @synchronized(self) { | 476 @synchronized(self) { |
471 return ++_activationCount; | 477 return ++_activationCount; |
472 } | 478 } |
473 } | 479 } |
474 | 480 |
475 - (NSInteger)decrementActivationCount { | 481 - (NSInteger)decrementActivationCount { |
476 RTCLog(@"Decrementing activation count."); | 482 RTCLog(@"Decrementing activation count."); |
477 @synchronized(self) { | 483 @synchronized(self) { |
478 return --_activationCount; | 484 return --_activationCount; |
479 } | 485 } |
480 } | 486 } |
481 | 487 |
| 488 - (BOOL)checkLock:(NSError **)outError { |
| 489 // Check ivar instead of trying to acquire lock so that we won't accidentally |
| 490 // acquire lock if it hasn't already been called. |
| 491 if (!self.isLocked) { |
| 492 if (outError) { |
| 493 *outError = [RTCAudioSession lockError]; |
| 494 } |
| 495 return NO; |
| 496 } |
| 497 return YES; |
| 498 } |
| 499 |
482 - (void)updateAudioSessionAfterEvent { | 500 - (void)updateAudioSessionAfterEvent { |
483 BOOL shouldActivate = self.activationCount > 0; | 501 BOOL shouldActivate = self.activationCount > 0; |
484 AVAudioSessionSetActiveOptions options = shouldActivate ? | 502 AVAudioSessionSetActiveOptions options = shouldActivate ? |
485 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation; | 503 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation; |
486 NSError *error = nil; | 504 NSError *error = nil; |
487 if ([self.session setActive:shouldActivate | 505 if ([self.session setActive:shouldActivate |
488 withOptions:options | 506 withOptions:options |
489 error:&error]) { | 507 error:&error]) { |
490 self.isActive = shouldActivate; | 508 self.isActive = shouldActivate; |
491 } else { | 509 } else { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 } | 542 } |
525 } | 543 } |
526 | 544 |
527 - (void)notifyMediaServicesWereReset { | 545 - (void)notifyMediaServicesWereReset { |
528 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 546 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { |
529 [delegate audioSessionMediaServicesWereReset:self]; | 547 [delegate audioSessionMediaServicesWereReset:self]; |
530 } | 548 } |
531 } | 549 } |
532 | 550 |
533 @end | 551 @end |
OLD | NEW |