Skip to content

Commit 6233ac4

Browse files
authored
Merge pull request dyte-io#359 from dyte-in/docs/oss
docs: community packages
2 parents 76cdb4c + 70dd367 commit 6233ac4

File tree

7 files changed

+244
-45
lines changed

7 files changed

+244
-45
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"position": 1,
3+
"label": "Device Emulator",
4+
"collapsible": false
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
slug: /device-emulator
3+
sidebar_position: 1
4+
keywords: [opensource]
5+
---
6+
7+
# Introduction
8+
9+
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.
10+
11+
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.
12+
13+
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.
14+
15+
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?
16+
17+
Dyte's Device Emulator is a solution that answers all these questions and provides a easier way to mimic, add, remove devices & their feed.
18+
19+
## Installation
20+
21+
<Tabs groupId="cdn-npm">
22+
<TabItem value="cdn" label="CDN" default>
23+
24+
To set up device-emulator add the following script tags inside
25+
the `<head />` tag.
26+
27+
```html
28+
<script>
29+
window.addEventListener('dyte.deviceEmulatorLoaded', () => {
30+
// use device emulator methods here...
31+
});
32+
</script>
33+
<script src="https://cdn.jsdelivr.net/npm/@dytesdk/device-emulator/dist/index.iife.js"></script>
34+
```
35+
36+
</TabItem>
37+
<TabItem value="npm" label="npm">
38+
39+
```bash
40+
npm install @dytesdk/device-emulator
41+
```
42+
43+
use the package like below
44+
45+
```js
46+
import '@dytesdk/device-emulator';
47+
48+
// use the device emulator methods
49+
```
50+
51+
</TabItem>
52+
53+
<TabItem value="yarn" label="yarn">
54+
55+
```bash
56+
yarn add @dytesdk/device-emulator
57+
```
58+
59+
use the package like below
60+
61+
```js
62+
import '@dytesdk/device-emulator';
63+
64+
// use the device emulator methods
65+
```
66+
67+
</TabItem>
68+
</Tabs>
69+
70+
## API reference
71+
72+
### Add a virtual device
73+
74+
```js {1}
75+
const virtualDeviceID = navigator.mediaDevices.addEmulatedDevice('videoinput');
76+
77+
// get a media track from the virtual device
78+
navigator.mediaDevices
79+
.getUserMedia({
80+
video: {
81+
deviceId: {
82+
exact: virtualDeviceID,
83+
},
84+
},
85+
})
86+
.then((mediaStream) => {
87+
const video = document.querySelector('video');
88+
video.srcObject = mediaStream;
89+
video.onloadedmetadata = () => {
90+
video.play();
91+
};
92+
})
93+
.catch((err) => {
94+
// always check for errors at the end.
95+
console.error(`${err.name}: ${err.message}`);
96+
});
97+
```
98+
99+
### Remove virtual device
100+
101+
```js
102+
navigator.mediaDevices.removeEmulatedDevice(deviceId);
103+
```
104+
105+
### Stop the device
106+
107+
You can use `brickDevice` method to test scenarios where the devices stops working abruptly.
108+
109+
```js {4}
110+
const virtualDeviceID = navigator.mediaDevices.addEmulatedDevice('videoinput');
111+
112+
// Stop the device from working
113+
navigator.mediaDevices.brickDevice(virtualDeviceID, true);
114+
115+
navigator.mediaDevices
116+
.getUserMedia({
117+
video: {
118+
deviceId: {
119+
exact: virtualDeviceID,
120+
},
121+
},
122+
})
123+
.then((mediaStream) => {
124+
// This will not work
125+
const video = document.querySelector('video');
126+
video.srcObject = mediaStream;
127+
video.onloadedmetadata = () => {
128+
video.play();
129+
};
130+
})
131+
.catch((err) => {
132+
// catch `NotReadableError` thrown from the device
133+
console.error(`${err.name}: ${err.message}`);
134+
});
135+
```
136+
137+
Executing the `brickDevice` after getting the tracks will stop the active tracks.
138+
139+
### Resume the device
140+
141+
Use `brickDevice` method to make the device work normally
142+
143+
```js
144+
navigator.mediaDevices.unbrickDevice(deviceId, false);
145+
```
146+
147+
### Silence the tracks
148+
149+
Generate tracks that are silent
150+
151+
```js
152+
navigator.mediaDevices.silenceDevice(deviceId, true);
153+
```
154+
155+
### Unmute the tracks from the device
156+
157+
Remove the silence check on the device
158+
159+
```js
160+
navigator.mediaDevices.silenceDevice(deviceId, false);
161+
```

