Skip to content
This repository has been archived by the owner on Jun 28, 2024. It is now read-only.

Commit

Permalink
Event emitters (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-stasiak authored May 15, 2024
1 parent 747df0a commit 732b982
Show file tree
Hide file tree
Showing 40 changed files with 4,910 additions and 3,225 deletions.
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nodejs 18.14.2
nodejs v20.13.1
27 changes: 14 additions & 13 deletions examples/minimal-react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions examples/minimal-react/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import VideoPlayer from "./VideoPlayer";
import { JellyfishClient, SCREEN_SHARING_MEDIA_CONSTRAINTS } from "@jellyfish-dev/react-client-sdk";
import { SCREEN_SHARING_MEDIA_CONSTRAINTS, Client } from "@jellyfish-dev/react-client-sdk";
import { useState } from "react";
import { useConnect, useDisconnect, useApi, useStatus, useTracks, useSelector } from "./client";
import { useConnect, useDisconnect, useClient, useStatus, useTracks } from "./client";

// Example metadata types for peer and track
// You can define your own metadata types just make sure they are serializable
Expand All @@ -18,14 +18,14 @@ export const App = () => {

const connect = useConnect();
const disconnect = useDisconnect();
const api = useApi();
const client = useClient();
const status = useStatus();
const tracks = useTracks();

{
// for e2e test
const client = useSelector((s) => s.connectivity.client);
(window as unknown as { client: JellyfishClient<PeerMetadata, TrackMetadata> }).client = client!;
const client = useClient();
(window as unknown as { client: Client<PeerMetadata, TrackMetadata> }).client = client!;
}

return (
Expand Down Expand Up @@ -58,7 +58,7 @@ export const App = () => {
// Get screen sharing MediaStream
navigator.mediaDevices.getDisplayMedia(SCREEN_SHARING_MEDIA_CONSTRAINTS).then((screenStream) => {
// Add local MediaStream to webrtc
screenStream.getTracks().forEach((track) => api.addTrack(track, screenStream, { type: "screen" }));
screenStream.getTracks().forEach((track) => client.addTrack(track, screenStream, { type: "screen" }));
});
}}
>
Expand Down
2 changes: 1 addition & 1 deletion examples/minimal-react/src/components/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import { PeerMetadata, TrackMetadata } from "./App";

// Create a Membrane client instance
// remember to use JellyfishContextProvider
export const { useApi, useTracks, useStatus, useConnect, useDisconnect, useSelector, JellyfishContextProvider } =
export const { useClient, useTracks, useStatus, useConnect, useDisconnect, useSelector, JellyfishContextProvider } =
create<PeerMetadata, TrackMetadata>();
27 changes: 14 additions & 13 deletions examples/use-camera-and-microphone-example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ export const AdditionalControls = () => {
<h3>Local:</h3>
<div className="max-w-[500px]">
{camera?.track?.kind === "video" && <VideoPlayer stream={camera?.stream} />}
{microphone?.track?.kind === "audio" && <AudioVisualizer stream={microphone?.stream} />}
{microphone?.track?.kind === "audio" && (
<AudioVisualizer stream={microphone?.stream} trackId={microphone?.track.id} />
)}
</div>
</div>
</div>
Expand Down
15 changes: 11 additions & 4 deletions examples/use-camera-and-microphone-example/src/AudioVisualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { useEffect, useRef, useState } from "react";

type Props = {
stream: MediaStream | null | undefined;
trackId: string | null;
};

export const AudioVisualizer = ({ stream }: Props) => {
export const AudioVisualizer = ({ stream, trackId }: Props) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvasParentRef = useRef<HTMLDivElement>(null);
const idRef = useRef<number | null>(null);
const [canvasWidth, setCanvasWidth] = useState<number>(400);

useEffect(() => {
Expand Down Expand Up @@ -34,9 +36,10 @@ export const AudioVisualizer = ({ stream }: Props) => {
const dataArray = new Uint8Array(bufferLength);

function renderFrame() {
const id = requestAnimationFrame(renderFrame);
idRef.current = requestAnimationFrame(renderFrame);

if (!canvasRef.current) {
cancelAnimationFrame(id);
cancelAnimationFrame(idRef.current);
return;
}

Expand All @@ -58,7 +61,11 @@ export const AudioVisualizer = ({ stream }: Props) => {
}

renderFrame();
}, [stream]);

return () => {
idRef.current && cancelAnimationFrame(idRef.current);
};
}, [stream, trackId]);

return (
<div ref={canvasParentRef} className="flex flex-row flex-nowrap justify-center border-4">
Expand Down
30 changes: 17 additions & 13 deletions examples/use-camera-and-microphone-example/src/DeviceControls.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { PeerStatus, UseScreenshareResult } from "@jellyfish-dev/react-client-sdk";
import { UseMicrophoneResult, UseCameraResult } from "@jellyfish-dev/react-client-sdk";
import {
PeerStatus,
UseMicrophoneResult,
UseCameraResult,
UseScreenShareResult,
} from "@jellyfish-dev/react-client-sdk";
import { TrackMetadata } from "./jellyfishSetup";

type DeviceControlsProps = {
Expand All @@ -15,7 +19,7 @@ type DeviceControlsProps = {
type: "video";
}
| {
device: UseScreenshareResult<TrackMetadata>;
device: UseScreenShareResult<TrackMetadata>;
type: "screenshare";
}
);
Expand All @@ -25,36 +29,36 @@ export const DeviceControls = ({ device, type, status, metadata }: DeviceControl
<div className="flex flex-col gap-2">
<button
className="btn btn-success btn-sm"
disabled={!!device.stream}
disabled={!!device?.stream}
onClick={() => {
device.start();
device?.start();
}}
>
Start {type} device
</button>
<button
className="btn btn-error btn-sm"
disabled={!device.stream}
disabled={!device?.stream}
onClick={() => {
device.stop();
device?.stop();
}}
>
Stop {type} device
</button>
<button
className="btn btn-success btn-sm"
disabled={!device.stream || device.enabled}
disabled={!device?.stream || device?.enabled}
onClick={() => {
device.setEnable(true);
device?.setEnable(true);
}}
>
Enable {type} track
</button>
<button
className="btn btn-error btn-sm"
disabled={!device.enabled}
disabled={!device?.enabled}
onClick={() => {
device.setEnable(false);
device?.setEnable(false);
}}
>
Disable {type} track
Expand All @@ -63,7 +67,7 @@ export const DeviceControls = ({ device, type, status, metadata }: DeviceControl
className="btn btn-success btn-sm"
disabled={status !== "joined" || !device?.stream || !!device?.broadcast?.trackId}
onClick={() => {
device.addTrack(metadata);
device?.addTrack(metadata);
}}
>
Stream {type} track
Expand All @@ -72,7 +76,7 @@ export const DeviceControls = ({ device, type, status, metadata }: DeviceControl
className="btn btn-error btn-sm"
disabled={status !== "joined" || !device?.stream || !device?.broadcast?.trackId}
onClick={() => {
device.removeTrack();
device?.removeTrack();
}}
>
Stop {type} track stream
Expand Down
47 changes: 26 additions & 21 deletions examples/use-camera-and-microphone-example/src/DeviceSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,41 @@ type Props = {
defaultOptionText: string;
devices: MediaDeviceInfo[] | null;
setInput: (value: string | null) => void;
// inputValue: string | null;
activeDevice: string | null;
};

export const DeviceSelector = ({ name, devices, setInput, defaultOptionText }: Props) => {
export const DeviceSelector = ({ name, devices, setInput, defaultOptionText, activeDevice }: Props) => {
const [selectedDevice, setSelectedDevice] = useState<string | null>(null);

const onOptionChangeHandler = (event: ChangeEvent<HTMLSelectElement>) => {
setSelectedDevice(event?.target?.value);
};

return (
<div className="flex flex-row items-center gap-2">
<span>{name}</span>
<select className="select w-full max-w-xs" onChange={onOptionChangeHandler} defaultValue={defaultOptionText}>
<option disabled>{defaultOptionText}</option>
{(devices || []).map(({ deviceId, label }) => (
<option key={deviceId} value={deviceId}>
{label}
</option>
))}
</select>
<button
className="btn btn-error btn-sm"
disabled={!selectedDevice}
onClick={() => {
setInput(selectedDevice);
}}
>
Change device!
</button>
<div className="flex flex-col gap-2">
<div className="flex flex-row">
<span>Selected: {activeDevice}</span>
</div>
<div className="flex flex-row items-center gap-2">
<span>{name}</span>
<select className="select w-full max-w-xs" onChange={onOptionChangeHandler} defaultValue={defaultOptionText}>
<option disabled>{defaultOptionText}</option>
{(devices || []).map(({ deviceId, label }) => (
<option key={deviceId} value={deviceId}>
{label}
</option>
))}
</select>
<button
className="btn btn-error btn-sm"
disabled={!selectedDevice}
onClick={() => {
setInput(selectedDevice);
}}
>
Change device!
</button>
</div>
</div>
);
};
Loading

0 comments on commit 732b982

Please sign in to comment.