✨ feat(im): 通话窗扬声器开关 + 按钮关闭态统一深色样式 + 群通话支持刷新后重新加入
- useLiveKitRoom 增加 speakerEnabled 状态 + setSpeakerEnabled;audio 元素 :muted 联动,实现扬声器实际开关 - mic / speaker / camera / 屏幕共享 4 个按钮关闭态统一 bg-white/15 深色(之前一直 bg-white 像「开」) - speaker / camera / 屏幕共享 关闭态 icon 借用 tabler:volume-off / video-off / device-laptop-off 显斜线(ant-design 缺 muted 变体) - RtcGroupCallBanner 修复刷新后无法重新加入:按钮文案改为「已在通话中 / 重新加入 / 加入」三态;按钮文字色锁定深色防暗色主题不可见 - RtcCallIncoming 对齐微信样式:右上角小条 + 横排(头像 / 名 / 按钮);群聊带「通话成员」头像行 - RtcCallRunning UnoCSS 重写 + 接收 isGroup prop(去 conversationType 派生) - RtcCallParticipantTile UnoCSS 重写 + speakerEnabled 透传静音 - 注释 / UI 文案半角省略号 → 全角……;watcher 参数 hidden → suppressTickim
parent
03d0ce800d
commit
5d222bdf48
|
|
@ -18,32 +18,33 @@
|
||||||
class="self-start"
|
class="self-start"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 中:群聊单行(邀请人 + 文案)+ 通话成员;私聊两行 -->
|
<!-- 中:群聊单行(邀请人 + 文案)+ 通话成员;私聊两行(名 / 文案) -->
|
||||||
<div class="flex flex-col flex-1 gap-1 self-start min-w-0">
|
<div class="flex flex-col flex-1 gap-1 self-start min-w-0">
|
||||||
<template v-if="isGroup">
|
<!-- 名 + 文案:群单行内联,私聊上下两行 -->
|
||||||
<div class="text-sm truncate">
|
<div v-if="isGroup" class="text-sm truncate">
|
||||||
<span class="font-medium">{{ payload?.inviterNickname || '对方' }}</span>
|
<span class="font-medium">{{ payload?.inviterNickname || '对方' }}</span>
|
||||||
<span class="ml-1 text-white/60">{{ tipText }}</span>
|
<span class="ml-1 text-white/60">{{ tipText }}</span>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="callMembers.length > 0">
|
|
||||||
<div class="mt-1 text-xs text-white/45">通话成员</div>
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
<UserAvatar
|
|
||||||
v-for="m in callMembers"
|
|
||||||
:key="m.userId"
|
|
||||||
:url="m.avatar"
|
|
||||||
:name="m.nickname"
|
|
||||||
:size="22"
|
|
||||||
radius="4px"
|
|
||||||
:clickable="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="text-sm font-medium truncate">{{ payload?.inviterNickname || '对方' }}</div>
|
<div class="text-sm font-medium truncate">{{ payload?.inviterNickname || '对方' }}</div>
|
||||||
<div class="text-13px text-white/60 truncate">{{ tipText }}</div>
|
<div class="text-13px text-white/60 truncate">{{ tipText }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- 群通话成员行;私聊无 -->
|
||||||
|
<template v-if="isGroup && callMembers.length > 0">
|
||||||
|
<div class="mt-1 text-xs text-white/45">通话成员</div>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<UserAvatar
|
||||||
|
v-for="member in callMembers"
|
||||||
|
:key="member.userId"
|
||||||
|
:url="member.avatar"
|
||||||
|
:name="member.nickname"
|
||||||
|
:size="22"
|
||||||
|
radius="4px"
|
||||||
|
:clickable="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右下角:拒绝 / 接听 -->
|
<!-- 右下角:拒绝 / 接听 -->
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- 主叫等待对方接听的悬浮窗;1v1 私聊 320×540;群通话切大窗 720×560 -->
|
<!-- 主叫等待对方接听的悬浮窗;1v1 私聊 320×540;群通话切大窗 720×560 -->
|
||||||
<div
|
<div
|
||||||
class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl overflow-hidden shadow-[0_12px_36px_rgba(0,0,0,0.35)] z-[9999] flex flex-col text-white bg-gradient-to-b from-[#2a2a2c] to-[#1a1a1c]"
|
class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl overflow-hidden shadow-[0_12px_36px_rgba(0,0,0,0.35)] z-[1000] flex flex-col text-white bg-gradient-to-b from-[#2a2a2c] to-[#1a1a1c]"
|
||||||
:class="isGroup ? 'w-[720px] h-[560px]' : 'w-[320px] h-[540px]'"
|
:class="isGroup ? 'w-[720px] h-[560px]' : 'w-[320px] h-[540px]'"
|
||||||
>
|
>
|
||||||
<div class="flex relative flex-1 justify-center items-center">
|
<div class="flex relative flex-1 justify-center items-center">
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
:clickable="false"
|
:clickable="false"
|
||||||
/>
|
/>
|
||||||
<div class="text-[17px] font-medium">{{ peerNickname || '对方' }}</div>
|
<div class="text-[17px] font-medium">{{ peerNickname || '对方' }}</div>
|
||||||
<div class="text-13px text-white/60">等待对方接受邀请...</div>
|
<div class="text-13px text-white/60">等待对方接受邀请……</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -36,8 +36,10 @@
|
||||||
class="flex flex-col gap-2 items-center cursor-pointer select-none"
|
class="flex flex-col gap-2 items-center cursor-pointer select-none"
|
||||||
@click="$emit('toggle-mic')"
|
@click="$emit('toggle-mic')"
|
||||||
>
|
>
|
||||||
|
<!-- ant-design 系列里 mic 有 audio-muted-outlined 变体;speaker / camera 没有 muted 变体,off 态借 tabler:*-off 表达斜线 -->
|
||||||
<span
|
<span
|
||||||
class="flex justify-center items-center w-12 h-12 bg-white rounded-full text-[#1a1a1c]"
|
class="flex justify-center items-center w-12 h-12 rounded-full"
|
||||||
|
:class="micEnabled ? 'bg-white text-[#1a1a1c]' : 'bg-white/15 text-white'"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
:icon="micEnabled ? 'ant-design:audio-outlined' : 'ant-design:audio-muted-outlined'"
|
:icon="micEnabled ? 'ant-design:audio-outlined' : 'ant-design:audio-muted-outlined'"
|
||||||
|
|
@ -65,14 +67,11 @@
|
||||||
@click="$emit('toggle-camera')"
|
@click="$emit('toggle-camera')"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="flex justify-center items-center w-12 h-12 bg-white rounded-full text-[#1a1a1c]"
|
class="flex justify-center items-center w-12 h-12 rounded-full"
|
||||||
|
:class="cameraEnabled ? 'bg-white text-[#1a1a1c]' : 'bg-white/15 text-white'"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
:icon="
|
:icon="cameraEnabled ? 'ant-design:video-camera-outlined' : 'tabler:video-off'"
|
||||||
cameraEnabled
|
|
||||||
? 'ant-design:video-camera-outlined'
|
|
||||||
: 'ant-design:video-camera-add-outlined'
|
|
||||||
"
|
|
||||||
:size="22"
|
:size="22"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -86,11 +85,17 @@
|
||||||
@click="$emit('toggle-speaker')"
|
@click="$emit('toggle-speaker')"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="flex justify-center items-center w-12 h-12 bg-white rounded-full text-[#1a1a1c]"
|
class="flex justify-center items-center w-12 h-12 rounded-full"
|
||||||
|
:class="speakerEnabled ? 'bg-white text-[#1a1a1c]' : 'bg-white/15 text-white'"
|
||||||
>
|
>
|
||||||
<Icon icon="ant-design:sound-outlined" :size="22" />
|
<Icon
|
||||||
|
:icon="speakerEnabled ? 'ant-design:sound-outlined' : 'tabler:volume-off'"
|
||||||
|
:size="22"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-white/70 whitespace-nowrap">
|
||||||
|
{{ speakerEnabled ? '扬声器已开' : '扬声器已关' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs text-white/70 whitespace-nowrap">扬声器已开</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -108,6 +113,7 @@ const props = defineProps<{
|
||||||
isVideo: boolean
|
isVideo: boolean
|
||||||
micEnabled: boolean
|
micEnabled: boolean
|
||||||
cameraEnabled: boolean
|
cameraEnabled: boolean
|
||||||
|
speakerEnabled: boolean
|
||||||
localStream?: MediaStream | null // 本地视频流;视频呼叫预览铺底
|
localStream?: MediaStream | null // 本地视频流;视频呼叫预览铺底
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
class="inline-flex absolute top-3 left-1/2 z-10 gap-2 items-center px-3.5 py-1.5 text-13px text-[#ffd45e] rounded-full -translate-x-1/2 bg-[rgba(255,196,0,0.18)]"
|
class="inline-flex absolute top-3 left-1/2 z-10 gap-2 items-center px-3.5 py-1.5 text-13px text-[#ffd45e] rounded-full -translate-x-1/2 bg-[rgba(255,196,0,0.18)]"
|
||||||
>
|
>
|
||||||
<span class="reconnect-dot w-2 h-2 rounded-full bg-[#ffd45e]"></span>
|
<span class="reconnect-dot w-2 h-2 rounded-full bg-[#ffd45e]"></span>
|
||||||
网络不佳,正在重连...
|
网络不佳,正在重连……
|
||||||
</div>
|
</div>
|
||||||
<div class="flex relative flex-1 justify-center items-center">
|
<div class="flex relative flex-1 justify-center items-center">
|
||||||
<!-- 群通话:网格布局,列数随人数自适应 -->
|
<!-- 群通话:网格布局,列数随人数自适应 -->
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
:class="gridColsClass"
|
:class="gridColsClass"
|
||||||
>
|
>
|
||||||
<RtcCallParticipantTile
|
<RtcCallParticipantTile
|
||||||
v-for="p in participants"
|
v-for="participant in participants"
|
||||||
:key="p.userId"
|
:key="participant.userId"
|
||||||
:participant="p"
|
:participant="participant"
|
||||||
:speaker-enabled="speakerEnabled"
|
:speaker-enabled="speakerEnabled"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
:clickable="false"
|
:clickable="false"
|
||||||
/>
|
/>
|
||||||
<div class="text-[17px] font-medium">{{ peerNickname }}</div>
|
<div class="text-[17px] font-medium">{{ peerNickname }}</div>
|
||||||
<div class="text-13px text-white/60">等待对方开启摄像头...</div>
|
<div class="text-13px text-white/60">等待对方开启摄像头……</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="localStream"
|
v-if="localStream"
|
||||||
|
|
@ -146,7 +146,10 @@
|
||||||
class="flex justify-center items-center w-[52px] h-[52px] rounded-full"
|
class="flex justify-center items-center w-[52px] h-[52px] rounded-full"
|
||||||
:class="screenShareEnabled ? 'bg-[#07c160] text-white' : 'bg-white/15 text-white'"
|
:class="screenShareEnabled ? 'bg-[#07c160] text-white' : 'bg-white/15 text-white'"
|
||||||
>
|
>
|
||||||
<Icon icon="ant-design:laptop-outlined" :size="22" />
|
<Icon
|
||||||
|
:icon="screenShareEnabled ? 'ant-design:laptop-outlined' : 'tabler:device-laptop-off'"
|
||||||
|
:size="22"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs text-white/70 whitespace-nowrap">
|
<span class="text-xs text-white/70 whitespace-nowrap">
|
||||||
{{ screenShareEnabled ? '停止共享' : '共享屏幕' }}
|
{{ screenShareEnabled ? '停止共享' : '共享屏幕' }}
|
||||||
|
|
@ -235,8 +238,8 @@ const now = ref(Date.now())
|
||||||
let tick = 0
|
let tick = 0
|
||||||
watch(
|
watch(
|
||||||
() => props.isGroup || props.isVideo,
|
() => props.isGroup || props.isVideo,
|
||||||
(hidden) => {
|
(suppressTick) => {
|
||||||
if (hidden) {
|
if (suppressTick) {
|
||||||
if (tick) {
|
if (tick) {
|
||||||
clearInterval(tick)
|
clearInterval(tick)
|
||||||
tick = 0
|
tick = 0
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,15 @@
|
||||||
<!-- 展开面板:在通话成员头像横排 + 加入按钮 -->
|
<!-- 展开面板:在通话成员头像横排 + 加入按钮 -->
|
||||||
<div class="flex flex-col gap-4 items-center pt-2 pb-1">
|
<div class="flex flex-col gap-4 items-center pt-2 pb-1">
|
||||||
<div class="flex flex-wrap gap-1.5 justify-center max-w-[240px]">
|
<div class="flex flex-wrap gap-1.5 justify-center max-w-[240px]">
|
||||||
<div v-for="m in joinedMembers" :key="m.userId" class="inline-flex" :title="m.nickname">
|
<div
|
||||||
|
v-for="member in joinedMembers"
|
||||||
|
:key="member.userId"
|
||||||
|
class="inline-flex"
|
||||||
|
:title="member.nickname"
|
||||||
|
>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
:url="m.avatar"
|
:url="member.avatar"
|
||||||
:name="m.nickname"
|
:name="member.nickname"
|
||||||
:size="40"
|
:size="40"
|
||||||
radius="6px"
|
radius="6px"
|
||||||
:clickable="false"
|
:clickable="false"
|
||||||
|
|
@ -43,13 +48,13 @@
|
||||||
暂无成员在通话
|
暂无成员在通话
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 自己已在通话内时置灰显示「已在通话中」,避免重复 join -->
|
<!-- 本端在通话内时置灰「已在通话中」;服务端残留我但本端连接断了显示「重新加入」(刷新页面后场景) -->
|
||||||
<button
|
<button
|
||||||
class="w-[200px] h-9 text-sm font-medium rounded-lg cursor-pointer border-none bg-[#f1f1f3] text-[var(--el-text-color-primary)] transition-colors duration-150 disabled:cursor-not-allowed disabled:text-[var(--el-text-color-secondary)] hover:[&:not(:disabled)]:bg-[#e7e7ea]"
|
class="w-[200px] h-9 text-sm font-medium rounded-lg cursor-pointer border-none bg-[#f1f1f3] text-[#1a1a1c] transition-colors duration-150 disabled:cursor-not-allowed disabled:text-[#999] hover:[&:not(:disabled)]:bg-[#e7e7ea]"
|
||||||
:disabled="joinDisabled"
|
:disabled="joinDisabled"
|
||||||
@click="handleJoin"
|
@click="handleJoin"
|
||||||
>
|
>
|
||||||
{{ joinDisabled ? '已在通话中' : '加入' }}
|
{{ joinLabel }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
|
|
@ -136,15 +141,30 @@ const joinedMembers = computed(() => {
|
||||||
|
|
||||||
const joinedCount = computed(() => joinedMembers.value.length)
|
const joinedCount = computed(() => joinedMembers.value.length)
|
||||||
|
|
||||||
/** 加入按钮禁用:自己已经在该房间内(含本端正在 INVITING / RUNNING) */
|
/** 本端是否正在该房间通话(处于 INVITING / RUNNING) */
|
||||||
const joinDisabled = computed(() => {
|
const isInThisCall = computed(
|
||||||
|
() => rtcStore.isActive && rtcStore.call?.room === activeCall.value?.room
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端是否记录我已加入;刷新后 LiveKit 连接已断但 webhook 还没把 status 标为 LEFT 时仍为 true;
|
||||||
|
* 用于把按钮文案切到「重新加入」,但不 disable 按钮
|
||||||
|
*/
|
||||||
|
const serverSaysJoined = computed(() => {
|
||||||
const myId = getCurrentUserId()
|
const myId = getCurrentUserId()
|
||||||
if (rtcStore.isActive && rtcStore.call?.room === activeCall.value?.room) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return activeCall.value?.joinedUserIds?.includes(myId) ?? false
|
return activeCall.value?.joinedUserIds?.includes(myId) ?? false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 加入按钮禁用:仅在本端实际持有 LiveKit 连接时禁用 */
|
||||||
|
const joinDisabled = computed(() => isInThisCall.value)
|
||||||
|
|
||||||
|
/** 加入按钮文案;本端连着 → 已在通话中;服务端还残留我但本端断了 → 重新加入;其它 → 加入 */
|
||||||
|
const joinLabel = computed(() => {
|
||||||
|
if (isInThisCall.value) return '已在通话中'
|
||||||
|
if (serverSaysJoined.value) return '重新加入'
|
||||||
|
return '加入'
|
||||||
|
})
|
||||||
|
|
||||||
/** 主动加入:调 invite 命中已有 call 拿 token;rtcStore 按 status 自动进 RUNNING */
|
/** 主动加入:调 invite 命中已有 call 拿 token;rtcStore 按 status 自动进 RUNNING */
|
||||||
async function handleJoin() {
|
async function handleJoin() {
|
||||||
const call = activeCall.value
|
const call = activeCall.value
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ export function useLiveKitRoom() {
|
||||||
const micEnabled = ref(true)
|
const micEnabled = ref(true)
|
||||||
/** 摄像头开关 */
|
/** 摄像头开关 */
|
||||||
const cameraEnabled = ref(false)
|
const cameraEnabled = ref(false)
|
||||||
|
/** 扬声器开关;浏览器无系统级 API,通过 audio 元素 muted 属性实现远端音频静音 */
|
||||||
|
const speakerEnabled = ref(true)
|
||||||
/** 屏幕共享开关 */
|
/** 屏幕共享开关 */
|
||||||
const screenShareEnabled = ref(false)
|
const screenShareEnabled = ref(false)
|
||||||
/** 当前是否处于「重连中」;瞬断时 UI 显示提示而不强制结束通话 */
|
/** 当前是否处于「重连中」;瞬断时 UI 显示提示而不强制结束通话 */
|
||||||
|
|
@ -99,7 +101,7 @@ export function useLiveKitRoom() {
|
||||||
.on(RoomEvent.ConnectionQualityChanged, (quality) => {
|
.on(RoomEvent.ConnectionQualityChanged, (quality) => {
|
||||||
connectionQuality.value = quality
|
connectionQuality.value = quality
|
||||||
})
|
})
|
||||||
// 瞬断 → 显示「重连中」;不关通话窗,由 ICE restart 机制恢复
|
// 瞬断 → 显示「重连中」;不关通话窗,由 SDK 内部重连机制恢复
|
||||||
.on(RoomEvent.Reconnecting, () => {
|
.on(RoomEvent.Reconnecting, () => {
|
||||||
reconnecting.value = true
|
reconnecting.value = true
|
||||||
})
|
})
|
||||||
|
|
@ -113,7 +115,7 @@ export function useLiveKitRoom() {
|
||||||
disconnectedHandlers.forEach((cb) => cb())
|
disconnectedHandlers.forEach((cb) => cb())
|
||||||
})
|
})
|
||||||
|
|
||||||
// 预热 getUserMedia 与 WebSocket 握手并行,省 100~300ms 串行延迟;
|
// 预热 getUserMedia 与 WebSocket 握手并行,省 100~300ms 串行延迟;
|
||||||
// 拿到的 stream 仅用于触发权限弹窗 + 设备就绪,握手完成后由 LiveKit 内部重新请求设备发布轨
|
// 拿到的 stream 仅用于触发权限弹窗 + 设备就绪,握手完成后由 LiveKit 内部重新请求设备发布轨
|
||||||
const warmup = prewarmMedia(opts)
|
const warmup = prewarmMedia(opts)
|
||||||
// 建立 WebSocket 信令 + WebRTC 媒体通道;完成后 localParticipant 可用,已在房参与者会通过 ParticipantConnected 事件批量推送
|
// 建立 WebSocket 信令 + WebRTC 媒体通道;完成后 localParticipant 可用,已在房参与者会通过 ParticipantConnected 事件批量推送
|
||||||
|
|
@ -176,6 +178,11 @@ export function useLiveKitRoom() {
|
||||||
cameraEnabled.value = enabled
|
cameraEnabled.value = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 切扬声器;仅切响应式状态,实际静音由模板上 audio 元素 :muted 绑定生效 */
|
||||||
|
function setSpeakerEnabled(enabled: boolean) {
|
||||||
|
speakerEnabled.value = enabled
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切屏幕共享;
|
* 切屏幕共享;
|
||||||
*
|
*
|
||||||
|
|
@ -264,6 +271,7 @@ export function useLiveKitRoom() {
|
||||||
reconnecting.value = false
|
reconnecting.value = false
|
||||||
micEnabled.value = true
|
micEnabled.value = true
|
||||||
cameraEnabled.value = false
|
cameraEnabled.value = false
|
||||||
|
speakerEnabled.value = true
|
||||||
screenShareEnabled.value = false
|
screenShareEnabled.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,12 +283,14 @@ export function useLiveKitRoom() {
|
||||||
connectionQuality,
|
connectionQuality,
|
||||||
micEnabled,
|
micEnabled,
|
||||||
cameraEnabled,
|
cameraEnabled,
|
||||||
|
speakerEnabled,
|
||||||
screenShareEnabled,
|
screenShareEnabled,
|
||||||
reconnecting,
|
reconnecting,
|
||||||
connect,
|
connect,
|
||||||
disconnect,
|
disconnect,
|
||||||
setMicEnabled,
|
setMicEnabled,
|
||||||
setCameraEnabled,
|
setCameraEnabled,
|
||||||
|
setSpeakerEnabled,
|
||||||
setScreenShareEnabled,
|
setScreenShareEnabled,
|
||||||
pickStream,
|
pickStream,
|
||||||
onDisconnected,
|
onDisconnected,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue