<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Rishit Bansal</title>
    <description>The latest articles on Forem by Rishit Bansal (@rishit).</description>
    <link>https://forem.com/rishit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F450700%2Ffb0a1cc8-84c6-42b2-810c-189788c599a9.jpeg</url>
      <title>Forem: Rishit Bansal</title>
      <link>https://forem.com/rishit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rishit"/>
    <language>en</language>
    <item>
      <title>Launching Dyte’s Live streaming SDK on Product Hunt</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Tue, 18 Jul 2023 08:51:43 +0000</pubDate>
      <link>https://forem.com/rishit/launching-dytes-live-streaming-sdk-on-product-hunt-d86</link>
      <guid>https://forem.com/rishit/launching-dytes-live-streaming-sdk-on-product-hunt-d86</guid>
      <description>&lt;h2&gt;
  
  
  What is Dyte?
&lt;/h2&gt;

&lt;p&gt;For those of you who are hearing about Dyte for the first time, here’s some quick context - &lt;/p&gt;

&lt;p&gt;We started building Dyte back in 2020 in the middle of the pandemic. Having started initially as yet another video calling platform we soon transitioned to offering video and voice SDKs after receiving several requests for the same. And it has been quite a journey ever since 🚀&lt;/p&gt;

&lt;p&gt;We’re super excited to announce the launch of “Dyte’s live streaming SDK”, newest addition to the suite of solutions we provide 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Dyte’s Live streaming SDK:
&lt;/h2&gt;

&lt;p&gt;Dyte's Live-streaming SDK is designed to enhance your audio and video capabilities by providing a comprehensive range of features. As a versatile SDK provider, expanding our offerings to include live-streaming was a natural progression. Live-streaming caters to a variety of use-cases, particularly for companies already leveraging our video services. We recognized this and made it a priority to expand our offerings to meet the demands of our valued users. Needless to say, many of them have already successfully incorporated our live-streaming SDK, benefiting from its exceptional performance. After months of meticulous testing and optimization, we are thrilled to announce that our live-streaming SDK is out of beta and available to the public for seamless integration and utilisation!&lt;/p&gt;

&lt;p&gt;Let's delve into some of the features that our Live-streaming SDK offers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Low latency streaming: Experience lightning-fast streams with latency as low as 2 seconds, ensuring your audience enjoys real-time content from anywhere.&lt;/li&gt;
&lt;li&gt;Custom layouts: Craft a visually captivating video feed with Dyte's UI Kits, allowing you to create a tailored and engaging user experience for your audience.&lt;/li&gt;
&lt;li&gt;Live analytics: Gain comprehensive insights into your live stream's health, user activity, and user behaviour, empowering you with valuable data for optimization.&lt;/li&gt;
&lt;li&gt;Adaptive bitrate: Enjoy smooth and uninterrupted live streams, regardless of network conditions, without requiring any manual intervention.&lt;/li&gt;
&lt;li&gt;Built-in interactivity: Foster engagement and collaboration with features like whiteboard, chat, reactions, screenshare, polls, and quizzes, making your live streams interactive and captivating.&lt;/li&gt;
&lt;li&gt;Seamless host addition: Enable viewers to effortlessly join the livestream and participate in games or activities with the streamer, enhancing the overall experience.&lt;/li&gt;
&lt;li&gt;Scalability: With Dyte's robust infrastructure, effortlessly scale your streams to support over 10,000 viewers while maintaining exceptional video quality.&lt;/li&gt;
&lt;li&gt;Platform agnostic: Stream live content from any device and browser, ensuring compatibility across a wide range of video codecs. Get started without a hitch!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are live on Product Hunt today! Check us out right now: &lt;a href="https://www.producthunt.com/posts/live-streaming-sdk-by-dyte"&gt;https://www.producthunt.com/posts/live-streaming-sdk-by-dyte&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you and I look forward to your comments and feedback! 🙇&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Just Launched Dyte on Product Hunt</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Mon, 30 Jan 2023 09:28:42 +0000</pubDate>
      <link>https://forem.com/dyte/just-launched-dyte-on-product-hunt-4h3f</link>
      <guid>https://forem.com/dyte/just-launched-dyte-on-product-hunt-4h3f</guid>
      <description>&lt;h3&gt;
  
  
  What is Dyte?
&lt;/h3&gt;

&lt;p&gt;Dyte is a live video calling SDK that lets you embed completely customizable and branded live video conferencing right in your product within minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem:
&lt;/h2&gt;

&lt;p&gt;Back in 2020, while being stuck in the pandemic, we all had to shift to virtual meetings. Not only was it tiring to keep juggling between tabs and links; but for a business like ed-tech, it also created unnecessary friction for the user. Once a user clicks on the meeting link, they leave the platform with no visibility of their actions and behaviours.&lt;br&gt;
Most of the video SDKs that already existed in the market either had a tightly coupled UI that provided close to no customizability or were so complex to implement that it was as good as building it from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution:
&lt;/h2&gt;

&lt;p&gt;This is when we decided to build Dyte. We wanted to create something that could be integrated with 0 hassle while also being completely customizable to fit into your product. &lt;/p&gt;

&lt;h2&gt;
  
  
  Dyte’s Key Features:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customise your meetings end-to-end:&lt;/strong&gt; From your meeting UI to the levels of user access you give your users, you can customise everything. Pick and choose every element of your call UI from our design library called &lt;a href="https://docs.dyte.io/ui-kit/"&gt;“UI Kits”&lt;/a&gt; or build your own UI from scratch with the video infra being powered by our &lt;a href="https://docs.dyte.io/web-core/quickstart"&gt;“Core SDKs”&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Integration:&lt;/strong&gt; Dyte is so easy to implement that we have had customers go live in a day. Our in-depth &lt;a href="https://docs.dyte.io/"&gt;documentation&lt;/a&gt; will help you navigate Dyte without any hiccups no matter which framework you use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plug-ins:&lt;/strong&gt; Our out-of-the-box plugins such as whiteboard, polls, chat, code editor etc. help you create interactive and collaborative spaces that keep your team engaged!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics:&lt;/strong&gt; Our &lt;a href="https://dev.dyte.io/"&gt;developer portal&lt;/a&gt; brings everything you need in one place. With GUI based configs and controls it also provides you with a granular view of all your meeting and user data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More than video calls:&lt;/strong&gt; With Dyte you can seamlessly switch to webinars or breakout rooms whenever required. You can also record and store your video meetings in a single place for easier access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support:&lt;/strong&gt; We provide 24*7 support either through dedicated slack channels or through our &lt;a href="https://community.dyte.io"&gt;community&lt;/a&gt; so you never find yourself stuck.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are live on Product Hunt today! Check us out right now: &lt;/p&gt;

&lt;p&gt;Thank you and I look forward to your comments and feedback! 🙇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dyte.io/ph"&gt;https://dyte.io/ph&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
    <item>
      <title>WebRTC 102: Understanding libWebrtc</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Mon, 28 Nov 2022 07:07:12 +0000</pubDate>
      <link>https://forem.com/rishit/webrtc-102-1-understanding-libwebrtc-1g1e</link>
      <guid>https://forem.com/rishit/webrtc-102-1-understanding-libwebrtc-1g1e</guid>
      <description>&lt;p&gt;Jump to the "libWebRTC" section if you are in a hurry and not interested in a general overview of the WebRTC space.&lt;br&gt;
If you've missed Part 1, here it is: &lt;a href="https://dyte.io/blog/webrtc-102-demystifying-ice/" rel="noopener noreferrer"&gt;WebRTC 102: Demystifying ICE | Dyte&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Anyone who has even slightly dwelled into the world of real-time video-audio communication over the internet would have surely heard about WebRTC: The standard for ultra-low latency, real-time media communications over the Internet! You may have also tried out building a simple P2P application using RTCPeerConnection, or tinkered around with high-level libraries such as Mediasoup, Pion, Jitsi to name a few. But something is missing...... what really powers this new family of protocols? How does it work? If you're someone who is interested in getting into the nitty-gritty of things to do with WebRTC, this series is for you!&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Should You Care About WebRTC?
&lt;/h2&gt;

&lt;p&gt;As previously stated, WebRTC is the protocol that powers all of the magic behind the scenes. Understanding WebRTC will help you understand how to optimize for a wider range of environments, enable you to make low-level modifications to cater to your particular case, and so on.&lt;br&gt;
So without further ado, let's get started!&lt;/p&gt;
&lt;h2&gt;
  
  
  A Small Refresher to the Current State of WebRTC
&lt;/h2&gt;

&lt;p&gt;To understand why libWebRTC exists and why it is so important, we should start by looking at its grassroots in 2011 when Google first announced a shiny new open-source project for web browsers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--Iomsx7jy--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsyjqn689xpdeeaqzl1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--Iomsx7jy--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsyjqn689xpdeeaqzl1f.png" alt="Google Release of WebRTC Source Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project has since moved to a brand new website webrtc.org, and the source can now be found at &lt;a href="https://webrtc.googlesource.com/src/" rel="noopener noreferrer"&gt;https://webrtc.googlesource.com/src/&lt;/a&gt;. This repository contains the native WebRTC library used by most modern browsers (Chrome, Firefox, Opera, etc.).&lt;/p&gt;

