import { Meta } from '@storybook/blocks';

<Meta title="SDK Providers/MeetingManager" />

# MeetingManager

The `MeetingManager` is a class that helps integration with the SDK. It is tied to the `MeetingProvider` and is primarily responsible for joining, starting, and leaving your meeting.

You can pass in the same `MeetingManager` instance to multiple different `MeetingProvider`s through props. This will override new `MeetingManager` instance creation inside
the `MeetingProvider`. This is to support very specific cases where you may have different React trees within you applications. For example, you are migrating
from an Angular application to a React application.

You can access the `MeetingManager` instance with the `useMeetingManager` hook.

## Constructor

You need to pass a class implementing [Logger](https://aws.github.io/amazon-chime-sdk-js/interfaces/logger.html) interface as a required property to construct a `MeetingManager` object.

```js
const logger = new ConsoleLogger('LoggerName');
const meetingManager = new MeetingManager(logger);
```

## Interface

### `meetingManager.join`

`meetingManager.join` creates a `MeetingSession` using the passed `MeetingSessionConfiguration` and `options`. `options` use `MeetingManagerJoinOptions` type interface.
`join` will attempt to select default devices for the user.

```typescript
(meetingSessionConfiguration: MeetingSessionConfiguration, options?: MeetingManagerJoinOptions) => Promise<void>
```

Let's take a deeper look at the interface of the `join` method params.

##### `MeetingSessionConfiguration`

```typescript
// Use the `MeetingSessionConfiguration`.
// The default properties of the `MeetingSessionConfiguration` can be updated to customize the meeting as per the builder's preference.
// Reference `MeetingSessionConfiguration` properties in Amazon Chime SDK for JavaScript: https://aws.github.io/amazon-chime-sdk-js/classes/meetingsessionconfiguration.html
meetingSessionConfiguration: MeetingSessionConfiguration;
```

##### `MeetingManagerJoinOptions`

```typescript
options?: {
  // The kind of device for which the browser requests permission.
  // Or override the default device label trigger in the Amazon Chime SDK for JavaScript.
  deviceLabels?: DeviceLabels | DeviceLabelTrigger;

  // Override the default event controller in the Amazon Chime SDK for JavaScript.
  eventController?: EventController;

  // If you want to enable Amazon Voice Focus feature, you should enable Web Audio for the meeting and pass the `enableWebAudio` prop with value set to `true`.
  // By default, `enableWebAudio` is `false`.
  enableWebAudio?: boolean;

  // The `ActiveSpeakerPolicy` object that you want to be used in the meeting session.
  // For more information on `ActiveSpeakerPolicy`, check Amazon Chime SDK for JavaScript ActiveSpeakerPolicy (https://aws.github.io/amazon-chime-sdk-js/interfaces/activespeakerpolicy.html).
  activeSpeakerPolicy?: ActiveSpeakerPolicy;

  /*
    The `meetingManager.join` API by default lists and selects the first available audio input, output and video input device.
    The audio and video devices listing and selection is needed for a successful meeting session start using `meetingManager.start` API following the `meetingManager.join` API call and then to start a video.
    In cases where you want to control the devices listing and selection on your side before joining a meeting, you can set `skipDeviceSelection` to `true`.
    With `skipDeviceSelection` being true`, the `meetingManager.join` API will not do any default devices listing and selection and it will be your responsibility to select the devices.
    Default is `false`.
    Note: Audio output device selection is only available in browsers that support `setSinkId`.
  */
  skipDeviceSelection?: boolean;
}
```

### `meetingManager.start`

Starts the meeting session so that attendees can receive audio and video from the meeting. This must be called after calling `join`.

```javascript
() => Promise<void>
```

### `meetingManager.leave`

Stops the meeting session and performs cleanup. This should be called anytime a user needs to leave a meeting.

```javascript
() => Promise<void>
```

### `meetingManager.getAttendee`

This method is expected to be supplied by the developer. You may call this function with the Chime user ID and external user ID anytime an attendee joins the meeting, and expect to be resolved with an object that has a `name` property that will be used for video nameplates and roster state. We also add support for optional keys, so you can also pass any other data except `name`.

For example - you may want to fetch the attendee from the database, or get the name from some local application state. This is up to the developer.

```javascript
(
  chimeAttendeeId: string,
  externalUserId?: string
) => Promise<AttendeeResponse>

interface AttendeeResponse {
  name?: string;
  [attribute: string]: any;
}
```

## Usage

`MeetingProvider` must be rendered somewhere higher in the tree. Call `useMeetingManager` hook to get the `MeetingManager` object.

```jsx
import React from 'react';
import { MeetingProvider, useMeetingManager } from 'amazon-chime-sdk-component-library-react';

const App = () => (
  <MeetingProvider>
    <MyApp />
  </MeetingProvider>
);

const MyApp = () => {
  const meetingManager = useMeetingManager();

  ...
}
```

## Usage Examples

### `MeetingManager` instance is created internally in the `MeetingProvider` and can be retrived using `useMeetingManager` hook.

```jsx
import {
  MeetingProvider,
  useMeetingManager,
} from 'amazon-chime-sdk-component-library-react';

const Root = () => (
  <MeetingProvider>
    <MyApp />
  </MeetingProvider>
);

