Browse Source

添加im等基础宝

wolyshaw 3 years ago
parent
commit
56098548ce

File diff suppressed because it is too large
+ 1168 - 5
package-lock.json


+ 5 - 0
package.json

@@ -8,13 +8,18 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@rongcloud/imlib-next": "^5.1.1",
+    "@rongcloud/plugin-rtc": "^5.3.1",
     "vue": "^3.2.25"
   },
   "devDependencies": {
     "@types/node": "^17.0.17",
+    "@vitejs/plugin-legacy": "^1.7.1",
     "@vitejs/plugin-vue": "^2.2.0",
+    "@vitejs/plugin-vue-jsx": "^1.3.7",
     "typescript": "^4.5.4",
     "vite": "^2.8.0",
+    "vite-plugin-pwa": "^0.11.13",
     "vue-tsc": "^0.29.8"
   }
 }

+ 2 - 2
src/App.vue

@@ -2,11 +2,11 @@
 // This starter template is using Vue 3 <script setup> SFCs
 // Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
 import HelloWorld from './components/HelloWorld.vue'
+import LiveBroadcast from './components/live-broadcast'
 </script>
 
 <template>
-  <img alt="Vue logo" src="./assets/logo.png" />
-  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
+  <LiveBroadcast/>
 </template>
 
 <style>

+ 14 - 0
src/components/live-broadcast/helpers.ts

@@ -0,0 +1,14 @@
+export const requireMedia = async (constraints: MediaStreamConstraints) => {
+  if (!navigator) throw new Error('浏览器版本过低,无法开始直播')
+  return navigator.mediaDevices.getUserMedia(constraints)
+}
+
+export const removeMedia = async (mediaStreams: MediaStream | null, tracks: MediaStreamTrack[]) => {
+  if (!navigator) throw new Error('浏览器版本过低')
+  if (!mediaStreams) return []
+  return (tracks || []).map(track => mediaStreams.removeTrack(track))
+}
+
+export const joinRoom = async (roomId: string) => {
+
+}

+ 117 - 0
src/components/live-broadcast/index.tsx

@@ -0,0 +1,117 @@
+import { defineComponent, ref } from 'vue'
+import * as RongIMLib from '@rongcloud/imlib-next'
+import { installer, RCRTCCode, RCRTCClient, RCLocalTrack } from '@rongcloud/plugin-rtc'
+import runtime from './runtime'
+import { requireMedia, removeMedia } from './helpers'
+
+const RONG_IM_TOKEN = 'c9kqb3rdc451j'
+
+RongIMLib.init({
+  appkey: RONG_IM_TOKEN,
+})
+
+/**
+ * 监听消息通知
+ */
+ const Events = RongIMLib.Events;
+ RongIMLib.addEventListener(Events.MESSAGES, (event) => {
+   console.log('received messages', event.messages)
+ })
+
+ /**
+  * 监听 IM 连接状态变化
+  */
+ RongIMLib.addEventListener(Events.CONNECTING, () => {
+   runtime.imConnectStatus = 'connecting'
+ })
+
+ RongIMLib.addEventListener(Events.CONNECTED, () => {
+   runtime.imConnectStatus = 'connected'
+ })
+
+ RongIMLib.addEventListener(Events.DISCONNECT, () => {
+   runtime.imConnectStatus = 'disconnect'
+ })
+
+ let rtcClient: RCRTCClient | null
+
+ RongIMLib.connect('hXAfqkZDs146m6MjMukBMEHvmRoZQV7Hgh8ZG4iscyE=@n56a.cn.rongnav.com;n56a.cn.rongcfg.com').then((user) => {
+  console.log('connect success', user.data?.userId);
+  rtcClient = RongIMLib.installPlugin(installer, { /*初始化参数请参考下方参数说明*/ })
+})
+.catch((error) => {
+  console.log(`连接失败: ${error}`);
+});
+
+
+const videoRef = ref<HTMLVideoElement | null>(null)
+
+type VideoStatus = 'init' | 'stream' | 'liveing' | 'stopped' | 'error' | 'loading'
+
+export default defineComponent({
+  name: 'LiveBroadcast',
+  data () {
+    return {
+      mediaStreamTrack: [] as MediaStreamTrack[],
+      mediaStreams: null as MediaStream | null,
+      videoStatus: 'init' as VideoStatus,
+      screenShareStatus: false,
+    }
+  },
+  async mounted() {
+    try {
+      const mediaStreams = await requireMedia({
+        audio: true,
+        video: true
+      })
+      this.videoStatus = 'stream'
+      this.mediaStreams = mediaStreams
+      this.mediaStreamTrack = mediaStreams.getTracks()
+      this.setVideoSrcObject(mediaStreams)
+    } catch (error) {
+      this.videoStatus = 'error'
+      console.log(error)
+    }
+  },
+  methods: {
+    setVideoSrcObject (mediaStreams: MediaStream | null) {
+      const video = videoRef.value
+      if (video && mediaStreams) {
+        video.srcObject = mediaStreams
+        video.onloadedmetadata = () => {
+          video.play()
+        }
+      }
+    },
+    closeLive() {
+      removeMedia(this.mediaStreams, this.mediaStreamTrack)
+      this.videoStatus = 'stopped'
+    },
+    async screenVideo() {
+      if (rtcClient) {
+        const { code, track: screenTrack } = await rtcClient.createScreenVideoTrack()
+        if (code !== RCRTCCode.SUCCESS) {
+          this.screenShareStatus = false
+        } else {
+          this.screenShareStatus = true
+          this.setVideoSrcObject(screenTrack?._msStream as MediaStream)
+        }
+        screenTrack?.on(RCLocalTrack.EVENT_LOCAL_TRACK_END, (track: RCLocalTrack) => {
+          console.log('screen track end', track)
+          this.screenShareStatus = false
+          this.setVideoSrcObject(this.mediaStreams)
+        })
+      }
+    }
+  },
+  render() {
+    return (
+      <div>
+        <video ref={videoRef}></video>
+        <button onClick={this.closeLive}>关闭直播</button>
+        <button onClick={this.screenVideo}>屏幕共享</button>
+        <div>video: {this.videoStatus}, imStatus: {runtime.imConnectStatus}</div>
+      </div>
+    )
+  }
+})

+ 9 - 0
src/components/live-broadcast/runtime.ts

@@ -0,0 +1,9 @@
+import { reactive } from 'vue'
+
+type imConnectStatus = 'connecting' | 'connected' | 'disconnect'
+
+const LiveRuntime = reactive({
+  imConnectStatus: 'connecting' as imConnectStatus,
+})
+
+export default LiveRuntime

Some files were not shown because too many files changed in this diff