@sbhjt-gr/react-native-webrtc 124.0.2 → 124.0.3

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.
@@ -17,6 +17,7 @@ import org.webrtc.AudioTrackSink;
17
17
  import java.io.BufferedReader;
18
18
  import java.io.ByteArrayOutputStream;
19
19
  import java.io.IOException;
20
+ import java.io.InputStream;
20
21
  import java.io.InputStreamReader;
21
22
  import java.io.OutputStream;
22
23
  import java.net.HttpURLConnection;
@@ -158,18 +159,54 @@ public class PalabraClient implements AudioTrackSink {
158
159
 
159
160
  int responseCode = conn.getResponseCode();
160
161
  if (responseCode < 200 || responseCode >= 300) {
161
- throw new IOException("session_http_error_" + responseCode);
162
+ throw new IOException(buildSessionError(conn, responseCode));
163
+ }
164
+
165
+ String response = readStream(conn.getInputStream());
166
+
167
+ return new JSONObject(response);
168
+ }
169
+
170
+ private String buildSessionError(HttpURLConnection conn, int responseCode) throws IOException {
171
+ String fallback = "session_http_error_" + responseCode;
172
+ String payload = readStream(conn.getErrorStream());
173
+ if (payload.isEmpty()) {
174
+ return fallback;
175
+ }
176
+
177
+ try {
178
+ JSONObject json = new JSONObject(payload);
179
+ JSONArray errors = json.optJSONArray("errors");
180
+ if (errors != null && errors.length() > 0) {
181
+ JSONObject first = errors.optJSONObject(0);
182
+ if (first != null) {
183
+ String detail = first.optString("detail");
184
+ if (detail != null && !detail.isEmpty()) {
185
+ return fallback + ": " + detail;
186
+ }
187
+ }
188
+ }
189
+ } catch (JSONException e) {
190
+ Log.d(TAG, "session_error_parse_failed", e);
191
+ }
192
+
193
+ return fallback;
194
+ }
195
+
196
+ private String readStream(InputStream stream) throws IOException {
197
+ if (stream == null) {
198
+ return "";
162
199
  }
163
200
 
164
201
  StringBuilder response = new StringBuilder();
165
- try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
202
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
166
203
  String line;
167
204
  while ((line = br.readLine()) != null) {
168
205
  response.append(line);
169
206
  }
170
207
  }
171
208
 
172
- return new JSONObject(response.toString());
209
+ return response.toString();
173
210
  }
174
211
 
175
212
  private void connectWebSocket() {
@@ -165,9 +165,10 @@ static const int kChunkBytes = kChunkSamples * 2;
165
165
 
166
166
  NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
167
167
  if (httpResponse.statusCode < 200 || httpResponse.statusCode >= 300) {
168
+ NSString *message = [self sessionErrorMessageForStatusCode:httpResponse.statusCode data:data];
168
169
  NSError *httpError = [NSError errorWithDomain:@"PalabraClient"
169
170
  code:httpResponse.statusCode
170
- userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"session_http_error_%ld", (long)httpResponse.statusCode]}];
171
+ userInfo:@{NSLocalizedDescriptionKey: message}];
171
172
  dispatch_async(dispatch_get_main_queue(), ^{
172
173
  completion(nil, httpError);
173
174
  });
@@ -185,6 +186,36 @@ static const int kChunkBytes = kChunkSamples * 2;
185
186
  [task resume];
186
187
  }
187
188
 
