Skip to content

Commit

Permalink
feat(rtc): add remote user
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed Mar 13, 2023
1 parent 3f158ab commit 66d15e5
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
11 changes: 11 additions & 0 deletions packages/agora-rtc-react/src/components/RemoteUser.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.agora-rtc-remote-user {
width: 288px;
height: 216px;
position: relative;
overflow: hidden;
}

.agora-rtc-remote-user-video {
width: 100%;
height: 100%;
}
94 changes: 94 additions & 0 deletions packages/agora-rtc-react/src/components/RemoteUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import "./RemoteUser.css";

import type { IAgoraRTCClient, IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng";
import type { HTMLProps, PropsWithChildren } from "react";
import { useEffect } from "react";

import { forwardRef, useRef } from "react";
import { RemoteAudioTrack } from "./RemoteAudioTrack";
import { RemoteVideoTrack } from "./RemoteVideoTrack";
import { useRTCClient } from "../hooks";
import { useForceUpdate } from "../hooks/tools";
import { useSafePromise } from "../utils";

export interface RemoteUserProps extends HTMLProps<HTMLDivElement> {
readonly client?: IAgoraRTCClient;
/**
* A remote user
*/
readonly user?: IAgoraRTCRemoteUser;
/**
* Whether to play the remote user's video track.
*/
readonly videoOn?: boolean;
/**
* Whether to play the remote user's audio track.
*/
readonly audioOn?: boolean;
/**
* Device ID, which can be retrieved by calling `getPlaybackDevices`.
*
* Changes of the ID will invoke `setPlaybackDevice` which sets the audio playback device, for example, the speaker.
*
* > `setPlaybackDevice` supports Chrome on desktop devices only. Other browsers throw a `NOT_SUPPORTED` error when calling the method.
*/
readonly playbackDeviceId?: string;
/**
* The volume. The value ranges from 0 (mute) to 100 (maximum). A value of 100 is the current volume.
*/
readonly volume?: number;
}

export const RemoteUser = /* @__PURE__ */ forwardRef<
HTMLDivElement,
PropsWithChildren<RemoteUserProps>
>(function RemoteUser(
{ user, videoOn, audioOn, playbackDeviceId, volume, children, className, ...props },
ref,
) {
const client = useRTCClient();
const subscribedRef = useRef(0b00); // 0b01: audio, 0b10: video, 0b11: both, 0: none
const forceUpdate = useForceUpdate();
const sp = useSafePromise();

useEffect(() => {
if (user && videoOn && !(subscribedRef.current & 0b10)) {
subscribedRef.current |= 0b10;
sp(client.subscribe(user, "video")).then(forceUpdate).catch(console.error);
}
}, [client, user, videoOn, sp, forceUpdate]);

useEffect(() => {
if (user && audioOn && !(subscribedRef.current & 0b01)) {
subscribedRef.current |= 0b01;
sp(client.subscribe(user, "audio")).then(forceUpdate).catch(console.error);
}
}, [client, user, audioOn, sp, forceUpdate]);

useEffect(
() => () => {
if (user && subscribedRef.current) {
subscribedRef.current = 0b00;
client.unsubscribe(user).catch(console.error);
}
},
[user, client],
);

return (
<div className={`agora-rtc-remote-user ${className ?? ""}`} {...props} ref={ref}>
<RemoteVideoTrack
className="agora-rtc-remote-user-video"
track={user?.videoTrack}
play={videoOn}
/>
<RemoteAudioTrack
playbackDeviceId={playbackDeviceId}
volume={volume}
track={user?.audioTrack}
play={audioOn}
/>
{children}
</div>
);
});
1 change: 1 addition & 0 deletions packages/agora-rtc-react/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./MicrophoneAudioTrack";
export * from "./CameraVideoTrack";
export * from "./RemoteVideoTrack";
export * from "./RemoteAudioTrack";
export * from "./RemoteUser";
6 changes: 6 additions & 0 deletions packages/agora-rtc-react/src/hooks/tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useCallback, useState } from "react";

export function useForceUpdate() {
const [_, forceUpdate] = useState(0);
return useCallback(() => forceUpdate(n => (n + 1) | 0), []);
}

0 comments on commit 66d15e5

Please sign in to comment.