const MyApp = () => {
  const meetingManager = useMeetingManager();

  useEffect(() => {
    meetingManager.getAttendee = async (
      chimeAttendeeId: string,
      externalUserId?: string
    ) => {
      const response = await fetch('/my-attendees-endpoint');
      const user = await response.json();

      return {
        name: user.name,
      };
    };
  }, []);
};
```

### Update the `MeetingSessionConfiguration` properties being passed to the `join` method

With V3 of the Amazon Chime SDK for JavaScript, builders now have the option of updating the properties of `MeetingSessionConfiguration`. `MeetingSessionConfiguration` is a class that allows the users to configure the meeting session.

The class contains several properties like `videoUplinkBandwidthPolicy`, `videoDownlinkBandwidthPolicy`, `attendeePresenceTimeoutMs` etc. You can learn more about the available properties at [MeetingSessionConfiguration](https://aws.github.io/amazon-chime-sdk-js/classes/meetingsessionconfiguration.html)
in the SDK documentation. The following code example shows a `MeetingSessionConfiguration` where the default value of the properties are overridden to cusomize the meeting session.

```jsx
import { useMeetingManager } from 'amazon-chime-sdk-component-library-react';
import { MeetingSessionConfiguration, VideoPriorityBasedPolicyConfig } from 'amazon-chime-sdk-js';

const MyApp = () => {
  const meetingManager = useMeetingManager();

  const joinMeeting = async () => {
    // Fetch the meeting and attendee data from your server application
    const response = await fetch('/my-server');
    const data = await response.json();

    // Initalize the `MeetingSessionConfiguration`
    const meetingSessionConfiguration = new MeetingSessionConfiguration(data.Meeting, data.Attendee);

    // Update the `MeetingSessionConfiguration` properties
    meetingSessionConfiguration.attendeePresenceTimeoutMs = 120;
    meetingSessionConfiguration.videoDownlinkBandwidthPolicy = new VideoPriorityBasedPolicy(
      logger,
      VideoPriorityBasedPolicyConfig.UnstableNetworkPreset,
    );

    // Create a `MeetingSession` using `join()` function with the modified `MeetingSessionConfiguration`
    await meetingManager.join(
      meetingSessionConfiguration
    );

    // At this point you could let users setup their devices, or by default
    // the SDK will select the first device in the list for the kind indicated
    // by `deviceLabels` (the default value is DeviceLabels.AudioAndVideo)
    ...

    // Start the `MeetingSession` to join the meeting
    await meetingManager.start();
  };

  return <button onClick={joinMeeting}>Join</button>;
};
```

### Share the same `MeetingManager` instance with multiple different `MeetingProvider`s.

**IMPORTANT NOTE**
This approach has limitations. This should be used only in very specific cases where you want to share the meeting manager instance
variable values and you will not use video, roster and audio at both places. Still, the hooks and providers may not work as expected as `MeetingProvider` wraps all the other providers.
The video will not work at both places due to limitations of JS SDK to bind a video stream to a single video tile only. Please check [this](https://github.com/aws/amazon-chime-sdk-component-library-react/issues/492#issuecomment-846317339) issue for more details.

Please make sure your app calls `meetingManager.join()` only once with the same `attendeeInfo`.
Otherwise, the previous attendee who joined the meeting will leave the meeting with [AudioJoinedFromAnotherDevice](https://aws.github.io/amazon-chime-sdk-js/enums/meetingsessionstatuscode.html#audiojoinedfromanotherdevice).

You can create a new `MeetingManager` instance and then pass it as a prop to your `MeetingProvider`s. If not passed,
a new `MeetingManager` instance will be created internally with each `MeetingProvider` when rendered; and,
you will get the `MeetingManager` instance associated with that particular `MeetingProvider` when `useMeetingManager` hook is called.

```jsx
import { ConsoleLogger } from 'amazon-chime-sdk-js';
import { MeetingProvider, useMeetingManager } from 'amazon-chime-sdk-component-library-react';

const Root = () => {
  const meetingManager = new MeetingManager(new ConsoleLogger('LoggerName'));

  return (
    <MeetingProvider meetingManager={meetingManager}>
      <MyApp1 />
    </MeetingProvider>

    <MeetingProvider meetingManager={meetingManager}>
      <MyApp2 />
    </MeetingProvider>
  );
}
```

### Opt-out of client event ingestion.

The Amazon Chime SDK for JavaScript sends meeting events to the Amazon Chime backend to analyze meeting health trends or identify common failures.
This helps to improve your meeting experience. For more information, check the [client event ingestion guide](https://aws.github.io/amazon-chime-sdk-js/modules/clientevent_ingestion.html) in the Amazon Chime SDK for JavaScript guides.

To opt-out of event ingestion from the Amazon Chime SDK for JavaScript, provide a `DefaultEventController` with a `NoOpEventReporter` as the `eventReporter` while joining the meeting.

```jsx
import React from 'react';
import {
  NoOpEventReporter,
  DefaultEventController,
  DefaultMeetingSessionConfiguration,
} from 'amazon-chime-sdk-js';
import { MeetingProvider } from 'amazon-chime-sdk-component-library-react';

const MeetingForm = () => {
  const meetingManager = useMeetingManager();

  const handleJoinMeeting = async () => {
    const response = await fetch('/my-meetings-endpoint');
    const data = await response.json();

    const meetingSessionConfiguration = new MeetingSessionConfiguration(
      data.Meeting,
      data.Attendee
    );

    const eventController = new DefaultEventController(
      meetingSessionConfiguration,
      new ConsoleLogger('SDK', LogLevel.WARN),
      new NoOpEventReporter()
    );

    const options = {
      eventController,
    };

    await meetingManager.join(meetingSessionConfiguration, options);
  };
  return <PrimaryButton label="Continue" onClick={handleJoinMeeting} />;
};

const App = () => (
  <MeetingProvider>
    <MeetingForm />
  </MeetingProvider>
);
```
