|
@@ -0,0 +1,328 @@
|
|
|
+<template>
|
|
|
+ <div class="trtccom" v-if="show">
|
|
|
+ <Device @switchDevice="switchDevice" v-if="show" />
|
|
|
+ <div class="local" id="local" v-if="isJoined">
|
|
|
+ <div class="tag">
|
|
|
+ <div :class="audioMuted ? 'muteAudio' : 'unmuteAudio'" @click="muteAudio"></div>
|
|
|
+ <div :class="videoMuted ? 'muteVideo' : 'unmuteVideo'" @click="muteVideo"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import TRTC, { Client, LocalStream } from "trtc-js-sdk";
|
|
|
+import { Dialog } from "@/global_components/";
|
|
|
+import { ref, computed, watch } from "vue";
|
|
|
+import Device from "./trtc/Device";
|
|
|
+import { useStore } from "vuex";
|
|
|
+const store = useStore();
|
|
|
+
|
|
|
+const show = ref(false);
|
|
|
+const isJoined = computed(() => store.getters["rtc/isJoined"]);
|
|
|
+const isPublished = computed(() => store.getters["rtc/isPublished"]);
|
|
|
+
|
|
|
+let localClient = "";
|
|
|
+let localStream = "";
|
|
|
+let shareClient = "";
|
|
|
+const audioMuted = ref(false);
|
|
|
+const videoMuted = ref(false);
|
|
|
+
|
|
|
+TRTC.checkSystemRequirements().then((checkResult) => {
|
|
|
+ console.log(checkResult.result, "checkResult.result");
|
|
|
+ if (!checkResult.result) {
|
|
|
+ Dialog.toast({ content: `您的設備不支持音視頻通訊`, type: "error" });
|
|
|
+ } else {
|
|
|
+ show.value = true;
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+async function createLocalStream() {
|
|
|
+ try {
|
|
|
+ localStream = TRTC.createStream({
|
|
|
+ userId: store.getters["rtc/userId"],
|
|
|
+ audio: true,
|
|
|
+ video: true,
|
|
|
+ cameraId: store.getters["rtc/videoDeviceId"],
|
|
|
+ microphoneId: store.getters["rtc/audioDeviceId"],
|
|
|
+ });
|
|
|
+ localStream.setVideoProfile("480p");
|
|
|
+
|
|
|
+ await localStream.initialize();
|
|
|
+
|
|
|
+ localStream
|
|
|
+ .play("local")
|
|
|
+ .then(() => {
|
|
|
+ // addLocalControlView();
|
|
|
+ })
|
|
|
+ .catch((e) => {});
|
|
|
+ } catch (error) {}
|
|
|
+}
|
|
|
+
|
|
|
+async function handleJoin() {
|
|
|
+ if (!store.commit("rtc/getInitParamsStates")) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const userSig = store.commit("rtc/getUserSig");
|
|
|
+
|
|
|
+ try {
|
|
|
+ localClient = TRTC.createClient({
|
|
|
+ mode: "rtc",
|
|
|
+ sdkAppId: parseInt(store.getters["rtc/sdkAppId"], 10),
|
|
|
+ userId: store.getters["rtc/userId"],
|
|
|
+ userSig,
|
|
|
+ });
|
|
|
+ installEventHandlers();
|
|
|
+ await localClient.join({ roomId: parseInt(store.getters["rtc/roomId"], 10) });
|
|
|
+ store.commit("rtc/setIsJoined", true);
|
|
|
+ inviteLink.value = store.commit("rtc/createShareLink");
|
|
|
+ } catch (error) {}
|
|
|
+
|
|
|
+ await createLocalStream();
|
|
|
+ await handlePublish();
|
|
|
+}
|
|
|
+
|
|
|
+async function handlePublish() {
|
|
|
+ if (!isJoined.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (isPublished.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await localClient.publish(localStream);
|
|
|
+ store.commit("rtc/setIsPublished", true);
|
|
|
+ } catch (error) {}
|
|
|
+}
|
|
|
+
|
|
|
+async function handleUnpublish() {
|
|
|
+ if (!isJoined.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!isPublished.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await localClient.unpublish(localStream);
|
|
|
+ store.commit("rtc/setIsPublished", false);
|
|
|
+ } catch (error) {}
|
|
|
+}
|
|
|
+
|
|
|
+async function handleLeave() {
|
|
|
+ if (!isJoined.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (isPublished.value) {
|
|
|
+ await handleUnpublish();
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ uninstallEventHandlers();
|
|
|
+ await localClient.leave();
|
|
|
+ store.commit("rtc/setIsJoined", false);
|
|
|
+ if (localStream) {
|
|
|
+ localStream.stop();
|
|
|
+ localStream.close();
|
|
|
+ localStream = null;
|
|
|
+ }
|
|
|
+ } catch (error) {}
|
|
|
+}
|
|
|
+
|
|
|
+function installEventHandlers() {
|
|
|
+ if (!localClient) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ localClient.on("error", handleError);
|
|
|
+ localClient.on("client-banned", handleBanned);
|
|
|
+ localClient.on("peer-join", handlePeerJoin);
|
|
|
+ localClient.on("peer-leave", handlePeerLeave);
|
|
|
+ localClient.on("stream-added", handleStreamAdded);
|
|
|
+ localClient.on("stream-subscribed", handleStreamSubscribed);
|
|
|
+ localClient.on("stream-removed", handleStreamRemoved);
|
|
|
+ localClient.on("stream-updated", handleStreamUpdated);
|
|
|
+ localClient.on("mute-video", handleMuteVideo);
|
|
|
+ localClient.on("mute-audio", handleMuteAudio);
|
|
|
+ localClient.on("unmute-video", handleUnmuteVideo);
|
|
|
+ localClient.on("unmute-audio", handleUnmuteAudio);
|
|
|
+}
|
|
|
+
|
|
|
+function uninstallEventHandlers() {
|
|
|
+ if (!localClient) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ localClient.off("error", handleError);
|
|
|
+ localClient.off("error", handleError);
|
|
|
+ localClient.off("client-banned", handleBanned);
|
|
|
+ localClient.off("peer-join", handlePeerJoin);
|
|
|
+ localClient.off("peer-leave", handlePeerLeave);
|
|
|
+ localClient.off("stream-added", handleStreamAdded);
|
|
|
+ localClient.off("stream-subscribed", handleStreamSubscribed);
|
|
|
+ localClient.off("stream-removed", handleStreamRemoved);
|
|
|
+ localClient.off("stream-updated", handleStreamUpdated);
|
|
|
+ localClient.off("mute-video", handleMuteVideo);
|
|
|
+ localClient.off("mute-audio", handleMuteAudio);
|
|
|
+ localClient.off("unmute-video", handleUnmuteVideo);
|
|
|
+ localClient.off("unmute-audio", handleUnmuteAudio);
|
|
|
+}
|
|
|
+
|
|
|
+function handleMuteVideo(event) {
|
|
|
+ console.log(`[${event.userId}] mute video`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleMuteAudio(event) {
|
|
|
+ console.log(`[${event.userId}] mute audio`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleUnmuteVideo(event) {
|
|
|
+ console.log(`[${event.userId}] unmute video`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleUnmuteAudio(event) {
|
|
|
+ console.log(`[${event.userId}] unmute audio`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleError(error) {
|
|
|
+ console.log(`LocalClient error: ${error.message_}`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleBanned(error) {
|
|
|
+ console.log(`Client has been banned for ${error.message_}`);
|
|
|
+}
|
|
|
+
|
|
|
+function handlePeerJoin(event) {
|
|
|
+ const { userId } = event;
|
|
|
+ if (userId !== "local-screen") {
|
|
|
+ console.log(`Peer Client [${userId}] joined`);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handlePeerLeave(event) {
|
|
|
+ const { userId } = event;
|
|
|
+ if (userId !== "local-screen") {
|
|
|
+ console.log(`[${userId}] leave`);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleStreamAdded(event) {
|
|
|
+ const remoteStream = event.stream;
|
|
|
+ const id = remoteStream.getId();
|
|
|
+ const userId = remoteStream.getUserId();
|
|
|
+
|
|
|
+ if (remoteStream.getUserId() === `share_${store.userId}`) {
|
|
|
+ // don't need to screen shared by us
|
|
|
+ localClient.unsubscribe(remoteStream).catch((error) => {
|
|
|
+ console.error(`unsubscribe failed: ${error.message_}`);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log(`remote stream added: [${userId}] ID: ${id} type: ${remoteStream.getType()}`);
|
|
|
+ localClient.subscribe(remoteStream).catch((error) => {
|
|
|
+ console.error(`subscribe failed: ${error.message_}`);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleStreamSubscribed(event) {
|
|
|
+ const remoteStream = event.stream;
|
|
|
+ const userId = remoteStream.getUserId();
|
|
|
+ console.log(`RemoteStream subscribed: [${userId}]`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleStreamRemoved(event) {
|
|
|
+ const remoteStream = event.stream;
|
|
|
+ const userId = remoteStream.getUserId();
|
|
|
+ console.log(`RemoteStream removed: [${userId}]`);
|
|
|
+}
|
|
|
+
|
|
|
+function handleStreamUpdated(event) {
|
|
|
+ const remoteStream = event.stream;
|
|
|
+ const userId = remoteStream.getUserId();
|
|
|
+ console.log(`RemoteStream updated: [${userId}] audio:${remoteStream.hasAudio()} video:${remoteStream.hasVideo()}`);
|
|
|
+}
|
|
|
+
|
|
|
+const muteAudio = () => {
|
|
|
+ if (!audioMuted.value) {
|
|
|
+ localStream.muteAudio();
|
|
|
+ audioMuted.value = true;
|
|
|
+ } else {
|
|
|
+ localStream.unmuteAudio();
|
|
|
+ audioMuted.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const muteVideo = () => {
|
|
|
+ if (!videoMuted.value) {
|
|
|
+ localStream.muteVideo();
|
|
|
+ videoMuted.value = true;
|
|
|
+ } else {
|
|
|
+ localStream.unmuteVideo();
|
|
|
+ videoMuted.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+let switchDevice = async ({ videoId, audioId }) => {
|
|
|
+ if (!isJoined.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (videoId) {
|
|
|
+ try {
|
|
|
+ await localStream.switchDevice("video", videoId);
|
|
|
+ } catch (error) {}
|
|
|
+ }
|
|
|
+ if (audioId) {
|
|
|
+ try {
|
|
|
+ await localStream.switchDevice("audio", audioId);
|
|
|
+ } catch (error) {}
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+watch(show, () => {
|
|
|
+ if (show.value) {
|
|
|
+ handleJoin();
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.trtccom {
|
|
|
+ .local {
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ position: fixed;
|
|
|
+ z-index: 9999;
|
|
|
+ left: 10px;
|
|
|
+ top: 10px;
|
|
|
+ .muteAudio {
|
|
|
+ background: url(~@/assets/images/icon/mic-mute.svg) center center no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ .unmuteAudio {
|
|
|
+ background: url(~@/assets/images/icon/mic.svg) center center no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ .muteVideo {
|
|
|
+ background: url(~@/assets/images/icon/camera-mute.svg) center center no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ .unmuteVideo {
|
|
|
+ background: url(~@/assets/images/icon/camera.svg) center center no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tag {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 25px;
|
|
|
+ z-index: 999;
|
|
|
+ background: rgba(0, 0, 0, 0.3);
|
|
|
+ display: flex;
|
|
|
+ padding: 0 4px;
|
|
|
+ flex-direction: row-reverse;
|
|
|
+ > div {
|
|
|
+ height: 25px;
|
|
|
+ width: 25px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|