CREATE YOUR WORLD
채팅 기능

음성 채팅 기능 사용하기

24min
zepeto voice chat 미리보기 버전 패키지는 월드에서 음성 채팅을 가능하게 합니다 zepeto voice chat 설치 및 모드 설정 1\) 윈도우 설치 → 패키지 관리자 → zepeto voice chat 이 기능은 멀티플레이어 요소가 구현된 월드에서 사용할 수 있습니다 테스트는 모바일 테스트에서만 가능하며, 에디터 테스트에서는 사용할 수 없습니다 ios 정책으로 인해 음성 채팅이 활성화된 월드에서 마이크가 켜져 있을 때 장치 볼륨이 0으로 떨어지지 않습니다 마이크가 꺼지면 장치 볼륨이 0으로 떨어집니다 2\) 개발 중인 유니티 프로젝트 화면의 중간 메뉴에서 \[▼] 버튼을 클릭합니다 팝업 메뉴에서 \[월드 설정 열기] 버튼을 클릭합니다 3\) zepeto voice chat 패키지가 올바르게 설치되면, 음성 채팅 모드 옵션이 추가된 것을 볼 수 있습니다 4\) 음성 채팅 모드에서 원하는 모드를 설정해 주세요 기본 기본 제공되는 음성 채팅 기능을 사용합니다 스크립트 음성 채팅 api를 구현하여 음성 채팅 기능을 사용합니다 런타임에서 음성 채팅을 위한 방 접근 진입/퇴장을 처리할 수 있습니다 구별된 팀을 위한 음성 채팅 구현 (예 빨간 팀 음성 채팅 및 파란 팀 음성 채팅) 현재 말하고 있는 사용자 감지 기본 모드 음성 채팅 기능 사용하기 기본 모드 음성 채팅이 있는 월드 는 이렇게 생겼습니다 음성 변조 기능을 사용하여 더 재미있는 음성 채팅을 만들 수 있습니다 음성 채팅 기능이 있는 월드 에 들어가면 음성 채팅이 자동으로 활성화됩니다 👍 zepeto에서 음성 채팅 기능을 처음 사용할 때 마이크 접근에 대한 팝업이 나타납니다 음성 채팅 기능을 사용하려면 접근을 허용해야 합니다 음성 채팅 버튼을 터치하여 사용할 수 있습니다 zepeto 앱 3 26 000 이상에서는 음성 채팅 스피커 아이콘이 나타나지 않습니다 스피치 아이콘을 나타내고 싶다면 스크립트 모드로 변경하고 가이드를 따라 자신의 코드를 작성하세요 스크립트 모드 voicechat api 사용하기 스크립트 모드는 팀별로 분리된 채널에서 음성 채팅을 가능하게 합니다 기능을 구현하기 위해 아래의 기능 설명 및 예제를 참조하십시오 api 설명 oninitializedevent 음성 채팅 api는 초기화 이벤트에서 true 이벤트가 발생한 후 사용할 수 있습니다 이 이벤트가 true이면 음성 채팅을 사용할 수 있으며, false이면 음성 채팅을 사용할 수 없습니다 enterroom(roomproperty roomproperty) 음성 채팅 방에 들어가기 위한 함수 \ 음성 채팅 방에 성공적으로 들어가면 음성 채팅 버튼이 나타납니다 exitroom() 음성 채팅 방을 나가기 위한 함수 onroomconnectedevent 음성 채팅 방에 들어간 상태를 확인하는 이벤트입니다 이 이벤트가 true이면 사용자가 음성 채팅 방에 들어간 것이고, false이면 사용자가 음성 채팅 방을 나간 것입니다 onspeechdetectedevent\<string, boolean> 현재 음성 채팅에서 말하고 있는 사용자를 감지하는 이벤트입니다 \ string은 말하고 있는 사용자의 userid입니다 \ boolean은 발화가 시작될 때 true, 발화가 끝날 때 false입니다 changeteamid(number teamid) 음성 채팅 방에서 사용되는 teamid를 변경하는 함수입니다 \ 1 이상의 int 값으로만 설정할 수 있습니다 룸 속성 클래스 api 설명 setaudiomode 음성 채팅에서 사용할 오디오 모드 \ audiomode omnidirectional 거리 기반 음성 감쇠가 없는 음성 채팅 모드 (이 모드는 zepeto 캐릭터와 함께 또는 없이 사용할 수 있습니다) \ audiomode directional 거리 기반 음성 감쇠가 있는 음성 채팅 모드 (zepeto 캐릭터의 위치에 따라 작동하므로 장면에 zepeto 캐릭터가 있어야 합니다) setteamid 음성 채팅에서 사용될 teamid로, 동일한 teamid를 가진 사용자 간의 음성 채팅을 활성화합니다 \ 정수 값 1 이상으로만 설정할 수 있습니다 팀별 음성 채팅 구현 예시 여기 음성 채팅 api를 시도해 볼 수 있는 예제 코드가 있습니다 1\) 아래 이미지와 같이 버튼을 추가하고 텍스트를 캔버스에 기록하여 음성 채팅 팀 채널에 들어가고 상태 로그를 표시합니다 버튼 button blueteam 블루 팀 음성 채팅 입장 버튼 button redteam 레드 팀 음성 채팅 입장 버튼 button exit 음성 채팅 종료 버튼 텍스트 text log 채팅 로그를 표시할 텍스트 text team 같은 음성 채팅 팀 채널의 멤버 목록을 표시할 텍스트 text currentspeaking 현재 음성 채팅에서 말하고 있는 사용자 id를 표시할 텍스트 2\) 프로젝트 생성 > 생성 > zepeto > typescript로 이름을 voicechattest로 변경합니다 3\) 아래와 같이 샘플 스크립트를 작성합니다 voicechattest import { button, inputfield, text } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script' import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat' export default class voicechattest extends zepetoscriptbehaviour { // ui 구성 요소를 공개 멤버로 선언 public blueteambutton button; public redteambutton button; public exitroombutton button; public logtext text; public currentteamidtext text; public currentspeakinguseridstext text; // 말하는 사용자 id와 팀 id 입력 필드를 저장하기 위한 비공개 멤버 선언 private currentspeakinguserids string\[]; private teamidinputfield inputfield; start() { this currentspeakinguserids = new array(); // 버튼 클릭에 대한 이벤트 리스너 추가 this blueteambutton onclick addlistener(()=>{ this enterblueteam(); }); this redteambutton onclick addlistener(()=>{ this enterredteam(); }); this exitroombutton onclick addlistener(()=>{ this exitvoicechatroom(); }); // 음성 채팅 컨트롤러에 대한 이벤트 리스너 추가 voicechatcontroller oninitializedevent addlistener(init => this oninitialized(init)); voicechatcontroller onroomconnectedevent addlistener(connected => this onroomconnected(connected)); voicechatcontroller onspeechdetectedevent addlistener((userid, speechdetected) => this onspeechdetected(userid, speechdetected)); this logtext text = "\[voicechat] voicechattest 시작"; } // 스크립트가 파괴될 때 호출되는 ondestroy 메서드 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); voicechatcontroller onspeechdetectedevent removealllisteners(); } // 음성 채팅 시스템이 초기화될 때 호출되는 메서드 private oninitialized(initialized boolean) { this logtext text = "\[voicechat] 초기화됨 " + initialized; } // 음성 채팅 방이 연결될 때 호출되는 메서드 private onroomconnected(connected boolean) { this logtext text = "\[voicechat] 방 연결됨 " + connected; } // 사용자의 음성이 감지되거나 감지되지 않을 때 호출되는 메서드 private onspeechdetected(userid string, speechdetected boolean) { this logtext text = "\[voicechat] 음성 감지됨 " + userid + ", " + speechdetected; if (speechdetected) { this currentspeakinguserids push(userid); } else { let index = this currentspeakinguserids indexof(userid); this currentspeakinguserids splice(index, 1); } let userids = "\[현재 말하는 사용자 ids]\n"; for (let i = 0; i < this currentspeakinguserids length; i++) { userids += this currentspeakinguserids\[i]; userids += "\n"; } this currentspeakinguseridstext text = userids; } // 블루 팀의 음성 채팅 방에 들어가는 메서드 public enterblueteam(){ this entervoicechatroom(2); } // 레드 팀의 음성 채팅 방에 들어가는 메서드 public enterredteam(){ this entervoicechatroom(3); } // 주어진 팀 인덱스에 따라 음성 채팅 방에 들어가는 메서드 private entervoicechatroom(teamindex number) { console log("\[voicechat] 음성 채팅 방에 들어감"); // 새로운 roomproperty 객체를 생성하고 속성을 설정 let roomproperty = new roomproperty(); roomproperty setaudiomode(audiomode omnidirectional); roomproperty setteamid(teamindex); voicechatcontroller enterroom(roomproperty); this currentteamidtext text = "팀 id " + roomproperty teamid tostring(); } // 음성 채팅 방에서 나가는 메서드 public exitvoicechatroom() { this logtext text = "\[voicechat] 음성 채팅 방에서 나감"; voicechatcontroller exitroom(); } // 현재 사용자의 팀 id를 변경하는 메서드 public changeteamid() { // 입력 필드에서 새로운 팀 id를 가져오고 정수로 파싱 let teamid = parseint(this teamidinputfield text); this logtext text = "\[voicechat] 팀 id 변경 " + teamid; this currentteamidtext text = "팀 id " + teamid tostring(); // 음성 채팅 시스템에서 팀 id 변경 voicechatcontroller changeteamid(teamid); } } 코드 설명 스크립트가 실행되면 start() 함수에서 각 버튼에 이벤트를 등록하고 voicechatcontroller에서 oninitialized, onroomconnected 및 onspeechdetected 이벤트를 등록합니다 블루 팀 버튼 또는 레드 팀 버튼이 클릭되면 entervoicechatroom() 함수가 실행되고 사용자는 지정된 roomproperty를 입력하여 음성 채팅 방에 들어갑니다 예제의 방 속성은 다음과 같습니다 roomproperty setaudiomode audiomode omnidirectional omnidirectional 오디오 모드는 플레이어의 위치에 관계없이 볼륨이 동일하게 들리는 모드입니다 반면 directional 모드는 3d 사운드 모드로, 캐릭터의 위치에 따라 볼륨이 다르게 들리므로 캐릭터가 멀어질수록 볼륨이 낮아집니다 roomproperty setteamid 블루 팀은 채널 2, 레드 팀은 채널 3입니다 setteamid는 음성 채팅에서 채널처럼 작동합니다 채널 2에 들어간 팀은 채널 2의 플레이어와만 음성 채팅을 할 수 있으며, 채널 3에 들어간 팀은 채널 3의 플레이어와만 음성 채팅을 할 수 있습니다 exitvoicechatroom()은 현재 음성 채팅 팀 채널에서 나갑니다 onspeechdetected()는 현재 팀 채널에서 음성 채팅을 사용 중인 플레이어 id를 로그 텍스트에 출력합니다 4\) 스크립트를 완료한 후, step1에서 생성한 버튼과 텍스트를 검사기에서 할당합니다 5\) qr 코드나 테스트 링크를 통해 모바일에서 테스트를 실행하면, 팀에 참여 버튼을 누를 때 음성 채팅 활성화 버튼이 생성되고, 플레이어가 말을 할 때마다 로그에 어떤 플레이어가 음성 채팅에 있는지 표시됩니다 다음 화면과 같이 나타납니다 음성 채팅 말풍선 이미지 표시 예시 zepeto 앱 3 26 000 및 이후 버전에서는 음성 채팅 발화 아이콘이 나타나지 않습니다 발화 아이콘이 나타나도록 하려면 가이드를 따라 자신의 코드를 작성해 주세요 1\) 플레이어가 음성 채팅에 있을 때 캐릭터 머리 위에 말풍선을 표시하려면, 말풍선 이미지를 사용하는 프리팹을 생성해야 합니다 아래와 같이 사용하고자 하는 말풍선 png 이미지를 가져오고, 텍스처 유형을 스프라이트로 변경하세요 2\) 프로젝트 > 생성 > 프리팹을 선택하고 이름을 chatbubble로 변경합니다 3\) chatbubble 프리팹을 더블 클릭하여 프리팹 편집 모드로 들어갑니다 chatbubble 프리팹을 선택하고 변환 > 위치 > y 값을 0 35로 변경합니다 4\) 프리팹 객체 안에 캔버스를 생성합니다 chatbubble 프리팹을 더블 클릭하여 프리팹 편집 모드로 들어가고, hierachy > ui > canvas를 추가합니다 캔버스의 recttransform 구성 요소의 값을 다음과 같이 변경합니다 posx 0 , posy 0 너비 100, 높이 100 scalex 0 005, scaley 0 005, scalez 0 005 캔버스 구성 요소의 rendermove를 월드 스페이스로 변경합니다 5\) 캔버스 안에 말풍선 이미지를 생성합니다 hierarchy > ui > image를 캔버스의 자식으로 추가하고, 이름을 chatbubbleimage로 변경합니다 chatbubbleimage의 recttransform 구성 요소의 값을 다음과 같이 변경합니다 너비 42, 높이 42 1단계에서 가져온 이미지 스프라이트를 이미지 구성 요소의 소스 이미지로 등록합니다 👍 팁 말풍선 이미지 스프라이트를 애니메이션으로 만들 수 있습니다 다른 팀을 위해 별도의 말풍선 이미지를 사용할 수도 있습니다 6\) 프로젝트 > 생성 > zepeto > typescript를 생성하고 이름을 voicechatbubblecontroller로 변경합니다 7\) 아래와 같이 샘플 스크립트를 작성하세요 voicechatbubblecontroller import { gameobject, object } from 'unityengine'; import { knowsockets, zepetoplayers } from 'zepeto character controller' import { zepetoscriptbehaviour } from 'zepeto script' import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat'; export default class voicechatbubblecontroller extends zepetoscriptbehaviour { // public gameobject variable to store the voice chat bubble prefab public voicechatprefab gameobject; // private map to store gameobjects associated with user ids private voicebubblemap map\<string, gameobject> = new map\<string, gameobject>(); start() { // add event listeners for voice chat controller voicechatcontroller oninitializedevent addlistener(init => this oninitialized(init)); voicechatcontroller onroomconnectedevent addlistener(connected => this onroomconnected(connected)); voicechatcontroller onspeechdetectedevent addlistener((userid, speechdetected) => this onspeechdetected(userid, speechdetected)); } // method called when the voice chat system is initialized private oninitialized(initialized boolean) { console log("\[voicechat] oninitialized "); this entervoicechatroom(1); } // method called when the voice chat room is connected private onroomconnected(connected boolean) { console log("\[voicechat] onroomconnected "); } // method to enter a voice chat room based on the given team index private entervoicechatroom(teamindex number) { console log("\[voicechat] entervoicechatroom"); // create a new roomproperty object and set its properties let roomproperty = new roomproperty(); roomproperty setaudiomode(audiomode omnidirectional); voicechatcontroller enterroom(roomproperty); } // method called when a user's speech is detected or not detected private onspeechdetected(userid string, speechdetected boolean) { console log("\[voicechat] onspeechdetected " + userid + ", " + speechdetected); // check if the user id is not in the voice bubble map and create a voice bubble if it is not if (!this voicebubblemap has(userid)) { this createvoicebubble(userid); } this setvoicebubble(userid, speechdetected); } // method to set the active state of the voice bubble for a given user id private setvoicebubble(userid string, speechdetected boolean) { const chatbubble = this voicebubblemap get(userid); chatbubble setactive(speechdetected); } // method to create a voice bubble for a given user id private createvoicebubble(userid string) { // get the head socket of the user's character const headsocket = zepetoplayers instance getplayerwithuserid(userid) character getsocket(knowsockets head upper); // instantiate the voice chat bubble prefab at the head socket position const instancebubble = object instantiate(this voicechatprefab, headsocket) as gameobject; // add the instantiated bubble to the voice bubble map this voicebubblemap set(userid, instancebubble); instancebubble setactive(false); } lateupdate() { // check if the voice bubble map is empty and return if it is if (this voicebubblemap size === 0) { return; } // iterate through the voice bubble map and update the rotation of each bubble gameobject this voicebubblemap foreach((bubbleobject gameobject) => { // set the rotation of the bubble object to match the camera's parent transform rotation bubbleobject transform rotation = zepetoplayers instance zepetocamera cameraparent transform rotation; }); } } 코드 설명 스크립트가 실행되면 start() 함수에서 각 버튼에 이벤트를 등록하고 voicechatcontroller의 oninitialized, onroomconnected, onspeechdetected 이벤트를 등록합니다 oninitialized() 후, 플레이어가 세계에 들어가면 음성 채팅 버튼이 화면에 표시되며, 버튼을 누르면 entervoicechatroom()이 실행되어 음성 채팅 방에 들어갑니다 플레이어가 voicechat을 활성화하고 말을 할 때마다 onspeechdetected()가 실행되며, speechdetected가 true이면 bubblechat 객체가 활성화되고, false이면 비활성화됩니다 onspeechdetected() 함수가 처음 활성화될 때, createvoicebubble()이 음성 채팅 프리팹 gameobject를 플레이어의 머리 위에 띄우고 voicebubblemap에 맵 데이터로 등록합니다 lateupdate()를 사용하여 매 프레임마다 음성 채팅 버블의 회전을 zepeto 세계의 cameraparent에 맞추어 업데이트합니다 이렇게 하면 말풍선 이미지가 항상 카메라를 향하게 됩니다 먼저 voicebubblemap이 비어 있는지 확인하고, 그렇지 않으면 말풍선 이미지 프리팹의 회전을 업데이트합니다 8\) 스크립트 작성을 마친 후, 검사기에서 voicechatprefab 항목을 step 1에서 생성한 말풍선 프리팹으로 지정합니다 9\) qr 코드나 테스트 링크를 통해 모바일에서 실행하면 플레이어가 음성 채팅을 사용할 때마다 캐릭터 머리 위에 말풍선 이미지가 나타나는 것을 볼 수 있습니다 음성 변조 음성 채팅 버전 0 2 1 preview부터 스크립트 모드에서 음성 채팅 음성을 조절할 수 있습니다 https //www youtube com/watch?v=yxfpuqypbqk https //www youtube com/watch?v=yxfpuqypbqk api 가이드와 샘플 코드를 사용하여 음성 조절을 시도해 보세요 음성 유형 (enum) 값 설명 유형00 0 원본 유형01 1 치프먼크 유형02 2 삼촌 유형03 3 에코 유형04 4 딥 보이스 유형05 5 로봇 유형06 6 방언 유형07 7 메가폰 유형08 8 짐승 유형09 9 기계 유형10 10 강한 전류 유형11 11 아이 유형12 12 고슴도치 여기 음성 변조의 샘플 스크립트가 있습니다 import { button } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script'; import { roomproperty, voicechatcontroller, voicetype } from 'zepeto voice chat'; export default class voicemodulationmanager extends zepetoscriptbehaviour { // 다양한 음성 유형을 설정하기 위한 버튼들 public buttons button\[]; start() { const voicetypes = \[ voicetype type00, voicetype type01, voicetype type05, voicetype type03, ]; for (const \[index, button] of this buttons entries()) { button onclick addlistener(() => { // 클릭된 버튼 인덱스에 해당하는 음성 유형 설정 voicechatcontroller setvoicetype(voicetypes\[index]); }); }; // 음성 채팅 시스템이 초기화될 때 호출되는 메서드 voicechatcontroller oninitializedevent addlistener( init => { voicechatcontroller enterroom(new roomproperty());; } ); // 음성 채팅 방에 연결될 때 호출되는 메서드 voicechatcontroller onroomconnectedevent addlistener( connected => { // 초기 음성 유형 설정 및 루프백 활성화 voicechatcontroller setvoicetype(voicetypes\[0]); voicechatcontroller enableloopback(true); } ); } // 음성 채팅 방을 나가는 메서드 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); } } 코드 설명 각 버튼에 대해 클릭 리스너를 추가하여 서로 다른 음성 변조 유형을 설정합니다 같은 인덱스의 요소는 버튼 배열과 음성 유형 배열이 일치합니다 세계에 들어가면, voicechatcontroller 가 초기화되고, 방 연결이 자동으로 설정됩니다 초기 음성 변조 유형은 type00 , 그리고 루프백이 활성화되어 자신의 목소리를 들을 수 있습니다 다음 호출을 위해 주의하세요 setvoicetype 및 enableloopback , 방 연결이 필요합니다 따라서 초기 설정은 onroomconnectedevent 의 리스너 내에서 처리됩니다 로컬 플레이어의 오디오 재생 위치 변경 로컬 플레이어의 음성 채팅 위치를 변경할 수 있습니다 voicechatcontroller setlocalplayertransform() 이를 사용하면 음성 채팅 중 특정 공간이나 객체 위치로 설정하여 다양한 시나리오를 만들 수 있습니다 📘 팁 음성 채팅의 변환은 로컬 플레이어의 zepeto 캐릭터 변환에 연결되어 있습니다 따라서 로컬 플레이어의 zepeto 캐릭터가 세계에 생성되지 않았다면, 당신의 목소리가 전송되지 않을 수 있습니다 이 경우, setlocalplayertransform() 를 사용하여 현재 장면 내에서 음성 재생 위치를 설정하여 음성 채팅을 사용할 수 있습니다 api 설명 public static setlocalplayertransform($transform unityengine transform)\ void 로컬 플레이어의 오디오 재생 위치를 변경하는 함수 ❗️ 주의 setlocalplayertransform() 는 음성 채팅이 초기화될 때 voicechatcontroller oninitializedevent(true) 이후에 호출되어야 합니다 1\) 아래는 음성 위치 변경 기능을 위한 샘플 스크립트입니다 voicetransformsample import { gameobject, transform, vector3 } from 'unityengine'; import { button } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script'; import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat'; export default class voicetransformsample extends zepetoscriptbehaviour { // 음성 변환을 가깝게 설정하는 버튼 public buttonclosertransform button; // 음성 변환을 멀리 설정하는 버튼 public buttonfarthertransform button; // 음성 위치를 위한 변환 private voicetransform transform; start() { // 새로운 gameobject 생성 및 음성 변환 객체를 저장할 변환 할당 const voicetransformobject = new gameobject; this voicetransform = voicetransformobject transform; // 음성 채팅 시스템이 초기화될 때 호출되는 메서드 voicechatcontroller oninitializedevent addlistener( init => { let roomproperty = new roomproperty(); // 오디오 모드를 방향성 3d 공간 오디오로 설정 roomproperty setaudiomode(audiomode directional); voicechatcontroller enterroom(roomproperty); // 로컬 플레이어의 음성에 대한 음성 채팅 변환 설정 voicechatcontroller setlocalplayertransform(this voicetransform); } ); // 'buttonclosetransform'이 클릭될 때 음성 변환 위치를 (0,0,0)으로 설정 this buttonclosertransform onclick addlistener(()=>{ this voicetransform position = vector3 zero; }) // 'buttonfartransform'이 클릭될 때 음성 변환 위치를 먼 지점으로 설정 this buttonfarthertransform onclick addlistener(()=>{ this voicetransform position = new vector3(0,0, 10); }) } // 음성 채팅 방에서 나가는 메서드 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); } } 코드 설명 장면이 시작될 때, start() 함수에서 voicetransformobject라는 게임 오브젝트를 생성하고 voicetransform에 transform을 등록합니다 음성 채팅이 oninitialized 리스너가 호출되면, 다음 설정을 적용해 주세요 음성 채팅을 3d 공간 오디오 모드로 설정합니다 setaudiomode(audiomode directional) 로컬 플레이어의 음성 채팅 위치를 voicetransform으로 설정합니다 voicechatcontroller setlocalplayertransform() buttonclosertransform은 버튼이 클릭될 때 voicetransform의 위치를 원점(0, 0, 0)으로 설정합니다 buttonfarthertransform은 버튼이 클릭될 때 voicetransform의 위치를 (10, 0, 0)으로 설정합니다 2\) 장면의 캔버스에 있는 버튼을 voicetransformsample 구성 요소의 buttonclosertransform 및 buttonfarthertransform에 등록합니다 3\) qr 코드를 사용하거나 테스트 링크를 통해 모바일 폰에서 실행하면 다음을 확인할 수 있습니다 closer 버튼을 누르면, 당신의 목소리가 다른 사람에게 더 가까이 들립니다 farther 버튼을 누르면, 당신의 목소리가 다른 사람에게 멀리 들립니다 https //www youtube com/watch?v=y pj4rcshts https //www youtube com/watch?v=y pj4rcshts