Introduction

In the last tutorial, we’ve built a video chat app with Twilio, Rails, and Javascript with basic calling functionality. Make sure you have visited the part 1 and have configured the video chat app as directed. Because, here, in this guideline, we will discuss the same demo app. So, don’t skip the last tutorial before going ahead with this guide.

We all are quite aware that adding basic calling functionality is not enough. A video chat application should have features like audio mute/unmute, turning the video on/off, and screen sharing.

So, here is the step-by-step guideline to make you clear how we can add such functionalities to your video chat app.

Tutorial Goal: Build Video Chat App with Twilio, Rails, and JS

Let’s discuss what we are going to do in this tutorial. These are the new features that we will implement in our demo application-

  • Audio mute and unmute
  • Video on and off
  • Screen sharing

Refer to the below video to have an idea of the final output with the user interface and functionality.

How to Mute and Unmute Audio in Video Chat App with Twilio?

The first step is to generate the user interface. For that, open the below file and add the buttons to our view for muting and unmuting audio. Every participant will have a clickable button, toggle, or another element to mute and unmute themselves.

//views/rooms/show.htm.erb

Copy Text
<button class="btn btn-success p-3 rounded-circle d-none m-3" id="call-mute-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-mic-fill" viewBox="0 0 16 16">
        <path d="M5 3a3 3 0 0 1 6 0v5a3 3 0 0 1-6 0V3z"/>
        <path d="M3.5 6.5A.5.5 0 0 1 4 7v1a4 4 0 0 0 8 0V7a.5.5 0 0 1 1 0v1a5 5 0 0 1-4.5 4.975V15h3a.5.5 0 0 1 0 1h-7a.5.5 0 0 1 0-1h3v-2.025A5 5 0 0 1 3 8V7a.5.5 0 0 1 .5-.5z"/>
      </svg>
    </button>
    <button class="btn btn-danger p-3 rounded-circle d-none m-3" id="call-unmute-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-mic-mute-fill" viewBox="0 0 16 16">
        <path d="M13 8c0 .564-.094 1.107-.266 1.613l-.814-.814A4.02 4.02 0 0 0 12 8V7a.5.5 0 0 1 1 0v1zm-5 4c.818 0 1.578-.245 2.212-.667l.718.719a4.973 4.973 0 0 1-2.43.923V15h3a.5.5 0 0 1 0 1h-7a.5.5 0 0 1 0-1h3v-2.025A5 5 0 0 1 3 8V7a.5.5 0 0 1 1 0v1a4 4 0 0 0 4 4zm3-9v4.879L5.158 2.037A3.001 3.001 0 0 1 11 3z"/>
        <path d="M9.486 10.607 5 6.12V8a3 3 0 0 0 4.486 2.607zm-7.84-9.253 12 12 .708-.708-12-12-.708.708z"/>
      </svg>
    </button>

To handle the logic part, use the below code.

// javascript/packs/video_call.js

Copy Text
window.onMuteAudioButton = function(room){
  room.localParticipant.audioTracks.forEach(function(audioTrack) {
     audioTrack.track.disable();
  });
   $("#call-mute-btn").addClass("d-none");
   $("#call-unmute-btn").removeClass("d-none");
};

window.onUnMuteAudioButton = function(room){
     room.localParticipant.audioTracks.forEach(function(audioTrack) {
     audioTrack.track.enable();
   });
  $("#call-mute-btn").removeClass("d-none");
  $("#call-unmute-btn").addClass("d-none");
};

LocalAudioTrack handles the audio of the LocalParticipant of a particular room. The disable() method is used to mute the microphone. This will stop publishing the audio track to the room. To unmute the audio, you can start publishing LocalAudioTrack using enable() method.

Now, add the below code in the joinRoom function.

Copy Text
$("#call-mute-btn").removeClass("d-none");
$("#call-mute-btn").on("click",function() {
  onMuteAudioButton(room);
})
$("#call-unmute-btn").on("click",function() {
  onUnMuteAudioButton(room);
})

The onMuteAudioButton and onUnMuteAudioButton functions will handle the logic for muting and unmuting the audio. These functions will be called when the user clicks on the call-mute-btn and call-unmute-btn buttons.

