Try Live Demo

Migrating from Zoom’s Video SDK to Ant Media Server (AMS) can unlock more control, lower costs, and greater deployment flexibility. Whether you’re building a conferencing solution, webinar platform, or low-latency streaming application, this guide will walk you through a smooth Zoom to Ant Media migration—step by step.

Step 1: Understanding the Core Differences Between Zoom SDK and Ant Media WebRTCAdaptor

Before migrating, it’s important to understand how each system works:

Zoom Video SDK:

  • Typically loaded via npm packages (e.g., @zoom/videosdk) or a script.
  • You create a client, generate a signature (JWT) from the backend, then client.join() with sdkKey and signature.
  • Manage local audio/video tracks, participant events, etc. all through Zoom’s client-based methods.

Ant Media WebRTCAdaptor:

  • A lightweight JS library to publish (send) and play (receive) WebRTC streams from your AMS instance.
  • Key steps:
    1. Initialize the adaptor with AMS’s WebSocket URL and callback handlers.
    2. Publish a local camera/mic stream to a given streamId.
    3. Play a remote stream by referencing the same streamId.
    4. Listen for events (connected, publishing started, playing started, etc.).

Note: Each peer connection is established using a WebSocket channel to negotiate the ICE candidates and track statuses with AMS.

Step 2: Set Up WebRTCAdaptor in Your Project

To integrate Ant Media Server’s WebRTCAdaptor in your application, you can either install it via npm (recommended for most modern build processes) or include a script tag directly in your HTML if you do not use a bundler.

a) Install via NPM (Recommended):

If your project uses a build tool like Webpack, Vite, or Parcel, install the WebRTCAdaptor package:

npm install webrtc-adaptor

Then import and initialize it in your JavaScript:

import WebRTCAdaptor from 'webrtc-adaptor';

const webRTCAdaptor = new WebRTCAdaptor({

  websocket_url: "wss://<YOUR-AMS-SERVER>:5443/WebRTCAppEE/websocket",

  mediaConstraints: { video: true, audio: true },

  token: "", // optional token for authentication

  debug: true,

  callback: (info, obj) => {

    if (info === "initialized") {

      console.log("WebRTCAdaptor initialized");

    } else if (info === "publish_started") {

      console.log("Publishing started for streamId:", obj.streamId);

    } else if (info === "play_started") {

      console.log("Playing started for streamId:", obj.streamId);

    }

    // Handle other events as needed

  },

  callbackError: (error) => {

    console.error("Error callback:", error);

  }

});

b) Include via Script Tag (No Bundler Needed):

If you prefer a simpler approach without a bundler, you can include the compiled .js file in your HTML directly. Make sure to download or reference the correct version from your own server or Ant Media’s repository:

<!DOCTYPE html>

<html>

  <head>

    <title>Ant Media Publish & Play</title>

  </head>

  <body>

    <video id="localVideo" autoplay muted playsinline></video>

    <video id="remoteVideo" autoplay playsinline></video>

    <!-- Replace with the correct path to webrtc_adaptor.js -->

    <script src="webrtc_adaptor.js"></script>

    <script>

      const webRTCAdaptor = new WebRTCAdaptor({

        websocket_url: "wss://<YOUR-AMS-SERVER>:5443/WebRTCAppEE/websocket",

        mediaConstraints: { video: true, audio: true },

        token: "",  // include a token here if needed

        debug: true,

        callback: function(info, obj) {

          if (info === "initialized") {

            console.log("WebRTCAdaptor initialized");

          } else if (info === "publish_started") {

            console.log("Publishing started for streamId:", obj.streamId);

          } else if (info === "play_started") {

            console.log("Playing started for streamId:", obj.streamId);

          }

          // Handle other events...

        },

        callbackError: function(error) {

          console.error("Error callback:", error);

        }

      });

    </script>

  </body>

</html>

Comparative Note: With the Zoom Video SDK, you might have used ZoomMtg.init(), client.init(), or client.join(). In AMS, you are effectively “joining” by connecting a WebSocket to AMS and specifying the streamId when you want to publish or play.

Step 3: Publishing a Stream (Replacing Zoom “Host” or “Active Speaker”)

In Zoom’s Video SDK:

// (Zoom) pseudo-code

const client = ZoomVideo.createClient();

await client.init("en-US", `YOUR_SDK_KEY`, ...);

await client.join("meetingNumber", "signature", "username");

const localStream = client.getMediaStream();

localStream.startVideo(...);

