# Hiyve RTC Client Developer Documentation

## Table of Contents

1. [Introduction](#introduction)
2. [How to Use](#how-to-use)
3. [Example Code](#example-code)
   - [Server-Side Application](#server-side-application)
   - [Client-Side Application](#client-side-application)
     - [Including the Library](#including-the-library)
     - [Using the Client](#using-the-client)
4. [Server-Side Requirements](#server-side-requirements)
5. [Client-Side Requirements](#client-side-requirements)
6. [Class Reference](#class-reference)
   - [Client](#client)
     - [Constructor](#constructor)
     - [Methods](#methods)
       - [`checkAudioDevice()`](#checkaudiodevice)
       - [`checkVideoDevice()`](#checkvideodevice)
       - [`async closeConnection()`](#async-closeconnection)
       - [`async connectTransports(options)`](#async-connecttransportsoptions)
       - [`async createJoinToken(options)`](#async-createjointokenoptions)
       - [`async createRoom(options)`](#async-createroomoptions)
       - [`async getAttendees()`](#async-getattendees)
       - [`getAudioInputMonitor()`](#getaudioinputmonitor)
       - [`getAudioOutputDeviceId()`](#getaudiooutputdeviceid)
       - [`async getCompositionList(options)`](#async-getcompositionlistoptions)
       - [`async getCompositionStatus(options)`](#async-getcompositionstatusoptions)
       - [`async getCompositionUrl(options)`](#async-getcompositionurloptions)
       - [`getLocalAudioConstraints()`](#getlocalaudioconstraints)
       - [`getLocalAudioInputDeviceId()`](#getlocalaudioinputdeviceid)
       - [`getLocalVideoDeviceId()`](#getlocalvideodeviceid)
       - [`getRecordingId()`](#getrecordingid)
       - [`async getRecordingUrls(options)`](#async-getrecordingurlsoptions)
       - [`async getSignedCompositionUrl(options)`](#async-getsignedcompositionurloptions)
       - [`isLocalAudioPaused()`](#islocalaudiopaused)
       - [`isLocalUserRoomOwner()`](#islocaluserroomowner)
       - [`isLocalVideoPaused()`](#islocalvideopaused)
       - [`isScreenShareActive()`](#isscreenshareactive)
       - [`async joinRoom(options)`](#async-joinroomoptions)
       - [`async joinRoomWithToken(options)`](#async-joinroomwithtokenoptions)
       - [`async listAudioInputDevices()`](#async-listaudioinputdevices)
       - [`async listAudioOutputDevices()`](#async-listaudiooutputdevices)
       - [`async listVideoDevices()`](#async-listvideodevices)
       - [`mergeAudioInput(options)`](#mergeaudioinputoptions)
       - [`async muteLocalAudio(muteAudio, overRide)`](#async-mutelocalaudiomuteaudio-override)
       - [`async muteLocalOutput(muteOutput, overRide)`](#async-mutelocaloutputmuteoutput-override)
       - [`async muteLocalVideo(muteVideo, overRide)`](#async-mutelocalvideomutevideo-override)
       - [`async muteRemoteAudio(options)`](#async-muteremoteaudiooptions)
       - [`async muteRemoteOutput(options)`](#async-muteremoteoutputoptions)
       - [`async muteRemoteVideo(options)`](#async-muteremotevideooptions)
       - [`async sendDataMessage(options)`](#async-senddatamessageoptions)
       - [`setAudioOutputDevice(options)`](#setaudiooutputdeviceoptions)
       - [`async setLocalAudioInputDevice(options)`](#async-setlocalaudioinputdeviceoptions)
       - [`async setLocalVideoDevice(options)`](#async-setlocalvideodeviceoptions)
       - [`async startComposition(options)`](#async-startcompositionoptions)
       - [`async startRecording(options)`](#async-startrecordingoptions)
       - [`async startScreenShare()`](#async-startscreenshare)
       - [`async stopRecording()`](#async-stoprecording)
       - [`async stopScreenShare()`](#async-stopscreenshare)
       - [`unmergeAudioInput(options)`](#unmergeaudioinputoptions)
7. [Sentiment Analysis](./SentimentAnalysis.md)
8. [Events](#events)
9. [Notes](#notes)
10. [Conclusion](#conclusion)

---

## Introduction

Hiyve RTC Client is a comprehensive video conferencing library designed to seamlessly integrate real-time communication features into your applications. It manages connections to servers, handles media devices, and provides a rich set of functionalities for creating and joining rooms, managing media tracks, and interacting with other users.

This documentation provides detailed information on how to use Hiyve RTC Client, including server-side and client-side requirements, as well as a comprehensive reference of available classes and methods, complete with examples for each method.

---

## How to Use

To get started with Hiyve RTC Client, follow these steps:

1. **Create a new instance of the client.**
2. **Use the `listVideoDevices`, `listAudioInputDevices`, and `listAudioOutputDevices` methods to get a list of available devices.**
3. **Set the desired devices using `setLocalVideoDevice`, `setLocalAudioInputDevice`, and `setAudioOutputDevice`.**
4. **Create or join a room using `createRoom` or `joinRoom`.**
   - Note: You can call `createRoom` only once, and that user becomes the owner of the room. When they leave, all other users are disconnected.
5. **Call `connectTransports` to connect the media devices to the room.**
6. **Handle events emitted by the client for actions like new media being added, users disconnecting, and the room closing.**

---

## Example Code

### Server-Side Application

```javascript
// In your server side application
app.post('/generate-room-token', async function (req, res) {
  const apiKey = process.env.APIKEY; // This is your API key obtained from Hiyve. Keep this server-side.
  const clientSecret = process.env.CLIENT_SECRET; // Keep this server-side as well.

  try {
    const response = await fetch('https://rtc.muziemedia.com/room-token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        apiKey: apiKey,
        secret: clientSecret,
      }),
    });
    const data = await response.json();
    if (!response.ok) {
      return res.status(500).send({ error: data.error });
    }
    res.send(data); // Return the generated roomToken back to your client application
  } catch (error) {
    console.error('Error:', error);
    res.status(500).send({ error: 'An error occurred while generating the room token' });
  }
});
```

### Client-Side Application

#### Including the Library

```html
<!-- In index.html (or similar) -->
<head>
  <script src="https://s3.amazonaws.com/muzie.media/dist_latest/muziertcclient.js"></script>
</head>
```

#### Using the Client

```javascript
// In app.jsx (or similar)
const { Client, ClientEvents } = window.MuzieClient;

const client = new Client({
  roomToken: 'your-room-token', // Generated by your server app calling the /room-token endpoint
});

// Add event listeners
client.addEventListener(ClientEvents.MEDIA_TRACK_ADDED, (event) => {
  console.log('Remote user\'s media track added:', event.detail);
  const { userId, track, kind } = event.detail;
  // Use the userId, track, and kind to bind the track to a video & audio element
});

// Get, list, and select a device from devices if needed
const videoDevices = await client.listVideoDevices();
const audioInputDevices = await client.listAudioInputDevices();
const audioOutputDevices = await client.listAudioOutputDevices();

// Set the devices (if needed)
await client.setLocalVideoDevice({ videoDeviceId: videoDevices[0].deviceId });
await client.setLocalAudioInputDevice({ audioInputDeviceId: audioInputDevices[0].deviceId });
await client.setAudioOutputDevice({ audioOutputDeviceId: audioOutputDevices[0].deviceId });

// Create or join a room
const room = await client.createRoom({ roomName: 'my-room', userId: 'my-user' });

// Connect the transports
await client.connectTransports({ localVideoElementId: 'local-video' });

// Mute or unmute the local audio (if needed)
await client.muteLocalAudio(true);

// Close the connection when done
await client.closeConnection();
```

---

## Server-Side Requirements

- **API Key and Secret**: Obtain your API key and secret from Hiyve and keep them secure on your server-side application.
- **Endpoint to Generate Room Token**: Implement an endpoint that calls the Hiyve `/room-token` endpoint to generate a room token.

---

## Client-Side Requirements

- **Include the Hiyve RTC Client Client Library**: Add the Hiyve RTC Client client library script to your HTML file.
- **Initialize the Client**: Create an instance of the `Client` class with the `roomToken` obtained from your server.
- **Handle User Media Devices**: Use provided methods to list and set user media devices.
- **Event Handling**: Add event listeners to handle events emitted by the client.

---

## Class Reference

### Client

This class is responsible for managing the connection to the servers and the media devices. It handles creating and joining rooms, managing media tracks, and emitting events for various actions.

#### Constructor

```javascript
new Client(options)
```

**Parameters:**

- `options` (Object): The options object.
  - `roomToken` (string): Generated from the server by calling the `/room-token` endpoint (required).

**Fires:**

See the [Events](#events) section for a complete list of all 46 events emitted by the Client class.

---

#### Methods

---

##### `checkAudioDevice()`

Check if the browser supports audio output.

**Returns:**

- `(boolean)`: `true` if audio output is supported.

**Example:**

```javascript
if (client.checkAudioDevice()) {
  console.log('Audio output is supported.');
} else {
  console.log('Audio output is not supported.');
}
```

---

##### `checkVideoDevice()`

Check if the browser supports video output.

**Returns:**

- `(boolean)`: `true` if video output is supported.

**Example:**

```javascript
if (client.checkVideoDevice()) {
  console.log('Video output is supported.');
} else {
  console.log('Video output is not supported.');
}
```

---

##### `async closeConnection()`

Close the connection and room. This will close the connection to the server and the room and should always be called when the user wants to leave the room. This will also close the audio context and audio input monitor.

**Returns:**

- `(Promise)`: Resolves when the connection is closed.

**Example:**

```javascript
await client.closeConnection();
console.log('Connection closed.');
```

---

##### `async connectTransports(options)`

Connect the media devices to the room. This method should be called after the room is created or joined.

**Parameters:**

- `options` (Object): The options object.
  - `localVideoElementId` (string): The ID of the video element to attach the local video to.
  - `options` (Object): Additional options.
    - `enableAudioInputMonitor` (boolean): Whether to enable audio input monitor.
    - `enableAudioMerge` (boolean): Whether to enable audio merging.

**Returns:**

- `(Promise)`: Resolves when the media devices are connected.

**Example:**

```javascript
await client.connectTransports({
  localVideoElementId: 'local-video',
  options: {
    enableAudioInputMonitor: true,
    enableAudioMerge: false,
  },
});
console.log('Media devices connected.');
```

---

##### `async createJoinToken(options)`

Create a token that can be used to join a room that has started.

**Parameters:**

- `options` (Object): The options object.
  - `userId` (string): The room owner.
  - `roomName` (string): The name of the room.
  - `joinUserId` (string): The ID of the user that is joining (required for type `'individual'`). If type is `'group'`, `joinUserId` will be ignored.
  - `password` (string): An optional password.
  - `expiresIn` (number): The time in seconds that the token is valid for.
  - `type` (string): The type of token to create (either `'individual'` or `'group'`).

**Returns:**

- `(Promise<string>)`: Resolves with the join token.

**Example:**

```javascript
const joinToken = await client.createJoinToken({
  userId: 'room-owner-id',
  roomName: 'my-room',
  joinUserId: 'joining-user-id',
  password: 'optional-password',
  expiresIn: 3600, // Token valid for 1 hour
  type: 'individual',
});
console.log('Join token created:', joinToken);
```

---

##### `async createRoom(options)`

Create a new room. This can only be called once per room, and the user that creates the room is the owner. The owner can mute and unmute other users, but other users cannot mute the owner. When the owner closes the room, all other users are disconnected.

Note: Room names and user IDs are cleaned to remove non-alphanumeric characters apart from `_` and are lowercased; all `-` are converted to `_`.

**Parameters:**

- `options` (Object): The options object.
  - `roomName` (string): The name of the room.
  - `userId` (string): The ID of the user.
  - `externalUserId` (string): An optional application-specific user ID  (this is recommended and ensure its unique).

**Returns:**

- `(Promise<Room>)`: Resolves with a `Room` object when the room is created.

**Example:**

```javascript
const room = await client.createRoom({
  roomName: 'team-meeting',
  userId: 'user123',
  externalUserId: 'ext-user-456', // Optional
});
console.log('Room created:', room);
```

---

##### `async getAttendees()`

Get the room attendees.

**Returns:**

- `(Array)`: An array of attendee information.

**Example:**

```javascript
const attendees = await client.getAttendees();
console.log('Room attendees:', attendees);
```

---

##### `getAudioInputMonitor()`

Get the audio input monitor. The audio input monitor is used to get the audio levels of the local audio input and is created when the media devices are connected and the `enableAudioInputMonitor` option is set to `true`.

**Returns:**

- `(Object)`: The audio input monitor.

**Example:**

```javascript
const audioMonitor = client.getAudioInputMonitor();
if (audioMonitor) {
  audioMonitor.on('volumeChange', (volume) => {
    console.log('Microphone volume level:', volume);
  });
} else {
  console.log('Audio input monitor not enabled.');
}
```

---

##### `getAudioOutputDeviceId()`

Get the local audio output device ID (if set).

**Returns:**

- `(string)`: The local audio output device ID.

**Example:**

```javascript
const audioOutputDeviceId = client.getAudioOutputDeviceId();
console.log('Current audio output device ID:', audioOutputDeviceId);
```

---

##### `async getCompositionList(options)`

Get the composition list for the room.

**Parameters:**

- `options` (Object): The options object.
  - `roomName` (string): The name of the room.
  - `userId` (string): The ID of the user.

**Returns:**

- `(Promise<Array>)`: Resolves to the list of compositions.

**Example:**

```javascript
const compositions = await client.getCompositionList({
  roomName: 'team-meeting',
  userId: 'user123',
});
console.log('Composition list:', compositions);
```

---

##### `async getCompositionStatus(options)`

Get the status of a composition.

**Parameters:**

- `options` (Object): The options object.
  - `recordingId` (string): The ID of the recording to check.
  - `roomName` (string): The name of the room.

**Returns:**

- `(Promise<string>)`: Resolves to the composition status.

**Example:**

```javascript
const status = await client.getCompositionStatus({
  recordingId: 'recording123',
  roomName: 'team-meeting',
});
console.log('Composition status:', status);
```

---

##### `async getCompositionUrl(options)`

Get the composition URL.

**Parameters:**

- `options` (Object): The options object.
  - `recordingId` (string): The ID of the recording to get the composition URL for.
  - `roomName` (string): The name of the room.
  - `userId` (string): The ID of the user.

**Returns:**

- `(Promise<string>)`: Resolves to the composition URL.

**Example:**

```javascript
const compositionUrl = await client.getCompositionUrl({
  recordingId: 'recording123',
  roomName: 'team-meeting',
  userId: 'user123',
});
console.log('Composition URL:', compositionUrl);
```

---

##### `getLocalAudioConstraints()`

Get the local audio constraints.

**Returns:**

- `(Object)`: The local audio constraints.

**Example:**

```javascript
const audioConstraints = client.getLocalAudioConstraints();
console.log('Audio constraints:', audioConstraints);
```

---

##### `getLocalAudioInputDeviceId()`

Get the local audio input device ID.

**Returns:**

- `(string)`: The local audio input device ID.

**Example:**

```javascript
const audioInputDeviceId = client.getLocalAudioInputDeviceId();
console.log('Current audio input device ID:', audioInputDeviceId);
```

---

##### `getLocalVideoDeviceId()`

Get the local video device ID.

**Returns:**

- `(string)`: The local video device ID.

**Example:**

```javascript
const videoDeviceId = client.getLocalVideoDeviceId();
console.log('Current video device ID:', videoDeviceId);
```

---

##### `getRecordingId()`

Get the recording ID. Only the room owner can start and stop recording and get the recording ID.

**Returns:**

- `(string)`: The recording ID.

**Example:**

```javascript
const recordingId = client.getRecordingId();
console.log('Current recording ID:', recordingId);
```

---

##### `async getRecordingUrls(options)`

Get the recording URLs for a recording ID.

**Parameters:**

- `options` (Object): The options object.
  - `recordingId` (string): The ID of the recording to get the URLs for.
  - `roomName` (string): The name of the room.
  - `userId` (string): The ID of the user.

**Returns:**

- `(Promise<Array>)`: Resolves to the recording URLs.

**Example:**

```javascript
const recordingUrls = await client.getRecordingUrls({
  recordingId: 'recording123',
  roomName: 'team-meeting',
  userId: 'user123',
});
console.log('Recording URLs:', recordingUrls);
```

---

##### `async getSignedCompositionUrl(options)`

Get the signed composition URL. This can also be used to get a signed URL for `recordingUrls` to download individual recordings. Note that this URL will expire after a short period of time.

**Parameters:**

- `options` (Object): The options object.
  - `url` (string): The URL to get the signed composition URL for.

**Returns:**

- `(Promise<string>)`: Resolves to the signed composition URL.

**Example:**

```javascript
const signedUrl = await client.getSignedCompositionUrl({
  url: 'https://example.com/path/to/composition',
});
console.log('Signed composition URL:', signedUrl);
```

---

##### `isLocalAudioPaused()`

Check if the local audio is paused.

**Returns:**

- `(boolean)`: `true` if the audio is paused.

**Example:**

```javascript
if (client.isLocalAudioPaused()) {
  console.log('Local audio is paused.');
} else {
  console.log('Local audio is active.');
}
```

---

##### `isLocalUserRoomOwner()`

Check if the local user is the room owner.

**Returns:**

- `(boolean)`: `true` if the local user is the room owner.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  console.log('You are the room owner.');
} else {
  console.log('You are not the room owner.');
}
```

---

##### `isLocalVideoPaused()`

Check if the local video is paused.

**Returns:**

- `(boolean)`: `true` if the video is paused.

**Example:**

```javascript
if (client.isLocalVideoPaused()) {
  console.log('Local video is paused.');
} else {
  console.log('Local video is active.');
}
```

---

##### `isScreenShareActive()`

Check if screen sharing is active.

**Returns:**

- `(boolean)`: `true` if screen sharing is active.

**Example:**

```javascript
if (client.isScreenShareActive()) {
  console.log('Screen sharing is active.');
} else {
  console.log('Screen sharing is not active.');
}
```

---

##### `async joinRoom(options)`

Join an existing room. Users will use this method to join a room that has already been created.

Note: Room names and user IDs are cleaned to remove non-alphanumeric characters apart from `_` and are lowercased; all `-` are converted to `_`.

**Parameters:**

- `options` (Object): The options object.
  - `roomName` (string): The name of the room.
  - `userId` (string): The ID of the user.
  - `externalUserId` (string): An optional application-specific user ID  (this is recommended and ensure its unique).

**Returns:**

- `(Promise<Room>)`: Resolves with a `Room` object when the user has joined the room.

**Example:**

```javascript
const room = await client.joinRoom({
  roomName: 'team-meeting',
  userId: 'user456',
  externalUserId: 'ext-user-789', // Optional
});
console.log('Joined room:', room);
```

---

##### `async joinRoomWithToken(options)`

Join an existing room using a join token created by the room owner using `createJoinToken`.

**Parameters:**

- `options` (Object): The options object.
  - `joinToken` (string): The join token created by the room owner.
  - `password` (string): An optional password.
  - `userId` (string): The ID of the user joining the room.

**Returns:**

- `(Promise<Room>)`: Resolves with a `Room` object when the user has joined the room.

**Example:**

```javascript
const room = await client.joinRoomWithToken({
  joinToken: 'provided-join-token',
  password: 'optional-password',
  userId: 'user456',
});
console.log('Joined room with token:', room);
```

---

##### `async listAudioInputDevices()`

Return a list of all the audio input devices available. Forces a permissions prompt where applicable.

**Returns:**

- `(Promise<Array>)`: A list of audio input devices.

**Example:**

```javascript
const audioInputDevices = await client.listAudioInputDevices();
audioInputDevices.forEach((device) => {
  console.log(`Audio Input Device: ${device.label} (${device.deviceId})`);
});
```

---

##### `async listAudioOutputDevices()`

Return a list of all the audio output devices available.

**Returns:**

- `(Promise<Array>)`: A list of audio output devices.

**Example:**

```javascript
const audioOutputDevices = await client.listAudioOutputDevices();
audioOutputDevices.forEach((device) => {
  console.log(`Audio Output Device: ${device.label} (${device.deviceId})`);
});
```

---

##### `async listVideoDevices()`

Return a list of all the video devices available. Forces a permissions prompt where applicable.

**Returns:**

- `(Promise<Array>)`: A list of video devices.

**Example:**

```javascript
const videoDevices = await client.listVideoDevices();
videoDevices.forEach((device) => {
  console.log(`Video Device: ${device.label} (${device.deviceId})`);
});
```

---

##### `mergeAudioInput(options)`

Merge a new audio stream into the current audio channel being sent to remote peers. This is useful for adding background music or other audio streams to the audio channel.

**Parameters:**

- `options` (Object): The options object.
  - `stream` (MediaStream): The audio stream to merge.

**Returns:**

- `(Promise<MediaStreamTrack>)`: Resolves to the merged track to be used to unmerge when done.

**Example:**

```javascript
// Assume we have a MediaStream from an audio file or other source
const backgroundMusicStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });

const mergedTrack = await client.mergeAudioInput({ stream: backgroundMusicStream });
console.log('Audio stream merged.');

// To unmerge later
await client.unmergeAudioInput({ stream: backgroundMusicStream });
console.log('Audio stream unmerged.');
```

---

##### `async muteLocalAudio(muteAudio, overRide)`

Mute or unmute the local audio.

**Parameters:**

- `muteAudio` (boolean): Whether to mute the audio.
- `overRide` (boolean): Should only be used internally.

**Returns:**

- `(Promise)`: Resolves when the audio is muted or unmuted.

**Example:**

```javascript
// Mute local audio
await client.muteLocalAudio(true);
console.log('Local audio muted.');

// Unmute local audio
await client.muteLocalAudio(false);
console.log('Local audio unmuted.');
```

---

##### `async muteLocalOutput(muteOutput, overRide)`

Mute or unmute the local audio output. Note that for this to work, all remote video elements must have an ID starting with `'remote-video-'`.

**Parameters:**

- `muteOutput` (boolean): Whether to mute the output.
- `overRide` (boolean): Should only be used internally.

**Returns:**

- `(Promise)`: Resolves when the output is muted or unmuted.

**Example:**

```javascript
// Mute local audio output
await client.muteLocalOutput(true);
console.log('Local audio output muted.');

// Unmute local audio output
await client.muteLocalOutput(false);
console.log('Local audio output unmuted.');
```

---

##### `async muteLocalVideo(muteVideo, overRide)`

Mute or unmute the local video.

**Parameters:**

- `muteVideo` (boolean): Whether to mute the video.
- `overRide` (boolean): Should only be used internally.

**Returns:**

- `(Promise)`: Resolves when the video is muted or unmuted.

**Example:**

```javascript
// Mute local video
await client.muteLocalVideo(true);
console.log('Local video muted.');

// Unmute local video
await client.muteLocalVideo(false);
console.log('Local video unmuted.');
```

---

##### `async muteRemoteAudio(options)`

Mute or unmute the remote audio. Can only be used by the room owner.

**Parameters:**

- `options` (Object): The options object.
  - `room` (Room): The room object.
  - `userId` (string): The ID of the user to mute.
  - `muteAudio` (boolean): Whether to mute the audio.

**Returns:**

- `(Promise)`: Resolves when the message is sent and the audio is muted or unmuted.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.muteRemoteAudio({
    room: room,
    userId: 'user456',
    muteAudio: true,
  });
  console.log('Remote user audio muted.');
} else {
  console.log('Only the room owner can mute remote users.');
}
```

---

##### `async muteRemoteOutput(options)`

Mute or unmute the remote audio output. Can only be used by the room owner.

**Parameters:**

- `options` (Object): The options object.
  - `room` (Room): The room object.
  - `userId` (string): The ID of the user to mute.
  - `muteOutput` (boolean): Whether to mute the output.

**Returns:**

- `(Promise)`: Resolves when the message is sent and the output is muted or unmuted.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.muteRemoteOutput({
    room: room,
    userId: 'user456',
    muteOutput: true,
  });
  console.log('Remote user output muted.');
} else {
  console.log('Only the room owner can mute remote users.');
}
```

---

##### `async muteRemoteVideo(options)`

Mute or unmute the remote video. Can only be used by the room owner.

**Parameters:**

- `options` (Object): The options object.
  - `room` (Room): The room object.
  - `userId` (string): The ID of the user to mute.
  - `muteVideo` (boolean): Whether to mute the video.

**Returns:**

- `(Promise)`: Resolves when the message is sent and the video is muted or unmuted.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.muteRemoteVideo({
    room: room,
    userId: 'user456',
    muteVideo: true,
  });
  console.log('Remote user video muted.');
} else {
  console.log('Only the room owner can mute remote users.');
}
```

---

##### `async sendDataMessage(options)`

Send a data message to a specific user or to all users in the room.

**Parameters:**

- `options` (Object): The options object.
  - `userId` (string): The ID of the user to send the message to. If `null`, the message will be sent to all users.
  - `message` (Object): The message to send.
  - `preventReturn` (boolean): Whether to prevent the message from being sent back to the sender (useful to prevent message echo).

**Returns:**

- `(Promise)`: Resolves when the message is sent.

**Example:**

```javascript
// Send a message to all users
await client.sendDataMessage({
  userId: null,
  message: { type: 'chat', content: 'Hello everyone!' },
  preventReturn: true,
});
console.log('Message sent to all users.');

// Send a message to a specific user
await client.sendDataMessage({
  userId: 'user456',
  message: { type: 'private-chat', content: 'Hello!' },
  preventReturn: true,
});
console.log('Private message sent.');
```

---

##### `setAudioOutputDevice(options)`

Set the local audio output device. Checks to see if a `sinkId` is available, and if not, throws an error.

**Parameters:**

- `options` (Object): The options object.
  - `audioOutputDeviceId` (string): The ID of the audio output device to use.

**Example:**

```javascript
try {
  client.setAudioOutputDevice({ audioOutputDeviceId: 'default' });
  console.log('Audio output device set.');
} catch (error) {
  console.error('Error setting audio output device:', error);
}
```

---

##### `async setLocalAudioInputDevice(options)`

Set the local audio input device.

**Parameters:**

- `options` (Object): The options object.
  - `audioInputDeviceId` (string): The ID of the audio input device to use. If connected and the device changes, the stream will be updated.
  - `constraints` (Object): The audio constraints to apply for the audio input.
  - `force` (boolean): Whether to force the change even if the device is the same (internal only).

**Returns:**

- `(Promise<MediaStream>)`: Resolves with the media stream.

**Example:**

```javascript
const audioStream = await client.setLocalAudioInputDevice({
  audioInputDeviceId: 'microphone-id',
  constraints: { echoCancellation: true },
});
console.log('Audio input device set:', audioStream);
```

---

##### `async setLocalVideoDevice(options)`

Set the local video device. If connected, updates the stream and attaches it to the video element.

**Parameters:**

- `options` (Object): The options object.
  - `videoDeviceId` (string): The ID of the video device to use.

**Returns:**

- `(Promise<MediaStream>)`: Resolves with the media stream.

**Example:**

```javascript
const videoStream = await client.setLocalVideoDevice({
  videoDeviceId: 'camera-id',
});
console.log('Video device set:', videoStream);
```

---

##### `async startComposition(options)`

Start composing the recording into a grid. Only the room owner can start composition.

**Parameters:**

- `options` (Object): The options object.
  - `recordingId` (string): The ID of the recording to compose.

**Returns:**

- `(Promise<void>)`: Resolves when the composition is started.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.startComposition({ recordingId: 'recording123' });
  console.log('Composition started.');
} else {
  console.log('Only the room owner can start composition.');
}
```

---

##### `async startRecording(options)`

Start recording the room. This will start recording the room, and all users will be recorded. Only the room owner can start recording.

**Parameters:**

- `options` (Object): The options object.
  - `type` (string): The type of recording to start (currently can be `'cloud'`).
  - `options` (Object): The options for the recording.
    - `autoCompose` (boolean): If `true`, will automatically start composing the recording into a grid when the recording is stopped.

**Returns:**

- `(Promise<void>)`: Resolves when the recording is started.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.startRecording({
    type: 'cloud',
    options: { autoCompose: true },
  });
  console.log('Recording started.');
} else {
  console.log('Only the room owner can start recording.');
}
```

---

##### `async startScreenShare()`

Start screen sharing. This will replace the video of the local user with the screen share.

**Returns:**

- `(Promise)`: Resolves when the screen share is started.

**Example:**

```javascript
await client.startScreenShare();
console.log('Screen sharing started.');
```

---

##### `async stopRecording()`

Stop recording the room. Only the room owner can stop recording.

**Returns:**

- `(Promise<void>)`: Resolves when the recording is stopped.

**Example:**

```javascript
if (client.isLocalUserRoomOwner()) {
  await client.stopRecording();
  console.log('Recording stopped.');
} else {
  console.log('Only the room owner can stop recording.');
}
```

---

##### `async stopScreenShare()`

Stop screen sharing. This will stop the screen share and replace the video of the local user with the camera video.

**Returns:**

- `(Promise)`: Resolves when the screen share is stopped.

**Example:**

```javascript
await client.stopScreenShare();
console.log('Screen sharing stopped.');
```

---

##### `unmergeAudioInput(options)`

Unmerge the audio stream (if one was merged using `mergeAudioInput`).

**Parameters:**

- `options` (Object): The options object.
  - `stream` (MediaStream): The audio stream to unmerge.

**Example:**

```javascript
// Assuming 'backgroundMusicStream' was previously merged
await client.unmergeAudioInput({ stream: backgroundMusicStream });
console.log('Audio stream unmerged.');
```

---

##### `async startStreaming(options)`

Start live streaming to an external platform (YouTube, Twitch, etc.). Only the room owner can start streaming.

**Parameters:**

- `options` (Object): The streaming options.
  - `type` (string): The streaming type (e.g., `'rtmp'`).
  - `options` (Object): Platform-specific options.
    - `streamUrl` (string): The RTMP URL for the streaming platform.
    - `streamKey` (string): The stream key provided by the platform.

**Returns:**

- `(Promise<Object>)`: Resolves with `{ streamingId }` when streaming starts.

**Fires:**

- `ClientEvents.STREAMING_STARTED`

**Example:**

```javascript
const { streamingId } = await client.startStreaming({
  type: 'rtmp',
  options: {
    streamUrl: 'rtmp://a.rtmp.youtube.com/live2',
    streamKey: 'xxxx-xxxx-xxxx-xxxx'
  }
});
console.log('Live streaming started:', streamingId);
```

---

##### `async stopStreaming()`

Stop live streaming. Only the room owner can stop streaming.

**Returns:**

- `(Promise)`: Resolves when streaming stops.

**Fires:**

- `ClientEvents.STREAMING_STOPPED`

**Example:**

```javascript
await client.stopStreaming();
console.log('Live streaming stopped.');
```

---

##### `async startTranscribing()`

Start real-time transcription for the meeting. Only the room owner can start transcription.

**Returns:**

- `(Promise<Object>)`: Resolves with `{ transcribingId }` when transcription starts.

**Fires:**

- `ClientEvents.TRANSCRIPTION_STARTED`
- `ClientEvents.TRANSCRIPTION_RECEIVED` (continuously, as text is transcribed)

**Example:**

```javascript
const { transcribingId } = await client.startTranscribing();
console.log('Transcription started:', transcribingId);

client.addEventListener(ClientEvents.TRANSCRIPTION_RECEIVED, (event) => {
  const { text, userId, isFinal } = event.detail;
  if (isFinal) {
    console.log(`${userId}: ${text}`);
  }
});
```

---

##### `async stopTranscribing()`

Stop real-time transcription. Only the room owner can stop transcription.

**Returns:**

- `(Promise)`: Resolves when transcription stops.

**Fires:**

- `ClientEvents.TRANSCRIPTION_STOPPED`

**Example:**

```javascript
await client.stopTranscribing();
console.log('Transcription stopped.');
```

---

##### `async reconnect(options)`

Reconnect to the room after a connection loss. Preserves local mute state and restores media streams.

**Parameters:**

- `options` (Object): Optional reconnection options.
  - `options` (Object): Additional options to pass during reconnection.
  - `waitingRoomToken` (string): Token if rejoining via waiting room.

**Returns:**

- `(Promise)`: Resolves when reconnection is complete.

**Example:**

```javascript
client.addEventListener(ClientEvents.DISCONNECTED, async () => {
  console.log('Connection lost, attempting to reconnect...');
  try {
    await client.reconnect();
    console.log('Reconnected successfully');
  } catch (error) {
    console.error('Reconnection failed:', error);
  }
});
```

---

##### `async admitWaitingRoomUser(options)`

Admit a user from the waiting room into the meeting. Only the room owner can admit users.

**Parameters:**

- `options` (Object): The options object.
  - `waitingRoomToken` (string): The token of the waiting user.

**Returns:**

- `(Promise)`: Resolves when the user is admitted.

**Example:**

```javascript
client.addEventListener(ClientEvents.ADMIT_WAITING_ROOM, async (event) => {
  const { userId, waitingRoomToken } = event.detail;
  // Optionally show UI to approve/reject
  await client.admitWaitingRoomUser({ waitingRoomToken });
  console.log('User admitted:', userId);
});
```

---

##### `async rejectWaitingRoomUser(options)`

Reject a user from the waiting room. Only the room owner can reject users.

**Parameters:**

- `options` (Object): The options object.
  - `waitingRoomToken` (string): The token of the waiting user.

**Returns:**

- `(Promise)`: Resolves when the user is rejected.

**Fires:**

- `ClientEvents.REJECT_WAITING_ROOM`

**Example:**

```javascript
await client.rejectWaitingRoomUser({ waitingRoomToken });
console.log('User rejected from waiting room.');
```

---

##### `async sendChatMessage(options)`

Send a chat message to all participants in the room.

**Parameters:**

- `options` (Object): The options object.
  - `message` (string): The chat message to send.

**Returns:**

- `(Promise)`: Resolves when the message is sent.

**Example:**

```javascript
await client.sendChatMessage({ message: 'Hello everyone!' });
```

---

##### `async getChatHistory(options)`

Get the chat message history for the current room.

**Parameters:**

- `options` (Object): Optional pagination options.
  - `cursor` (string): Pagination cursor for fetching more messages.

**Returns:**

- `(Promise<Object>)`: Resolves with `{ messages, cursor }`.

**Example:**

```javascript
const { messages, cursor } = await client.getChatHistory();
messages.forEach(msg => {
  console.log(`${msg.userId}: ${msg.message}`);
});
```

---

##### `isConnected()`

Check if the client is currently connected to a room.

**Returns:**

- `(boolean)`: `true` if connected, `false` otherwise.

**Example:**

```javascript
if (client.isConnected()) {
  console.log('Currently in a room');
} else {
  console.log('Not connected');
}
```

---

##### `getRemoteUserMediaStatus(userId)`

Get the media status (audio/video mute state) of a remote participant.

**Parameters:**

- `userId` (string): The user ID of the remote participant.

**Returns:**

- `(Object)`: Media status object with properties:
  - `hasAudio` (boolean): Whether the user has an audio track.
  - `hasVideo` (boolean): Whether the user has a video track.
  - `audioPaused` (boolean): Whether the user's audio is muted.
  - `videoPaused` (boolean): Whether the user's video is muted.

**Example:**

```javascript
const status = client.getRemoteUserMediaStatus('user-123');
console.log('Audio muted:', status.audioPaused);
console.log('Video muted:', status.videoPaused);
```

---

#### File Management Methods

The Client provides a complete file management API for uploading, sharing, and organizing files. See the [Workflow Guide](./MUZIERTCCLIENT_API_WORKFLOWS.md#7-file-management-workflows) for detailed examples.

**Available methods:**
- `uploadFile({ file, location, resourceType, appData })` - Upload a file
- `deleteFile({ fileId })` - Delete a file
- `updateFilename({ fileId, newFilename })` - Rename a file
- `moveFile({ fileId, newLocation })` - Move a file to a different folder
- `shareFile({ fileId, userIds, sharedRoom })` - Share a file with users
- `getFileURL({ fileId })` - Get download URL for a file
- `getFileMetadata({ fileId })` - Get file metadata
- `getUsersFiles()` - Get all files for the current user
- `getUsersFilesSinceLastSync({ lastSyncTime })` - Get files modified since last sync
- `getAllUsersFiles()` - Get files from all users (room owner only)
- `getUsersFilesOfType({ resourceType })` - Get files of a specific type
- `createFolder({ location })` - Create a new folder
- `deleteFolder({ location })` - Delete a folder

---

## Events

The `Client` class emits 46 events that can be listened to using `addEventListener()`. Import `ClientEvents` for type-safe event names.

For detailed workflow examples using these events, see the [Workflow Guide](./MUZIERTCCLIENT_API_WORKFLOWS.md).

### Connection Events

| Event | Description | Payload |
|-------|-------------|---------|
| `CONNECTED` | WebRTC transport connection established | `{}` |
| `DISCONNECTED` | WebRTC transport connection lost | `{}` |
| `ROOM_JOINED` | Successfully joined a room | `{ room }` |
| `ROOM_CLOSED` | Room closed by owner | `{ reason }` |
| `ERROR` | Error occurred | `{ error, message }` |

### User Events

| Event | Description | Payload |
|-------|-------------|---------|
| `USER_JOINED_ROOM` | New participant joined | `{ userId, externalUserId, audioOnly }` |
| `USER_DISCONNECTED` | Participant left | `{ userId }` |

### Media Events

| Event | Description | Payload |
|-------|-------------|---------|
| `MEDIA_TRACK_ADDED` | Remote track available | `{ userId, track, kind, paused, audioOnly }` |
| `MEDIA_TRACK_REMOVED` | Remote track removed | `{ userId, kind }` |
| `SCREEN_SHARE_STARTED` | Screen sharing started | `{ userId }` |
| `SCREEN_SHARE_STOPPED` | Screen sharing stopped | `{ userId }` |

### Mute Events

| Event | Description | Payload |
|-------|-------------|---------|
| `AUDIO_MUTED` | Local audio mute state changed | `{ muted }` |
| `VIDEO_MUTED` | Local video mute state changed | `{ muted }` |
| `OUTPUT_MUTED` | Local audio output mute state changed | `{ muted }` |
| `REMOTE_AUDIO_MUTED` | Room owner requested audio mute | `{ muted }` |
| `REMOTE_VIDEO_MUTED` | Room owner requested video mute | `{ muted }` |
| `REMOTE_OUTPUT_MUTED` | Room owner requested output mute | `{ muted }` |

### Recording & Streaming Events

| Event | Description | Payload |
|-------|-------------|---------|
| `RECORDING_STARTED` | Recording in progress | `{ recordingId }` |
| `RECORDING_STOPPED` | Recording stopped | `{ recordingId }` |
| `RECORDING_STATE_CHANGED` | Recording state update | `{ state, recordingId }` |
| `STREAMING_STARTED` | Live streaming started | `{ streamingId }` |
| `STREAMING_STOPPED` | Live streaming stopped | `{ streamingId }` |
| `STREAMING_USER_CHANGED` | Featured user in stream changed | `{ userId }` |

### Transcription Events

| Event | Description | Payload |
|-------|-------------|---------|
| `TRANSCRIPTION_RECEIVED` | Transcribed text received | `{ text, userId, timestamp, isFinal }` |
| `TRANSCRIPTION_STARTED` | Transcription service started | `{ transcribingId }` |
| `TRANSCRIPTION_STOPPED` | Transcription service stopped | `{ transcribingId }` |

### Audio Events

| Event | Description | Payload |
|-------|-------------|---------|
| `AUDIO_INPUT_MONITOR_CREATED` | Audio monitor available | `{ monitor }` |
| `AUDIO_GAIN_CONTROL_CREATED` | Gain control available | `{ gainControl }` |
| `AUDIO_STREAM_ADDED` | Audio stream merged | `{ stream }` |
| `AUDIO_STREAM_REMOVED` | Merged audio stream removed | `{ stream }` |
| `FEEDBACK_DETECTED` | Audio feedback detected | `{}` |
| `FEEDBACK_STOPPED` | Audio feedback stopped | `{}` |

### Device Events

| Event | Description | Payload |
|-------|-------------|---------|
| `AUDIO_INPUT_DEVICE_CHANGED` | Audio input device changed | `{ deviceId }` |
| `VIDEO_INPUT_DEVICE_CHANGED` | Video input device changed | `{ deviceId }` |
| `AUDIO_OUTPUT_DEVICE_CHANGED` | Audio output device changed | `{ deviceId }` |
| `AUDIO_VALIDATION_FAILED` | Audio validation failed | `{ error, constraints }` |
| `AUDIO_VALIDATION_WARNING` | Audio validation has warnings | `{ warning, constraints }` |
| `CONSTRAINTS_RELAXED` | Media constraints relaxed due to errors | `{ originalConstraints, relaxedConstraints }` |

### Communication Events

| Event | Description | Payload |
|-------|-------------|---------|
| `RECEIVE_CHAT_MESSAGE` | New chat message | `{ message, userId, timestamp }` |
| `DATA_MESSAGE` | Custom data message received | `{ message, userId }` |

### Waiting Room Events

| Event | Description | Payload |
|-------|-------------|---------|
| `ADMIT_WAITING_ROOM` | User waiting for admission | `{ userId, waitingRoomToken }` |
| `REJECT_WAITING_ROOM` | User rejected from waiting room | `{ userId }` |
| `WAIT_FOR_HOST_STARTED` | Waiting for host to start meeting | `{}` |
| `WAIT_FOR_HOST_ROOM_READY` | Host started, room is ready | `{ room }` |
| `WAIT_FOR_HOST_TIMEOUT` | Waiting for host timed out | `{}` |
| `WAIT_FOR_HOST_CANCELLED` | Waiting for host cancelled | `{}` |

### Example Usage

```javascript
import { Client, ClientEvents } from 'muziertcclient';

const client = new Client({ roomToken });

// Connection events
client.addEventListener(ClientEvents.CONNECTED, () => {
  console.log('Connected to room');
});

// Media events - handle remote participants
client.addEventListener(ClientEvents.MEDIA_TRACK_ADDED, (event) => {
  const { userId, track, kind, paused } = event.detail;
  console.log(`${kind} track from ${userId}, muted: ${paused}`);
});

// User events
client.addEventListener(ClientEvents.USER_JOINED_ROOM, (event) => {
  console.log('User joined:', event.detail.userId);
});

// Mute state changes
client.addEventListener(ClientEvents.AUDIO_MUTED, (event) => {
  console.log('Local audio muted:', event.detail.muted);
});

// Communication
client.addEventListener(ClientEvents.DATA_MESSAGE, (event) => {
  console.log('Message from', event.detail.userId, ':', event.detail.message);
});

// Recording
client.addEventListener(ClientEvents.RECORDING_STARTED, (event) => {
  console.log('Recording started:', event.detail.recordingId);
});

// Transcription
client.addEventListener(ClientEvents.TRANSCRIPTION_RECEIVED, (event) => {
  const { text, userId, isFinal } = event.detail;
  if (isFinal) {
    console.log(`${userId}: ${text}`);
  }
});
```

---

## Notes

- **Room Ownership**: The user who creates the room is the owner and has special privileges like muting other users and starting/stopping recordings.
- **Device Selection**: It's recommended to list and allow users to select their preferred audio and video devices before joining a room.
- **Event Handling**: Properly handling events emitted by the client is crucial for a smooth user experience.
- **Security**: Keep your API keys and secrets secure on the server-side and never expose them in client-side code.
- **Permissions**: Some methods will prompt the user for permissions to access media devices; ensure to handle these prompts gracefully.

---

## Conclusion

Hiyve RTC Client provides a powerful and flexible way to add real-time video conferencing capabilities to your application. By following this documentation, you can integrate and utilize the various features offered by the library to build engaging and interactive communication experiences.

For further assistance or questions, please refer to the official Hiyve RTC Client documentation or contact support.

---
