What is powering the Dyte Video SDK 2.0? Meet Web-Core!

As you might have heard already, we’re launching our new SDKs. So, what is the hype all about? In our new SDKs, we’ve tried to solve some of the recurring problems that we faced in our “old” SDKs (Palash has talked more about it here, do check it out!).

In short, we had previously built a demo video-calling application in React, which we ported into an SDK when a client requested us to do so. For this reason, the UI and the business logic of the pre-built SDK were muddled, and hard to separate.

Also, since we wanted to get our MVP ready super-fast, and our engineering team then consisted of 2 co-founders and 2 interns, the readability of our code and best practices like separation into modules weren't our priorities.

As we kept growing, it kept getting harder and harder for us to manage that codebase. Although we cleaned it up to a huge extent (over countless nights of anguish 😢), we knew that we couldn’t maintain it for much longer - so we parallelly started working on our “low-level SDK”, which we now call web-core.

What else would you call it anyway?

We wanted our user’s to be able to use Dyte without having to use our UI. Our UI may be opinionated, and might not sit well with our user’s use case, theme, and branding. By separating the business logic in web-core, our users can use Dyte with a custom UI. Moreover, one can now opt-in to use our UI components by using ui-kit (article on ui-kit coming soon!).

Our plan

We followed some basic principles while building web-core:

  1. Each module should be independent. For example, a bug in the chat module should not hamper the video-calling experience.
  2. The number of external dependencies should be as low as possible. In our old SDK, we had extremely unnecessary dependencies such as React and Chakra UI, increasing our bundle-size manifold. We wanted to avoid this at all costs.
  3. The linter is strict and unavoidable. The linter enforces a format in everything - code, commit messages, PR titles, and descriptions. This may seem unnecessary, but it makes it very easy to find commits from our changelog, and understand what the code does.
  4. The documentation (API reference) should be generated from the code so that it gets updated automatically. Whenever the code is updated, the JS Doc associated with it should also be updated.

Basically, we wrote some 11000 lines (excluding all the new internal packages that we built) of frontend code to rebuild our MVP (minus the UI) in a few months, while trying to use as few external libraries/dependencies as we could.

Fancy command to prove a point.

Why you should start using web-core

What makes web-core different?

There are a bunch of WebRTC SDKs out there that provide low-level access and high customizability. But what makes web-core different?

Conventional WebRTC SDK Design

Most SDKs by design work on "streams". A user has to publish his stream to the server (if not P2P), and another user has to subscribe to the other user's stream. If you're using a conventional SDK, you as a developer will need to decide which streams you want to subscribe to, and which ones you want to group together in a "meeting room". These SDKs often require some amount of knowledge about the functioning of WebRTC. They give you complete jurisdiction over each stream of every user and provide extremely high customizability, but lose out on developer experience while providing this control.

To enable your video, you will most probably have to do something like the following:

SDK.createVideoTrackFromCamera({
  encoderConfig: {
    width: 640,
    height: { ideal: 480, min: 400, max: 500 },
    frameRate: 10,
    bitrateMin: 700, bitrateMax: 900,
  },
}).then((localVideoTrack) => {
    SDK.publish(localVideoTrack);
});
High customizability, high maintenance.

Our approach

Our SDKs, however, are opinionated; i.e., we have taken a fresh take in designing the interface based on how we envision an easy-to-use API for most video/audio use cases. Our primary goal is to make a “developer-friendly” product, and we did not want the users of our SDKs to have to deal with the convolution of subscribing to streams and managing rooms. We tried to make our SDKs in such a way that it abstracts out the underlying complexity and provides a dumb, simple API. We do not want our users to have to understand the intricacies of WebRTC or any other technologies that we use to support our product. Instead, we provide a dense wrapper that works out-of-the-box for 90% of use cases, while supporting the customizability for the remaining 10%.

For example, turning on your video is as simple as:

meeting.self.enableVideo();
We provide optimal default device configuration so that you don't have to worry about it!

Similarly, you can send messages in chat by running:

meeting.chat.sendTextMessage('Galileo, Figaro.');
Magnificooo!

Utility Modules

Modules in web-core.

We’ve tried to make composite high-level modules such as the ones mentioned above. Here are all the modules that our SDK consists of:

  1. meeting.self: This consists of properties and methods corresponding to the current (local) user, such as enabling or disabling their audio and video, or changing their device.
  2. meeting.participants: This module is useful for providing information about the other participants that are present in the meeting. A host can use this module for access control, i.e., the host can mute or kick a participant.
  3. meeting.chat: Consists of actions that you can perform on the meeting chat, such as sending, receiving, and deleting messages.
  4. meeting.polls: This module lets you perform actions related to polls.
  5. meeting.recording: This lets you start or stop a recording, and get the current status of an ongoing recording.
  6. meeting.meta: This object consists of all the metadata related to the current meeting, such as the title, the timestamp of when it started, and so on.

Easy Quickstart

It’s very easy to get started with web-core. All you need to do is create an object of DyteClient, and you’re set.

const meeting = await DyteClient.init({...});

Once you have this meeting object, you can run meeting.joinRoom() to join the meeting, and use any of the modules mentioned above to interact with the meeting.

Propagating Event System

We emit events for changes that occur in the meeting object for the user to listen to. Let's say a participant in the meeting sent a chat message. You can listen for this new chat message by using:

meeting.chat.on('chatUpdate', ({ message }) => {
	console.log(`Received message: ${message}.`);
});

Similarly, you can set listeners for all the actions that a participant is performing. All the data related to all the participants who have joined the meeting is stored in  a map named meeting.participants.joined. Now, you can add a listener to each participant in the map to see if they're toggled their video for instance.

meeting.participants.joined.get(id).on('videoUpdate', ({
    videoEnabled,
    videoTrack,
}) => {
	console.log('Video update!');
});

Fun fact: some magic happens in the joined map (in fact, all the maps in meeting.participants and meeting.plugins) to re-emit all events that are emitted by any of the objects that are present in it. So, you could also listen for the same by doing:

meeting.participants.joined.on('videoUpdate', (
    participant,
    { videoTrack, videoEnabled },
) => {
	console.log(`Participant with ID: ${participant.id} emitted video update.`);
});

The following image demonstrates how it works.

You can check out this gist to see how it works!

That's All Folks

Feel old yet?

Well, not really. Our engineering team has built a tonne of features within web-core, and we've barely scratched the surface. Head over to our official documentation (https://docs.dyte.io) to find out more about web-core. Want access to our private beta? Get in touch with us on our community Discord server.

If you haven’t heard about Dyte yet, head over to https://dyte.io to learn how we are revolutionizing live video calling through our SDKs and libraries and how you can get started quickly on your 10,000 free minutes which renew every month. If you have any questions, you can reach us at support@dyte.io or ask our developer community.