Skip to content
This repository was archived by the owner on Jun 28, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/minimal-react/package-lock.json

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

2 changes: 1 addition & 1 deletion examples/minimal-react/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,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) => client.addTrack(track, screenStream, { type: "screen" }));
screenStream.getTracks().forEach((track) => client.addTrack(track, { type: "screen" }));
});
}}
>
Expand Down
4 changes: 2 additions & 2 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
@@ -1,20 +1,20 @@
import type { PeerStatus, UseMicrophoneResult, UseCameraResult, UseScreenShareResult } from "@fishjam-dev/react-client";
import type { PeerStatus, CameraAPI, MicrophoneAPI, ScreenShareAPI } from "@fishjam-dev/react-client";
import type { TrackMetadata } from "./fishjamSetup";

type DeviceControlsProps = {
status: PeerStatus;
metadata: TrackMetadata;
} & (
| {
device: UseMicrophoneResult<TrackMetadata>;
device: MicrophoneAPI<TrackMetadata>;
type: "audio";
}
| {
device: UseCameraResult<TrackMetadata>;
device: CameraAPI<TrackMetadata>;
type: "video";
}
| {
device: UseScreenShareResult<TrackMetadata>;
device: ScreenShareAPI<TrackMetadata>;
type: "screenshare";
}
);
Expand Down
16 changes: 13 additions & 3 deletions examples/use-camera-and-microphone-example/src/DeviceSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ type Props = {
name: string;
defaultOptionText: string;
devices: MediaDeviceInfo[] | null;
stop: () => void;
setInput: (value: string | null) => void;
activeDevice: string | null;
};

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

const onOptionChangeHandler = (event: ChangeEvent<HTMLSelectElement>) => {
Expand All @@ -32,13 +33,22 @@ export const DeviceSelector = ({ name, devices, setInput, defaultOptionText, act
))}
</select>
<button
className="btn btn-error btn-sm"
className="btn btn-success btn-sm"
disabled={!selectedDevice}
onClick={() => {
setInput(selectedDevice);
}}
>
Change device!
start / change
</button>
<button
className="btn btn-error btn-sm"
disabled={!selectedDevice}
onClick={() => {
stop();
}}
>
stop
</button>
</div>
</div>
Expand Down
84 changes: 64 additions & 20 deletions examples/use-camera-and-microphone-example/src/MainControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,26 @@ import { Badge } from "./Badge";
import { DeviceControls } from "./DeviceControls";
import { Radio } from "./Radio";

type RestartChange = "stop" | "replace" | undefined;
type OnDeviceChange = "remove" | "replace" | undefined;
type OnDeviceStop = "remove" | "mute" | undefined;

const isRestartChange = (e: string | undefined): e is RestartChange => {
return e === undefined || e === "stop" || e === "replace";
};
const isDeviceChangeValue = (e: string | undefined): e is OnDeviceChange =>
e === undefined || e === "remove" || e === "replace";

const isDeviceStopValue = (e: string | undefined): e is OnDeviceStop =>
e === undefined || e === "remove" || e === "mute";

const tokenAtom = atomWithStorage("token", "");

const broadcastVideoOnConnectAtom = atomWithStorage<boolean | undefined>("broadcastVideoOnConnect", undefined);
const broadcastVideoOnDeviceStartAtom = atomWithStorage<boolean | undefined>("broadcastVideoOnDeviceStart", undefined);
const broadcastVideoOnDeviceChangeAtom = atomWithStorage<RestartChange>("broadcastVideoOnDeviceChange", undefined);
const videoOnDeviceChangeAtom = atomWithStorage<OnDeviceChange>("videoOnDeviceChange", undefined);
const videoOnDeviceStopAtom = atomWithStorage<OnDeviceStop>("videoOnDeviceStop", undefined);

const broadcastAudioOnConnectAtom = atomWithStorage<boolean | undefined>("broadcastAudioOnConnect", undefined);
const broadcastAudioOnDeviceStartAtom = atomWithStorage<boolean | undefined>("broadcastAudioOnDeviceStart", undefined);
const broadcastAudioOnDeviceChangeAtom = atomWithStorage<RestartChange>("broadcastAudioOnDeviceChange", undefined);
const audioOnDeviceChangeAtom = atomWithStorage<OnDeviceChange>("audioOnDeviceChange", undefined);
const audioOnDeviceStopAtom = atomWithStorage<OnDeviceStop>("audioOnDeviceStop", undefined);