189
+ - (NSString *)sessionErrorMessageForStatusCode:(NSInteger)statusCode data:(NSData *)data {
190
+ NSString *fallback = [NSString stringWithFormat:@"session_http_error_%ld", (long)statusCode];
191
+ if (!data || data.length == 0) {
192
+ return fallback;
193
+ }
194
+
195
+ NSError *parseError;
196
+ id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
197
+ if (parseError || ![json isKindOfClass:[NSDictionary class]]) {
198
+ return fallback;
199
+ }
200
+
201
+ NSArray *errors = ((NSDictionary *)json)[@"errors"];
202
+ if (![errors isKindOfClass:[NSArray class]] || errors.count == 0) {
203
+ return fallback;
204
+ }
205
+
206
+ NSDictionary *first = errors.firstObject;
207
+ if (![first isKindOfClass:[NSDictionary class]]) {
208
+ return fallback;
209
+ }
210
+
211
+ NSString *detail = first[@"detail"];
212
+ if (![detail isKindOfClass:[NSString class]] || detail.length == 0) {
213
+ return fallback;
214
+ }
215
+
216
+ return [NSString stringWithFormat:@"%@: %@", fallback, detail];
217
+ }
218
+
188
219
  - (void)connectWebSocket {
189
220
  NSString *endpoint = [NSString stringWithFormat:@"%@?token=%@", self.wsUrl, self.publisherToken];
190
221
  NSLog(@"palabra_connecting_ws: %@", endpoint);
@@ -194,23 +225,36 @@ static const int kChunkBytes = kChunkSamples * 2;
194
225
  [self.webSocket resume];
195
226
 
196
227
  [self receiveMessage];
197
-
228
+ }
229
+
230
+ - (void)handleWebSocketOpened {
231
+ if (self.connected || self.translating || !self.webSocket) {
232
+ return;
233
+ }
234
+
198
235
  self.connected = YES;
199
236
  self.translating = YES;
200
-
237
+
201
238
  [self.remoteTrack addRenderer:self];
202
-
239
+
203
240
  NSError *audioError;
204
241
  [self.audioEngine startAndReturnError:&audioError];
205
242
  if (audioError) {
206
243
  NSLog(@"palabra_audio_engine_error: %@", audioError);
207
- } else {
208
- [self.playerNode play];
209
- NSLog(@"palabra_audio_engine_started");
244
+ [self.remoteTrack removeRenderer:self];
245
+ self.translating = NO;
246
+ self.connected = NO;
247
+ [self.webSocket cancelWithCloseCode:NSURLSessionWebSocketCloseCodeInternalServerError reason:nil];
248
+ self.webSocket = nil;
249
+ [self notifyError:audioError];
250
+ return;
210
251
  }
211
-
252
+
253
+ [self.playerNode play];
254
+ NSLog(@"palabra_audio_engine_started");
255
+
212
256
  [self notifyConnectionState:@"connected"];
213
-
257
+
214
258
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
215
259
  [self sendSetTask];
216
260
  });
@@ -496,6 +540,19 @@ static const int kChunkBytes = kChunkSamples * 2;
496
540
  if (dstSamples == 0) dstSamples = 1;
497
541
 
498
542
  int16_t *dstData = malloc(dstSamples * sizeof(int16_t));
543
+
544
+ if (dstSamples == 1 || srcSamples == 1) {
545
+ float sample = monoSrc[0];
546
+ sample = fmaxf(-1.0f, fminf(1.0f, sample));
547
+ dstData[0] = (int16_t)(sample * 32767.0f);
548
+
549
+ if (monoBuffer) free(monoBuffer);
550
+ if (tempFloat) free(tempFloat);
551
+
552
+ NSData *result = [NSData dataWithBytes:dstData length:sizeof(int16_t)];
553
+ free(dstData);
554
+ return result;
555
+ }
499
556
 
