feat(meeting): Task 15 UI 打磨 + 主持人四件套 + 媒体层稳定性回归修复
- Task 15 UI:6 项原创特色(说话者流光 / 柔性网格 / 自视频浮窗 / 静音氛围色 / 入会滑入 / NetworkBadge 3 条波浪)+ 说话者双源探测(RTP audioLevel + WebAudio RMS)+ 主持人四件套(静音/开麦/转让/踢出) - 新增 SelfVideoFloat 浮窗组件 + 4 份 design-system 页面文档(home / preview / room / invite) - 媒体回归补丁(手工联调触发): * 后端 signal_service 在 OnRoomJoin 追加 pushExistingRoomState → 向新加入者补发历史 producers + 历史成员 audio/video 状态 * 新增 Redis Hash memberStateKey 持久化成员 audio/video enabled,OnMemberStateChanged 落盘、cleanupUserResources 清理 * 前端 _broadcastSelfState 在本地音视频开关末尾同步 state.changed;_afterJoined 先 getRoom 再 room.join 修复后入者成员状态时序;_onMemberStateChanged 占位兜底 * _cleanupRemoteProducer 改为按 producerId 精准清理(修复 "关音频误关视频") * _onRoomEnded + createAndEnter/joinAndEnter 强化 reset(修复重入会看不到自己画面) * mediasoup-client ensureSend/RecvTransport 引入 in-flight Promise 锁防并发重复建连 - 文档同步:CURRENT_STATUS.md / Task 15 plan / phase2e-2 implementation plan Made-with: Cursor
This commit is contained in:
@@ -184,12 +184,32 @@ export function createMediaEngine({ roomCode, userId, sendWithAck, logger = defa
|
||||
})
|
||||
}
|
||||
|
||||
/** 按需创建 sendTransport(已存在则复用) */
|
||||
/** in-flight Promise:sendTransport 创建并发锁;避免突发并发下重复创建 */
|
||||
let sendTransportPromise = null
|
||||
/** in-flight Promise:recvTransport 创建并发锁;Task 15 后入者 burst 订阅时尤其关键 */
|
||||
let recvTransportPromise = null
|
||||
|
||||
/** 按需创建 sendTransport(已存在则复用,并发调用共享同一个 in-flight Promise) */
|
||||
const ensureSendTransport = async () => {
|
||||
ensureDeviceLoaded()
|
||||
if (sendTransport && !sendTransport.closed) {
|
||||
return sendTransport
|
||||
}
|
||||
if (sendTransportPromise) {
|
||||
return sendTransportPromise
|
||||
}
|
||||
sendTransportPromise = (async () => {
|
||||
try {
|
||||
return await _createSendTransport()
|
||||
} finally {
|
||||
sendTransportPromise = null
|
||||
}
|
||||
})()
|
||||
return sendTransportPromise
|
||||
}
|
||||
|
||||
/** 首次创建 sendTransport 的底层流程,原本 inline 在 ensureSendTransport 中 */
|
||||
const _createSendTransport = async () => {
|
||||
const info = await requestTransportInfo('send')
|
||||
sendTransport = device.createSendTransport({
|
||||
id: info.id,
|
||||
@@ -203,12 +223,27 @@ export function createMediaEngine({ roomCode, userId, sendWithAck, logger = defa
|
||||
return sendTransport
|
||||
}
|
||||
|
||||
/** 按需创建 recvTransport(已存在则复用) */
|
||||
/** 按需创建 recvTransport(已存在则复用,并发调用共享同一个 in-flight Promise) */
|
||||
const ensureRecvTransport = async () => {
|
||||
ensureDeviceLoaded()
|
||||
if (recvTransport && !recvTransport.closed) {
|
||||
return recvTransport
|
||||
}
|
||||
if (recvTransportPromise) {
|
||||
return recvTransportPromise
|
||||
}
|
||||
recvTransportPromise = (async () => {
|
||||
try {
|
||||
return await _createRecvTransport()
|
||||
} finally {
|
||||
recvTransportPromise = null
|
||||
}
|
||||
})()
|
||||
return recvTransportPromise
|
||||
}
|
||||
|
||||
/** 首次创建 recvTransport 的底层流程 */
|
||||
const _createRecvTransport = async () => {
|
||||
const info = await requestTransportInfo('recv')
|
||||
recvTransport = device.createRecvTransport({
|
||||
id: info.id,
|
||||
|
||||
Reference in New Issue
Block a user