gaoluyang
2026-06-24 bfdc0e0e6d5e47aa501f9b6fadd143d9c97cf00a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { type VNodeRef, watch } from 'vue'
 
/**
 * 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
 * stream 为空时清掉 srcObject,避免设备关闭后画面卡在最后一帧
 */
export function useMediaStreamElement<T extends HTMLMediaElement>(
  streamSource: () => MediaStream | null | undefined
): VNodeRef {
  let el: T | null = null
  let currentStream: MediaStream | null | undefined
 
  const syncStream = () => {
    if (el) {
      el.srcObject = currentStream || null
    }
  }
 
  watch(
    streamSource,
    (stream) => {
      currentStream = stream
      syncStream()
    },
    { flush: 'post', immediate: true }
  )
 
  return (value) => {
    if (value instanceof HTMLMediaElement) {
      el = value as T
      syncStream()
      return
    }
 
    if (el) {
      el.srcObject = null
    }
    el = null
  }
}