Studio GuideWorld SDK Guide
Log In

Using the Voice Chat Function

Zepeto.Voice.Chat preview version package enables voice chat in the World.


Install ZEPETO.Voice.Chat and set the mode

  1. Install Window → Package Manager → ZEPETO.Voice.Chat.

❗️

Caution

  • This feature is available in a World where multiplayer elements are implemented.
  • Testing is only available in the mobile test, not editor test.
  • Due to iOS policy, the device volume does not drop to zero when the microphone is turned on in worlds with voice chat enabled.
    The device volume will drop to zero when the microphone is turned off.

  1. Click the [▼] button in the middle menu of the Unity project screen that's under development.
    Click the [Open World Settings] button in the pop-up menu that appears.

  1. If the ZEPETO.Voice.Chat package is installed correctly, you will see the Voice Chat Mode option added.

  1. In Voice Chat Mode, please set the desired mode.
  • Basic: Use the voice chat feature provided by default.
  • Script: Use the voice chat feature by implementing the voice chat API.
    • You can process room access entry/exit for voice chat at runtime.
    • Implement voice chat for distinct teams (e.g., red team voice chat and blue team voice chat)
    • Detecting current speaking user

Basic Mode: Using the Voice Chat Feature

A world with Basic Mode voice chat looks like this.

You can also create more entertaining voice chats using the voice modulation feature.

Voice chat is automatically enabled when entering the World with voice chat function.

👍

The first time you use the voice chat feature in ZEPETO, a pop-up regarding microphone access will appear.
You must allow access in order to use the voice chat function.

1334

When you enable the voice chat feature, a button automatically appears in the UI

You can use it by touching the voice chat button

You can use it by touching the voice chat button


❗️

Caution

  • In ZEPETO app 3.26.000 and above, the voice chat speaker icon does not appear.
  • If you want to make the speech icon appear, please change to Script Mode and follow the guide to write your own code.

Script Mode : Using the VoiceChat API

Script Mode enables voice chat in channels separated by teams.

Please refer to the function description and example below to implement the feature.

APIDescription
OnInitializedEventThe voice chat APIs are available after a True event occurs in the initialization event.
If this event is True, voice chat is available, and if it is False, voice chat is not available.
EnterRoom(RoomProperty roomProperty)Functions to enter a voice chat room
- After successfully entering the voice chat room, the voice chat button will appear
ExitRoom()Function to leave a voice chat room
OnRoomConnectedEventAn event to check the status of entering a voice chat room.
If this event is true, the user has entered the voice chat room; if it is false, the user has left the voice chat room.
OnSpeechDetectedEvent<string, boolean>Event to detect the user who is currently speaking in the voice chat.
- string is the userId of the speaking user
- boolean is true when the utterance starts, false when the utterance ends
ChangeTeamID(number teamid)Function to change the TeamId used in the voice chat room
- Can only be set to an int value of 1 or more

RoomProperty Class

APIDescription
SetAudioModeAudio mode to use in voice chat
- AudioMode.Omnidirectional: Voice chat mode with no voice attenuation based on distance
(You can use it with or without the ZEPETO character)