const broadcastScreenShareOnConnectAtom = atomWithStorage<boolean | undefined>(
"broadcastScreenShareOnConnect",
Expand All @@ -67,11 +72,13 @@ export const MainControls = () => {

const [broadcastVideoOnConnect, setBroadcastVideoOnConnect] = useAtom(broadcastVideoOnConnectAtom);
const [broadcastVideoOnDeviceStart, setBroadcastVideoOnDeviceStart] = useAtom(broadcastVideoOnDeviceStartAtom);
const [broadcastVideoOnDeviceChange, setBroadcastVideoOnDeviceChange] = useAtom(broadcastVideoOnDeviceChangeAtom);
const [broadcastVideoOnDeviceChange, setBroadcastVideoOnDeviceChange] = useAtom(videoOnDeviceChangeAtom);
const [broadcastVideoOnDeviceStop, setBroadcastVideoOnDeviceStop] = useAtom(videoOnDeviceStopAtom);

const [broadcastAudioOnConnect, setBroadcastAudioOnConnect] = useAtom(broadcastAudioOnConnectAtom);
const [broadcastAudioOnDeviceStart, setBroadcastAudioOnDeviceStart] = useAtom(broadcastAudioOnDeviceStartAtom);
const [broadcastAudioOnDeviceChange, setBroadcastAudioOnDeviceChange] = useAtom(broadcastAudioOnDeviceChangeAtom);
const [broadcastAudioOnDeviceChange, setBroadcastAudioOnDeviceChange] = useAtom(audioOnDeviceChangeAtom);
const [broadcastAudioOnDeviceStop, setBroadcastAudioOnDeviceStop] = useAtom(audioOnDeviceStopAtom);

const [broadcastScreenShareOnConnect, setBroadcastScreenShareOnConnect] = useAtom(broadcastScreenShareOnConnectAtom);
const [broadcastScreenShareOnDeviceStart, setBroadcastScreenShareOnDeviceStart] = useAtom(
Expand All @@ -85,7 +92,8 @@ export const MainControls = () => {
trackConstraints: VIDEO_TRACK_CONSTRAINTS,
broadcastOnConnect: broadcastVideoOnConnect,
broadcastOnDeviceStart: broadcastVideoOnDeviceStart,
broadcastOnDeviceChange: broadcastVideoOnDeviceChange,
onDeviceChange: broadcastVideoOnDeviceChange,
onDeviceStop: broadcastVideoOnDeviceStop,
defaultTrackMetadata: DEFAULT_VIDEO_TRACK_METADATA,
defaultSimulcastConfig: {
enabled: true,
Expand All @@ -97,7 +105,8 @@ export const MainControls = () => {
trackConstraints: AUDIO_TRACK_CONSTRAINTS,
broadcastOnConnect: broadcastAudioOnConnect,
broadcastOnDeviceStart: broadcastAudioOnDeviceStart,
broadcastOnDeviceChange: broadcastAudioOnDeviceChange,
onDeviceChange: broadcastAudioOnDeviceChange,
onDeviceStop: broadcastAudioOnDeviceStop,
defaultTrackMetadata: DEFAULT_AUDIO_TRACK_METADATA,
},
screenShare: {
Expand Down Expand Up @@ -221,15 +230,28 @@ export const MainControls = () => {
name='Broadcast video on device change (default "replace")'
value={broadcastVideoOnDeviceChange}
set={(value) => {
if (isRestartChange(value)) setBroadcastVideoOnDeviceChange(value);
if (isDeviceChangeValue(value)) setBroadcastVideoOnDeviceChange(value);
}}
radioClass="radio-primary"
options={[
{ value: undefined, key: "undefined" },
{ value: "stop", key: "stop" },
{ value: "remove", key: "remove" },
{ value: "replace", key: "replace" },
]}
/>
<Radio
name='Broadcast video on device stop (default "mute")'
value={broadcastVideoOnDeviceStop}
set={(value) => {
if (isDeviceStopValue(value)) setBroadcastVideoOnDeviceStop(value);
}}
radioClass="radio-primary"
options={[
{ value: undefined, key: "undefined" },
{ value: "remove", key: "remove" },
{ value: "mute", key: "mute" },
]}
/>

<ThreeStateRadio
name="Broadcast audio on connect (default false)"
Expand All @@ -247,15 +269,28 @@ export const MainControls = () => {
name='Broadcast audio on device change (default "replace")'
value={broadcastAudioOnDeviceChange}
set={(value) => {
if (isRestartChange(value)) setBroadcastAudioOnDeviceChange(value);
if (isDeviceChangeValue(value)) setBroadcastAudioOnDeviceChange(value);
}}
radioClass="radio-secondary"
options={[
{ value: undefined, key: "undefined" },
{ value: "stop", key: "stop" },
{ value: "remove", key: "remove" },
{ value: "replace", key: "replace" },
]}
/>
<Radio
name='Broadcast audio on device stop (default "mute")'
value={broadcastAudioOnDeviceStop}
set={(value) => {
if (isDeviceStopValue(value)) setBroadcastAudioOnDeviceStop(value);
}}
radioClass="radio-secondary"
options={[
{ value: undefined, key: "undefined" },
{ value: "remove", key: "remove" },
{ value: "mute", key: "mute" },
]}
/>

<ThreeStateRadio
name="Broadcast screen share on connect (default false)"
Expand All @@ -279,6 +314,9 @@ export const MainControls = () => {
video.start(id);
}}
defaultOptionText="Select video device"
stop={() => {
video.stop();
}}
/>

<DeviceSelector
Expand All @@ -290,6 +328,9 @@ export const MainControls = () => {
audio.start(id);
}}
defaultOptionText="Select audio device"
stop={() => {
audio.stop();
}}
/>

<div className="grid grid-cols-3 gap-2">
Expand Down Expand Up @@ -318,12 +359,15 @@ export const MainControls = () => {

<div>
<h3>Streaming:</h3>
{local.map(({ trackId, stream, track }) => (
<div key={trackId} className="max-w-[500px]">
{track?.kind === "video" && <VideoPlayer key={trackId} stream={stream} />}
{track?.kind === "audio" && <AudioVisualizer trackId={track.id} stream={stream} />}
</div>
))}
<div className="flex max-w-[500px] flex-col gap-2">
{local.map(({ trackId, stream, track }) => (
<div key={trackId} className="max-w-[500px] border">
<span>trackId: {trackId}</span>
{track?.kind === "audio" && <AudioVisualizer trackId={track.id} stream={stream} />}
{track?.kind === "video" && <VideoPlayer key={trackId} stream={stream} />}
</div>
))}
</div>
</div>
</div>
</div>
Expand Down
Loading