<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Junpyeong Kim</title>
    <description>The latest articles on DEV Community by Junpyeong Kim (@junpyeongkim).</description>
    <link>https://dev.to/junpyeongkim</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1010299%2Fe08057fd-42b2-4802-989e-79f8f62998be.jpg</url>
      <title>DEV Community: Junpyeong Kim</title>
      <link>https://dev.to/junpyeongkim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/junpyeongkim"/>
    <language>en</language>
    <item>
      <title>Unity에서 라이브 스트리밍 - 실시간 게임 브로드캐스팅 (Part 2) (Live Streaming from Unity - Broadcasting a Game in Real-Time (Part 2))</title>
      <dc:creator>Junpyeong Kim</dc:creator>
      <pubDate>Thu, 09 May 2024 01:33:32 +0000</pubDate>
      <link>https://dev.to/aws/unityeseo-raibeu-seuteuriming-silsigan-geim-beurodeukaeseuting-part-2-live-streaming-from-unity-broadcasting-a-game-in-real-time-part-2-4anb</link>
      <guid>https://dev.to/aws/unityeseo-raibeu-seuteuriming-silsigan-geim-beurodeukaeseuting-part-2-live-streaming-from-unity-broadcasting-a-game-in-real-time-part-2-4anb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;이 블로그 포스트는 &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;(Amazon IVS Developer Evangelist)이 포스팅한 &lt;a href="https://dev.to/aws/live-streaming-from-unity-with-amazon-ivs-part-1-52nc"&gt;Live Streaming from Unity with Amazon IVS - Part 1&lt;/a&gt;의 한국어 번역입니다.&lt;br&gt;
