import { Meta, ArgTypes } from '@storybook/blocks';
import { VoiceFocusProvider } from '../';

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

# VoiceFocusProvider

The `VoiceFocusProvider` provides a function transforming a normal audio device to an Amazon Voice Focus device, and whether Amazon Voice Focus is supported.
Amazon Voice Focus related logs can be found in the browser developer tools when Amazon Voice Focus is enabled.

The Voice Focus Provider manages the state of a `VoiceFocusDeviceTransformer` behind the scenes. When you call `addVoiceFocus` the provider will use the current `VoiceFocusDeviceTransformer`
to create a new `VoiceFocusTransformerDevice` and provide it to the consumer. The `VoiceFocusDeviceTransformer` that is used to create a `VoiceFocusTransformDevice` will be destroyed when
the provider is unmounted.

This provider is independent from `MeetingProvider`. You can put `VoiceFocusProvider` wherever you want in the component tree to control the workflow of Voice Focus, so long
as any component which relies on `VoiceFocusProvider` is nested within `VoiceFocusProvider`.

## State

```typescript
{
  // Whether Amazon Voice Focus is supported. The default value is undefined, then changes to true or false.
  isVoiceFocusSupported: boolean | undefined;

  // A function to transform an audio input device to an Amazon Voice Focus device.
  addVoiceFocus: (device: Device) =>
    Promise<Device | VoiceFocusTransformDevice>;
}
```

You should see either "Amazon Voice Focus is supported." or "Amazon Voice Focus is not supported." in your browser developer tools based on whether
Amazon Voice Focus is supported on your device and browser. For more information, please check Amazon Chime SDK for JavaScript's Amazon Voice Focus
[guide](https://aws.github.io/amazon-chime-sdk-js/modules/amazonvoice_focus.html#can-i-use-amazon-voice-focus-in-my-application).

You can access the state by using the [useVoiceFocus](/docs/sdk-hooks-usevoicefocus--page) hook.

## Props

<ArgTypes of={VoiceFocusProvider} />

## Importing

```javascript
import { VoiceFocusProvider } from 'amazon-chime-sdk-component-library-react';
```

## Usage

`joinInfo` here is the response of [CreateMeeting](https://docs.aws.amazon.com/chime-sdk/latest/APIReference/API_CreateMeeting.html)
from [Amazon Chime SDK Meetings endpoint](https://docs.aws.amazon.com/chime-sdk/latest/dg/meeting-namespace-migration.html).
`joinInfo` is needed here so as to decide whether download Voice Focus or Echo Reduction model according to `CreatingMeetingResponse`.

```jsx
import React from 'react';
import { VoiceFocusTransformDevice } from 'amazon-chime-sdk-js';
import {
  MeetingProvider,
  VoiceFocusProvider,
  useMeetingManager,
  useVoiceFocus,
  useAudioInputs,
} from 'amazon-chime-sdk-component-library-react';

const joinInfo = { Meeting: {} }

function voiceFocusName(name: string): VoiceFocusModelName {
  if (name && ['default', 'ns_es'].includes(name)) {
    return name as VoiceFocusModelName;
  }
  return 'default';
}

function getVoiceFocusSpecName(): VoiceFocusModelName {
  if (
    joinInfo &&
    joinInfo.Meeting?.MeetingFeatures?.Audio?.EchoReduction === 'AVAILABLE'
  ) {
    return voiceFocusName('ns_es');
  }
  return voiceFocusName('default');
}

const vfConfigValue = {
  spec: {name: getVoiceFocusSpecName()},
  createMeetingResponse: joinInfo,
};

const App = () => {
  return (
    <VoiceFocusProvider {...vfConfigValue}>
      <MeetingProvider>
        <MyChild />
      </MeetingProvider>
    </VoiceFocusProvider>
  );
};

const MyChild = () => {
  const meetingManager = useMeetingManager();
  const { selectedDevice } = useAudioInputs();
  const [isVoiceFocusOn, setIsVoiceFocusOn] = useState(false);
  const [isVoiceFocusEnabled, setIsVoiceFocusEnabled] = useState(false);
  const { isVoiceFocusSupported, addVoiceFocus } = useVoiceFocus();

  useEffect(() => {
    if (selectedDevice instanceof VoiceFocusTransformDevice) {
      setIsVoiceFocusEnabled(true);
    } else {
      setIsVoiceFocusEnabled(false);
    }
  }, [selectedDevice]);

  useEffect(() => {
    const toggleVoiceFocus = async () => {
      try {
        let current = selectedDevice;
        if (isVoiceFocusOn) {
          if (typeof selectedDevice === 'string') {
            current = await addVoiceFocus(selectedDevice);
          }
        } else {
          if (selectedDevice instanceof VoiceFocusTransformDevice) {
            current = selectedDevice.getInnerDevice();
          }
        }
        await meetingManager.startAudioInputDevice(current);
      } catch (error) {
        // Handle device selection failure here
        console.error('Failed to toggle Voice Focus');
      }
    };

    toggleVoiceFocus();
  }, [isVoiceFocusOn]);

  const onClick = () => {
    setIsVoiceFocusOn((current) => !current);
  };

  return (
    <div>
      {isVoiceFocusSupported && (
        <button onClick={onClick}>
          {isVoiceFocusEnabled
            ? 'Disable Amazon Voice Focus'
            : 'Enable Amazon Voice Focus'}
        </button>
      )}
    </div>
  );
};
```

### Dependencies

- `MeetingProvider`
- `VoiceFocusProvider`