- AudioMode.Directional: Voice chat mode with voice attenuation based on distance
(The ZEPETO character must be present in the Scene, as this mode works based on the ZEPETO character's location)
SetTeamIDTeamId to be used in voice chat to enable voice chat between users with the same TeamId.
- Can only be set to an int value of 1 or higher

Example of team-specific voice chat implementation

Here is some example code to try out the Voice Chat API.

  1. Add a button and log text to the canvas as shown in the image below to enter the Voice Chat team channel and display the status log.
  • Button
    • Button_blueTeam : Blue team voice chat entry button
    • Button_redTeam : Red team voice chat entry button
    • Button_exit : Exit voice chat button
  • Text
    • Text_log : Text to display the chat log
    • Text_team : Text to display the list of members of the same voice chat team channel
    • Text_currentSpeaking : Text to display the UserId who is currently speaking in the voice chat.


  1. Create Project > Create > ZEPETO > TypeScript and rename it to VoiceChatTest.
  2. Write a sample script as shown below.
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 {
 
    // Declare UI components as public members
    public BlueTeamButton: Button;
    public RedTeamButton: Button;
    public exitRoomButton: Button;
    public logText: Text;
    public currentTeamIDText: Text;
    public currentSpeakingUserIDsText: Text;
     
    // Declare private members to store speaking user IDs and team ID input field
    private currentSpeakingUserIDs: string[];   
    private teamIDInputField: InputField;
 
    Start() {
        this.currentSpeakingUserIDs = new Array();
         
        // Add event listeners for button clicks
        this.BlueTeamButton.onClick.AddListener(()=>{
            this.EnterBlueTeam();
        });
        this.RedTeamButton.onClick.AddListener(()=>{
            this.EnterRedTeam();
        });
        this.exitRoomButton.onClick.AddListener(()=>{
            this.ExitVoiceChatRoom();
        });
 
        // 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));
         
        this.logText.text = "[VoiceChat] VoiceChatTest Start";
    }
 
    // OnDestroy method called when the script is destroyed
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
        VoiceChatController.OnSpeechDetectedEvent.RemoveAllListeners();
    }
 
    // Method called when the Voice Chat system is initialized
    private OnInitialized(initialized: boolean) {
        this.logText.text = "[VoiceChat] OnInitialized: " + initialized;
    }
 
     // Method called when the Voice Chat room is connected
    private OnRoomConnected(connected: boolean) {
        this.logText.text = "[VoiceChat] OnRoomConnected: " + connected;
    }
 
    // Method called when a user's speech is detected or not detected
    private OnSpeechDetected(userId: string, speechDetected: boolean) {
        this.logText.text = "[VoiceChat] OnSpeechDetected: " + userId + ", " + speechDetected;
 
        if (speechDetected) {
            this.currentSpeakingUserIDs.push(userId);
        }
        else {
            let index = this.currentSpeakingUserIDs.indexOf(userId);
            this.currentSpeakingUserIDs.splice(index, 1);
        }
 
        let userIds = "[CurrentSpeakingUserIDs]\n";
        for (let i = 0; i < this.currentSpeakingUserIDs.length; i++) {
            userIds += this.currentSpeakingUserIDs[i];
            userIds += "\n";
        }
 
        this.currentSpeakingUserIDsText.text = userIds;
    }
 
    // Method to enter the blue team's Voice Chat room
    public EnterBlueTeam(){
        this.EnterVoiceChatRoom(2);
    }
 
    // Method to enter the red team's Voice Chat room
    public EnterRedTeam(){
        this.EnterVoiceChatRoom(3);
    }
 
    // 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);
        roomProperty.SetTeamID(teamIndex);
        VoiceChatController.EnterRoom(roomProperty);
        this.currentTeamIDText.text = "TeamID: " + roomProperty.TeamId.toString();
    }
 
    // Method to exit the Voice Chat room
    public ExitVoiceChatRoom() {
        this.logText.text = "[VoiceChat] ExitVoiceChatRoom";
        VoiceChatController.ExitRoom();
    }
 
    // Method to change the team ID for the current user
    public ChangeTeamID() {
        // Get the new team ID from the input field and parse it as an integer
        let teamID = parseInt(this.teamIDInputField.text);
        this.logText.text = "[VoiceChat] ChangeTeamID: " + teamID;
        this.currentTeamIDText.text = "TeamID: " + teamID.toString();
        // Change the team ID in the Voice Chat system
        VoiceChatController.ChangeTeamID(teamID);
    }
 
}

  • Code Description
    • When the script runs, it will register an event on each button in the Start() function and register the OnInitialized, OnRoomConnected, and OnSpeechDetected events on the VoiceChatController.
    • When the Blue Team button or Red Team button is clicked, the EnterVoiceChatRoom() function is executed and the user enters the voice chat room by entering the specified RoomProperty. The room properties in the example are as follows.
      • roomProperty.SetAudioMode : AudioMode.Omnidirectional. The audio mode Omnidirectional is a mode where the volume sounds the same regardless of the player's position. In contrast, Directional mode is a 3D sound mode, which means that the volume will sound different depending on the character's position, so the farther away the character is, the lower the volume will be.
      • roomProperty.SetTeamID : Channel 2 for Blue Team, Channel 3 for Red Team. SetTeamID acts like a channel in Voice Chat. A team that enters channel 2 can only voice chat with players in channel 2, and a team that enters channel 3 can only voice chat with players in channel 3.
    • ExitVoiceChatRoom() will exit the current voice chat team channel.
    • OnSpeechDetected() will output the player ID that is currently using voice chat in the team channel to the log text.

  1. After completing the script, assign the button and text created in Step1 in the inspector.


  1. Run the test on mobile via QR code or test link, and you can see that the voice chat activation button is created when the Enter Team button is pressed, and whenever a player speaks, the log shows which player is in voice chat, as shown in the following screen.


