Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ugrwh/collab-space-frontend
1 result
Show changes
Commits on Source (2)
<template>
<div class="points-display">
<div v-if="loading">Loading points...</div>
<div v-else class="points-value">{{ points }}</div>
</div>
<form onsubmit="return false">
<input type="text" id="sessionInput">
<input type="submit" value="Submit" onclick="updatePage()">
</form>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useApi } from '@/composables/api';
const props = defineProps<{
userId?: number;
sessionId?: number;
}>();
const api = useApi();
const points = ref<number>(0);
const loading = ref<boolean>(true);
onMounted(async () => {
try {
if (props.userId) {
const response = await api.getPointsByUser(props.userId);
points.value = response.points;
} else if (props.sessionId) {
const response = await api.getPointsBySession(props.sessionId);
points.value = response.points;
}
} catch (error) {
console.error('Failed to fetch points:', error);
} finally {
loading.value = false;
}
});
async function updatePage() {
const sessionInput = document.getElementById('sessionInput') as HTMLInputElement;
const sessionId = parseInt(sessionInput.value);
try {
const response = await api.getPointsBySession(sessionId);
points.value = response.points;
} catch (error) {
console.error('Failed to fetch points:', error);
} finally {
loading.value = false;
}
}
</script>
\ No newline at end of file
......@@ -138,6 +138,12 @@ export type UpdateUser = {
export type UpdateCategory = CreateCategory;
export type UpdateRoom = CreateRoom;
export type Points = {
points: number;
userId: number;
sessionId?: number;
};
/**
* An object containing async functions to interact with the server API.
*/
......@@ -331,6 +337,14 @@ const api = {
async updatePassword(data: ChangePassword): Promise<boolean> {
return fetch.postOrFail('/user/changePassword', data);
},
async getPointsByUser(userId: number): Promise<Points> {
return fetch.getOrFail(`/sessionPoints/user/${userId}`);
},
async getPointsBySession(sessionId: number): Promise<Points> {
return fetch.getOrFail(`/sessionPoints/session/${sessionId}`);
},
};
/**
......
import Peer from 'peerjs';
import { reactive } from 'vue';
import { reactive, ref } from 'vue';
import { Socket } from 'socket.io-client';
import { ChannelUser, Student } from '@/composables/channel/channel';
export const useWebcam = () => {
let webcamsLoaded = false;
const streams: Record<string, MediaStream> = reactive({});
const volume = ref(0);
let user: ChannelUser | null = null;
let socket: Socket | null = null;
......@@ -34,6 +35,7 @@ export const useWebcam = () => {
video: true,
audio: true,
});
measureVolume(stream);
if (!user?.video) {
stream.getVideoTracks().forEach((track) => (track.enabled = false));
......@@ -151,6 +153,37 @@ export const useWebcam = () => {
webcamsLoaded = false;
}
function measureVolume(stream: MediaStream) {
const audioCtx = new AudioContext();
const source = audioCtx.createMediaStreamSource(stream);
const analyser = audioCtx.createAnalyser();
source.connect(analyser);
const dataArray = new Uint8Array(analyser.fftSize);
let isTalking = false;
function updateVolume() {
analyser.getByteTimeDomainData(dataArray);
let sum = 0;
for (let i = 0; i < dataArray.length; i++) {
sum += (dataArray[i] - 128) ** 2;
}
volume.value = Math.sqrt(sum / dataArray.length);
if (volume.value > 10 && !isTalking) {
isTalking = true;
socket?.emit('start-talking',{volume: volume.value});
} else if (volume.value <= 10 && isTalking) {
isTalking = false;
socket?.emit('stop-talking',{volume: volume.value});
}
}
updateVolume();
setInterval(updateVolume, 100);
}
function getVolume(): number {
return volume.value;
}
return {
streams,
init,
......@@ -160,5 +193,6 @@ export const useWebcam = () => {
toggleAudio,
disableAudioFor,
stop,
getVolume,
};
};
......@@ -79,6 +79,16 @@ const router = createRouter({
component: () => import('../views/PreRoomView.vue'),
beforeEnter: roomGuard,
},
/**
* Analysis Route
*/
{
path: '/analysis',
name: 'analysis',
component: () => import('../views/AnalysisView.vue'),
beforeEnter: authGuard,
},
],
});
......
<template>
<Layout title="Analysis">
<Points />
</Layout>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useApi } from '@/composables/api';
import Points from '@/components/Points.vue';
</script>
\ No newline at end of file
......@@ -232,6 +232,7 @@
</div>
</div>
</template>
<p class="text-white">(volume: {{ channel.webcam.getVolume().toFixed(2) }})</p>
</div>
<span class="flex-grow-1"></span>
......