docs/community-packages/index.mdx

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
slug: /
3+
sidebar_position: 1
4+
sidebar_class_name: community_packages_sidebar_index
5+
---
6+
7+
# Community packages
8+
9+
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.
10+
11+
We are excited to see the new applications and platforms that you will build using our technology.
12+
13+
<CardSection id="packages" title="Packages">
14+
<Card
15+
title="Device Emulator"
16+
to="/community-packages/device-emulator"
17+
description="Simulate media devices within your browser, by providing a seamless testing environment and enabling more efficient development and debugging."
18+
tag={{
19+
label: 'OSS',
20+
color: '#2160FD',
21+
description: 'Opensource Software',
22+
}}
23+
>
24+
<span class="community-tag">Opensource</span>
25+
</Card>
26+
<Card
27+
title="Troubleshooter (Coming soon)"
28+
description="Our diagnostic tool designed to analyze, identify, and resolve real-time communication issues, enhancing connection stability and performance."
29+
/>
30+
</CardSection>

docusaurus.config.js

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ const docs = [
3434
},
3535
},
3636

37+
// Community packages
38+
{
39+
id: 'community-packages',
40+
path: 'docs/community-packages',
41+
routeBasePath: '/community-packages',
42+
},
43+
3744
// Web UI Kits
3845
{
3946
id: 'ui-kit',

src/components/CardComponents.tsx

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactNode } from 'react';
1+
import React, { ReactNode, PropsWithChildren } from 'react';
22
import { paramCase } from 'param-case';
33
import Link from '@docusaurus/Link';
44
import clsx from 'clsx';
@@ -17,7 +17,7 @@ export function CardSection({
1717
children: ReactNode;
1818
description?: ReactNode;
1919
hasSubSections?: boolean;
20-
HeadingTag?: any;
20+
HeadingTag?: keyof JSX.IntrinsicElements;
2121
className?: string;
2222
}) {
2323
return (
@@ -41,13 +41,19 @@ export function Card({
4141
title,
4242
description,
4343
to,
44-
}: {
44+
tag,
45+
}: PropsWithChildren<{
4546
id?: string;
4647
icon?: JSX.Element;
4748
title: string;
4849
description?: string;
4950
to: string;
50-
}) {
51+
tag?: {
52+
label: string;
53+
color: string;
54+
description: string;
55+
};
56+
}>) {
5157
return (
5258
<Link to={to} className="homepage-card">
5359
{icon && <div className="icon">{icon}</div>}
@@ -57,6 +63,17 @@ export function Card({
5763
</div>
5864
{description && <div className="description">{description}</div>}
5965
</div>
66+
{tag && (
67+
<div className="tag absolute right-0 top-0 h-16 w-16">
68+
<span
69+
className="absolute right-[-28px] top-[-2px] w-[80px] rotate-45 transform bg-gray-600 py-1 text-center font-semibold text-white"
70+
style={{ backgroundColor: tag.color }}
71+
title={tag.description}
72+
>
73+
{tag.label}
74+
</span>
75+
</div>
76+
)}
6077
</Link>
6178
);
6279
}

src/css/custom.css

+14-2
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,8 @@ img[src$='#terminal'] {
917917
transition-property: background-color, color;
918918

919919
border-radius: 8px;
920+
position: relative;
921+
overflow: hidden;
920922
}
921923

922924
.homepage-card.row {
@@ -932,8 +934,6 @@ img[src$='#terminal'] {
932934
width: 48px;
933935
height: 48px;
934936
@apply mx-1;
935-
/* background-color: #262626;
936-
border-radius: 8px; */
937937
}
938938

939939
.card-content {
@@ -954,6 +954,14 @@ img[src$='#terminal'] {
954954
line-height: 1.5;
955955
}
956956

957+
.homepage-card .tag {
958+
font-size: 12px;
959+
padding: 0.25rem 0.5rem;
960+
border-radius: 4px;
961+
font-weight: 500;
962+
position: absolute;
963+
}
964+
957965
details {
958966
font-size: 14px;
959967
font-weight: 500;
@@ -1134,6 +1142,10 @@ article ul {
11341142
@apply -ml-2;
11351143
}
11361144

1145+
.community_packages_sidebar_index {
1146+
@apply -ml-2;
1147+
}
1148+
11371149
.video_sidebar_header > div > a::before {
11381150
@apply mt-1 mr-2;
11391151
content: url('data:image/svg+xml,<svg fill="currentColor" class="sidebar-icon-header ___12fm75w f1w7gpdv fez10in fg4l7m0" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4.5 4A2.5 2.5 0 0 0 2 6.5v7A2.5 2.5 0 0 0 4.5 16h7a2.5 2.5 0 0 0 2.5-2.5v-1l2.4 1.8a1 1 0 0 0 1.6-.8v-7a1 1 0 0 0-1.6-.8L14 7.5v-1A2.5 2.5 0 0 0 11.5 4h-7ZM14 8.75l3-2.25v7l-3-2.25v-2.5ZM13 6.5v7c0 .83-.67 1.5-1.5 1.5h-7A1.5 1.5 0 0 1 3 13.5v-7C3 5.67 3.67 5 4.5 5h7c.83 0 1.5.67 1.5 1.5Z" fill="currentColor"></path></svg>');

src/snippets/resources.html

+6-39
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@
1818
Developer Portal
1919
</a>
2020
</li>
21-
<!-- <li>
22-
<a
23-
href="https://github.com/dyte-samples"
24-
class="flex items-center gap-2 text-inherit"
25-
target="_blank"
26-
>
27-
<img src="/static/landing-page/sdk-icons/resources/apps.png" />
28-
Sample Apps
29-
</a>
30-
</li> -->
3121
<li>
3222
<a href="/faq" class="flex items-center gap-2 text-inherit">
3323
<img
@@ -72,37 +62,14 @@
7262
Release Notes
7363
</a>
7464
</li>
75-
</ul>
76-
77-
<!-- <div class="hr-line"></div> -->
78-
79-
<!-- <h2 class="text-sm text-primary dark:text-primary-100">
80-
Getting started with Dyte
81-
</h2>
82-
<ul
83-
class="flex list-none flex-col gap-2 pl-0 text-gray-700 dark:text-zinc-200"
84-
>
8565
<li>
86-
<a href="#" class="flex items-center gap-2 text-inherit">
87-
<img src="/static/landing-page/sdk-icons/resources/video-library.png" />
88-
Videos
89-
</a>
90-
</li>
91-
<li>
92-
<a href="#" class="flex items-center gap-2 text-inherit">
93-
<img src="/static/landing-page/sdk-icons/resources/menu-book.png" />
94-
Blog
95-
</a>
96-
</li>
97-
<li>
98-
<a href="/guides" class="flex items-center gap-2 text-inherit">
99-
<img src="/static/landing-page/sdk-icons/resources/book.png" />
100-
Guides
66+
<a
67+
href="/community-packages"
68+
class="flex items-center gap-2 text-inherit"
69+
>
70+
<img src="/static/landing-page/sdk-icons/resources/book-open.svg" />
71+
Community packages
10172
</a>
10273
</li>
10374
</ul>
104-
105-
<a href="#" class="mt-4 font-semibold text-primary dark:text-primary-100">
106-
View all resources &rarr;
107-
</a> -->
10875
</div>

0 commit comments

Comments
 (0)