Example of displaying a voice chat speech bubble image

In ZEPETO App 3.26.000 and later versions, the voice chat utterance icon does not appear.
If you want to handle the utterance icon to appear, please follow the guide and write your own code.

  1. To show a speech bubble above the character's head when the player is in voice chat, you will need to create a prefab that uses a speech bubble image. Import the speech bubble PNG image you want to use as shown below and change its Texture Type to Sprite.


  1. Project > Create > Prefab and rename it to ChatBubble.

  1. Double-click the ChatBubble prefab to enter the prefab editing mode. Select the ChatBubble prefab and choose Transform > Position > Change the Y value to 0.35.


  1. Create a Canvas inside the prefab object.
  • Double-click the ChatBubble prefab to enter Prefab Edit mode, and then add Hierachy > UI > Canvas.
  • Change the values of the RectTransform component of the Canvas to the following
    • PosX: 0 , posY: 0
    • Width: 100, height: 100
    • ScaleX: 0.005, ScaleY: 0.005, ScaleZ: 0.005
  • Change the RenderMove of the Canvas component to World Space.


  1. Create a speech bubble image inside the Canvas.
  • Add Hierarchy > UI > Image as a child of Canvas, and rename it ChatBubbleImage.
  • Change the values of the RectTrasform component of the ChatBubbleImage to the following
    • Width 42, Height:42
  • Register the Image Sprite you imported in step 1 as the Source Image in the Image Component.


👍

Tip

  • You can also animate the speech bubble image sprite.
  • You can also use separate bubble images for different teams.

  1. Project > Create > ZEPETO > Create a TypeScript and rename it to VoiceChatBubbleController.
  2. Write a sample script as shown below.
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;
        });

    }
 
}

  • Code Description
    • When the script is executed, it will register events on each button in the Start() function and OnInitialized, OnRoomConnected, and OnSpeechDetected events on the VoiceChatController.
    • After OnInitialized(), the Voice Chat button will be exposed on the player's screen when they enter the world, and when they press the button, EnterVoiceChatRoom() will be executed to enter the Voice Chat room.
    • Whenever the player activates VoiceChat and speaks, OnSpeechDetected() is executed, and if speechDetected is tue, the BubbleChat object is enabled, and if false, it is disabled.
    • The first time the OnSpeechDetected() function is activated, CreateVoiceBubble() will instantiate a voiceChatPrefab GameObject to float above the player's head and register it as map data in _voiceBubbleMap.
    • We use LateUpdate() to update the rotation of the voice chat bubble every frame to match the CameraParent of the ZEPETO world. This ensures that the speech bubble image is always facing the camera. It first checks to see if _voiceBubbleMap is empty, otherwise it updates the rotation of the speech bubble image prefab.

  1. After finishing writing the script, assign the VoiceChatPrefab entry in the inspector as the speech bubble prefab you created in STEP 1.

  1. Run it on mobile via a QR code or test link and you should see the speech bubble image appear above the character's head whenever the player uses voice chat.

Voice Modulation

Starting with Voice Chat version 0.2.1-preview, you can modulate the Voice Chat voice in Script Mode.


Try voice modulation using the API guide and the sample code.

APIDescription
SetVoiceType($voiceType: ZEPETO_Voice_Chat_IVoiceEffect.VoiceType)Set the voice modulation type. Make sure that you are connected to a Room.

Refer to the table below for a description of the Voice Type associated with each enum.
EnableLoopback($enabled: boolean)Determine whether to enable the loop-back function, which allows you to hear your own voice. To do this, please make sure you are connected to a Room first.
VoiceType (enum)ValueDescription
Type000Original
Type011Chipmunk
Type022Uncle
Type033Echo
Type044Deep Voice
Type055Robot
Type066Dialect
Type077Megaphone
Type088Beast
Type099Machine
Type1010Strong Current
Type1111Kid
Type1212Hedgehog

Here is a sample script of voice modulation.

import { Button } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { RoomProperty, VoiceChatController, VoiceType } from 'ZEPETO.Voice.Chat';

export default class VoiceModulationManager extends ZepetoScriptBehaviour {
 