(This is the Korean translation of Amazon IVS Developer Evangelist, &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;'s &lt;a href="https://dev.to/aws/live-streaming-from-unity-with-amazon-ivs-part-1-52nc"&gt;Live Streaming from Unity with Amazon IVS - Part 1&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이 포스팅에서는 Unity에서 제작한 게임을 Amazon IVS(Amazon Interactive Video Service)에서 제공하는 실시간 라이브 스트림으로 직접 브로드캐스팅하는 방법을 살펴보겠습니다. 이 포스팅에서는 Amazon IVS Stage를 만들고, 해당 Stage로 브로드캐스팅하는 데 필요한 토큰을 생성하는 등 향후 포스팅에서 재사용될 몇 가지 주제를 다루기 때문에 이 시리즈의 다른 포스팅보다 내용이 조금 더 많을 것입니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  시작하기
&lt;/h2&gt;

&lt;p&gt;이 포스팅에서는 Unity Hub에서 학습용 템플릿으로 제공되는 'Karting Microgame'을 활용하겠습니다.&lt;/p&gt;

&lt;p&gt;Unity Hub에서 'New Project'를 클릭하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivab63ghinefymhqgd9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivab63ghinefymhqgd9t.png" alt="New project" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;왼쪽 사이드바에서 'Learning'을 클릭하고 'Karting Microgame'을 선택한 다음, 프로젝트 이름을 &lt;code&gt;ivs-rtx-broadcast-demo&lt;/code&gt;로 지정하고 'Create project'를 클릭하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7qr3gzcflhbiq1ik51d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7qr3gzcflhbiq1ik51d.png" alt="Create project" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  WebRTC 지원 추가하기
&lt;/h2&gt;

&lt;p&gt;Amazon IVS Stage로 브로드캐스팅(하고 Stage로부터 재생)하려면 WebRTC가 사용됩니다. 다행히도 이를 위해 사용할 수 있는 훌륭한 &lt;a href="https://docs.unity3d.com/Packages/com.unity.webrtc@3.0/manual/index.html" rel="noopener noreferrer"&gt;Unity WebRTC package&lt;/a&gt;가 있으며 Amazon IVS가 &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;이제 WHIP 프로토콜을 지원하므로&lt;/a&gt;, 이를 활용하여 게임에서 직접 브로드캐스팅할 수 있습니다.&lt;/p&gt;

&lt;p&gt;Karting 데모를 위해 WebRTC 패키지를 설치하려면 Window -&amp;gt; Package Manager로 이동하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqzwvwpjja5ek5xrgce9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqzwvwpjja5ek5xrgce9.png" alt="Unity Package Manager" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Package Manager 대화 상자에서 'Add package from git URL'를 선택합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz4hec3uonc72w19os5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkz4hec3uonc72w19os5a.png" alt="Add package from git URL" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;com.unity.webrtc@3.0.0-pre.7&lt;/code&gt; 을 Git URL로 입력하고 'Add'를 클릭합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnb4lgjmny5xuomx1vv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnb4lgjmny5xuomx1vv4.png" alt="Add the Git URL" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ 이 데모는 테스트를 거쳤으며 위에 나열된 패키지 버전에서 작동하는 것으로 알려져 있습니다. 이 글을 읽는 시점에는 최신 버전이 아닐 수도 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;설치가 완료되면 Package Manager 대화 상자에 WebRTC 패키지 세부 정보가 표시됩니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk9z3p7xxeazjrp1etcq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk9z3p7xxeazjrp1etcq.png" alt="WebRTC package details" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;게임플레이를 퍼블리시하는 데 필요한 카메라와 스크립트를 추가하기 전에, Amazon IVS Stage를 생성하고 Stage로 퍼블리시하는 데 필요한 참여자 토큰을 생성하는 방법을 설정해야 합니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 생성
&lt;/h2&gt;

&lt;p&gt;Amazon IVS Stage에서는 최대 12명의 브로드캐스터가 최대 10,000명의 시청자에게 실시간 라이브 스트리밍을 할 수 있습니다. 모든 데모에서 이 Stage를 재사용할 것이므로 AWS Management Console을 통해 수동으로 생성하겠습니다. 모든 플레이어에게 이 기능을 통합하기로 결정한다면, AWS SDK를 통해 프로그래밍 방식으로 Stage를 생성하고 백엔드 서비스에서 현재 플레이어의 ARN(Amazon Resource Name)을 검색해야할 것입니다. 우리는 단지 작동 방식을 배우는 중이므로 수동으로 생성하고 데모 게임에 ARN을 하드코딩해도 아무런 문제가 없습니다.&lt;/p&gt;

&lt;p&gt;AWS Management Console에서, 'Amazon Interactive Video Service'를 검색하세요. Amazon IVS Console 랜딩 페이지에서 'Amazon IVS Stage'를 선택하고 'Get Started'를 클릭하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xz9yjlq1bpysos8ume0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xz9yjlq1bpysos8ume0.png" alt="Get started" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stage 이름을 입력하고 'Create statge'를 클릭하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm3r7jgkkvntyflgpmgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm3r7jgkkvntyflgpmgi.png" alt="Create stage details" width="800" height="589"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이제 Stage가 준비되었습니다! Stage 세부 정보 페이지에서 Stage ARN을 가져옵니다. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0odqqmmlvpqfds1fka3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0odqqmmlvpqfds1fka3.png" alt="Stage details" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이제 토큰을 생성해야 합니다.&lt;/p&gt;

&lt;h1&gt;
  
  
  참가자 토큰
&lt;/h1&gt;

&lt;p&gt;Amazon IVS Stage의 모든 참가자 - 브로드캐스터와 시청자 모두 - 는 Stage에 연결하기 위해 참가자 토큰이 필요합니다. 이것은 JWT 토큰으로, 사용자를 인증하는데 사용되고 &lt;code&gt;userid&lt;/code&gt;와 같은 정보와 참가자에게 부여된 모든 기능(예: &lt;code&gt;PUBLISH&lt;/code&gt; 및 &lt;code&gt;SUBSCRIBE&lt;/code&gt;)을 포함합니다. 이러한 토큰을 수동으로 생성하고 Unity 코드에 반복적으로 붙여넣으려면 시간이 많이 걸리므로 AWS SDK를 사용하여 이러한 토큰을 생성하는 독립형 서비스를 만드는 것이 좋습니다. 저는 이와 같은 데모를 많이 제작하기 때문에 토큰 생성을 처리하기 위해 AWS Lambda를 배포했습니다. 여러분이 아직 이렇게 할 준비가 되지 않았다면, 로컬에서 [선호하는 언어]용 AWS SDK를 사용하는 서비스를 만들고 &lt;code&gt;CreateParticipantToken&lt;/code&gt;(&lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeAPIReference/API_CreateParticipantToken.html" rel="noopener noreferrer"&gt;문서&lt;/a&gt;)을 활용하세요. 저는 JavaScript를 선호하므로 제 함수는 JavaScript(v3) 용 AWS SDK를 사용하고 &lt;code&gt;CreateParticipantTokenCommand&lt;/code&gt;(&lt;a href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ivs-realtime/command/CreateParticipantTokenCommand/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;)를 실행합니다. &lt;/p&gt;

&lt;p&gt;이를 수행하는 가장 기본적인 방법은 디렉터리를 생성하고 다음 종속성을 설치하는 것입니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @aws-sdk/client-ivs-realtime@latest @aws-sdk/credential-providers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;그런 다음 &lt;code&gt;index.js&lt;/code&gt;라는 파일을 생성합니다. 이 파일에서는 &lt;code&gt;/token&lt;/code&gt;이라는 하나의 경로에 응답하는 Node.js를 이용한 매우 기본적인 웹 서버를 실행할 것입니다. 이 경로는 토큰을 생성하여 JSON으로 반환합니다. 참고로, &lt;code&gt;[YOUR STAGE ARN]&lt;/code&gt; 대신에 여러분의 Stage ARN을 입력해야 합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromIni&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/credential-providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CreateParticipantTokenCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IVSRealTimeClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-ivs-realtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ivsRealtimeClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IVSRealTimeClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;fromIni&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recursivecodes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createStageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createStageTokenRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreateParticipantTokenCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createStageTokenResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ivsRealtimeClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createStageTokenRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;createStageTokenResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createStageToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenResponse&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;404 Not Found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;node index.js&lt;/code&gt;로 실행하고 &lt;code&gt;http://localhost:3000/token&lt;/code&gt;을 호출하여 토큰을 생성합니다. 토큰이 필요할 때마다 Unity에서 이 엔드포인트를 사용할 것입니다. 다음은 토큰이 어떻게 생성되는지 보여주는 예시입니다:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"stageArn": "[YOUR STAGE ARN]", "userId": "123456", "capabilities": ["PUBLISH", "SUBSCRIBE"], "attributes": {"username": "todd"}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  http://localhost:3000/token | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이 명령은 다음과 같은 결과를 보여줍니다:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"httpStatusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"requestId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cfId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attempts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"totalRetryDelay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"participantToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"todd"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"PUBLISH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"SUBSCRIBE"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expirationTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-01-19T15:11:32.000Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"participantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bWO1wUhGopye"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ....[truncated]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1705605092467"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  카메라 추가하기
&lt;/h2&gt;

&lt;p&gt;이제 Stage와 토큰을 생성하는 방법이 생겼으니, Stage에 게임플레이를 브로드캐스팅하는 데 사용할 새 카메라를 추가할 수 있습니다.  Unity에서 'Main Scene'을 확장해서 &lt;code&gt;CinemachineVirtualCamera&lt;/code&gt;를 찾습니다. 이 카메라는 Karting Microgame 프로젝트에서 플레이어의 카트가 코스를 주행할 때 트랙 주변을 따라가는 데 사용됩니다. &lt;code&gt;CinemachineVirtualCamera&lt;/code&gt;를 마우스 오른쪽 버튼으로 클릭하고 &lt;code&gt;Camera&lt;/code&gt;를 추가합니다. 저는 &lt;code&gt;WebRTCPublishCamera&lt;/code&gt;라고 이름을 지었습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6a7obnedx0vqft7ue2o4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6a7obnedx0vqft7ue2o4.png" alt="Add camera" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;다음으로, 새로 생성한 카메라를 선택하고 'Inspector' 탭의 하단으로 스크롤합니다. 'Audio Listener'를 선택 해제하지 않으면 하나의 Scene에 여러 오디오 리스너가 있다는 오류가 콘솔에 표시됩니다. 이를 선택 해제하고, 'Add Component'를 클릭합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52qij16nhve5y71uumvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52qij16nhve5y71uumvs.png" alt="Camera inspector" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;'Add Component' 메뉴에서 'New Script'를 선택하고 스크립트 이름을 &lt;code&gt;WebRTCPublish&lt;/code&gt;로 지정합니다. 'Create and Add'를 클릭합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp3xzu3aaaal0nd0tjro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp3xzu3aaaal0nd0tjro.png" alt="Add camera script" width="800" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;스크립트가 추가되면 스크립트를 두 번 클릭하여 VS Code (또는 여러분이 설정한 편집기)에서 엽니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd25rh4iprb7a9vsgpvoj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd25rh4iprb7a9vsgpvoj.png" alt="Edit script" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이제 카메라를 Stage로 브로드캐스트하는데 사용할 스크립트를 편집할 수 있습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon IVS Stage로 카메라 브로드캐스트하기
&lt;/h2&gt;

&lt;p&gt;이제 Stage 토큰을 가져오고 카메라를 Stage에 게시하기 위한 WebRTC 연결을 설정하는 데 필요한 로직을 포함하도록 &lt;code&gt;WebRTCPublish.cs&lt;/code&gt; 스크립트를 수정할 수 있습니다.&lt;/p&gt;

&lt;p&gt;토큰 생성 서비스의 요청과 응답을 처리하는 데 도움이 되는 몇 가지 클래스를 만들겠습니다. 별도의 파일을 사용할 수도 있지만, 지금은 모든 것을 한 곳에 보관하기 위해 동일한 파일 내에 정의합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParticipantToken&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;participantId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;expirationTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ParticipantToken&lt;/span&gt; &lt;span class="nf"&gt;CreateFromJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonUtility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromJson&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ParticipantToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StageToken&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ParticipantToken&lt;/span&gt; &lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;StageToken&lt;/span&gt; &lt;span class="nf"&gt;CreateFromJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonUtility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromJson&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StageToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StageTokenRequestAttributes&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StageTokenRequestAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serializable&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StageTokenRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;StageTokenRequestAttributes&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StageTokenRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StageTokenRequestAttributes&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stageArn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;다음으로 게임 오디오를 브로드캐스트하기 위해 &lt;code&gt;AudioListener&lt;/code&gt;가 필요하다고 클래스에 Annotation을 추가해야 합니다. 또한 스크립트에서 사용할 몇 가지 변수를 선언할 것입니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;RequireComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AudioListener&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebRTCPublish&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;RTCPeerConnection&lt;/span&gt; &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;MediaStreamTrack&lt;/span&gt; &lt;span class="n"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;AudioStreamTrack&lt;/span&gt; &lt;span class="n"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Camera&lt;/span&gt; &lt;span class="n"&gt;cam&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ParticipantToken&lt;/span&gt; &lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이제 토큰 생성 서비스를 호출하고 토큰을 요청할 비동기 함수를 만들어 보겠습니다. 이 함수는 &lt;code&gt;WebRTCPublish&lt;/code&gt; 클래스 안에서 정의하겠습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StageToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStageToken&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityWebRequest&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:3000/token"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;StageTokenRequest&lt;/span&gt; &lt;span class="n"&gt;tokenRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StageTokenRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"[YOUR STAGE ARN]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="m"&gt;1440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"PUBLISH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SUBSCRIBE"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StageTokenRequestAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ivs-rtx-broadcast-demo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uploadHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UploadHandlerRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASCII&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JsonUtility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenRequest&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DownloadHandlerBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kHttpVerbPOST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendWebRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;StageToken&lt;/span&gt; &lt;span class="n"&gt;stageToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateFromJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stageToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;participantToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stageToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stageToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Start()&lt;/code&gt; 메서드 내에서 &lt;code&gt;WebRTC.Update()&lt;/code&gt; 코루틴을 시작하고, 새 &lt;code&gt;RTCPeerConnection&lt;/code&gt;을 설정하고, 카메라를 가져와서 그 출력을 &lt;code&gt;peerConnection&lt;/code&gt;에 추가하고, 게임 오디오도 추가하겠습니다. 그런 다음 잠시 후에 정의할 &lt;code&gt;DoWhip()&lt;/code&gt;이라는 코루틴을 시작하겠습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;StartCoroutine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebRTC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="n"&gt;peerConnection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RTCPeerConnection&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;OnIceConnectionChange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Peer Connection: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="n"&gt;cam&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="n"&gt;videoTrack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CaptureStreamTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;720&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;AudioListener&lt;/span&gt; &lt;span class="n"&gt;audioListener&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AudioListener&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="n"&gt;audioTrack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AudioStreamTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audioListener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Loopback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;StartCoroutine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;DoWHIP&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;토큰을 가져오고, 로컬 SDP를 생성한 다음, 이를 전달하여 원격 SDP를 검색하는 &lt;code&gt;DoWhip()&lt;/code&gt;을 정의해 보겠습니다 (결국 &lt;code&gt;peerConnection&lt;/code&gt;에서 이를 설정하여 WebRTC 연결 프로세스를 완료합니다). &lt;code&gt;Authorization&lt;/code&gt; 헤더에 &lt;code&gt;Bearer&lt;/code&gt; 값으로 토큰을 전달하여 SDP를 검색하기 위해, Amazon IVS 글로벌 WHIP 엔드포인트(&lt;a href="https://global.whip.live-video.net/" rel="noopener noreferrer"&gt;https://global.whip.live-video.net/&lt;/a&gt;) 를 사용할 것입니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;IEnumerator&lt;/span&gt; &lt;span class="nf"&gt;DoWHIP&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;getStageTokenTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetStageToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WaitUntil&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getStageTokenTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCompleted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;participantId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;offer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateOffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;offerDesc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Desc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;opLocal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;offerDesc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opLocal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filteredSdp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;sdpLine&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Desc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sdp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\r\n"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;sdpLine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a=extmap"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;filteredSdp&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;sdpLine&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\r\n"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnityWebRequest&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://global.whip.live-video.net/"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uploadHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UploadHandlerRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASCII&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filteredSdp&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DownloadHandlerBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kHttpVerbPOST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/sdp"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendWebRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;UnityWebRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RTCSessionDescription&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RTCSdpType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sdp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;opRemote&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetRemoteDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;opRemote&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opRemote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opRemote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이제 게임을 실행해서 Unity 콘솔에서 토큰 확인 및 연결 설정되었는지 확인할 준비가 되었습니다. Unity에서 &lt;code&gt;play&lt;/code&gt; 버튼을 눌러 게임을 실행하고 콘솔을 확인합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7clnema487nibglxps1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7clnema487nibglxps1n.png" alt="Unity console" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;결과가 괜찮아 보입니다! 토큰이 생성되었고 피어 연결이 &lt;code&gt;Connected&lt;/code&gt;상태가 되었습니다. 게임플레이가 Stage로 스트리밍되는지 확인해 봅시다.&lt;/p&gt;

&lt;h2&gt;
  
  
  재생 테스트
&lt;/h2&gt;

&lt;p&gt;재생을 테스트하기 위해, &lt;a href="https://aws.github.io/amazon-ivs-web-broadcast/docs/real-time-sdk-guides/introduction" rel="noopener noreferrer"&gt;Amazon IVS Web Broadcast SDK&lt;/a&gt;를 사용하여 무대에 연결하고 참가자가 연결될 때 렌더링할 수 있습니다. 이 부분은 오프라인 연습으로 남겨두고 &lt;a href="https://codepen.io/amazon-ivs/project/editor/ZzWobn" rel="noopener noreferrer"&gt;이 CodePen&lt;/a&gt;에서 테스트해 보겠습니다. 다른 토큰을 생성하여 클립보드에 복사한 다음, CodePen에 붙여넣고 게임이 실행 중이고 스테이지로 방송을 하는 동안 'Join Stage'를 클릭합니다. 모든 것이 잘 진행되었다면 실시간 방송을 볼 수 있을 것입니다!&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/W9IDb_4xRCk"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔊 &lt;strong&gt;참고:&lt;/strong&gt; 위 동영상에서 오디오가 중복되는 것을 볼 수 있는데, 이는 로컬 게임 오디오와 스트림 오디오가 모두 캡처되었기 때문입니다. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  리소스 정리
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Destroy()&lt;/code&gt;에서, 'peerConnection'을 닫아서 삭제하고 오디오 및 비디오 트랙리소스들을 정리할 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OnDestroy"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;peerConnection&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videoTrack&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;videoTrack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audioTrack&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;audioTrack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  어떻게 개선할 수 있을까요?
&lt;/h2&gt;

&lt;p&gt;현재 상태로는 꽤 인상적이라고 말씀드리고 싶습니다! 이 시리즈의 이전 게시물에서 언급한 몇 가지 사항 외에도, 이 시리즈의 다음 게시물에서 다룰 개선 사항이 한 가지 있습니다. 위 동영상에서 이미 눈치채셨을 수도 있습니다. 놓치셨다면 위 동영상에서 실시간 재생을 확인해보시면 스트림에서 경기 타이머와 같은 HUD 요소와 지침과 같은 오버레이가 표시되지 않는 것을 확인할 수 있습니다. 이는 Unity의 캔버스 엘리먼트가 일반적으로 'Screen Space - Overlay'를 사용하도록 구성되어 있어서, 이는 카메라가 게임 화면에 렌더링하는 모든 것 위에 렌더링된다는 것을 의미합니다. 모든 HUD와 UI 요소를 라이브 스트림에 렌더링할 필요가 없을 수도 있으므로(특히 사용자별 데이터를 표시할 수 있는 화면의 경우) 반드시 나쁜 것은 아닙니다. 이는 게임마다 사례별로 처리될 수 있지만, 전체 UI를 렌더링해야 하는 경우에는 이 시리즈의 다음 포스팅에서 이 문제를 해결하는 한 가지 접근 방식을 살펴보겠습니다.&lt;/p&gt;

&lt;p&gt;또 다른 개선 사항은 게임이 시작될 때 자동으로 스트림을 실행하는 대신 스트림을 시작/중단할 수 있는 UI 버튼을 추가하는 것입니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  요약
&lt;/h2&gt;

&lt;p&gt;(다소 긴) 이번 포스팅에서는, Unity로 만든 게임에서 Amazon IVS 실시간 Stage로 직접 방송하는 방법에 대해 알아보았습니다. 이 시리즈의 다음 포스팅에서는 반복하지 않을 Stage 생성 및 토큰 생성과 같은 몇 가지 소개 주제를 다루었으므로 복습이 필요한 경우 이 포스팅을 다시 참조하시기 바랍니다.&lt;/p&gt;

&lt;p&gt;이 데모에 사용한 전체 스크립트를 보고 싶으시다면 GitHub에서 &lt;a href="https://gist.github.com/recursivecodes/e948b81e53bf9259b981c88e9fc216fa" rel="noopener noreferrer"&gt;이 Gist&lt;/a&gt;를 확인하세요. 제 프로덕션 토큰 엔드포인트는 &lt;code&gt;POST&lt;/code&gt; 메서드를 사용하며 Stage ARN, 사용자 ID 등을 전송할 수 있으므로 이 스크립트는 해당 POST 요청을 모델링하기 위한 몇 가지 추가 클래스가 포함되어 있다는 점에 유의하세요. 여러분의 자체 엔드포인트에서 작동하도록 수정해야 할 수도 있지만 이 스크립트로 시작할 수 있습니다.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>gamedev</category>
      <category>unity3d</category>
    </item>
    <item>
      <title>Unity에서 Amazon IVS로 라이브 스트리밍하기 - Part 1 (Live Streaming from Unity with Amazon IVS - Part 1)</title>
      <dc:creator>Junpyeong Kim</dc:creator>
      <pubDate>Thu, 09 May 2024 01:33:11 +0000</pubDate>
      <link>https://dev.to/aws/unityeseo-amazon-ivsro-raibeu-seuteuriminghagi-part-1-live-streaming-from-unity-with-amazon-ivs-part-1-42hp</link>
      <guid>https://dev.to/aws/unityeseo-amazon-ivsro-raibeu-seuteuriminghagi-part-1-live-streaming-from-unity-with-amazon-ivs-part-1-42hp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;이 블로그 포스트는 &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;(Amazon IVS Developer Evangelist)이 포스팅한 &lt;a href="https://dev.to/aws/live-streaming-from-unity-with-amazon-ivs-part-1-52nc"&gt;Live Streaming from Unity with Amazon IVS - Part 1&lt;/a&gt;의 한국어 번역입니다.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;(This is the Korean translation of Amazon IVS Developer Evangelist, &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;'s &lt;a href="https://dev.to/aws/live-streaming-from-unity-with-amazon-ivs-part-1-52nc"&gt;Live Streaming from Unity with Amazon IVS - Part 1&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;'Unity에서 Amazon IVS로 라이브 스트리밍하기' 시리즈에 오신 것을 환영합니다 - 이 시리즈는 게임 개발자가 Amazon IVS (Amazon Interactive Video Service)를 이용하여 실시간 인터랙티브 스트리밍을 Unity로 제작한 게임에 직접 통합할 수 있는 다양한 방법을 안내하기 위해 마련되었습니다. 이 소개 포스팅에서는 Amazon IVS를 소개하고, 게임에서 통합 스트리밍 경험을 제공해야 하는 &lt;strong&gt;이유&lt;/strong&gt;에 대해 설명하며, 이 시리즈의 향후 포스팅에 대한 개요를 제공합니다. 그럼 시작해 보겠습니다!&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/FXpQa86y_bs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon IVS가 무엇입니까?
&lt;/h2&gt;

&lt;p&gt;Amazon IVS를 처음 사용하시는 분들을 위해 간략하게 설명해 드리겠습니다. Amazon IVS는 Twitch를 지원하는 것과 동일한 라이브 스트리밍 기술과 글로벌 인프라를 사용하여 개발자가 자체 애플리케이션을 구축할 수 있도록 지원하는 AWS 서비스입니다. Amazon IVS는 저지연(2~5초) RTMPS 기반 스트리밍, 실시간(300ms 미만) WebRTC 기반 스트리밍, 고성능 및 확장성이 뛰어난 WebSocket 기반 채팅이라는 세 가지 주요 기능을 제공합니다.&lt;/p&gt;

&lt;p&gt;이 블로그 시리즈에서, Amazon IVS는 게임 개발자들이 플레이어들을 위한 매우 맞춤화되고 밀접하게 통합된 라이브 스트리밍 애플리케이션을 구축할 수 있도록 도와줍니다. 이를 통해 더 많은 참여와 전반적인 경험에 대한 더 많은 제어가 가능해집니다. 이는 이전에 본 적 없는 다이나믹하고 인터랙티브한 게임 플레이를 이끌어낼 것입니다. 수익화, 모더레이션(Moderation), 재생 품질, 시청자 상호 작용, 채팅 통합 등 많은 기능을 모두 개발자가 제어할 수 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;a href="https://ivs.rocks/" rel="noopener noreferrer"&gt;https://ivs.rocks/&lt;/a&gt;에서 Amazon IVS에 대해 자세히 알아보세요.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  게임에서 직접 라이브 스트리밍하는 이유는 무엇일까요?
&lt;/h2&gt;

&lt;p&gt;게임 스트리밍은 &lt;strong&gt;매우 인기&lt;/strong&gt;가 있습니다. 하지만, 여러분은 이미 이것을 알고 있습니다! 여러분의 플레이어들은 이미 OBS와 같은 소프트웨어를 통해 라이브 스트리밍을 하고 있을 수도 있고, Twitch에서 발표한 &lt;a href="https://blog.twitch.tv/en/2024/01/08/introducing-the-enhanced-broadcasting-beta" rel="noopener noreferrer"&gt;개선된 방송하기&lt;/a&gt; 기능처럼, 일부 플레이어에게는 항상 사용 가능한(때로는 선호되는) 스트리밍 방식이 될 것입니다. 하지만 솔직히 말해서 OBS 설정은 일부 플레이어에게 쉬운 일이 아닙니다. 비트레이트, B-프레임, 코덱, 키프레임 간격 등은 단순히 게임플레이 시청자들에게 스트리밍하려는 사람에게는 부담스러울 수 있습니다.&lt;/p&gt;

&lt;p&gt;게임에서 플레이어들에게 직접 스트리밍할 수 있는 기회를 제공함으로써, 일부 플레이어들에게는 진입 장벽을 없애주면서 모든 플레이어들에게는 시청자들로부터 피드백을 통해 게임플레이를 향상시킬 수 있는 기회를 제공할 수 있습니다. 시청자를 위한 다양한 카메라 각도(boss cam)는 어떨까요?  시청자가 플레이어의 캠에 영향을 주지 않고 카메라를 팬/틸트/줌/회전하여 원하는 각도로 시청할 수 있는 사용자 제어 카메라는 어떨까요? (네, 정말 가능합니다!) 채팅이나 설문조사에 따라 환경이나 NPC의 행동을 수정하는 것은 어떨까요? 네, 스트리밍 경험을 게임에 직접 통합하면 이 모든 것(그리고 훨씬 더 많은 것)이 가능합니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  시리즈 개요
&lt;/h2&gt;

&lt;p&gt;여러분은 이미 유니티로 만든 게임에서 직접 라이브 스트리밍을 할 수 있는 가능성에 대해 꽤나 푹 빠져있을⚙️ 것으로 확신합니다. 이 시리즈에서는 다음과 같은 주제를 다룰 예정입니다:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;소개 (이 글)&lt;/li&gt;
&lt;li&gt;Unity에서 Amazon IVS Real-Time으로 브로드캐스팅하기&lt;/li&gt;
&lt;li&gt;향상된 실시간 게임 브로드캐스팅하기 (HUD 포함)&lt;/li&gt;
&lt;li&gt;Unity 게임에 Amazon IVS Chat 통합하기&lt;/li&gt;
&lt;li&gt;동적 및 대화형 스트림 (사용자 제어 카메라, 동적 환경 및 목표물)&lt;/li&gt;
&lt;li&gt;여러 대의 카메라를 실시간으로 방송하기 (시청자는 서로 볼수 있거나 그 둘 사이를 전환할 수 있음)&lt;/li&gt;
&lt;li&gt;Unity에서 실시간 스트림 재생하기 (비디오로 그룹 채팅 가능)&lt;/li&gt;
&lt;li&gt;Meta의 Quest VR 헤드셋에서 실시간 방송하기&lt;/li&gt;
&lt;li&gt;게임을 &lt;strong&gt;Twitch로 직접 방송하기&lt;/strong&gt; (저지연)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  면책 조항
&lt;/h2&gt;

&lt;p&gt;저는 20년 동안 풀스택 개발자로 일한 경력이 있지만 게임 개발자는 아니라는 점을 말씀드리고 싶습니다. 앞으로 제작할 모든 것들은 &lt;a href="https://unity.com/download" rel="noopener noreferrer"&gt;Unity Hub&lt;/a&gt;에서 제공되는 기존 데모 게임을 기반으로 합니다. 나는 이 데모를 만드는 데 많은 시간을 보냈지만, Unity를 사용하여 게임을 만드는 것과 관련하여 나에게 익숙하지 않은 몇 가지 개념들이 있을 수 있습니다. 최선을 다해 설명하겠지만, 기억해주세요 - 저는 게임 개발🎮 전문가가 아닙니다!&lt;/p&gt;

&lt;h2&gt;
  
  
  사전 요구 사항
&lt;/h2&gt;

&lt;p&gt;이 시리즈를 따라 저와 함께 빌드하려면 Unity Hub를 설치해야 합니다. 또한 실시간 Stage를 생성하고 해당 Stage로 브로드캐스팅하는 데 필요한 토큰과 이 시리즈에서 사용할 수 있는 기타 리소스를 생성할 AWS 계정이 필요합니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  요약
&lt;/h2&gt;

&lt;p&gt;이 시리즈에서는 다룰 내용이 많으며 모두 매우 흥미로운 내용입니다. 이 시리즈를 마치면, 매력적이고 인터랙티브하며 역동적인 라이브 스트리밍 플랫폼을 만들어서 이것을 Unity로 만든 게임에 통합할 준비가 될 것입니다. 다음 포스팅으로 이동해서 15분 정도 사용하여 게임을 브로드캐스팅하는 방법을 배워보세요!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>gamedev</category>
      <category>unity3d</category>
    </item>
    <item>
      <title>OBS에서 WHIP을 사용하여 Amazon IVS 실시간 스트림으로 브로드캐스팅하기 (Broadcasting to an Amazon IVS Real-Time Stream with WHIP from OBS)</title>
      <dc:creator>Junpyeong Kim</dc:creator>
      <pubDate>Wed, 24 Apr 2024 08:48:31 +0000</pubDate>
      <link>https://dev.to/aws/obseseo-whipeul-sayonghayeo-amazon-ivs-silsigan-seuteurimeuro-beurodeukaeseutinghagi-broadcasting-to-an-amazon-ivs-real-time-stream-with-whip-from-obs-579b</link>
      <guid>https://dev.to/aws/obseseo-whipeul-sayonghayeo-amazon-ivs-silsigan-seuteurimeuro-beurodeukaeseutinghagi-broadcasting-to-an-amazon-ivs-real-time-stream-with-whip-from-obs-579b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;이 블로그 포스트는 &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;(Amazon IVS Developer Evangelist)이 포스팅한 &lt;a href="https://dev.to/aws/broadcasting-to-an-amazon-ivs-real-time-stream-with-whip-from-obs-p67"&gt;Broadcasting to an Amazon IVS Real-Time Stream with WHIP from OBS&lt;/a&gt;의 한국어 번역입니다.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;(This is the Korean translation of Amazon IVS Developer Evangelist, &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;'s &lt;a href="https://dev.to/aws/broadcasting-to-an-amazon-ivs-real-time-stream-with-whip-from-obs-p67"&gt;Broadcasting to an Amazon IVS Real-Time Stream with WHIP from OBS&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;최근까지 Amazon IVS(Amazon Interactive Video Service) 실시간 Stage로 브로드캐스팅하려면 개발자가 IVS Broadcast SDK(웹 및 모바일) 중 하나를 활용해야 했습니다. 내부적으로, SDK는 사용자의 연결을 초기화하고 사용자의 비디오를 Stage로 브로드캐스팅하는데 필요한 모든 로직을 추상화하고 있습니다. SDK를 이용하면 개발자는 애플리케이션에 실시간 스트리밍 통합을 더 쉽게 할 수 하지만, 궁극적으로는 해당 Stage에 브로드캐스팅하는 최종 사용자 측면에서는 웹 및 모바일 기반 클라이언트 소프트웨어 사용으로만 선택권이 제한되게 됩니다. 이제 드디어, WHIP 호환 인코더 지원이 추가됨으로써 미디어를 실시간 Stage로 게시할 수 있게 되었습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  WHIP??
&lt;/h2&gt;

&lt;p&gt;프로토콜 이름으로는 좀 이상하긴한데, 받아들일께요 🤷🏻‍♂️. 맞아요, 저는 이름 짓는 일을 담당하지 않아서 좋습니다. WHIP(WebRTC-HTTP Ingest Protocol)은 HTTP &lt;code&gt;POST&lt;/code&gt; 요청을 사용하여 SDP(Session Description Protocol) offer와 answer의 일회성 교환 프로세스를 표준화하는 IETF 프로토콜입니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;SDP에 대해 잘 모르시나요?&lt;/strong&gt; &lt;a href="https://webrtcforthecurious.com/docs/02-signaling/#what-is-the-session-description-protocol-sdp" rel="noopener noreferrer"&gt;WebRTC for the Curious&lt;/a&gt;에서 'What is the Session Description Protocol (SDP)?'를 확인해보세요.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이름에서 짐작할 수 있듯이, WHIP 프로토콜은 &lt;strong&gt;Ingest&lt;/strong&gt;(즉, 'Broadcasting' 또는 'Publish')만을 나타냅니다. Egress(즉, 'Viewing' 또는 'Subscribing')를 처리하는 WHEP라는 별도의 프로토콜이 있습니다. 불면증으로 고생하고 있다면 🥱, &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-wish-whip/" rel="noopener noreferrer"&gt;WHIP&lt;/a&gt; 또는 &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-wish-whep/" rel="noopener noreferrer"&gt;WHEP&lt;/a&gt;에 대한 IETF 초안을 전부 읽어보세요.&lt;/p&gt;

&lt;h2&gt;
  
  
  OBS를 사용하여 Amazon IVS Stage로 브로드캐스팅하기
&lt;/h2&gt;

&lt;p&gt;OBS는 화면 전환, 오버레이, 간편한 화면 공유, 오디오 믹싱 등과 같은 고급 제작 기능으로 인해 널리 사용되고 있습니다. OBS에서 Amazon IVS Stage로 브로드캐스팅하려면 사용자는 OBS 버전 30 이상과 Stage 참여자 토큰이 필요합니다. 토큰의 만료 시간은 일반적으로 12시간(기본값)이지만 최대 14일까지 연장할 수 있습니다.&lt;/p&gt;

&lt;p&gt;사용해 보려면, AWS SDK, AWS CLI, 또는 Amazon IVS 관리 콘솔을 통해 Stage 참가자 토큰을 생성하고 OBS의 'Settings' 대화 상자로 이동합니다.&lt;/p&gt;

&lt;p&gt;'Stream' 탭에서 'Service'로 'WHIP'을 선택하고, 'Server'에 &lt;code&gt;https://global.whip.live-video.net&lt;/code&gt;을 입력한 다음, 유효한 Stage 참가자 토큰을 'Bearer Token'에 붙여 넣습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uxyu4hwknhgxx57s1io.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uxyu4hwknhgxx57s1io.png" alt="OBS Stream tab" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;참고: OBS는 WHIP 브로드캐스팅에 Opus 오디오 인코딩이 필요하다고 경고할 것입니다. 이는 예상되었던 것이므로, 계속하려면 'Yes'를 선택하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jgjs3tz6owevw6z38ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jgjs3tz6owevw6z38ia.png" alt="Opus warning" width="544" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;다음으로, 'Output' 탭으로 이동하여 'Output Mode'가 'Advanced'으로 설정되어 있는지 확인하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37oh5uiyhfxx0ul9p06k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37oh5uiyhfxx0ul9p06k.png" alt="Advanced output mode" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;최상의 성능을 위해 'Bitrate'를 &lt;code&gt;2500 Kbps&lt;/code&gt; 이하로 설정하고, 'Keyframe Interval'은 &lt;code&gt;1s&lt;/code&gt; 또는 &lt;code&gt;2s&lt;/code&gt;를 사용하고, 'CPU Usage Preset'은 &lt;code&gt;ultrafast&lt;/code&gt;로, 'Tune'을 &lt;code&gt;zerolatency&lt;/code&gt;로 설정하세요.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xtn0z4pvhpo8ali3qhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xtn0z4pvhpo8ali3qhk.png" alt="Output streaming settings" width="800" height="737"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이제 'Settings' 대화 상자를 종료하고 'Start Streaming'을 클릭하면 Stage로 브로드캐스팅을 시작하게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dydq4khkd9vr2ictb1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4dydq4khkd9vr2ictb1k.png" alt="Streaming with OBS" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;좀 더 자세한 내용은 &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;OBS and WHIP Support&lt;/a&gt; 문서를 참조하세요.&lt;/p&gt;

&lt;h2&gt;
  
  
  GStreamer를 사용하여 Amazon IVS Stage로 브로드캐스팅하기
&lt;/h2&gt;

&lt;p&gt;여러분이 오픈 소스 멀티미디어 프레임워크인 &lt;a href="https://gstreamer.freedesktop.org/" rel="noopener noreferrer"&gt;GStreamer&lt;/a&gt;의 팬이라면, GStreamer에서도 역시 WHIP 지원을 이용할 수 있습니다. 다음은 웹캠과 마이크를 Stage에 게시하는 데 사용할 수 있는 간단한 파이프라인입니다. 이 파이프라인은 MacOS에서 테스트되었지만, 지원되는 모든 OS에 적용될 수 있습니다. 참가자 토큰을 가져와서 &lt;code&gt;IVS_STAGE_TOKEN&lt;/code&gt;에 설정해야 합니다. (또는 토큰을 복사하여 붙여넣어도 됩니다)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gst-launch-1.0 &lt;span class="se"&gt;\&lt;/span&gt;
  avfvideosrc device-index&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; videoconvert &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; x264enc &lt;span class="nv"&gt;tune&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;zerolatency &lt;span class="nv"&gt;bitrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2500 speed-preset&lt;span class="o"&gt;=&lt;/span&gt;ultrafast &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; rtph264pay &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s1"&gt;'application/x-rtp,media=video,encoding-name=H264,payload=97,clock-rate=90000,width=1280,height=720,framerate=30/1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; whip.sink_0 autoaudiosrc &lt;span class="nv"&gt;wave&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; audioconvert &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; opusenc &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; rtpopuspay &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s1"&gt;'application/x-rtp,media=audio,encoding-name=OPUS,payload=96,clock-rate=48000,encoding-params=(string)2'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt; whip.sink_1 &lt;span class="se"&gt;\&lt;/span&gt;
  whipsink &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;whip &lt;span class="se"&gt;\&lt;/span&gt;
  auth-token&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$IVS_STAGE_TOKEN&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  whip-endpoint&lt;span class="o"&gt;=&lt;/span&gt;https://global.whip.live-video.net/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  요약
&lt;/h2&gt;

&lt;p&gt;이번 포스팅에서는, WHIP 호환 인코더를 통해 Amazon IVS 실시간 Stage에 퍼블리싱하는 방법에 대해 알아보았습니다. 이러한 지원은 Amazon IVS를 통한 실시간 스트리밍에 대한 많은 가능성을 보여주고 있습니다. 자세한 내용은 &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;OBS and WHIP Support&lt;/a&gt;의 Amazon IVS 실시간 사용자 가이드 페이지를 참조하세요. 사용 사례에 대한 질문이나 아이디어가 있으면 &lt;a href="https://dev.to/recursivecodes"&gt;Todd Sharp&lt;/a&gt;'s &lt;a href="https://dev.to/aws/broadcasting-to-an-amazon-ivs-real-time-stream-with-whip-from-obs-p67"&gt;Broadcasting to an Amazon IVS Real-Time Stream with WHIP from OBS&lt;/a&gt;에 댓글을 남겨주세요!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>webrtc</category>
      <category>livestreaming</category>
    </item>
    <item>
      <title>Terraform을 이용해서 Amazon IVS Live Streams 및 Chat 배포하기 (Deploy Amazon IVS Live Streams and Chat with Terraform)</title>
      <dc:creator>Junpyeong Kim</dc:creator>
      <pubDate>Tue, 31 Jan 2023 02:12:30 +0000</pubDate>
      <link>https://dev.to/aws/terraformeul-iyonghaeseo-amazon-ivs-live-streams-mic-chat-baepohagi-deploy-amazon-ivs-live-streams-and-chat-with-terraform-2812</link>
      <guid>https://dev.to/aws/terraformeul-iyonghaeseo-amazon-ivs-live-streams-mic-chat-baepohagi-deploy-amazon-ivs-live-streams-and-chat-with-terraform-2812</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Disclaimer&lt;br&gt;
이 블로그 포스트는 Amazon IVS Engineer인 &lt;a href="https://dev.to/kevineady"&gt;Kevin Eady&lt;/a&gt;가 포스팅한 &lt;a href="https://dev.to/aws/deploy-amazon-ivs-live-streams-and-chat-with-terraform-3cml"&gt;Deploy Amazon IVS Live Streams and Chat with Terraform&lt;/a&gt;의 한국어 번역 포스트입니다.&lt;br&gt;
(This blog post is the Korean translation of Amazon IVS Engineer, &lt;a href="https://dev.to/kevineady"&gt;Kevin Eady&lt;/a&gt;'s &lt;a href="https://dev.to/aws/deploy-amazon-ivs-live-streams-and-chat-with-terraform-3cml"&gt;Deploy Amazon IVS Live Streams and Chat with Terraform&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;IaC(Infrastructure as Code)는 사용자 인터페이스를 통해 직접하기 보다는, 코드를 통해 서비스 인프라를 관리하고 프로비저닝하는 방법입니다. 여기에는 서버, 로드 밸런서, 데이터베이스, 네트워크 구성 등과 같은 리소스가 포함될 수 있습니다.&lt;/p&gt;

&lt;p&gt;코드를 사용하여 인프라를 관리함으로써 많은 팀들이 인프라의 버전을 제어하고 리소스 프로비저닝 및 관리를 보다 쉽게 자동화할 수 있습니다. 이는 보다 일관되고 예측 가능한 배포가 가능하므로 많은 팀이 있고 복잡한 인프라가 있는 대규모 조직에서 특히 유용할 수 있습니다. 또한 필요한 경우 변경 사항을 쉽게 롤백할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Hashicorp Terraform&lt;/a&gt;은 인프라를 안전하고 효율적으로 구축, 변경 및 버전 관리하기 위한 오픈 소스 도구입니다. Terraform은 &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" rel="noopener noreferrer"&gt;AWS Provider&lt;/a&gt;를 통해 AWS 리소스를 비롯한 다양한 리소스 유형을 관리하는 데 사용할 수 있습니다. 이 블로그 포스트에서는 Terraform 설치, Amazon IVS(Interactive Video Service) 채널 생성, Amazon S3(Simple Storage Service)에 녹화하기, 채널 보호 활성화 및 IVS 채팅방 생성 과정을 안내합니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform 설치
&lt;/h3&gt;

&lt;p&gt;시작하려면 &lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli#install-terraform" rel="noopener noreferrer"&gt;Terraform tutorial&lt;/a&gt;의 가이드에 따라 Terraform을 설치합니다. 이렇게 하면 &lt;code&gt;terraform&lt;/code&gt; 커맨드라인 인터페이스(CLI)를 사용하여 HCL(HashiCorp Configuration Language)로 작성된 코드를 사용하여 인프라를 배포할 수 있습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS 계정 생성
&lt;/h3&gt;

&lt;p&gt;Amazon IVS를 사용하려면 계정이 있어야 합니다. Amazon은 현재 &lt;a href="https://aws.amazon.com/ivs/pricing/" rel="noopener noreferrer"&gt;AWS Free Tier for Amazon IVS&lt;/a&gt;에 따라 Amazon IVS 무료 평가판을 제공합니다(매월 기본 입력 5시간 및 SD 비디오 출력 100시간 - 그 외 다수).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;프로덕션 애플리케이션에서 Amazon IVS를 실행하는 데 드는 비용이 궁금하십니까? &lt;a href="https://ivs.rocks/calculator" rel="noopener noreferrer"&gt;Amazon IVS Cost Estimator&lt;/a&gt;를 확인하세요!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  AWS Terraform Provider 사용
&lt;/h3&gt;

&lt;p&gt;Terraform은 Provider를 사용하여 API와의 상호 작용을 가능하게 합니다. &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs" rel="noopener noreferrer"&gt;Terraform AWS Provider 설명서&lt;/a&gt;는 AWS 인증 및 리전 선택과 같은 Provider 구성에 대한 세부 정보를 제공합니다. 또한 자격 증명 사용에 대한 가이드와 모범 사례를 제공합니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon IVS에 Terraform 사용하기
&lt;/h2&gt;

&lt;p&gt;Terraform은 다음 리소스 및 데이터 소스를 사용하여 AWS Terraform Provider 버전 &lt;code&gt;v4.40.0&lt;/code&gt;부터 IVS를 완벽하게 지원합니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channels: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivs_channel&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Playback Key Pairs: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_playback_key_pair" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivs_playback_key_pair&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Recording Configurations: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_recording_configuration" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivs_recording_configuration&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Stream Key: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_stream_key" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivs_stream_key&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IVS Channel 만들기
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivs_channel&lt;/code&gt;&lt;/a&gt; 리소스는 S3에 저장하기 또는 재생 권한 부여 등 채널 속성을 구성하기 위한 많은 인수를 지원합니다.이 리소스는 Ingest endpoint(&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel#ingest_endpoint" rel="noopener noreferrer"&gt;&lt;code&gt;ingest_endpoint&lt;/code&gt;&lt;/a&gt;)와 Playback URL(&lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel#playback_url" rel="noopener noreferrer"&gt;&lt;code&gt;playback_url&lt;/code&gt;&lt;/a&gt;) 등의 출력 속성도 가지고 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 0.12"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivs_channel"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"BASIC"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivs_stream_key"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;channel_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_ivs_channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"ingest_endpoint"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_ivs_channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ingest_endpoint&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"stream_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_ivs_stream_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"playback_url"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_ivs_channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playback_url&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;참고: AWS Free Tier에는 Basic 채널 유형만 적용됩니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;terraform apply&lt;/code&gt;를 통해 이 구성을 적용할 때 Terraform은 인프라 Plan을 표시하고 구성을 적용하려면 "&lt;code&gt;yes&lt;/code&gt;"라는 사용자 입력을 필요로 합니다. 이렇게 Plan을 적용하고 나면 출력변수들(ingest_endpoint, stream_key 및 playback_url)이 표시되는것을 볼 수 있습니다.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;➜  terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
 + create
&amp;lt;= read (data resources)

Terraform will perform the following actions:

&lt;/span&gt;&lt;span class="gp"&gt; #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;data.aws_ivs_stream_key.example will be &lt;span class="nb"&gt;read &lt;/span&gt;during apply
&lt;span class="gp"&gt; #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;config refers to values not yet known&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;&amp;lt;= data "aws_ivs_stream_key" "example" {
     + arn         = (known after apply)
     + channel_arn = (known after apply)
     + id          = (known after apply)
     + tags        = (known after apply)
     + value       = (known after apply)
   }

&lt;/span&gt;&lt;span class="gp"&gt; #&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;aws_ivs_channel.example will be created
&lt;span class="go"&gt; + resource "aws_ivs_channel" "example" {
     + arn                         = (known after apply)
     + authorized                  = (known after apply)
     + id                          = (known after apply)
     + ingest_endpoint             = (known after apply)
     + latency_mode                = (known after apply)
     + name                        = (known after apply)
     + playback_url                = (known after apply)
     + recording_configuration_arn = (known after apply)
     + tags_all                    = (known after apply)
     + type                        = (known after apply)
   }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
 + ingest_endpoint = (known after apply)
 + playback_url    = (known after apply)
 + stream_key      = (known after apply)

Do you want to perform these actions?
 Terraform will perform the actions described above.
 Only 'yes' will be accepted to approve.

 Enter a value: yes

aws_ivs_channel.example: Creating...
aws_ivs_channel.example: Creation complete after 3s [id=arn:aws:ivs:us-west-2:326937407773:channel/EmVV0KxDONIR]
data.aws_ivs_stream_key.example: Reading...
data.aws_ivs_stream_key.example: Read complete after 1s [id=arn:aws:ivs:us-west-2:326937407773:stream-key/0Dy6pn6CQhMx]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

ingest_endpoint = "a447f74b0a52.global-contribute.live-video.net"
playback_url = "https://a447f74b0a52.us-west-2.playback.live-video.net/api/video/v1/us-west-2.326937407773.channel.EmVV0KxDONIR.m3u8"
stream_key = "sk_us-west-xxxxxxxxxxxxx"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;ingest_endpoint와 stream_key를 가지고 &lt;a href="https://stream.ivs.rocks/" rel="noopener noreferrer"&gt;Amazon IVS - Web Broadcast Tool&lt;/a&gt;로 이동하여 스트리밍을 시작합니다. 페이지 하단 근처에 있는 "Open settings" 톱니바퀴 아이콘을 클릭합니다…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjitmb67z4alstmnmmxng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjitmb67z4alstmnmmxng.png" alt="Web Broadcast Tool - Open Settings" width="778" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... Ingest endpoint와 Stream key를 입력합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vp0nqmy3bivovh5jj0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vp0nqmy3bivovh5jj0d.png" alt="Web Broadcast Tool - Update Settings" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Save"을 클릭한 다음 "Start Streaming" 버튼을 클릭합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfel7jlzdb551b7tanns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfel7jlzdb551b7tanns.png" alt="Web Broadcast Tool - Start Streaming" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... 그러면 당신의 스트림이 시작됩니다!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftptp6kzp68ulyfcj39gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftptp6kzp68ulyfcj39gw.png" alt="Web Broadcast Tool - Live" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;스트림을 보려면 &lt;a href="https://debug.ivsdemos.com/" rel="noopener noreferrer"&gt;Amazon IVS Player Tester&lt;/a&gt;로 이동하세요. 오른쪽 상단 모서리에 있는 톱니바퀴 아이콘을 클릭합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqh507w7aktehd9ukqjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqh507w7aktehd9ukqjf.png" alt="Player Tester - Open Settings" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... 그리고 IVS Player를 추가합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1thrbj69moksqkyu0f37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1thrbj69moksqkyu0f37.png" alt="Player Tester - Add IVS Player" width="782" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;재생 URL을 입력하고 "Load" 버튼을 클릭하면 라이브 스트림 재생이 시작됩니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0v48vunw3eo7jluefof.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn0v48vunw3eo7jluefof.png" alt="Player Tester - Live Stream" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  S3에 레코드를 추가하기 위해 IVS 채널을 수정
&lt;/h3&gt;

&lt;p&gt;이 예제에서는 Recording Configuration에서 사용할 새로운 S3 Bucket과 대상 Bucket 및 Thumbnail 속성을 지정하는 Recording Configuration을 생성하고, 이전에 생성한 채널에 Recording Configuration을 할당합니다. 이전 예제 설정을 수정해 봅시다.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;provider "aws" {
&lt;/span&gt;   region = "us-west-2"
 }
&lt;span class="gi"&gt;+
+resource "aws_s3_bucket" "example" {
+  bucket_prefix = "tf-ivs-stream-archive-"
+  force_destroy = true
+}
+
+resource "aws_ivs_recording_configuration" "example" {
+  name = "tf-ivs-recording-configuration"
+  lifecycle {
+    create_before_destroy = true
+  }
+  thumbnail_configuration {
+    recording_mode = "INTERVAL"
+    target_interval_seconds = 30
+  }
+  destination_configuration {
+    s3 {
+      bucket_name = aws_s3_bucket.example.id
+    }
+  }
+}
+
&lt;/span&gt; resource "aws_ivs_channel" "example" {
  type = "BASIC"
&lt;span class="gi"&gt;+  recording_configuration_arn = aws_ivs_recording_configuration.example.arn
&lt;/span&gt; }
&lt;span class="err"&gt;
&lt;/span&gt; data "aws_ivs_stream_key" "example" {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;참고: &lt;a href="https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#create_before_destroy" rel="noopener noreferrer"&gt;&lt;code&gt;create_before_destroy&lt;/code&gt;&lt;/a&gt; lifecycle 옵션은 Recording Configuration이 삭제되어야 하는 설정 수정이 발생할 경우에 필요합니다. 왜냐하면, Recording Configuration은 in-place 수정이 불가하고 수정 사항이 존재하는 경우 재생성되어야 하기 때문입니다. Recording Configuration은 채널에서 사용하는 동안 삭제할 수 없으므로, 이 옵션(후속 수정 시)은 이전 Recording Configuration을 삭제하기 전에 새로운 Recording Configuration으로 채널을 업데이트합니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;스트리밍하는 동안 IVS는 생성된 S3 Bucket 내부에 스트림을 저장합니다. 자세한 내용은 &lt;a href="https://docs.aws.amazon.com/ivs/latest/userguide/record-to-s3.html" rel="noopener noreferrer"&gt;Auto-Record to Amazon S3 - Amazon Interactive Video Service&lt;/a&gt;를 참조하십시오.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;참고: 라이브 상태인 채널은 수정할 수 없습니다. Terraform은 라이브 상태인 채널을 수정하려고 시도하는 경우 &lt;code&gt;Unable to perform: ivs:UpdateChannel while resource: &amp;lt;arn&amp;gt; is live&lt;/code&gt;처럼 적절한 오류를 보고합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  재생 권한 부여 기능을 가지는 IVS Channel 만들기
&lt;/h3&gt;

&lt;p&gt;이 예제에서는 &lt;a href="https://aws.amazon.com/kms/" rel="noopener noreferrer"&gt;Amazon Key Management Service(KMS)&lt;/a&gt;를 사용하여 새로운 비대칭 키 쌍을 생성 후, 여기서 생성된 공개 키를 사용하여 새로운 Playback Key Pair를 생성하고, 마지막으로 인증 권한이 추가된 채널을 생성합니다:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_kms_key"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"KMS Key for IVS Playback"&lt;/span&gt;
  &lt;span class="nx"&gt;key_usage&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SIGN_VERIFY"&lt;/span&gt;
  &lt;span class="nx"&gt;customer_master_key_spec&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ECC_NIST_P384"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_kms_public_key"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_kms_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivs_playback_key_pair"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivs-playback-key-pair"&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_kms_public_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_key_pem&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivs_channel"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivs-playback-key-pair-example"&lt;/span&gt;
  &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;인증 권한이 추가된 채널은 재생 URL에 JWT &lt;code&gt;token&lt;/code&gt; URL 파라미터 추가를 요구합니다. &lt;a href="https://docs.aws.amazon.com/ivs/latest/userguide/private-channels-generate-tokens.html" rel="noopener noreferrer"&gt;Generate and Sign Playback Tokens&lt;/a&gt;에서 자세한 내용을 확인하십시오.&lt;/p&gt;

&lt;p&gt;다음은 서명된 URL을 생성하는 Node.js(v18) 콘솔 스크립트의 예제입니다. 이 스크립트는 &lt;code&gt;npm&lt;/code&gt; 또는 &lt;code&gt;yarn&lt;/code&gt;을 통해 설치된 다음의 노드 모듈을 필요로 합니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@aws-sdk/client-kms" rel="noopener noreferrer"&gt;@aws-sdk/client-kms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@aws-sdk/client-ivs" rel="noopener noreferrer"&gt;@aws-sdk/client-ivs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/ecdsa-sig-formatter" rel="noopener noreferrer"&gt;ecdsa-sig-formatter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;이 스크립트는 &lt;code&gt;keyId&lt;/code&gt;, &lt;code&gt;channelArn&lt;/code&gt;, 그리고 만료 시간을 나타내는 &lt;code&gt;expiresIn&lt;/code&gt;을 인수로 사용합니다. Terraform 설정(&lt;code&gt;terraform show&lt;/code&gt;를 사용하거나 설정 파일에 출력을 추가하여 확인 가능)을 통해서 생성된 인프라에 대해서 아래 스크립트를 실행하면 유효한 토큰이 추가된 재생 URL이 반환됩니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  node create-playback-url-with-token.mjs \
  --keyId 3df50d5f-054a-4f20-88c6-bb7a73306dd0 \
  --channelArn arn:aws:ivs:us-west-2:326937407773:channel/aVbMPCM9Il2x \
  --expiresIn 30

https://a447f74b0a52.us-west-2.playback.live-video.net/api/video/v1/us-west-2.326937407773.channel.aVbMPCM9Il2x.m3u8?token=eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhd3M6Y2hhbm5lbC1hcm4iOiJhcm46YXdzOml2czp1cy13ZXN0LTI6MzI2OTM3NDA3NzczOmNoYW5uZWwvYVZiTVBDTTlJbDJ4IiwiYXdzOmFjY2Vzcy1jb250cm9sLWFsbG93LW9yaWdpbiI6IiIsImV4cCI6MTY3MzI3MzY5NCwiaWF0IjoxNjczMjczNjY0fQ.YAvlvVdO3rAq-7K3KHRPBvN1sU-JXJZ2963_thbaHBlBaYfyGYGAiqdJEN8XraEm3uc-h8NZiea8o0_XlOCHWIh9F1TGI1hSPqD7YY757C0ZF5cNsyBU49-sPbPvqpqa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IVS Chat에 Terraform 사용하기
&lt;/h2&gt;

&lt;p&gt;Terraform은 다음 리소스 및 데이터 소스를 사용하여 AWS Terraform Provider 버전 &lt;code&gt;v4.41.0&lt;/code&gt;부터 IVS Chat을 완벽하게 지원합니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logging Configuration: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_logging_configuration" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivschat_logging_configuration&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Room: &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_room" rel="noopener noreferrer"&gt;&lt;code&gt;aws_ivschat_room&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IVS Chat Room 만들기
&lt;/h3&gt;

&lt;p&gt;IVS Chat Room은 &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_room" rel="noopener noreferrer"&gt;ivschat_room&lt;/a&gt; 리소스를 사용하여 쉽게 생성할 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivschat_room"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이렇게 생성된 Chat Room은 Amazon IVS Chat과 함께 사용할 수 있습니다. 좀 더 상세한 정보를 위해 &lt;a href="https://docs.aws.amazon.com/ivs/latest/userguide/getting-started-chat.html" rel="noopener noreferrer"&gt;Getting Started with Amazon IVS Chat&lt;/a&gt;과 이전에 생성된 리소스들을 사용하여 채팅 기능을 검증하는 &lt;a href="https://github.com/aws-samples/amazon-ivs-chat-web-demo" rel="noopener noreferrer"&gt;Amazon IVS Chat Web Demo&lt;/a&gt;도 살펴보시기 바랍니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message Handler가 추가된 IVS Chat Room 만들기
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/ivs/latest/userguide/chat-message-review-handler.html" rel="noopener noreferrer"&gt;IVS Chat Message Review Handler&lt;/a&gt;는 채팅 메시지 전송 전에 메시지 수정 또는 메시지 전송 거부를 가능하도록 하는 Lambda Function입니다. 이 예제에서는 Lambda Function, IVS Chat이 Lambda Function을 실행가능하도록 하는 IAM Role, 그리고 여기서 생성한 Lambda Function을 Message Review Handler로 사용하는 IVS Chat Room을 생성합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;

&lt;span class="cm"&gt;/** IVS Chat message review handler */&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ReviewResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ALLOW&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - edited by Lambda`&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.tf&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_region"&lt;/span&gt; &lt;span class="s2"&gt;"current"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_caller_identity"&lt;/span&gt; &lt;span class="s2"&gt;"current"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-message-handler-role"&lt;/span&gt;
  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": ["sts:AssumeRole"],
        "Principal": {"Service": "lambda.amazonaws.com"}
    }]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"archive_file"&lt;/span&gt; &lt;span class="s2"&gt;"message_review_handler"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"zip"&lt;/span&gt;
  &lt;span class="nx"&gt;source_file&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module}&lt;/span&gt;&lt;span class="s2"&gt;/index.js"&lt;/span&gt;
  &lt;span class="nx"&gt;output_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module}&lt;/span&gt;&lt;span class="s2"&gt;/lambda-handler.zip"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;archive_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_review_handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_path&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-message-handler"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;source_code_hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;archive_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message_review_handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output_base64sha256&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nodejs18.x"&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.handler"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_permission"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;action&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;function_name&lt;/span&gt;
  &lt;span class="nx"&gt;principal&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ivschat.amazonaws.com"&lt;/span&gt;
  &lt;span class="nx"&gt;source_account&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_caller_identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_id&lt;/span&gt;
  &lt;span class="nx"&gt;source_arn&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:ivschat:&lt;/span&gt;&lt;span class="k"&gt;${data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_caller_identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:room/*"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivschat_room"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-room"&lt;/span&gt;
  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_lambda_permission&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;message_review_handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;uri&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
    &lt;span class="nx"&gt;fallback_result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Logging이 가능한 IVS Chat Room 만들기
&lt;/h3&gt;

&lt;p&gt;IVS Chat은 S3 Bucket 또는 CloudWatch와 같은 다양한 유형의 대상에 채팅 메시지를 Logging할 수 있도록 지원합니다. 이 예제에서는 Logging Configuration에 사용할 S3 Bucket을 생성하고, 이전에 생성한 Room에 Logging Configuration을 할당합니다:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_prefix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-logging-"&lt;/span&gt;
  &lt;span class="nx"&gt;force_destroy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivschat_logging_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-logging-configuration"&lt;/span&gt;
  &lt;span class="nx"&gt;destination_configuration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_ivschat_room"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tf-ivschat-room"&lt;/span&gt;
  &lt;span class="nx"&gt;logging_configuration_identifiers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_ivschat_logging_configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  마무리
&lt;/h3&gt;

&lt;p&gt;Terraform을 사용해서도, 개발자는 설정 파일을 생성해서 IVS 및 IVS Chat 리소스의 배포를 관리할 수 있습니다. IaC를 사용하면 개발팀에 버전 제어, 공동 작업, 재사용성 및 재해 복구와 같은 여러 가지 이점을 제공할 수 있습니다. Amazon IVS 및 IVS Chat과 관련된 모든 기능을 살펴보려면 &lt;a href="https://docs.aws.amazon.com/ivs/latest/userguide/what-is.html" rel="noopener noreferrer"&gt;Amazon IVS 사용 설명서&lt;/a&gt;를 살펴보십시오.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
