# Super Clarity (Beta) (/en/realtime-media/interactive-live-streaming/build/apply-effects-and-enhancements/super-clarity)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<CalloutContainer type="info">
  <CalloutDescription>
    This feature is supported only on Web.
  </CalloutDescription>
</CalloutContainer>

The Super Clarity extension leverages Agora's AI quality enhancement algorithm, which intelligently improves video quality without altering the resolution, thereby optimizing the viewing experience at the receiving end. The AI enhancement algorithm supports over 95% of mobile devices and ensures high-quality video rendering on low-end devices.

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="web" platforms="[&#x22;web&#x22;]" showTabs="false">
  <_PlatformPanel platform="web">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />

    ## Understand the tech [#understand-the-tech]

    The media transmission pipeline of the Agora Web SDK consists of capture, pre-processing, encoding, transmission, decoding, post-processing, and playback stages. The Super Clarity extension processes video data in the post-processing stage to apply the AI enhancement effect.

    ![Super clarity tech](https://assets-docs.agora.io/images/extensions-marketplace/web-extension-tech.svg)

    ## Prerequisites [#prerequisites]

    Ensure that you have implemented the [SDK quickstart](/en/realtime-media/video/get-started-sdk) in your project.

    ## Implement the logic [#implement-the-logic]

    This section shows you how to integrate the Super Clarity extension into your app.

    ### Integrate the extension [#integrate-the-extension]

    To install the [Super Clarity extension](https://www.npmjs.com/package/agora-extension-super-clarity), do the following:

    1. Run the following command in the root directory of your project:

       ```bash
       npm install agora-extension-super-clarity
       ```

    2. To import the Super Clarity extension, use one of the following methods:

       * **Method 1**: Add the following code to your JavaScript file:

         ```javascript
         import {
          SuperClarityExtension,
          SuperClarityEvents,
          SuperClarityProcessor,
         } from 'agora-extension-super-clarity';
         ```

       * **Method 2:** Import it in the HTML file using the script tag. After importing, you can directly use the `SuperClarityExtension` object in your JavaScript file.

         ```html
         <script src="../agora-extension-super-clarity.js"></script>
         ```

    ### Register the extension [#register-the-extension]

    Before joining a channel, create a `SuperClarityExtension` object and call the SDK's `registerExtensions` method to register the extension.

    ```javascript
    // Create a SuperClarityExtension object
    const extension = new SuperClarityExtension();

    // Register the extension
    AgoraRTC.registerExtensions([extension]);

    const context = {
     uid: undefined,
     client: undefined,
     track: undefined,
     processor: undefined,
    };

    async function join(appid, channel) {
     context.client = AgoraRTC.createClient({ mode: "live", codec: "vp8", role: "host" });
     context.client.on("user-published", onUserPublished);
     context.client.on("user-unpublished", onUserUnpublished);

     await context.client.join(appid, channel, null);
    }

    // Join the channel
    join('your-appid', 'your-channel');
    ```

    ### Enable the extension [#enable-the-extension]

    When subscribing to a remote video track, follow these steps to enable the Super Clarity extension:

    1. Call the extension's `createProcessor` method to create the extension's processor and listen to related events.
    2. Call the SDK's `IRemoteVideoTrack.pipe` method to connect the pipeline between the Super Clarity extension and the video track.
    3. Call the `enable` method of the extension to activate it. After enabling, play the video track to see the effect of the Super Clarity extension.

       <CalloutContainer type="warning">
         <CalloutDescription>
           To avoid performance issues caused by multiple processors working simultaneously, you can create a maximum of two processors. As a result, the Super Clarity extension can only be applied to a maximum of two video tracks at the same time.
         </CalloutDescription>
       </CalloutContainer>

    ```typescript
    async function onUserPublished(user, mediaType) {
     if (!context.client || mediaType !== "video" || !!context.uid) {
      return;
     }
     context.uid = user.uid;
     context.track = await context.client.subscribe(user, mediaType);

     // Create a processor
     context.processor = extension.createProcessor();

     // Listen for processor-related events
     context.processor.on("first-video-frame", (stats) => {
      console.log("Plugin received the first video frame, stats:", stats);
     });
     context.processor.on("error", (msg) => {
      console.error("Plugin error:", msg);
     });

     context.processor.on("stats", (stats) => {
      console.log("Plugin stats:", Date.now(), stats);
     });

     // Connect the pipeline between the processor and the video track
     context.track.pipe(context.processor).pipe(context.track.processorDestination);

     // Enable the extension
     await context.processor.enable();
     context.track.play('any-element-id');
    }
    ```

    ### Switch video tracks [#switch-video-tracks]

    Although the extension limits the number of `processors` that can be created, you can use the same `processor` to perform Super Clarity processing on multiple video tracks by switching tracks.

    To switch video tracks, call `IRemoteVideoTrack.unpipe` to disconnect the `processor` from the current video track, and then call `IRemoteVideoTrack.pipe` to connect the new video track.

    ```typescript
    // Disconnect the processor from the current video track
    await processor.disable();
    processor.unpipe();
    track?.unpipe();
    track?.pipe(track.processorDestination);

    // Connect to the new video track
    track2.pipe(processor).pipe(track2.processorDestination);
    await processor.enable();
    track2.play(ele);
    ```

    ### Destroy the extension [#destroy-the-extension]

    To stop using the Super Clarity extension, follow these steps to ensure proper cleanup and avoid potential issues:

    1. Call the SDK's `IRemoteVideoTrack.unpipe` method to disconnect the pipeline between the `processor` and the current video track.
    2. Call the extension's `release` method to destroy the `processor`.
    3. Call the SDK's `stop` method to stop the video track, set it to `null`, and destroy it.

       ```typescript
       async function onUserUnpublished(user, mediaType) {
        if (!context.client || mediaType !== "video" || context.uid !== user.uid) {
         return;
        }

        // Disconnect the pipeline between the processor and the current video track
        context.processor.unpipe();
        context.track.unpipe();

        // Destroy the processor and video track
        await context.processor.release();
        context.processor = undefined;
        context.track.stop();
        context.track = undefined;
       }
       ```

    ### Complete sample code [#complete-sample-code]

    This section presents the minimum code to integrate the Super Clarity extension into your project. Copy the following into your script file:

    **Complete sample code for the Super Clarity extension**

    ```js
    const extension = new SuperClarityExtension();
    AgoraRTC.registerExtensions([extension]);

    const context = {
     uid: undefined,
     client: undefined,
     track: undefined,
     processor: undefined,
    };

    async function join(appid, channel) {
     context.client = AgoraRTC.createClient({ mode: "live", codec: "vp8", role: "host" });
     client.on("user-published", onUserPublished);
     client.on("user-unpublished", onUserUnpublished);

     await client.join(appid, channel, null);
    }

    async function onUserPublished(user, mediaType) {
     if (!context.client || mediaType !== "video" || !!context.uid) {
      return;
     }
     context.uid = user.uid;
     context.track = await context.client.subscribe(user, mediaType);
     context.processor = extension.createProcessor();

     context.processor.on("first-video-frame", (stats) => {
      console.log("plugin have first video frame, stats:", stats);
     });
     context.processor.on("error", (msg) => {
      console.log("plugin error:", msg);
     });
     context.processor.on("stats", (stats) => {
      console.log("plugin stats:", Date.now(), stats);
     });
     context.track.pipe(context.processor).pipe(context.track.processorDestination);
     await context.processor.enable();
     context.track.play('any element id')
    }

    async function onUserUnpublished(user, mediaType) {
     if (!context.client || mediaType !== "video" || context.uid !== user.uid) {
      return;
     }
     context.processor.unpipe();
     context.track.unpipe();
     await context.processor.release();
     context.processor = undefined;
     context.track.stop();
     context.track = undefined;
    }

    join('your-appid', 'your-channel');
    ```

    ## Reference [#reference]

    This section completes the information on this page, or points you to documentation that explains other aspects about this product.

    ### Considerations [#considerations]

    The Super Clarity extension may not adaptively switch resolutions on iOS devices. As a workaround, when the remote video resolution changes, destroy the processor and then recreate it.

    **Sample code to destroy the processor and then recreate it.**

    ```js
    const isIOS =
     // @ts-ignore
     /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
    const versions = navigator.userAgent.match(/Version\/([\d.]+).*Safari/);
    let version = 0;
    if (versions && versions.length > 1) {
     version = parseInt(versions[1]);
    }
    var shouldCleanResource: boolean =
     isIOS && isSafari && version < 16 ? true : false;

    var extension: SuperClarityExtension | undefined = undefined;

    var initSCProcessor = async () => {
     if (!extension) {
      extension = new SuperClarityExtension();
      AgoraRTC.registerExtensions([extension]);
     }

     var processor = extension.createProcessor();

     processor.on(SuperClarityEvents.FIRST_VIDEO_FRAME, (stats: any) => {
      console.log('plugin have first video frame, stats:', stats);
     });
     processor.on(SuperClarityEvents.ERROR, (msg: any) => {
      console.log('plugin error:', msg);
     });
     processor.on(SuperClarityEvents.STATS, (stats: any) => {
      console.log('plugin stats:', Date.now(), stats);
     });
     return processor;
    };
    var destroySCProcessor = async (processor) => {
     if (!processor ) {
      return;
     }
     processor.removeAllListeners(SuperClarityEvents.FIRST_VIDEO_FRAME);
     processor.removeAllListeners(SuperClarityEvents.ERROR);
     processor.removeAllListeners(SuperClarityEvents.STATS);
     await processor .release();
     processor= undefined;
    };
    // Refresh processor
    {
      var info:{ w?:number, h?:number}={}
      if (shouldCleanResource) {
       setInterval(async ()=>{
        !info.w && info.w = track?.getStats().receiveResolutionWidth;
        !info.h && info.h = track?.getStats().receiveResolutionHeight;
        if (
        (track?.getStats().receiveResolutionWidth &&
         info.w &&
         track?.getStats().receiveResolutionWidth !== info.w) ||
        (track?.getStats().receiveResolutionHeight &&
         info.h &&
         track?.getStats().receiveResolutionHeight !== info.h)
       ) {
        info.w = track?.getStats().receiveResolutionWidth;
        info.h = track?.getStats().receiveResolutionHeight;
        if (processor) {
         processor.unpipe();
         track?.unpipe();
         track?.pipe(track.processorDestination);
         await destroySCProcessor(processor);
         processor= undefined;
        }
         processor = await initSCProcessor();
          track!.pipe(processor !).pipe(track!.processorDestination);
          await processor !.enable();
        }
       }, 1000);
      }
    }
    ```

    ### API reference [#api-reference]

    This section provides the API reference for the Super Clarity extension.

    #### `ISuperClarityExtension` [#isuperclarityextension]

    ##### `createProcessor` [#createprocessor]

    Creates an instance of `ISuperClarityProcessor`.

    ```typescript
    createProcessor(): ISuperClarityProcessor;
    ```

    #### `ISuperClarityExtension` [#isuperclarityextension-1]

    ##### `enable` [#enable]

    Enables the Super Clarity function.

    ```typescript
    enable(): void | Promise<void>;
    ```

    ##### `disable` [#disable]

    Disables the Super Clarity function.

    ```typescript
    disable(): void | Promise<void>;
    ```

    ##### `release` [#release]

    Releases all resources used by the extension.

    ```typescript
    release(): Promise<void>;
    ```

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