That’s it for Audio mute and unmute functionality.

Looking for a helping hand to build a feature-rich app with 05x faster performance?
Hire RoR developer from us to delight your end-users with meaningful CX.

Implement Video On/Off in Twilio Video Chat App

Add these Video on and off buttons to our view using the below code.

//views/rooms/show.htm.erb

Copy Text
<button class="btn btn-success p-3 rounded-circle d-none m-3" id="video-disable-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-camera-video-fill" viewBox="0 0 16 16">
        <path fill-rule="evenodd" d="M0 5a2 2 0 0 1 2-2h7.5a2 2 0 0 1 1.983 1.738l3.11-1.382A1 1 0 0 1 16 4.269v7.462a1 1 0 0 1-1.406.913l-3.111-1.382A2 2 0 0 1 9.5 13H2a2 2 0 0 1-2-2V5z"/>
      </svg>
    </button>
    <button class="btn btn-danger p-3 rounded-circle d-none m-3" id="video-enable-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-camera-video-off-fill" viewBox="0 0 16 16">
        <path fill-rule="evenodd" d="M10.961 12.365a1.99 1.99 0 0 0 .522-1.103l3.11 1.382A1 1 0 0 0 16 11.731V4.269a1 1 0 0 0-1.406-.913l-3.111 1.382A2 2 0 0 0 9.5 3H4.272l6.69 9.365zm-10.114-9A2.001 2.001 0 0 0 0 5v6a2 2 0 0 0 2 2h5.728L.847 3.366zm9.746 11.925-10-14 .814-.58 10 14-.814.58z"/>
      </svg>
    </button>

For handling business logic, add this code in javascript/packs/video_call.js

// javascript/packs/video_call.js

Copy Text
window.onDisableVideoButton = function(room){
  room.localParticipant.videoTracks.forEach(function(videoTrack) {
    videoTrack.track.disable();
  });
  $("#video-disable-btn").addClass("d-none");
  $("#video-enable-btn").removeClass("d-none");
};

window.onEnableVideoButton = function(room){
    room.localParticipant.videoTracks.forEach(function(videoTrack) {
    videoTrack.track.enable();
  });
  $("#video-disable-btn").removeClass("d-none");
  $("#video-enable-btn").addClass("d-none");
};

The logic is similar to the audio mute and unmute feature. Here, LocalVideoTrack works like LocalAudioTrack. You can use the disable() and enable() method for disabling and enabling the video track.

Now add the below code in the joinRoom function.

Copy Text
$("#video-disable-btn").removeClass("d-none");
$("#video-disable-btn").on("click",function() {
  onDisableVideoButton(room);
})
$("#video-enable-btn").on("click",function() {
  onEnableVideoButton(room);
})

We bind that code in onDisableVideoButton and onEnableVideoButton function. You have to call this function when clicking on the video-disable-btn and video-enable-btn buttons.

When a user disables the video, it should stop streaming it from the remote participant’s view. For that, we will use the trackDisabled and trackEnabled track events.

Add the below code in the onParticipantConnected() function.

Copy Text
participant.on('trackDisabled', track => {
    if (track.kind == "video"){
      $("#remote-video video:first").addClass("d-none");
    }
  });
  participant.on('trackEnabled', track => {
    if (track.kind == "video"){
      $("#remote-video video:first").removeClass("d-none");
    }
 }); 

So, this was about the Video On and Off functionality. Go to the show page of the room and test it out.

Add Screen Sharing to Twilio Video Chat Application

Now, it’s time to implement the last feature in our video chat app with Twilio, Rails, and JS, i.e., screen sharing. Like the above sessions, add screen share and unshare buttons to our view.

//views/rooms/show.htm.erb

