diff --git a/docs/community-packages/device-emulator/_category_.json b/docs/community-packages/device-emulator/_category_.json new file mode 100644 index 0000000000..b92ddf5e09 --- /dev/null +++ b/docs/community-packages/device-emulator/_category_.json @@ -0,0 +1,5 @@ +{ + "position": 1, + "label": "Device Emulator", + "collapsible": false +} diff --git a/docs/community-packages/device-emulator/intro.mdx b/docs/community-packages/device-emulator/intro.mdx new file mode 100644 index 0000000000..7d1160fa45 --- /dev/null +++ b/docs/community-packages/device-emulator/intro.mdx @@ -0,0 +1,161 @@ +--- +slug: /device-emulator +sidebar_position: 1 +keywords: [opensource] +--- + +# Introduction + +For a product, integration tests are one of the crucial part that improves quality & stability. For a WebRTC based solution like Dyte, having integration tests that can test multi-user call with Audio/Video on is necessary. + +For an end user, sharing a camera & mic is easy. For this, browsers expose APIs such as enumerateDevices & getUserMedia on MediaDevices interface, on which user interfaces can be built easily. + +Access to camera & mic prompts the users to allow permissions to do so. This works great as long as an end-user is using the product and actively allowing permissions and selecting devices, However this makes it impossible to write integration tests because for integration tests there is no active user and you need to somehow allow permissions programmatically which at the moment of writing this README is not reliably supported in modern tools like Playwright. + +Even if we can somehow allow permissions, The next set of questions would be: What would the video & audio feed look like? Can we customize the feed? Can we use the feed to detect delays between a video feed producer and consumer? How do we test multiple devices? How do we test media ejection on the fly? How do we test addition of a new device? + +Dyte's Device Emulator is a solution that answers all these questions and provides a easier way to mimic, add, remove devices & their feed. + +## Installation + + + + +To set up device-emulator add the following script tags inside +the `` tag. + +```html + + +``` + + + + +```bash +npm install @dytesdk/device-emulator +``` + +use the package like below + +```js +import '@dytesdk/device-emulator'; + +// use the device emulator methods +``` + + + + + +```bash +yarn add @dytesdk/device-emulator +``` + +use the package like below + +```js +import '@dytesdk/device-emulator'; + +// use the device emulator methods +``` + + + + +## API reference + +### Add a virtual device + +```js {1} +const virtualDeviceID = navigator.mediaDevices.addEmulatedDevice('videoinput'); + +// get a media track from the virtual device +navigator.mediaDevices + .getUserMedia({ + video: { + deviceId: { + exact: virtualDeviceID, + }, + }, + }) + .then((mediaStream) => { + const video = document.querySelector('video'); + video.srcObject = mediaStream; + video.onloadedmetadata = () => { + video.play(); + }; + }) + .catch((err) => { + // always check for errors at the end. + console.error(`${err.name}: ${err.message}`); + }); +``` + +### Remove virtual device + +```js +navigator.mediaDevices.removeEmulatedDevice(deviceId); +``` + +### Stop the device + +You can use `brickDevice` method to test scenarios where the devices stops working abruptly. + +```js {4} +const virtualDeviceID = navigator.mediaDevices.addEmulatedDevice('videoinput'); + +// Stop the device from working +navigator.mediaDevices.brickDevice(virtualDeviceID, true); + +navigator.mediaDevices + .getUserMedia({ + video: { + deviceId: { + exact: virtualDeviceID, + }, + }, + }) + .then((mediaStream) => { + // This will not work + const video = document.querySelector('video'); + video.srcObject = mediaStream; + video.onloadedmetadata = () => { + video.play(); + }; + }) + .catch((err) => { + // catch `NotReadableError` thrown from the device + console.error(`${err.name}: ${err.message}`); + }); +``` + +Executing the `brickDevice` after getting the tracks will stop the active tracks. + +### Resume the device + +Use `brickDevice` method to make the device work normally + +```js +navigator.mediaDevices.unbrickDevice(deviceId, false); +``` + +### Silence the tracks + +Generate tracks that are silent + +```js +navigator.mediaDevices.silenceDevice(deviceId, true); +``` + +### Unmute the tracks from the device + +Remove the silence check on the device + +```js +navigator.mediaDevices.silenceDevice(deviceId, false); +``` diff --git a/docs/community-packages/index.mdx b/docs/community-packages/index.mdx new file mode 100644 index 0000000000..498d384212 --- /dev/null +++ b/docs/community-packages/index.mdx @@ -0,0 +1,30 @@ +--- +slug: / +sidebar_position: 1 +sidebar_class_name: community_packages_sidebar_index +--- + +# Community packages + +At Dyte, we believe in empowering developers to create innovative solutions that go beyond our own use cases. By opening access to some of our resources, we aim to foster creativity, collaboration, and technological advancement across diverse domains. + +We are excited to see the new applications and platforms that you will build using our technology. + + + + Opensource + + + diff --git a/docusaurus.config.js b/docusaurus.config.js index 4cca7fe2f0..b29a03cf21 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -34,6 +34,13 @@ const docs = [ }, }, + // Community packages + { + id: 'community-packages', + path: 'docs/community-packages', + routeBasePath: '/community-packages', + }, + // Web UI Kits { id: 'ui-kit', diff --git a/src/components/CardComponents.tsx b/src/components/CardComponents.tsx index a60311ef81..eab3b8daa3 100644 --- a/src/components/CardComponents.tsx +++ b/src/components/CardComponents.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode, PropsWithChildren } from 'react'; import { paramCase } from 'param-case'; import Link from '@docusaurus/Link'; import clsx from 'clsx'; @@ -17,7 +17,7 @@ export function CardSection({ children: ReactNode; description?: ReactNode; hasSubSections?: boolean; - HeadingTag?: any; + HeadingTag?: keyof JSX.IntrinsicElements; className?: string; }) { return ( @@ -41,13 +41,19 @@ export function Card({ title, description, to, -}: { + tag, +}: PropsWithChildren<{ id?: string; icon?: JSX.Element; title: string; description?: string; to: string; -}) { + tag?: { + label: string; + color: string; + description: string; + }; +}>) { return ( {icon &&
{icon}
} @@ -57,6 +63,17 @@ export function Card({ {description &&
{description}
} + {tag && ( +
+ + {tag.label} + +
+ )} ); } diff --git a/src/css/custom.css b/src/css/custom.css index 41c60c8c7e..c313495564 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -917,6 +917,8 @@ img[src$='#terminal'] { transition-property: background-color, color; border-radius: 8px; + position: relative; + overflow: hidden; } .homepage-card.row { @@ -932,8 +934,6 @@ img[src$='#terminal'] { width: 48px; height: 48px; @apply mx-1; - /* background-color: #262626; - border-radius: 8px; */ } .card-content { @@ -954,6 +954,14 @@ img[src$='#terminal'] { line-height: 1.5; } +.homepage-card .tag { + font-size: 12px; + padding: 0.25rem 0.5rem; + border-radius: 4px; + font-weight: 500; + position: absolute; +} + details { font-size: 14px; font-weight: 500; @@ -1134,6 +1142,10 @@ article ul { @apply -ml-2; } +.community_packages_sidebar_index { + @apply -ml-2; +} + .video_sidebar_header > div > a::before { @apply mt-1 mr-2; content: url('data:image/svg+xml,'); diff --git a/src/snippets/resources.html b/src/snippets/resources.html index 845ab116c8..bede1efafa 100644 --- a/src/snippets/resources.html +++ b/src/snippets/resources.html @@ -18,16 +18,6 @@ Developer Portal -
  • - - - - -