    // Buttons for setting different voice types
    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(() => {
                // Set the voice type corresponding to the clicked button index
                VoiceChatController.SetVoiceType(voiceTypes[index]);
            });
        };
 
        // Method called when the Voice Chat system is initialized
        VoiceChatController.OnInitializedEvent.AddListener(
            init => {
                VoiceChatController.EnterRoom(new RoomProperty());;
            }
        );
 
        // Method called when the Voice Chat room is connected
        VoiceChatController.OnRoomConnectedEvent.AddListener(
            connected => {
                // Set the initial voice type and activate loopback
                VoiceChatController.SetVoiceType(voiceTypes[0]);
                VoiceChatController.EnableLoopback(true);
            }
        );
    }
 
    // Method to exit the Voice Chat room
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
    }
}
  • Code Description:
    • Adds an onClick listener for each button to set different voice modulation types.
      • Elements of the same index in the buttons array and the voiceTypes array are matched.
    • Upon entering the world, VoiceChatController is initialized, and the room connection is established automatically.
    • The initial voice modulation type is set to Type00, and loopback is enabled to hear your own voice.
      • Note that for the invocation of SetVoiceType and EnableLoopback, a room connection is necessary. Hence, the initial setup is handled within the listener of theOnRoomConnectedEvent.

This is an inspector example connecting buttons with the sample script.

This is an inspector example connecting buttons with the sample script.


Change the local player's audio playback location


You can change the local player's voice chat location using VoiceChatController.SetLocalPlayerTransform().

Using this, you can create various scenarios by setting your location to a specific space or object location when speaking in voice chat.


📘

tips

The Voice Chat’s Transform is linked to the local player’s ZEPETO character Transform.

Therefore, if the local player’s ZEPETO character hasn’t been created in the world, your voice may not be transmitted.

In this case, you can use voice chat by setting the voice playback location within the current scene using SetLocalPlayerTransform().


APIDescription
public static SetLocalPlayerTransform($transform: UnityEngine.Transform):voidFunction to change the local player's audio playback position

❗️

Caution

SetLocalPlayerTransform() must be called sometime after VoiceChatController.OnInitializedEvent(true) when voice chat is initialized.


  1. Below is a sample script for the voice position change function.
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 {

    // Button to set voice transform close
    public buttonCloserTransform: Button;

    // Button to set voice transform far
    public buttonFartherTransform: Button;

    // Transform for the voice position
    private voiceTransform: Transform;

    Start() {

        // Create new GameObject Assign the transform to store voice transform object
        const voiceTransformObject = new GameObject;  
        this.voiceTransform = voiceTransformObject.transform;

        // Method called when the Voice Chat system is initialized
        VoiceChatController.OnInitializedEvent.AddListener(
            init => {
                let roomProperty = new RoomProperty();

                // Set audio mode to directional 3d space audio
                roomProperty.SetAudioMode(AudioMode.Directional);
                VoiceChatController.EnterRoom(roomProperty);  

                // Set the voice chat transform for local player's voice
                VoiceChatController.SetLocalPlayerTransform(this.voiceTransform);
            }
        );
        
        // Set voice transform position to (0,0,0) when 'buttonCloseTransform' is clicked
        this.buttonCloserTransform.onClick.AddListener(()=>{
            this.voiceTransform.position = Vector3.zero;
        })
        
        // Set voice transform position to a distant point when 'buttonFarTransform' is clicked
        this.buttonFartherTransform.onClick.AddListener(()=>{
            this.voiceTransform.position = new Vector3(0,0,-10);
        })

    }

    // Method to exit the Voice Chat room
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
    }

}

Code Description

  • When the scene starts, create a game object called voiceTransformObject in the Start() function and register the Transform in voiceTransform.
  • When the voice chat OnInitialized listener is called, please apply the following settings:
  • Set voice chat to 3D spatial audio mode via SetAudioMode(AudioMode.Directional).
  • Set the local player's voice chat position to voiceTransform through VoiceChatController.SetLocalPlayerTransform().
  • buttonCloserTransform sets the position of voiceTransform to the origin (0, 0, 0) when the button is clicked.
  • buttonFartherTransform Sets the position of the voiceTransform to (10, 0, 0) when the button is clicked.

  1. Register the button on the Canvas in the scene to the buttonCloserTransform and buttonFartherTransform of the VoiceTransformSample component.

  1. If you run it on your mobile phone using the QR code or test link, you can check the following.
  • When you press the Closer button, your voice will sound closer to others.
  • When you press the Farther button, your voice will be heard far away from others.