|
@@ -35,11 +35,19 @@
|
|
|
</div>
|
|
|
<h4 class="student-name">{{ item.examStudentName }}</h4>
|
|
|
<div v-if="callStatus === 'START'">
|
|
|
- <el-button round type="success" @click="answer(item, 0)"
|
|
|
+ <el-button
|
|
|
+ round
|
|
|
+ type="success"
|
|
|
+ @click="answer(item, 0)"
|
|
|
+ :loading="holding"
|
|
|
>语音通话</el-button
|
|
|
>
|
|
|
<br />
|
|
|
- <el-button round type="primary" @click="answer(item, 1)"
|
|
|
+ <el-button
|
|
|
+ round
|
|
|
+ type="primary"
|
|
|
+ @click="answer(item, 1)"
|
|
|
+ :loading="holding"
|
|
|
>视频通话</el-button
|
|
|
>
|
|
|
</div>
|
|
@@ -117,6 +125,7 @@ export default {
|
|
|
examId: this.$route.params.examId,
|
|
|
callStatus: "START",
|
|
|
dialogVisible: false,
|
|
|
+ holding: false,
|
|
|
students: [],
|
|
|
curStudent: {},
|
|
|
current: 1,
|
|
@@ -171,6 +180,12 @@ export default {
|
|
|
this.current = page;
|
|
|
this.getCommunicationList();
|
|
|
},
|
|
|
+ notifyError(content) {
|
|
|
+ this.$notify({
|
|
|
+ type: "error",
|
|
|
+ message: content,
|
|
|
+ });
|
|
|
+ },
|
|
|
async initClient(examRecordId) {
|
|
|
const res = await getUserMonitorKey(examRecordId);
|
|
|
this.userMonitor = res.data.data;
|
|
@@ -181,33 +196,68 @@ export default {
|
|
|
userSig: this.userMonitor.monitorUserSig,
|
|
|
});
|
|
|
},
|
|
|
+ async getLocalMedia(isVideo) {
|
|
|
+ const localStream = createStream({
|
|
|
+ userId: this.userMonitor.monitorUserId,
|
|
|
+ audio: true,
|
|
|
+ video: isVideo,
|
|
|
+ });
|
|
|
+ const errorTips = {
|
|
|
+ NotFoundError: "找不到硬件设备,请确保硬件设备已经正常插入。",
|
|
|
+ NotAllowedError: "不授权摄像头/麦克风访问无法进行音视频通话。",
|
|
|
+ NotReadableError:
|
|
|
+ "暂时无法访问摄像头/麦克风,请确保当前没有其他应用请求访问摄像头/麦克风,并重试。",
|
|
|
+ OverConstrainedError: "设备异常",
|
|
|
+ AbortError: "设备异常",
|
|
|
+ };
|
|
|
+
|
|
|
+ let initLocalStreamResult = true;
|
|
|
+ await localStream.initialize().catch((error) => {
|
|
|
+ console.log(errorTips[error.name]);
|
|
|
+ this.notifyError(errorTips[error.name]);
|
|
|
+ initLocalStreamResult = false;
|
|
|
+ localStream.close();
|
|
|
+ });
|
|
|
+ return initLocalStreamResult && localStream;
|
|
|
+ },
|
|
|
async answer(student, isVideo) {
|
|
|
+ if (this.holding) return;
|
|
|
+ this.holding = true;
|
|
|
+
|
|
|
this.curStudent = student;
|
|
|
- await this.initClient(student.examRecordId);
|
|
|
- // 更改学生的通话申请状态
|
|
|
- await communicationCalling({
|
|
|
- recordId: student.examRecordId,
|
|
|
- source: student.source,
|
|
|
- });
|
|
|
+ await this.initClient(student.examRecordId).catch(() => {});
|
|
|
+ if (!this.client) {
|
|
|
+ this.holding = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.localStream = await this.getLocalMedia(isVideo);
|
|
|
+ if (!this.localStream) {
|
|
|
+ this.holding = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
this.dialogVisible = true;
|
|
|
+ this.holding = false;
|
|
|
// 添加远程用户视频发布监听
|
|
|
this.client.on("stream-added", (event) => {
|
|
|
console.log(event);
|
|
|
- const remoteStream = event.stream;
|
|
|
+ if (event.stream.userId_ !== student.sourceUserId) return;
|
|
|
|
|
|
+ const remoteStream = event.stream;
|
|
|
this.client
|
|
|
.subscribe(remoteStream, { audio: true, video: true })
|
|
|
.then(() => {
|
|
|
- console.log("订阅视频成功!");
|
|
|
+ console.log("开始订阅视频成功!");
|
|
|
})
|
|
|
.catch((error) => {
|
|
|
console.log("订阅视频失败!", error);
|
|
|
+ this.notifyError("学生视频获取失败!");
|
|
|
});
|
|
|
});
|
|
|
this.client.on("stream-subscribed", (event) => {
|
|
|
+ console.log("视频已订阅!");
|
|
|
const remoteStream = event.stream;
|
|
|
- this.$refs.SecondTimer.start();
|
|
|
+ if (!this.$refs.SecondTimer.recoding) this.$refs.SecondTimer.start();
|
|
|
remoteStream.play("communication-host", { objectFit: "contain" });
|
|
|
});
|
|
|
|
|
@@ -222,6 +272,7 @@ export default {
|
|
|
.catch((error) => {
|
|
|
roomJoinResult = false;
|
|
|
console.log("加入房间失败!", error);
|
|
|
+ this.notifyError("接通通信失败!");
|
|
|
});
|
|
|
if (!roomJoinResult) return;
|
|
|
|
|
@@ -229,34 +280,28 @@ export default {
|
|
|
let switchResult = true;
|
|
|
await this.client.switchRole("anchor").catch((error) => {
|
|
|
console.log("切换角色失败!", error);
|
|
|
+ this.notifyError("接通通信失败!");
|
|
|
switchResult = false;
|
|
|
});
|
|
|
if (!switchResult) return;
|
|
|
|
|
|
- // 初始化stream
|
|
|
- this.localStream = createStream({
|
|
|
- userId: this.userMonitor.monitorUserId,
|
|
|
- audio: true,
|
|
|
- video: isVideo,
|
|
|
- });
|
|
|
-
|
|
|
- let initLocalStreamResult = true;
|
|
|
- await this.localStream.initialize().catch((error) => {
|
|
|
- console.log("初始化视频失败!", error);
|
|
|
- initLocalStreamResult = false;
|
|
|
- });
|
|
|
- if (!initLocalStreamResult) return;
|
|
|
-
|
|
|
// 发布本地视频
|
|
|
let publishStreamResult = true;
|
|
|
this.client.publish(this.localStream).catch((error) => {
|
|
|
console.log("发布本地视频失败!", error);
|
|
|
+ this.notifyError("本地音视频推送失败!");
|
|
|
publishStreamResult = false;
|
|
|
});
|
|
|
if (!publishStreamResult) return;
|
|
|
|
|
|
// 播放本地视频
|
|
|
this.localStream.play("communication-guest", { muted: true });
|
|
|
+
|
|
|
+ // 更改学生的通话申请状态
|
|
|
+ await communicationCalling({
|
|
|
+ recordId: student.examRecordId,
|
|
|
+ source: student.source,
|
|
|
+ });
|
|
|
},
|
|
|
async hangup() {
|
|
|
this.$refs.SecondTimer.end();
|
|
@@ -268,12 +313,9 @@ export default {
|
|
|
this.curStudent = {};
|
|
|
|
|
|
// 取消发布本地视频
|
|
|
- let unpublishStreamResult = true;
|
|
|
- this.client.unpublish(this.localStream).catch((error) => {
|
|
|
+ await this.client.unpublish(this.localStream).catch((error) => {
|
|
|
console.log("取消发布本地视频失败!", error);
|
|
|
- unpublishStreamResult = false;
|
|
|
});
|
|
|
- if (!unpublishStreamResult) return;
|
|
|
|
|
|
this.localStream.close();
|
|
|
this.localStream = null;
|
|
@@ -281,6 +323,7 @@ export default {
|
|
|
let result = true;
|
|
|
await this.client.leave().catch((error) => {
|
|
|
console.log("离开房间失败!", error);
|
|
|
+ this.notifyError("操作异常,请重新尝试!");
|
|
|
result = false;
|
|
|
});
|
|
|
if (!result) return;
|