&lt;p&gt;Of course, browser vendors rarely use the EXACT same library and versions due to compatibility reasons, and differing release cycles. For example, here is &lt;a href="https://github.com/mozilla/libwebrtc" rel="noopener noreferrer"&gt;Firefox's clone of libWebRTC&lt;/a&gt; on Github with their own modifications to the project.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Actual WebRTC Standard
&lt;/h2&gt;

&lt;p&gt;libWebRTC is amazing, and everything, but the real mission to maintain interoperability between multiple platforms, browsers, etc., is realized by two projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://datatracker.ietf.org/wg/rtcweb/documents/" rel="noopener noreferrer"&gt;IETF&lt;/a&gt;: IETF is an organization that maintains a collection of documents with various standards for real-time communication. These documents do not cover the actual WebRTC API, but rather, the different codecs, and protocols that are used by WebRTC clients to communicate with others. For example, ICE, STUN, and RTP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.w3.org/TR/webrtc/" rel="noopener noreferrer"&gt;W3&lt;/a&gt;: W3 maintains the spec for the official WebRTC API which you commonly see in browsers (RTCPeerConnection). All browsers are expected to comply with this specification to allow JavaScript clients to be cross-compatible. In actual practice, however, you would find that Chrome (or "Chromium") is by far the closest implementation of this spec and other projects currently implement a subset of the standard.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we refer to WebRTC as a whole, we actually usually refer to these two specifications and not just chrome's WebRTC implementation.&lt;/p&gt;

&lt;p&gt;Now that we have an idea of the WebRTC space let's dive deeper into libWebRTC!&lt;/p&gt;
&lt;h2&gt;
  
  
  libWebRTC
&lt;/h2&gt;

&lt;p&gt;LibWebRTC is a C++/C native implementation of the WebRTC API which is compatible with Windows, MacOS, and Linux. On the mobile side of things, it also provides Java and Objective-C bindings for Android and iOS respectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--d12cErLt--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe9wtu4p40zao27td3po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fpracticaldev%2Fimage%2Ffetch%2Fs--d12cErLt--%2Fc_limit%252Cf_auto%252Cfl_progressive%252Cq_auto%252Cw_880%2Fhttps%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbe9wtu4p40zao27td3po.png" alt="WebRTC Commit Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source for image: &lt;a href="//BlogGeek.me"&gt;BlogGeek.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, the project is open source, but Google and other browsers (Firefox, Opera) are the primary contributors and driving force behind the codebase since inception. Despite the fact that the most popular use case for libWebRTC has been web browsers, there is nothing stopping you from using it as a native library to communicate with other WebRTC peers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Should you be using libWebRTC?
&lt;/h2&gt;

&lt;p&gt;Unless you are someone particularly keen on dealing with C/C++ and the million other pain points that come with it...you might find it easier to use some other open-source projects implementing the WebRTC specs which we cover below.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://mediasoup.org/" rel="noopener noreferrer"&gt;"Mediasoup" project&lt;/a&gt; provides a high level JavaScript/TypeScript interface to the WebRTC APIs. The core logic of this project is implemented in C++/Rust. Consider taking a look at the project if you want an easy-to-use library instead of the low-level libWebRTC APIs.&lt;br&gt;
A notable project to mention is the &lt;a href="https://github.com/pion/webrtc" rel="noopener noreferrer"&gt;Pion/webrtc&lt;/a&gt; project which has a Golang implementation of the WebRTC API. Of course, we should mention the rust port &lt;a href="https://github.com/webrtc-rs/webrtc" rel="noopener noreferrer"&gt;WebRTC.rs&lt;/a&gt;. Let’s keep all the rustaceans happy too!&lt;/p&gt;

&lt;p&gt;If "ease of use" is not particularly important, and you are looking for cross-platform support, libWebRTC is definitely the safest bet to make native WebRTC clients that are compatible with browser clients from Chrome, Firefox, and other browsers.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started with libWebRTC
&lt;/h2&gt;

&lt;p&gt;Now that we have talked about the WebRTC space, lets go over how you can start working on the libWebRTC codebase.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cloning the repo
&lt;/h3&gt;

&lt;p&gt;You can clone the source directly using git clone &lt;a href="https://webrtc.googlesource.com/src" rel="noopener noreferrer"&gt;https://webrtc.googlesource.com/src&lt;/a&gt;, but it is recommended that you install &lt;a href="https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up" rel="noopener noreferrer"&gt;Google's Depot Tools&lt;/a&gt; which includes a set of tools for working with the project.&lt;/p&gt;

&lt;p&gt;Start by cloning depot tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;https://chromium.googlesource.com/chromium/tools/depot_tools.git&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repository's root folder has executable tools that we'll use later, so it can be convenient to add it to your PATH variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/depot_tools:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we can get the libWebRTC source by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;webrtc-checkout
&lt;span class="nb"&gt;cd &lt;/span&gt;webrtc-checkout
fetch &lt;span class="nt"&gt;--nohooks&lt;/span&gt; webrtc
gclient &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the src folder should have the entire source code from libWebRTC's main branch!&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the source
&lt;/h3&gt;

&lt;p&gt;Chromium, libwebRTC, and other Google projects use the ninja build system.&lt;/p&gt;

&lt;p&gt;But before we can use ninja to build the project, we must use another tool, gn.&lt;/p&gt;

&lt;p&gt;gn uses the configuration options in the &lt;a href="https://webrtc.googlesource.com/src/+/e9c3f0158c826af7a564a37ef0d513476fa89ec6/BUILD.gn" rel="noopener noreferrer"&gt;BUILD.gn&lt;/a&gt; file to generate ninja build files for multiple operating systems, executables, shared libraries, etc.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://webrtc.googlesource.com/src/+/49850c328cd4ba9c0ddeb0e8763bf13718188433/webrtc.gni" rel="noopener noreferrer"&gt;webrtc.GNI file&lt;/a&gt; contains some boolean flags to control which components of the project are built, which you can mess with if you wish to do so. For now, we will just stick to the defaults.&lt;/p&gt;

&lt;p&gt;To generate ninja's build files, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gn gen out/Default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will by default generate files for a DEBUG build that has extra data that we will use later while debugging an example on the repo.&lt;/p&gt;

&lt;p&gt;Finally, to start the build using ninja, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ninja &lt;span class="nt"&gt;-C&lt;/span&gt; out/Default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  LibWebrtc’s Threading Model
&lt;/h2&gt;

&lt;p&gt;The first step to working on any codebase is to locate the entry point of the code. Since libWebRTC is a library, it's hard to narrow it down to a single entry point. But the majority of codebases will start by using the &lt;a href="https://webrtc.googlesource.com/src/+/4b6819434d6b851b6cfcf211992b12a9793e0bc5/api/create_peerconnection_factory.cc#30" rel="noopener noreferrer"&gt;CreatePeerConnectionFactory&lt;/a&gt; function in the codebase which lets you easily create a WebRTC PeerConnection. The first three parameters of this function are essential to understand the entire webRTC codebase. These three thread objects are instances of the &lt;a href="https://webrtc.googlesource.com/src/+/d1875a232c3b365b2b68287ccba68676977bd410/rtc_base/thread.h" rel="noopener noreferrer"&gt;rtc::Thread&lt;/a&gt; class, and are used globally in the entire codebase to allocate different tasks on separate threads to help avoid processing tasks from bottlenecking network calls and external APIs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;network_thread&lt;/strong&gt;: This thread is responsible for writing the actual media packets flowing through your peer connection, and performing minimal processing tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;worker_thread&lt;/strong&gt;: The most resource-intensive of the three, this thread deals with processing the individual video/audio streams received/sent to peers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;signaling_thread&lt;/strong&gt;: This thread is where all the external API functions of the peer_connection class run. All external callbacks also run on this thread, therefore it is essential for users of the library to not block inside callbacks, since this will block the whole signaling thread.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Throughout the codebase, libWebRTC uses the &lt;a href="https://webrtc.googlesource.com/src/+/07eaddf93932e7aaf16ca6a5bed3aeb59bbaae8e/api/sequence_checker.h#116" rel="noopener noreferrer"&gt;RTC_DCHECK_RUN_ON&lt;/a&gt; macro to assert that function calls are running on the correct threads. This is also super helpful for someone reading the codebase to know which thread each function runs on.&lt;/p&gt;

&lt;h2&gt;
  
  
  LibWebRTC's peer_connection Example
&lt;/h2&gt;

&lt;p&gt;The best way to get your hands dirty with libWebRTC is by using the peer_connection example available in the src/examples/peerconnection directory of the project. If you followed the steps previously covered in the “Building the source” section, the example should already have been built according to the default rules in the webrtc.gni file.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: As of the date of writing this article, we are using the commit (bdf25670973611ae0c2562a43922e6120edab070). Some of the information covered in this section might get outdated in the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The architecture of the example
&lt;/h3&gt;

