@joewinke/jatui 0.6.1 → 0.6.2
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.
|
@@ -224,30 +224,46 @@
|
|
|
224
224
|
} catch {
|
|
225
225
|
secondaryStream = null
|
|
226
226
|
}
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
227
|
+
const displayAudio = primaryStream.getAudioTracks()
|
|
228
|
+
const micAudio = secondaryStream?.getAudioTracks() ?? []
|
|
229
|
+
const hasLiveAudio = displayAudio.length > 0 || micAudio.length > 0
|
|
230
|
+
|
|
231
|
+
// Only build the mixed audio track when there is a REAL source to
|
|
232
|
+
// feed it. A `MediaStreamAudioDestinationNode` with nothing
|
|
233
|
+
// connected — no display audio (a window share, or a tab with no
|
|
234
|
+
// sound) and no mic (denied, or blocked at the Permissions-Policy
|
|
235
|
+
// layer) — still produces a "live" track, but one that carries no
|
|
236
|
+
// samples at all. Pairing that dead track with the video track in
|
|
237
|
+
// one MediaRecorder stalls the muxer: every `ondataavailable` fires
|
|
238
|
+
// with `size === 0`, the whole clip comes back empty, and the
|
|
239
|
+
// caller's `blob.size === 0` guard silently drops it — a clean
|
|
240
|
+
// "recording…" UI that attaches nothing on Stop, no error shown
|
|
241
|
+
// (mos-oq8b1.27). Recording video-only when there is no audio
|
|
242
|
+
// avoids ever constructing that dead track.
|
|
243
|
+
let audioTracks: MediaStreamTrack[] = []
|
|
244
|
+
if (hasLiveAudio) {
|
|
245
|
+
const AudioCtxCls =
|
|
246
|
+
window.AudioContext ||
|
|
247
|
+
(window as unknown as { webkitAudioContext: typeof AudioContext })
|
|
248
|
+
.webkitAudioContext
|
|
249
|
+
audioCtx = new AudioCtxCls()
|
|
250
|
+
const dest = audioCtx.createMediaStreamDestination()
|
|
251
|
+
for (const tracks of [displayAudio, micAudio]) {
|
|
252
|
+
if (tracks.length) {
|
|
253
|
+
audioCtx.createMediaStreamSource(new MediaStream(tracks)).connect(dest)
|
|
254
|
+
}
|
|
237
255
|
}
|
|
256
|
+
audioTracks = dest.stream.getAudioTracks()
|
|
238
257
|
}
|
|
239
|
-
stream = new MediaStream([
|
|
240
|
-
...primaryStream.getVideoTracks(),
|
|
241
|
-
...dest.stream.getAudioTracks()
|
|
242
|
-
])
|
|
258
|
+
stream = new MediaStream([...primaryStream.getVideoTracks(), ...audioTracks])
|
|
243
259
|
primaryStream.getVideoTracks()[0]?.addEventListener('ended', () => {
|
|
244
260
|
if (phase === 'recording') stop()
|
|
245
261
|
})
|
|
246
|
-
mimeUsed = pickMime(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
262
|
+
mimeUsed = pickMime(
|
|
263
|
+
hasLiveAudio
|
|
264
|
+
? ['video/webm;codecs=vp9,opus', 'video/webm;codecs=vp8,opus', 'video/webm']
|
|
265
|
+
: ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm']
|
|
266
|
+
)
|
|
251
267
|
}
|
|
252
268
|
recordedStream = stream
|
|
253
269
|
|