blog #1
|
@ -24,7 +24,7 @@ export const Agora = ({ sessionId, secret, stopCalling, remoteUser }: AgoraProps
|
|||
|
||||
useJoin(
|
||||
{
|
||||
appid: 'ed90c9dc42634e5687d4e2e0766b363f',
|
||||
appid: process.env.NEXT_PUBLIC_AGORA_APPID,
|
||||
channel: `${sessionId}-${secret}`,
|
||||
token: null,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { useEffect } from 'react';
|
||||
import { ICameraVideoTrack, LocalVideoTrack, LocalVideoTrackProps, MaybePromiseOrNull } from 'agora-rtc-react';
|
||||
import { useAwaited } from '../../../../utils/agora/tools';
|
||||
|
||||
interface CameraVideoTrackProps extends LocalVideoTrackProps {
|
||||
/**
|
||||
* A camera video track which can be created by `createCameraVideoTrack()`.
|
||||
*/
|
||||
readonly track?: MaybePromiseOrNull<ICameraVideoTrack>;
|
||||
/**
|
||||
* Device ID, which can be retrieved by calling `getDevices()`.
|
||||
*/
|
||||
readonly deviceId?: string;
|
||||
}
|
||||
|
||||
export const CameraVideoTrack = ({
|
||||
track: maybeTrack,
|
||||
deviceId,
|
||||
...props
|
||||
}: CameraVideoTrackProps) => {
|
||||
const track = useAwaited(maybeTrack);
|
||||
|
||||
useEffect(() => {
|
||||
if (track && deviceId != null) {
|
||||
track.setDevice(deviceId).catch(console.warn);
|
||||
}
|
||||
}, [deviceId, track]);
|
||||
|
||||
return <LocalVideoTrack track={maybeTrack} {...props} />;
|
||||
};
|
|
@ -0,0 +1,108 @@
|
|||
import { HTMLProps, ReactNode } from 'react';
|
||||
import { ICameraVideoTrack, IMicrophoneAudioTrack, MaybePromiseOrNull } from 'agora-rtc-react';
|
||||
import { UserCover } from '../components';
|
||||
import { MicrophoneAudioTrack } from './MicrophoneAudioTrack';
|
||||
import { CameraVideoTrack } from './CameraVideoTrack';
|
||||
|
||||
interface LocalUserProps extends HTMLProps<HTMLDivElement> {
|
||||
/**
|
||||
* Whether to turn on the local user's microphone. Default false.
|
||||
*/
|
||||
readonly micOn?: boolean;
|
||||
/**
|
||||
* Whether to turn on the local user's camera. Default false.
|
||||
*/
|
||||
readonly cameraOn?: boolean;
|
||||
/**
|
||||
* A microphone audio track which can be created by `createMicrophoneAudioTrack()`.
|
||||
*/
|
||||
readonly audioTrack?: MaybePromiseOrNull<IMicrophoneAudioTrack>;
|
||||
/**
|
||||
* A camera video track which can be created by `createCameraVideoTrack()`.
|
||||
*/
|
||||
readonly videoTrack?: MaybePromiseOrNull<ICameraVideoTrack>;
|
||||
/**
|
||||
* Whether to play the local user's audio track. Default follows `micOn`.
|
||||
*/
|
||||
readonly playAudio?: boolean;
|
||||
/**
|
||||
* Whether to play the local user's video track. Default follows `cameraOn`.
|
||||
*/
|
||||
readonly playVideo?: boolean;
|
||||
/**
|
||||
* Device ID, which can be retrieved by calling `getDevices()`.
|
||||
*/
|
||||
readonly micDeviceId?: string;
|
||||
/**
|
||||
* Device ID, which can be retrieved by calling `getDevices()`.
|
||||
*/
|
||||
readonly cameraDeviceId?: string;
|
||||
/**
|
||||
* The volume. The value ranges from 0 (mute) to 1000 (maximum). A value of 100 is the current volume.
|
||||
*/
|
||||
readonly volume?: number;
|
||||
/**
|
||||
* Render cover image if playVideo is off.
|
||||
*/
|
||||
readonly cover?: string;
|
||||
/**
|
||||
* Children is rendered on top of the video canvas.
|
||||
*/
|
||||
readonly children?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play/Stop local user camera and microphone track.
|
||||
*/
|
||||
export function LocalUser({
|
||||
micOn,
|
||||
cameraOn,
|
||||
audioTrack,
|
||||
videoTrack,
|
||||
playAudio = false,
|
||||
playVideo,
|
||||
micDeviceId,
|
||||
cameraDeviceId,
|
||||
volume,
|
||||
cover,
|
||||
children,
|
||||
style,
|
||||
...props
|
||||
}: LocalUserProps) {
|
||||
playVideo = playVideo ?? !!cameraOn;
|
||||
playAudio = playAudio ?? !!micOn;
|
||||
return (
|
||||
<div {...props} style={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
background: "#000",
|
||||
...style
|
||||
}}>
|
||||
<CameraVideoTrack
|
||||
deviceId={cameraDeviceId}
|
||||
disabled={!cameraOn}
|
||||
play={playVideo}
|
||||
track={videoTrack}
|
||||
/>
|
||||
<MicrophoneAudioTrack
|
||||
deviceId={micDeviceId}
|
||||
disabled={!micOn}
|
||||
play={playAudio}
|
||||
track={audioTrack}
|
||||
volume={volume}
|
||||
/>
|
||||
{cover && !cameraOn && <UserCover cover={cover} />}
|
||||
<div style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
zIndex: 2,
|
||||
}}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,14 +1,14 @@
|
|||
import { LocalUser, useLocalMicrophoneTrack, useLocalCameraTrack, usePublish, useIsConnected } from 'agora-rtc-react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useLocalMicrophoneTrack, useLocalCameraTrack, usePublish, useIsConnected } from 'agora-rtc-react';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { useLocalStorage } from '../../../../hooks/useLocalStorage';
|
||||
import { AUTH_USER } from '../../../../constants/common';
|
||||
import { LocalUser } from './LocalUser';
|
||||
|
||||
type LocalUserPanelProps = {
|
||||
calling: boolean;
|
||||
micOn: boolean;
|
||||
cameraOn: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export const LocalUserPanel = ({
|
||||
calling,
|
||||
|
@ -18,26 +18,11 @@ export const LocalUserPanel = ({
|
|||
const isConnected = useIsConnected();
|
||||
const [userData] = useLocalStorage(AUTH_USER, '');
|
||||
const { faceImageUrl: userImage = '' } = userData ? JSON.parse(userData) : {};
|
||||
|
||||
const [playVideo, setPlayVideo] = useState(false);
|
||||
const [playAudio, setPlayAudio] = useState(false);
|
||||
|
||||
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
|
||||
const { localCameraTrack } = useLocalCameraTrack(cameraOn);
|
||||
|
||||
usePublish([localMicrophoneTrack, localCameraTrack]);
|
||||
|
||||
useEffect(() => {
|
||||
if (calling) {
|
||||
setPlayVideo(cameraOn)
|
||||
}
|
||||
}, [cameraOn]);
|
||||
|
||||
useEffect(() => {
|
||||
if (calling) {
|
||||
setPlayAudio(micOn)
|
||||
}
|
||||
}, [micOn]);
|
||||
|
||||
return calling && isConnected ? (
|
||||
<div className="b-agora__local_user">
|
||||
{!cameraOn && (
|
||||
|
@ -51,9 +36,6 @@ export const LocalUserPanel = ({
|
|||
audioTrack={localMicrophoneTrack}
|
||||
cameraOn={cameraOn}
|
||||
micOn={micOn}
|
||||
playAudio={playAudio}
|
||||
playVideo={playVideo}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
videoTrack={localCameraTrack}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { ReactNode, useEffect } from 'react';
|
||||
import { IMicrophoneAudioTrack, LocalAudioTrack, LocalAudioTrackProps, MaybePromiseOrNull } from 'agora-rtc-react';
|
||||
import { useAwaited } from '../../../../utils/agora/tools';
|
||||
|
||||
interface MicrophoneAudioTrackProps extends LocalAudioTrackProps {
|
||||
/**
|
||||
* A microphone audio track which can be created by `createMicrophoneAudioTrack()`.
|
||||
*/
|
||||
readonly track?: MaybePromiseOrNull<IMicrophoneAudioTrack>;
|
||||
/**
|
||||
* Device ID, which can be retrieved by calling `getDevices()`.
|
||||
*/
|
||||
readonly deviceId?: string;
|
||||
|
||||
readonly children?: ReactNode;
|
||||
}
|
||||
|
||||
export const MicrophoneAudioTrack = ({
|
||||
track: maybeTrack,
|
||||
deviceId,
|
||||
...props
|
||||
}: MicrophoneAudioTrackProps) => {
|
||||
const track = useAwaited(maybeTrack);
|
||||
|
||||
useEffect(() => {
|
||||
if (track && deviceId != null) {
|
||||
track.setDevice(deviceId).catch(console.warn);
|
||||
}
|
||||
}, [deviceId, track]);
|
||||
|
||||
return <LocalAudioTrack track={maybeTrack} {...props} />;
|
||||
};
|
|
@ -31,39 +31,38 @@ export interface RemoteVideoPlayerProps extends HTMLProps<HTMLDivElement> {
|
|||
* An `IRemoteVideoTrack` can only be own by one `RemoteVideoPlayer`.
|
||||
*/
|
||||
export function RemoteVideoPlayer({
|
||||
track,
|
||||
playVideo,
|
||||
cover,
|
||||
client,
|
||||
style,
|
||||
children,
|
||||
...props
|
||||
track,
|
||||
playVideo,
|
||||
cover,
|
||||
client,
|
||||
style,
|
||||
children,
|
||||
...props
|
||||
}: RemoteVideoPlayerProps) {
|
||||
const resolvedClient = useRTCClient(client);
|
||||
const hasVideo = resolvedClient.remoteUsers?.find(
|
||||
user => user.uid === track?.getUserId(),
|
||||
)?.hasVideo;
|
||||
playVideo = playVideo ?? hasVideo;
|
||||
return (
|
||||
<div {...props} style={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
background: "#000",
|
||||
...style
|
||||
}}>
|
||||
<RemoteVideoTrack play={playVideo} track={track} />
|
||||
{cover && !playVideo && <UserCover cover={cover} />}
|
||||
<div style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
zIndex: 2,
|
||||
}}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const resolvedClient = useRTCClient(client);
|
||||
const hasVideo = resolvedClient.remoteUsers?.find(user => user.uid === track?.getUserId())?.hasVideo;
|
||||
playVideo = playVideo ?? hasVideo;
|
||||
|
||||
return (
|
||||
<div {...props} style={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
background: "#000",
|
||||
...style
|
||||
}}>
|
||||
<RemoteVideoTrack play={playVideo} track={track} />
|
||||
{cover && !playVideo && <UserCover cover={cover} />}
|
||||
<div style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
zIndex: 2,
|
||||
}}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,8 +4,6 @@ import AgoraRTC, { AgoraRTCProvider } from 'agora-rtc-react';
|
|||
import { Session } from '../../../types/sessions';
|
||||
import { Agora } from './Agora';
|
||||
|
||||
AgoraRTC.setLogLevel(0);
|
||||
|
||||
export const AgoraClient = ({ session, stopCalling, isCoach }: { session?: Session, stopCalling: () => void, isCoach: boolean }) => {
|
||||
const remoteUser = isCoach ? (session?.clients?.length ? session?.clients[0] : undefined) : session?.coach;
|
||||
|
||||
|
|
Loading…
Reference in New Issue