&lt;p&gt;The example outlines how to set up a simple peer connection to send a video stream from one client to another client and display it on the receiving end on top of a GTK window:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3zcobhw18djfv55fxf1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3zcobhw18djfv55fxf1.png" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see in the above diagram, there are two components in this example: the client and the server. In this blog post, we will concentrate on the client code as the server logic is irrelevant to LibWebRTC itself and is just a simple socket server that routes traffic between the clients. The architecture of the client application is as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchawhndroubty9wi9i53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchawhndroubty9wi9i53.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Code
&lt;/h2&gt;

&lt;p&gt;In the rest of this guide, we'll assume that you are using a Linux machine. To run the example, first, we need to start the server process. We can run the binary we previously built by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./src/out/Default/peerconnection_server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should start up the socket server on port 8888:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6wli0gd4i1inz4o72kx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6wli0gd4i1inz4o72kx.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, spin up two more terminal windows and run the client application on each of them. It will be useful to attach these windows to gdb . This will help us debug errors when we make changes to the codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gdb ./src/out/Default/peerconnection_client
r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the clients start up correctly, you should see two GTK windows popup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdic35e1eby0kate6if1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdic35e1eby0kate6if1m.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on Connect on both of these windows, and now you should see the list of peers connected on both windows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccztypw69rnjpho7pvvh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fccztypw69rnjpho7pvvh.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, click on the peer on any one of the windows. This should set up a WebRTC connection that streams video from that window to the other window! But at the time of writing this article, this seems to fail with the following error: 😞&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nmwp8goz9mpxxqo3ild.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9nmwp8goz9mpxxqo3ild.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s try debugging why this error happens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging/Fixing the client binary crash #1 (Race condition in thread management) :
&lt;/h3&gt;

&lt;p&gt;We can run &lt;code&gt;bt&lt;/code&gt; on our GDB window to view the call stack when the application crashed and see that the following functions were called:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PhysicalSocketServer::Wait() is invoked in the main thread of the client, which blocks until we get a socket message.&lt;/li&gt;
&lt;li&gt;On clicking the peer on the interface, a socket message is received which triggers OnMessageFromPeer.&lt;/li&gt;
&lt;li&gt;This triggers the creation of a new Peer connection, which seems to call PhysicalSocketServer::Wait() recursively again…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm6coauvkxqoh1gyk1oy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm6coauvkxqoh1gyk1oy.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On debugging the code, we found that this happens because of a caveat in the Threading Model we covered before. The thread where we invoke the CreatePeerConnectionFactory is actually the main thread of our client application. The constructor for the factory has a check which makes sure that all function calls run on the signaling thread. But, since we invoked the constructor from a different thread, it tried to queue a call on the signaling thread and blocked the main thread until the function call was completed on the former.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5n0605flxci2rhigxqu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh5n0605flxci2rhigxqu.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This causes Wait() to be called on our main application’s thread recursively, and the rtc::Thread class doesn’t allow Wait() to be called twice in this manner:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc9ag47adsbdi76ime24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc9ag47adsbdi76ime24.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ez5kptw0ix6oc7l1vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48ez5kptw0ix6oc7l1vm.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can prevent this issue by simply queuing the function call on the signaling thread instead of synchronously calling it on the main thread of our application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvailm5nddw4f4vejsjze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvailm5nddw4f4vejsjze.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://gist.github.com/thebongy/b59446faa4bd72fdfd52dc3a1b24a90a" rel="noopener noreferrer"&gt;patch on github gist&lt;/a&gt; with the fixes, you can use this to apply the fixes on your local machine. Now, when we rebuild the files and run the code, the video stream shows up correctly!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpkg2td27isa13s13a19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpkg2td27isa13s13a19.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This works for a small duration, but after a while, it appears that the video stream gets stuck on the client application on the receiving end, and now it crashes with a different segmentation fault error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwv6giszxltnh05j2an4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwv6giszxltnh05j2an4k.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look into why this happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging/Fixing the client binary crash #2 (Buffer overflow in Video Renderer):
&lt;/h2&gt;

&lt;p&gt;On viewing the call stack, we noticed that the crash occurs in the Redraw() function in the main_wnd.cc file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbky1akhccunn2fslw8ve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbky1akhccunn2fslw8ve.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On analyzing OnRedraw(), we found that the function is responsible for transferring the video of the peer from the remote_renderer to the draw_buffer. In the process, the code seems to be scaling the width of the source video by 2x, by duplicating adjacent pixels on the same row.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft3qilbf8vi80qpny1ios.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft3qilbf8vi80qpny1ios.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the memcpy is leading to a segfault after a duration, it is possible that the size of the source video is increasing to a larger size after a while, and since we initialize the draw_buffer just once, we ended up overflowing its bounds as it still has a smaller size. We can confirm this by adding some log lines in the code to log the width and height of the remote_renderer’s video :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;RTC_LOG&lt;span class="o"&gt;(&lt;/span&gt;LS_INFO&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="s2"&gt;"Video size: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;size&lt;/span&gt;&lt;span class="sh"&gt;;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir0vqjpg53kvsngdf70a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir0vqjpg53kvsngdf70a.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can fix this bug by re-initializing the draw buffer each time the size of the remote_renderer’s video changes, &lt;a href="https://gist.github.com/thebongy/fecccfe8b57a39430ac9c051eeff25db" rel="noopener noreferrer"&gt;as outlined in this patch&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffczs5jqqa2a4bx74d2nr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffczs5jqqa2a4bx74d2nr.png" alt="Code sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the video stream should render correctly for an indefinite period of time!&lt;/p&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulation, you reached the end of this article! You should now have a basic understanding of libWebRTC, and how to work with the project. If you are interested in contributing, you can head over to &lt;a href="https://bugs.chromium.org/p/webrtc/issues/list" rel="noopener noreferrer"&gt;webrtc’s bug tracker&lt;/a&gt; and try your hands at squashing some bugs 😉&lt;/p&gt;

&lt;p&gt;Try &lt;a href="https://dyte.io/" rel="noopener noreferrer"&gt;Dyte&lt;/a&gt; if you don't want to deal with the hassle of managing your own peer-to-peer connections!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you haven't heard of Dyte yet, go to &lt;a href="https://dyte.io/" rel="noopener noreferrer"&gt;https://dyte.io&lt;/a&gt; to learn how our SDKs and libraries revolutionize the live video and voice-calling experience. Don't just take our word for it; try it for yourself! Dyte offers &lt;a href="https://dev.dyte.io/signup" rel="noopener noreferrer"&gt;free 10,000 minutes&lt;/a&gt; every month to get you started quickly.If you have any questions or simply want to chat with us, please contact us through &lt;a href="//mailto:support@dyte.io"&gt;support&lt;/a&gt; or visit our &lt;a href="https://community.dyte.io/" rel="noopener noreferrer"&gt;developer community forum&lt;/a&gt;. Looking forward to it!&lt;/em&gt;&lt;/p&gt;





</description>
      <category>webrtc</category>
      <category>opensource</category>
      <category>video</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why we Chose Flagsmith for Feature Flagging</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Wed, 28 Sep 2022 05:13:06 +0000</pubDate>
      <link>https://forem.com/rishit/why-we-chose-flagsmith-for-feature-flagging-3l7g</link>
      <guid>https://forem.com/rishit/why-we-chose-flagsmith-for-feature-flagging-3l7g</guid>
      <description>&lt;p&gt;We at Dyte are super excited about the fact that we're growing at a super-fast pace, and so is our software delivery cycle. Almost every sprint, we introduce new features. However, the ever-increasing number of customers with different requirements warrants the need for an effective way to manage the feature delivery process as well. All of the features are not intended for all of our customers. The features that are not intended for all, are shipped behind the flags (indicators/controllers). These flags basically control the recipient of any such new features. In the software industry, the flags are commonly referred to as feature flags.&lt;/p&gt;

&lt;p&gt;Before we dive into why Dyte chose Flagsmith for feature flagging, let's make sure we're all on the same page about feature flags.&lt;/p&gt;

&lt;h2&gt;
  
  
  The What's and Why's of Feature Flag
&lt;/h2&gt;



&lt;p&gt;First thing first -:) Let's understand what Feature Flags are! A feature flag is a feature management solution that allows users to change the software's functionality without deploying new code. You can hide the code or behavior of software using feature flags without shipping new versions of the software.&lt;/p&gt;

&lt;p&gt;In the simplest terms, consider the feature flag as a powerful "if" statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DyteFlagsmithFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;newamazingfeature&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;renderNewAmazingFeature&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feature flags go by different names (to list a few), in the software industry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature Toggles&lt;/li&gt;
&lt;li&gt;Feature Switch&lt;/li&gt;
&lt;li&gt;Release Toggle&lt;/li&gt;
&lt;li&gt;Feature Controls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feature flags allow developers to conditionally turn on or off specific sections of their code (or code paths).&lt;/p&gt;

&lt;p&gt;Now, come to why's:&lt;/p&gt;

