123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- import { reactive, ref, Ref } from 'vue'
- import * as RongIMLib from '@rongcloud/imlib-next'
- import * as RTC from '@rongcloud/plugin-rtc'
- import request from '/src/helpers/request'
- import event, { LIVE_EVENT_MESSAGE } from './event'
- import { removeMedia } from './helpers'
- type imConnectStatus = 'connecting' | 'connected' | 'disconnect'
- type VideoStatus = 'init' | 'stream' | 'liveing' | 'stopped' | 'error' | 'loading'
- type TrackType = 'microphone' | 'camera' | 'screen'
- type ActiveTracks = {
- [key in TrackType]: RTC.RCLocalTrack | null
- }
- const runtime = reactive({
- /** IM连接状态 */
- imConnectStatus: 'connecting' as imConnectStatus,
- // 屏幕分享状态
- screenShareStatus: false,
- // 视频节点
- videoRef: ref<HTMLVideoElement | null>(null),
- // RTC实例
- rtcClient: null as RTC.RCRTCClient | null,
- /** 加入房间实例 */
- joinedRoom: null as RTC.RCLivingRoom | null,
- // Tracks
- mediaStreamTrack: [] as MediaStreamTrack[],
- // 媒体流
- mediaStreams: null as MediaStream | null,
- // 视频状态
- videoStatus: 'init' as VideoStatus,
- // 麦克风设备列表
- microphones: [] as MediaDeviceInfo[],
- // 摄像头设备列表
- cameras: [] as MediaDeviceInfo[],
- // 摄像头设备
- selectedCamera: null as MediaDeviceInfo | null,
- // 麦克风设备
- selectedMicrophone: null as MediaDeviceInfo | null,
- // 点赞数量
- likeCount: 0,
- // 上一次点赞数量
- lastLikeCount: 0,
- /** 当前活跃的数据流 */
- activeTracks: {} as ActiveTracks,
- })
- export default runtime
- const RONG_IM_TOKEN = 'c9kqb3rdc451j'
- RongIMLib.init({
- appkey: RONG_IM_TOKEN,
- })
- type MessageProps = {
- messageType: 'RC:Chatroom:Welcome' | 'RC:TxtMsg' | 'RC:Chatroom:Barrage' | 'RC:Chatroom:Like',
- content: any,
- }
- type MessageEvent = {
- messages: MessageProps[],
- }
- const Events = RongIMLib.Events
- /**
- * 监听消息通知
- */
- const { MESSAGES, ...RestMessage } = Events
- RongIMLib.addEventListener(Events.MESSAGES, (evt: MessageEvent) => {
- const { messages } = evt
- for (const message of messages) {
- if (LIVE_EVENT_MESSAGE[message.messageType]) {
- event.emit(LIVE_EVENT_MESSAGE[message.messageType], {...message.content, $EventMessage: message})
- }
- }
- })
- for (const Message of Object.values(RestMessage)) {
- RongIMLib.addEventListener(Message, (evt: any) => {
- console.log(Message, evt)
- // chatroomDestroyed
- event.emit(Message, {$EventMessage: null})
- })
- }
- /**
- * 监听 IM 连接状态变化
- */
- RongIMLib.addEventListener(Events.CONNECTING, () => {
- console.log('connecting')
- runtime.imConnectStatus = 'connecting'
- })
- RongIMLib.addEventListener(Events.CONNECTED, () => {
- console.log('connected')
- runtime.imConnectStatus = 'connected'
- })
- RongIMLib.addEventListener(Events.DISCONNECT, () => {
- console.log('disconnect')
- runtime.imConnectStatus = 'disconnect'
- })
- export const connectIM = async (imToken: string) => {
- try {
- const user = await RongIMLib.connect(imToken)
- runtime.rtcClient = RongIMLib.installPlugin(RTC.installer, {})
- console.log('connect success', user.data?.userId)
- return user
- } catch (error) {
- throw error
- }
- }
- /**
- * 设置video视频流
- */
- export const setVideoSrcObject = (video: HTMLVideoElement | null, mediaStreams: MediaStream | null) => {
- if (video && mediaStreams) {
- video.srcObject = mediaStreams
- video.onloadedmetadata = () => {
- video.play()
- }
- }
- }
- /**
- * 发起屏幕共享
- */
- export const shareScreenVideo = async () => {
- if (runtime.rtcClient) {
- const screenTrack = await getTrack('screen')
- const oldTrack = runtime.activeTracks.camera as RTC.RCLocalTrack
- removeTrack([oldTrack], 'camera')
- setTrack([screenTrack as RTC.RCLocalTrack], 'screen')
- screenTrack?.on(RTC.RCLocalTrack.EVENT_LOCAL_TRACK_END, (track: RTC.RCLocalTrack) => {
- runtime.screenShareStatus = false
- removeTrack([track], 'screen')
- setTrack([oldTrack as RTC.RCLocalTrack], 'camera')
- // setVideoSrcObject(runtime.videoRef, this.mediaStreams)
- })
- }
- }
- /**
- *
- * 获取所有音频输入设备
- * @returns {Promise<void>}
- */
- export const getMicrophones = async () => {
- const microphones = await RTC.device.getMicrophones()
- runtime.microphones = microphones
- return microphones
- }
- /**
- *
- * 获取所有视频输入设备
- * @returns {Promise<void>}
- */
- export const getCameras = async () => {
- const cameras = await RTC.device.getCameras()
- runtime.cameras = cameras
- return cameras
- }
- /**
- *
- * 设置当前视频设备
- * @param camera MediaDeviceInfo
- */
- export const setSelectCamera = (camera: MediaDeviceInfo) => {
- runtime.selectedCamera = camera
- }
- /**
- *
- * 设置当前麦克风设备
- * @param microphone MediaDeviceInfo
- */
- export const setSelectMicrophone = (microphone: MediaDeviceInfo) => {
- runtime.selectedMicrophone = microphone
- }
- type TrackResult = {
- code: RTC.RCRTCCode,
- track: RTC.RCMicphoneAudioTrack | RTC.RCCameraVideoTrack | RTC.RCScreenVideoTrack | undefined
- }
- export const getTrack = async (trackType: TrackType): Promise<RTC.RCLocalTrack> => {
- let res: TrackResult | undefined
- let Track: RTC.RCLocalTrack | null = null
- if (trackType === 'microphone') {
- res = await runtime.rtcClient?.createMicrophoneAudioTrack('RongCloudRTC', {
- micphoneId: runtime.selectedMicrophone?.deviceId,
- }) as TrackResult
- } else if (trackType === 'camera') {
- res = await runtime.rtcClient?.createCameraVideoTrack('RongCloudRTC', {
- cameraId: runtime.selectedCamera?.deviceId,
- faceMode: 'user',
- frameRate: RTC.RCFrameRate.FPS_15,
- resolution: RTC.RCResolution.W1280_H720,
- }) as TrackResult
- } else {
- res = await runtime?.rtcClient?.createScreenVideoTrack() as TrackResult
- }
- Track = res?.track as RTC.RCLocalTrack
- if (res.code !== RTC.RCRTCCode.SUCCESS || !Track) {
- throw new Error('获取数据流失败')
- }
- return Track
- }
- /**
- * 添加视频流,会同步修改当先视频与推送的流
- * @param track
- */
- export const setTrack = async (tracks: RTC.RCLocalTrack[], trackType: TrackType) => {
- for (const track of tracks) {
- // @ts-ignore
- await runtime.mediaStreams?.addTrack(track._msTrack)
- runtime.activeTracks[trackType] = track
- }
- await runtime.joinedRoom?.publish(tracks)
- }
- /**
- * 删除视频流,会同步修改当先视频与推送的流
- * @param track
- */
- export const removeTrack = async (tracks: RTC.RCLocalTrack[], trackType: TrackType) => {
- for (const track of tracks) {
- // @ts-ignore
- await runtime.mediaStreams?.removeTrack(track._msTrack)
- runtime.activeTracks[trackType] = null
- }
- await runtime.joinedRoom?.unpublish(tracks)
- }
- export const joinRoom = async (roomId: string, type: RTC.RCLivingType, listenEvents: RTC.IRoomEventListener | null) => {
- await RongIMLib.joinChatRoom(roomId, {count: 0})
- const join = await runtime.rtcClient?.joinLivingRoom(roomId, type)
- if (join?.code != RTC.RCRTCCode.SUCCESS) throw Error('加入房间失败')
- join.room?.registerRoomEventListener(listenEvents)
- return join
- }
- /**
- * 开始直播
- */
- export const startLive = async () => {
- if (runtime.videoStatus !== 'stream') throw Error('当前无视频流')
- }
- /**
- * 关闭直播
- */
- export const closeLive = async () => {
- removeMedia(runtime.mediaStreams, runtime.mediaStreamTrack)
- runtime.videoStatus = 'stopped'
- }
- /**
- * 同步点赞数量
- */
- export const loopSyncLike = async () => {
- if (runtime.likeCount !== runtime.lastLikeCount) {
- try {
- await request.post('/api/live/like', {})
- runtime.lastLikeCount = runtime.likeCount
- } catch (error) {}
- }
- setTimeout(() => {
- loopSyncLike()
- }, 1000 * 60 * 5)
- }
|