@sbhjt-gr/react-native-webrtc 137.0.3 → 137.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +101 -1
- package/ios/RCTWebRTC/WLVAudioDevice.h +8 -0
- package/ios/RCTWebRTC/WLVAudioDevice.m +201 -0
- package/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +183 -1
- package/ios/RCTWebRTC/WebRTCModule.h +3 -0
- package/ios/RCTWebRTC/WebRTCModule.m +18 -0
- package/ios/RCTWebRTC.xcodeproj/project.pbxproj +6 -0
- package/lib/commonjs/EventEmitter.js +3 -1
- package/lib/commonjs/EventEmitter.js.map +1 -1
- package/lib/commonjs/MediaDevices.js +13 -0
- package/lib/commonjs/MediaDevices.js.map +1 -1
- package/lib/commonjs/MediaStreamTrack.js.map +1 -1
- package/lib/module/EventEmitter.js +3 -1
- package/lib/module/EventEmitter.js.map +1 -1
- package/lib/module/MediaDevices.js +13 -0
- package/lib/module/MediaDevices.js.map +1 -1
- package/lib/module/MediaStreamTrack.js.map +1 -1
- package/lib/typescript/MediaDevices.d.ts +15 -0
- package/lib/typescript/MediaStreamTrack.d.ts +2 -0
- package/package.json +1 -1
- package/src/EventEmitter.ts +7 -3
- package/src/MediaDevices.ts +33 -0
- package/src/MediaStreamTrack.ts +6 -3
|
@@ -27,6 +27,7 @@ import com.oney.WebRTCModule.webrtcutils.H264AndSoftwareVideoEncoderFactory;
|
|
|
27
27
|
import org.webrtc.AddIceObserver;
|
|
28
28
|
import org.webrtc.AudioProcessingFactory;
|
|
29
29
|
import org.webrtc.AudioTrack;
|
|
30
|
+
import org.webrtc.AudioTrackSink;
|
|
30
31
|
import org.webrtc.CryptoOptions;
|
|
31
32
|
import org.webrtc.EglBase;
|
|
32
33
|
import org.webrtc.IceCandidate;
|
|
@@ -52,12 +53,17 @@ import org.webrtc.VideoTrack;
|
|
|
52
53
|
import org.webrtc.audio.AudioDeviceModule;
|
|
53
54
|
import org.webrtc.audio.JavaAudioDeviceModule;
|
|
54
55
|
|
|
56
|
+
import java.nio.ByteBuffer;
|
|
57
|
+
import java.nio.ByteOrder;
|
|
58
|
+
import java.nio.IntBuffer;
|
|
59
|
+
import java.nio.ShortBuffer;
|
|
55
60
|
import java.util.ArrayList;
|
|
56
61
|
import java.util.HashMap;
|
|
57
62
|
import java.util.List;
|
|
58
63
|
import java.util.Map;
|
|
59
64
|
import java.util.Objects;
|
|
60
65
|
import java.util.concurrent.Callable;
|
|
66
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
61
67
|
import java.util.concurrent.ExecutionException;
|
|
62
68
|
|
|
63
69
|
@ReactModule(name = "WebRTCModule")
|
|
@@ -72,6 +78,7 @@ public class WebRTCModule extends ReactContextBaseJavaModule {
|
|
|
72
78
|
// Need to expose the peer connection codec factories here to get capabilities
|
|
73
79
|
private final SparseArray<PeerConnectionObserver> mPeerConnectionObservers;
|
|
74
80
|
final Map<String, MediaStream> localStreams;
|
|
81
|
+
private final Map<String, AudioTrackSink> audioSinkMap = new ConcurrentHashMap<>();
|
|
75
82
|
|
|
76
83
|
private final GetUserMediaImpl getUserMediaImpl;
|
|
77
84
|
|
|
@@ -479,6 +486,10 @@ public class WebRTCModule extends ReactContextBaseJavaModule {
|
|
|
479
486
|
return pco.remoteTracks.get(trackId);
|
|
480
487
|
}
|
|
481
488
|
|
|
489
|
+
private String audioSinkKey(int pcId, String trackId) {
|
|
490
|
+
return pcId + ":" + trackId;
|
|
491
|
+
}
|
|
492
|
+
|
|
482
493
|
MediaStreamTrack getLocalTrack(String trackId) {
|
|
483
494
|
return getUserMediaImpl.getTrack(trackId);
|
|
484
495
|
}
|
|
@@ -971,9 +982,98 @@ public class WebRTCModule extends ReactContextBaseJavaModule {
|
|
|
971
982
|
});
|
|
972
983
|
}
|
|
973
984
|
|
|
985
|
+
private class AudioSamplesInterceptor implements AudioTrackSink {
|
|
986
|
+
private final String trackId;
|
|
987
|
+
|
|
988
|
+
AudioSamplesInterceptor(String trackId) {
|
|
989
|
+
this.trackId = trackId;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
@Override
|
|
993
|
+
public void onData(
|
|
994
|
+
ByteBuffer audioData,
|
|
995
|
+
int bitsPerSample,
|
|
996
|
+
int sampleRate,
|
|
997
|
+
int numberOfChannels,
|
|
998
|
+
int numberOfFrames,
|
|
999
|
+
long absoluteCaptureTimestampMs) {
|
|
1000
|
+
WritableMap params = Arguments.createMap();
|
|
1001
|
+
params.putString("trackId", trackId);
|
|
1002
|
+
params.putArray("samples", convertSamples(audioData, bitsPerSample));
|
|
1003
|
+
params.putInt("sampleRate", sampleRate);
|
|
1004
|
+
params.putInt("channels", numberOfChannels);
|
|
1005
|
+
params.putInt("bitsPerSample", bitsPerSample);
|
|
1006
|
+
params.putInt("framesPerBuffer", numberOfFrames);
|
|
1007
|
+
params.putDouble("timestamp", (double) absoluteCaptureTimestampMs);
|
|
1008
|
+
|
|
1009
|
+
sendEvent("audioSamples", params);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
private WritableArray convertSamples(ByteBuffer audioData, int bitsPerSample) {
|
|
1013
|
+
WritableArray samples = Arguments.createArray();
|
|
1014
|
+
if (audioData == null) {
|
|
1015
|
+
return samples;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
ByteBuffer buffer = audioData.slice().order(ByteOrder.LITTLE_ENDIAN);
|
|
1019
|
+
|
|
1020
|
+
if (bitsPerSample == 16) {
|
|
1021
|
+
ShortBuffer shortBuffer = buffer.asShortBuffer();
|
|
1022
|
+
while (shortBuffer.hasRemaining()) {
|
|
1023
|
+
samples.pushDouble(shortBuffer.get());
|
|
1024
|
+
}
|
|
1025
|
+
} else if (bitsPerSample == 32) {
|
|
1026
|
+
IntBuffer intBuffer = buffer.asIntBuffer();
|
|
1027
|
+
while (intBuffer.hasRemaining()) {
|
|
1028
|
+
samples.pushDouble(intBuffer.get());
|
|
1029
|
+
}
|
|
1030
|
+
} else {
|
|
1031
|
+
while (buffer.hasRemaining()) {
|
|
1032
|
+
samples.pushDouble(buffer.get());
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
return samples;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
974
1040
|
@ReactMethod
|
|
975
1041
|
public void mediaStreamTrackEnableAudioSink(int pcId, String id, boolean enabled) {
|
|
976
|
-
|
|
1042
|
+
ThreadUtils.runOnExecutor(() -> {
|
|
1043
|
+
String sinkKey = audioSinkKey(pcId, id);
|
|
1044
|
+
|
|
1045
|
+
if (enabled) {
|
|
1046
|
+
if (audioSinkMap.containsKey(sinkKey)) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
MediaStreamTrack track = getTrack(pcId, id);
|
|
1051
|
+
if (track == null) {
|
|
1052
|
+
Log.d(TAG, "mediaStreamTrackEnableAudioSink() could not find track " + id);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (!(track instanceof AudioTrack)) {
|
|
1057
|
+
Log.d(TAG, "mediaStreamTrackEnableAudioSink() track is not an AudioTrack!");
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
AudioSamplesInterceptor sink = new AudioSamplesInterceptor(id);
|
|
1062
|
+
((AudioTrack) track).addSink(sink);
|
|
1063
|
+
audioSinkMap.put(sinkKey, sink);
|
|
1064
|
+
} else {
|
|
1065
|
+
AudioTrackSink sink = audioSinkMap.remove(sinkKey);
|
|
1066
|
+
|
|
1067
|
+
if (sink == null) {
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
MediaStreamTrack track = getTrack(pcId, id);
|
|
1072
|
+
if (track instanceof AudioTrack) {
|
|
1073
|
+
((AudioTrack) track).removeSink(sink);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
977
1077
|
}
|
|
978
1078
|
|
|
979
1079
|
/**
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#import "WLVAudioDevice.h"
|
|
2
|
+
#import <AudioToolbox/AudioToolbox.h>
|
|
3
|
+
#import <math.h>
|
|
4
|
+
|
|
5
|
+
static const double kDefaultSampleRate = 48000.0;
|
|
6
|
+
static const NSInteger kDefaultChannels = 1;
|
|
7
|
+
static const NSTimeInterval kDefaultBufferDuration = 0.02;
|
|
8
|
+
|
|
9
|
+
@interface WLVAudioDevice ()
|
|
10
|
+
|
|
11
|
+
@property(nonatomic, weak) id<RTCAudioDeviceDelegate> delegate;
|
|
12
|
+
@property(nonatomic) BOOL initialized;
|
|
13
|
+
@property(nonatomic) BOOL playoutInitialized;
|
|
14
|
+
@property(nonatomic) BOOL recordingInitialized;
|
|
15
|
+
@property(nonatomic) BOOL playing;
|
|
16
|
+
@property(nonatomic) BOOL recording;
|
|
17
|
+
@property(nonatomic) double inRate;
|
|
18
|
+
@property(nonatomic) NSInteger inChannels;
|
|
19
|
+
@property(nonatomic) double outRate;
|
|
20
|
+
@property(nonatomic) NSInteger outChannels;
|
|
21
|
+
@property(nonatomic) NSTimeInterval inBufferDuration;
|
|
22
|
+
@property(nonatomic) NSTimeInterval outBufferDuration;
|
|
23
|
+
@property(nonatomic) NSTimeInterval inLatency;
|
|
24
|
+
@property(nonatomic) NSTimeInterval outLatency;
|
|
25
|
+
@property(nonatomic) double sampleTime;
|
|
26
|
+
@property(nonatomic, strong) dispatch_queue_t queue;
|
|
27
|
+
|
|
28
|
+
@end
|
|
29
|
+
|
|
30
|
+
@implementation WLVAudioDevice
|
|
31
|
+
|
|
32
|
+
- (instancetype)init {
|
|
33
|
+
self = [super init];
|
|
34
|
+
if (self) {
|
|
35
|
+
_inRate = kDefaultSampleRate;
|
|
36
|
+
_outRate = kDefaultSampleRate;
|
|
37
|
+
_inChannels = kDefaultChannels;
|
|
38
|
+
_outChannels = kDefaultChannels;
|
|
39
|
+
_inBufferDuration = kDefaultBufferDuration;
|
|
40
|
+
_outBufferDuration = kDefaultBufferDuration;
|
|
41
|
+
_queue = dispatch_queue_create("webrtc.virtual.audio", DISPATCH_QUEUE_SERIAL);
|
|
42
|
+
}
|
|
43
|
+
return self;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (void)pushAudioData:(NSData *)data sampleRate:(double)sampleRate channels:(NSInteger)channels {
|
|
47
|
+
if (!self.recording || !self.delegate || data.length == 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
NSInteger bytesPerFrame = channels * sizeof(int16_t);
|
|
51
|
+
if (bytesPerFrame == 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
UInt32 frames = (UInt32)(data.length / bytesPerFrame);
|
|
55
|
+
if (frames == 0) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
[self updateInputRate:sampleRate channels:channels];
|
|
59
|
+
NSData *chunk = [data copy];
|
|
60
|
+
dispatch_async(self.queue, ^{
|
|
61
|
+
if (!self.recording || !self.delegate) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
AudioBuffer buffer;
|
|
65
|
+
buffer.mNumberChannels = (UInt32)channels;
|
|
66
|
+
buffer.mDataByteSize = (UInt32)chunk.length;
|
|
67
|
+
buffer.mData = (void *)chunk.bytes;
|
|
68
|
+
AudioBufferList list;
|
|
69
|
+
list.mNumberBuffers = 1;
|
|
70
|
+
list.mBuffers[0] = buffer;
|
|
71
|
+
AudioUnitRenderActionFlags flags = 0;
|
|
72
|
+
AudioTimeStamp stamp;
|
|
73
|
+
memset(&stamp, 0, sizeof(AudioTimeStamp));
|
|
74
|
+
stamp.mFlags = kAudioTimeStampSampleTimeValid;
|
|
75
|
+
stamp.mSampleTime = self.sampleTime;
|
|
76
|
+
self.sampleTime += frames;
|
|
77
|
+
RTC_OBJC_TYPE(RTCAudioDeviceDeliverRecordedDataBlock) block = self.delegate.deliverRecordedData;
|
|
78
|
+
if (block) {
|
|
79
|
+
block(&flags, &stamp, 0, frames, &list, NULL, nil);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
- (void)updateInputRate:(double)rate channels:(NSInteger)channels {
|
|
85
|
+
BOOL rateChanged = fabs(self.inRate - rate) > 0.1;
|
|
86
|
+
BOOL channelChanged = self.inChannels != channels;
|
|
87
|
+
if (rateChanged) {
|
|
88
|
+
self.inRate = rate;
|
|
89
|
+
}
|
|
90
|
+
if (channelChanged) {
|
|
91
|
+
self.inChannels = channels;
|
|
92
|
+
}
|
|
93
|
+
if ((rateChanged || channelChanged) && self.delegate) {
|
|
94
|
+
[self.delegate dispatchAsync:^{
|
|
95
|
+
[self.delegate notifyAudioInputParametersChange];
|
|
96
|
+
}];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#pragma mark - RTCAudioDevice
|
|
101
|
+
|
|
102
|
+
- (double)deviceInputSampleRate {
|
|
103
|
+
return self.inRate;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
- (NSTimeInterval)inputIOBufferDuration {
|
|
107
|
+
return self.inBufferDuration;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
- (NSInteger)inputNumberOfChannels {
|
|
111
|
+
return self.inChannels;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
- (NSTimeInterval)inputLatency {
|
|
115
|
+
return self.inLatency;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
- (double)deviceOutputSampleRate {
|
|
119
|
+
return self.outRate;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
- (NSTimeInterval)outputIOBufferDuration {
|
|
123
|
+
return self.outBufferDuration;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
- (NSInteger)outputNumberOfChannels {
|
|
127
|
+
return self.outChannels;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
- (NSTimeInterval)outputLatency {
|
|
131
|
+
return self.outLatency;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
- (BOOL)isInitialized {
|
|
135
|
+
return self.initialized;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
- (BOOL)initializeWithDelegate:(id<RTCAudioDeviceDelegate>)delegate {
|
|
139
|
+
self.delegate = delegate;
|
|
140
|
+
self.initialized = YES;
|
|
141
|
+
return YES;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
- (BOOL)terminateDevice {
|
|
145
|
+
self.delegate = nil;
|
|
146
|
+
self.initialized = NO;
|
|
147
|
+
self.playoutInitialized = NO;
|
|
148
|
+
self.recordingInitialized = NO;
|
|
149
|
+
self.playing = NO;
|
|
150
|
+
self.recording = NO;
|
|
151
|
+
self.sampleTime = 0;
|
|
152
|
+
return YES;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
- (BOOL)isPlayoutInitialized {
|
|
156
|
+
return self.playoutInitialized;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
- (BOOL)initializePlayout {
|
|
160
|
+
self.playoutInitialized = YES;
|
|
161
|
+
return YES;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
- (BOOL)isPlaying {
|
|
165
|
+
return self.playing;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
- (BOOL)startPlayout {
|
|
169
|
+
self.playing = YES;
|
|
170
|
+
return YES;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
- (BOOL)stopPlayout {
|
|
174
|
+
self.playing = NO;
|
|
175
|
+
return YES;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
- (BOOL)isRecordingInitialized {
|
|
179
|
+
return self.recordingInitialized;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
- (BOOL)initializeRecording {
|
|
183
|
+
self.recordingInitialized = YES;
|
|
184
|
+
return YES;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
- (BOOL)isRecording {
|
|
188
|
+
return self.recording;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
- (BOOL)startRecording {
|
|
192
|
+
self.recording = YES;
|
|
193
|
+
return YES;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
- (BOOL)stopRecording {
|
|
197
|
+
self.recording = NO;
|
|
198
|
+
return YES;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@end
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#import <objc/runtime.h>
|
|
2
2
|
|
|
3
|
+
#import <AVFoundation/AVFoundation.h>
|
|
4
|
+
#import <math.h>
|
|
5
|
+
#import <limits.h>
|
|
6
|
+
#import <stdint.h>
|
|
7
|
+
|
|
3
8
|
#import <WebRTC/RTCCameraVideoCapturer.h>
|
|
4
9
|
#import <WebRTC/RTCMediaConstraints.h>
|
|
5
10
|
#import <WebRTC/RTCMediaStreamTrack.h>
|
|
@@ -16,8 +21,109 @@
|
|
|
16
21
|
#import "TrackCapturerEventsEmitter.h"
|
|
17
22
|
#import "VideoCaptureController.h"
|
|
18
23
|
|
|
24
|
+
@interface AudioSamplesRenderer : NSObject<RTCAudioRenderer>
|
|
25
|
+
|
|
26
|
+
- (instancetype)initWithModule:(WebRTCModule *)module trackId:(NSString *)trackId;
|
|
27
|
+
|
|
28
|
+
@end
|
|
29
|
+
|
|
30
|
+
@implementation AudioSamplesRenderer {
|
|
31
|
+
__weak WebRTCModule *_module;
|
|
32
|
+
NSString *_trackId;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
- (instancetype)initWithModule:(WebRTCModule *)module trackId:(NSString *)trackId {
|
|
36
|
+
self = [super init];
|
|
37
|
+
if (self) {
|
|
38
|
+
_module = module;
|
|
39
|
+
_trackId = [trackId copy];
|
|
40
|
+
}
|
|
41
|
+
return self;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (void)render:(AVAudioPCMBuffer *)pcmBuffer {
|
|
45
|
+
WebRTCModule *module = _module;
|
|
46
|
+
if (!module) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
AVAudioFrameCount frameLength = pcmBuffer.frameLength;
|
|
51
|
+
if (frameLength == 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
UInt32 channelCount = pcmBuffer.format.channelCount;
|
|
56
|
+
if (channelCount == 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
AVAudioCommonFormat format = pcmBuffer.format.commonFormat;
|
|
61
|
+
NSUInteger totalSamples = (NSUInteger)frameLength * (NSUInteger)channelCount;
|
|
62
|
+
NSMutableArray<NSNumber *> *samples = [NSMutableArray arrayWithCapacity:totalSamples];
|
|
63
|
+
int bitsPerSample = (int)pcmBuffer.format.streamDescription->mBitsPerChannel;
|
|
64
|
+
|
|
65
|
+
if (format == AVAudioPCMFormatInt16) {
|
|
66
|
+
int16_t **channelData = pcmBuffer.int16ChannelData;
|
|
67
|
+
if (!channelData) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (AVAudioFrameCount frame = 0; frame < frameLength; frame++) {
|
|
71
|
+
for (UInt32 channel = 0; channel < channelCount; channel++) {
|
|
72
|
+
[samples addObject:@(channelData[channel][frame])];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} else if (format == AVAudioPCMFormatFloat32) {
|
|
76
|
+
float **channelData = pcmBuffer.floatChannelData;
|
|
77
|
+
if (!channelData) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
bitsPerSample = 16;
|
|
81
|
+
for (AVAudioFrameCount frame = 0; frame < frameLength; frame++) {
|
|
82
|
+
for (UInt32 channel = 0; channel < channelCount; channel++) {
|
|
83
|
+
float value = channelData[channel][frame];
|
|
84
|
+
float clipped = fminf(fmaxf(value, -1.0f), 1.0f);
|
|
85
|
+
int16_t sample = (int16_t)lrintf(clipped * (float)INT16_MAX);
|
|
86
|
+
[samples addObject:@(sample)];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} else if (format == AVAudioPCMFormatInt32) {
|
|
90
|
+
int32_t **channelData = pcmBuffer.int32ChannelData;
|
|
91
|
+
if (!channelData) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
bitsPerSample = 32;
|
|
95
|
+
for (AVAudioFrameCount frame = 0; frame < frameLength; frame++) {
|
|
96
|
+
for (UInt32 channel = 0; channel < channelCount; channel++) {
|
|
97
|
+
int32_t value = channelData[channel][frame];
|
|
98
|
+
[samples addObject:@(value)];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
NSTimeInterval timestampMs = [[NSDate date] timeIntervalSince1970] * 1000.0;
|
|
106
|
+
|
|
107
|
+
[module sendEventWithName:kEventAudioSamples
|
|
108
|
+
body:@{
|
|
109
|
+
@"trackId" : _trackId,
|
|
110
|
+
@"samples" : samples,
|
|
111
|
+
@"sampleRate" : @(pcmBuffer.format.sampleRate),
|
|
112
|
+
@"channels" : @(channelCount),
|
|
113
|
+
@"bitsPerSample" : @(bitsPerSample),
|
|
114
|
+
@"framesPerBuffer" : @(frameLength),
|
|
115
|
+
@"timestamp" : @(timestampMs)
|
|
116
|
+
}];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@end
|
|
120
|
+
|
|
19
121
|
@implementation WebRTCModule (RTCMediaStream)
|
|
20
122
|
|
|
123
|
+
- (NSString *)audioSinkKeyForPcId:(NSNumber *)pcId trackId:(NSString *)trackId {
|
|
124
|
+
return [NSString stringWithFormat:@"%@:%@", pcId, trackId];
|
|
125
|
+
}
|
|
126
|
+
|
|
21
127
|
- (VideoEffectProcessor *)videoEffectProcessor {
|
|
22
128
|
return objc_getAssociatedObject(self, _cmd);
|
|
23
129
|
}
|
|
@@ -217,6 +323,53 @@ RCT_EXPORT_METHOD(getDisplayMedia : (RCTPromiseResolveBlock)resolve rejecter : (
|
|
|
217
323
|
#endif
|
|
218
324
|
}
|
|
219
325
|
|
|
326
|
+
RCT_EXPORT_METHOD(createVirtualAudioTrack : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
327
|
+
#if TARGET_OS_TV
|
|
328
|
+
reject(@"unsupported_platform", @"tvOS is not supported", nil);
|
|
329
|
+
return;
|
|
330
|
+
#else
|
|
331
|
+
RTCPeerConnectionFactory *factory = [self virtualFactory];
|
|
332
|
+
if (!factory) {
|
|
333
|
+
reject(@"virtual_factory_error", @"Factory unavailable", nil);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
NSString *trackId = [[NSUUID UUID] UUIDString];
|
|
337
|
+
RTCAudioSource *source = [factory audioSourceWithConstraints:nil];
|
|
338
|
+
RTCAudioTrack *track = [factory audioTrackWithSource:source trackId:trackId];
|
|
339
|
+
NSArray *components = [self createMediaStream:@[ track ]];
|
|
340
|
+
resolve(@{ @"streamId" : components[0], @"tracks" : components[1] });
|
|
341
|
+
#endif
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
RCT_EXPORT_METHOD(pushVirtualAudioSamples
|
|
345
|
+
: (nonnull NSArray<NSNumber *> *)samples
|
|
346
|
+
sampleRate
|
|
347
|
+
: (nonnull NSNumber *)sampleRate
|
|
348
|
+
channels
|
|
349
|
+
: (nonnull NSNumber *)channels) {
|
|
350
|
+
#if TARGET_OS_TV
|
|
351
|
+
return;
|
|
352
|
+
#else
|
|
353
|
+
if (samples.count == 0) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (!self.virtualAudioDevice) {
|
|
357
|
+
[self virtualFactory];
|
|
358
|
+
}
|
|
359
|
+
if (!self.virtualAudioDevice) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
NSUInteger length = samples.count * sizeof(int16_t);
|
|
363
|
+
NSMutableData *data = [NSMutableData dataWithLength:length];
|
|
364
|
+
int16_t *buffer = data.mutableBytes;
|
|
365
|
+
NSUInteger idx = 0;
|
|
366
|
+
for (NSNumber *value in samples) {
|
|
367
|
+
buffer[idx++] = (int16_t)value.shortValue;
|
|
368
|
+
}
|
|
369
|
+
[self.virtualAudioDevice pushAudioData:data sampleRate:sampleRate.doubleValue channels:channels.integerValue];
|
|
370
|
+
#endif
|
|
371
|
+
}
|
|
372
|
+
|
|
220
373
|
/**
|
|
221
374
|
* Implements {@code getUserMedia}. Note that at this point constraints have
|
|
222
375
|
* been normalized and permissions have been granted. The constraints only
|
|
@@ -497,7 +650,36 @@ RCT_EXPORT_METHOD(mediaStreamTrackSetPlaybackEnabled : (nonnull NSNumber *)pcId
|
|
|
497
650
|
}
|
|
498
651
|
|
|
499
652
|
RCT_EXPORT_METHOD(mediaStreamTrackEnableAudioSink : (nonnull NSNumber *)pcId : (nonnull NSString *)trackID : (BOOL)enabled) {
|
|
500
|
-
|
|
653
|
+
NSString *key = [self audioSinkKeyForPcId:pcId trackId:trackID];
|
|
654
|
+
|
|
655
|
+
if (enabled) {
|
|
656
|
+
if (self.audioRenderers[key]) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
RTCMediaStreamTrack *track = [self trackForId:trackID pcId:pcId];
|
|
661
|
+
if (track == nil || ![track.kind isEqualToString:@"audio"]) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
RTCAudioTrack *audioTrack = (RTCAudioTrack *)track;
|
|
666
|
+
AudioSamplesRenderer *renderer = [[AudioSamplesRenderer alloc] initWithModule:self trackId:trackID];
|
|
667
|
+
self.audioRenderers[key] = renderer;
|
|
668
|
+
[audioTrack addRenderer:renderer];
|
|
669
|
+
} else {
|
|
670
|
+
id<RTCAudioRenderer> renderer = self.audioRenderers[key];
|
|
671
|
+
if (!renderer) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
RTCMediaStreamTrack *track = [self trackForId:trackID pcId:pcId];
|
|
676
|
+
if ([track isKindOfClass:[RTCAudioTrack class]]) {
|
|
677
|
+
RTCAudioTrack *audioTrack = (RTCAudioTrack *)track;
|
|
678
|
+
[audioTrack removeRenderer:renderer];
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
[self.audioRenderers removeObjectForKey:key];
|
|
682
|
+
}
|
|
501
683
|
}
|
|
502
684
|
|
|
503
685
|
RCT_EXPORT_METHOD(mediaStreamTrackSetVideoEffects
|
|
@@ -36,10 +36,13 @@ static NSString *const kEventAudioSamples = @"audioSamples";
|
|
|
36
36
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, RTCMediaStream *> *localStreams;
|
|
37
37
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, RTCMediaStreamTrack *> *localTracks;
|
|
38
38
|
|
|
39
|
+
@property(nonatomic, strong) NSMutableDictionary<NSString *, id<RTCAudioRenderer>> *audioRenderers;
|
|
40
|
+
|
|
39
41
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, RTCFrameCryptor *> *frameCryptors;
|
|
40
42
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, RTCFrameCryptorKeyProvider *> *keyProviders;
|
|
41
43
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, RTCDataPacketCryptor *> *dataPacketCryptors;
|
|
42
44
|
|
|
43
45
|
- (RTCMediaStream *)streamForReactTag:(NSString *)reactTag;
|
|
46
|
+
- (RTCPeerConnectionFactory *)virtualFactory;
|
|
44
47
|
|
|
45
48
|
@end
|
|
@@ -10,8 +10,13 @@
|
|
|
10
10
|
#import "WebRTCModule+RTCPeerConnection.h"
|
|
11
11
|
#import "WebRTCModule.h"
|
|
12
12
|
#import "WebRTCModuleOptions.h"
|
|
13
|
+
#import "WLVAudioDevice.h"
|
|
13
14
|
|
|
14
15
|
@interface WebRTCModule ()
|
|
16
|
+
|
|
17
|
+
@property(nonatomic, strong) WLVAudioDevice *virtualAudioDevice;
|
|
18
|
+
@property(nonatomic, strong) RTCPeerConnectionFactory *virtualPeerConnectionFactory;
|
|
19
|
+
|
|
15
20
|
@end
|
|
16
21
|
|
|
17
22
|
@implementation WebRTCModule
|
|
@@ -23,6 +28,8 @@
|
|
|
23
28
|
- (void)dealloc {
|
|
24
29
|
[_localTracks removeAllObjects];
|
|
25
30
|
_localTracks = nil;
|
|
31
|
+
[_audioRenderers removeAllObjects];
|
|
32
|
+
_audioRenderers = nil;
|
|
26
33
|
[_localStreams removeAllObjects];
|
|
27
34
|
_localStreams = nil;
|
|
28
35
|
|
|
@@ -92,6 +99,7 @@
|
|
|
92
99
|
_peerConnections = [NSMutableDictionary new];
|
|
93
100
|
_localStreams = [NSMutableDictionary new];
|
|
94
101
|
_localTracks = [NSMutableDictionary new];
|
|
102
|
+
_audioRenderers = [NSMutableDictionary new];
|
|
95
103
|
|
|
96
104
|
_frameCryptors = [NSMutableDictionary new];
|
|
97
105
|
_keyProviders = [NSMutableDictionary new];
|
|
@@ -125,6 +133,16 @@ RCT_EXPORT_MODULE();
|
|
|
125
133
|
return _workerQueue;
|
|
126
134
|
}
|
|
127
135
|
|
|
136
|
+
- (RTCPeerConnectionFactory *)virtualFactory {
|
|
137
|
+
if (_virtualPeerConnectionFactory == nil) {
|
|
138
|
+
self.virtualAudioDevice = [[WLVAudioDevice alloc] init];
|
|
139
|
+
_virtualPeerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:_encoderFactory
|
|
140
|
+
decoderFactory:_decoderFactory
|
|
141
|
+
audioDevice:self.virtualAudioDevice];
|
|
142
|
+
}
|
|
143
|
+
return _virtualPeerConnectionFactory;
|
|
144
|
+
}
|
|
145
|
+
|
|
128
146
|
- (NSArray<NSString *> *)supportedEvents {
|
|
129
147
|
return @[
|
|
130
148
|
kEventPeerConnectionSignalingStateChanged,
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
4EE3A8D225B841DD00FAA24A /* CaptureController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EE3A8C925B841DD00FAA24A /* CaptureController.m */; };
|
|
23
23
|
4EE3A8D325B841DD00FAA24A /* ScreenCaptureController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EE3A8CC25B841DD00FAA24A /* ScreenCaptureController.m */; };
|
|
24
24
|
4EE3A8D425B841DD00FAA24A /* ScreenCapturer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EE3A8CD25B841DD00FAA24A /* ScreenCapturer.m */; };
|
|
25
|
+
E0C37C1F2D8D1C6A009E2E63 /* WLVAudioDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C37C1E2D8D1C6A009E2E63 /* WLVAudioDevice.m */; };
|
|
25
26
|
D3FF699919D2664B25C9D458 /* Pods_RCTWebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A20F721AD842563B66292D5B /* Pods_RCTWebRTC.framework */; };
|
|
26
27
|
D74EF94829652169000742E1 /* TrackCapturerEventsEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = D74EF94629652169000742E1 /* TrackCapturerEventsEmitter.m */; };
|
|
27
28
|
D7F0711E2C6DC91F0031F594 /* WebRTCModule+RTCAudioSession.m in Sources */ = {isa = PBXBuildFile; fileRef = D7F0711D2C6DC91F0031F594 /* WebRTCModule+RTCAudioSession.m */; };
|
|
@@ -72,6 +73,8 @@
|
|
|
72
73
|
4EE3A8CC25B841DD00FAA24A /* ScreenCaptureController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScreenCaptureController.m; path = RCTWebRTC/ScreenCaptureController.m; sourceTree = SOURCE_ROOT; };
|
|
73
74
|
4EE3A8CD25B841DD00FAA24A /* ScreenCapturer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScreenCapturer.m; path = RCTWebRTC/ScreenCapturer.m; sourceTree = SOURCE_ROOT; };
|
|
74
75
|
4EE3A8CE25B841DD00FAA24A /* SocketConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SocketConnection.h; path = RCTWebRTC/SocketConnection.h; sourceTree = SOURCE_ROOT; };
|
|
76
|
+
E0C37C1D2D8D1C6A009E2E63 /* WLVAudioDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WLVAudioDevice.h; path = RCTWebRTC/WLVAudioDevice.h; sourceTree = SOURCE_ROOT; };
|
|
77
|
+
E0C37C1E2D8D1C6A009E2E63 /* WLVAudioDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = WLVAudioDevice.m; path = RCTWebRTC/WLVAudioDevice.m; sourceTree = SOURCE_ROOT; };
|
|
75
78
|
A20F721AD842563B66292D5B /* Pods_RCTWebRTC.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RCTWebRTC.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
76
79
|
D74EF94529652148000742E1 /* CapturerEventsDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CapturerEventsDelegate.h; path = RCTWebRTC/CapturerEventsDelegate.h; sourceTree = SOURCE_ROOT; };
|
|
77
80
|
D74EF94629652169000742E1 /* TrackCapturerEventsEmitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TrackCapturerEventsEmitter.m; path = RCTWebRTC/TrackCapturerEventsEmitter.m; sourceTree = SOURCE_ROOT; };
|
|
@@ -157,6 +160,8 @@
|
|
|
157
160
|
4EE3A8CD25B841DD00FAA24A /* ScreenCapturer.m */,
|
|
158
161
|
4EE3A8CE25B841DD00FAA24A /* SocketConnection.h */,
|
|
159
162
|
4EE3A8C825B841DD00FAA24A /* SocketConnection.m */,
|
|
163
|
+
E0C37C1D2D8D1C6A009E2E63 /* WLVAudioDevice.h */,
|
|
164
|
+
E0C37C1E2D8D1C6A009E2E63 /* WLVAudioDevice.m */,
|
|
160
165
|
DEC96579264176DF0052DB35 /* DataChannelWrapper.h */,
|
|
161
166
|
DEC96576264176C10052DB35 /* DataChannelWrapper.m */,
|
|
162
167
|
);
|
|
@@ -255,6 +260,7 @@
|
|
|
255
260
|
isa = PBXSourcesBuildPhase;
|
|
256
261
|
buildActionMask = 2147483647;
|
|
257
262
|
files = (
|
|
263
|
+
E0C37C1F2D8D1C6A009E2E63 /* WLVAudioDevice.m in Sources */,
|
|
258
264
|
4EE3A8C525B8417800FAA24A /* WebRTCModule+VideoTrackAdapter.m in Sources */,
|
|
259
265
|
4EE3A8BA25B8415900FAA24A /* WebRTCModule+RTCDataChannel.m in Sources */,
|
|
260
266
|
4EE3A8B625B8414A00FAA24A /* WebRTCModule+Permissions.m in Sources */,
|
|
@@ -51,7 +51,9 @@ function removeListener(listener) {
|
|
|
51
51
|
}
|
|
52
52
|
function removeListenerForEvent(listener, eventName) {
|
|
53
53
|
const subs = _subscriptions.get(listener);
|
|
54
|
-
if (!subs)
|
|
54
|
+
if (!subs) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
55
57
|
const remaining = [];
|
|
56
58
|
subs.forEach(sub => {
|
|
57
59
|
if (sub.eventType === eventName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_EventEmitter","_interopRequireDefault","obj","__esModule","default","WebRTCModule","NativeModules","nativeEmitter","NativeEventEmitter","NATIVE_EVENTS","eventEmitter","EventEmitter","setupNativeEvents","eventName","addListener","_len","arguments","length","args","Array","_key","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete","removeListenerForEvent","subs","remaining","eventType"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeModules, NativeEventEmitter, EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\n\nconst { WebRTCModule } = NativeModules;\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(WebRTCModule);\n\nconst NATIVE_EVENTS = [\n 'peerConnectionSignalingStateChanged',\n 'peerConnectionStateChanged',\n 'peerConnectionOnRenegotiationNeeded',\n 'peerConnectionIceConnectionChanged',\n 'peerConnectionIceGatheringChanged',\n 'peerConnectionGotICECandidate',\n 'peerConnectionDidOpenDataChannel',\n 'peerConnectionOnRemoveTrack',\n 'peerConnectionOnTrack',\n 'dataChannelStateChanged',\n 'dataChannelReceiveMessage',\n 'dataChannelDidChangeBufferedAmount',\n 'mediaStreamTrackMuteChanged',\n 'mediaStreamTrackEnded',\n 'frameCryptionStateChanged',\n 'audioSamples',\n];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(listener: Listener, eventName: string, eventHandler: EventHandler): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions.get(listener)?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach(sub => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n\nexport function removeListenerForEvent(listener: Listener, eventName: string): void {\n const subs = _subscriptions.get(listener);\n if (!subs) return;\n \n const remaining: EmitterSubscription[] = [];\n subs.forEach(sub => {\n if ((sub as any).eventType === eventName) {\n sub.remove();\n } else {\n remaining.push(sub);\n }\n });\n
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_EventEmitter","_interopRequireDefault","obj","__esModule","default","WebRTCModule","NativeModules","nativeEmitter","NativeEventEmitter","NATIVE_EVENTS","eventEmitter","EventEmitter","setupNativeEvents","eventName","addListener","_len","arguments","length","args","Array","_key","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete","removeListenerForEvent","subs","remaining","eventType"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeModules, NativeEventEmitter, EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\n\nconst { WebRTCModule } = NativeModules;\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(WebRTCModule);\n\nconst NATIVE_EVENTS = [\n 'peerConnectionSignalingStateChanged',\n 'peerConnectionStateChanged',\n 'peerConnectionOnRenegotiationNeeded',\n 'peerConnectionIceConnectionChanged',\n 'peerConnectionIceGatheringChanged',\n 'peerConnectionGotICECandidate',\n 'peerConnectionDidOpenDataChannel',\n 'peerConnectionOnRemoveTrack',\n 'peerConnectionOnTrack',\n 'dataChannelStateChanged',\n 'dataChannelReceiveMessage',\n 'dataChannelDidChangeBufferedAmount',\n 'mediaStreamTrackMuteChanged',\n 'mediaStreamTrackEnded',\n 'frameCryptionStateChanged',\n 'audioSamples',\n];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(listener: Listener, eventName: string, eventHandler: EventHandler): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions.get(listener)?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach(sub => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n\nexport function removeListenerForEvent(listener: Listener, eventName: string): void {\n const subs = _subscriptions.get(listener);\n\n if (!subs) {\n return;\n }\n\n const remaining: EmitterSubscription[] = [];\n\n subs.forEach(sub => {\n if ((sub as any).eventType === eventName) {\n sub.remove();\n } else {\n remaining.push(sub);\n }\n });\n\n if (remaining.length === 0) {\n _subscriptions.delete(listener);\n } else {\n _subscriptions.set(listener, remaining);\n }\n}\n"],"mappings":"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"}
|
|
@@ -42,6 +42,19 @@ class MediaDevices extends _index.EventTarget {
|
|
|
42
42
|
getUserMedia(constraints) {
|
|
43
43
|
return (0, _getUserMedia.default)(constraints);
|
|
44
44
|
}
|
|
45
|
+
createVirtualAudioTrack() {
|
|
46
|
+
if (!WebRTCModule.createVirtualAudioTrack) {
|
|
47
|
+
return Promise.reject(new Error('virtual audio unavailable'));
|
|
48
|
+
}
|
|
49
|
+
return WebRTCModule.createVirtualAudioTrack();
|
|
50
|
+
}
|
|
51
|
+
pushVirtualAudioSamples(samples, sampleRate, channels) {
|
|
52
|
+
if (!WebRTCModule.pushVirtualAudioSamples) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const array = samples instanceof Int16Array ? Array.from(samples) : samples.slice();
|
|
56
|
+
WebRTCModule.pushVirtualAudioSamples(array, sampleRate, channels);
|
|
57
|
+
}
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_index","require","_reactNative","_getDisplayMedia","_interopRequireDefault","_getUserMedia","obj","__esModule","default","WebRTCModule","NativeModules","MediaDevices","EventTarget","enumerateDevices","Promise","resolve","getDisplayMedia","getUserMedia","constraints","proto","prototype","defineEventAttribute","_default","exports"],"sources":["MediaDevices.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport getDisplayMedia from './getDisplayMedia';\nimport getUserMedia, { Constraints } from './getUserMedia';\n\nconst { WebRTCModule } = NativeModules;\n\ntype MediaDevicesEventMap = {\n devicechange: Event<'devicechange'>\n}\n\nclass MediaDevices extends EventTarget<MediaDevicesEventMap> {\n /**\n * W3C \"Media Capture and Streams\" compatible {@code enumerateDevices}\n * implementation.\n */\n enumerateDevices() {\n return new Promise(resolve => WebRTCModule.enumerateDevices(resolve));\n }\n\n /**\n * W3C \"Screen Capture\" compatible {@code getDisplayMedia} implementation.\n * See: https://w3c.github.io/mediacapture-screen-share/\n *\n * @returns {Promise}\n */\n getDisplayMedia() {\n return getDisplayMedia();\n }\n\n /**\n * W3C \"Media Capture and Streams\" compatible {@code getUserMedia}\n * implementation.\n * See: https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-enumeratedevices\n *\n * @param {*} constraints\n * @returns {Promise}\n */\n getUserMedia(constraints: Constraints) {\n return getUserMedia(constraints);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaDevices.prototype;\n\ndefineEventAttribute(proto, 'devicechange');\n\n\nexport default new MediaDevices();\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;
|
|
1
|
+
{"version":3,"names":["_index","require","_reactNative","_getDisplayMedia","_interopRequireDefault","_getUserMedia","obj","__esModule","default","WebRTCModule","NativeModules","MediaDevices","EventTarget","enumerateDevices","Promise","resolve","getDisplayMedia","getUserMedia","constraints","createVirtualAudioTrack","reject","Error","pushVirtualAudioSamples","samples","sampleRate","channels","array","Int16Array","Array","from","slice","proto","prototype","defineEventAttribute","_default","exports"],"sources":["MediaDevices.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport { type MediaTrackSettings } from './MediaStreamTrack';\nimport getDisplayMedia from './getDisplayMedia';\nimport getUserMedia, { Constraints } from './getUserMedia';\n\nconst { WebRTCModule } = NativeModules;\n\ntype MediaDevicesEventMap = {\n devicechange: Event<'devicechange'>\n}\n\ntype VirtualTrackInfo = {\n enabled: boolean;\n id: string;\n kind: string;\n readyState: string;\n remote: boolean;\n settings: MediaTrackSettings;\n}\n\ntype VirtualAudioResponse = {\n streamId: string;\n tracks: VirtualTrackInfo[];\n}\n\nclass MediaDevices extends EventTarget<MediaDevicesEventMap> {\n /**\n * W3C \"Media Capture and Streams\" compatible {@code enumerateDevices}\n * implementation.\n */\n enumerateDevices() {\n return new Promise(resolve => WebRTCModule.enumerateDevices(resolve));\n }\n\n /**\n * W3C \"Screen Capture\" compatible {@code getDisplayMedia} implementation.\n * See: https://w3c.github.io/mediacapture-screen-share/\n *\n * @returns {Promise}\n */\n getDisplayMedia() {\n return getDisplayMedia();\n }\n\n /**\n * W3C \"Media Capture and Streams\" compatible {@code getUserMedia}\n * implementation.\n * See: https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-enumeratedevices\n *\n * @param {*} constraints\n * @returns {Promise}\n */\n getUserMedia(constraints: Constraints) {\n return getUserMedia(constraints);\n }\n\n createVirtualAudioTrack(): Promise<VirtualAudioResponse> {\n if (!WebRTCModule.createVirtualAudioTrack) {\n return Promise.reject(new Error('virtual audio unavailable'));\n }\n\n return WebRTCModule.createVirtualAudioTrack();\n }\n\n pushVirtualAudioSamples(samples: Int16Array | number[], sampleRate: number, channels: number) {\n if (!WebRTCModule.pushVirtualAudioSamples) {\n return;\n }\n\n const array = samples instanceof Int16Array ? Array.from(samples) : samples.slice();\n\n WebRTCModule.pushVirtualAudioSamples(array, sampleRate, channels);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaDevices.prototype;\n\ndefineEventAttribute(proto, 'devicechange');\n\n\nexport default new MediaDevices();\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAGA,IAAAE,gBAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,aAAA,GAAAD,sBAAA,CAAAH,OAAA;AAA2D,SAAAG,uBAAAE,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAE3D,MAAM;EAAEG;AAAa,CAAC,GAAGC,0BAAa;AAoBtC,MAAMC,YAAY,SAASC,kBAAW,CAAuB;EACzD;AACJ;AACA;AACA;EACIC,gBAAgBA,CAAA,EAAG;IACf,OAAO,IAAIC,OAAO,CAACC,OAAO,IAAIN,YAAY,CAACI,gBAAgB,CAACE,OAAO,CAAC,CAAC;EACzE;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACIC,eAAeA,CAAA,EAAG;IACd,OAAO,IAAAA,wBAAe,EAAC,CAAC;EAC5B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACIC,YAAYA,CAACC,WAAwB,EAAE;IACnC,OAAO,IAAAD,qBAAY,EAACC,WAAW,CAAC;EACpC;EAEAC,uBAAuBA,CAAA,EAAkC;IACrD,IAAI,CAACV,YAAY,CAACU,uBAAuB,EAAE;MACvC,OAAOL,OAAO,CAACM,MAAM,CAAC,IAAIC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACjE;IAEA,OAAOZ,YAAY,CAACU,uBAAuB,CAAC,CAAC;EACjD;EAEAG,uBAAuBA,CAACC,OAA8B,EAAEC,UAAkB,EAAEC,QAAgB,EAAE;IAC1F,IAAI,CAAChB,YAAY,CAACa,uBAAuB,EAAE;MACvC;IACJ;IAEA,MAAMI,KAAK,GAAGH,OAAO,YAAYI,UAAU,GAAGC,KAAK,CAACC,IAAI,CAACN,OAAO,CAAC,GAAGA,OAAO,CAACO,KAAK,CAAC,CAAC;IAEnFrB,YAAY,CAACa,uBAAuB,CAACI,KAAK,EAAEF,UAAU,EAAEC,QAAQ,CAAC;EACrE;AACJ;;AAEA;AACA;AACA;AACA,MAAMM,KAAK,GAAGpB,YAAY,CAACqB,SAAS;AAEpC,IAAAC,2BAAoB,EAACF,KAAK,EAAE,cAAc,CAAC;AAAC,IAAAG,QAAA,GAG7B,IAAIvB,YAAY,CAAC,CAAC;AAAAwB,OAAA,CAAA3B,OAAA,GAAA0B,QAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_index","require","_reactNative","_EventEmitter","_Logger","_interopRequireDefault","_RTCUtil","obj","__esModule","default","_defineProperty","key","value","Object","defineProperty","enumerable","configurable","writable","log","Logger","WebRTCModule","NativeModules","MediaStreamTrack","EventTarget","constructor","info","_constraints","constraints","_enabled","enabled","_settings","settings","_muted","_peerConnectionId","peerConnectionId","_readyState","readyState","id","kind","remote","_registerEvents","Boolean","mediaStreamTrackSetEnabled","muted","stop","_switchCamera","Error","deepClone","deviceId","facingMode","applyConstraints","_setVideoEffects","names","mediaStreamTrackSetVideoEffects","_setVideoEffect","name","_setMutedInternal","dispatchEvent","Event","_setVolume","volume","mediaStreamTrackSetVolume","normalized","normalizeConstraints","video","mediaStreamTrackApplyConstraints","clone","getCapabilities","getConstraints","getSettings","addListener","ev","trackId","debug","_setAudioSinkCallback","callback","_audioSinkCallback","_handleAudioSamples","data","setAudioSink","_audioSinkListenerActive","mediaStreamTrackEnableAudioSink","removeListenerForEvent","setPlaybackEnabled","_playbackEnabled","mediaStreamTrackSetPlaybackEnabled","isPlaybackEnabled","release","removeListener","mediaStreamTrackRelease","exports","proto","prototype","defineEventAttribute"],"sources":["MediaStreamTrack.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules, NativeEventEmitter, Platform } from 'react-native';\n\nimport { MediaTrackConstraints } from './Constraints';\nimport { addListener, removeListener, removeListenerForEvent } from './EventEmitter';\nimport Logger from './Logger';\nimport { deepClone, normalizeConstraints } from './RTCUtil';\n\nconst log = new Logger('pc');\nconst { WebRTCModule } = NativeModules;\n\nexport type AudioSampleData = {\n trackId: string;\n samples: number[];\n sampleRate: number;\n channels: number;\n timestamp: number;\n}\n\nexport type AudioSinkCallback = (data: AudioSampleData) => void;\n\n\ntype MediaStreamTrackState = 'live' | 'ended';\n\nexport type MediaStreamTrackInfo = {\n id: string;\n kind: string;\n remote: boolean;\n constraints: object;\n enabled: boolean;\n settings: object;\n peerConnectionId: number;\n readyState: MediaStreamTrackState;\n}\n\nexport type MediaTrackSettings = {\n width?: number;\n height?: number;\n frameRate?: number;\n facingMode?: string;\n deviceId?: string;\n groupId?: string;\n}\n\ntype MediaStreamTrackEventMap = {\n ended: Event<'ended'>;\n mute: Event<'mute'>;\n unmute: Event<'unmute'>;\n}\n\nexport default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventMap> {\n _constraints: MediaTrackConstraints;\n _enabled: boolean;\n _settings: MediaTrackSettings;\n _muted: boolean;\n _peerConnectionId: number;\n _readyState: MediaStreamTrackState;\n\n readonly id: string;\n readonly kind: string;\n readonly label: string = '';\n readonly remote: boolean;\n\n constructor(info: MediaStreamTrackInfo) {\n super();\n\n this._constraints = info.constraints || {};\n this._enabled = info.enabled;\n this._settings = info.settings || {};\n this._muted = false;\n this._peerConnectionId = info.peerConnectionId;\n this._readyState = info.readyState;\n\n this.id = info.id;\n this.kind = info.kind;\n this.remote = info.remote;\n\n if (!this.remote) {\n this._registerEvents();\n }\n }\n\n get enabled(): boolean {\n return this._enabled;\n }\n\n set enabled(enabled: boolean) {\n if (enabled === this._enabled) {\n return;\n }\n\n this._enabled = Boolean(enabled);\n\n if (this._readyState === 'ended') {\n return;\n }\n\n WebRTCModule.mediaStreamTrackSetEnabled(this.remote ? this._peerConnectionId : -1, this.id, this._enabled);\n }\n\n get muted(): boolean {\n return this._muted;\n }\n\n get readyState(): string {\n return this._readyState;\n }\n\n stop(): void {\n this.enabled = false;\n this._readyState = 'ended';\n }\n\n /**\n * Private / custom API for switching the cameras on the fly, without the\n * need for adding / removing tracks or doing any SDP renegotiation.\n *\n * This is how the reference application (AppRTCMobile) implements camera\n * switching.\n *\n * @deprecated Use applyConstraints instead.\n */\n _switchCamera(): void {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n const constraints = deepClone(this._settings);\n\n delete constraints.deviceId;\n constraints.facingMode = this._settings.facingMode === 'user' ? 'environment' : 'user';\n\n this.applyConstraints(constraints);\n }\n\n _setVideoEffects(names: string[]) {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVideoEffects(this.id, names);\n }\n\n _setVideoEffect(name: string) {\n this._setVideoEffects([ name ]);\n }\n\n /**\n * Internal function which is used to set the muted state on remote tracks and\n * emit the mute / unmute event.\n *\n * @param muted Whether the track should be marked as muted / unmuted.\n */\n _setMutedInternal(muted: boolean) {\n if (!this.remote) {\n throw new Error('Track is not remote!');\n }\n\n this._muted = muted;\n this.dispatchEvent(new Event(muted ? 'mute' : 'unmute'));\n }\n\n /**\n * Custom API for setting the volume on an individual audio track.\n *\n * @param volume a gain value in the range of 0-10. defaults to 1.0\n */\n _setVolume(volume: number) {\n if (this.kind !== 'audio') {\n throw new Error('Only implemented for audio tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVolume(this.remote ? this._peerConnectionId : -1, this.id, volume);\n }\n\n /**\n * Applies a new set of constraints to the track.\n *\n * @param constraints An object listing the constraints\n * to apply to the track's constrainable properties; any existing\n * constraints are replaced with the new values specified, and any\n * constrainable properties not included are restored to their default\n * constraints. If this parameter is omitted, all currently set custom\n * constraints are cleared.\n */\n async applyConstraints(constraints?: MediaTrackConstraints): Promise<void> {\n if (this.kind !== 'video') {\n log.info(`Only implemented for video tracks, ignoring applyConstraints for ${this.id}`);\n\n return;\n }\n\n const normalized = normalizeConstraints({ video: constraints ?? true });\n\n this._settings = await WebRTCModule.mediaStreamTrackApplyConstraints(this.id, normalized.video);\n this._constraints = constraints ?? {};\n }\n\n clone(): never {\n throw new Error('Not implemented.');\n }\n\n getCapabilities(): never {\n throw new Error('Not implemented.');\n }\n\n getConstraints() {\n return deepClone(this._constraints);\n }\n\n getSettings(): MediaTrackSettings {\n return deepClone(this._settings);\n }\n\n _registerEvents(): void {\n addListener(this, 'mediaStreamTrackEnded', (ev: any) => {\n if (ev.trackId !== this.id || this._readyState === 'ended') {\n return;\n }\n\n log.debug(`${this.id} mediaStreamTrackEnded`);\n this._readyState = 'ended';\n\n this.dispatchEvent(new Event('ended'));\n });\n }\n\n private _audioSinkCallback: AudioSinkCallback | null = null;\n private _audioSinkListenerActive: boolean = false;\n private _playbackEnabled: boolean = true;\n\n _setAudioSinkCallback(callback: AudioSinkCallback | null): void {\n this._audioSinkCallback = callback;\n }\n\n _handleAudioSamples(data: AudioSampleData): void {\n if (this._audioSinkCallback) {\n this._audioSinkCallback(data);\n }\n }\n\n setAudioSink(callback: AudioSinkCallback | null): void {\n if (this.kind !== 'audio') {\n throw new Error('Audio sink only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Audio sink only available for remote tracks');\n }\n\n this._setAudioSinkCallback(callback);\n\n if (callback && !this._audioSinkListenerActive) {\n this._audioSinkListenerActive = true;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n true\n );\n addListener(this, 'audioSamples', (ev: any) => {\n if (ev.trackId === this.id) {\n this._handleAudioSamples(ev);\n }\n });\n } else if (!callback && this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n }\n\n setPlaybackEnabled(enabled: boolean): void {\n if (this.kind !== 'audio') {\n throw new Error('Playback control only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Playback control only available for remote tracks');\n }\n\n this._playbackEnabled = enabled;\n WebRTCModule.mediaStreamTrackSetPlaybackEnabled(\n this._peerConnectionId,\n this.id,\n enabled\n );\n }\n\n isPlaybackEnabled(): boolean {\n return this._playbackEnabled;\n }\n\n release(): void {\n if (this.remote) {\n if (this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n return;\n }\n\n removeListener(this);\n WebRTCModule.mediaStreamTrackRelease(this.id);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaStreamTrack.prototype;\n\ndefineEventAttribute(proto, 'ended');\ndefineEventAttribute(proto, 'mute');\ndefineEventAttribute(proto, 'unmute');\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["_index","require","_reactNative","_EventEmitter","_Logger","_interopRequireDefault","_RTCUtil","obj","__esModule","default","_defineProperty","key","value","Object","defineProperty","enumerable","configurable","writable","log","Logger","WebRTCModule","NativeModules","MediaStreamTrack","EventTarget","constructor","info","_constraints","constraints","_enabled","enabled","_settings","settings","_muted","_peerConnectionId","peerConnectionId","_readyState","readyState","id","kind","remote","_registerEvents","Boolean","mediaStreamTrackSetEnabled","muted","stop","_switchCamera","Error","deepClone","deviceId","facingMode","applyConstraints","_setVideoEffects","names","mediaStreamTrackSetVideoEffects","_setVideoEffect","name","_setMutedInternal","dispatchEvent","Event","_setVolume","volume","mediaStreamTrackSetVolume","normalized","normalizeConstraints","video","mediaStreamTrackApplyConstraints","clone","getCapabilities","getConstraints","getSettings","addListener","ev","trackId","debug","_setAudioSinkCallback","callback","_audioSinkCallback","_handleAudioSamples","data","setAudioSink","_audioSinkListenerActive","mediaStreamTrackEnableAudioSink","removeListenerForEvent","setPlaybackEnabled","_playbackEnabled","mediaStreamTrackSetPlaybackEnabled","isPlaybackEnabled","release","removeListener","mediaStreamTrackRelease","exports","proto","prototype","defineEventAttribute"],"sources":["MediaStreamTrack.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport { MediaTrackConstraints } from './Constraints';\nimport { addListener, removeListener, removeListenerForEvent } from './EventEmitter';\nimport Logger from './Logger';\nimport { deepClone, normalizeConstraints } from './RTCUtil';\n\nconst log = new Logger('pc');\nconst { WebRTCModule } = NativeModules;\n\nexport type AudioSampleData = {\n trackId: string;\n samples: number[];\n sampleRate: number;\n channels: number;\n bitsPerSample: number;\n framesPerBuffer: number;\n timestamp: number;\n}\n\nexport type AudioSinkCallback = (data: AudioSampleData) => void;\n\n\ntype MediaStreamTrackState = 'live' | 'ended';\n\nexport type MediaStreamTrackInfo = {\n id: string;\n kind: string;\n remote: boolean;\n constraints: object;\n enabled: boolean;\n settings: object;\n peerConnectionId: number;\n readyState: MediaStreamTrackState;\n}\n\nexport type MediaTrackSettings = {\n width?: number;\n height?: number;\n frameRate?: number;\n facingMode?: string;\n deviceId?: string;\n groupId?: string;\n}\n\ntype MediaStreamTrackEventMap = {\n ended: Event<'ended'>;\n mute: Event<'mute'>;\n unmute: Event<'unmute'>;\n}\n\nexport default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventMap> {\n _constraints: MediaTrackConstraints;\n _enabled: boolean;\n _settings: MediaTrackSettings;\n _muted: boolean;\n _peerConnectionId: number;\n _readyState: MediaStreamTrackState;\n\n readonly id: string;\n readonly kind: string;\n readonly label: string = '';\n readonly remote: boolean;\n\n constructor(info: MediaStreamTrackInfo) {\n super();\n\n this._constraints = info.constraints || {};\n this._enabled = info.enabled;\n this._settings = info.settings || {};\n this._muted = false;\n this._peerConnectionId = info.peerConnectionId;\n this._readyState = info.readyState;\n\n this.id = info.id;\n this.kind = info.kind;\n this.remote = info.remote;\n\n if (!this.remote) {\n this._registerEvents();\n }\n }\n\n get enabled(): boolean {\n return this._enabled;\n }\n\n set enabled(enabled: boolean) {\n if (enabled === this._enabled) {\n return;\n }\n\n this._enabled = Boolean(enabled);\n\n if (this._readyState === 'ended') {\n return;\n }\n\n WebRTCModule.mediaStreamTrackSetEnabled(this.remote ? this._peerConnectionId : -1, this.id, this._enabled);\n }\n\n get muted(): boolean {\n return this._muted;\n }\n\n get readyState(): string {\n return this._readyState;\n }\n\n stop(): void {\n this.enabled = false;\n this._readyState = 'ended';\n }\n\n /**\n * Private / custom API for switching the cameras on the fly, without the\n * need for adding / removing tracks or doing any SDP renegotiation.\n *\n * This is how the reference application (AppRTCMobile) implements camera\n * switching.\n *\n * @deprecated Use applyConstraints instead.\n */\n _switchCamera(): void {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n const constraints = deepClone(this._settings);\n\n delete constraints.deviceId;\n constraints.facingMode = this._settings.facingMode === 'user' ? 'environment' : 'user';\n\n this.applyConstraints(constraints);\n }\n\n _setVideoEffects(names: string[]) {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVideoEffects(this.id, names);\n }\n\n _setVideoEffect(name: string) {\n this._setVideoEffects([ name ]);\n }\n\n /**\n * Internal function which is used to set the muted state on remote tracks and\n * emit the mute / unmute event.\n *\n * @param muted Whether the track should be marked as muted / unmuted.\n */\n _setMutedInternal(muted: boolean) {\n if (!this.remote) {\n throw new Error('Track is not remote!');\n }\n\n this._muted = muted;\n this.dispatchEvent(new Event(muted ? 'mute' : 'unmute'));\n }\n\n /**\n * Custom API for setting the volume on an individual audio track.\n *\n * @param volume a gain value in the range of 0-10. defaults to 1.0\n */\n _setVolume(volume: number) {\n if (this.kind !== 'audio') {\n throw new Error('Only implemented for audio tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVolume(this.remote ? this._peerConnectionId : -1, this.id, volume);\n }\n\n /**\n * Applies a new set of constraints to the track.\n *\n * @param constraints An object listing the constraints\n * to apply to the track's constrainable properties; any existing\n * constraints are replaced with the new values specified, and any\n * constrainable properties not included are restored to their default\n * constraints. If this parameter is omitted, all currently set custom\n * constraints are cleared.\n */\n async applyConstraints(constraints?: MediaTrackConstraints): Promise<void> {\n if (this.kind !== 'video') {\n log.info(`Only implemented for video tracks, ignoring applyConstraints for ${this.id}`);\n\n return;\n }\n\n const normalized = normalizeConstraints({ video: constraints ?? true });\n\n this._settings = await WebRTCModule.mediaStreamTrackApplyConstraints(this.id, normalized.video);\n this._constraints = constraints ?? {};\n }\n\n clone(): never {\n throw new Error('Not implemented.');\n }\n\n getCapabilities(): never {\n throw new Error('Not implemented.');\n }\n\n getConstraints() {\n return deepClone(this._constraints);\n }\n\n getSettings(): MediaTrackSettings {\n return deepClone(this._settings);\n }\n\n _registerEvents(): void {\n addListener(this, 'mediaStreamTrackEnded', (ev: any) => {\n if (ev.trackId !== this.id || this._readyState === 'ended') {\n return;\n }\n\n log.debug(`${this.id} mediaStreamTrackEnded`);\n this._readyState = 'ended';\n\n this.dispatchEvent(new Event('ended'));\n });\n }\n\n private _audioSinkCallback: AudioSinkCallback | null = null;\n private _audioSinkListenerActive = false;\n private _playbackEnabled = true;\n\n _setAudioSinkCallback(callback: AudioSinkCallback | null): void {\n this._audioSinkCallback = callback;\n }\n\n _handleAudioSamples(data: AudioSampleData): void {\n if (this._audioSinkCallback) {\n this._audioSinkCallback(data);\n }\n }\n\n setAudioSink(callback: AudioSinkCallback | null): void {\n if (this.kind !== 'audio') {\n throw new Error('Audio sink only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Audio sink only available for remote tracks');\n }\n\n this._setAudioSinkCallback(callback);\n\n if (callback && !this._audioSinkListenerActive) {\n this._audioSinkListenerActive = true;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n true\n );\n addListener(this, 'audioSamples', (ev: any) => {\n if (ev.trackId === this.id) {\n this._handleAudioSamples(ev);\n }\n });\n } else if (!callback && this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n }\n\n setPlaybackEnabled(enabled: boolean): void {\n if (this.kind !== 'audio') {\n throw new Error('Playback control only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Playback control only available for remote tracks');\n }\n\n this._playbackEnabled = enabled;\n WebRTCModule.mediaStreamTrackSetPlaybackEnabled(\n this._peerConnectionId,\n this.id,\n enabled\n );\n }\n\n isPlaybackEnabled(): boolean {\n return this._playbackEnabled;\n }\n\n release(): void {\n if (this.remote) {\n if (this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n\n return;\n }\n\n removeListener(this);\n WebRTCModule.mediaStreamTrackRelease(this.id);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaStreamTrack.prototype;\n\ndefineEventAttribute(proto, 'ended');\ndefineEventAttribute(proto, 'mute');\ndefineEventAttribute(proto, 'unmute');\n"],"mappings":"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"}
|
|
@@ -40,7 +40,9 @@ export function removeListener(listener) {
|
|
|
40
40
|
}
|
|
41
41
|
export function removeListenerForEvent(listener, eventName) {
|
|
42
42
|
const subs = _subscriptions.get(listener);
|
|
43
|
-
if (!subs)
|
|
43
|
+
if (!subs) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
44
46
|
const remaining = [];
|
|
45
47
|
subs.forEach(sub => {
|
|
46
48
|
if (sub.eventType === eventName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","NativeEventEmitter","EventEmitter","WebRTCModule","nativeEmitter","NATIVE_EVENTS","eventEmitter","setupNativeEvents","eventName","addListener","_len","arguments","length","args","Array","_key","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete","removeListenerForEvent","subs","remaining","eventType"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeModules, NativeEventEmitter, EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\n\nconst { WebRTCModule } = NativeModules;\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(WebRTCModule);\n\nconst NATIVE_EVENTS = [\n 'peerConnectionSignalingStateChanged',\n 'peerConnectionStateChanged',\n 'peerConnectionOnRenegotiationNeeded',\n 'peerConnectionIceConnectionChanged',\n 'peerConnectionIceGatheringChanged',\n 'peerConnectionGotICECandidate',\n 'peerConnectionDidOpenDataChannel',\n 'peerConnectionOnRemoveTrack',\n 'peerConnectionOnTrack',\n 'dataChannelStateChanged',\n 'dataChannelReceiveMessage',\n 'dataChannelDidChangeBufferedAmount',\n 'mediaStreamTrackMuteChanged',\n 'mediaStreamTrackEnded',\n 'frameCryptionStateChanged',\n 'audioSamples',\n];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(listener: Listener, eventName: string, eventHandler: EventHandler): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions.get(listener)?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach(sub => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n\nexport function removeListenerForEvent(listener: Listener, eventName: string): void {\n const subs = _subscriptions.get(listener);\n if (!subs) return;\n \n const remaining: EmitterSubscription[] = [];\n subs.forEach(sub => {\n if ((sub as any).eventType === eventName) {\n sub.remove();\n } else {\n remaining.push(sub);\n }\n });\n
|
|
1
|
+
{"version":3,"names":["NativeModules","NativeEventEmitter","EventEmitter","WebRTCModule","nativeEmitter","NATIVE_EVENTS","eventEmitter","setupNativeEvents","eventName","addListener","_len","arguments","length","args","Array","_key","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete","removeListenerForEvent","subs","remaining","eventType"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeModules, NativeEventEmitter, EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\n\nconst { WebRTCModule } = NativeModules;\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(WebRTCModule);\n\nconst NATIVE_EVENTS = [\n 'peerConnectionSignalingStateChanged',\n 'peerConnectionStateChanged',\n 'peerConnectionOnRenegotiationNeeded',\n 'peerConnectionIceConnectionChanged',\n 'peerConnectionIceGatheringChanged',\n 'peerConnectionGotICECandidate',\n 'peerConnectionDidOpenDataChannel',\n 'peerConnectionOnRemoveTrack',\n 'peerConnectionOnTrack',\n 'dataChannelStateChanged',\n 'dataChannelReceiveMessage',\n 'dataChannelDidChangeBufferedAmount',\n 'mediaStreamTrackMuteChanged',\n 'mediaStreamTrackEnded',\n 'frameCryptionStateChanged',\n 'audioSamples',\n];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(listener: Listener, eventName: string, eventHandler: EventHandler): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions.get(listener)?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach(sub => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n\nexport function removeListenerForEvent(listener: Listener, eventName: string): void {\n const subs = _subscriptions.get(listener);\n\n if (!subs) {\n return;\n }\n\n const remaining: EmitterSubscription[] = [];\n\n subs.forEach(sub => {\n if ((sub as any).eventType === eventName) {\n sub.remove();\n } else {\n remaining.push(sub);\n }\n });\n\n if (remaining.length === 0) {\n _subscriptions.delete(listener);\n } else {\n _subscriptions.set(listener, remaining);\n }\n}\n"],"mappings":"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"}
|
|
@@ -35,6 +35,19 @@ class MediaDevices extends EventTarget {
|
|
|
35
35
|
getUserMedia(constraints) {
|
|
36
36
|
return getUserMedia(constraints);
|
|
37
37
|
}
|
|
38
|
+
createVirtualAudioTrack() {
|
|
39
|
+
if (!WebRTCModule.createVirtualAudioTrack) {
|
|
40
|
+
return Promise.reject(new Error('virtual audio unavailable'));
|
|
41
|
+
}
|
|
42
|
+
return WebRTCModule.createVirtualAudioTrack();
|
|
43
|
+
}
|
|
44
|
+
pushVirtualAudioSamples(samples, sampleRate, channels) {
|
|
45
|
+
if (!WebRTCModule.pushVirtualAudioSamples) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const array = samples instanceof Int16Array ? Array.from(samples) : samples.slice();
|
|
49
|
+
WebRTCModule.pushVirtualAudioSamples(array, sampleRate, channels);
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
52
|
|
|
40
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["EventTarget","defineEventAttribute","NativeModules","getDisplayMedia","getUserMedia","WebRTCModule","MediaDevices","enumerateDevices","Promise","resolve","constraints","proto","prototype"],"sources":["MediaDevices.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport getDisplayMedia from './getDisplayMedia';\nimport getUserMedia, { Constraints } from './getUserMedia';\n\nconst { WebRTCModule } = NativeModules;\n\ntype MediaDevicesEventMap = {\n devicechange: Event<'devicechange'>\n}\n\nclass MediaDevices extends EventTarget<MediaDevicesEventMap> {\n /**\n * W3C \"Media Capture and Streams\" compatible {@code enumerateDevices}\n * implementation.\n */\n enumerateDevices() {\n return new Promise(resolve => WebRTCModule.enumerateDevices(resolve));\n }\n\n /**\n * W3C \"Screen Capture\" compatible {@code getDisplayMedia} implementation.\n * See: https://w3c.github.io/mediacapture-screen-share/\n *\n * @returns {Promise}\n */\n getDisplayMedia() {\n return getDisplayMedia();\n }\n\n /**\n * W3C \"Media Capture and Streams\" compatible {@code getUserMedia}\n * implementation.\n * See: https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-enumeratedevices\n *\n * @param {*} constraints\n * @returns {Promise}\n */\n getUserMedia(constraints: Constraints) {\n return getUserMedia(constraints);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaDevices.prototype;\n\ndefineEventAttribute(proto, 'devicechange');\n\n\nexport default new MediaDevices();\n"],"mappings":"AAAA,SAASA,WAAW,EAASC,oBAAoB,QAAQ,yBAAyB;AAClF,SAASC,aAAa,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["EventTarget","defineEventAttribute","NativeModules","getDisplayMedia","getUserMedia","WebRTCModule","MediaDevices","enumerateDevices","Promise","resolve","constraints","createVirtualAudioTrack","reject","Error","pushVirtualAudioSamples","samples","sampleRate","channels","array","Int16Array","Array","from","slice","proto","prototype"],"sources":["MediaDevices.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport { type MediaTrackSettings } from './MediaStreamTrack';\nimport getDisplayMedia from './getDisplayMedia';\nimport getUserMedia, { Constraints } from './getUserMedia';\n\nconst { WebRTCModule } = NativeModules;\n\ntype MediaDevicesEventMap = {\n devicechange: Event<'devicechange'>\n}\n\ntype VirtualTrackInfo = {\n enabled: boolean;\n id: string;\n kind: string;\n readyState: string;\n remote: boolean;\n settings: MediaTrackSettings;\n}\n\ntype VirtualAudioResponse = {\n streamId: string;\n tracks: VirtualTrackInfo[];\n}\n\nclass MediaDevices extends EventTarget<MediaDevicesEventMap> {\n /**\n * W3C \"Media Capture and Streams\" compatible {@code enumerateDevices}\n * implementation.\n */\n enumerateDevices() {\n return new Promise(resolve => WebRTCModule.enumerateDevices(resolve));\n }\n\n /**\n * W3C \"Screen Capture\" compatible {@code getDisplayMedia} implementation.\n * See: https://w3c.github.io/mediacapture-screen-share/\n *\n * @returns {Promise}\n */\n getDisplayMedia() {\n return getDisplayMedia();\n }\n\n /**\n * W3C \"Media Capture and Streams\" compatible {@code getUserMedia}\n * implementation.\n * See: https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-enumeratedevices\n *\n * @param {*} constraints\n * @returns {Promise}\n */\n getUserMedia(constraints: Constraints) {\n return getUserMedia(constraints);\n }\n\n createVirtualAudioTrack(): Promise<VirtualAudioResponse> {\n if (!WebRTCModule.createVirtualAudioTrack) {\n return Promise.reject(new Error('virtual audio unavailable'));\n }\n\n return WebRTCModule.createVirtualAudioTrack();\n }\n\n pushVirtualAudioSamples(samples: Int16Array | number[], sampleRate: number, channels: number) {\n if (!WebRTCModule.pushVirtualAudioSamples) {\n return;\n }\n\n const array = samples instanceof Int16Array ? Array.from(samples) : samples.slice();\n\n WebRTCModule.pushVirtualAudioSamples(array, sampleRate, channels);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaDevices.prototype;\n\ndefineEventAttribute(proto, 'devicechange');\n\n\nexport default new MediaDevices();\n"],"mappings":"AAAA,SAASA,WAAW,EAASC,oBAAoB,QAAQ,yBAAyB;AAClF,SAASC,aAAa,QAAQ,cAAc;AAG5C,OAAOC,eAAe,MAAM,mBAAmB;AAC/C,OAAOC,YAAY,MAAuB,gBAAgB;AAE1D,MAAM;EAAEC;AAAa,CAAC,GAAGH,aAAa;AAoBtC,MAAMI,YAAY,SAASN,WAAW,CAAuB;EACzD;AACJ;AACA;AACA;EACIO,gBAAgBA,CAAA,EAAG;IACf,OAAO,IAAIC,OAAO,CAACC,OAAO,IAAIJ,YAAY,CAACE,gBAAgB,CAACE,OAAO,CAAC,CAAC;EACzE;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACIN,eAAeA,CAAA,EAAG;IACd,OAAOA,eAAe,CAAC,CAAC;EAC5B;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACIC,YAAYA,CAACM,WAAwB,EAAE;IACnC,OAAON,YAAY,CAACM,WAAW,CAAC;EACpC;EAEAC,uBAAuBA,CAAA,EAAkC;IACrD,IAAI,CAACN,YAAY,CAACM,uBAAuB,EAAE;MACvC,OAAOH,OAAO,CAACI,MAAM,CAAC,IAAIC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACjE;IAEA,OAAOR,YAAY,CAACM,uBAAuB,CAAC,CAAC;EACjD;EAEAG,uBAAuBA,CAACC,OAA8B,EAAEC,UAAkB,EAAEC,QAAgB,EAAE;IAC1F,IAAI,CAACZ,YAAY,CAACS,uBAAuB,EAAE;MACvC;IACJ;IAEA,MAAMI,KAAK,GAAGH,OAAO,YAAYI,UAAU,GAAGC,KAAK,CAACC,IAAI,CAACN,OAAO,CAAC,GAAGA,OAAO,CAACO,KAAK,CAAC,CAAC;IAEnFjB,YAAY,CAACS,uBAAuB,CAACI,KAAK,EAAEF,UAAU,EAAEC,QAAQ,CAAC;EACrE;AACJ;;AAEA;AACA;AACA;AACA,MAAMM,KAAK,GAAGjB,YAAY,CAACkB,SAAS;AAEpCvB,oBAAoB,CAACsB,KAAK,EAAE,cAAc,CAAC;AAG3C,eAAe,IAAIjB,YAAY,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["EventTarget","Event","defineEventAttribute","NativeModules","addListener","removeListener","removeListenerForEvent","Logger","deepClone","normalizeConstraints","log","WebRTCModule","MediaStreamTrack","constructor","info","_defineProperty","_constraints","constraints","_enabled","enabled","_settings","settings","_muted","_peerConnectionId","peerConnectionId","_readyState","readyState","id","kind","remote","_registerEvents","Boolean","mediaStreamTrackSetEnabled","muted","stop","_switchCamera","Error","deviceId","facingMode","applyConstraints","_setVideoEffects","names","mediaStreamTrackSetVideoEffects","_setVideoEffect","name","_setMutedInternal","dispatchEvent","_setVolume","volume","mediaStreamTrackSetVolume","normalized","video","mediaStreamTrackApplyConstraints","clone","getCapabilities","getConstraints","getSettings","ev","trackId","debug","_setAudioSinkCallback","callback","_audioSinkCallback","_handleAudioSamples","data","setAudioSink","_audioSinkListenerActive","mediaStreamTrackEnableAudioSink","setPlaybackEnabled","_playbackEnabled","mediaStreamTrackSetPlaybackEnabled","isPlaybackEnabled","release","mediaStreamTrackRelease","proto","prototype"],"sources":["MediaStreamTrack.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules, NativeEventEmitter, Platform } from 'react-native';\n\nimport { MediaTrackConstraints } from './Constraints';\nimport { addListener, removeListener, removeListenerForEvent } from './EventEmitter';\nimport Logger from './Logger';\nimport { deepClone, normalizeConstraints } from './RTCUtil';\n\nconst log = new Logger('pc');\nconst { WebRTCModule } = NativeModules;\n\nexport type AudioSampleData = {\n trackId: string;\n samples: number[];\n sampleRate: number;\n channels: number;\n timestamp: number;\n}\n\nexport type AudioSinkCallback = (data: AudioSampleData) => void;\n\n\ntype MediaStreamTrackState = 'live' | 'ended';\n\nexport type MediaStreamTrackInfo = {\n id: string;\n kind: string;\n remote: boolean;\n constraints: object;\n enabled: boolean;\n settings: object;\n peerConnectionId: number;\n readyState: MediaStreamTrackState;\n}\n\nexport type MediaTrackSettings = {\n width?: number;\n height?: number;\n frameRate?: number;\n facingMode?: string;\n deviceId?: string;\n groupId?: string;\n}\n\ntype MediaStreamTrackEventMap = {\n ended: Event<'ended'>;\n mute: Event<'mute'>;\n unmute: Event<'unmute'>;\n}\n\nexport default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventMap> {\n _constraints: MediaTrackConstraints;\n _enabled: boolean;\n _settings: MediaTrackSettings;\n _muted: boolean;\n _peerConnectionId: number;\n _readyState: MediaStreamTrackState;\n\n readonly id: string;\n readonly kind: string;\n readonly label: string = '';\n readonly remote: boolean;\n\n constructor(info: MediaStreamTrackInfo) {\n super();\n\n this._constraints = info.constraints || {};\n this._enabled = info.enabled;\n this._settings = info.settings || {};\n this._muted = false;\n this._peerConnectionId = info.peerConnectionId;\n this._readyState = info.readyState;\n\n this.id = info.id;\n this.kind = info.kind;\n this.remote = info.remote;\n\n if (!this.remote) {\n this._registerEvents();\n }\n }\n\n get enabled(): boolean {\n return this._enabled;\n }\n\n set enabled(enabled: boolean) {\n if (enabled === this._enabled) {\n return;\n }\n\n this._enabled = Boolean(enabled);\n\n if (this._readyState === 'ended') {\n return;\n }\n\n WebRTCModule.mediaStreamTrackSetEnabled(this.remote ? this._peerConnectionId : -1, this.id, this._enabled);\n }\n\n get muted(): boolean {\n return this._muted;\n }\n\n get readyState(): string {\n return this._readyState;\n }\n\n stop(): void {\n this.enabled = false;\n this._readyState = 'ended';\n }\n\n /**\n * Private / custom API for switching the cameras on the fly, without the\n * need for adding / removing tracks or doing any SDP renegotiation.\n *\n * This is how the reference application (AppRTCMobile) implements camera\n * switching.\n *\n * @deprecated Use applyConstraints instead.\n */\n _switchCamera(): void {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n const constraints = deepClone(this._settings);\n\n delete constraints.deviceId;\n constraints.facingMode = this._settings.facingMode === 'user' ? 'environment' : 'user';\n\n this.applyConstraints(constraints);\n }\n\n _setVideoEffects(names: string[]) {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVideoEffects(this.id, names);\n }\n\n _setVideoEffect(name: string) {\n this._setVideoEffects([ name ]);\n }\n\n /**\n * Internal function which is used to set the muted state on remote tracks and\n * emit the mute / unmute event.\n *\n * @param muted Whether the track should be marked as muted / unmuted.\n */\n _setMutedInternal(muted: boolean) {\n if (!this.remote) {\n throw new Error('Track is not remote!');\n }\n\n this._muted = muted;\n this.dispatchEvent(new Event(muted ? 'mute' : 'unmute'));\n }\n\n /**\n * Custom API for setting the volume on an individual audio track.\n *\n * @param volume a gain value in the range of 0-10. defaults to 1.0\n */\n _setVolume(volume: number) {\n if (this.kind !== 'audio') {\n throw new Error('Only implemented for audio tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVolume(this.remote ? this._peerConnectionId : -1, this.id, volume);\n }\n\n /**\n * Applies a new set of constraints to the track.\n *\n * @param constraints An object listing the constraints\n * to apply to the track's constrainable properties; any existing\n * constraints are replaced with the new values specified, and any\n * constrainable properties not included are restored to their default\n * constraints. If this parameter is omitted, all currently set custom\n * constraints are cleared.\n */\n async applyConstraints(constraints?: MediaTrackConstraints): Promise<void> {\n if (this.kind !== 'video') {\n log.info(`Only implemented for video tracks, ignoring applyConstraints for ${this.id}`);\n\n return;\n }\n\n const normalized = normalizeConstraints({ video: constraints ?? true });\n\n this._settings = await WebRTCModule.mediaStreamTrackApplyConstraints(this.id, normalized.video);\n this._constraints = constraints ?? {};\n }\n\n clone(): never {\n throw new Error('Not implemented.');\n }\n\n getCapabilities(): never {\n throw new Error('Not implemented.');\n }\n\n getConstraints() {\n return deepClone(this._constraints);\n }\n\n getSettings(): MediaTrackSettings {\n return deepClone(this._settings);\n }\n\n _registerEvents(): void {\n addListener(this, 'mediaStreamTrackEnded', (ev: any) => {\n if (ev.trackId !== this.id || this._readyState === 'ended') {\n return;\n }\n\n log.debug(`${this.id} mediaStreamTrackEnded`);\n this._readyState = 'ended';\n\n this.dispatchEvent(new Event('ended'));\n });\n }\n\n private _audioSinkCallback: AudioSinkCallback | null = null;\n private _audioSinkListenerActive: boolean = false;\n private _playbackEnabled: boolean = true;\n\n _setAudioSinkCallback(callback: AudioSinkCallback | null): void {\n this._audioSinkCallback = callback;\n }\n\n _handleAudioSamples(data: AudioSampleData): void {\n if (this._audioSinkCallback) {\n this._audioSinkCallback(data);\n }\n }\n\n setAudioSink(callback: AudioSinkCallback | null): void {\n if (this.kind !== 'audio') {\n throw new Error('Audio sink only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Audio sink only available for remote tracks');\n }\n\n this._setAudioSinkCallback(callback);\n\n if (callback && !this._audioSinkListenerActive) {\n this._audioSinkListenerActive = true;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n true\n );\n addListener(this, 'audioSamples', (ev: any) => {\n if (ev.trackId === this.id) {\n this._handleAudioSamples(ev);\n }\n });\n } else if (!callback && this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n }\n\n setPlaybackEnabled(enabled: boolean): void {\n if (this.kind !== 'audio') {\n throw new Error('Playback control only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Playback control only available for remote tracks');\n }\n\n this._playbackEnabled = enabled;\n WebRTCModule.mediaStreamTrackSetPlaybackEnabled(\n this._peerConnectionId,\n this.id,\n enabled\n );\n }\n\n isPlaybackEnabled(): boolean {\n return this._playbackEnabled;\n }\n\n release(): void {\n if (this.remote) {\n if (this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n return;\n }\n\n removeListener(this);\n WebRTCModule.mediaStreamTrackRelease(this.id);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaStreamTrack.prototype;\n\ndefineEventAttribute(proto, 'ended');\ndefineEventAttribute(proto, 'mute');\ndefineEventAttribute(proto, 'unmute');\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["EventTarget","Event","defineEventAttribute","NativeModules","addListener","removeListener","removeListenerForEvent","Logger","deepClone","normalizeConstraints","log","WebRTCModule","MediaStreamTrack","constructor","info","_defineProperty","_constraints","constraints","_enabled","enabled","_settings","settings","_muted","_peerConnectionId","peerConnectionId","_readyState","readyState","id","kind","remote","_registerEvents","Boolean","mediaStreamTrackSetEnabled","muted","stop","_switchCamera","Error","deviceId","facingMode","applyConstraints","_setVideoEffects","names","mediaStreamTrackSetVideoEffects","_setVideoEffect","name","_setMutedInternal","dispatchEvent","_setVolume","volume","mediaStreamTrackSetVolume","normalized","video","mediaStreamTrackApplyConstraints","clone","getCapabilities","getConstraints","getSettings","ev","trackId","debug","_setAudioSinkCallback","callback","_audioSinkCallback","_handleAudioSamples","data","setAudioSink","_audioSinkListenerActive","mediaStreamTrackEnableAudioSink","setPlaybackEnabled","_playbackEnabled","mediaStreamTrackSetPlaybackEnabled","isPlaybackEnabled","release","mediaStreamTrackRelease","proto","prototype"],"sources":["MediaStreamTrack.ts"],"sourcesContent":["import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';\nimport { NativeModules } from 'react-native';\n\nimport { MediaTrackConstraints } from './Constraints';\nimport { addListener, removeListener, removeListenerForEvent } from './EventEmitter';\nimport Logger from './Logger';\nimport { deepClone, normalizeConstraints } from './RTCUtil';\n\nconst log = new Logger('pc');\nconst { WebRTCModule } = NativeModules;\n\nexport type AudioSampleData = {\n trackId: string;\n samples: number[];\n sampleRate: number;\n channels: number;\n bitsPerSample: number;\n framesPerBuffer: number;\n timestamp: number;\n}\n\nexport type AudioSinkCallback = (data: AudioSampleData) => void;\n\n\ntype MediaStreamTrackState = 'live' | 'ended';\n\nexport type MediaStreamTrackInfo = {\n id: string;\n kind: string;\n remote: boolean;\n constraints: object;\n enabled: boolean;\n settings: object;\n peerConnectionId: number;\n readyState: MediaStreamTrackState;\n}\n\nexport type MediaTrackSettings = {\n width?: number;\n height?: number;\n frameRate?: number;\n facingMode?: string;\n deviceId?: string;\n groupId?: string;\n}\n\ntype MediaStreamTrackEventMap = {\n ended: Event<'ended'>;\n mute: Event<'mute'>;\n unmute: Event<'unmute'>;\n}\n\nexport default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventMap> {\n _constraints: MediaTrackConstraints;\n _enabled: boolean;\n _settings: MediaTrackSettings;\n _muted: boolean;\n _peerConnectionId: number;\n _readyState: MediaStreamTrackState;\n\n readonly id: string;\n readonly kind: string;\n readonly label: string = '';\n readonly remote: boolean;\n\n constructor(info: MediaStreamTrackInfo) {\n super();\n\n this._constraints = info.constraints || {};\n this._enabled = info.enabled;\n this._settings = info.settings || {};\n this._muted = false;\n this._peerConnectionId = info.peerConnectionId;\n this._readyState = info.readyState;\n\n this.id = info.id;\n this.kind = info.kind;\n this.remote = info.remote;\n\n if (!this.remote) {\n this._registerEvents();\n }\n }\n\n get enabled(): boolean {\n return this._enabled;\n }\n\n set enabled(enabled: boolean) {\n if (enabled === this._enabled) {\n return;\n }\n\n this._enabled = Boolean(enabled);\n\n if (this._readyState === 'ended') {\n return;\n }\n\n WebRTCModule.mediaStreamTrackSetEnabled(this.remote ? this._peerConnectionId : -1, this.id, this._enabled);\n }\n\n get muted(): boolean {\n return this._muted;\n }\n\n get readyState(): string {\n return this._readyState;\n }\n\n stop(): void {\n this.enabled = false;\n this._readyState = 'ended';\n }\n\n /**\n * Private / custom API for switching the cameras on the fly, without the\n * need for adding / removing tracks or doing any SDP renegotiation.\n *\n * This is how the reference application (AppRTCMobile) implements camera\n * switching.\n *\n * @deprecated Use applyConstraints instead.\n */\n _switchCamera(): void {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n const constraints = deepClone(this._settings);\n\n delete constraints.deviceId;\n constraints.facingMode = this._settings.facingMode === 'user' ? 'environment' : 'user';\n\n this.applyConstraints(constraints);\n }\n\n _setVideoEffects(names: string[]) {\n if (this.remote) {\n throw new Error('Not implemented for remote tracks');\n }\n\n if (this.kind !== 'video') {\n throw new Error('Only implemented for video tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVideoEffects(this.id, names);\n }\n\n _setVideoEffect(name: string) {\n this._setVideoEffects([ name ]);\n }\n\n /**\n * Internal function which is used to set the muted state on remote tracks and\n * emit the mute / unmute event.\n *\n * @param muted Whether the track should be marked as muted / unmuted.\n */\n _setMutedInternal(muted: boolean) {\n if (!this.remote) {\n throw new Error('Track is not remote!');\n }\n\n this._muted = muted;\n this.dispatchEvent(new Event(muted ? 'mute' : 'unmute'));\n }\n\n /**\n * Custom API for setting the volume on an individual audio track.\n *\n * @param volume a gain value in the range of 0-10. defaults to 1.0\n */\n _setVolume(volume: number) {\n if (this.kind !== 'audio') {\n throw new Error('Only implemented for audio tracks');\n }\n\n WebRTCModule.mediaStreamTrackSetVolume(this.remote ? this._peerConnectionId : -1, this.id, volume);\n }\n\n /**\n * Applies a new set of constraints to the track.\n *\n * @param constraints An object listing the constraints\n * to apply to the track's constrainable properties; any existing\n * constraints are replaced with the new values specified, and any\n * constrainable properties not included are restored to their default\n * constraints. If this parameter is omitted, all currently set custom\n * constraints are cleared.\n */\n async applyConstraints(constraints?: MediaTrackConstraints): Promise<void> {\n if (this.kind !== 'video') {\n log.info(`Only implemented for video tracks, ignoring applyConstraints for ${this.id}`);\n\n return;\n }\n\n const normalized = normalizeConstraints({ video: constraints ?? true });\n\n this._settings = await WebRTCModule.mediaStreamTrackApplyConstraints(this.id, normalized.video);\n this._constraints = constraints ?? {};\n }\n\n clone(): never {\n throw new Error('Not implemented.');\n }\n\n getCapabilities(): never {\n throw new Error('Not implemented.');\n }\n\n getConstraints() {\n return deepClone(this._constraints);\n }\n\n getSettings(): MediaTrackSettings {\n return deepClone(this._settings);\n }\n\n _registerEvents(): void {\n addListener(this, 'mediaStreamTrackEnded', (ev: any) => {\n if (ev.trackId !== this.id || this._readyState === 'ended') {\n return;\n }\n\n log.debug(`${this.id} mediaStreamTrackEnded`);\n this._readyState = 'ended';\n\n this.dispatchEvent(new Event('ended'));\n });\n }\n\n private _audioSinkCallback: AudioSinkCallback | null = null;\n private _audioSinkListenerActive = false;\n private _playbackEnabled = true;\n\n _setAudioSinkCallback(callback: AudioSinkCallback | null): void {\n this._audioSinkCallback = callback;\n }\n\n _handleAudioSamples(data: AudioSampleData): void {\n if (this._audioSinkCallback) {\n this._audioSinkCallback(data);\n }\n }\n\n setAudioSink(callback: AudioSinkCallback | null): void {\n if (this.kind !== 'audio') {\n throw new Error('Audio sink only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Audio sink only available for remote tracks');\n }\n\n this._setAudioSinkCallback(callback);\n\n if (callback && !this._audioSinkListenerActive) {\n this._audioSinkListenerActive = true;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n true\n );\n addListener(this, 'audioSamples', (ev: any) => {\n if (ev.trackId === this.id) {\n this._handleAudioSamples(ev);\n }\n });\n } else if (!callback && this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n }\n\n setPlaybackEnabled(enabled: boolean): void {\n if (this.kind !== 'audio') {\n throw new Error('Playback control only available for audio tracks');\n }\n\n if (!this.remote) {\n throw new Error('Playback control only available for remote tracks');\n }\n\n this._playbackEnabled = enabled;\n WebRTCModule.mediaStreamTrackSetPlaybackEnabled(\n this._peerConnectionId,\n this.id,\n enabled\n );\n }\n\n isPlaybackEnabled(): boolean {\n return this._playbackEnabled;\n }\n\n release(): void {\n if (this.remote) {\n if (this._audioSinkListenerActive) {\n this._audioSinkListenerActive = false;\n WebRTCModule.mediaStreamTrackEnableAudioSink(\n this._peerConnectionId,\n this.id,\n false\n );\n removeListenerForEvent(this, 'audioSamples');\n }\n\n return;\n }\n\n removeListener(this);\n WebRTCModule.mediaStreamTrackRelease(this.id);\n }\n}\n\n/**\n * Define the `onxxx` event handlers.\n */\nconst proto = MediaStreamTrack.prototype;\n\ndefineEventAttribute(proto, 'ended');\ndefineEventAttribute(proto, 'mute');\ndefineEventAttribute(proto, 'unmute');\n"],"mappings":"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"}
|
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
import { EventTarget, Event } from 'event-target-shim/index';
|
|
2
|
+
import { type MediaTrackSettings } from './MediaStreamTrack';
|
|
2
3
|
import { Constraints } from './getUserMedia';
|
|
3
4
|
declare type MediaDevicesEventMap = {
|
|
4
5
|
devicechange: Event<'devicechange'>;
|
|
5
6
|
};
|
|
7
|
+
declare type VirtualTrackInfo = {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
id: string;
|
|
10
|
+
kind: string;
|
|
11
|
+
readyState: string;
|
|
12
|
+
remote: boolean;
|
|
13
|
+
settings: MediaTrackSettings;
|
|
14
|
+
};
|
|
15
|
+
declare type VirtualAudioResponse = {
|
|
16
|
+
streamId: string;
|
|
17
|
+
tracks: VirtualTrackInfo[];
|
|
18
|
+
};
|
|
6
19
|
declare class MediaDevices extends EventTarget<MediaDevicesEventMap> {
|
|
7
20
|
/**
|
|
8
21
|
* W3C "Media Capture and Streams" compatible {@code enumerateDevices}
|
|
@@ -25,6 +38,8 @@ declare class MediaDevices extends EventTarget<MediaDevicesEventMap> {
|
|
|
25
38
|
* @returns {Promise}
|
|
26
39
|
*/
|
|
27
40
|
getUserMedia(constraints: Constraints): Promise<import("./MediaStream").default>;
|
|
41
|
+
createVirtualAudioTrack(): Promise<VirtualAudioResponse>;
|
|
42
|
+
pushVirtualAudioSamples(samples: Int16Array | number[], sampleRate: number, channels: number): void;
|
|
28
43
|
}
|
|
29
44
|
declare const _default: MediaDevices;
|
|
30
45
|
export default _default;
|
package/package.json
CHANGED
package/src/EventEmitter.ts
CHANGED
|
@@ -64,9 +64,13 @@ export function removeListener(listener: Listener): void {
|
|
|
64
64
|
|
|
65
65
|
export function removeListenerForEvent(listener: Listener, eventName: string): void {
|
|
66
66
|
const subs = _subscriptions.get(listener);
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
|
|
68
|
+
if (!subs) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
69
72
|
const remaining: EmitterSubscription[] = [];
|
|
73
|
+
|
|
70
74
|
subs.forEach(sub => {
|
|
71
75
|
if ((sub as any).eventType === eventName) {
|
|
72
76
|
sub.remove();
|
|
@@ -74,7 +78,7 @@ export function removeListenerForEvent(listener: Listener, eventName: string): v
|
|
|
74
78
|
remaining.push(sub);
|
|
75
79
|
}
|
|
76
80
|
});
|
|
77
|
-
|
|
81
|
+
|
|
78
82
|
if (remaining.length === 0) {
|
|
79
83
|
_subscriptions.delete(listener);
|
|
80
84
|
} else {
|
package/src/MediaDevices.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';
|
|
2
2
|
import { NativeModules } from 'react-native';
|
|
3
3
|
|
|
4
|
+
import { type MediaTrackSettings } from './MediaStreamTrack';
|
|
4
5
|
import getDisplayMedia from './getDisplayMedia';
|
|
5
6
|
import getUserMedia, { Constraints } from './getUserMedia';
|
|
6
7
|
|
|
@@ -10,6 +11,20 @@ type MediaDevicesEventMap = {
|
|
|
10
11
|
devicechange: Event<'devicechange'>
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
type VirtualTrackInfo = {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
id: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
readyState: string;
|
|
19
|
+
remote: boolean;
|
|
20
|
+
settings: MediaTrackSettings;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type VirtualAudioResponse = {
|
|
24
|
+
streamId: string;
|
|
25
|
+
tracks: VirtualTrackInfo[];
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
class MediaDevices extends EventTarget<MediaDevicesEventMap> {
|
|
14
29
|
/**
|
|
15
30
|
* W3C "Media Capture and Streams" compatible {@code enumerateDevices}
|
|
@@ -40,6 +55,24 @@ class MediaDevices extends EventTarget<MediaDevicesEventMap> {
|
|
|
40
55
|
getUserMedia(constraints: Constraints) {
|
|
41
56
|
return getUserMedia(constraints);
|
|
42
57
|
}
|
|
58
|
+
|
|
59
|
+
createVirtualAudioTrack(): Promise<VirtualAudioResponse> {
|
|
60
|
+
if (!WebRTCModule.createVirtualAudioTrack) {
|
|
61
|
+
return Promise.reject(new Error('virtual audio unavailable'));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return WebRTCModule.createVirtualAudioTrack();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pushVirtualAudioSamples(samples: Int16Array | number[], sampleRate: number, channels: number) {
|
|
68
|
+
if (!WebRTCModule.pushVirtualAudioSamples) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const array = samples instanceof Int16Array ? Array.from(samples) : samples.slice();
|
|
73
|
+
|
|
74
|
+
WebRTCModule.pushVirtualAudioSamples(array, sampleRate, channels);
|
|
75
|
+
}
|
|
43
76
|
}
|
|
44
77
|
|
|
45
78
|
/**
|
package/src/MediaStreamTrack.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';
|
|
2
|
-
import { NativeModules
|
|
2
|
+
import { NativeModules } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { MediaTrackConstraints } from './Constraints';
|
|
5
5
|
import { addListener, removeListener, removeListenerForEvent } from './EventEmitter';
|
|
@@ -14,6 +14,8 @@ export type AudioSampleData = {
|
|
|
14
14
|
samples: number[];
|
|
15
15
|
sampleRate: number;
|
|
16
16
|
channels: number;
|
|
17
|
+
bitsPerSample: number;
|
|
18
|
+
framesPerBuffer: number;
|
|
17
19
|
timestamp: number;
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -234,8 +236,8 @@ export default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventM
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
private _audioSinkCallback: AudioSinkCallback | null = null;
|
|
237
|
-
private _audioSinkListenerActive
|
|
238
|
-
private _playbackEnabled
|
|
239
|
+
private _audioSinkListenerActive = false;
|
|
240
|
+
private _playbackEnabled = true;
|
|
239
241
|
|
|
240
242
|
_setAudioSinkCallback(callback: AudioSinkCallback | null): void {
|
|
241
243
|
this._audioSinkCallback = callback;
|
|
@@ -313,6 +315,7 @@ export default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventM
|
|
|
313
315
|
);
|
|
314
316
|
removeListenerForEvent(this, 'audioSamples');
|
|
315
317
|
}
|
|
318
|
+
|
|
316
319
|
return;
|
|
317
320
|
}
|
|
318
321
|
|