@stream-io/video-react-native-sdk 1.37.1-beta.0 → 1.38.0
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/CHANGELOG.md +20 -0
- package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +0 -81
- package/dist/commonjs/hooks/index.js +0 -11
- package/dist/commonjs/hooks/index.js.map +1 -1
- package/dist/commonjs/modules/call-manager/CallManager.js +13 -0
- package/dist/commonjs/modules/call-manager/CallManager.js.map +1 -1
- package/dist/commonjs/providers/StreamCall/AudioInterruptionTracer.js +37 -0
- package/dist/commonjs/providers/StreamCall/AudioInterruptionTracer.js.map +1 -0
- package/dist/commonjs/providers/StreamCall/index.js +2 -1
- package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
- package/dist/commonjs/utils/internal/callingx/callingx.js +2 -2
- package/dist/commonjs/utils/internal/callingx/callingx.js.map +1 -1
- package/dist/commonjs/utils/push/internal/ios.js +5 -0
- package/dist/commonjs/utils/push/internal/ios.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/commonjs/version.js.map +1 -1
- package/dist/module/hooks/index.js +0 -1
- package/dist/module/hooks/index.js.map +1 -1
- package/dist/module/modules/call-manager/CallManager.js +13 -0
- package/dist/module/modules/call-manager/CallManager.js.map +1 -1
- package/dist/module/providers/StreamCall/AudioInterruptionTracer.js +30 -0
- package/dist/module/providers/StreamCall/AudioInterruptionTracer.js.map +1 -0
- package/dist/module/providers/StreamCall/index.js +2 -1
- package/dist/module/providers/StreamCall/index.js.map +1 -1
- package/dist/module/utils/internal/callingx/callingx.js +2 -2
- package/dist/module/utils/internal/callingx/callingx.js.map +1 -1
- package/dist/module/utils/push/internal/ios.js +5 -0
- package/dist/module/utils/push/internal/ios.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/module/version.js.map +1 -1
- package/dist/typescript/hooks/index.d.ts +0 -1
- package/dist/typescript/hooks/index.d.ts.map +1 -1
- package/dist/typescript/modules/call-manager/CallManager.d.ts +8 -1
- package/dist/typescript/modules/call-manager/CallManager.d.ts.map +1 -1
- package/dist/typescript/modules/call-manager/types.d.ts +6 -0
- package/dist/typescript/modules/call-manager/types.d.ts.map +1 -1
- package/dist/typescript/providers/StreamCall/AudioInterruptionTracer.d.ts +5 -0
- package/dist/typescript/providers/StreamCall/AudioInterruptionTracer.d.ts.map +1 -0
- package/dist/typescript/providers/StreamCall/index.d.ts.map +1 -1
- package/dist/typescript/utils/push/internal/ios.d.ts.map +1 -1
- package/dist/typescript/version.d.ts +1 -1
- package/dist/typescript/version.d.ts.map +1 -1
- package/ios/PictureInPicture/StreamBufferTransformer.swift +13 -4
- package/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift +76 -70
- package/ios/PictureInPicture/StreamRTCYUVBuffer.swift +20 -16
- package/ios/StreamInCallManager.swift +237 -81
- package/ios/StreamVideoReactNative-Bridging-Header.h +0 -2
- package/ios/StreamVideoReactNative.m +0 -81
- package/package.json +11 -11
- package/src/hooks/index.ts +0 -1
- package/src/modules/call-manager/CallManager.ts +25 -1
- package/src/modules/call-manager/types.ts +7 -0
- package/src/providers/StreamCall/AudioInterruptionTracer.tsx +51 -0
- package/src/providers/StreamCall/index.tsx +2 -0
- package/src/utils/internal/callingx/callingx.ts +2 -2
- package/src/utils/push/internal/ios.ts +5 -0
- package/src/version.ts +1 -1
- package/android/src/main/java/com/streamvideo/reactnative/recorder/AudioPipeline.kt +0 -436
- package/android/src/main/java/com/streamvideo/reactnative/recorder/EncoderConstants.kt +0 -17
- package/android/src/main/java/com/streamvideo/reactnative/recorder/PipelineHost.kt +0 -36
- package/android/src/main/java/com/streamvideo/reactnative/recorder/RecorderPlaybackSamplesSink.kt +0 -60
- package/android/src/main/java/com/streamvideo/reactnative/recorder/RecorderVideoSink.kt +0 -31
- package/android/src/main/java/com/streamvideo/reactnative/recorder/TracksRecorderManager.kt +0 -329
- package/android/src/main/java/com/streamvideo/reactnative/recorder/VideoPipeline.kt +0 -472
- package/dist/commonjs/hooks/useLoopbackRecording.js +0 -243
- package/dist/commonjs/hooks/useLoopbackRecording.js.map +0 -1
- package/dist/module/hooks/useLoopbackRecording.js +0 -238
- package/dist/module/hooks/useLoopbackRecording.js.map +0 -1
- package/dist/typescript/hooks/useLoopbackRecording.d.ts +0 -85
- package/dist/typescript/hooks/useLoopbackRecording.d.ts.map +0 -1
- package/ios/TracksRecorder/AudioPipeline.swift +0 -270
- package/ios/TracksRecorder/PipelineHost.swift +0 -56
- package/ios/TracksRecorder/RecorderAudioRenderTap.swift +0 -154
- package/ios/TracksRecorder/RecorderVideoSink.swift +0 -137
- package/ios/TracksRecorder/TracksRecorderManager.swift +0 -327
- package/ios/TracksRecorder/VideoPipeline.swift +0 -297
- package/src/hooks/useLoopbackRecording.ts +0 -438
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.useLoopbackRecording = useLoopbackRecording;
|
|
7
|
-
var _react = require("react");
|
|
8
|
-
var _reactNative = require("react-native");
|
|
9
|
-
var _rxjs = require("rxjs");
|
|
10
|
-
var _videoClient = require("@stream-io/video-client");
|
|
11
|
-
var _videoReactBindings = require("@stream-io/video-react-bindings");
|
|
12
|
-
/** @internal */
|
|
13
|
-
const {
|
|
14
|
-
StreamVideoReactNative
|
|
15
|
-
} = _reactNative.NativeModules;
|
|
16
|
-
|
|
17
|
-
// Upper bound on how long `startRecording` will wait for the SFU to
|
|
18
|
-
// echo loopback tracks back via the Subscriber. Tuned generously since
|
|
19
|
-
// this includes connection setup; consumers that want shorter feedback
|
|
20
|
-
// should call `stopRecording` to cancel the wait early.
|
|
21
|
-
const STREAMS_WAIT_TIMEOUT_MS = 10 * 1000;
|
|
22
|
-
const DEFAULT_RECORDING_DURATION = 10 * 1000;
|
|
23
|
-
const MIN_RECORDING_DURATION = 5 * 1000;
|
|
24
|
-
const MAX_RECORDING_DURATION = 2 * 60 * 1000;
|
|
25
|
-
/**
|
|
26
|
-
* Records the SFU loopback streams (audio + video) on the local participant
|
|
27
|
-
* to a local MP4 file. Designed for the `selfSubEnabled` pre-call test mode:
|
|
28
|
-
* the SFU echoes the caller's published tracks back through the Subscriber
|
|
29
|
-
* peer connection. The hook identifies the loopback streams on the local
|
|
30
|
-
* participant by reference inequality against
|
|
31
|
-
* `call.camera.state.mediaStream` / `call.microphone.state.mediaStream` —
|
|
32
|
-
* the canonical references to the local capture — and captures them.
|
|
33
|
-
*/
|
|
34
|
-
function useLoopbackRecording() {
|
|
35
|
-
const call = (0, _videoReactBindings.useCall)();
|
|
36
|
-
const {
|
|
37
|
-
useCallCallingState,
|
|
38
|
-
useParticipantCount
|
|
39
|
-
} = (0, _videoReactBindings.useCallStateHooks)();
|
|
40
|
-
const callingState = useCallCallingState();
|
|
41
|
-
const participantCount = useParticipantCount();
|
|
42
|
-
const [recordingState, setRecordingState] = (0, _react.useState)('idle');
|
|
43
|
-
const recordingStateRef = (0, _react.useRef)('idle');
|
|
44
|
-
const isMountedRef = (0, _react.useRef)(true);
|
|
45
|
-
// Used to abort the awaiting-streams wait on stop / leave / unmount.
|
|
46
|
-
const awaitAbortRef = (0, _react.useRef)(null);
|
|
47
|
-
const [loopbackStreams, setLoopbackStreams] = (0, _react.useState)(() => {
|
|
48
|
-
if (!call) return {};
|
|
49
|
-
return getLoopbackStreamsFor(call.state.localParticipant, call.camera.state.mediaStream, call.microphone.state.mediaStream);
|
|
50
|
-
});
|
|
51
|
-
const updateState = (0, _react.useCallback)(next => {
|
|
52
|
-
recordingStateRef.current = next;
|
|
53
|
-
if (isMountedRef.current) {
|
|
54
|
-
setRecordingState(next);
|
|
55
|
-
}
|
|
56
|
-
}, []);
|
|
57
|
-
const stopRecording = (0, _react.useCallback)(async () => {
|
|
58
|
-
const current = recordingStateRef.current;
|
|
59
|
-
if (current === 'idle') {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (current === 'awaiting-streams') {
|
|
63
|
-
_videoClient.videoLoggerSystem.getLogger('useLoopbackRecording').debug('aborting awaiting-streams wait');
|
|
64
|
-
awaitAbortRef.current?.abort();
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
await StreamVideoReactNative?.stopTrackRecording();
|
|
68
|
-
}, []);
|
|
69
|
-
const startRecording = (0, _react.useCallback)(async ({
|
|
70
|
-
includeVideo = true,
|
|
71
|
-
maxDurationMs = DEFAULT_RECORDING_DURATION
|
|
72
|
-
} = {}) => {
|
|
73
|
-
if (!call) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
if (recordingStateRef.current !== 'idle') {
|
|
77
|
-
console.warn('useLoopbackRecording: a recording is already running');
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
if (call.state.participantCount > 1) {
|
|
81
|
-
console.warn('useLoopbackRecording: cannot start recording with other participants present');
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
awaitAbortRef.current = new AbortController();
|
|
85
|
-
updateState('awaiting-streams');
|
|
86
|
-
let audioTrack;
|
|
87
|
-
try {
|
|
88
|
-
const streams = await waitForLoopbackStreams(call, {
|
|
89
|
-
includeVideo,
|
|
90
|
-
signal: awaitAbortRef.current.signal,
|
|
91
|
-
timeoutMs: STREAMS_WAIT_TIMEOUT_MS
|
|
92
|
-
});
|
|
93
|
-
if (streams === null) {
|
|
94
|
-
_videoClient.videoLoggerSystem.getLogger('useLoopbackRecording').warn('timed out waiting for loopback streams');
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
audioTrack = streams.audioTrack;
|
|
98
|
-
const videoTrackId = streams.videoTrack?.id;
|
|
99
|
-
|
|
100
|
-
// The loopback audio track lands disabled (the SDK default-mutes
|
|
101
|
-
// it to prevent echo). Enable it so the native recording
|
|
102
|
-
// pipeline receives PCM; `finally` returns it to muted.
|
|
103
|
-
if (audioTrack) {
|
|
104
|
-
audioTrack.enabled = true;
|
|
105
|
-
}
|
|
106
|
-
updateState('recording');
|
|
107
|
-
const clampedDuration = Math.min(MAX_RECORDING_DURATION, Math.max(MIN_RECORDING_DURATION, maxDurationMs));
|
|
108
|
-
|
|
109
|
-
// Pre-size the native encoder to the publisher's max video
|
|
110
|
-
// publish-option dimension. Without this, the encoder locks to
|
|
111
|
-
// whatever the SFU happens to echo *first* and stays there for the
|
|
112
|
-
// rest of the recording even after the network improves and
|
|
113
|
-
// higher layers arrive.
|
|
114
|
-
const publishMaxDim = call.getMaxVideoPublishDimension();
|
|
115
|
-
const uri = await StreamVideoReactNative.startTrackRecording({
|
|
116
|
-
videoTrackId,
|
|
117
|
-
maxDurationMs: Math.round(clampedDuration),
|
|
118
|
-
targetWidth: publishMaxDim?.width,
|
|
119
|
-
targetHeight: publishMaxDim?.height
|
|
120
|
-
});
|
|
121
|
-
return uri;
|
|
122
|
-
} finally {
|
|
123
|
-
if (audioTrack) {
|
|
124
|
-
audioTrack.enabled = false;
|
|
125
|
-
}
|
|
126
|
-
awaitAbortRef.current = null;
|
|
127
|
-
updateState('idle');
|
|
128
|
-
}
|
|
129
|
-
}, [call, updateState]);
|
|
130
|
-
const clearRecordings = (0, _react.useCallback)(async () => {
|
|
131
|
-
await StreamVideoReactNative.clearStreamRecordings();
|
|
132
|
-
}, []);
|
|
133
|
-
const getRecordings = (0, _react.useCallback)(async () => {
|
|
134
|
-
const list = await StreamVideoReactNative.getStreamRecordings();
|
|
135
|
-
return list ?? [];
|
|
136
|
-
}, []);
|
|
137
|
-
|
|
138
|
-
// Auto-stop on call leave / end. Aborts an awaiting-streams wait or
|
|
139
|
-
// signals native finalisation depending on which phase we're in.
|
|
140
|
-
// Without this, leaving the call mid-recording would leave native
|
|
141
|
-
// encoders mid-write while the SFU subscriber tracks end under their
|
|
142
|
-
// feet — undefined final file state.
|
|
143
|
-
(0, _react.useEffect)(() => {
|
|
144
|
-
if (callingState === _videoClient.CallingState.LEFT || callingState === _videoClient.CallingState.IDLE) {
|
|
145
|
-
_videoClient.videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on call leave / end');
|
|
146
|
-
stopRecording().catch(() => {});
|
|
147
|
-
}
|
|
148
|
-
}, [callingState, stopRecording]);
|
|
149
|
-
|
|
150
|
-
// Auto-stop if another participant joins. Loopback recording is a
|
|
151
|
-
// single-user pre-call test.
|
|
152
|
-
(0, _react.useEffect)(() => {
|
|
153
|
-
if (recordingState !== 'idle' && participantCount > 1) {
|
|
154
|
-
stopRecording().catch(() => {});
|
|
155
|
-
_videoClient.videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on participant count change');
|
|
156
|
-
}
|
|
157
|
-
}, [participantCount, recordingState, stopRecording]);
|
|
158
|
-
(0, _react.useEffect)(() => {
|
|
159
|
-
isMountedRef.current = true;
|
|
160
|
-
return () => {
|
|
161
|
-
isMountedRef.current = false;
|
|
162
|
-
_videoClient.videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on unmount');
|
|
163
|
-
stopRecording().catch(() => {});
|
|
164
|
-
};
|
|
165
|
-
}, [stopRecording]);
|
|
166
|
-
|
|
167
|
-
// Subscribe to the local participant, camera and microphone streams and update the loopback streams state.
|
|
168
|
-
(0, _react.useEffect)(() => {
|
|
169
|
-
if (!call) return;
|
|
170
|
-
const subscription = (0, _rxjs.combineLatest)([call.state.localParticipant$, call.camera.state.mediaStream$, call.microphone.state.mediaStream$]).pipe((0, _rxjs.map)(([participant, cameraStream, microphoneStream]) => getLoopbackStreamsFor(participant, cameraStream, microphoneStream)), (0, _rxjs.distinctUntilChanged)((a, b) => a.loopbackVideoStream === b.loopbackVideoStream && a.loopbackAudioStream === b.loopbackAudioStream)).subscribe(setLoopbackStreams);
|
|
171
|
-
return () => subscription.unsubscribe();
|
|
172
|
-
}, [call]);
|
|
173
|
-
return {
|
|
174
|
-
startRecording,
|
|
175
|
-
stopRecording,
|
|
176
|
-
clearRecordings,
|
|
177
|
-
getRecordings,
|
|
178
|
-
recordingState,
|
|
179
|
-
loopbackVideoStream: loopbackStreams.loopbackVideoStream,
|
|
180
|
-
loopbackAudioStream: loopbackStreams.loopbackAudioStream
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
function getLoopbackStreamsFor(participant, cameraStream, microphoneStream) {
|
|
184
|
-
return {
|
|
185
|
-
loopbackVideoStream: participant?.videoStream && participant.videoStream !== cameraStream ? participant.videoStream : undefined,
|
|
186
|
-
loopbackAudioStream: participant?.audioStream && participant.audioStream !== microphoneStream ? participant.audioStream : undefined
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Subscribe to `localParticipant$` and resolve once the requested loopback
|
|
192
|
-
* streams are present on the participant. Aborts cleanly on `signal`
|
|
193
|
-
* (resolves `null`) and rejects on timeout.
|
|
194
|
-
*/
|
|
195
|
-
function waitForLoopbackStreams(call, opts) {
|
|
196
|
-
return new Promise((resolve, reject) => {
|
|
197
|
-
const initial = getLoopbackStreams(call.state.localParticipant, call.camera.state.mediaStream, call.microphone.state.mediaStream, opts.includeVideo);
|
|
198
|
-
if (initial) {
|
|
199
|
-
resolve(initial);
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const cleanup = () => {
|
|
203
|
-
subscription.unsubscribe();
|
|
204
|
-
if (timeoutId !== undefined) {
|
|
205
|
-
clearTimeout(timeoutId);
|
|
206
|
-
}
|
|
207
|
-
opts.signal.removeEventListener('abort', onAbort);
|
|
208
|
-
};
|
|
209
|
-
const onAbort = () => {
|
|
210
|
-
cleanup();
|
|
211
|
-
resolve(null);
|
|
212
|
-
};
|
|
213
|
-
opts.signal.addEventListener('abort', onAbort);
|
|
214
|
-
const timeoutId = setTimeout(() => {
|
|
215
|
-
cleanup();
|
|
216
|
-
reject(new Error('useLoopbackRecording: timed out waiting for loopback streams. ' + 'Ensure the call was joined with `selfSubEnabled: true` and ' + 'that the SFU is configured to echo self-sub tracks.'));
|
|
217
|
-
}, opts.timeoutMs);
|
|
218
|
-
const subscription = (0, _rxjs.combineLatest)([call.state.localParticipant$, call.camera.state.mediaStream$, call.microphone.state.mediaStream$]).subscribe(([participant, cameraStream, microphoneStream]) => {
|
|
219
|
-
const ready = getLoopbackStreams(participant, cameraStream, microphoneStream, opts.includeVideo);
|
|
220
|
-
if (ready) {
|
|
221
|
-
cleanup();
|
|
222
|
-
resolve(ready);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
function getLoopbackStreams(participant, cameraStream, microphoneStream, includeVideo) {
|
|
228
|
-
if (!participant) return undefined;
|
|
229
|
-
const {
|
|
230
|
-
loopbackAudioStream,
|
|
231
|
-
loopbackVideoStream
|
|
232
|
-
} = getLoopbackStreamsFor(participant, cameraStream, microphoneStream);
|
|
233
|
-
const audioTrack = loopbackAudioStream?.getAudioTracks()[0];
|
|
234
|
-
const videoTrack = includeVideo ? loopbackVideoStream?.getVideoTracks()[0] : undefined;
|
|
235
|
-
if (!audioTrack || includeVideo && !videoTrack) {
|
|
236
|
-
return undefined;
|
|
237
|
-
}
|
|
238
|
-
return {
|
|
239
|
-
audioTrack,
|
|
240
|
-
videoTrack
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
//# sourceMappingURL=useLoopbackRecording.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_reactNative","_rxjs","_videoClient","_videoReactBindings","StreamVideoReactNative","NativeModules","STREAMS_WAIT_TIMEOUT_MS","DEFAULT_RECORDING_DURATION","MIN_RECORDING_DURATION","MAX_RECORDING_DURATION","useLoopbackRecording","call","useCall","useCallCallingState","useParticipantCount","useCallStateHooks","callingState","participantCount","recordingState","setRecordingState","useState","recordingStateRef","useRef","isMountedRef","awaitAbortRef","loopbackStreams","setLoopbackStreams","getLoopbackStreamsFor","state","localParticipant","camera","mediaStream","microphone","updateState","useCallback","next","current","stopRecording","videoLoggerSystem","getLogger","debug","abort","stopTrackRecording","startRecording","includeVideo","maxDurationMs","console","warn","AbortController","audioTrack","streams","waitForLoopbackStreams","signal","timeoutMs","videoTrackId","videoTrack","id","enabled","clampedDuration","Math","min","max","publishMaxDim","getMaxVideoPublishDimension","uri","startTrackRecording","round","targetWidth","width","targetHeight","height","clearRecordings","clearStreamRecordings","getRecordings","list","getStreamRecordings","useEffect","CallingState","LEFT","IDLE","catch","subscription","combineLatest","localParticipant$","mediaStream$","pipe","map","participant","cameraStream","microphoneStream","distinctUntilChanged","a","b","loopbackVideoStream","loopbackAudioStream","subscribe","unsubscribe","videoStream","undefined","audioStream","opts","Promise","resolve","reject","initial","getLoopbackStreams","cleanup","timeoutId","clearTimeout","removeEventListener","onAbort","addEventListener","setTimeout","Error","ready","getAudioTracks","getVideoTracks"],"sourceRoot":"../../../src","sources":["hooks/useLoopbackRecording.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,YAAA,GAAAH,OAAA;AAMA,IAAAI,mBAAA,GAAAJ,OAAA;AAEA;AACA,MAAM;EAAEK;AAAuB,CAAC,GAAGC,0BAAa;;AAEhD;AACA;AACA;AACA;AACA,MAAMC,uBAAuB,GAAG,EAAE,GAAG,IAAI;AACzC,MAAMC,0BAA0B,GAAG,EAAE,GAAG,IAAI;AAC5C,MAAMC,sBAAsB,GAAG,CAAC,GAAG,IAAI;AACvC,MAAMC,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;AAuF5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,oBAAoBA,CAAA,EAA+B;EACjE,MAAMC,IAAI,GAAG,IAAAC,2BAAO,EAAC,CAAC;EACtB,MAAM;IAAEC,mBAAmB;IAAEC;EAAoB,CAAC,GAAG,IAAAC,qCAAiB,EAAC,CAAC;EACxE,MAAMC,YAAY,GAAGH,mBAAmB,CAAC,CAAC;EAC1C,MAAMI,gBAAgB,GAAGH,mBAAmB,CAAC,CAAC;EAE9C,MAAM,CAACI,cAAc,EAAEC,iBAAiB,CAAC,GACvC,IAAAC,eAAQ,EAAyB,MAAM,CAAC;EAC1C,MAAMC,iBAAiB,GAAG,IAAAC,aAAM,EAAyB,MAAM,CAAC;EAChE,MAAMC,YAAY,GAAG,IAAAD,aAAM,EAAC,IAAI,CAAC;EACjC;EACA,MAAME,aAAa,GAAG,IAAAF,aAAM,EAAyB,IAAI,CAAC;EAE1D,MAAM,CAACG,eAAe,EAAEC,kBAAkB,CAAC,GAAG,IAAAN,eAAQ,EACpD,MAAM;IACJ,IAAI,CAACT,IAAI,EAAE,OAAO,CAAC,CAAC;IACpB,OAAOgB,qBAAqB,CAC1BhB,IAAI,CAACiB,KAAK,CAACC,gBAAgB,EAC3BlB,IAAI,CAACmB,MAAM,CAACF,KAAK,CAACG,WAAW,EAC7BpB,IAAI,CAACqB,UAAU,CAACJ,KAAK,CAACG,WACxB,CAAC;EACH,CACF,CAAC;EAED,MAAME,WAAW,GAAG,IAAAC,kBAAW,EAAEC,IAA4B,IAAK;IAChEd,iBAAiB,CAACe,OAAO,GAAGD,IAAI;IAChC,IAAIZ,YAAY,CAACa,OAAO,EAAE;MACxBjB,iBAAiB,CAACgB,IAAI,CAAC;IACzB;EACF,CAAC,EAAE,EAAE,CAAC;EAEN,MAAME,aAAa,GAAG,IAAAH,kBAAW,EAAC,YAA2B;IAC3D,MAAME,OAAO,GAAGf,iBAAiB,CAACe,OAAO;IACzC,IAAIA,OAAO,KAAK,MAAM,EAAE;MACtB;IACF;IAEA,IAAIA,OAAO,KAAK,kBAAkB,EAAE;MAClCE,8BAAiB,CACdC,SAAS,CAAC,sBAAsB,CAAC,CACjCC,KAAK,CAAC,gCAAgC,CAAC;MAC1ChB,aAAa,CAACY,OAAO,EAAEK,KAAK,CAAC,CAAC;MAC9B;IACF;IAEA,MAAMrC,sBAAsB,EAAEsC,kBAAkB,CAAC,CAAC;EACpD,CAAC,EAAE,EAAE,CAAC;EAEN,MAAMC,cAAc,GAAG,IAAAT,kBAAW,EAChC,OAAO;IACLU,YAAY,GAAG,IAAI;IACnBC,aAAa,GAAGtC;EACa,CAAC,GAAG,CAAC,CAAC,KAA6B;IAChE,IAAI,CAACI,IAAI,EAAE;MACT,OAAO,IAAI;IACb;IAEA,IAAIU,iBAAiB,CAACe,OAAO,KAAK,MAAM,EAAE;MACxCU,OAAO,CAACC,IAAI,CAAC,sDAAsD,CAAC;MACpE,OAAO,IAAI;IACb;IAEA,IAAIpC,IAAI,CAACiB,KAAK,CAACX,gBAAgB,GAAG,CAAC,EAAE;MACnC6B,OAAO,CAACC,IAAI,CACV,8EACF,CAAC;MACD,OAAO,IAAI;IACb;IAEAvB,aAAa,CAACY,OAAO,GAAG,IAAIY,eAAe,CAAC,CAAC;IAC7Cf,WAAW,CAAC,kBAAkB,CAAC;IAE/B,IAAIgB,UAAwC;IAC5C,IAAI;MACF,MAAMC,OAAO,GAAG,MAAMC,sBAAsB,CAACxC,IAAI,EAAE;QACjDiC,YAAY;QACZQ,MAAM,EAAE5B,aAAa,CAACY,OAAO,CAACgB,MAAM;QACpCC,SAAS,EAAE/C;MACb,CAAC,CAAC;MAEF,IAAI4C,OAAO,KAAK,IAAI,EAAE;QACpBZ,8BAAiB,CACdC,SAAS,CAAC,sBAAsB,CAAC,CACjCQ,IAAI,CAAC,wCAAwC,CAAC;QACjD,OAAO,IAAI;MACb;MAEAE,UAAU,GAAGC,OAAO,CAACD,UAAU;MAC/B,MAAMK,YAAY,GAAGJ,OAAO,CAACK,UAAU,EAAEC,EAAE;;MAE3C;MACA;MACA;MACA,IAAIP,UAAU,EAAE;QACdA,UAAU,CAACQ,OAAO,GAAG,IAAI;MAC3B;MACAxB,WAAW,CAAC,WAAW,CAAC;MAExB,MAAMyB,eAAe,GAAGC,IAAI,CAACC,GAAG,CAC9BnD,sBAAsB,EACtBkD,IAAI,CAACE,GAAG,CAACrD,sBAAsB,EAAEqC,aAAa,CAChD,CAAC;;MAED;MACA;MACA;MACA;MACA;MACA,MAAMiB,aAAa,GAAGnD,IAAI,CAACoD,2BAA2B,CAAC,CAAC;MAExD,MAAMC,GAAkB,GACtB,MAAM5D,sBAAsB,CAAC6D,mBAAmB,CAAC;QAC/CX,YAAY;QACZT,aAAa,EAAEc,IAAI,CAACO,KAAK,CAACR,eAAe,CAAC;QAC1CS,WAAW,EAAEL,aAAa,EAAEM,KAAK;QACjCC,YAAY,EAAEP,aAAa,EAAEQ;MAC/B,CAAC,CAAC;MACJ,OAAON,GAAG;IACZ,CAAC,SAAS;MACR,IAAIf,UAAU,EAAE;QACdA,UAAU,CAACQ,OAAO,GAAG,KAAK;MAC5B;MACAjC,aAAa,CAACY,OAAO,GAAG,IAAI;MAC5BH,WAAW,CAAC,MAAM,CAAC;IACrB;EACF,CAAC,EACD,CAACtB,IAAI,EAAEsB,WAAW,CACpB,CAAC;EAED,MAAMsC,eAAe,GAAG,IAAArC,kBAAW,EAAC,YAA2B;IAC7D,MAAM9B,sBAAsB,CAACoE,qBAAqB,CAAC,CAAC;EACtD,CAAC,EAAE,EAAE,CAAC;EAEN,MAAMC,aAAa,GAAG,IAAAvC,kBAAW,EAAC,YAA+B;IAC/D,MAAMwC,IAAiC,GACrC,MAAMtE,sBAAsB,CAACuE,mBAAmB,CAAC,CAAC;IACpD,OAAOD,IAAI,IAAI,EAAE;EACnB,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA;EACA;EACA;EACA;EACA,IAAAE,gBAAS,EAAC,MAAM;IACd,IACE5D,YAAY,KAAK6D,yBAAY,CAACC,IAAI,IAClC9D,YAAY,KAAK6D,yBAAY,CAACE,IAAI,EAClC;MACAzC,8BAAiB,CACdC,SAAS,CAAC,sBAAsB,CAAC,CACjCC,KAAK,CAAC,6CAA6C,CAAC;MACvDH,aAAa,CAAC,CAAC,CAAC2C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACjC;EACF,CAAC,EAAE,CAAChE,YAAY,EAAEqB,aAAa,CAAC,CAAC;;EAEjC;EACA;EACA,IAAAuC,gBAAS,EAAC,MAAM;IACd,IAAI1D,cAAc,KAAK,MAAM,IAAID,gBAAgB,GAAG,CAAC,EAAE;MACrDoB,aAAa,CAAC,CAAC,CAAC2C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;MAC/B1C,8BAAiB,CACdC,SAAS,CAAC,sBAAsB,CAAC,CACjCC,KAAK,CAAC,qDAAqD,CAAC;IACjE;EACF,CAAC,EAAE,CAACvB,gBAAgB,EAAEC,cAAc,EAAEmB,aAAa,CAAC,CAAC;EAErD,IAAAuC,gBAAS,EAAC,MAAM;IACdrD,YAAY,CAACa,OAAO,GAAG,IAAI;IAC3B,OAAO,MAAM;MACXb,YAAY,CAACa,OAAO,GAAG,KAAK;MAC5BE,8BAAiB,CACdC,SAAS,CAAC,sBAAsB,CAAC,CACjCC,KAAK,CAAC,oCAAoC,CAAC;MAC9CH,aAAa,CAAC,CAAC,CAAC2C,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACjC,CAAC;EACH,CAAC,EAAE,CAAC3C,aAAa,CAAC,CAAC;;EAEnB;EACA,IAAAuC,gBAAS,EAAC,MAAM;IACd,IAAI,CAACjE,IAAI,EAAE;IAEX,MAAMsE,YAAY,GAAG,IAAAC,mBAAa,EAAC,CACjCvE,IAAI,CAACiB,KAAK,CAACuD,iBAAiB,EAC5BxE,IAAI,CAACmB,MAAM,CAACF,KAAK,CAACwD,YAAY,EAC9BzE,IAAI,CAACqB,UAAU,CAACJ,KAAK,CAACwD,YAAY,CACnC,CAAC,CACCC,IAAI,CACH,IAAAC,SAAG,EAAC,CAAC,CAACC,WAAW,EAAEC,YAAY,EAAEC,gBAAgB,CAAC,KAChD9D,qBAAqB,CAAC4D,WAAW,EAAEC,YAAY,EAAEC,gBAAgB,CACnE,CAAC,EACD,IAAAC,0BAAoB,EAClB,CAACC,CAAC,EAAEC,CAAC,KACHD,CAAC,CAACE,mBAAmB,KAAKD,CAAC,CAACC,mBAAmB,IAC/CF,CAAC,CAACG,mBAAmB,KAAKF,CAAC,CAACE,mBAChC,CACF,CAAC,CACAC,SAAS,CAACrE,kBAAkB,CAAC;IAEhC,OAAO,MAAMuD,YAAY,CAACe,WAAW,CAAC,CAAC;EACzC,CAAC,EAAE,CAACrF,IAAI,CAAC,CAAC;EAEV,OAAO;IACLgC,cAAc;IACdN,aAAa;IACbkC,eAAe;IACfE,aAAa;IACbvD,cAAc;IACd2E,mBAAmB,EAAEpE,eAAe,CAACoE,mBAAmB;IACxDC,mBAAmB,EAAErE,eAAe,CAACqE;EACvC,CAAC;AACH;AAEA,SAASnE,qBAAqBA,CAC5B4D,WAA+C,EAC/CC,YAAqC,EACrCC,gBAAyC,EACxB;EACjB,OAAO;IACLI,mBAAmB,EACjBN,WAAW,EAAEU,WAAW,IAAIV,WAAW,CAACU,WAAW,KAAKT,YAAY,GAChED,WAAW,CAACU,WAAW,GACvBC,SAAS;IACfJ,mBAAmB,EACjBP,WAAW,EAAEY,WAAW,IAAIZ,WAAW,CAACY,WAAW,KAAKV,gBAAgB,GACpEF,WAAW,CAACY,WAAW,GACvBD;EACR,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS/C,sBAAsBA,CAC7BxC,IAAU,EACVyF,IAAuE,EACtC;EACjC,OAAO,IAAIC,OAAO,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;IACtC,MAAMC,OAAO,GAAGC,kBAAkB,CAChC9F,IAAI,CAACiB,KAAK,CAACC,gBAAgB,EAC3BlB,IAAI,CAACmB,MAAM,CAACF,KAAK,CAACG,WAAW,EAC7BpB,IAAI,CAACqB,UAAU,CAACJ,KAAK,CAACG,WAAW,EACjCqE,IAAI,CAACxD,YACP,CAAC;IACD,IAAI4D,OAAO,EAAE;MACXF,OAAO,CAACE,OAAO,CAAC;MAChB;IACF;IAEA,MAAME,OAAO,GAAGA,CAAA,KAAM;MACpBzB,YAAY,CAACe,WAAW,CAAC,CAAC;MAC1B,IAAIW,SAAS,KAAKT,SAAS,EAAE;QAC3BU,YAAY,CAACD,SAAS,CAAC;MACzB;MACAP,IAAI,CAAChD,MAAM,CAACyD,mBAAmB,CAAC,OAAO,EAAEC,OAAO,CAAC;IACnD,CAAC;IAED,MAAMA,OAAO,GAAGA,CAAA,KAAM;MACpBJ,OAAO,CAAC,CAAC;MACTJ,OAAO,CAAC,IAAI,CAAC;IACf,CAAC;IAEDF,IAAI,CAAChD,MAAM,CAAC2D,gBAAgB,CAAC,OAAO,EAAED,OAAO,CAAC;IAE9C,MAAMH,SAAS,GAAGK,UAAU,CAAC,MAAM;MACjCN,OAAO,CAAC,CAAC;MACTH,MAAM,CACJ,IAAIU,KAAK,CACP,gEAAgE,GAC9D,6DAA6D,GAC7D,qDACJ,CACF,CAAC;IACH,CAAC,EAAEb,IAAI,CAAC/C,SAAS,CAAC;IAElB,MAAM4B,YAAY,GAAG,IAAAC,mBAAa,EAAC,CACjCvE,IAAI,CAACiB,KAAK,CAACuD,iBAAiB,EAC5BxE,IAAI,CAACmB,MAAM,CAACF,KAAK,CAACwD,YAAY,EAC9BzE,IAAI,CAACqB,UAAU,CAACJ,KAAK,CAACwD,YAAY,CACnC,CAAC,CAACW,SAAS,CAAC,CAAC,CAACR,WAAW,EAAEC,YAAY,EAAEC,gBAAgB,CAAC,KAAK;MAC9D,MAAMyB,KAAK,GAAGT,kBAAkB,CAC9BlB,WAAW,EACXC,YAAY,EACZC,gBAAgB,EAChBW,IAAI,CAACxD,YACP,CAAC;MACD,IAAIsE,KAAK,EAAE;QACTR,OAAO,CAAC,CAAC;QACTJ,OAAO,CAACY,KAAK,CAAC;MAChB;IACF,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ;AAEA,SAAST,kBAAkBA,CACzBlB,WAA+C,EAC/CC,YAAqC,EACrCC,gBAAyC,EACzC7C,YAAqB,EACQ;EAC7B,IAAI,CAAC2C,WAAW,EAAE,OAAOW,SAAS;EAElC,MAAM;IAAEJ,mBAAmB;IAAED;EAAoB,CAAC,GAAGlE,qBAAqB,CACxE4D,WAAW,EACXC,YAAY,EACZC,gBACF,CAAC;EAED,MAAMxC,UAAU,GAAG6C,mBAAmB,EAAEqB,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;EAC3D,MAAM5D,UAAU,GAAGX,YAAY,GAC3BiD,mBAAmB,EAAEuB,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GACxClB,SAAS;EAEb,IAAI,CAACjD,UAAU,IAAKL,YAAY,IAAI,CAACW,UAAW,EAAE;IAChD,OAAO2C,SAAS;EAClB;EAEA,OAAO;IAAEjD,UAAU;IAAEM;EAAW,CAAC;AACnC","ignoreList":[]}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { NativeModules } from 'react-native';
|
|
3
|
-
import { combineLatest, distinctUntilChanged, map } from 'rxjs';
|
|
4
|
-
import { CallingState, videoLoggerSystem } from '@stream-io/video-client';
|
|
5
|
-
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
6
|
-
|
|
7
|
-
/** @internal */
|
|
8
|
-
const {
|
|
9
|
-
StreamVideoReactNative
|
|
10
|
-
} = NativeModules;
|
|
11
|
-
|
|
12
|
-
// Upper bound on how long `startRecording` will wait for the SFU to
|
|
13
|
-
// echo loopback tracks back via the Subscriber. Tuned generously since
|
|
14
|
-
// this includes connection setup; consumers that want shorter feedback
|
|
15
|
-
// should call `stopRecording` to cancel the wait early.
|
|
16
|
-
const STREAMS_WAIT_TIMEOUT_MS = 10 * 1000;
|
|
17
|
-
const DEFAULT_RECORDING_DURATION = 10 * 1000;
|
|
18
|
-
const MIN_RECORDING_DURATION = 5 * 1000;
|
|
19
|
-
const MAX_RECORDING_DURATION = 2 * 60 * 1000;
|
|
20
|
-
/**
|
|
21
|
-
* Records the SFU loopback streams (audio + video) on the local participant
|
|
22
|
-
* to a local MP4 file. Designed for the `selfSubEnabled` pre-call test mode:
|
|
23
|
-
* the SFU echoes the caller's published tracks back through the Subscriber
|
|
24
|
-
* peer connection. The hook identifies the loopback streams on the local
|
|
25
|
-
* participant by reference inequality against
|
|
26
|
-
* `call.camera.state.mediaStream` / `call.microphone.state.mediaStream` —
|
|
27
|
-
* the canonical references to the local capture — and captures them.
|
|
28
|
-
*/
|
|
29
|
-
export function useLoopbackRecording() {
|
|
30
|
-
const call = useCall();
|
|
31
|
-
const {
|
|
32
|
-
useCallCallingState,
|
|
33
|
-
useParticipantCount
|
|
34
|
-
} = useCallStateHooks();
|
|
35
|
-
const callingState = useCallCallingState();
|
|
36
|
-
const participantCount = useParticipantCount();
|
|
37
|
-
const [recordingState, setRecordingState] = useState('idle');
|
|
38
|
-
const recordingStateRef = useRef('idle');
|
|
39
|
-
const isMountedRef = useRef(true);
|
|
40
|
-
// Used to abort the awaiting-streams wait on stop / leave / unmount.
|
|
41
|
-
const awaitAbortRef = useRef(null);
|
|
42
|
-
const [loopbackStreams, setLoopbackStreams] = useState(() => {
|
|
43
|
-
if (!call) return {};
|
|
44
|
-
return getLoopbackStreamsFor(call.state.localParticipant, call.camera.state.mediaStream, call.microphone.state.mediaStream);
|
|
45
|
-
});
|
|
46
|
-
const updateState = useCallback(next => {
|
|
47
|
-
recordingStateRef.current = next;
|
|
48
|
-
if (isMountedRef.current) {
|
|
49
|
-
setRecordingState(next);
|
|
50
|
-
}
|
|
51
|
-
}, []);
|
|
52
|
-
const stopRecording = useCallback(async () => {
|
|
53
|
-
const current = recordingStateRef.current;
|
|
54
|
-
if (current === 'idle') {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (current === 'awaiting-streams') {
|
|
58
|
-
videoLoggerSystem.getLogger('useLoopbackRecording').debug('aborting awaiting-streams wait');
|
|
59
|
-
awaitAbortRef.current?.abort();
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
await StreamVideoReactNative?.stopTrackRecording();
|
|
63
|
-
}, []);
|
|
64
|
-
const startRecording = useCallback(async ({
|
|
65
|
-
includeVideo = true,
|
|
66
|
-
maxDurationMs = DEFAULT_RECORDING_DURATION
|
|
67
|
-
} = {}) => {
|
|
68
|
-
if (!call) {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
if (recordingStateRef.current !== 'idle') {
|
|
72
|
-
console.warn('useLoopbackRecording: a recording is already running');
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
if (call.state.participantCount > 1) {
|
|
76
|
-
console.warn('useLoopbackRecording: cannot start recording with other participants present');
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
awaitAbortRef.current = new AbortController();
|
|
80
|
-
updateState('awaiting-streams');
|
|
81
|
-
let audioTrack;
|
|
82
|
-
try {
|
|
83
|
-
const streams = await waitForLoopbackStreams(call, {
|
|
84
|
-
includeVideo,
|
|
85
|
-
signal: awaitAbortRef.current.signal,
|
|
86
|
-
timeoutMs: STREAMS_WAIT_TIMEOUT_MS
|
|
87
|
-
});
|
|
88
|
-
if (streams === null) {
|
|
89
|
-
videoLoggerSystem.getLogger('useLoopbackRecording').warn('timed out waiting for loopback streams');
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
audioTrack = streams.audioTrack;
|
|
93
|
-
const videoTrackId = streams.videoTrack?.id;
|
|
94
|
-
|
|
95
|
-
// The loopback audio track lands disabled (the SDK default-mutes
|
|
96
|
-
// it to prevent echo). Enable it so the native recording
|
|
97
|
-
// pipeline receives PCM; `finally` returns it to muted.
|
|
98
|
-
if (audioTrack) {
|
|
99
|
-
audioTrack.enabled = true;
|
|
100
|
-
}
|
|
101
|
-
updateState('recording');
|
|
102
|
-
const clampedDuration = Math.min(MAX_RECORDING_DURATION, Math.max(MIN_RECORDING_DURATION, maxDurationMs));
|
|
103
|
-
|
|
104
|
-
// Pre-size the native encoder to the publisher's max video
|
|
105
|
-
// publish-option dimension. Without this, the encoder locks to
|
|
106
|
-
// whatever the SFU happens to echo *first* and stays there for the
|
|
107
|
-
// rest of the recording even after the network improves and
|
|
108
|
-
// higher layers arrive.
|
|
109
|
-
const publishMaxDim = call.getMaxVideoPublishDimension();
|
|
110
|
-
const uri = await StreamVideoReactNative.startTrackRecording({
|
|
111
|
-
videoTrackId,
|
|
112
|
-
maxDurationMs: Math.round(clampedDuration),
|
|
113
|
-
targetWidth: publishMaxDim?.width,
|
|
114
|
-
targetHeight: publishMaxDim?.height
|
|
115
|
-
});
|
|
116
|
-
return uri;
|
|
117
|
-
} finally {
|
|
118
|
-
if (audioTrack) {
|
|
119
|
-
audioTrack.enabled = false;
|
|
120
|
-
}
|
|
121
|
-
awaitAbortRef.current = null;
|
|
122
|
-
updateState('idle');
|
|
123
|
-
}
|
|
124
|
-
}, [call, updateState]);
|
|
125
|
-
const clearRecordings = useCallback(async () => {
|
|
126
|
-
await StreamVideoReactNative.clearStreamRecordings();
|
|
127
|
-
}, []);
|
|
128
|
-
const getRecordings = useCallback(async () => {
|
|
129
|
-
const list = await StreamVideoReactNative.getStreamRecordings();
|
|
130
|
-
return list ?? [];
|
|
131
|
-
}, []);
|
|
132
|
-
|
|
133
|
-
// Auto-stop on call leave / end. Aborts an awaiting-streams wait or
|
|
134
|
-
// signals native finalisation depending on which phase we're in.
|
|
135
|
-
// Without this, leaving the call mid-recording would leave native
|
|
136
|
-
// encoders mid-write while the SFU subscriber tracks end under their
|
|
137
|
-
// feet — undefined final file state.
|
|
138
|
-
useEffect(() => {
|
|
139
|
-
if (callingState === CallingState.LEFT || callingState === CallingState.IDLE) {
|
|
140
|
-
videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on call leave / end');
|
|
141
|
-
stopRecording().catch(() => {});
|
|
142
|
-
}
|
|
143
|
-
}, [callingState, stopRecording]);
|
|
144
|
-
|
|
145
|
-
// Auto-stop if another participant joins. Loopback recording is a
|
|
146
|
-
// single-user pre-call test.
|
|
147
|
-
useEffect(() => {
|
|
148
|
-
if (recordingState !== 'idle' && participantCount > 1) {
|
|
149
|
-
stopRecording().catch(() => {});
|
|
150
|
-
videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on participant count change');
|
|
151
|
-
}
|
|
152
|
-
}, [participantCount, recordingState, stopRecording]);
|
|
153
|
-
useEffect(() => {
|
|
154
|
-
isMountedRef.current = true;
|
|
155
|
-
return () => {
|
|
156
|
-
isMountedRef.current = false;
|
|
157
|
-
videoLoggerSystem.getLogger('useLoopbackRecording').debug('auto-stopping recording on unmount');
|
|
158
|
-
stopRecording().catch(() => {});
|
|
159
|
-
};
|
|
160
|
-
}, [stopRecording]);
|
|
161
|
-
|
|
162
|
-
// Subscribe to the local participant, camera and microphone streams and update the loopback streams state.
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
if (!call) return;
|
|
165
|
-
const subscription = combineLatest([call.state.localParticipant$, call.camera.state.mediaStream$, call.microphone.state.mediaStream$]).pipe(map(([participant, cameraStream, microphoneStream]) => getLoopbackStreamsFor(participant, cameraStream, microphoneStream)), distinctUntilChanged((a, b) => a.loopbackVideoStream === b.loopbackVideoStream && a.loopbackAudioStream === b.loopbackAudioStream)).subscribe(setLoopbackStreams);
|
|
166
|
-
return () => subscription.unsubscribe();
|
|
167
|
-
}, [call]);
|
|
168
|
-
return {
|
|
169
|
-
startRecording,
|
|
170
|
-
stopRecording,
|
|
171
|
-
clearRecordings,
|
|
172
|
-
getRecordings,
|
|
173
|
-
recordingState,
|
|
174
|
-
loopbackVideoStream: loopbackStreams.loopbackVideoStream,
|
|
175
|
-
loopbackAudioStream: loopbackStreams.loopbackAudioStream
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
function getLoopbackStreamsFor(participant, cameraStream, microphoneStream) {
|
|
179
|
-
return {
|
|
180
|
-
loopbackVideoStream: participant?.videoStream && participant.videoStream !== cameraStream ? participant.videoStream : undefined,
|
|
181
|
-
loopbackAudioStream: participant?.audioStream && participant.audioStream !== microphoneStream ? participant.audioStream : undefined
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Subscribe to `localParticipant$` and resolve once the requested loopback
|
|
187
|
-
* streams are present on the participant. Aborts cleanly on `signal`
|
|
188
|
-
* (resolves `null`) and rejects on timeout.
|
|
189
|
-
*/
|
|
190
|
-
function waitForLoopbackStreams(call, opts) {
|
|
191
|
-
return new Promise((resolve, reject) => {
|
|
192
|
-
const initial = getLoopbackStreams(call.state.localParticipant, call.camera.state.mediaStream, call.microphone.state.mediaStream, opts.includeVideo);
|
|
193
|
-
if (initial) {
|
|
194
|
-
resolve(initial);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
const cleanup = () => {
|
|
198
|
-
subscription.unsubscribe();
|
|
199
|
-
if (timeoutId !== undefined) {
|
|
200
|
-
clearTimeout(timeoutId);
|
|
201
|
-
}
|
|
202
|
-
opts.signal.removeEventListener('abort', onAbort);
|
|
203
|
-
};
|
|
204
|
-
const onAbort = () => {
|
|
205
|
-
cleanup();
|
|
206
|
-
resolve(null);
|
|
207
|
-
};
|
|
208
|
-
opts.signal.addEventListener('abort', onAbort);
|
|
209
|
-
const timeoutId = setTimeout(() => {
|
|
210
|
-
cleanup();
|
|
211
|
-
reject(new Error('useLoopbackRecording: timed out waiting for loopback streams. ' + 'Ensure the call was joined with `selfSubEnabled: true` and ' + 'that the SFU is configured to echo self-sub tracks.'));
|
|
212
|
-
}, opts.timeoutMs);
|
|
213
|
-
const subscription = combineLatest([call.state.localParticipant$, call.camera.state.mediaStream$, call.microphone.state.mediaStream$]).subscribe(([participant, cameraStream, microphoneStream]) => {
|
|
214
|
-
const ready = getLoopbackStreams(participant, cameraStream, microphoneStream, opts.includeVideo);
|
|
215
|
-
if (ready) {
|
|
216
|
-
cleanup();
|
|
217
|
-
resolve(ready);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
function getLoopbackStreams(participant, cameraStream, microphoneStream, includeVideo) {
|
|
223
|
-
if (!participant) return undefined;
|
|
224
|
-
const {
|
|
225
|
-
loopbackAudioStream,
|
|
226
|
-
loopbackVideoStream
|
|
227
|
-
} = getLoopbackStreamsFor(participant, cameraStream, microphoneStream);
|
|
228
|
-
const audioTrack = loopbackAudioStream?.getAudioTracks()[0];
|
|
229
|
-
const videoTrack = includeVideo ? loopbackVideoStream?.getVideoTracks()[0] : undefined;
|
|
230
|
-
if (!audioTrack || includeVideo && !videoTrack) {
|
|
231
|
-
return undefined;
|
|
232
|
-
}
|
|
233
|
-
return {
|
|
234
|
-
audioTrack,
|
|
235
|
-
videoTrack
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
//# sourceMappingURL=useLoopbackRecording.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["useCallback","useEffect","useRef","useState","NativeModules","combineLatest","distinctUntilChanged","map","CallingState","videoLoggerSystem","useCall","useCallStateHooks","StreamVideoReactNative","STREAMS_WAIT_TIMEOUT_MS","DEFAULT_RECORDING_DURATION","MIN_RECORDING_DURATION","MAX_RECORDING_DURATION","useLoopbackRecording","call","useCallCallingState","useParticipantCount","callingState","participantCount","recordingState","setRecordingState","recordingStateRef","isMountedRef","awaitAbortRef","loopbackStreams","setLoopbackStreams","getLoopbackStreamsFor","state","localParticipant","camera","mediaStream","microphone","updateState","next","current","stopRecording","getLogger","debug","abort","stopTrackRecording","startRecording","includeVideo","maxDurationMs","console","warn","AbortController","audioTrack","streams","waitForLoopbackStreams","signal","timeoutMs","videoTrackId","videoTrack","id","enabled","clampedDuration","Math","min","max","publishMaxDim","getMaxVideoPublishDimension","uri","startTrackRecording","round","targetWidth","width","targetHeight","height","clearRecordings","clearStreamRecordings","getRecordings","list","getStreamRecordings","LEFT","IDLE","catch","subscription","localParticipant$","mediaStream$","pipe","participant","cameraStream","microphoneStream","a","b","loopbackVideoStream","loopbackAudioStream","subscribe","unsubscribe","videoStream","undefined","audioStream","opts","Promise","resolve","reject","initial","getLoopbackStreams","cleanup","timeoutId","clearTimeout","removeEventListener","onAbort","addEventListener","setTimeout","Error","ready","getAudioTracks","getVideoTracks"],"sourceRoot":"../../../src","sources":["hooks/useLoopbackRecording.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
export type LoopbackRecordingState = 'idle' | 'awaiting-streams' | 'recording';
|
|
2
|
-
export type ResolvedStreams = {
|
|
3
|
-
audioTrack?: MediaStreamTrack;
|
|
4
|
-
videoTrack?: MediaStreamTrack;
|
|
5
|
-
};
|
|
6
|
-
export interface StartLoopbackRecordingOptions {
|
|
7
|
-
/**
|
|
8
|
-
* Whether to include the loopback video track in the recording.
|
|
9
|
-
* Defaults to `true`. Set to `false` for an audio-only recording.
|
|
10
|
-
* Audio is always recorded — there is no video-only mode.
|
|
11
|
-
*/
|
|
12
|
-
includeVideo?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Maximum recording duration in milliseconds, after which the
|
|
15
|
-
* recording auto-stops and finalises the file.
|
|
16
|
-
*
|
|
17
|
-
* Defaults to `10_000` (10 seconds). Clamped to
|
|
18
|
-
* `[5_000, 120_000]` (5 seconds — 2 minutes).
|
|
19
|
-
*/
|
|
20
|
-
maxDurationMs?: number;
|
|
21
|
-
}
|
|
22
|
-
export interface UseLoopbackRecordingResult {
|
|
23
|
-
/**
|
|
24
|
-
* Start a recording. The hook waits internally for the SFU loopback
|
|
25
|
-
* streams to arrive on `localParticipant`, then begins recording.
|
|
26
|
-
*
|
|
27
|
-
* The returned promise resolves with the produced `file://` URI **at
|
|
28
|
-
* the recording's terminal moment** — whether that is the auto-stop
|
|
29
|
-
* timer expiring, an explicit `stopRecording` call, or a cleanup-
|
|
30
|
-
* driven stop on unmount/leave. Resolves with `null` if no file was
|
|
31
|
-
* produced (writer torn down before any buffer arrived, or
|
|
32
|
-
* `stopRecording` was called while still awaiting streams). Rejects
|
|
33
|
-
* on a fatal error, if a recording is already running, or if the
|
|
34
|
-
* stream-wait times out.
|
|
35
|
-
*/
|
|
36
|
-
startRecording: (options?: StartLoopbackRecordingOptions) => Promise<string | null>;
|
|
37
|
-
/**
|
|
38
|
-
* Signal an early termination. While `awaiting-streams` this aborts
|
|
39
|
-
* the wait and the pending `startRecording` resolves with `null`.
|
|
40
|
-
* While `recording` this signals native finalisation and resolves
|
|
41
|
-
* once it completes.
|
|
42
|
-
*/
|
|
43
|
-
stopRecording: () => Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Recursively delete every file under the SDK's recordings directory.
|
|
46
|
-
*/
|
|
47
|
-
clearRecordings: () => Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* List every `file://` URI in the SDK's recordings directory, sorted
|
|
50
|
-
* most-recent first. Returns an empty array if the directory doesn't
|
|
51
|
-
* exist yet.
|
|
52
|
-
*/
|
|
53
|
-
getRecordings: () => Promise<string[]>;
|
|
54
|
-
/**
|
|
55
|
-
* Lifecycle phase of the recording, owned by the hook:
|
|
56
|
-
* - `'idle'`: no recording in progress.
|
|
57
|
-
* - `'awaiting-streams'`: `startRecording` was called but the SFU
|
|
58
|
-
* has not yet echoed the loopback tracks back.
|
|
59
|
-
* - `'recording'`: native pipeline is actively writing.
|
|
60
|
-
*/
|
|
61
|
-
recordingState: LoopbackRecordingState;
|
|
62
|
-
/**
|
|
63
|
-
* The SFU loopback video stream on the local participant, when
|
|
64
|
-
* present. Identified by reference inequality against
|
|
65
|
-
* `call.camera.state.mediaStream`.
|
|
66
|
-
*/
|
|
67
|
-
loopbackVideoStream?: MediaStream;
|
|
68
|
-
/**
|
|
69
|
-
* The SFU loopback audio stream on the local participant, when
|
|
70
|
-
* present. Identified by reference inequality against
|
|
71
|
-
* `call.microphone.state.mediaStream`.
|
|
72
|
-
*/
|
|
73
|
-
loopbackAudioStream?: MediaStream;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Records the SFU loopback streams (audio + video) on the local participant
|
|
77
|
-
* to a local MP4 file. Designed for the `selfSubEnabled` pre-call test mode:
|
|
78
|
-
* the SFU echoes the caller's published tracks back through the Subscriber
|
|
79
|
-
* peer connection. The hook identifies the loopback streams on the local
|
|
80
|
-
* participant by reference inequality against
|
|
81
|
-
* `call.camera.state.mediaStream` / `call.microphone.state.mediaStream` —
|
|
82
|
-
* the canonical references to the local capture — and captures them.
|
|
83
|
-
*/
|
|
84
|
-
export declare function useLoopbackRecording(): UseLoopbackRecordingResult;
|
|
85
|
-
//# sourceMappingURL=useLoopbackRecording.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useLoopbackRecording.d.ts","sourceRoot":"","sources":["../../../src/hooks/useLoopbackRecording.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,kBAAkB,GAAG,WAAW,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;;;;OAYG;IACH,cAAc,EAAE,CACd,OAAO,CAAC,EAAE,6BAA6B,KACpC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;OAEG;IACH,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC;;;;OAIG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC;;;;;;OAMG;IACH,cAAc,EAAE,sBAAsB,CAAC;IACvC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,WAAW,CAAC;IAClC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,WAAW,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,0BAA0B,CAmNjE"}
|