blog #1

Merged
Dasha merged 5 commits from blog into develop 2024-08-16 23:49:23 +00:00
7 changed files with 209 additions and 60 deletions
Showing only changes of commit f3d2cfd55a - Show all commits

View File

@ -24,7 +24,7 @@ export const Agora = ({ sessionId, secret, stopCalling, remoteUser }: AgoraProps
useJoin( useJoin(
{ {
appid: 'ed90c9dc42634e5687d4e2e0766b363f', appid: process.env.NEXT_PUBLIC_AGORA_APPID,
channel: `${sessionId}-${secret}`, channel: `${sessionId}-${secret}`,
token: null, token: null,
}, },

View File

@ -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} />;
};

View File

@ -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>
);
};

View File

@ -1,14 +1,14 @@
import { LocalUser, useLocalMicrophoneTrack, useLocalCameraTrack, usePublish, useIsConnected } from 'agora-rtc-react'; import { useLocalMicrophoneTrack, useLocalCameraTrack, usePublish, useIsConnected } from 'agora-rtc-react';
import { useState, useEffect } from 'react';
import { UserOutlined } from '@ant-design/icons'; import { UserOutlined } from '@ant-design/icons';
import { useLocalStorage } from '../../../../hooks/useLocalStorage'; import { useLocalStorage } from '../../../../hooks/useLocalStorage';
import { AUTH_USER } from '../../../../constants/common'; import { AUTH_USER } from '../../../../constants/common';
import { LocalUser } from './LocalUser';
type LocalUserPanelProps = { type LocalUserPanelProps = {
calling: boolean; calling: boolean;
micOn: boolean; micOn: boolean;
cameraOn: boolean; cameraOn: boolean;
} };
export const LocalUserPanel = ({ export const LocalUserPanel = ({
calling, calling,
@ -18,26 +18,11 @@ export const LocalUserPanel = ({
const isConnected = useIsConnected(); const isConnected = useIsConnected();
const [userData] = useLocalStorage(AUTH_USER, ''); const [userData] = useLocalStorage(AUTH_USER, '');
const { faceImageUrl: userImage = '' } = userData ? JSON.parse(userData) : {}; const { faceImageUrl: userImage = '' } = userData ? JSON.parse(userData) : {};
const [playVideo, setPlayVideo] = useState(false);
const [playAudio, setPlayAudio] = useState(false);
const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn); const { localMicrophoneTrack } = useLocalMicrophoneTrack(micOn);
const { localCameraTrack } = useLocalCameraTrack(cameraOn); const { localCameraTrack } = useLocalCameraTrack(cameraOn);
usePublish([localMicrophoneTrack, localCameraTrack]); usePublish([localMicrophoneTrack, localCameraTrack]);
useEffect(() => {
if (calling) {
setPlayVideo(cameraOn)
}
}, [cameraOn]);
useEffect(() => {
if (calling) {
setPlayAudio(micOn)
}
}, [micOn]);
return calling && isConnected ? ( return calling && isConnected ? (
<div className="b-agora__local_user"> <div className="b-agora__local_user">
{!cameraOn && ( {!cameraOn && (
@ -51,9 +36,6 @@ export const LocalUserPanel = ({
audioTrack={localMicrophoneTrack} audioTrack={localMicrophoneTrack}
cameraOn={cameraOn} cameraOn={cameraOn}
micOn={micOn} micOn={micOn}
playAudio={playAudio}
playVideo={playVideo}
style={{ width: '100%', height: '100%' }}
videoTrack={localCameraTrack} videoTrack={localCameraTrack}
/> />
</div> </div>

View File

@ -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} />;
};

View File

@ -31,39 +31,38 @@ export interface RemoteVideoPlayerProps extends HTMLProps<HTMLDivElement> {
* An `IRemoteVideoTrack` can only be own by one `RemoteVideoPlayer`. * An `IRemoteVideoTrack` can only be own by one `RemoteVideoPlayer`.
*/ */
export function RemoteVideoPlayer({ export function RemoteVideoPlayer({
track, track,
playVideo, playVideo,
cover, cover,
client, client,
style, style,
children, children,
...props ...props
}: RemoteVideoPlayerProps) { }: RemoteVideoPlayerProps) {
const resolvedClient = useRTCClient(client); const resolvedClient = useRTCClient(client);
const hasVideo = resolvedClient.remoteUsers?.find( const hasVideo = resolvedClient.remoteUsers?.find(user => user.uid === track?.getUserId())?.hasVideo;
user => user.uid === track?.getUserId(), playVideo = playVideo ?? hasVideo;
)?.hasVideo;
playVideo = playVideo ?? hasVideo; return (
return ( <div {...props} style={{
<div {...props} style={{ position: "relative",
position: "relative", width: "100%",
width: "100%", height: "100%",
height: "100%", overflow: "hidden",
overflow: "hidden", background: "#000",
background: "#000", ...style
...style }}>
}}> <RemoteVideoTrack play={playVideo} track={track} />
<RemoteVideoTrack play={playVideo} track={track} /> {cover && !playVideo && <UserCover cover={cover} />}
{cover && !playVideo && <UserCover cover={cover} />} <div style={{
<div style={{ position: "absolute",
position: "absolute", top: 0,
top: 0, left: 0,
left: 0, width: "100%",
width: "100%", height: "100%",
height: "100%", overflow: "hidden",
overflow: "hidden", zIndex: 2,
zIndex: 2, }}>{children}</div>
}}>{children}</div> </div>
</div> );
); };
}

View File

@ -4,8 +4,6 @@ import AgoraRTC, { AgoraRTCProvider } from 'agora-rtc-react';
import { Session } from '../../../types/sessions'; import { Session } from '../../../types/sessions';
import { Agora } from './Agora'; import { Agora } from './Agora';
AgoraRTC.setLogLevel(0);
export const AgoraClient = ({ session, stopCalling, isCoach }: { session?: Session, stopCalling: () => void, isCoach: boolean }) => { export const AgoraClient = ({ session, stopCalling, isCoach }: { session?: Session, stopCalling: () => void, isCoach: boolean }) => {
const remoteUser = isCoach ? (session?.clients?.length ? session?.clients[0] : undefined) : session?.coach; const remoteUser = isCoach ? (session?.clients?.length ? session?.clients[0] : undefined) : session?.coach;