500
557
  for (int i = 0; i < dstSamples; i++) {
501
558
  float srcIdx = (float)i * (srcSamples - 1) / (dstSamples - 1);
@@ -560,7 +617,7 @@ static const int kChunkBytes = kChunkSamples * 2;
560
617
  if ([self.delegate respondsToSelector:@selector(palabraDidReceiveTranscription:)]) {
561
618
  [self.delegate palabraDidReceiveTranscription:@{
562
619
  @"text": text,
563
- @"language": lang,
620
+ @"lang": lang,
564
621
  @"isFinal": @(isFinal)
565
622
  }];
566
623
  }
@@ -570,6 +627,9 @@ static const int kChunkBytes = kChunkSamples * 2;
570
627
 
571
628
  - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask didOpenWithProtocol:(NSString *)protocol {
572
629
  NSLog(@"palabra_ws_opened");
630
+ dispatch_async(dispatch_get_main_queue(), ^{
631
+ [self handleWebSocketOpened];
632
+ });
573
633
  }
574
634
 
575
635
  - (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData *)reason {
@@ -79,12 +79,24 @@ class RTCPeerConnection extends _index.EventTarget {
79
79
  log.debug(`${this._pcId} ctor`);
80
80
  }
81
81
  async createOffer(options) {
82
+ var _sdpInfo$sdp$length, _sdpInfo$sdp;
83
+ const _t0 = Date.now();
84
+ console.log(`[RNWebRTC] pc:${this._pcId} create_offer_start`, {
85
+ signalingState: this.signalingState,
86
+ connectionState: this.connectionState,
87
+ iceConnectionState: this.iceConnectionState
88
+ });
82
89
  log.debug(`${this._pcId} createOffer`);
83
90
  const {
84
91
  sdpInfo,
85
92
  newTransceivers,
86
93
  transceiversInfo
87
94
  } = await WebRTCModule.peerConnectionCreateOffer(this._pcId, RTCUtil.normalizeOfferOptions(options));
95
+ console.log(`[RNWebRTC] pc:${this._pcId} create_offer_done`, {
96
+ durationMs: Date.now() - _t0,
97
+ sdpType: sdpInfo === null || sdpInfo === void 0 ? void 0 : sdpInfo.type,
98
+ sdpLen: (_sdpInfo$sdp$length = sdpInfo === null || sdpInfo === void 0 ? void 0 : (_sdpInfo$sdp = sdpInfo.sdp) === null || _sdpInfo$sdp === void 0 ? void 0 : _sdpInfo$sdp.length) !== null && _sdpInfo$sdp$length !== void 0 ? _sdpInfo$sdp$length : 0
99
+ });
88
100
  log.debug(`${this._pcId} createOffer OK`);
89
101
  newTransceivers === null || newTransceivers === void 0 ? void 0 : newTransceivers.forEach(t => {
90
102
  const {
@@ -111,11 +123,22 @@ class RTCPeerConnection extends _index.EventTarget {
111
123
  return sdpInfo;
112
124
  }
113
125
  async createAnswer() {
126
+ var _sdpInfo$sdp$length2, _sdpInfo$sdp2;
127
+ const _t0 = Date.now();
128
+ console.log(`[RNWebRTC] pc:${this._pcId} create_answer_start`, {
129
+ signalingState: this.signalingState,
130
+ connectionState: this.connectionState
131
+ });
114
132
  log.debug(`${this._pcId} createAnswer`);
115
133
  const {
116
134
  sdpInfo,
117
135
  transceiversInfo
118
136
  } = await WebRTCModule.peerConnectionCreateAnswer(this._pcId, {});
137
+ console.log(`[RNWebRTC] pc:${this._pcId} create_answer_done`, {
138
+ durationMs: Date.now() - _t0,
139
+ sdpType: sdpInfo === null || sdpInfo === void 0 ? void 0 : sdpInfo.type,
140
+ sdpLen: (_sdpInfo$sdp$length2 = sdpInfo === null || sdpInfo === void 0 ? void 0 : (_sdpInfo$sdp2 = sdpInfo.sdp) === null || _sdpInfo$sdp2 === void 0 ? void 0 : _sdpInfo$sdp2.length) !== null && _sdpInfo$sdp$length2 !== void 0 ? _sdpInfo$sdp$length2 : 0
141
+ });
119
142
  this._updateTransceivers(transceiversInfo);
120
143
  return sdpInfo;
121
144
  }
@@ -123,14 +146,20 @@ class RTCPeerConnection extends _index.EventTarget {
123
146
  WebRTCModule.peerConnectionSetConfiguration(configuration, this._pcId);
124
147
  }
125
148
  async setLocalDescription(sessionDescription) {
126
- var _desc;
149
+ var _sessionDescription$s, _sessionDescription$s2, _desc;
150
+ const _t0 = Date.now();
151
+ console.log(`[RNWebRTC] pc:${this._pcId} set_local_desc_start`, {
152
+ type: sessionDescription === null || sessionDescription === void 0 ? void 0 : sessionDescription.type,
153
+ sdpLen: (_sessionDescription$s = sessionDescription === null || sessionDescription === void 0 ? void 0 : (_sessionDescription$s2 = sessionDescription.sdp) === null || _sessionDescription$s2 === void 0 ? void 0 : _sessionDescription$s2.length) !== null && _sessionDescription$s !== void 0 ? _sessionDescription$s : 0,
154
+ signalingState: this.signalingState
155
+ });
127
156
  log.debug(`${this._pcId} setLocalDescription`);
128
157
  let desc;
129
158
  if (sessionDescription) {
130
- var _sessionDescription$s;
159
+ var _sessionDescription$s3;
131
160
  desc = {
132
161
  type: sessionDescription.type,
133
- sdp: (_sessionDescription$s = sessionDescription.sdp) !== null && _sessionDescription$s !== void 0 ? _sessionDescription$s : ''
162
+ sdp: (_sessionDescription$s3 = sessionDescription.sdp) !== null && _sessionDescription$s3 !== void 0 ? _sessionDescription$s3 : ''
134
163
  };
135
164
  if (!RTCUtil.isSdpTypeValid(desc.type)) {
136
165
  throw new Error(`Invalid session description: invalid type: ${desc.type}`);
@@ -148,17 +177,28 @@ class RTCPeerConnection extends _index.EventTarget {
148
177
  this.localDescription = null;
149
178
  }
150
179
  this._updateTransceivers(transceiversInfo, /* removeStopped */((_desc = desc) === null || _desc === void 0 ? void 0 : _desc.type) === 'answer');
180
+ console.log(`[RNWebRTC] pc:${this._pcId} set_local_desc_done`, {
181
+ durationMs: Date.now() - _t0,
182
+ signalingState: this.signalingState
183
+ });
151
184
  log.debug(`${this._pcId} setLocalDescription OK`);
152
185
  }
153
186
  async setRemoteDescription(sessionDescription) {
154
- var _sessionDescription$s2, _desc$type;
187
+ var _sessionDescription$s4, _sessionDescription$s5, _sessionDescription$s6, _desc$type;
188
+ const _t0 = Date.now();
189
+ console.log(`[RNWebRTC] pc:${this._pcId} set_remote_desc_start`, {
190
+ type: sessionDescription === null || sessionDescription === void 0 ? void 0 : sessionDescription.type,
191
+ sdpLen: (_sessionDescription$s4 = sessionDescription === null || sessionDescription === void 0 ? void 0 : (_sessionDescription$s5 = sessionDescription.sdp) === null || _sessionDescription$s5 === void 0 ? void 0 : _sessionDescription$s5.length) !== null && _sessionDescription$s4 !== void 0 ? _sessionDescription$s4 : 0,
192
+ signalingState: this.signalingState,
193
+ connectionState: this.connectionState
194
+ });
155
195
  log.debug(`${this._pcId} setRemoteDescription`);
156
196
  if (!sessionDescription) {
157
197
  return Promise.reject(new Error('No session description provided'));
158
198
  }
159
199
  const desc = {
160
200
  type: sessionDescription.type,
161
- sdp: (_sessionDescription$s2 = sessionDescription.sdp) !== null && _sessionDescription$s2 !== void 0 ? _sessionDescription$s2 : ''
201
+ sdp: (_sessionDescription$s6 = sessionDescription.sdp) !== null && _sessionDescription$s6 !== void 0 ? _sessionDescription$s6 : ''
162
202
  };
163
203
  if (!RTCUtil.isSdpTypeValid((_desc$type = desc.type) !== null && _desc$type !== void 0 ? _desc$type : '')) {
164
204
  throw new Error(`Invalid session description: invalid type: ${desc.type}`);
@@ -246,9 +286,24 @@ class RTCPeerConnection extends _index.EventTarget {
246
286
  // Dispatch an unmute event for the track.
247
287
  track._setMutedInternal(false);
248
288
  }
289
+ console.log(`[RNWebRTC] pc:${this._pcId} set_remote_desc_done`, {
290
+ durationMs: Date.now() - _t0,
291
+ signalingState: this.signalingState,
292
+ pendingTrackEventsDispatched: this._pendingTrackEvents.length
293
+ });
249
294
  log.debug(`${this._pcId} setRemoteDescription OK`);
250
295
  }
251
296
  async addIceCandidate(candidate) {
297
+ console.log(`[RNWebRTC] pc:${this._pcId} add_ice_candidate`, {
298
+ type: candidate === null || candidate === void 0 ? void 0 : candidate.type,
299
+ protocol: candidate === null || candidate === void 0 ? void 0 : candidate.protocol,
300
+ sdpMid: candidate === null || candidate === void 0 ? void 0 : candidate.sdpMid,
301
+ sdpMLineIndex: candidate === null || candidate === void 0 ? void 0 : candidate.sdpMLineIndex,
302
+ empty: !(candidate !== null && candidate !== void 0 && candidate.candidate),
303
+ signalingState: this.signalingState,
304
+ connectionState: this.connectionState,
305
+ iceConnectionState: this.iceConnectionState
306
+ });
252
307
  log.debug(`${this._pcId} addIceCandidate`);
253
308
  if (!candidate || !candidate.candidate) {
254
309
  // XXX end-of candidates is not implemented: https://bugs.chromium.org/p/webrtc/issues/detail?id=9218
@@ -465,22 +520,43 @@ class RTCPeerConnection extends _index.EventTarget {
465
520
  if (ev.pcId !== this._pcId) {
466
521
  return;
467
522
  }
523
+ console.log(`[RNWebRTC] pc:${this._pcId} negotiation_needed`, {
524
+ signalingState: this.signalingState,
525
+ connectionState: this.connectionState,
526
+ iceConnectionState: this.iceConnectionState
527
+ });
468
528
  this.dispatchEvent(new _index.Event('negotiationneeded'));
469
529
  });
470
530
  (0, _EventEmitter.addListener)(this, 'peerConnectionIceConnectionChanged', ev => {
471
531
  if (ev.pcId !== this._pcId) {
472
532
  return;
473
533
  }
534
+ const prev = this.iceConnectionState;
474
535
  this.iceConnectionState = ev.iceConnectionState;
536
+ console.log(`[RNWebRTC] pc:${this._pcId} ice_connection_changed`, {
537
+ prev,
538
+ current: ev.iceConnectionState,
539
+ connectionState: this.connectionState,
540
+ signalingState: this.signalingState
541
+ });
475
542
  this.dispatchEvent(new _index.Event('iceconnectionstatechange'));
476
543
  });
477
544
  (0, _EventEmitter.addListener)(this, 'peerConnectionStateChanged', ev => {
478
545
  if (ev.pcId !== this._pcId) {
479
546
  return;
480
547
  }
548
+ const prev = this.connectionState;
481
549
  this.connectionState = ev.connectionState;
550
+ console.log(`[RNWebRTC] pc:${this._pcId} connection_state_changed`, {
551
+ prev,
552
+ current: ev.connectionState,
553
+ iceConnectionState: this.iceConnectionState,
554
+ iceGatheringState: this.iceGatheringState,
555
+ signalingState: this.signalingState
556
+ });
482
557
  this.dispatchEvent(new _index.Event('connectionstatechange'));
483
558
  if (ev.connectionState === 'closed') {
559
+ console.log(`[RNWebRTC] pc:${this._pcId} disposing`);
484
560
  // This PeerConnection is done, clean up.
485
561
  (0, _EventEmitter.removeListener)(this);
486
562
  WebRTCModule.peerConnectionDispose(this._pcId);
@@ -490,15 +566,28 @@ class RTCPeerConnection extends _index.EventTarget {
490
566
  if (ev.pcId !== this._pcId) {
491
567
  return;
492
568
  }
569
+ const prev = this.signalingState;
493
570
  this.signalingState = ev.signalingState;
571
+ console.log(`[RNWebRTC] pc:${this._pcId} signaling_state_changed`, {
572
+ prev,
573
+ current: ev.signalingState,
574
+ connectionState: this.connectionState
575
+ });
494
576
  this.dispatchEvent(new _index.Event('signalingstatechange'));
495
577
  });
496
578
 
497
579
  // Consider moving away from this event: https://github.com/WebKit/WebKit/pull/3953
498
580
  (0, _EventEmitter.addListener)(this, 'peerConnectionOnTrack', ev => {
581
+ var _ev$receiver, _ev$receiver2, _ev$receiver2$track, _ev$streams$length, _ev$streams;
499
582
  if (ev.pcId !== this._pcId) {
500
583
  return;
501
584
  }
585
+ console.log(`[RNWebRTC] pc:${this._pcId} track_event_queued`, {
586
+ receiverId: (_ev$receiver = ev.receiver) === null || _ev$receiver === void 0 ? void 0 : _ev$receiver.id,
587
+ trackKind: (_ev$receiver2 = ev.receiver) === null || _ev$receiver2 === void 0 ? void 0 : (_ev$receiver2$track = _ev$receiver2.track) === null || _ev$receiver2$track === void 0 ? void 0 : _ev$receiver2$track.kind,
588
+ streamCount: (_ev$streams$length = (_ev$streams = ev.streams) === null || _ev$streams === void 0 ? void 0 : _ev$streams.length) !== null && _ev$streams$length !== void 0 ? _ev$streams$length : 0,
589
+ pendingCount: this._pendingTrackEvents.length + 1
590
+ });
502
591
  log.debug(`${this._pcId} ontrack`);
503
592
 
504
593
  // NOTE: We need to make sure the track event fires right before sRD completes,
@@ -510,6 +599,9 @@ class RTCPeerConnection extends _index.EventTarget {
510
599
  if (ev.pcId !== this._pcId) {
511
600
  return;
512
601
  }
602
+ console.log(`[RNWebRTC] pc:${this._pcId} remove_track`, {
603
+ receiverId: ev.receiverId
604
+ });
513
605
  log.debug(`${this._pcId} onremovetrack ${ev.receiverId}`);
514
606
  const receiver = this.getReceivers().find(r => r.id === ev.receiverId);
515
607
  const track = receiver === null || receiver === void 0 ? void 0 : receiver.track;
@@ -535,9 +627,16 @@ class RTCPeerConnection extends _index.EventTarget {
535
627
  }
536
628
  });
537
629
  (0, _EventEmitter.addListener)(this, 'peerConnectionGotICECandidate', ev => {
630
+ var _ev$candidate, _ev$candidate2, _ev$candidate3;
538
631
  if (ev.pcId !== this._pcId) {
539
632
  return;
540
633
  }
634
+ console.log(`[RNWebRTC] pc:${this._pcId} local_ice_candidate`, {
635
+ type: (_ev$candidate = ev.candidate) === null || _ev$candidate === void 0 ? void 0 : _ev$candidate.type,
636
+ protocol: (_ev$candidate2 = ev.candidate) === null || _ev$candidate2 === void 0 ? void 0 : _ev$candidate2.protocol,
637
+ sdpMid: (_ev$candidate3 = ev.candidate) === null || _ev$candidate3 === void 0 ? void 0 : _ev$candidate3.sdpMid,
638
+ iceGatheringState: this.iceGatheringState
639
+ });
541
640
  const sdpInfo = ev.sdp;
542
641
 
543
642
  // Can happen when doing a rollback.
@@ -555,7 +654,13 @@ class RTCPeerConnection extends _index.EventTarget {
555
654
  if (ev.pcId !== this._pcId) {
556
655
  return;
557
656
  }
657
+ const prev = this.iceGatheringState;
558
658
  this.iceGatheringState = ev.iceGatheringState;
659
+ console.log(`[RNWebRTC] pc:${this._pcId} ice_gathering_state_changed`, {
660
+ prev,
661
+ current: ev.iceGatheringState,
662
+ connectionState: this.connectionState
663
+ });
559
664
  if (this.iceGatheringState === 'complete') {
560
665
  const sdpInfo = ev.sdp;
561
666