Spaces:
Build error
Build error
video switcher
Browse files
frontend/src/lib/components/MediaListSwitcher.svelte
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { mediaDevices, mediaStreamActions } from '$lib/mediaStream';
|
| 3 |
+
import { onMount } from 'svelte';
|
| 4 |
+
|
| 5 |
+
let deviceId: string = '';
|
| 6 |
+
$: {
|
| 7 |
+
console.log($mediaDevices);
|
| 8 |
+
}
|
| 9 |
+
$: {
|
| 10 |
+
console.log(deviceId);
|
| 11 |
+
}
|
| 12 |
+
onMount(() => {
|
| 13 |
+
deviceId = $mediaDevices[0].deviceId;
|
| 14 |
+
});
|
| 15 |
+
</script>
|
| 16 |
+
|
| 17 |
+
<div class="text-xs">
|
| 18 |
+
{#if $mediaDevices}
|
| 19 |
+
<select
|
| 20 |
+
bind:value={deviceId}
|
| 21 |
+
on:change={() => mediaStreamActions.switchCamera(deviceId)}
|
| 22 |
+
id="devices-list"
|
| 23 |
+
class="border-1 cursor-pointer rounded-md border-gray-500 border-opacity-50 bg-slate-100 bg-opacity-30 p-1 font-medium text-white"
|
| 24 |
+
>
|
| 25 |
+
{#each $mediaDevices as device, i}
|
| 26 |
+
<option value={device.deviceId}>{device.label}</option>
|
| 27 |
+
{/each}
|
| 28 |
+
</select>
|
| 29 |
+
{/if}
|
| 30 |
+
</div>
|
frontend/src/lib/components/VideoInput.svelte
CHANGED
|
@@ -5,14 +5,19 @@
|
|
| 5 |
mediaStreamStatus,
|
| 6 |
MediaStreamStatusEnum,
|
| 7 |
onFrameChangeStore,
|
| 8 |
-
mediaStream
|
|
|
|
| 9 |
} from '$lib/mediaStream';
|
|
|
|
| 10 |
|
| 11 |
let videoEl: HTMLVideoElement;
|
| 12 |
let videoFrameCallbackId: number;
|
| 13 |
const WIDTH = 512;
|
| 14 |
const HEIGHT = 512;
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
| 16 |
onDestroy(() => {
|
| 17 |
if (videoFrameCallbackId) videoEl.cancelVideoFrameCallback(videoFrameCallbackId);
|
| 18 |
});
|
|
@@ -20,7 +25,6 @@
|
|
| 20 |
$: if (videoEl) {
|
| 21 |
videoEl.srcObject = $mediaStream;
|
| 22 |
}
|
| 23 |
-
|
| 24 |
async function onFrameChange(now: DOMHighResTimeStamp, metadata: VideoFrameCallbackMetadata) {
|
| 25 |
const blob = await grapBlobImg();
|
| 26 |
onFrameChangeStore.set({ blob });
|
|
@@ -55,8 +59,13 @@
|
|
| 55 |
|
| 56 |
<div class="relative mx-auto max-w-lg overflow-hidden rounded-lg border border-slate-300">
|
| 57 |
<div class="relative z-10 aspect-square w-full object-cover">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
<video
|
| 59 |
-
class="aspect-square w-full object-cover"
|
| 60 |
bind:this={videoEl}
|
| 61 |
playsinline
|
| 62 |
autoplay
|
|
|
|
| 5 |
mediaStreamStatus,
|
| 6 |
MediaStreamStatusEnum,
|
| 7 |
onFrameChangeStore,
|
| 8 |
+
mediaStream,
|
| 9 |
+
mediaDevices
|
| 10 |
} from '$lib/mediaStream';
|
| 11 |
+
import MediaListSwitcher from './MediaListSwitcher.svelte';
|
| 12 |
|
| 13 |
let videoEl: HTMLVideoElement;
|
| 14 |
let videoFrameCallbackId: number;
|
| 15 |
const WIDTH = 512;
|
| 16 |
const HEIGHT = 512;
|
| 17 |
+
let selectedDevice: string = '';
|
| 18 |
+
$: {
|
| 19 |
+
console.log(selectedDevice);
|
| 20 |
+
}
|
| 21 |
onDestroy(() => {
|
| 22 |
if (videoFrameCallbackId) videoEl.cancelVideoFrameCallback(videoFrameCallbackId);
|
| 23 |
});
|
|
|
|
| 25 |
$: if (videoEl) {
|
| 26 |
videoEl.srcObject = $mediaStream;
|
| 27 |
}
|
|
|
|
| 28 |
async function onFrameChange(now: DOMHighResTimeStamp, metadata: VideoFrameCallbackMetadata) {
|
| 29 |
const blob = await grapBlobImg();
|
| 30 |
onFrameChangeStore.set({ blob });
|
|
|
|
| 59 |
|
| 60 |
<div class="relative mx-auto max-w-lg overflow-hidden rounded-lg border border-slate-300">
|
| 61 |
<div class="relative z-10 aspect-square w-full object-cover">
|
| 62 |
+
{#if $mediaDevices.length > 0}
|
| 63 |
+
<div class="absolute bottom-0 right-0">
|
| 64 |
+
<MediaListSwitcher />
|
| 65 |
+
</div>
|
| 66 |
+
{/if}
|
| 67 |
<video
|
| 68 |
+
class="pointer-events-none aspect-square w-full object-cover"
|
| 69 |
bind:this={videoEl}
|
| 70 |
playsinline
|
| 71 |
autoplay
|
frontend/src/lib/mediaStream.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import { writable, type Writable } from 'svelte/store';
|
| 2 |
|
| 3 |
export enum MediaStreamStatusEnum {
|
| 4 |
INIT = "init",
|
|
@@ -44,6 +44,9 @@ export const mediaStreamActions = {
|
|
| 44 |
});
|
| 45 |
},
|
| 46 |
async switchCamera(mediaDevicedID: string) {
|
|
|
|
|
|
|
|
|
|
| 47 |
const constraints = {
|
| 48 |
audio: false,
|
| 49 |
video: { width: 1024, height: 1024, deviceId: mediaDevicedID }
|
|
|
|
| 1 |
+
import { writable, type Writable, get } from 'svelte/store';
|
| 2 |
|
| 3 |
export enum MediaStreamStatusEnum {
|
| 4 |
INIT = "init",
|
|
|
|
| 44 |
});
|
| 45 |
},
|
| 46 |
async switchCamera(mediaDevicedID: string) {
|
| 47 |
+
if (get(mediaStreamStatus) !== MediaStreamStatusEnum.CONNECTED) {
|
| 48 |
+
return;
|
| 49 |
+
}
|
| 50 |
const constraints = {
|
| 51 |
audio: false,
|
| 52 |
video: { width: 1024, height: 1024, deviceId: mediaDevicedID }
|