提交 28f4122c authored 作者: 王鹏飞's avatar 王鹏飞

feat: 增强直播功能,支持动态上传选项和流重启

上级 483b0ac7
......@@ -31,7 +31,7 @@ watch(
() => {
props.onStatsChange && props.onStatsChange({ ...stats, viewers: viewers.value.length })
},
{ immediate: true, deep: true }
{ immediate: true, deep: true },
)
const detail = inject('detail')
......@@ -71,11 +71,13 @@ const { start: startSpeechTranscriber, stop: stopSpeechTranscriber } = useSpeech
const isOSSUpload = true
let ossResult = null
let totalSize = 0
const {
stream,
start: startLive,
stop: stopLive,
restartStream,
startTime,
endTime,
duration,
......@@ -83,6 +85,7 @@ const {
switchCamera,
isMobile,
} = useLive({
keepChunks: props.isLocalUpload,
onStart: () => {
console.log('开始直播')
props.onStart && props.onStart()
......@@ -92,6 +95,7 @@ const {
}
},
onRecord: async (blob) => {
totalSize += blob.size
if (props.isLocalUpload) return
if (isOSSUpload) {
ossResult = await appendUpload(blob, {
......@@ -114,7 +118,7 @@ const {
if (enabled.value) return
props.onStop && props.onStop(blob)
stopChat()
handleUpdateRecord({ live_video_size: blob.size.toString() })
handleUpdateRecord({ live_video_size: (props.isLocalUpload ? blob.size : totalSize).toString() })
// 保存录像到本地
if (props.isLocalUpload) {
saveAs(blob, `${fileName.value}.mp4`)
......@@ -201,12 +205,24 @@ const toggleLive = () => {
}
watch(enabled, toggleLive)
function start() {
if (video.value) enabled.value = true
async function start() {
if (!video.value) return
if (window.parent !== window) {
window.parent.postMessage({ action: 'monitor-pause' }, '*')
// 等父页面释放摄像头后再重新获取
await new Promise((r) => setTimeout(r, 500))
await restartStream()
}
enabled.value = true
}
function stop() {
if (video.value) {
if (!video.value) return
enabled.value = false
if (window.parent !== window) {
// 等录制完全停止后通知父页面恢复监控
setTimeout(() => {
window.parent.postMessage({ action: 'monitor-resume' }, '*')
}, 500)
}
}
defineExpose({ enabled, start, stop })
......@@ -228,9 +244,18 @@ defineExpose({ enabled, start, stop })
size="small"
@click="switchCamera"
v-if="isMobile && !enabled && !recordId">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
<circle cx="12" cy="13" r="4"/>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round">
<path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
<circle cx="12" cy="13" r="4" />
</svg>
</el-button>
</div>
......
......@@ -20,12 +20,13 @@ export const readBlobAsBase64 = (blob: Blob): Promise<string> => {
interface UseLiveProps {
enabledUserMedia: boolean
keepChunks?: boolean
onStart?: () => void
onRecord?: (data: Blob) => void
onStop?: (blob: Blob) => void
}
export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }: UseLiveProps) {
export function useLive({ enabledUserMedia = true, keepChunks = true, onStart, onRecord, onStop }: UseLiveProps) {
const startTime = ref(0)
const endTime = ref(0)
const duration = computed(() => (endTime.value - startTime.value) / 1000)
......@@ -52,7 +53,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
})
// 创建媒体流
const { stream } = useUserMedia({
const { stream, restart: restartStream } = useUserMedia({
enabled: enabledUserMedia,
constraints: constraints as any,
})
......@@ -75,7 +76,7 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
// 数据可用时处理
const handleDataAvailable = (event: BlobEvent) => {
if (event.data.size > 0) {
recordedChunks.value.push(event.data)
if (keepChunks) recordedChunks.value.push(event.data)
onRecord && onRecord(event.data)
}
}
......@@ -125,5 +126,18 @@ export function useLive({ enabledUserMedia = true, onStart, onRecord, onStop }:
nextTick(() => initializeMediaRecorder())
}
return { stream, start, stop, startTime, endTime, duration, currentTime, switchCamera, facingMode, isFrontCamera, isMobile }
return {
stream,
start,
stop,
restartStream,
startTime,
endTime,
duration,
currentTime,
switchCamera,
facingMode,
isFrontCamera,
isMobile,
}
}
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论