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

Side by Side Diff: webrtc/modules/audio_device/ios/objc/RTCAudioSession.mm

Issue 1945563003: Provide isAudioEnabled flag to control audio unit. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix some bluetooth issue. Created 4 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 unified diff | Download patch
OLDNEW
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/atomicops.h" 13 #include "webrtc/base/atomicops.h"
14 #include "webrtc/base/checks.h" 14 #include "webrtc/base/checks.h"
15 #include "webrtc/base/criticalsection.h" 15 #include "webrtc/base/criticalsection.h"
16 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" 16 #include "webrtc/modules/audio_device/ios/audio_device_ios.h"
17 17
18 #import "WebRTC/RTCLogging.h" 18 #import "WebRTC/RTCLogging.h"
19 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" 19 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h"
20 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSessionConfiguration.h"
20 21
21 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; 22 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession";
22 NSInteger const kRTCAudioSessionErrorLockRequired = -1; 23 NSInteger const kRTCAudioSessionErrorLockRequired = -1;
23 NSInteger const kRTCAudioSessionErrorConfiguration = -2; 24 NSInteger const kRTCAudioSessionErrorConfiguration = -2;
24 25
25 // This class needs to be thread-safe because it is accessed from many threads. 26 // This class needs to be thread-safe because it is accessed from many threads.
26 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of 27 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of
27 // lock contention so coarse locks should be fine for now. 28 // lock contention so coarse locks should be fine for now.
28 @implementation RTCAudioSession { 29 @implementation RTCAudioSession {
29 rtc::CriticalSection _crit; 30 rtc::CriticalSection _crit;
30 AVAudioSession *_session; 31 AVAudioSession *_session;
31 volatile int _activationCount; 32 volatile int _activationCount;
32 volatile int _lockRecursionCount; 33 volatile int _lockRecursionCount;
33 volatile int _webRTCSessionCount; 34 volatile int _webRTCSessionCount;
34 BOOL _isActive; 35 BOOL _isActive;
35 BOOL _shouldDelayAudioConfiguration; 36 BOOL _useManualAudio;
37 BOOL _isAudioEnabled;
38 BOOL _canPlayOrRecord;
36 } 39 }
37 40
38 @synthesize session = _session; 41 @synthesize session = _session;
39 @synthesize delegates = _delegates; 42 @synthesize delegates = _delegates;
40 @synthesize savedConfiguration = _savedConfiguration;
41 43
42 + (instancetype)sharedInstance { 44 + (instancetype)sharedInstance {
43 static dispatch_once_t onceToken; 45 static dispatch_once_t onceToken;
44 static RTCAudioSession *sharedInstance = nil; 46 static RTCAudioSession *sharedInstance = nil;
45 dispatch_once(&onceToken, ^{ 47 dispatch_once(&onceToken, ^{
46 sharedInstance = [[self alloc] init]; 48 sharedInstance = [[self alloc] init];
47 }); 49 });
48 return sharedInstance; 50 return sharedInstance;
49 } 51 }
50 52
(...skipping 23 matching lines...) Expand all
74 return self; 76 return self;
75 } 77 }
76 78
77 - (void)dealloc { 79 - (void)dealloc {
78 [[NSNotificationCenter defaultCenter] removeObserver:self]; 80 [[NSNotificationCenter defaultCenter] removeObserver:self];
79 } 81 }
80 82
81 - (NSString *)description { 83 - (NSString *)description {
82 NSString *format = 84 NSString *format =
83 @"RTCAudioSession: {\n" 85 @"RTCAudioSession: {\n"
86 " category: %@\n"
87 " categoryOptions: %ld\n"
88 " mode: %@\n"
84 " isActive: %d\n" 89 " isActive: %d\n"
85 " sampleRate: %.2f\n" 90 " sampleRate: %.2f\n"
86 " IOBufferDuration: %f\n" 91 " IOBufferDuration: %f\n"
87 " outputNumberOfChannels: %ld\n" 92 " outputNumberOfChannels: %ld\n"
88 " inputNumberOfChannels: %ld\n" 93 " inputNumberOfChannels: %ld\n"
89 " outputLatency: %f\n" 94 " outputLatency: %f\n"
90 " inputLatency: %f\n" 95 " inputLatency: %f\n"
91 "}"; 96 "}";
92 NSString *description = [NSString stringWithFormat:format, 97 NSString *description = [NSString stringWithFormat:format,
98 self.category, (long)self.categoryOptions, self.mode,
93 self.isActive, self.sampleRate, self.IOBufferDuration, 99 self.isActive, self.sampleRate, self.IOBufferDuration,
94 self.outputNumberOfChannels, self.inputNumberOfChannels, 100 self.outputNumberOfChannels, self.inputNumberOfChannels,
95 self.outputLatency, self.inputLatency]; 101 self.outputLatency, self.inputLatency];
96 return description; 102 return description;
97 } 103 }
98 104
99 - (void)setIsActive:(BOOL)isActive { 105 - (void)setIsActive:(BOOL)isActive {
100 @synchronized(self) { 106 @synchronized(self) {
101 _isActive = isActive; 107 _isActive = isActive;
102 } 108 }
103 } 109 }
104 110
105 - (BOOL)isActive { 111 - (BOOL)isActive {
106 @synchronized(self) { 112 @synchronized(self) {
107 return _isActive; 113 return _isActive;
108 } 114 }
109 } 115 }
110 116
111 - (BOOL)isLocked { 117 - (BOOL)isLocked {
112 return _lockRecursionCount > 0; 118 return _lockRecursionCount > 0;
113 } 119 }
114 120
115 - (void)setShouldDelayAudioConfiguration:(BOOL)shouldDelayAudioConfiguration { 121 - (void)setUseManualAudio:(BOOL)useManualAudio {
116 @synchronized(self) { 122 @synchronized(self) {
117 // No one should be changing this while an audio device is active. 123 if (_useManualAudio == useManualAudio) {
118 RTC_DCHECK(!self.isConfiguredForWebRTC);
119 if (_shouldDelayAudioConfiguration == shouldDelayAudioConfiguration) {
120 return; 124 return;
121 } 125 }
122 _shouldDelayAudioConfiguration = shouldDelayAudioConfiguration; 126 _useManualAudio = useManualAudio;
127 }
128 [self updateCanPlayOrRecord];
129 }
130
131 - (BOOL)useManualAudio {
132 @synchronized(self) {
133 return _useManualAudio;
123 } 134 }
124 } 135 }
125 136
126 - (BOOL)shouldDelayAudioConfiguration { 137 - (void)setIsAudioEnabled:(BOOL)isAudioEnabled {
127 @synchronized(self) { 138 @synchronized(self) {
128 return _shouldDelayAudioConfiguration; 139 if (_isAudioEnabled == isAudioEnabled) {
140 return;
141 }
142 _isAudioEnabled = isAudioEnabled;
143 }
144 [self updateCanPlayOrRecord];
145 }
146
147 - (BOOL)isAudioEnabled {
148 @synchronized(self) {
149 return _isAudioEnabled;
129 } 150 }
130 } 151 }
131 152
132 // TODO(tkchin): Check for duplicates. 153 // TODO(tkchin): Check for duplicates.
133 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { 154 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate {
134 if (!delegate) { 155 if (!delegate) {
135 return; 156 return;
136 } 157 }
137 @synchronized(self) { 158 @synchronized(self) {
138 _delegates.push_back(delegate); 159 _delegates.push_back(delegate);
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } 246 }
226 247
227 - (AVAudioSessionDataSourceDescription *)outputDataSource { 248 - (AVAudioSessionDataSourceDescription *)outputDataSource {
228 return self.session.outputDataSource; 249 return self.session.outputDataSource;
229 } 250 }
230 251
231 - (double)sampleRate { 252 - (double)sampleRate {
232 return self.session.sampleRate; 253 return self.session.sampleRate;
233 } 254 }
234 255
256 - (double)preferredSampleRate {
257 return self.session.preferredSampleRate;
258 }
259
235 - (NSInteger)inputNumberOfChannels { 260 - (NSInteger)inputNumberOfChannels {
236 return self.session.inputNumberOfChannels; 261 return self.session.inputNumberOfChannels;
237 } 262 }
238 263
239 - (NSInteger)outputNumberOfChannels { 264 - (NSInteger)outputNumberOfChannels {
240 return self.session.outputNumberOfChannels; 265 return self.session.outputNumberOfChannels;
241 } 266 }
242 267
243 - (float)outputVolume { 268 - (float)outputVolume {
244 return self.session.outputVolume; 269 return self.session.outputVolume;
245 } 270 }
246 271
247 - (NSTimeInterval)inputLatency { 272 - (NSTimeInterval)inputLatency {
248 return self.session.inputLatency; 273 return self.session.inputLatency;
249 } 274 }
250 275
251 - (NSTimeInterval)outputLatency { 276 - (NSTimeInterval)outputLatency {
252 return self.session.outputLatency; 277 return self.session.outputLatency;
253 } 278 }
254 279
255 - (NSTimeInterval)IOBufferDuration { 280 - (NSTimeInterval)IOBufferDuration {
256 return self.session.IOBufferDuration; 281 return self.session.IOBufferDuration;
257 } 282 }
258 283
284 - (NSTimeInterval)preferredIOBufferDuration {
285 return self.session.preferredIOBufferDuration;
286 }
287
259 // TODO(tkchin): Simplify the amount of locking happening here. Likely that we 288 // TODO(tkchin): Simplify the amount of locking happening here. Likely that we
260 // can just do atomic increments / decrements. 289 // can just do atomic increments / decrements.
261 - (BOOL)setActive:(BOOL)active 290 - (BOOL)setActive:(BOOL)active
262 error:(NSError **)outError { 291 error:(NSError **)outError {
263 if (![self checkLock:outError]) { 292 if (![self checkLock:outError]) {
264 return NO; 293 return NO;
265 } 294 }
266 int activationCount = _activationCount; 295 int activationCount = _activationCount;
267 if (!active && activationCount == 0) { 296 if (!active && activationCount == 0) {
268 RTCLogWarning(@"Attempting to deactivate without prior activation."); 297 RTCLogWarning(@"Attempting to deactivate without prior activation.");
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 return error; 519 return error;
491 } 520 }
492 521
493 - (std::vector<__weak id<RTCAudioSessionDelegate> >)delegates { 522 - (std::vector<__weak id<RTCAudioSessionDelegate> >)delegates {
494 @synchronized(self) { 523 @synchronized(self) {
495 // Note: this returns a copy. 524 // Note: this returns a copy.
496 return _delegates; 525 return _delegates;
497 } 526 }
498 } 527 }
499 528
500 - (void)setSavedConfiguration:(RTCAudioSessionConfiguration *)configuration {
501 @synchronized(self) {
502 if (_savedConfiguration == configuration) {
503 return;
504 }
505 _savedConfiguration = configuration;
506 }
507 }
508
509 - (RTCAudioSessionConfiguration *)savedConfiguration {
510 @synchronized(self) {
511 return _savedConfiguration;
512 }
513 }
514
515 // TODO(tkchin): check for duplicates. 529 // TODO(tkchin): check for duplicates.
516 - (void)pushDelegate:(id<RTCAudioSessionDelegate>)delegate { 530 - (void)pushDelegate:(id<RTCAudioSessionDelegate>)delegate {
517 @synchronized(self) { 531 @synchronized(self) {
518 _delegates.insert(_delegates.begin(), delegate); 532 _delegates.insert(_delegates.begin(), delegate);
519 } 533 }
520 } 534 }
521 535
522 - (void)removeZeroedDelegates { 536 - (void)removeZeroedDelegates {
523 @synchronized(self) { 537 @synchronized(self) {
524 _delegates.erase( 538 _delegates.erase(
(...skipping 15 matching lines...) Expand all
540 554
541 - (NSInteger)decrementActivationCount { 555 - (NSInteger)decrementActivationCount {
542 RTCLog(@"Decrementing activation count."); 556 RTCLog(@"Decrementing activation count.");
543 return rtc::AtomicOps::Decrement(&_activationCount); 557 return rtc::AtomicOps::Decrement(&_activationCount);
544 } 558 }
545 559
546 - (int)webRTCSessionCount { 560 - (int)webRTCSessionCount {
547 return _webRTCSessionCount; 561 return _webRTCSessionCount;
548 } 562 }
549 563
564 - (BOOL)canPlayOrRecord {
565 return !self.useManualAudio || self.isAudioEnabled;
566 }
567
550 - (BOOL)checkLock:(NSError **)outError { 568 - (BOOL)checkLock:(NSError **)outError {
551 // Check ivar instead of trying to acquire lock so that we won't accidentally 569 // Check ivar instead of trying to acquire lock so that we won't accidentally
552 // acquire lock if it hasn't already been called. 570 // acquire lock if it hasn't already been called.
553 if (!self.isLocked) { 571 if (!self.isLocked) {
554 if (outError) { 572 if (outError) {
555 *outError = [RTCAudioSession lockError]; 573 *outError = [RTCAudioSession lockError];
556 } 574 }
557 return NO; 575 return NO;
558 } 576 }
559 return YES; 577 return YES;
560 } 578 }
561 579
562 - (BOOL)beginWebRTCSession:(NSError **)outError { 580 - (BOOL)beginWebRTCSession:(NSError **)outError {
563 if (outError) { 581 if (outError) {
564 *outError = nil; 582 *outError = nil;
565 } 583 }
566 if (![self checkLock:outError]) { 584 if (![self checkLock:outError]) {
567 return NO; 585 return NO;
568 } 586 }
569 NSInteger sessionCount = rtc::AtomicOps::Increment(&_webRTCSessionCount); 587 rtc::AtomicOps::Increment(&_webRTCSessionCount);
570 if (sessionCount > 1) { 588 [self notifyDidStartPlayOrRecord];
571 // Should already be configured.
572 RTC_DCHECK(self.isConfiguredForWebRTC);
573 return YES;
574 }
575
576 // Only perform configuration steps once. Application might have already
577 // configured the session.
578 if (self.isConfiguredForWebRTC) {
579 // Nothing more to do, already configured.
580 return YES;
581 }
582
583 // If application has prevented automatic configuration, return here and wait
584 // for application to call configureWebRTCSession.
585 if (self.shouldDelayAudioConfiguration) {
586 [self notifyShouldConfigure];
587 return YES;
588 }
589
590 // Configure audio session.
591 NSError *error = nil;
592 if (![self configureWebRTCSession:&error]) {
593 RTCLogError(@"Error configuring audio session: %@",
594 error.localizedDescription);
595 if (outError) {
596 *outError = error;
597 }
598 return NO;
599 }
600
601 return YES; 589 return YES;
602 } 590 }
603 591
604 - (BOOL)endWebRTCSession:(NSError **)outError { 592 - (BOOL)endWebRTCSession:(NSError **)outError {
605 if (outError) { 593 if (outError) {
606 *outError = nil; 594 *outError = nil;
607 } 595 }
608 if (![self checkLock:outError]) { 596 if (![self checkLock:outError]) {
609 return NO; 597 return NO;
610 } 598 }
611 int sessionCount = rtc::AtomicOps::Decrement(&_webRTCSessionCount); 599 rtc::AtomicOps::Decrement(&_webRTCSessionCount);
612 RTC_DCHECK_GE(sessionCount, 0); 600 [self notifyDidStopPlayOrRecord];
613 if (sessionCount != 0) { 601 return YES;
614 // Should still be configured. 602 }
615 RTC_DCHECK(self.isConfiguredForWebRTC); 603
616 return YES; 604 - (BOOL)configureWebRTCSession:(NSError **)outError {
605 if (outError) {
606 *outError = nil;
617 } 607 }
608 if (![self checkLock:outError]) {
609 return NO;
610 }
611 RTCLog(@"Configuring audio session for WebRTC.");
618 612
619 // Only unconfigure if application has not done it. 613 // Configure the AVAudioSession and activate it.
620 if (!self.isConfiguredForWebRTC) { 614 // Provide an error even if there isn't one so we can log it.
621 // Nothing more to do, already unconfigured.
622 return YES;
623 }
624
625 // If application has prevented automatic configuration, return here and wait
626 // for application to call unconfigureWebRTCSession.
627 if (self.shouldDelayAudioConfiguration) {
628 [self notifyShouldUnconfigure];
629 return YES;
630 }
631
632 // Unconfigure audio session.
633 NSError *error = nil; 615 NSError *error = nil;
634 if (![self unconfigureWebRTCSession:&error]) { 616 RTCAudioSessionConfiguration *webRTCConfig =
635 RTCLogError(@"Error unconfiguring audio session: %@", 617 [RTCAudioSessionConfiguration webRTCConfiguration];
618 if (![self setConfiguration:webRTCConfig active:YES error:&error]) {
619 RTCLogError(@"Failed to set WebRTC audio configuration: %@",
636 error.localizedDescription); 620 error.localizedDescription);
621 [self unconfigureWebRTCSession:nil];
637 if (outError) { 622 if (outError) {
638 *outError = error; 623 *outError = error;
639 } 624 }
640 return NO; 625 return NO;
641 } 626 }
642 627
628 // Ensure that the device currently supports audio input.
629 // TODO(tkchin): Figure out if this is really necessary.
630 if (!self.inputAvailable) {
631 RTCLogError(@"No audio input path is available!");
632 [self unconfigureWebRTCSession:nil];
633 if (outError) {
634 *outError = [self configurationErrorWithDescription:@"No input path."];
635 }
636 return NO;
637 }
638
643 return YES; 639 return YES;
644 } 640 }
641
642 - (BOOL)unconfigureWebRTCSession:(NSError **)outError {
643 if (outError) {
644 *outError = nil;
645 }
646 if (![self checkLock:outError]) {
647 return NO;
648 }
649 RTCLog(@"Unconfiguring audio session for WebRTC.");
650 [self setActive:NO error:outError];
651
652 return YES;
653 }
645 654
646 - (NSError *)configurationErrorWithDescription:(NSString *)description { 655 - (NSError *)configurationErrorWithDescription:(NSString *)description {
647 NSDictionary* userInfo = @{ 656 NSDictionary* userInfo = @{
648 NSLocalizedDescriptionKey: description, 657 NSLocalizedDescriptionKey: description,
649 }; 658 };
650 return [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain 659 return [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain
651 code:kRTCAudioSessionErrorConfiguration 660 code:kRTCAudioSessionErrorConfiguration
652 userInfo:userInfo]; 661 userInfo:userInfo];
653 } 662 }
654 663
655 - (void)updateAudioSessionAfterEvent { 664 - (void)updateAudioSessionAfterEvent {
656 BOOL shouldActivate = self.activationCount > 0; 665 BOOL shouldActivate = self.activationCount > 0;
657 AVAudioSessionSetActiveOptions options = shouldActivate ? 666 AVAudioSessionSetActiveOptions options = shouldActivate ?
658 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation; 667 0 : AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation;
659 NSError *error = nil; 668 NSError *error = nil;
660 if ([self.session setActive:shouldActivate 669 if ([self.session setActive:shouldActivate
661 withOptions:options 670 withOptions:options
662 error:&error]) { 671 error:&error]) {
663 self.isActive = shouldActivate; 672 self.isActive = shouldActivate;
664 } else { 673 } else {
665 RTCLogError(@"Failed to set session active to %d. Error:%@", 674 RTCLogError(@"Failed to set session active to %d. Error:%@",
666 shouldActivate, error.localizedDescription); 675 shouldActivate, error.localizedDescription);
667 } 676 }
668 } 677 }
669 678
679 - (void)updateCanPlayOrRecord {
680 BOOL canPlayOrRecord = NO;
681 BOOL shouldNotify = NO;
682 @synchronized(self) {
683 canPlayOrRecord = !self.useManualAudio || self.isAudioEnabled;
684 if (_canPlayOrRecord == canPlayOrRecord) {
685 return;
686 }
687 _canPlayOrRecord = canPlayOrRecord;
688 shouldNotify = YES;
689 }
690 if (shouldNotify) {
691 [self notifyDidChangeCanPlayOrRecord:canPlayOrRecord];
692 }
693 }
694
670 - (void)notifyDidBeginInterruption { 695 - (void)notifyDidBeginInterruption {
671 for (auto delegate : self.delegates) { 696 for (auto delegate : self.delegates) {
672 SEL sel = @selector(audioSessionDidBeginInterruption:); 697 SEL sel = @selector(audioSessionDidBeginInterruption:);
673 if ([delegate respondsToSelector:sel]) { 698 if ([delegate respondsToSelector:sel]) {
674 [delegate audioSessionDidBeginInterruption:self]; 699 [delegate audioSessionDidBeginInterruption:self];
675 } 700 }
676 } 701 }
677 } 702 }
678 703
679 - (void)notifyDidEndInterruptionWithShouldResumeSession: 704 - (void)notifyDidEndInterruptionWithShouldResumeSession:
(...skipping 30 matching lines...) Expand all
710 735
711 - (void)notifyMediaServicesWereReset { 736 - (void)notifyMediaServicesWereReset {
712 for (auto delegate : self.delegates) { 737 for (auto delegate : self.delegates) {
713 SEL sel = @selector(audioSessionMediaServicesWereReset:); 738 SEL sel = @selector(audioSessionMediaServicesWereReset:);
714 if ([delegate respondsToSelector:sel]) { 739 if ([delegate respondsToSelector:sel]) {
715 [delegate audioSessionMediaServicesWereReset:self]; 740 [delegate audioSessionMediaServicesWereReset:self];
716 } 741 }
717 } 742 }
718 } 743 }
719 744
720 - (void)notifyShouldConfigure { 745 - (void)notifyDidChangeCanPlayOrRecord:(BOOL)canPlayOrRecord {
721 for (auto delegate : self.delegates) { 746 for (auto delegate : self.delegates) {
722 SEL sel = @selector(audioSessionShouldConfigure:); 747 SEL sel = @selector(audioSession:didChangeCanPlayOrRecord:);
723 if ([delegate respondsToSelector:sel]) { 748 if ([delegate respondsToSelector:sel]) {
724 [delegate audioSessionShouldConfigure:self]; 749 [delegate audioSession:self didChangeCanPlayOrRecord:canPlayOrRecord];
725 } 750 }
726 } 751 }
727 } 752 }
728 753
729 - (void)notifyShouldUnconfigure { 754 - (void)notifyDidStartPlayOrRecord {
730 for (auto delegate : self.delegates) { 755 for (auto delegate : self.delegates) {
731 SEL sel = @selector(audioSessionShouldUnconfigure:); 756 SEL sel = @selector(audioSessionDidStartPlayOrRecord:);
732 if ([delegate respondsToSelector:sel]) { 757 if ([delegate respondsToSelector:sel]) {
733 [delegate audioSessionShouldUnconfigure:self]; 758 [delegate audioSessionDidStartPlayOrRecord:self];
734 } 759 }
735 } 760 }
736 } 761 }
737 762
738 - (void)notifyDidConfigure { 763 - (void)notifyDidStopPlayOrRecord {
739 for (auto delegate : self.delegates) { 764 for (auto delegate : self.delegates) {
740 SEL sel = @selector(audioSessionDidConfigure:); 765 SEL sel = @selector(audioSessionDidStopPlayOrRecord:);
741 if ([delegate respondsToSelector:sel]) { 766 if ([delegate respondsToSelector:sel]) {
742 [delegate audioSessionDidConfigure:self]; 767 [delegate audioSessionDidStopPlayOrRecord:self];
743 } 768 }
744 } 769 }
745 } 770 }
746
747 - (void)notifyDidUnconfigure {
748 for (auto delegate : self.delegates) {
749 SEL sel = @selector(audioSessionDidUnconfigure:);
750 if ([delegate respondsToSelector:sel]) {
751 [delegate audioSessionDidUnconfigure:self];
752 }
753 }
754 }
755 771
756 @end 772 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698