In Ant Media via WebRTCAdaptor:

function startPublishing() {

  let streamId = "myStreamId"; // or from REST API creation

  let token = ""; // if using token-based control, fill in

  webRTCAdaptor.publish(streamId, token);

}
  • Obtain streamId from your backend (or define your own).
  • Optionally obtain a token from your AMS if token control is enabled.
  • Call webRTCAdaptor.publish(streamId, token) to open your camera/microphone and push the WebRTC stream to the server.
  • Local Preview: The WebRTCAdaptor uses the mediaConstraints you defined (video/audio). If you want a local preview, attach the local stream to an HTML <video> element.

webRTCAdaptor.localStream

  .then(stream => {

    document.getElementById("localVideo").srcObject = stream;

  });

AMS automatically assigns the role “publisher” to this connection.

Step 4: Playing/Receiving a Stream (Replacing Zoom “Join as Participant”)

In Zoom’s Video SDK:

// (Zoom) pseudo-code

client.join("meetingNumber", "signature", "user2");

client.getMediaStream().startVideo(...); 

// or subscribe to another user’s feed

In Ant Media:

function startPlaying() {

  let streamId = "myStreamId"; 

  let token = ""; // again, only if token is enabled

  webRTCAdaptor.play(streamId, token);

}

// Then, in the callback:

callback: function(info, obj) {

  if(info === "play_started") {

    console.log("Play started for:", obj.streamId);

    // The remote stream is automatically attached to a <video> tag 

  // with the id matching "streamId" by default if you pass the HTML element. 

  }

},
  1. Call webRTCAdaptor.play(streamId, token) for each remote stream you want to view.
  2. Attach the remote stream to a <video> element. By default, the adaptor attaches the video to an element with id=”streamId”. You can override or manually handle the stream event in your callback.

Step 5: Handle Events and Errors

  • Zoom: You might have used client.on(“error”, …) or client.on(“user-added”, …).
  • AMS:
    • callback: function(info, obj) handles events like publish_started, publish_finished, play_started, play_finished, screen_share_started, etc.
    • callbackError: function(error, message) { … } handles errors (e.g., camera access denial, ICE negotiation failures).

Step 6: Post-Migration Considerations

  1. Recording: Zoom’s cloud recording can be replaced by AMS’s built-in recording or server-side recording settings.
  2. Scaling: For large-scale usage, set up AMS in cluster mode (Enterprise Edition) or horizontally scale multiple AMS nodes behind a load balancer. AMS can scale to a basically infinite number of viewers.
  3. Token Security: If you rely on more secure access control, enable token-based publishing/playing. Ensure your back-end is issuing valid tokens with short expiration times.

Step 7: Test and Validate the Migration

  1. Prototype: Set up a test environment with a single AMS instance.
  2. API Call Validation: Test each replaced Zoom API call with the new AMS REST endpoint.
  3. Load Test: If you were handling large meetings, simulate concurrency and ensure AMS can handle the load.

Best Practices for a Smooth Zoom to Ant Media Migration

  • Security: Always secure your AMS REST endpoints with HTTPS and implement token-based access for publishing and playback.
  • Turnkey Deployment: Use Docker or Kubernetes for containerized setups if you anticipate frequent deployments.
  • Monitoring: Keep an eye on CPU, RAM, and network usage on your AMS instances to ensure stable performance.
  • Regular Updates: Stay updated with the latest AMS releases, as they often provide performance improvements, security patches, and new features.

Conclusion

Migrating from Zoom’s platform to Ant Media Server for backend streaming and conferencing solutions enables greater control, flexible self-hosting, and extensibility. Although the transition can involve reworking API calls, token generation, and scaling strategies, the steps outlined in this document should help you design a clear roadmap.

By aligning your existing backend architecture with AMS’s REST endpoints and server-side modules, you’ll be well on your way to deploying a low-latency, customizable streaming solution tailored to your needs.

Screenshot 2025 04 21 at 10.33.56

If you have questions or need any support, contact us via a formschedule a meeting to have a coffee and chat, or write directly to contact@antmedia.io

Categories: Tutorial

tahir.golge

Tahir Ahmet Gölge is a full-stack software developer at Ant Media. He mainly implements new features and works on the bugs that may appear in the software for both back-end and front-end, also he helps the technical support and sales. He has around 2 years of experience in video engineering, server (REST, spring, tomcat, etc. ) development and testing, and live streaming platforms to create solutions for ultra-low latency streaming.