Skip to content

Commit d46511f

Browse files
santhoshvaigreenfrvrhiroshihorie
authored
fix: handle mute state management along with callkit (#24)
## Overview Change muteMode to inputMixer, this plays well along with callkit.. Here is the explanation of the modes ``` public enum MicrophoneMuteMode { /// Uses `AVAudioEngine`'s `isVoiceProcessingInputMuted` internally. /// This is fast, and muted speaker detection works. However, iOS will play a sound effect. /// Does not reconfigure the audio session on mute/unmute. case voiceProcessing /// Restarts the internal `AVAudioEngine` without mic input when muted. /// This is slower, and muted speaker detection does not work. No sound effect is played. /// Deactivates the audio session on mute and reconfigures it on unmute. case restart /// Simply mutes the output of the input mixer. /// The mic indicator remains on, and the internal `AVAudioEngine` continues running /// without reconfiguration. /// Does not reconfigure the audio session on mute/unmute. /// No sound effect is played. case inputMixer } ``` ## Why? voiceProcessing in our test, doesnt work will callkit well. When we do a track.release() or track.diable() now: It automatically triggers callkit setMuted to true and then soon it reverts to false.. ## Additional I added RN event senders for AudioEngine, but its currently unused in Stream SDK. its for future, where we can listen to speaking while muted and audio levels from native level ## Future We would likely revert the change in the future. When we get the Audio LLC from Stream-Swift-Video-SDK <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added audio device module events for monitoring speech activity, engine state transitions, audio processing updates, and device changes. * Added frame cryption state change events. * Introduced typed event listeners for audio device monitoring on iOS/macOS platforms. * **Chores** * Version bump to 137.1.2-alpha.1. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com> Co-authored-by: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com>
1 parent 3bab881 commit d46511f

File tree

9 files changed

+485
-15
lines changed

9 files changed

+485
-15
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#import <WebRTC/WebRTC.h>
2+
#import "WebRTCModule.h"
3+
4+
NS_ASSUME_NONNULL_BEGIN
5+
6+
@interface AudioDeviceModuleObserver : NSObject<RTCAudioDeviceModuleDelegate>
7+
8+
- (instancetype)initWithWebRTCModule:(WebRTCModule *)module;
9+
10+
@end
11+
12+
NS_ASSUME_NONNULL_END
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#import "AudioDeviceModuleObserver.h"
2+
#import <React/RCTLog.h>
3+
4+
NS_ASSUME_NONNULL_BEGIN
5+
6+
@interface AudioDeviceModuleObserver ()
7+
8+
@property(weak, nonatomic) WebRTCModule *module;
9+
10+
@end
11+
12+
@implementation AudioDeviceModuleObserver
13+
14+
- (instancetype)initWithWebRTCModule:(WebRTCModule *)module {
15+
self = [super init];
16+
if (self) {
17+
self.module = module;
18+
RCTLog(@"[AudioDeviceModuleObserver] Initialized observer: %@ for module: %@", self, module);
19+
}
20+
return self;
21+
}
22+
23+
#pragma mark - RTCAudioDeviceModuleDelegate
24+
25+
- (void)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
26+
didReceiveSpeechActivityEvent:(RTCSpeechActivityEvent)speechActivityEvent {
27+
NSString *eventType = speechActivityEvent == RTCSpeechActivityEventStarted ? @"started" : @"ended";
28+
29+
if (self.module.bridge != nil) {
30+
[self.module sendEventWithName:kEventAudioDeviceModuleSpeechActivity
31+
body:@{
32+
@"event" : eventType,
33+
}];
34+
}
35+
36+
RCTLog(@"[AudioDeviceModuleObserver] Speech activity event: %@", eventType);
37+
}
38+
39+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule didCreateEngine:(AVAudioEngine *)engine {
40+
RCTLog(@"[AudioDeviceModuleObserver] Engine created");
41+
42+
if (self.module.bridge != nil) {
43+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineCreated body:@{}];
44+
}
45+
46+
return 0; // Success
47+
}
48+
49+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
50+
willEnableEngine:(AVAudioEngine *)engine
51+
isPlayoutEnabled:(BOOL)isPlayoutEnabled
52+
isRecordingEnabled:(BOOL)isRecordingEnabled {
53+
RCTLog(@"[AudioDeviceModuleObserver] Engine will enable - playout: %d, recording: %d",
54+
isPlayoutEnabled,
55+
isRecordingEnabled);
56+
57+
if (self.module.bridge != nil) {
58+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineWillEnable
59+
body:@{
60+
@"isPlayoutEnabled" : @(isPlayoutEnabled),
61+
@"isRecordingEnabled" : @(isRecordingEnabled),
62+
}];
63+
}
64+
65+
return 0; // Success
66+
}
67+
68+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
69+
willStartEngine:(AVAudioEngine *)engine
70+
isPlayoutEnabled:(BOOL)isPlayoutEnabled
71+
isRecordingEnabled:(BOOL)isRecordingEnabled {
72+
RCTLog(@"[AudioDeviceModuleObserver] Engine will start - playout: %d, recording: %d",
73+
isPlayoutEnabled,
74+
isRecordingEnabled);
75+
76+
if (self.module.bridge != nil) {
77+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineWillStart
78+
body:@{
79+
@"isPlayoutEnabled" : @(isPlayoutEnabled),
80+
@"isRecordingEnabled" : @(isRecordingEnabled),
81+
}];
82+
}
83+
84+
return 0; // Success
85+
}
86+
87+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
88+
didStopEngine:(AVAudioEngine *)engine
89+
isPlayoutEnabled:(BOOL)isPlayoutEnabled
90+
isRecordingEnabled:(BOOL)isRecordingEnabled {
91+
RCTLog(@"[AudioDeviceModuleObserver] Engine did stop - playout: %d, recording: %d",
92+
isPlayoutEnabled,
93+
isRecordingEnabled);
94+
95+
if (self.module.bridge != nil) {
96+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineDidStop
97+
body:@{
98+
@"isPlayoutEnabled" : @(isPlayoutEnabled),
99+
@"isRecordingEnabled" : @(isRecordingEnabled),
100+
}];
101+
}
102+
103+
return 0; // Success
104+
}
105+
106+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
107+
didDisableEngine:(AVAudioEngine *)engine
108+
isPlayoutEnabled:(BOOL)isPlayoutEnabled
109+
isRecordingEnabled:(BOOL)isRecordingEnabled {
110+
RCTLog(@"[AudioDeviceModuleObserver] Engine did disable - playout: %d, recording: %d",
111+
isPlayoutEnabled,
112+
isRecordingEnabled);
113+
114+
if (self.module.bridge != nil) {
115+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineDidDisable
116+
body:@{
117+
@"isPlayoutEnabled" : @(isPlayoutEnabled),
118+
@"isRecordingEnabled" : @(isRecordingEnabled),
119+
}];
120+
}
121+
122+
return 0; // Success
123+
}
124+
125+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule willReleaseEngine:(AVAudioEngine *)engine {
126+
RCTLog(@"[AudioDeviceModuleObserver] Engine will release");
127+
128+
if (self.module.bridge != nil) {
129+
[self.module sendEventWithName:kEventAudioDeviceModuleEngineWillRelease body:@{}];
130+
}
131+
132+
return 0; // Success
133+
}
134+
135+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
136+
engine:(AVAudioEngine *)engine
137+
configureInputFromSource:(nullable AVAudioNode *)source
138+
toDestination:(AVAudioNode *)destination
139+
withFormat:(AVAudioFormat *)format
140+
context:(NSDictionary *)context {
141+
RCTLog(@"[AudioDeviceModuleObserver] Configure input - format: %@", format);
142+
return 0;
143+
}
144+
145+
- (NSInteger)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
146+
engine:(AVAudioEngine *)engine
147+
configureOutputFromSource:(AVAudioNode *)source
148+
toDestination:(nullable AVAudioNode *)destination
149+
withFormat:(AVAudioFormat *)format
150+
context:(NSDictionary *)context {
151+
RCTLog(@"[AudioDeviceModuleObserver] Configure output - format: %@", format);
152+
return 0;
153+
}
154+
155+
- (void)audioDeviceModuleDidUpdateDevices:(RTCAudioDeviceModule *)audioDeviceModule {
156+
if (self.module.bridge != nil) {
157+
[self.module sendEventWithName:kEventAudioDeviceModuleDevicesUpdated body:@{}];
158+
}
159+
160+
RCTLog(@"[AudioDeviceModuleObserver] Devices updated");
161+
}
162+
163+
- (void)audioDeviceModule:(RTCAudioDeviceModule *)audioDeviceModule
164+
didUpdateAudioProcessingState:(RTCAudioProcessingState)state {
165+
if (self.module.bridge != nil) {
166+
[self.module sendEventWithName:kEventAudioDeviceModuleAudioProcessingStateUpdated
167+
body:@{
168+
@"voiceProcessingEnabled" : @(state.voiceProcessingEnabled),
169+
@"voiceProcessingBypassed" : @(state.voiceProcessingBypassed),
170+
@"voiceProcessingAGCEnabled" : @(state.voiceProcessingAGCEnabled),
171+
@"stereoPlayoutEnabled" : @(state.stereoPlayoutEnabled),
172+
}];
173+
}
174+
175+
RCTLog(@"[AudioDeviceModuleObserver] Audio processing state updated - VP enabled: %d, VP bypassed: %d, AGC enabled: %d, stereo: %d",
176+
state.voiceProcessingEnabled,
177+
state.voiceProcessingBypassed,
178+
state.voiceProcessingAGCEnabled,
179+
state.stereoPlayoutEnabled);
180+
}
181+
182+
@end
183+
184+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)