Skip to content

Commit f9fa365

Browse files
authored
fix: race condition for local track dimension update (#16)
## The issue when getUserMedia is made. native side track is created, and immediately dimensions event is sent but JS side, the constructor happens after track is created (resulting in not listening to the event) in the end we never really received the event for the first ever local stream ## The fix listen to the event in JS before track is created by holding a cache
1 parent dc23387 commit f9fa365

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

src/MediaDevices.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,40 @@
11
import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index';
22
import { NativeModules } from 'react-native';
33

4+
import { addListener } from './EventEmitter';
45
import getDisplayMedia from './getDisplayMedia';
56
import getUserMedia, { Constraints } from './getUserMedia';
67

78
const { WebRTCModule } = NativeModules;
89

10+
export type VideoTrackDimension = {
11+
width: number;
12+
height: number;
13+
};
14+
15+
export const videoTrackDimensionChangedEventQueue = new Map<string, VideoTrackDimension>();
16+
17+
let listenersReady = false;
18+
19+
function ensureListeners() {
20+
if (listenersReady) {
21+
return;
22+
}
23+
24+
addListener('MediaDevices', 'videoTrackDimensionChanged', (ev: any) => {
25+
// We only want to queue events for local tracks.
26+
if (ev.pcId !== -1) {
27+
return;
28+
}
29+
30+
const { trackId, width, height } = ev;
31+
32+
videoTrackDimensionChangedEventQueue.set(trackId, { width, height });
33+
});
34+
35+
listenersReady = true;
36+
}
37+
938
type MediaDevicesEventMap = {
1039
devicechange: Event<'devicechange'>
1140
}
@@ -26,6 +55,8 @@ class MediaDevices extends EventTarget<MediaDevicesEventMap> {
2655
* @returns {Promise}
2756
*/
2857
getDisplayMedia() {
58+
ensureListeners();
59+
2960
return getDisplayMedia();
3061
}
3162

@@ -38,6 +69,8 @@ class MediaDevices extends EventTarget<MediaDevicesEventMap> {
3869
* @returns {Promise}
3970
*/
4071
getUserMedia(constraints: Constraints) {
72+
ensureListeners();
73+
4174
return getUserMedia(constraints);
4275
}
4376
}

src/MediaStreamTrack.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { NativeModules } from 'react-native';
44
import { MediaTrackConstraints } from './Constraints';
55
import { addListener, removeListener } from './EventEmitter';
66
import Logger from './Logger';
7+
import { videoTrackDimensionChangedEventQueue } from './MediaDevices';
78
import { deepClone, normalizeConstraints } from './RTCUtil';
89

910
const log = new Logger('pc');
@@ -54,19 +55,22 @@ export default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventM
5455
constructor(info: MediaStreamTrackInfo) {
5556
super();
5657

58+
this.id = info.id;
59+
this.kind = info.kind;
60+
this.remote = info.remote;
5761
this._constraints = info.constraints || {};
5862
this._enabled = info.enabled;
5963
this._settings = info.settings || {};
6064
this._muted = false;
6165
this._peerConnectionId = info.peerConnectionId;
6266
this._readyState = info.readyState;
6367

64-
this.id = info.id;
65-
this.kind = info.kind;
66-
this.remote = info.remote;
67-
6868
if (!this.remote) {
6969
this._registerEvents();
70+
71+
if (this.kind === 'video') {
72+
this._processVideoTrackDimensionChangedQueue();
73+
}
7074
}
7175
}
7276

@@ -272,13 +276,32 @@ export default class MediaStreamTrack extends EventTarget<MediaStreamTrackEventM
272276
}
273277
}
274278

279+
/**
280+
* Processes any queued `videoTrackDimensionChanged` events for this track.
281+
*/
282+
_processVideoTrackDimensionChangedQueue(): void {
283+
const eventData = videoTrackDimensionChangedEventQueue.get(this.id);
284+
285+
if (!eventData) {
286+
return;
287+
}
288+
289+
this._setVideoTrackDimensions(eventData.width, eventData.height);
290+
291+
videoTrackDimensionChangedEventQueue.delete(this.id);
292+
}
293+
275294
release(): void {
276295
if (this.remote) {
277296
return;
278297
}
279298

280299
removeListener(this);
281300
WebRTCModule.mediaStreamTrackRelease(this.id);
301+
302+
if (this.kind === 'video') {
303+
videoTrackDimensionChangedEventQueue.delete(this.id);
304+
}
282305
}
283306
}
284307

0 commit comments

Comments
 (0)