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 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" | |
15 | 16 |
16 #import "webrtc/base/objc/RTCLogging.h" | 17 #import "webrtc/base/objc/RTCLogging.h" |
17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" | 18 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" |
18 | 19 |
19 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; | 20 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; |
20 NSInteger const kRTCAudioSessionErrorLockRequired = -1; | 21 NSInteger const kRTCAudioSessionErrorLockRequired = -1; |
21 NSInteger const kRTCAudioSessionErrorConfiguration = -2; | 22 NSInteger const kRTCAudioSessionErrorConfiguration = -2; |
22 | 23 |
23 // This class needs to be thread-safe because it is accessed from many threads. | 24 // This class needs to be thread-safe because it is accessed from many threads. |
24 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of | 25 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of |
25 // lock contention so coarse locks should be fine for now. | 26 // lock contention so coarse locks should be fine for now. |
26 @implementation RTCAudioSession { | 27 @implementation RTCAudioSession { |
27 rtc::CriticalSection _crit; | 28 rtc::CriticalSection _crit; |
28 AVAudioSession *_session; | 29 AVAudioSession *_session; |
29 NSHashTable *_delegates; | |
30 NSInteger _activationCount; | 30 NSInteger _activationCount; |
31 NSInteger _lockRecursionCount; | 31 NSInteger _lockRecursionCount; |
32 BOOL _isActive; | 32 BOOL _isActive; |
33 BOOL _shouldDelayAudioConfiguration; | 33 BOOL _shouldDelayAudioConfiguration; |
34 } | 34 } |
35 | 35 |
36 @synthesize session = _session; | 36 @synthesize session = _session; |
37 @synthesize delegates = _delegates; | |
Chuck
2016/03/15 14:33:21
Where does _delegates get initialized?
tkchin_webrtc
2016/03/15 20:14:58
It's on the stack so it's ctor gets called automat
| |
37 | 38 |
38 + (instancetype)sharedInstance { | 39 + (instancetype)sharedInstance { |
39 static dispatch_once_t onceToken; | 40 static dispatch_once_t onceToken; |
40 static RTCAudioSession *sharedInstance = nil; | 41 static RTCAudioSession *sharedInstance = nil; |
41 dispatch_once(&onceToken, ^{ | 42 dispatch_once(&onceToken, ^{ |
42 sharedInstance = [[RTCAudioSession alloc] init]; | 43 sharedInstance = [[RTCAudioSession alloc] init]; |
43 }); | 44 }); |
44 return sharedInstance; | 45 return sharedInstance; |
45 } | 46 } |
46 | 47 |
47 - (instancetype)init { | 48 - (instancetype)init { |
48 if (self = [super init]) { | 49 if (self = [super init]) { |
49 _session = [AVAudioSession sharedInstance]; | 50 _session = [AVAudioSession sharedInstance]; |
50 _delegates = [NSHashTable weakObjectsHashTable]; | |
51 | 51 |
52 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; | 52 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; |
53 [center addObserver:self | 53 [center addObserver:self |
54 selector:@selector(handleInterruptionNotification:) | 54 selector:@selector(handleInterruptionNotification:) |
55 name:AVAudioSessionInterruptionNotification | 55 name:AVAudioSessionInterruptionNotification |
56 object:nil]; | 56 object:nil]; |
57 [center addObserver:self | 57 [center addObserver:self |
58 selector:@selector(handleRouteChangeNotification:) | 58 selector:@selector(handleRouteChangeNotification:) |
59 name:AVAudioSessionRouteChangeNotification | 59 name:AVAudioSessionRouteChangeNotification |
60 object:nil]; | 60 object:nil]; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 } | 102 } |
103 } | 103 } |
104 | 104 |
105 - (BOOL)shouldDelayAudioConfiguration { | 105 - (BOOL)shouldDelayAudioConfiguration { |
106 @synchronized(self) { | 106 @synchronized(self) { |
107 return _shouldDelayAudioConfiguration; | 107 return _shouldDelayAudioConfiguration; |
108 } | 108 } |
109 } | 109 } |
110 | 110 |
111 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { | 111 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { |
112 if (!delegate) { | |
113 return; | |
114 } | |
112 @synchronized(self) { | 115 @synchronized(self) { |
113 [_delegates addObject:delegate]; | 116 _delegates.push_back(delegate); |
117 [self removeZeroedDelegates]; | |
114 } | 118 } |
115 } | 119 } |
116 | 120 |
117 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { | 121 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { |
122 if (!delegate) { | |
123 return; | |
124 } | |
118 @synchronized(self) { | 125 @synchronized(self) { |
119 [_delegates removeObject:delegate]; | 126 _delegates.erase(std::remove(_delegates.begin(), |
127 _delegates.end(), | |
128 delegate)); | |
129 [self removeZeroedDelegates]; | |
120 } | 130 } |
121 } | 131 } |
122 | 132 |
123 - (void)lockForConfiguration { | 133 - (void)lockForConfiguration { |
124 _crit.Enter(); | 134 _crit.Enter(); |
125 @synchronized(self) { | 135 @synchronized(self) { |
126 ++_lockRecursionCount; | 136 ++_lockRecursionCount; |
127 } | 137 } |
128 } | 138 } |
129 | 139 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 } | 230 } |
221 | 231 |
222 - (NSTimeInterval)outputLatency { | 232 - (NSTimeInterval)outputLatency { |
223 return self.session.outputLatency; | 233 return self.session.outputLatency; |
224 } | 234 } |
225 | 235 |
226 - (NSTimeInterval)IOBufferDuration { | 236 - (NSTimeInterval)IOBufferDuration { |
227 return self.session.IOBufferDuration; | 237 return self.session.IOBufferDuration; |
228 } | 238 } |
229 | 239 |
240 // TODO(tkchin): Simplify the amount of locking happening here. Likely that we | |
241 // can just do atomic increments / decrements. | |
230 - (BOOL)setActive:(BOOL)active | 242 - (BOOL)setActive:(BOOL)active |
231 error:(NSError **)outError { | 243 error:(NSError **)outError { |
232 if (![self checkLock:outError]) { | 244 if (![self checkLock:outError]) { |
233 return NO; | 245 return NO; |
234 } | 246 } |
235 NSInteger activationCount = self.activationCount; | 247 NSInteger activationCount = self.activationCount; |
236 if (!active && activationCount == 0) { | 248 if (!active && activationCount == 0) { |
237 RTCLogWarning(@"Attempting to deactivate without prior activation."); | 249 RTCLogWarning(@"Attempting to deactivate without prior activation."); |
238 } | 250 } |
239 BOOL success = YES; | 251 BOOL success = YES; |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 NSLocalizedDescriptionKey: | 464 NSLocalizedDescriptionKey: |
453 @"Must call lockForConfiguration before calling this method." | 465 @"Must call lockForConfiguration before calling this method." |
454 }; | 466 }; |
455 NSError *error = | 467 NSError *error = |
456 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain | 468 [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain |
457 code:kRTCAudioSessionErrorLockRequired | 469 code:kRTCAudioSessionErrorLockRequired |
458 userInfo:userInfo]; | 470 userInfo:userInfo]; |
459 return error; | 471 return error; |
460 } | 472 } |
461 | 473 |
462 - (NSSet *)delegates { | 474 - (std::vector<__weak id<RTCAudioSessionDelegate> >)delegates { |
Chuck
2016/03/15 14:33:21
Does the set for this property need to be synchron
tkchin_webrtc
2016/03/15 20:14:58
Thanks for catching that. No setter.
| |
463 @synchronized(self) { | 475 @synchronized(self) { |
464 return _delegates.setRepresentation; | 476 return _delegates; |
465 } | 477 } |
466 } | 478 } |
467 | 479 |
480 - (void)pushDelegate:(id<RTCAudioSessionDelegate>)delegate { | |
481 @synchronized(self) { | |
482 _delegates.insert(_delegates.begin(), delegate); | |
483 } | |
484 } | |
485 | |
486 - (void)removeZeroedDelegates { | |
487 @synchronized(self) { | |
488 for (auto it = _delegates.begin(); it != _delegates.end(); ++it) { | |
489 if (!*it) { | |
490 _delegates.erase(it); | |
491 } | |
492 } | |
493 } | |
494 } | |
495 | |
468 - (NSInteger)activationCount { | 496 - (NSInteger)activationCount { |
469 @synchronized(self) { | 497 @synchronized(self) { |
470 return _activationCount; | 498 return _activationCount; |
471 } | 499 } |
472 } | 500 } |
473 | 501 |
474 - (NSInteger)incrementActivationCount { | 502 - (NSInteger)incrementActivationCount { |
475 RTCLog(@"Incrementing activation count."); | 503 RTCLog(@"Incrementing activation count."); |
476 @synchronized(self) { | 504 @synchronized(self) { |
477 return ++_activationCount; | 505 return ++_activationCount; |
(...skipping 28 matching lines...) Expand all Loading... | |
506 withOptions:options | 534 withOptions:options |
507 error:&error]) { | 535 error:&error]) { |
508 self.isActive = shouldActivate; | 536 self.isActive = shouldActivate; |
509 } else { | 537 } else { |
510 RTCLogError(@"Failed to set session active to %d. Error:%@", | 538 RTCLogError(@"Failed to set session active to %d. Error:%@", |
511 shouldActivate, error.localizedDescription); | 539 shouldActivate, error.localizedDescription); |
512 } | 540 } |
513 } | 541 } |
514 | 542 |
515 - (void)notifyDidBeginInterruption { | 543 - (void)notifyDidBeginInterruption { |
516 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 544 for (auto delegate : self.delegates) { |
517 [delegate audioSessionDidBeginInterruption:self]; | 545 [delegate audioSessionDidBeginInterruption:self]; |
518 } | 546 } |
519 } | 547 } |
520 | 548 |
521 - (void)notifyDidEndInterruptionWithShouldResumeSession: | 549 - (void)notifyDidEndInterruptionWithShouldResumeSession: |
522 (BOOL)shouldResumeSession { | 550 (BOOL)shouldResumeSession { |
523 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 551 for (auto delegate : self.delegates) { |
524 [delegate audioSessionDidEndInterruption:self | 552 [delegate audioSessionDidEndInterruption:self |
525 shouldResumeSession:shouldResumeSession]; | 553 shouldResumeSession:shouldResumeSession]; |
526 } | 554 } |
527 | 555 |
528 } | 556 } |
529 | 557 |
530 - (void)notifyDidChangeRouteWithReason:(AVAudioSessionRouteChangeReason)reason | 558 - (void)notifyDidChangeRouteWithReason:(AVAudioSessionRouteChangeReason)reason |
531 previousRoute:(AVAudioSessionRouteDescription *)previousRoute { | 559 previousRoute:(AVAudioSessionRouteDescription *)previousRoute { |
532 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 560 for (auto delegate : self.delegates) { |
533 [delegate audioSessionDidChangeRoute:self | 561 [delegate audioSessionDidChangeRoute:self |
534 reason:reason | 562 reason:reason |
535 previousRoute:previousRoute]; | 563 previousRoute:previousRoute]; |
536 } | 564 } |
537 } | 565 } |
538 | 566 |
539 - (void)notifyMediaServicesWereLost { | 567 - (void)notifyMediaServicesWereLost { |
540 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 568 for (auto delegate : self.delegates) { |
541 [delegate audioSessionMediaServicesWereLost:self]; | 569 [delegate audioSessionMediaServicesWereLost:self]; |
542 } | 570 } |
543 } | 571 } |
544 | 572 |
545 - (void)notifyMediaServicesWereReset { | 573 - (void)notifyMediaServicesWereReset { |
546 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 574 for (auto delegate : self.delegates) { |
547 [delegate audioSessionMediaServicesWereReset:self]; | 575 [delegate audioSessionMediaServicesWereReset:self]; |
548 } | 576 } |
549 } | 577 } |
550 | 578 |
551 @end | 579 @end |
OLD | NEW |