Talk to us
Talk to us

How To Make A Movie-watching App

How To Make A Movie-watching App

A movie-watching app is an excellent solution for remote friends or lovers who still want to enjoy watching content together.

In this article, I will introduce how I built the movie-watching app that allowed me to spend quality free time with my girlfriend, who lives in a different city. We will use ZEGOCLOUD solutions.

movie-watching app

Implementation of your movie-watching app

Set up the development environment

  • Android Studio (version 2.1 or later)
  • Android SDK 25, Android SDK Build-Tools 25.0.2, Android SDK Platform-Tools 25. x.x or later
  • An Android device (Android 4.1 or later) with a microphone and camera
  • Android is connected to the internet.


Here are a few things that need to be done before you can start building with ZEGOCLOUD.

Now, we can start coding!

Movie-watching app Feature Overview

This is gonna be a simple app with the following features:

  • There will be two participants joining a room to watch a movie together. Let’s call them viewer A and viewer B.
  • To ensure that the two participants can have a truly synchronized watching together experience, I decided to play and stream the movie to the room from a separate device. Let’s call it the movie streamer. The consideration in this decision is that if the film is played and streamed to the room from the device of one of the participants, then the streaming latency may result in a perceivable out-of-sync issue between the two participants. But if the movie is played and streamed from a separate device, then both participants will subscribe to and play the movie stream from the cloud. The probability of having a perceivable out-of-sync issue will be much lower.
  • Participants in the room can have video chat and text chat while watching the movie together.
  • To make it simple, in this project, I set the maximum number of participants in a room to 3.

The movie streamer side – Play a movie and stream it in the room

1: Create an ZegoExpressEngine instance.

/// Define the ZegoExpressEngine object
ZegoExpressEngine engine;
/// Specify the AppID and AppSign for SDK authentication
/// AppID Format:123456789L
long appID = ; 
/// AppSign Format:"0123456789012345678901234567890123456789012345678901234567890123"
String appSign = "";
/// Create a ZegoExpressEngine instance
engine = ZegoExpressEngine.createEngine(appID, appSign, true, ZegoScenario.GENERAL, getApplication(), null); 

2: Enable custom video capture for the engine.

ZegoCustomVideoCaptureConfig videoCaptureConfig = new ZegoCustomVideoCaptureConfig();
// Use RAW_DATA as video buffer data type
videoCaptureConfig.bufferType = ZegoVideoBufferType.RAW_DATA;  engine.enableCustomVideoCapture(true, videoCaptureConfig, ZegoPublishChannel.MAIN);

3: Set a callback handler for custom video capture and implement the callback methods.

