Make Video Sharing Web App — Part II — Sync
This is a second entry of the journal of developing video sharing web app, VidU (Video with You). Please check out my first entry if you haven’t. In this entry, I will explain how I implemented Sync Mode through which multiple users can sync the playback position of the YouTube video to watch it together.
Here is a list of entries for this journal series.
Part III — Comment
Part IV — Deployment with HTTPS, PostgreSQL, Nginx
Part V — Video Chat
Part VI — UI/UX
Part VII — Misc and Conclusion
What Sync Mode Does
Once your friend accepts your invitation to the room, you can send request to sync with you. When your friend accepts the request, the video playback state is synced. If you pause, your friend’s video pauses. If your friend skips 30 sec, your video also skips. So, you will be watching the same content at the same time.
Main Logic
First, let me define couple terminology here. Playback position is the current time of the video playing, such as 1min 10sec. Video state is either pause or playing (there are actually load and finished states, but for simplicity, only consider two cases). Sync-owner is the user who invites others to join the sync, and sync-requested user is the one requested to join the sync (duh).
Sync mode is very simple to implement by sharing playback position and video state every time a user changes the video state.
- Once the sync-requested user accepts the sync, this user first receives the current playback position and video state from the sync-owner. Using YouTube API, the playback position is jumped to the sync-owner’s playback position and changes to the same video state as the video-owner’s.
- After the initial video state is synced, then every time any users in the sync-mode changes the video state, this user will send message to every user in the sync-mode to sync the playback position and video state.
How to Communicate Realtime?
The main question is how to send the playback position and video state information realtime. There are many ways to do this such as websockets. But I wanted to build it real quick, so I used another web service called Pusher. This allows you to send messages among different users simply.
Very Quick Guide How To Use Pusher
Please check out the official documentation as it is very well written.
Pusher is a simple hosted API for quickly, easily and securely integrating realtime bi-directional functionality via WebSockets to web and mobile apps, or any other Internet connected device.
To use Pusher, in my frontend Javascript, the app first subscribes to channels. These channels can be any name. In my case, “user-1-channel”, “room-3-channel”, “sync-5-channel”, etc. Then in my backend, python code can send messages to the selected channels with json data. In my sync-mode example, backend will send playback information to all the “sync-1-channel” subscribers, if any of the users in “sync-1-channel” changes playback/video state.
3 Main Kinds of Channels That I use
In my app, there are mainly three different kinds of channels for different purposes.
1. User Channel
Each user has its own unique user channel. This channel is responsible for receiving any user related events, such as request for sync, room invitation, online status check, video chat request, etc.
2. Room Channel
Each room has a unique channel that is responsible for any room related events, such as modifying room information and user accepting room invitation, deleting a room, etc.
3. Sync Channel
Once two or more users are in sync mode, they share the same sync channel. In this sync channel, video playback position and video states are shared among everyone in the same sync channel.
Details of the Implementation
- When a user enters the website, each user subscribes to a unique user channel. Say this user’s username is “johnny”, his channel’s name is “user-johnny-channel” (the naming pattern is “user-username-channel”). This channel is listening on events such as room invitation and sync request.
- When another user, “shuny” in a room wants to sync with “johnny”, shuny clicks Sync button to send request to johnny. This triggers python backend to send sync invitation data to “user-johnny-channel” with sync-channel name. This sync-channel name contains room name and the sync-owner name (“sync-shuny-room1-channel”). This sync channel name is also unique.
- user-johnny-channel receives the sync invitation request data. This allows the frontend to jump to the target room in which shuny is waiting for johnny to join. After entering the room, the sync mode begins as both shuny and johnny subscribe to “sync-shuny-room1-channel”.
- Since johnny is the sync-requested user, sync-owner playback position and video state are sent everyone in the sync channel for johnny to jump to where shuny is playing.
- Every time either shuny or johnny skips/pauses/plays the video, the state will be shared among the sync-channel.
The above steps are main logic for implementing the feature. There are details that I omitted for clarity. For example, when a new user enters the sync-channel, the initial state does not need to be sent to the users who are already in the sync channel. We only need to send the sync-owner’s state to the newly joined user. It is simple to differentiate which user is requesting for an initial sync.
A lot of VidU (this web app’s name) features are implemented using very similar logic as above. For example, comments and chat room functionality is simply sending messages among the room-channel. Individual user’s chat functionality is also just sending messages in a channel that two users share.
Hope this entry explains how I implemented the sync mode. I will keep editing this entry as I clean up my code in my GitHub and will try to add some graphics to clarify my points. I will share the code once I think it’s readable for other people.
In next part, I will explain how I implemented comment feature. It will be really cool!
Thanks for reading so far! Stay tuned!