forked from livekit/react-native-webrtc
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathWebRTCModule+AudioTrackAdapter.m
More file actions
114 lines (93 loc) · 3.97 KB
/
WebRTCModule+AudioTrackAdapter.m
File metadata and controls
114 lines (93 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <stdatomic.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTLog.h>
#import <WebRTC/RTCAudioRenderer.h>
#import <WebRTC/RTCAudioTrack.h>
#import "WebRTCModule+AudioTrackAdapter.h"
#import "WebRTCModule+RTCPeerConnection.h"
#import "WebRTCModule.h"
/* Fires the W3C 'unmute' event on a remote audio track when the first
* decoded PCM buffer arrives via RTCAudioRenderer.
*
* IMPORTANT — only the initial muted → unmuted transition is detectable.
* Subsequent mute events (network stall mid-call) cannot be detected
* from the renderer: the iOS audio render path and WebRTC's NetEq
* synthesize silence / PLC frames whenever RTP stops, so
* renderPCMBuffer: keeps firing at a steady rate regardless of network
* state. For "remote participant muted their mic" UI, use the
* out-of-band participant state from your signaling layer — that is the
* correct source of truth, not this adapter.
*/
@interface FirstBufferUnmuteRenderer : NSObject<RTCAudioRenderer>
@property(copy, nonatomic) NSNumber *peerConnectionId;
@property(copy, nonatomic) NSString *trackId;
@property(weak, nonatomic) WebRTCModule *module;
- (instancetype)initWith:(NSNumber *)peerConnectionId
trackId:(NSString *)trackId
webRTCModule:(WebRTCModule *)module;
@end
@implementation FirstBufferUnmuteRenderer {
atomic_flag _fired;
}
- (instancetype)initWith:(NSNumber *)peerConnectionId
trackId:(NSString *)trackId
webRTCModule:(WebRTCModule *)module {
self = [super init];
if (self) {
self.peerConnectionId = peerConnectionId;
self.trackId = trackId;
self.module = module;
atomic_flag_clear(&_fired);
}
return self;
}
- (void)renderPCMBuffer:(AVAudioPCMBuffer *)pcmBuffer {
if (atomic_flag_test_and_set(&_fired)) {
return;
}
[self.module sendEventWithName:kEventMediaStreamTrackMuteChanged
body:@{
@"pcId" : self.peerConnectionId,
@"trackId" : self.trackId,
@"muted" : @NO
}];
RCTLog(@"[AudioTrackAdapter] Unmute event for pc %@ track %@", self.peerConnectionId, self.trackId);
}
@end
@implementation RTCPeerConnection (AudioTrackAdapter)
- (NSMutableDictionary<NSString *, id> *)audioTrackAdapters {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setAudioTrackAdapters:(NSMutableDictionary<NSString *, id> *)audioTrackAdapters {
objc_setAssociatedObject(
self, @selector(audioTrackAdapters), audioTrackAdapters, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)addAudioTrackAdapter:(RTCAudioTrack *)track {
NSString *trackId = track.trackId;
if ([self.audioTrackAdapters objectForKey:trackId] != nil) {
RCTLogWarn(@"[AudioTrackAdapter] Adapter already exists for track %@", trackId);
return;
}
FirstBufferUnmuteRenderer *renderer = [[FirstBufferUnmuteRenderer alloc] initWith:self.reactTag
trackId:trackId
webRTCModule:self.webRTCModule];
[self.audioTrackAdapters setObject:renderer forKey:trackId];
[track addRenderer:renderer];
RCTLogTrace(@"[AudioTrackAdapter] Adapter created for track %@", trackId);
}
- (void)removeAudioTrackAdapter:(RTCAudioTrack *)track {
NSString *trackId = track.trackId;
FirstBufferUnmuteRenderer *renderer = [self.audioTrackAdapters objectForKey:trackId];
if (renderer == nil) {
RCTLogWarn(@"[AudioTrackAdapter] Adapter doesn't exist for track %@", trackId);
return;
}
[track removeRenderer:renderer];
[self.audioTrackAdapters removeObjectForKey:trackId];
RCTLogTrace(@"[AudioTrackAdapter] Adapter removed for track %@", trackId);
}
@end