라이브 스트리밍 (AWS-IVS) 개발기 - 3

박상하·2025년 5월 8일

1년차

목록 보기
14/26
post-thumbnail

AWS IVS 독립성 (Player, Chat, Broadcast)

AWS IVS의 장점이라고 생각되는 부분은 Player, Chat, Broadcast가 각각 독립적이라는 점이다.

우리는 AWS IVS가 제공하는 SDK를 보면 다음과 같다.

크게 3가지 SDK 를 제공하는데 Player, Chat, Broadcast 이다. 사용해보면 각각 SDK 가 독립적이라 만약 aws ivs의 Player만 사용하고 Chat은 다른 플랫폼을 사용할거야! 라고 해도 문제가 되지 않는다.

우리 서비스는 모두 aws ivs를 사용했다. 다른 chat 플랫폼을 사용했을 때 이점을 찾지 못했기 때문이다.

하나씩 구현과정을 살펴보자.

이번 포스팅에서는 Broadcast를 구현해보자!!

Broadcast 기본 구현

공식홈페이지를 기준으로 설명하겠다.

npm install amazon-ivs-web-broadcast

먼저 sdk를 설치해준다.

const client = IVSBroadcastClient.create({
   // Enter the desired stream configuration
   streamConfig: IVSBroadcastClient.BASIC_LANDSCAPE,
   // Enter the ingest endpoint from the AWS console or CreateChannel API
   ingestEndpoint: 'UNIQUE_ID.global-contribute.live-video.net',
});

Stream에 연결하는건 간단하다. 다음과 같이 streamConfig와 ingestEndpoint를 넣어주면된다.

streamConfig는 stream에 관련된 설정사항을, ingestEndpoint에는 해당 스트리밍 채널의 엔드포인트 값을 넣어주면된다.

const client = IVSBroadcastClient.create({
   // Enter the custom stream configuration
   streamConfig: {
      maxResolution: {
         width: 1080,
         height: 1920,
     },
     maxFramerate: 30,
     /**
      * maxBitrate is measured in kbps
      */
     maxBitrate: 3500,
   },
   // Other configuration . . .
});

디테일한 스트리밍 설정이 가능하다.

일단 방송을 하려는 디바이스에 audio와 video에 대한 허용이 필요하다.

async function handlePermissions() {
   let permissions = {
       audio: false,
       video: false,
   };
   try {
       const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
       for (const track of stream.getTracks()) {
           track.stop();
       }
       permissions = { video: true, audio: true };
   } catch (err) {
       permissions = { video: false, audio: false };
       console.error(err.message);
   }
   // If we still don't have permissions after requesting them display the error message
   if (!permissions.video) {
       console.error('Failed to get video permissions.');
   } else if (!permissions.audio) {
       console.error('Failed to get audio permissions.');
   }
}

그리고 방송을 시작하는 코드는 아까 전에 생성한 client를 가지고 방송을 시작하자

client
   .startBroadcast(streamKey)
   .then((result) => {
       console.log('I am successfully broadcasting!');
   })
   .catch((error) => {
       console.error('Something drastically failed while broadcasting!', error);
   });

결과 코드

// 일부코드

    const [facingMode, setFacingMode] = React.useState<'user' | 'enviroment'>('user');

    // 카메라 오디오 허용
    async function handlePermissions() {
        let permissions = {
            audio: false,
            video: false,
        };
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
            for (const track of stream.getTracks()) {
                track.stop();
            }
            permissions = { video: true, audio: true };
        } catch (err: any) {
            permissions = { video: false, audio: false };
            console.error(err.message);
        }

        if (!permissions.video) {
            console.error('Failed to get video permissions.');
        } else if (!permissions.audio) {
            console.error('Failed to get audio permissions.');
        }
    }


    useEffect(() => {
        handlePermissions();

        const setupBroadcast = async () => {
            if (typeof window === 'undefined') return;

            const { default: IVSBroadcastClient }: any = await import('amazon-ivs-web-broadcast');

            const client = IVSBroadcastClient.create({
                streamConfig: IVSBroadcastClient.BASIC_LANDSCAPE,
                ingestEndpoint: '엔드포인트',
            });

            const previewEl = document.getElementById('preview') as HTMLCanvasElement;
            if (previewEl) {
                client.attachPreview(previewEl);
            }

            const devices = await navigator.mediaDevices.enumerateDevices();

            let stream;
            if (!isMobile) {
                // 💻 PC에서는 DroidCam 사용
                const videoDevices = devices.filter(d => d.label === 'DroidCam Video');
                if (videoDevices.length > 0) {
                    stream = await navigator.mediaDevices.getUserMedia({
                        video: { deviceId: { exact: videoDevices[0].deviceId } },
                        audio: true,
                    });

                    client.addVideoInputDevice(stream, 'camera', { index: 0 });
                } else {
                    console.warn('DroidCam not found, using default camera');
                }
            } else {
                // 📱 모바일에서는 기본 전면 카메라 사용

                stream = await navigator.mediaDevices.getUserMedia({
                    video: { facingMode: { ideal: facingMode } },
                    audio: true,
                });
                client.addVideoInputDevice(stream, 'camera', { index: 0 });
            }

            startBroadcastRef.current = () => {
                client
                    .startBroadcast('스트림 키')
                    .then(() => {
                        console.log('I am successfully broadcasting!');
                    })
                    .catch(error => {
                        console.error('Broadcast failed!', error);
                    });
            };

            stopBroadcastRef.current = () => {
                client.stopBroadcast();
                console.log('방송 멈춤!');
            };
        };

        setupBroadcast();
    }, []);

결과적으로 이런 캠을 띄우고 방송을 시작하고 멈출 수 있다.

0개의 댓글