// Set the engine itself as the callback handler object
engine.setCustomVideoCaptureHandler(new IZegoCustomVideoCaptureHandler() {    
     public void onStart(ZegoPublishChannel channel) {         
     // On receiving the onStart callback, start to capture video and send the captured video frame data to the ZegoExpressEngine.

      public void onStop(ZegoPublishChannel channel) {         
      // On receiving the onStop callback, stop the video capture process.

4: Join a room.

/// Create a user
ZegoUser user = new ZegoUser("userA"); 
/// Join a room
engine.loginRoom("room", user);

Step 5: Set up a video event handler for the ZegoMediaPlayer. By setting up this handler, you can receive the video frame data of the movie played through the callback. onVideoFrame.

    new IZegoMediaPlayerVideoHandler() {
        public void onVideoFrame(ZegoMediaPlayer zegoMediaPlayer, ByteBuffer[] byteBuffers, int[] ints, ZegoVideoFrameParam zegoVideoFrameParam) { 
        if (RoomManager.getInstance().isCanSenRawData()) {
            int totalDataLength = byteBuffers[0].capacity();
            if (tempByteBuffer == null || tempByteBuffer.capacity() != totalDataLength) {
                tempByteBuffer = ByteBuffer.allocateDirect(byteBuffers[0].capacity()).put(byteBuffers[0]);
            } else {
            ZegoSDKManager.getInstance().getStreamService().sendCustomVideoCaptureRawData(tempByteBuffer, tempByteBuffer.capacity(), zegoVideoFrameParam);
    }, ZegoVideoFrameFormat.RGBA32);

Step 6: Start stream publishing. Load the movie from the specified file path (local file path or an URL that points to an internet media resource), and start playing the movie.

/// Start publishing the stream

mZegoMediaPlayer.loadResource(path, new IZegoMediaPlayerLoadResourceCallback() {
    public void onLoadResourceCallback(int code) {
        if (code == 0) {
            if (callback != null) {

Step 7: When no other participants are in the room or the participant publishing the stream leaves the room, stop posting the stream, and the callback for stopping custom video capture will be triggered.

ZegoSDKManager.getInstance().getDeviceService().setCustomVideoCaptureHandler(new IZegoVideoCaptureCallback() {
    public void onStart(ZegoPublishChannel channel) {
        canSenRawData = true;

    public void onStop(ZegoPublishChannel channel) {
        canSenRawData = false;

The movie viewer’s side

Subscribe to the movie stream to watch together, video chat, and text chat

To realize the watch together feature, we will need to implement the following:

  • The viewers subscribe to the video stream of the movie being played so they can watch it together.
  • Both viewers can have control over the movie playback. For example, either one of them can pause and resume the playback.
  • Stream publishing/subscribing and camera/microphone operations for video chat while watching the movie.
  • Sending and receiving real-time text messaging in the room.

The high-level program logic for movie playing:

  • The movie streamer will create a room first, and the viewers need to join the same room (by specifying the same Room ID when calling the loginRoom Method). If viewers attempt to join a room that doesn’t exist or without a movie streamer in there, they will be promoted with a message Room doesn't exist. If the specified room has already reached its total capacity, the login will fail, and the user will be notified accordingly.
  • When a viewer clicks the Start Movie button, call them setRoomExtraInfo() to notify the movie streamer. Upon receiving such information through the onRoomExtraInfoUpdate() callback, the movie streamer will execute the logic to start playing the movie and stream the film to the room.
  • The movie stream will then be received by both viewers and played on their devices.
/// start playing stream
engine.startPlayingStream("stream1", new ZegoCanvas(play_view));
  • Both viewers can call the setRoomExtraInfo(String roomID,String key,String value,null) method to control the movie playback (Play or Pause).

The following table shows the key-value parameters you can pass to the setRoomExtraInfo plan to send out different notifications:

room info0: movie being loaded…
1: movie playing
2: movie on pause
3: the room has been closed

The high-level program logic for video chat:

  • After joining the room, viewer A (or B) can start publishing video from the camera with a unique Stream ID and start the local preview.
  • When the other viewer joins the room and starts publishing his/her video to the room, the ZEGO Express SDK will send out an event notification accordingly. Viewer A (or B) then can start playing the other viewer’s video using the Stream ID received from the callback notification.
  • Both viewers can control their camera (e.g., switch between front/rear camera, turn on/off the camera) and microphone (e.g., mute/unmute) as they wish.
/// Switch between the front/rear camera

/// Turn on/off the camera

/// Mute or unmute the microphone

The high-level program logic for text chat:

  • Both viewers can send and receive real-time text messages in the room.
  • Call sendBroadcastMessage method to send a Broadcast Message (no longer than 1024 bytes) to other participants in the room.
/// Send broadcast messages
engine.sendBroadcastMessage(roomID, msg, new IZegoIMSendBroadcastMessageCallback() {
   public void onIMSendBroadcastMessageResult(int errorCode, long messageID) {   
    /// Returned result of sending broadcast messages       
  • Implement the callback method onIMRecvBroadcastMessage defined in IZegoEventHandler to listen for and handle the Broadcast Messages sent by other participants. You can get the message details from this callback, including the message content, message ID, time the message was sent, and message sender.
    java /// reveice message public void onIMRecvBroadcastMessage(String roomID, ArrayList<ZegoBroadcastMessageInfo> messageList){ }

How the final movie-watching app looks like

The movie streamer view

movie-watching app

Viewers view

Viewer view

Download Demo & Source Code →

You may download the demo app and try it yourself:

Demo instructions:

  1. Start the movie streamer, choose a movie, then configure the Room ID.
  2. Start the viewer app and enter the same Room ID.


After reading this article, I hope you’ll see that making an app for watching movies together is not that hard at all. Ready to create your own app?

Let’s Build APP Together

Start building with real-time video, voice & chat SDK for apps today!

Talk to us

Take your apps to the next level with our voice, video and chat APIs

Free Trial
  • 10,000 minutes for free
  • 4,000+ corporate clients
  • 3 Billion daily call minutes

Stay updated with us by signing up for our newsletter!

Don't miss out on important news and updates from ZEGOCLOUD!

* You may unsubscribe at any time using the unsubscribe link in the digest email. See our privacy policy for more information.