&lt;p&gt;There are a few ways to look at when you should use feature flags. Some of the most common use cases are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show or hide a button to access a new feature&lt;/li&gt;
&lt;li&gt;Test a UI change&lt;/li&gt;
&lt;li&gt;Try a new call to action to see how it performs&lt;/li&gt;
&lt;li&gt;Let users try an experimental use case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To understand it better, imagine you're working on a feature that doesn’t provide support for all browsers yet or cannot be deployed in all geographic locations. For example, the new functionality is bound to work only on Chrome, and the standard support is not there yet for other browsers. Maybe the functionality doesn’t pass compliance of a few specific countries. In such a situation, you can use feature flags to manage the features easily.&lt;/p&gt;

&lt;p&gt;A feature flag is a method of controlling the delivery of a specific feature (for example, user engagement metrics or facial gesture detection) to a subset of clients, countries, and browsers rather than rolling out all features to all clients.&lt;/p&gt;

&lt;p&gt;You can easily create and manage feature flags with an advanced and user-friendly flag management platform, such as &lt;a href="https://flagsmith.com/"&gt;Flagsmith&lt;/a&gt;. Your changes can be applied in real-time, eliminating the need to deploy and ship your solutions repeatedly.&lt;/p&gt;

&lt;p&gt;This is especially useful for SDK solutions like &lt;a href="https://dyte.io/"&gt;Dyte&lt;/a&gt;, where the release cycle is too agile. We can now instantly enable/disable a feature without requiring our clients to spare their developers countless hours in deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluation Phase
&lt;/h2&gt;

&lt;p&gt;At Dyte, we evaluated multiple possible options and solutions before reaching the final decision!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We could have used a third party such as Flagsmith or LaunchDarkly.&lt;/li&gt;
&lt;li&gt;Build an in-house solution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After extensive discussion and evaluation, we decided to go with a third-party solution that is expert in this area. There were several reasons for this decision, but the most important one for us was not spending our developers' time and energy on something that was not our company's primary goal.&lt;/p&gt;

&lt;p&gt;The next step was to figure out who:) This required a lot more research!&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluation Table
&lt;/h2&gt;

&lt;p&gt;We wanted a solution that was cost-effective while still meeting our requirements.&lt;/p&gt;

&lt;p&gt;There are many common and expected features of a feature flag solution, such as segmentation, flag types (boolean, string, JSON), A/B testing, and percentage rollouts, but we dug even deeper to find a solution that provided the most customization in terms of performance and functionality while remaining simple to use and integrate, just like Dyte!&lt;/p&gt;

&lt;p&gt;So we researched, compared, and came up with a comparison table.&lt;/p&gt;

&lt;p&gt;Symbols:&lt;br&gt;
&lt;code&gt;~&lt;/code&gt; denotes approximately&lt;/p&gt;

&lt;p&gt;&lt;code&gt;—&lt;/code&gt; denotes “Information not readily available”&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function / Parameter&lt;/th&gt;
&lt;th&gt;Flagsmith&lt;/th&gt;
&lt;th&gt;LaunchDarkly&lt;/th&gt;
&lt;th&gt;Optimizely&lt;/th&gt;
&lt;th&gt;Split.io&lt;/th&gt;
&lt;th&gt;DevCycle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SDK size (Vanilla JS)&lt;/td&gt;
&lt;td&gt;~ 23 KB&lt;/td&gt;
&lt;td&gt;~ 40 KB&lt;/td&gt;
&lt;td&gt;~ 101 KB&lt;/td&gt;
&lt;td&gt;~ 108 KB&lt;/td&gt;
&lt;td&gt;~ 47 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDK size (React)&lt;/td&gt;
&lt;td&gt;~ 39 KB&lt;/td&gt;
&lt;td&gt;~ 64 KB&lt;/td&gt;
&lt;td&gt;~ 123 KB&lt;/td&gt;
&lt;td&gt;~ 119 KB&lt;/td&gt;
&lt;td&gt;~ 59 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDK Support (Go, Java, Swift)&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-premise hosting&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load testing availability&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Website navigation index on the scale of 1-5. 5 being the most painful&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs navigation, index on the scale of 1-5. 5 being extremely painful&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking the flags which were enabled for a session/call&lt;/td&gt;
&lt;td&gt;YES (it was possible by having Integration of Webhook/ New Relic)&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;YES (Needed events or integration)&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;NO (We needed to add our own solution)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard to view audit logs&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ways to find/define flag dependencies&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Call response within xx ms&lt;/td&gt;
&lt;td&gt;We could control it by having our custom-hosted solution. 100ms was the SLA expectation of flagsmith. &lt;a href="https://docs.flagsmith.com/advanced-use/edge-api"&gt;https://docs.flagsmith.com/advanced-use/edge-api&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;200 ms&lt;/td&gt;
&lt;td&gt;&lt;a href="https://launchdarkly.com/how-it-works/"&gt;https://launchdarkly.com/how-it-works/&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;45ms to 400ms&lt;/td&gt;
&lt;td&gt;130ms to 400ms &lt;a href="https://status.split.io/"&gt;https://status.split.io/&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SLAs for issues&lt;/td&gt;
&lt;td&gt;99% uptime or 10% credit &lt;a href="https://flagsmith.com/service-level-agreement/"&gt;https://flagsmith.com/service-level-agreement/&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://launchdarkly.com/policies/enterprise/premium-sla/"&gt;https://launchdarkly.com/policies/enterprise/premium-sla/&lt;/a&gt; (Response in 1 day to 1 week or Pay more, 98% uptime or 10% credit)&lt;/td&gt;
&lt;td&gt;No clear SLA.&lt;/td&gt;
&lt;td&gt;99.9% uptime or moneyback if an issue arises for 2 months consequently &lt;a href="https://www.split.io/legal/terms-of-service/"&gt;https://www.split.io/legal/terms-of-service/&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Response in 4 hours to 2 days based on the plan. 99.9% uptime. &lt;a href="https://devcycle.com/pricing"&gt;https://devcycle.com/pricing&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What I liked?&lt;/td&gt;
&lt;td&gt;API was easy to use and verbose. Functions such as hasFeature were aptly named. We could create our own infra as well as contribute. It is Open Source.&lt;/td&gt;
&lt;td&gt;Documentation was better and rich. Promised the closest solution to what we needed.&lt;/td&gt;
&lt;td&gt;Drag and drop for the layman. Advance event tracking to get insights in Optmizely’s in-built metrics section.&lt;/td&gt;
&lt;td&gt;Better metrics and alert policies. A lot of features were really advanced but feel like overkill.&lt;/td&gt;
&lt;td&gt;Extremely easy docs to follow.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What I didn’t like?&lt;/td&gt;
&lt;td&gt;Docs were not updated or were updated in advance at various places.&lt;/td&gt;
&lt;td&gt;Information was not readily available on the website. The free account had various limitations so couldn’t play around. SDK functions were named poorly.&lt;/td&gt;
&lt;td&gt;Website navigation was not as intended. Features were called decisions, looks weird to read the code.&lt;/td&gt;
&lt;td&gt;Weird naming conventions. The entire system was named believing that it will only serve A/B testing.&lt;/td&gt;
&lt;td&gt;Still in the nascent stage. No auditing. No history.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Evaluation as per March 2022&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deciding Factors
&lt;/h2&gt;

&lt;p&gt;For us, the most crucial points apart from the functionality were SLAs (can’t let the ship sink with others), SDK size (we are an SDK ourselves, bundle size matters, cannot afford more KBs), ease of use (API structure, Doc navigation), and the price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flagsmith?
&lt;/h2&gt;

