Next.js와 100ms로 제작된 Video Chat App

58901 단어 Next.jsReact100mstech

개시하다


안녕하세요.황금주 잘 보냈어?
비정기적으로 이전 회사 동기들과 온라인 점심을 먹었는데 줌과 메트가 무료 계좌라면 3인 이상이면 시간 제한이 있잖아요.나는 이 제한을 좋아하지 않아서 영상 채팅 소프트웨어를 만드는 이야기를 썼다.
(회사에서 쉬는 시간에 점심을 먹기 때문에 한 시간은 문제없다.)

100ms


이번에 사용100ms한 거 아세요?
며칠 전에 읽었다이 블로그.써보려고
100ms는 개발자가 웹, 안드로이드, iOS 애플리케이션에 동영상 음성 회의를 추가하는 클라우드 플랫폼이라고 한다.
100ms is a cloud platform that allows developers to add video and audio conferencing to Web, Android and iOS applications.
첫 페이지에는'몇 시간이면 라이브 앱을 만들 수 있다'고 적혀 있지만 하루 정도 화상채팅 앱을 완성했기 때문에 틀림없다.
빨리 100ms로 영상통화 앱을 실현하세요!

사전 준비


우선 100ms로 계정을 만들어야 합니다.이 페이지부터 등록하십시오.
자유계획은 매달 10000분을 사용할 수 있기 때문에 이번 목적은 충분하다.
등록 후 "Createa newapp"페이지로 이동합니다. 다음 질문에 답하십시오.
  • Virtual Events 를 선택하고 Next
  • 원하는 도메인 이름 입력, Set up App(Region)
  • 설정 종료!
  • 여기에 도착하면 오른쪽 아래에 있는'Go to Dashboard'로 대시보드로 이동한다.

    시험을 준비하다


    사실 이렇게 하면 영상통화를 할 수 있다.위 화면의 "Join as statge"를 클릭하여 앞 페이지로 이동, 룸에 들어가면 화상 채팅이 시작됩니다!
    화면 구축, 맞춤형 제작 등 필요 없는 사람은 이걸로 하면 될 것 같아요.

    GOAL


    지금부터 실시되는 코드의 완성 형식은여기.이기 때문에 문장을 읽는 것이 번거로운 분들은 직접 코드를 참조하세요.
    실현하고자 하는 기능은 다음과 같다.
    · 참가·탈퇴 영상채팅
    • 마이크 켜기/끄기
    • 카메라 켜기/끄기
    • 화면 공유 켜기/끄기
    · 스피커·마이크·카메라의 설비 변경

    전제 조건


  • Next.js 사용* React
  • 100ms에서 제공하는 SDK가 React18을 지원하지 않기 때문에 17
  • 사용
  • 사용Tailwind CSS양식
  • UI 라이브러리Headless UI로 사용
  • 100ms의 사용 방법 이외의 설명을 생략
  • 공식 문서의 React Quickstart Guide 내용을 번역하면서 해설
  • Install


    우선 환경을 조정해야 한다.
    npx create-next-app --ts demo_100ms
    cd demo_100ms
    npm i @100mslive/react-sdk react@17 react-dom@17 
    

    라이브러리 초기화


    먼저 100ms를 사용할 수 있도록 제작된 React 애플리케이션에서 초기화합니다.HMSRoomProviderimport과 랩만 있으면 됩니다.
    // src/pages/_app.tsx
    import '../styles/globals.css';
    import type { AppProps } from 'next/app';
    import { HMSRoomProvider } from '@100mslive/react-sdk';
    
    function MyApp({ Component, pageProps }: AppProps) {
      return (
        {/* HMSRoomProviderでラップする */}
        <HMSRoomProvider>
          <Component {...pageProps} />
        </HMSRoomProvider>
      );
    }
    export default MyApp;
    

    콘셉트


    구체적인 실시에 들어가기 전에 필요한 키워드를 소개한다.
  • 룸: 전화 회의에 참석했을 때 참가자가 영상통화 룸에서
  • Peer: 영상통화 참가자.자신은 현지인이고 다른 사람은 원격 Peer입니다.
  • 와 미디어.등점이 가질 수 있는 트랙은 오디오와 동영상 두 종류가 있다.
  • Room 참가

    hmsActionsjoin 방법을 사용하여 Room에 참가합니다.
    이 방법을 사용하려면 userNameauthToken가 필요하다.userName는 참가자가 임의로 결정하는 문자열이다.authToken 계기판에서 복사해 왔어요.

    authToken 복제

  • 대시보드 왼쪽 메뉴에서 Room을 선택하고 RoomId
  • 를 선택합니다.
  • 페이지의 오른쪽 상단에 있는 Join room
  • 선택
  • Stage의 키 아이콘을 클릭하고 Token
  • 을 복제한다.

    ※ 롤이 할 수 없는 일을 제한하기 때문에 필요에 따라 다른 롤톡을 복제하세요.이번에는 모든 참가자가 같은 기능을 사용할 수 있도록 한 라운드를 치르기로 했다.

    이루어지다


    // src/components/JoinForm/index.tsx
    import { ChangeEvent, FormEvent, useState, VFC } from 'react';
    import { useHMSActions } from '@100mslive/react-sdk';
    
    export const JoinForm: VFC = () => {
      const hmsActions = useHMSActions();
      const [userName, setUserName] = useState('');
    
      const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        setUserName(e.target.value);
      };
    
     const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        // joinメソッドにuserNameと先ほどコピーしたauthTokenを渡す
        hmsActions.join({
          userName,
          // tokenはenvファイルから呼び出してます
          authToken:  process.env.NEXT_PUBLIC_STAGE_TOKEN || "",
        });
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <h2>Join Room</h2>
          <div>
            <label htmlFor="user_name">User Name:</label>
            <input
              type="text"
              id="user_name"
              name="name"
              required
              value={userName}
              onChange={handleChange}
            />
          </div>
          <button type="submit">Join</button>
        </form>
     );
    };
    

    Room 종료


    룸에 참가할 수 있어서 탈퇴할 수 있어요.
    사용hmsActionsleave 방법을 종료합니다.
    페이지를 떠나는 시간에 탈퇴onunload할 수 있도록 불이 났습니다.
    // src/components/Home/index.tsx
    import { useHMSActions } from '@100mslive/react-sdk';
    import { useEffect, VFC } from 'react';
    
    export const Home: VFC = () => {
      const hmsActions = useHMSActions();
    
      useEffect(() => {
        window.onunload = () => {
          hmsActions.leave();
        };
      }, [hmsActions]);
    
      return <div>Home</div>;
    };
    

    참여자 비디오 표시


    이어서 참가자들의 동영상이 표시됩니다.
    참가자의 정보는 useHMSStore에 대한 매개 변수 전달selectPeers을 통해 수조로 얻을 수 있다.
    각 사람의 영상은 useVideo의 매개 변수에 videoTrack에 건네주고 반환된 refvideo 라벨에 연결한 후에 나타난다.
    // src/components/VideoChat/index.tsx
    import { selectPeers, useHMSStore } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    import { Peer } from './Peer';
    
    export const VideoChat: VFC = () => {
      const peers = useHMSStore(selectPeers);
    
      return (
        <div>
          {peers.map((peer) => (
            <Peer key={peer.id} peer={peer} />
          ))}
        </div>
      );
    };
    
    // src/components/VideoChat/Peer/index.tsx
    import { HMSPeer, useVideo } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    
    type Props = {
      peer: HMSPeer;
    };
    export const Peer: VFC<Props> = ({ peer }) => {
      const { videoRef } = useVideo({
        trackId: peer.videoTrack,
      });
    
      return (
        <div>
          <video
            ref={videoRef}
            autoPlay
            muted
            playsInline
            // 映像が反転するのでcssで対処
            style={{ transform: 'scaleX(-1)' }}
          />
          <span>
            {/* ユーザ名はnameプロパティを参照することで取得可能 */}
            {peer.name} {peer.isLocal && '(You)'}
          </span>
        </div>
      );
    };
    

    상태에 따라 어셈블리 분할


    최소한의 설치가 완료되었기 때문에 제작된 구성 요소를 첫 페이지에 연결합니다.useHMSStoreselectIsConnectedToRoom에 건네주면 isConnected를 받을 수 있으며, 이를 토대로 룸에 가입 여부를 판단하고 구성 요소를 분리한다.
    import { useHMSStore, selectIsConnectedToRoom, useHMSActions } from '@100mslive/react-sdk';
    import { useEffect, VFC } from 'react';
    import { VideoChat } from '../VideoChat';
    import { JoinForm } from '../JoinForm';
    
    export const Home: VFC = () => {
      const hmsActions = useHMSActions();
      const isConnected = useHMSStore(selectIsConnectedToRoom);
    
      useEffect(() => {
        window.onunload = () => {
          // Roomに参加している時、という条件分岐追加
          if (isConnected) {
            hmsActions.leave();
          }
        };
      }, [hmsActions, isConnected]);
      // Roomに参加していればVideoChat、そうでなければJoinFormを表示する
      return <>{isConnected ? <VideoChat /> : <JoinForm />}</>;
    };
    
    완성되면 룸에 한번 참가해 보세요!
    JoinForm으로 사용자 이름을 입력해서 참가하고 싶으면 카메라의 이미지가 표시됩니다.
    (첫 번째 브라우저에서는 마이크와 카메라에 접근할 수 있는 대화상자가 나타날 수 있습니다. 허락해 주십시오.)

    컨트롤러 추가


    이제 추가 기능을 구현합니다.

    마이크 켜기/끄기


    마이크의 켜기/끄기 사용useAVToggle의 반환값toggleAudio 방법은 현재 상태isLocalAudioEnabled에서 확인할 수 있습니다.
    // src/components/VideoChat/Controller/AudioController/index.tsx
    import { useAVToggle } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    
    export const AudioController: VFC = () => {
      const { isLocalAudioEnabled, toggleAudio } = useAVToggle();
    
      return (
        // 省略
      );
    };
    

    카메라 켜기/끄기

    useAVToggle 반환치toggleVideo의 방법을 사용하여 현재 상태isLocalVideoEnabled를 확인할 수 있습니다.
    // src/components/VideoChat/Controller/index.tsx
    import { useAVToggle } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    
    export const VideoController: VFC = () => {
      const { isLocalVideoEnabled, toggleVideo } = useAVToggle();
    
      return (
        // 省略
      );
    };
    

    화면 공유 켜기/끄기


    화면 공유도 간단하게 실현할 수 있다.단지 hmsActionssetScreenShareEnabled 방법에 표지를 제출할 뿐이다.현재 상태는 useHMSStoreselectIsLocalScreenShared에 맡기면 된다.
    // src/components/VideoChat/Controller/ScreenShareController/index.tsx
    import { selectIsLocalScreenShared, useHMSActions, useHMSStore } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    import { Switch } from '@headlessui/react';
    
    export const ScreenShareController: VFC = () => {
      const hmsActions = useHMSActions();
      // 自分が画面共有しているかどうか
      const amIScreenSharing = useHMSStore(selectIsLocalScreenShared);
    
      const handleToggleShareScreen = async () => {
        try {
          // 現在の状態を反転したものを引数に渡してtoggleする
          await hmsActions.setScreenShareEnabled(!amIScreenSharing);
        } catch (error) {
          console.error({ error });
        }
      };
    
      return (
        // 省略
      );
    };
    
    화면 공유 내용은 비디오 태그에 연결하여 표시할 수 있습니다.
    이를 위해서는 화면 공유 내용의 트랙이 필요하다.selectScreenShareByperID를 사용하면 id를 키로 화면이 공유하는 정보를 얻고useHMSStore에 전달할 수 있습니다.
    이번 실장에서는 화면을 공유했다면 카메라 영상이 아닌 화면 공유를 한곳으로 옮겼다.
    // src/components/VideoChat/Peer/index.tsx
    import { HMSPeer, selectScreenShareByPeerID, useHMSStore, useVideo } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    
    type Props = {
      peer: HMSPeer;
    };
    export const Peer: VFC<Props> = ({ peer }) => {
      const screenshareVideoTrack = useHMSStore(selectScreenShareByPeerID(peer.id));
      const { videoRef } = useVideo({
        // 画面供されたらそのidを渡して、されてなければ今まで通りvideoTrackを渡す
        trackId: screenshareVideoTrack?.id ?? peer.videoTrack,
      });
    
      return (
        // 省略
      );
    };
    

    스피커 마이크 카메라 장치 변경


    사용 가능한 장치 가져오기


    사용 가능한 장치는 useHMSStore에 전달selectDevices을 통해 얻을 수 있다.
    반환값은 DeviceMap의 유형으로 각 키를 배열할 수 있습니다.
    const devices = useHMSStore(selectDevices);
    
    interface DeviceMap {
        audioInput: MediaDeviceInfo[];
        audioOutput: MediaDeviceInfo[];
        videoInput: MediaDeviceInfo[];
    }
    

    현재 사용 중인 장치 가져오기


    현재 사용 중인 장치는 useHMSStore에 전달selectLocalMediaSettings을 통해 얻을 수 있다.
    반환값은 HMSMediaSettings의 형식으로 키마다 id를 얻을 수 있습니다.
    const selectedDevices = useHMSStore(selectLocalMediaSettings);
    
    interface HMSMediaSettings {
        audioInputDeviceId: string;
        videoInputDeviceId: string;
        audioOutputDeviceId?: string;
    }
    

    장치 변경


    디바이스를 변경하려면 deviceId 를 hmsActions 에 전달하는 방법입니다.
    스피커의 변경setAudioOutputDevice, 마이크의 변경setAudioSettings, 카메라의 변경 사용setVideoSettings 방법.매개 변수의 교부 방법이 다르다는 것을 주의하세요.
    const hmsActions = useHMSActions();
    
    // スピーカーの変更
    const handleChangeAudioOutput = (deviceId: string) => {
      // 引数は文字列で渡す
      hmsActions.setAudioOutputDevice(deviceId);
    };
    // マイクの変更
    const handleChangeAudioInput = async (deviceId: string) => {
      // 引数はオブジェクトで渡す
      await hmsActions.setAudioSettings({ deviceId });
    };
    // カメラの変更
    const handleChangeVideo = async (deviceId: string) => {
      // 引数はオブジェクトで渡す
      await hmsActions.setVideoSettings({ deviceId });
    };
    

    종료 버튼


    페이지를 다시 불러와서 종료할 수 있기 때문에 종료 단추를 만들 수도 있습니다.
    이것은 방금 소개한 hmsActions 방법leave을 온클릭 처리 프로그램에 맡긴 것일 뿐이다.
    // src/components/VideoChat/Controller/LeaveButton/index.tsx
    import { useHMSActions } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    
    export const LeaveButton: VFC = () => {
      const hmsActions = useHMSActions();
    
      const handleClick = () => {
        hmsActions.leave();
      };
    
      return (
        <button type="button" onClick={handleClick}>
          Leave
        </button>
      );
    };
    

    비디오 채팅 화면에 컨트롤러 연결


    마지막으로 제작된 컨트롤러를 하나의 구성 요소로 합쳐 영상 채팅 화면에 연결하면 된다.
    // src/components/VideoChat/Controller/VideoController/index.tsx
    import { selectPeers, useHMSStore } from '@100mslive/react-sdk';
    import type { VFC } from 'react';
    import { Controller } from './Controller';
    import { Peer } from './Peer';
    
    export const VideoChat: VFC = () => {
      const peers = useHMSStore(selectPeers);
    
      return (
        <div>
          <div>
            {peers.map((peer) => (
              <Peer key={peer.id} peer={peer} />
            ))}
          </div>
          {/* ページ下部に表示 */}
          <Controller />
        </div>
      );
    };
    

    끝맺다


    어때?
    나는 이렇게 간단하게 동영상 채팅 소프트웨어를 만들 수 있을 줄 몰랐기 때문에 몇 시간 안에 만들 수 있을 것이라고 생각한다.
    WebRTC를 업무적으로 처리하니까 배운다는 의미도 있지만 그 일대가 다 잘해서 아무것도 못 배울 것 같아서...
    그것은 물론이고, 나는 동기로부터 FB로부터 편안한 온라인 점심 환경을 조정하고 싶다.

    참고 자료

  • 공식 문서
  • Building a Video Chat App with Next.js, 100ms, and TailwindCSS
  • 샘플 코드
  • 좋은 웹페이지 즐겨찾기