Copy Text
<button class="btn btn-success p-3 rounded-circle d-none m-3" id="screen-share-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-cast" viewBox="0 0 16 16">
        <path d="m7.646 9.354-3.792 3.792a.5.5 0 0 0 .353.854h7.586a.5.5 0 0 0 .354-.854L8.354 9.354a.5.5 0 0 0-.708 0z"/>
        <path d="M11.414 11H14.5a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5h-13a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 .5.5h3.086l-1 1H1.5A1.5 1.5 0 0 1 0 10.5v-7A1.5 1.5 0 0 1 1.5 2h13A1.5 1.5 0 0 1 16 3.5v7a1.5 1.5 0 0 1-1.5 1.5h-2.086l-1-1z"/>
      </svg>
    </button>
    <button class="btn btn-danger p-3 rounded-circle d-none m-3" id="stop-screen-share-btn">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-cast" viewBox="0 0 16 16">
        <path d="m7.646 9.354-3.792 3.792a.5.5 0 0 0 .353.854h7.586a.5.5 0 0 0 .354-.854L8.354 9.354a.5.5 0 0 0-.708 0z"/>
        <path d="M11.414 11H14.5a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5h-13a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 .5.5h3.086l-1 1H1.5A1.5 1.5 0 0 1 0 10.5v-7A1.5 1.5 0 0 1 1.5 2h13A1.5 1.5 0 0 1 16 3.5v7a1.5 1.5 0 0 1-1.5 1.5h-2.086l-1-1z"/>
      </svg>
    </button>

Use the below code to capture your screen.

// javascript/packs/video_call.js

Copy Text
window.createScreenTrack= function(height, width) {
  const Video = Twilio.Video;
  if (typeof navigator === 'undefined'
    || !navigator.mediaDevices
    || !navigator.mediaDevices.getDisplayMedia) {
    return Promise.reject(new Error('getDisplayMedia is not supported'));
  }
  return navigator.mediaDevices.getDisplayMedia({
    video: {
      height: height,
      width: width
    }
  }).then(function(stream) {
    return new Video.LocalVideoTrack(stream.getVideoTracks()[0]);
  });
}

The function will publish your captured screen. And will display a small preview for you.

Copy Text
window.PublishedTracks =function( room, track){
     room.localParticipant.publishTrack(track);
     let localMediaContainer = document.getElementById("local-video");
     localMediaContainer.appendChild(track.attach());
     $("#stop-screen-share-btn").on("click",function() {
         onStopScreenShareButton(room,track);
    })
}

The below function will stop publishing your captured screen. And will remove your screen share preview.

Copy Text
window.StopTracks =function( room, track){
  room.localParticipant.unpublishTrack(track);
  track.stop();
  track = null;
  let localMediaContainer = document.getElementById("local-video");
  localMediaContainer.removeChild(localMediaContainer.lastChild);
}

The below function would be called when you click on the share screen button.

Copy Text
window.onScreenShareButton = async function(room){
  let screenTrack = await createScreenTrack(700, 700);
  PublishedTracks( room, screenTrack );
  $("#screen-share-btn").addClass("d-none");
  $("#stop-screen-share-btn").removeClass("d-none");
}

The below function would be called when you click on the stop share screen button.

Copy Text
window.onStopScreenShareButton = function(room,track){
  StopTracks( room, track );
  $("#screen-share-btn").removeClass("d-none");
  $("#stop-screen-share-btn").addClass("d-none");
}

Call all these functions from the joinRoom() function.

Copy Text
$("#screen-share-btn").removeClass("d-none");
$("#screen-share-btn").on("click",function() {
    onScreenShareButton(room);
  })

When you share your screen, it should display to the remote participant on priority.

For that, add the following code in the onParticipantConnected() function.

Copy Text
participant.on("trackPublished", (publication) =>{
    $("#remote-video video:first").addClass("d-none");
  } );

  participant.on("trackUnpublished", (publication) =>{
    $("#remote-video video:first").removeClass("d-none");
  } );

Now go to your root path and create a room. After that, go to the show page of that room and wait 3-4 sec while Twilio js is loaded from CDN. Copy that URL and paste it into the incognito tab, and Here we go. Your functionality is ready to use.

The entire source code is available here: twilio-video-chat-app

Conclusion

So, this was about building a video chat app with Twilio, Rails, and JS and later adding features like audio and video mute/unmute, sharing screen to the application. I hope you have got the idea and will start implementing it! We are always open for suggestions/feedbacks/queries; please feel free to contact us. You can visit the Rails tutorials page and explore more for more such Ruby on Rails tutorials.

Hire Ruby on Rails Developer

Connect Now

Get In Touch

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?