&lt;p&gt;We found Flagsmith to be the best solution available for our requirements. It had all the features, the ability to self-host, and more reasonable SLAs. Best of all, a very easy-to-follow API docs (&lt;a href="https://docs.flagsmith.com/clients/rest"&gt;https://docs.flagsmith.com/clients/rest&lt;/a&gt;). And just a single API call can do it all; no need to open a Postman collection and hit your head against the wall for days 😊&lt;/p&gt;

&lt;p&gt;The cherry on top is that it is open source. If someday we get stuck on a requirement, with the help of a league of extraordinary folks,  we can always contribute to their open-source codebase.&lt;/p&gt;

&lt;p&gt;Given these considerations, we concluded Flagsmith to be the richest platform with a significantly lower fee.&lt;/p&gt;

&lt;p&gt;Thanks to Flagsmith, we could avoid burning a hole in our pockets. Other service providers would have charged ten times the price for comparable features.&lt;/p&gt;

&lt;p&gt;We highly recommend &lt;a href="https://flagsmith.com/"&gt;Flagsmith&lt;/a&gt; for all of your feature flag needs. Happy feature flagging with &lt;a href="https://flagsmith.com/"&gt;Flagsmith&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you haven't heard of Dyte yet, go to &lt;a href="https://dyte.io"&gt;https://dyte.io&lt;/a&gt; to learn how our SDKs and libraries revolutionize the live video and voice-calling experience.  Don't just take our word for it; try it for yourself!  Dyte offers &lt;a href="https://dev.dyte.io/signup"&gt;free 10,000 minutes&lt;/a&gt; every month to get you started quickly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you have any questions or simply want to chat with us, please contact us through &lt;a href="//support@dyte.io"&gt;support&lt;/a&gt; or visit our &lt;a href="https://community.dyte.io/"&gt;developer community forum&lt;/a&gt;. Looking forward to it!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>programming</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Meeting Recordings at Dyte</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Fri, 25 Mar 2022 09:47:44 +0000</pubDate>
      <link>https://forem.com/rishit/meeting-recordings-at-dyte-3m41</link>
      <guid>https://forem.com/rishit/meeting-recordings-at-dyte-3m41</guid>
      <description>&lt;p&gt;Authors: &lt;a href="https://www.linkedin.com/in/kushagra-vaish-9437b3110/"&gt;Kushagra Vaish&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/bansal-rishit/"&gt;Rishit Bansal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do you remember what people said on the last video call you attended? The average person attends 3-4 calls every day, making it difficult to remember everything that was discussed in the calls. At Dyte, we always have a single person taking notes for every call (generally the person that joins last 🧙‍♂️). But even this leads to frequently missing out on a few action items every call. Cue cloud recordings! Cloud recordings capture everything on your video call to a file that can be viewed anytime in the future. This article will cover the different approaches we covered while engineering this feature at Dyte and the hurdles we had to overcome in the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build it?
&lt;/h2&gt;

&lt;p&gt;We knew we had to build recordings for our video calling company (duh) but we could have accomplished this in numerous ways. Firstly, we started by asking ourselves the following questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What do we want to record? Just the webcam and audio stream? Or the chat in the meeting as well? What about other interactive elements (polls, plugins, file uploads, etc.) in the meeting?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we want to record on the client-side or server-side?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we want to store the recording locally or server-side?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's consider these questions one by one. To answer the first question, we decided that we want to record any interactive element present on the screen. Also, we were sure that we wanted to store all the recordings on the server side since everyone in a meeting should be able to download the recording post-meeting. But, we didn't know how to answer the second question as all the approaches had trade-offs.&lt;/p&gt;

&lt;p&gt;We came up with 3 major approaches to answer the second question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Recording a browser tab&lt;/strong&gt;: We could run a recording logic on the user’s browser that would record their screen and either store it locally or send it to the cloud. All browsers already ship with MediaRecorder APIs allowing you to record and store any media stream you generate. The flow looks something like this:&lt;/p&gt;


    &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wJ8Cr2i6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bj8flvdaaegki2ykwbsb.png" width="880" height="394"&gt;Recording a browser tab via MediaRecorder APIs
    



&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Record the streams received from the server&lt;/strong&gt;: Most video call solutions send their streams to a server that processes them and sends them to all users who want to consume them. We can simply add another layer that sends these videos to a processing pipeline built using GStreamer or FFmpeg, which takes all the raw streams, stitches them together, and then stores them. In layman’s terms, think of this as taking everyone’s webcam videos from a call, then placing the videos side-by-side, and finally exporting to a single video.&lt;/p&gt;


&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v4p0ji5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-3.png" width="880" height="443"&gt;Recording the streams received from the server

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Good old screen capture&lt;/strong&gt;: A simple approach is to join the meeting using a virtual “Bot” user and record the entire screen of this Bot using tools like FFmpeg or OBS. This approach preserves the interactive elements on a webpage as we now see the meeting just like how any other user in the meeting would perceive it. However, we would need to incur the hardware cost of running FFmpeg/OBS for every recorded meeting.&lt;/p&gt;


&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--InW9Sl3R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-2.png" width="880" height="176"&gt;Recording the entire screen using tools like FFmpeg or OBS

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The MVP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fWKyfP2Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fWKyfP2Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-4.png" width="880" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
Our first approach prototype used the MediaRecorder API



&lt;p&gt;We first thought of allowing users to record locally (using their own browser’s MediaRecorder API) but quickly realized that we can’t depend on the user’s machine to remain stable during lengthy recordings.  What if a user leaves a meeting earlier than other users or runs into network issues and rejoins a meeting mid-way? To overcome these issues, we structured our recording MVP like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We ran a Chrome browser on the cloud that joined the call as a hidden participant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This Chrome browser had an extension that activated as soon as a call was joined.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The hidden participant then starts to stream its tab. This stream is fed to the MediaRecorder API which then stores the recording in browser storage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the meeting ends, the recording is transferred to our S3 bucket.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We shipped the MVP within 2 weeks of planning that we had to do recording (oh, we do miss those days) and on the first day, it broke the entire system! Why? Well, there were a few things we failed to account for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The entire recording was stored in memory, and as the calls become larger, the available memory decreases. We were running Chrome. This led to our cloud VMs running out of memory frequently.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Even when it had enough memory, the Chrome browser was unstable and crashed randomly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes our recorder was unable to join the meeting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Certain players couldn’t play the recording. Most importantly, it couldn't be played in QuickTime Player (Mac’s default player) and Windows Media Player (Windows default player).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;... and a lot more.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PIaqveHM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://media.tenor.com/images/c416170c8fa3d90426944d421f34f373/tenor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PIaqveHM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://media.tenor.com/images/c416170c8fa3d90426944d421f34f373/tenor.gif" width="426" height="240"&gt;&lt;/a&gt;&lt;/p&gt;
Our MVP



&lt;p&gt;On a side note, we were in the YC W21 batch during the time and recently came to know about a concept called PRD or Product Requirements Document (stop rolling your eyes OK, we had no clue about anything). Getting into the details of how we struggled with that will take another blog post, but we essentially realized this: we were just building a cool showcase by linking the maximum amount of systems possible, most of which weren’t even necessary.&lt;/p&gt;

&lt;p&gt;Thinking along the same lines, we decided to start by writing a detailed PRD outlining the revamped architecture for the system. We clearly defined the goals with the rewrite, and how we could satisfy these requirements in a reliable manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The big refactor
&lt;/h2&gt;

&lt;p&gt;This time, we decided to architecture a solution around the third approach, i.e., screen capture, described previously in this article. We built our own in-house docker image packaged with selenium, Xrandr, FFMPEG, and our application code. This container would join the meeting and then record the browser’s screen using FFMPEG. A lot of our time went into fine-tuning FFMPEG parameters to ensure the correct trade-off between quality and output size of the video file. Since FFMPEG continuously writes to the file system, we did not encounter the memory issue faced in the MediaRecorder approach. Moreover, FFMPEG provided a plethora of output encoding formats, allowing us to export videos to both H.264 and VP9 codecs. The vast majority of video players can easily play these.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rH3Y-FHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Untitled--9-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rH3Y-FHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Untitled--9-.png" width="880" height="601"&gt;&lt;/a&gt;&lt;/p&gt;
FFMPEG gives a range of CLI options to control I/O formats and other parameters like bitrate (Source: https://ffmpeg.org/ffmpeg.html)



&lt;p&gt;To ensure that the browser joined our meetings reliably, we added retry logic that would look for failures in joining the meeting and try to reload the page again when such errors happened. Moreover, we added logging in every component of the system, which helped us easily debug issues on live-call. A crucial step was monitoring these logs and setting up automated alerts on slack whenever we saw an increased frequency of “error” log lines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bMoq3OXi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-6-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bMoq3OXi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-6-1.png" width="880" height="649"&gt;&lt;/a&gt;&lt;/p&gt;
An example of an alert on our slack channel from our recording service



&lt;p&gt;Another issue we encountered was the long durations to spawn these docker containers on Amazon’s Elastic Container Service. ECS did not have any well-defined SLAs on how long it would take to spin up our containers. Our tests revealed that this startup time could range anywhere from 10 seconds to 5 minutes under stress and high load. We were later able to optimize this startup time to less than a second by using a neat trick, something we will cover in a future blog post.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ck2H4uDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ck2H4uDB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dyte.io/content/images/size/w1000/2022/03/Asset-5.png" width="880" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
AWS ECS



&lt;h2&gt;
  
  
  What we learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;LOG EVERYTHING!! This is probably the most understated thing that we have learned. Don’t worry about performance; use a proper logging library. Don’t worry about cluttering; use proper log levels and make the logging follow a proper structure. If you don’t have data on how to debug the problem, it’s really hard to find the issue. We ended up building a structured logging framework on top of winston which helped us identify edge cases with FFmpeg and our recording logic, and this was then shipped across all our microservices. Also, we ended up building alerts on top of these logs using Grafana, which allowed us to respond to issues even before customers reported them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try to reduce your iteration loop. We realized that testing a recording change locally was taking a lot of time and we didn’t have a proper reproducible test for testing our recording. For the redesign, we started with first writing a simple reproducible test and collecting baseline performance for that test. We built a simple script that allows us to deploy local change directly on the testing environment. That allowed us to shift from doing 1-2 iterations of recording per day to at least 5 iterations per day.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the other end, once you are ready with the change, test everything. There was a random bug we saw where for some meetings, we saw the recording was never stopping. We saw then that these were meeting with a host, which when ends meeting for all participants causes recorder (who is also a hidden participant) to get stuck in an invalid state. You can’t test for everything but we ended up creating a feature checklist as part of our SDK and then each new feature is tested against the combinations of existing features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understand the cloud infra that you are building on top. Remember that random Chrome crash that we talked about? Turns out it was an issue on ECS. We had to go deep in the documentation for how ECS works and debug that.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we described our engineering journey in developing and perfecting meeting recordings on Dyte. We covered the different approaches we took, and what we learned in the process. Hope this helped you not only learn something new but also understand the importance of a well-defined developer workflow!&lt;/p&gt;

&lt;p&gt;Do check out our recording APIs by triggering a recording using our REST API. Also, stay tuned for a future blog post on how we fine-tuned our infra for lightning-fast recording start times!&lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>aws</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>TypeORM Tips (Part 2: Use where() with care)</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Sat, 22 Jan 2022 19:15:01 +0000</pubDate>
      <link>https://forem.com/rishit/optimizing-typeorm-tips-from-experience-part-2-use-where-with-care-40jp</link>
      <guid>https://forem.com/rishit/optimizing-typeorm-tips-from-experience-part-2-use-where-with-care-40jp</guid>
      <description>&lt;p&gt;Hey everyone! This is the second post in my series on tips while developing with TypeORM, a popular typescript ORM library. In this post I will remark on a common pitfall when using the &lt;code&gt;where()&lt;/code&gt; method in the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;where()&lt;/code&gt; with care
&lt;/h2&gt;

&lt;p&gt;TypeORM's &lt;code&gt;QueryBuilder&lt;/code&gt; provides a &lt;code&gt;where()&lt;/code&gt; method to add SQL &lt;code&gt;WHERE&lt;/code&gt; clauses in a your queries which allows you to specify a condition to control the records which your query processes. Here's a code snippet illustrating how you can use this method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;select&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user.id=:userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getOne&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method follows a similar pattern to several other methods of &lt;code&gt;QueryBuilder&lt;/code&gt; which let you successively chain methods. Each method call returns back another &lt;code&gt;QueryBuilder&lt;/code&gt; instance. Here is an example of a chain which performs multiple LEFT JOINS, filters by a where condition and finally limits the query result to just 10 rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;gt; :minAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neat! Now lets say I want to add another filter on this query to ensure that the user age is also under 65 years old. Naturally, if I were to follow the chain pattern offered by the library I might do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;gt; :minAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;lt; :maxAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeORM successfully executes the above and doesn't give any compile-time/runtime warnings at all. But this piece of code &lt;strong&gt;will not filter out records correctly&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the problem?
&lt;/h2&gt;

&lt;p&gt;Adding multiple &lt;code&gt;where()&lt;/code&gt; clauses to a query doesn't make sure all of them are satisfied. Rather, TypeORM only picks the last &lt;code&gt;where()&lt;/code&gt; in the chain and uses that as the &lt;strong&gt;sole filter&lt;/strong&gt; for the query. In other words, successive &lt;code&gt;where()&lt;/code&gt; clauses just override previous clauses instead of adding new conditions. Thus the above code snippet will just return users whose age is less than 65 (i.e, The condition user &amp;gt; 18 won't be enforced!).&lt;/p&gt;

&lt;p&gt;This is vague as the library doesn't complain with this usage and can sometimes blindside developers. If a developer didn't test the above code on corner-cases, he/she might unknowingly deploy this on production and may discover the edge case only much later when the bug is reported.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you fix this?
&lt;/h2&gt;

&lt;p&gt;The correct usage is to use &lt;code&gt;andWhere&lt;/code&gt; or &lt;code&gt;orWhere&lt;/code&gt; depending on if you want to concatenate multiple conditions using &lt;code&gt;AND&lt;/code&gt; or &lt;code&gt;OR&lt;/code&gt;. For example, the above code snippet can be correct to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;gt; :minAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;andWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;lt; :maxAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use the &lt;code&gt;Brackets&lt;/code&gt; function to create more complicated queries. Say I wanted to check if the user falls in either of two age ranges (18&amp;lt;age&amp;lt;35 OR 50&amp;lt;age&amp;lt;65), I could do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;leftJoinAndSelect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Brackets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
                &lt;span class="nx"&gt;qb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;gt; :minAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;andWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;lt; :maxAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Brackets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
                &lt;span class="nx"&gt;qb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;gt; :minAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
                  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;andWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user.age &amp;lt; :maxAge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that here it was completely safe to use multiple &lt;code&gt;where()&lt;/code&gt; clauses as the other usages actually operate on a seperate &lt;code&gt;QueryBuilder&lt;/code&gt; instance and not the parent one. The basic rule to follow is to avoid multiple &lt;code&gt;where()&lt;/code&gt; method calls on the same &lt;code&gt;QueryBuilder&lt;/code&gt; instance.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>database</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>TypeORM Tips (Part 1: Don't use save())</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Sat, 22 Jan 2022 13:09:43 +0000</pubDate>
      <link>https://forem.com/rishit/optimizing-typeorm-tips-from-experience-part-1-dont-use-save-4ke9</link>
      <guid>https://forem.com/rishit/optimizing-typeorm-tips-from-experience-part-1-dont-use-save-4ke9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to the series
&lt;/h2&gt;

&lt;p&gt;As of January 21st 2022 (&lt;a href="https://openbase.com/categories/js/most-popular-nodejs-mysql-orm-libraries"&gt;source&lt;/a&gt;), TypeORM is the &lt;strong&gt;3rd most popular&lt;/strong&gt; Javascript ORM library and certainly the most popular if we're talking about Typescript.&lt;/p&gt;

&lt;p&gt;I have been extensively working with this library for the past two years, using it to serve millions of database queries every single day. In this series, I will list a few tips and pitfalls I learned while working with the project, which helped me catch bugs in production and optimize API calls. I'll try to keep each post short, informative and straightforward so you can quickly use these optimizations in your code.&lt;/p&gt;

&lt;p&gt;In each post, we will go over:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the problem?&lt;/li&gt;
&lt;li&gt;Why is it wrong?&lt;/li&gt;
&lt;li&gt;How can you fix it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  save() vs insert(), update()
&lt;/h2&gt;

&lt;p&gt;Repositories have the &lt;code&gt;.save()&lt;/code&gt; method, which has a dual function:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It inserts the entity if it doesn't already exist.&lt;/li&gt;
&lt;li&gt;If the entity exists, it attempts to update the existing one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's observe two example usages of the method:&lt;/p&gt;

&lt;p&gt;Here is a code snippet taken from an API endpoint which registers a new user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rishit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is a snippet from another endpoint which updates the name of an existing user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rishit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty handy, right? Well, not so much as this comes at the cost of a performance penalty. The implementation of &lt;code&gt;save()&lt;/code&gt; executes 2 queries instead of a single one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, it uses a &lt;code&gt;SELECT&lt;/code&gt; query to search for an existing entity.&lt;/li&gt;
&lt;li&gt;If step 1 returns a record, it uses &lt;code&gt;UPDATE&lt;/code&gt; to update the record. Otherwise, it uses &lt;code&gt;INSERT&lt;/code&gt; to insert a new record.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why is it bad?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;These queries need &lt;strong&gt;two round trips&lt;/strong&gt; to the database, meaning that you have to suffer the network latency due to each of the trips.&lt;/li&gt;
&lt;li&gt;There are specific contexts in your code where you know for a fact that you are certainly inserting / updating and do not require to use &lt;code&gt;save()&lt;/code&gt;'s dual functionality.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SELECT&lt;/code&gt; query generated by TypeORM includes a subquery, which is highly inefficient for tables with millions of rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How do you fix this?
&lt;/h2&gt;

&lt;p&gt;Look at the context you use your query in, and that should usually let you decide whether you meant to do an &lt;code&gt;insert()&lt;/code&gt; or an &lt;code&gt;update()&lt;/code&gt;. For example, you can refactor the above two snippets to:&lt;/p&gt;

&lt;p&gt;registering a new user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rishit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;updating an existing user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rishit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, you reduced the database load due to these queries by half: a &lt;strong&gt;2x&lt;/strong&gt; improvement!. The usage of &lt;code&gt;save()&lt;/code&gt; might seem pretty obvious. Still, it's a prevalent practice to use &lt;code&gt;.save()&lt;/code&gt; everywhere in code due to the &lt;a href="https://typeorm.io/#/undefined/updating-in-the-database"&gt;documentation of TypeORM itself&lt;/a&gt; recommending it as the primary mode to update entities.&lt;/p&gt;

&lt;p&gt;That said, &lt;code&gt;save()&lt;/code&gt; does indeed pose a valid use case for code that actually requires the functionality to &lt;code&gt;insert&lt;/code&gt; OR &lt;code&gt;update&lt;/code&gt; depending on if the entity exists or not. However, I am sure that most use cases don't need this feature and intend to either insert or update a record, not both.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>database</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How MoleculerJS Powers Dyte!</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Mon, 15 Nov 2021 06:52:33 +0000</pubDate>
      <link>https://forem.com/rishit/how-moleculerjs-powers-dyte-2d</link>
      <guid>https://forem.com/rishit/how-moleculerjs-powers-dyte-2d</guid>
      <description>&lt;p&gt;Microservices enable organizations to be more agile and build highly scalable applications. We, at Dyte, take advantage of MoleculerJS to connect our different microservices and APIs.&lt;/p&gt;

&lt;p&gt;In this blog post, we will be talking about how we structure all of our services around Moleculer and use it to collect critical insights and metrics to debug and optimize our infrastructure to serve millions of minutes of #livevideo calls every month.&lt;/p&gt;

&lt;p&gt;We would love to hear from you especially about what frameworks and tools you use to manage your microservices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.dyte.io/how-moleculerjs-powers-dyte/"&gt;Read the blog here&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>agile</category>
      <category>webrtc</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Reverse Engineering Keyboard Driver: Part 2 (Decompiling .NET applications)</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Tue, 05 Oct 2021 10:19:22 +0000</pubDate>
      <link>https://forem.com/rishit/reverse-engineering-keyboard-driver-part-2-decompiling-net-applications-44l2</link>
      <guid>https://forem.com/rishit/reverse-engineering-keyboard-driver-part-2-decompiling-net-applications-44l2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This post is a part of my series to reverse engineer the keyboard driver/Omen Light Studio application on my HP Omen Laptop and re-implement its functionality on  Linux. In this post, I will be covering how to decompile .NET services/DLLs&lt;/p&gt;

&lt;h2&gt;
  
  
  Locating the Service
&lt;/h2&gt;

&lt;p&gt;I have been using the Light Studio Application for a while, and one of its best features is the ability to set up dynamic "wave" lighting on your keyboard. In this setting, the lighting on the keyboard keeps changing dynamically to show a sort of wave animation. An intriguing behavior I have observed with this feature is that the animation works just once you have booted into Windows. During the boot process in Ubuntu, the lighting is set to the last set color from windows and remains static. This means that the animation is most likely set by a background service on windows which starts on boot and is not a feature of the keyboard on the hardware level. &lt;/p&gt;

&lt;p&gt;So, I began by opening a task manager and looking for any relevant background services that are running. I found two of particular interest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Omen Gaming Hub&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvd2p9ys07tvuw3mjxg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvd2p9ys07tvuw3mjxg6.png" alt="Omen Gaming Hub Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Light Studio Helper&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39y65if43hqtw52bwe47.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39y65if43hqtw52bwe47.png" alt="Light Studio Helper Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second service looks more interesting, so I right-clicked on the service and selected "Open File Location", and found that it was located at &lt;code&gt;C:\Program Files\HP\LightStudioHelper&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can see several files, but one which caught my eye was &lt;code&gt;Newtonsoft.Json.dll&lt;/code&gt;. I instantly recognized it as a C# library (&lt;a href="https://www.newtonsoft.com/json" rel="noopener noreferrer"&gt;https://www.newtonsoft.com/json&lt;/a&gt;), as I have worked with it in the past. This is important, as this means that the application was likely to be written in &lt;code&gt;.Net&lt;/code&gt; in &lt;code&gt;C#&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Decompiling the Executable and DLL Files
&lt;/h2&gt;

&lt;p&gt;Next, I looked for tools to decompile .NET applications. The top result was a free tool by Jetbrains called &lt;code&gt;DotPeek&lt;/code&gt;. I began by opening the folder on DotPeek and it was able to decompile all the DLLs. The two results of most importance to us are the ones for &lt;code&gt;LightStudioHelper&lt;/code&gt; and &lt;code&gt;OmenFourZoneLighting&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LightStudioHelper&lt;/code&gt; binary is what runs the background service. We start by looking at the &lt;code&gt;Main()&lt;/code&gt; method in this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;productVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetCurrentProcess&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;MainModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileVersionInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductVersion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"----- Log Start, version: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;productVersion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ProcessCommands&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"----- program exits, returnCode = {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_returnCode&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_returnCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsAnotherInstanceRunning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OLS_HELPER"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"----- program exits"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_returnCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Cleanup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateTimer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateAndRunThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"----- program exits"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_returnCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This method first gets the version of the service, processes command line arguments, and then checks if another process of the &lt;code&gt;OLS_HELPER&lt;/code&gt; service is running (not sure why yet) and then runs the &lt;code&gt;Cleanup()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Cleanup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cleanup()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;TaskScheduler&lt;/span&gt; &lt;span class="n"&gt;taskScheduler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TaskScheduler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LightStudioHelperTemp"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;taskScheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;taskScheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;DirectoryInfo&lt;/span&gt; &lt;span class="n"&gt;directoryInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DirectoryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InstallDirTemp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;directoryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;directoryInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;cleanup()&lt;/code&gt; method creates a &lt;code&gt;TaskScheduler&lt;/code&gt; class, which is another user-defined class in the source code of the service.&lt;br&gt;
The implementation for &lt;code&gt;Stop()&lt;/code&gt; and &lt;code&gt;Delete()&lt;/code&gt; can be seen in the source, but it's irrelevant as it just deals with killing any already running process of the LightStudioHelper. We concentrate on the &lt;code&gt;CreateAndRunThread()&lt;/code&gt; method which is run next:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CreateAndRunThread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CreateAndRunThread()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ParameterizedThreadStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThreadLightingUpdate&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsBackground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAlive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This method creates a new &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread?view=net-5.0" rel="noopener noreferrer"&gt;Thead&lt;/a&gt; which executes the &lt;code&gt;ThreadLightingUpdate&lt;/code&gt; method in the background:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ThreadLightingUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;colorArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enter ThreadLightingUpdate()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_isRunning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FourZoneLightingData&lt;/span&gt; &lt;span class="n"&gt;zoneLightingData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FourZoneLightingData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zoneLightingData&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;zoneLightingData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FourZoneColors&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;++&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;colorArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;zoneLightingData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FourZoneColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
              &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;colorArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zoneLightingData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FourZoneColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;FourZoneLighting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsTurnOn&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;FourZoneLighting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetZoneColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zoneLightingData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FourZoneColors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;33&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"leave ThreadLightingUpdate()"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the main loop of the thread(), and on looking at it, we already got a lot of clues on how the background service works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It maintains a 4 element array of &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.drawing.color?view=net-5.0" rel="noopener noreferrer"&gt;Color&lt;/a&gt;, which is encouraging, as I know my keyboard has 4 configurable lighting zones, this might refer to the color of each zone!&lt;/li&gt;
&lt;li&gt;The program has a while loop that seems to read colors from some sort of storage (&lt;code&gt;LightStudioStorage&amp;lt;FourZoneLightingData&amp;gt;.ReadData()&lt;/code&gt;), and then stores the color data in the 4 element color array. It maintains a &lt;code&gt;flag&lt;/code&gt; variable to check if any of the regions has a different color. Finally, if the &lt;code&gt;flag&lt;/code&gt; variable is set, and &lt;code&gt;FourZoneLighting.IsTurnOn()&lt;/code&gt; is true (presumably checking if the keyboard lights are turned on), it calls &lt;code&gt;FourZoneLighting.SetZoneColors&lt;/code&gt; to set the colors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I went in a little side adventure in checking out the  &lt;code&gt;LightStudioStorage&lt;/code&gt; and where it stores data, and found that it is a &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.io.memorymappedfiles.memorymappedfile?view=net-5.0" rel="noopener noreferrer"&gt;MemoryMappedFile&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;CommonLib.SharedMemory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;MemoryMappedFileHelper&lt;/span&gt; &lt;span class="n"&gt;_mmfHelper&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryMappedFileHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;WriteData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;_mmfHelper&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;_mmfHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;ReadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;_mmfHelper&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LightStudioStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;_mmfHelper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This likely refers to some shared memory logic, and another process might be writing to this memory-mapped file and calculating colors based on an algorithm. For now, I stopped here, but this area might be interesting to look at in the future as well.&lt;/p&gt;

&lt;p&gt;Moving on, I searched for the implementation of &lt;code&gt;FourZoneLighting.SetZoneColors&lt;/code&gt;, and found it was implemented in &lt;code&gt;OmenFourZoneLighting.dll&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;SetZoneColors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;zoneColors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zoneColors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FourZoneLighting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;131081&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;returnData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;++&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zoneColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zoneColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zoneColors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FourZoneLighting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;131081&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This file basically seems too transfer the colors to another data structure, &lt;code&gt;inputData&lt;/code&gt;, and then passes them to &lt;code&gt;Execute()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;commandType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;inputDataSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;returnData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;returnData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ManagementObject&lt;/span&gt; &lt;span class="n"&gt;managementObject1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagementObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root\\wmi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hpqBIntM.InstanceName='ACPI\\PNP0C14\\0_0'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ObjectGetOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ManagementObject&lt;/span&gt; &lt;span class="n"&gt;managementObject2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ManagementObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagementClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root\\wmi:hpqBDataIn"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ManagementBaseObject&lt;/span&gt; &lt;span class="n"&gt;methodParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;managementObject1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethodParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hpqBIOSInt128"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ManagementBaseObject&lt;/span&gt; &lt;span class="n"&gt;managementBaseObject1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ManagementBaseObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ManagementClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root\\wmi:hpqBDataOut128"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Sign"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FourZoneLighting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sign&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Command"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CommandType"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;commandType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Size"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;inputDataSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"hpqBData"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;inputData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;methodParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"InData"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;managementObject2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;InvokeMethodOptions&lt;/span&gt; &lt;span class="n"&gt;invokeMethodOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvokeMethodOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;invokeMethodOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;InvokeMethodOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;invokeMethodOptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;ManagementBaseObject&lt;/span&gt; &lt;span class="n"&gt;managementBaseObject2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;managementObject1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvokeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hpqBIOSInt128"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methodParameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"OutData"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ManagementBaseObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;returnData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;managementBaseObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToInt32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;managementBaseObject2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"rwReturnCode"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OMEN Four zone lighting - WmiCommand.Execute occurs exception: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This method seems to be doing the actual interaction with the hardware of the keyboard. I did a bit of research about &lt;code&gt;ManagementObject&lt;/code&gt; and found that it's a class used to interact with &lt;code&gt;WMI&lt;/code&gt; (Windows Management Instrumentation). WMI, specifically &lt;a href="https://docs.microsoft.com/en-us/samples/microsoft/windows-driver-samples/wmi-acpi-sample/" rel="noopener noreferrer"&gt;WMIACPI&lt;/a&gt; allows you to interact with the Bios and hardware devices, but more on this on the next blog post, for now, let us just treat this function as a black box which does some magic to set the colors of the keyboard.&lt;/p&gt;

&lt;p&gt;Since now we have enough information on how the service works, I tried to implement everything in the &lt;code&gt;OmenFourZoneLighting.dll&lt;/code&gt; file in my command line C# program for windows.&lt;/p&gt;
&lt;h2&gt;
  
  
  Rewriting the WMI Code in a C# program
&lt;/h2&gt;

&lt;p&gt;I started by setting up a .NET console application on &lt;a href="https://www.jetbrains.com/rider/" rel="noopener noreferrer"&gt;Rider&lt;/a&gt; and added the &lt;code&gt;System.Drawing&lt;/code&gt;, and &lt;code&gt;System.Management&lt;/code&gt; DLLs as assembly references from my system.&lt;/p&gt;

&lt;p&gt;I copied most of the Code from the &lt;code&gt;dotPeek&lt;/code&gt; decompiled result, and fixed some variable references, and wrote a CMD application which is available on this Github repository:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/thebongy" rel="noopener noreferrer"&gt;
        thebongy
      &lt;/a&gt; / &lt;a href="https://github.com/thebongy/omen-cli" rel="noopener noreferrer"&gt;
        omen-cli
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;br&gt;
&lt;p&gt;
  &lt;a href="https://github.com/thebongy/omen-cli" rel="noopener noreferrer"&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fthebongy%2Fomen-cli%2Fmaster%2Fassets%2Flogo.png" alt="Logo" width="80"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;b&gt;omen-cli&lt;/b&gt;&lt;/h2&gt;
&lt;/div&gt;


&lt;p&gt;&lt;br&gt;
    A CLI to customize your keyboard backlight 🚀&lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://github.com/thebongy/omen-cli" rel="noopener noreferrer"&gt;&lt;strong&gt;Explore the docs »&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;br&gt;&lt;br&gt;
    &lt;a href="https://github.com/thebongy/omen-cli" rel="noopener noreferrer"&gt;View Demo&lt;/a&gt;&lt;br&gt;
    ·&lt;br&gt;
    &lt;a href="https://github.com/thebongy/omen-cli/issues" rel="noopener noreferrer"&gt;Report Bug&lt;/a&gt;&lt;br&gt;
    ·&lt;br&gt;
    &lt;a href="https://github.com/thebongy/omen-cli/issues" rel="noopener noreferrer"&gt;Request Feature&lt;/a&gt;&lt;br&gt;
  &lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🎯 Table of Contents&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/thebongy/omen-cli#about-the-project" rel="noopener noreferrer"&gt;About the Project&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#built-with" rel="noopener noreferrer"&gt;Built With&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/thebongy/omen-cli#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#prerequisites" rel="noopener noreferrer"&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#roadmap" rel="noopener noreferrer"&gt;Roadmap&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/thebongy/omen-cli#contributors-" rel="noopener noreferrer"&gt;Contributors&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📖 About The Project&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;omen-cli&lt;/code&gt; is  a lightweight CLI tools built in C# to customize keyboard backlights on HP Omen  laptops similar to how Omen Light studio does.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Built With&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/" rel="nofollow noopener noreferrer"&gt;C#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet-framework/net48" rel="nofollow noopener noreferrer"&gt;.Net Framework 4.8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/commandlineparser/commandline" rel="noopener noreferrer"&gt;CommandLineParser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;
✈️ Getting Started&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To get a local copy up and running follow these simple steps.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;.NET Framework 4.8&lt;/li&gt;
&lt;li&gt;Nuget.exe CLI&lt;/li&gt;
&lt;li&gt;MSBuild.exe CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/thebongy/omen-cli.git&lt;/pre&gt;

&lt;/div&gt;

&lt;ol start="2"&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;nuget install .&lt;span class="pl-cce"&gt;\C&lt;/span&gt;LI&lt;span class="pl-cce"&gt;\p&lt;/span&gt;ackages.config -OutputDirectory packages&lt;/pre&gt;

&lt;/div&gt;

&lt;ol start="3"&gt;
&lt;li&gt;Run the following command from the root dir to build the project&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;MSBuild.exe&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🔧 Usage&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;To view all the options available, use the &lt;code&gt;--help&lt;/code&gt; command:&lt;/p&gt;


&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/thebongy/omen-cli./assets/ss-1.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fthebongy%2Fomen-cli.%2Fassets%2Fss-1.png" alt="ss-1"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
 &lt;br&gt;

&lt;p&gt;The &lt;code&gt;set4&lt;/code&gt; command is used to set 4 colors to…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/thebongy/omen-cli" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post, we saw how to decompile a C# application, and then implemented is using .NET Framework. In the next post, I will research more into ACPI and WMI drivers for Linux, to get a better idea of how to implement this functionality on Linux. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Reversing Keyboard Driver: Part 1 (Introduction)</title>
      <dc:creator>Rishit Bansal</dc:creator>
      <pubDate>Sat, 21 Aug 2021 20:00:05 +0000</pubDate>
      <link>https://forem.com/rishit/reverse-engineering-keyboard-driver-part-1-introduction-2hdg</link>
      <guid>https://forem.com/rishit/reverse-engineering-keyboard-driver-part-1-introduction-2hdg</guid>
      <description>&lt;h2&gt;
  
  
  Tldr; (What is the series about)
&lt;/h2&gt;

&lt;p&gt;This post is an introductory post to a series that will describe my journey to analyze and learn how the keyboard backlight driver on my laptop works, and then re-implement it on my own. I wanted a place to dump my thoughts and different things I try, and learn in the process. &lt;br&gt;
This post is just an intro to the series, if you're looking for the actual action, head over to the next post in the series!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;I recently upgraded to a new laptop &lt;strong&gt;(HP Omen 15-en0037AX)&lt;/strong&gt;. The laptop has a four-zone RGB LED backlight on the keyboard. Like most laptops that ship with such a keyboard, the manufacturer shipped a preinstalled app &lt;strong&gt;(Omen Light Studio)&lt;/strong&gt; on windows to customize the various lighting modes on the keyboard. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pgzdsm3ihnkyqxx4fhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5pgzdsm3ihnkyqxx4fhu.png"&gt;&lt;/a&gt;&lt;br&gt;HP Omen Light Studio
  &lt;/p&gt;

&lt;p&gt;Unfortunately, this app is only available for Windows, which is a problem, as I am primarily a Linux user.&lt;/p&gt;

&lt;p&gt;Since I have always been interested in cybersecurity and have taken part in multiple &lt;a href="https://ctftime.org/ctf-wtf/" rel="noopener noreferrer"&gt;CTF (Capture the Flag)&lt;/a&gt; events, I have a basic understanding of how to Reverse Engineer C/C++ binaries using tools like &lt;a href="https://ghidra-sre.org/" rel="noopener noreferrer"&gt;Ghidra&lt;/a&gt; but have never reversed an actual real-life application. In this series I want to (hopefully) achieve two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reverse Engineer the Omen Light Studio App, and figure out how it interfaces with the hardware on the laptop to control the keyboard's lighting.&lt;/li&gt;
&lt;li&gt;Re implementing the functionality on Linux (maybe in C/C++/Python/NodeJS) and possibly make a similar desktop app.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;This series is going to be me documenting all my approaches (right or wrong), and also explaining various concepts I learned in the process. Currently, I have no idea where this will lead to or what tools/languages I need to know/learn, but all that begins from the next post. See you there!&lt;/p&gt;

</description>
      <category>security</category>
    </item>
  </channel>
</rss>
