


{"id":9878,"date":"2023-03-24T20:07:27","date_gmt":"2023-03-24T16:07:27","guid":{"rendered":"https:\/\/krisp.ai\/blog\/?p=9878"},"modified":"2025-03-12T14:28:41","modified_gmt":"2025-03-12T10:28:41","slug":"breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk","status":"publish","type":"post","link":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/","title":{"rendered":"Breaking the audio processing barrier on the web with Krisp JS SDK"},"content":{"rendered":"<p>In today&#8217;s world, browsers have become an integral part of our daily lives. Although Krisp worked on various native libraries for most platforms in use (Windows, Mac, Linux, Android, IOS), there were still many use cases where Krisp SDK was needed in the context of web applications. This article summarizes our journey of creating world-class noise cancellation SDKs for web usage. We believe this is a unique usage of Web Assembly, which showcases the unlimited possibilities that WASM has to offer. We put a lot of time and effort into this project and have delivered a game-changing JS SDK, enabling many products to level up their web-based real-time communication.<\/p>\n<h2>Challenges<\/h2>\n<p>Processing audio in the browser is more challenging than it may seem at first glance. We faced different challenges. Some were well-known and had defined technical solutions. In contrast, some challenges were particular to our use case and we had to get creative. Let&#8217;s review some of our main challenges and discuss the solutions we came up with.<\/p>\n<h3>Run C++ directly on the web.<\/h3>\n<p>Our first challenge when working on Krisp&#8217;s JS SDK was that our core SDK is C++ based and we needed to find a way to use our core SDK&#8217;s functionality inside a browser. We found a well-known solution for that: <a href=\"https:\/\/webassembly.org\/\">WASM (WebAssembly)<\/a>. This binary instruction format allows running programming languages such as C and C++ in the browser and achieving near-native performance on the web. To compile our C++ library into a WASM module, we used <a href=\"https:\/\/emscripten.org\/index.html\">Emscripten<\/a>: a complete compiler toolchain to WebAssembly, with a primary focus on performance in web platforms. After compiling C++ into a WASM module, we can import that module to our javascript\/typescript project and use it (see Figure 1).<\/p>\n<div id=\"attachment_9882\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9882\" loading=\"lazy\" class=\"wp-image-9882\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage.png\" alt=\"WASM module usage figure\" width=\"800\" height=\"92\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage.png 1220w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage-300x34.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage-380x44.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage-768x88.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig1-WASM-module-usage-600x69.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9882\" class=\"wp-caption-text\">Figure 1. WASM module usage<\/p>\n<\/div>\n<h3>Using our NC models<\/h3>\n<p>After understanding how to use our C++ code, we faced another problem: using our noise cancellation models. Up until this point, we were using our models in a native context and we didn&#8217;t have to worry about the size of our models that much. But everything changes in the context of web applications where you can&#8217;t load 30 or 40 MB of data every time while opening the application. To solve this problem, our research team worked on smaller yet fully functional models focused on performance. In Figure 2, you can see the comparison between our regular and small models.<\/p>\n<div id=\"attachment_9884\" style=\"width: 450px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9884\" loading=\"lazy\" class=\"size-full wp-image-9884\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig-2-Models.png\" alt=\"Native Model Size Comparison\" width=\"440\" height=\"137\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig-2-Models.png 440w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig-2-Models-300x93.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig-2-Models-380x118.png 380w\" sizes=\"(max-width: 440px) 100vw, 440px\" \/><\/p>\n<p id=\"caption-attachment-9884\" class=\"wp-caption-text\">Figure 2. Model size comparison<\/p>\n<\/div>\n<h3><strong>128 samples per frame limitation<\/strong><\/h3>\n<p>With native development, you have flexibility and control over your audio flow. However, there are some limitations you have to consider while working with audio inside a browser. Audio circulates in frames (see Figure 3). Each frame consists of 128 samples (a sample is just a number describing the sound). There is also a term called sample rate &#8211; the number of samples we will receive per second. The sample rate may vary based on the device (you may have already seen the sample rate characteristic in audio devices&#8217; descriptions).<\/p>\n<div id=\"attachment_9885\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9885\" loading=\"lazy\" class=\"wp-image-9885\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples.png\" alt=\"Sample rate\" width=\"800\" height=\"191\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples.png 1313w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples-300x72.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples-380x91.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples-768x183.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig3-Samples-600x143.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9885\" class=\"wp-caption-text\">Figure 3. Audio frames in web<\/p>\n<\/div>\n<p>Now, with this information, it is reasonably easy to understand how many seconds\/milliseconds of audio is stored in the given number of samples based on our sample rate. The sample count divided by the sample rate will provide us with the number of seconds stored in that sample count. To make the calculation even more helpful, we can multiply the result by 1000 to get the answer in milliseconds.<\/p>\n<blockquote><p><strong>Example:<\/strong>\u00a0Let&#8217;s say our sample rate is 48000 Hz, and we need to understand the duration of audio stored in one frame. One frame holds 128 samples; therefore, the calculation is as follows:<\/p>\n<p>(128 \/ 48000) * 1000 = 2.66ms.<\/p><\/blockquote>\n<p>So what exactly was our problem? Our SDK needs at least 10 milliseconds of audio to process, while the browser gives and expects to receive 128 sample frames. Our solution was to create a buffering system that will:<\/p>\n<p>a) Accumulate 10 milliseconds of audio and send that chunk to our WASM module to process b) Take the processed audio from the WASM module, split it into 128 sample frames, and return it to the browser (See Figure 4).<\/p>\n<div id=\"attachment_9886\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9886\" loading=\"lazy\" class=\"wp-image-9886\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram.png\" alt=\"Diagram image for buffers\" width=\"800\" height=\"276\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram.png 1145w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram-300x103.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram-380x131.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram-768x265.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig4-Buffering-Diagram-600x207.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9886\" class=\"wp-caption-text\">Figure 4. A simplified diagram of our buffering system operations<\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<p>After handling these initial challenges, nothing stopped us from creating our first version of Krisp JS SDK.<\/p>\n<h2>The first version of Krisp JS SDK<\/h2>\n<div id=\"attachment_9887\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9887\" loading=\"lazy\" class=\"wp-image-9887\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram.png\" alt=\"JS SDK diagram\" width=\"800\" height=\"142\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram.png 1056w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram-300x53.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram-380x68.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram-768x137.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig5-JS-POC-diagram-600x107.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9887\" class=\"wp-caption-text\">Figure 5. Simplified diagram of our first version of Krisp JS SDK<\/p>\n<\/div>\n<p>In Figure 5, you can see the simplified architecture diagram of our prototype of JS SDK.<\/p>\n<h3>C++ side<\/h3>\n<p>Krisp Audio SDK is the C++ library we needed to run in Javascript. We also added a 128-sample state machine to it to track the state of the audio data and ensure audio consistency. Krisp WASM Processor is a middleware to create Emscripten bindings, allowing us to use methods from C++ on our Javascript side. As you can see, a buffering system is included here, which works with the state machine. Everything is compiled from this point, and we get our WASM Module.<\/p>\n<h3>JS Side and Web Audio API<\/h3>\n<p>We needed to work with <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Audio_API\">Web Audio API<\/a> to process the audio on our javascript side. Web Audio API provides a robust system to process audio on the web. Three main concepts were important in our use case: AudioContext, AudioWorkletProcessor, and AudioWorkletNode. Let&#8217;s go over each of these shortly. AudioContext is basically an audio graph that lets you manipulate audio sources and process the audio with various effects and processors before passing it into the audio destination (see Figure 6).<\/p>\n<div id=\"attachment_9888\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9888\" loading=\"lazy\" class=\"wp-image-9888\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context.png\" alt=\"JS Audio Context\" width=\"800\" height=\"154\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context.png 1002w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context-300x58.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context-380x73.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context-768x148.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig6-Audio-Context-600x116.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9888\" class=\"wp-caption-text\">Figure 6. The basic structure of AudioContext<\/p>\n<\/div>\n<p>AudioWorkletProcessor is capable of receiving input audio and setting the output audio. The interesting part is that you can manipulate audio in its process() method in between. In our case, we imported the WASM Module to the same krisp.processor.js file and started using it in the process() method, taking the cleaned audio and setting it as output.<\/p>\n<p>After writing the necessary code for the processor, the final step would be to integrate that processor into the AudioContext graph somehow. For that, in our krispsdk.js file, <span class=\"discussion-id-ca95a671-b738-44cb-bef8-9ee2de72efcb notion-enable-hover\" data-token-index=\"1\">we c<\/span>reated our filter node using AudioWorkletNode, which takes our processor and adds it to the audio context&#8217;s graph.<\/p>\n<div id=\"attachment_9889\" style=\"width: 1416px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9889\" loading=\"lazy\" class=\"size-full wp-image-9889\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1.png\" alt=\"Snippet image\" width=\"1406\" height=\"404\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1.png 1406w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1-300x86.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1-380x109.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1-768x221.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Snippet1-600x172.png 600w\" sizes=\"(max-width: 1406px) 100vw, 1406px\" \/><\/p>\n<p id=\"caption-attachment-9889\" class=\"wp-caption-text\">Simplified look at the connection between AudioWorkletNode, AudioWorkletProcessor, and AudioContext<\/p>\n<\/div>\n<p>So, at this point, we already got our first working prototype, but there were several issues with it.<\/p>\n<h3>Issues with our first version<\/h3>\n<h4><strong>Buffering system on the C++ side<\/strong><\/h4>\n<p>Although our initial version worked, we encountered some issues with our buffering system. First of all, we implemented all the buffering logic on our C++ side, and as a result, that system was getting compiled into the WASM Module. And although we implemented logic to ensure that audio was consistent, the buffer&#8217;s location could have been more practical, as there was still a chance of losing audio data between processing. It is essential to note that the buffering system was an additional middleware.<\/p>\n<h4><strong>Terminating AudioWorkletNode<\/strong><\/h4>\n<p>Another issue was that we couldn&#8217;t entirely terminate our AudioWorkletNode, which resulted in multiple memory leak issues. Also, because of the same problem, we couldn&#8217;t handle device change based on the sample rate. We should re-initialize our SDK with a proper NC model optimal for that sample rate to ensure the best quality.<\/p>\n<h4><strong>Providing NC models separately<\/strong><\/h4>\n<p>And our last issue was that we were providing our NC models separately in a folder so that they could be hosted on our client&#8217;s side and imported to JS SDK with static URLs. Seeing all these issues, we started working on solutions and came up with a new version of JS SDK.<\/p>\n<h2>The new version of Krisp JS SDK<\/h2>\n<div id=\"attachment_9891\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9891\" loading=\"lazy\" class=\"wp-image-9891\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram.png\" alt=\"New JavaScript Diagram\" width=\"800\" height=\"275\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram.png 1151w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram-300x103.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram-380x130.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram-768x264.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig7-New-JS-diagram-600x206.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9891\" class=\"wp-caption-text\">Figure 7. The new architecture of Krisp JS SDK<\/p>\n<\/div>\n<p>We developed core architectural improvements to eliminate the problems mentioned above (see Figure 7). Let&#8217;s go over each of them.<\/p>\n<ul>\n<li>We moved all the buffering systems to the JS side so that our core SDK would receive data in the expected form, which resulted in a more straightforward implementation and more consistent behavior of our buffers. We started collecting audio and checking for the accumulated audio size. When we have our target 10ms audio in our buffer, we provide that 10ms chunk directly to SDK (So we are not sending every audio frame separately, which is a huge optimization.) With the same logic, our custom buffer class takes the cleaned audio and delivers it back to the browser, split into 128 sample frames.<\/li>\n<li>We moved all the audio processing to a new, separate web worker thread to handle memory leak issues, which worked perfectly. After terminating the worker, everything inside of it gets terminated as well. Although there will remain an open thread, we solved the main issue with loading and keeping multiple WASM Modules. Clients can implement device change handling logic to achieve the best possible audio quality thanks to this change.<\/li>\n<li>We decided to modify our Emscripten method bindings to achieve more flexibility in JS SDK. In the first version, we had only three methods, which were combinations of methods called from the C++ side: init(), toggle(), and dispose(). With the new version, we came to the idea of having a 1-to-1 method binding from C++ to the JS side, allowing us to work with audio on a more advanced level while in JS.For example, while calling init() before, it called multiple methods, including session and its id creation. With the new bindings, we get the session creation method separately, which means together with our in-worker processing logic, we can run multiple instances of NC sessions (for example, run for both microphone and speaker)<\/li>\n<li>And our last improvement was related to our NC models&#8217; delivery. Instead of handling them separately, we packed them into one Emscripten .data file. Later, we also added options to choose which NC models we should preload and which should only be loaded when needed.<\/li>\n<\/ul>\n<p>As you can see in the new architecture, all the communication goes through krispsdk.js which is our main thread. We initialize the worker and worklet from it, and to make them communicate with each other, we used PostMessages. But there was room for optimization for this &#8211; to pass one chunk of audio to SDK and back, we were sending 4 PostMessages. To solve this problem, we came up with two solutions.<\/p>\n<ol>\n<li>The first option was using <a class=\"notion-link-token notion-enable-hover\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/SharedArrayBuffer\" target=\"_blank\" rel=\"noopener noreferrer\" data-token-index=\"1\"><span class=\"link-annotation-unknown-block-id-1855296925\">SharedArrayBuffer<\/span><\/a> so the worker and worklet could communicate directly. This solution works, but it needs to be more practical to make it the main way of operation, as SharedArrayBuffer got some security requirements. To be able to use it, you should set specific headers:We implemented this solution and created an optional flag, which you can enable during the initialization.<\/li>\n<li>The final solution we came up with was to share a port between the worker and the worklet and send post messages directly to the same port. This optimization resulted in a 50% PostMessage cut, and now to process one chunk of audio, we are using only 2 PostMessages (See Figure 8).\n<div id=\"attachment_9892\" style=\"width: 810px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-9892\" loading=\"lazy\" class=\"wp-image-9892\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture.png\" alt=\"New JS Architechture\" width=\"800\" height=\"380\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture.png 997w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture-300x142.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture-380x180.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture-768x364.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/Fig8-New-Architecture-600x285.png 600w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/p>\n<p id=\"caption-attachment-9892\" class=\"wp-caption-text\">Figure 8. The improved architecture of the new version of Krisp JS SDK<\/p>\n<\/div>\n<\/li>\n<\/ol>\n<h2>Summary<\/h2>\n<p>In conclusion, developing a noise cancellation SDK for web usage comes with its own set of unique challenges. Through hard work and ingenuity, the team was able to create a game-changing JS SDK that allows for web-based real-time communication with top-tier noise cancellation. The use of Web Assembly showcased the endless possibilities of this technology. The team&#8217;s efforts demonstrate that with the right approach, web-based noise cancellation can be achieved with near-native performance.<\/p>\n<h2><strong>Try next-level audio and voice technologies \u00a0<\/strong><\/h2>\n<p><a href=\"https:\/\/krisp.ai\/blog\/voice-communication-quality-with-krisp-sdk\/\" target=\"_blank\" rel=\"noopener\">Krisp licenses its SDKs<\/a>\u00a0to embed directly into applications and devices. <a href=\"https:\/\/krisp.ai\/developers\/\" target=\"_blank\" rel=\"noopener\">Learn more about Krisp&#8217;s SDKs<\/a> and begin your evaluation today.<\/p>\n<p><a href=\"https:\/\/krisp.ai\/developers\/\"><img loading=\"lazy\" class=\"alignnone wp-image-9898 size-full\" src=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta.png\" alt=\"Link to Krisp Developers Page banner\" width=\"1280\" height=\"720\" srcset=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta.png 1280w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta-300x169.png 300w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta-380x214.png 380w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta-768x432.png 768w, https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/engineering-blog-cta-600x338.png 600w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<h3>References<\/h3>\n<ul>\n<li>WebAssembly documentation on Mozilla Developer Network: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/WebAssembly\">https:\/\/developer.mozilla.org\/en-US\/docs\/WebAssembly<\/a><\/li>\n<li>Emscripten documentation: <a href=\"https:\/\/emscripten.org\/docs\/index.html\">https:\/\/emscripten.org\/docs\/index.html<\/a><\/li>\n<li>Web Audio API documentation on Mozilla Developer Network: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Audio_API\">https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Audio_API<\/a><\/li>\n<\/ul>\n<hr \/>\n<p>This article was written by Arman Jivanyan, BSc in Computer Science, Software Engineer at Krisp.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In today&#8217;s world, browsers have become an integral part of our daily lives. Although Krisp worked on various native libraries for most platforms in use (Windows, Mac, Linux, Android, IOS), there were still many use cases where Krisp SDK was needed in the context of web applications. This article summarizes our journey of creating world-class [&hellip;]<\/p>\n","protected":false},"author":71,"featured_media":9896,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"two_page_speed":[]},"categories":[421],"tags":[434,433,430,431,432],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.2 (Yoast SEO v23.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Krisp Blog | Better Audio Processing with Krisp JS SDK<\/title>\n<meta name=\"description\" content=\"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Krisp Blog | Better Audio Processing with Krisp JS SDK\" \/>\n<meta property=\"og:description\" content=\"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\" \/>\n<meta property=\"og:site_name\" content=\"Krisp\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/krispHQ\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-03-24T16:07:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-12T10:28:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1400\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Krisp Engineering Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@krispHQ\" \/>\n<meta name=\"twitter:site\" content=\"@krispHQ\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\"},\"author\":{\"name\":\"Krisp Engineering Team\",\"@id\":\"https:\/\/krisp.ai\/blog\/#\/schema\/person\/e9f59158d89de3002958d323d2e788f5\"},\"headline\":\"Breaking the audio processing barrier on the web with Krisp JS SDK\",\"datePublished\":\"2023-03-24T16:07:27+00:00\",\"dateModified\":\"2025-03-12T10:28:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\"},\"wordCount\":2050,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/krisp.ai\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png\",\"keywords\":[\"Audio Filter\",\"Java Script\",\"JS SDK\",\"WASM\",\"Web Assembly\"],\"articleSection\":[\"Engineering Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\",\"url\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\",\"name\":\"Krisp Blog | Better Audio Processing with Krisp JS SDK\",\"isPartOf\":{\"@id\":\"https:\/\/krisp.ai\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png\",\"datePublished\":\"2023-03-24T16:07:27+00:00\",\"dateModified\":\"2025-03-12T10:28:41+00:00\",\"description\":\"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.\",\"breadcrumb\":{\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage\",\"url\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png\",\"contentUrl\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png\",\"width\":2000,\"height\":1400},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/krisp.ai\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Breaking the audio processing barrier on the web with Krisp JS SDK\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/krisp.ai\/blog\/#website\",\"url\":\"https:\/\/krisp.ai\/blog\/\",\"name\":\"Krisp\",\"description\":\"Blog\",\"publisher\":{\"@id\":\"https:\/\/krisp.ai\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/krisp.ai\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/krisp.ai\/blog\/#organization\",\"name\":\"Krisp\",\"url\":\"https:\/\/krisp.ai\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/krisp.ai\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2024\/10\/K.png\",\"contentUrl\":\"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2024\/10\/K.png\",\"width\":696,\"height\":696,\"caption\":\"Krisp\"},\"image\":{\"@id\":\"https:\/\/krisp.ai\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/krispHQ\/\",\"https:\/\/x.com\/krispHQ\",\"https:\/\/www.linkedin.com\/company\/krisphq\/\",\"https:\/\/www.youtube.com\/channel\/UCAMZinJdR9P33fZUNpuxXtg\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/krisp.ai\/blog\/#\/schema\/person\/e9f59158d89de3002958d323d2e788f5\",\"name\":\"Krisp Engineering Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/krisp.ai\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/26475ad8219056696662f819691ee49d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/26475ad8219056696662f819691ee49d?s=96&d=mm&r=g\",\"caption\":\"Krisp Engineering Team\"},\"url\":\"https:\/\/krisp.ai\/blog\/author\/eng-team\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Krisp Blog | Better Audio Processing with Krisp JS SDK","description":"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/","og_locale":"en_US","og_type":"article","og_title":"Krisp Blog | Better Audio Processing with Krisp JS SDK","og_description":"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.","og_url":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/","og_site_name":"Krisp","article_publisher":"https:\/\/www.facebook.com\/krispHQ\/","article_published_time":"2023-03-24T16:07:27+00:00","article_modified_time":"2025-03-12T10:28:41+00:00","og_image":[{"width":2000,"height":1400,"url":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png","type":"image\/png"}],"author":"Krisp Engineering Team","twitter_card":"summary_large_image","twitter_creator":"@krispHQ","twitter_site":"@krispHQ","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#article","isPartOf":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/"},"author":{"name":"Krisp Engineering Team","@id":"https:\/\/krisp.ai\/blog\/#\/schema\/person\/e9f59158d89de3002958d323d2e788f5"},"headline":"Breaking the audio processing barrier on the web with Krisp JS SDK","datePublished":"2023-03-24T16:07:27+00:00","dateModified":"2025-03-12T10:28:41+00:00","mainEntityOfPage":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/"},"wordCount":2050,"commentCount":4,"publisher":{"@id":"https:\/\/krisp.ai\/blog\/#organization"},"image":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage"},"thumbnailUrl":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png","keywords":["Audio Filter","Java Script","JS SDK","WASM","Web Assembly"],"articleSection":["Engineering Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/","url":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/","name":"Krisp Blog | Better Audio Processing with Krisp JS SDK","isPartOf":{"@id":"https:\/\/krisp.ai\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage"},"image":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage"},"thumbnailUrl":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png","datePublished":"2023-03-24T16:07:27+00:00","dateModified":"2025-03-12T10:28:41+00:00","description":"This article shares the journey of tackling the challenges of bringing audio processing and Krisp Noise Cancellation to the web.","breadcrumb":{"@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#primaryimage","url":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png","contentUrl":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2023\/03\/JSbanner.png","width":2000,"height":1400},{"@type":"BreadcrumbList","@id":"https:\/\/krisp.ai\/blog\/breaking-the-audio-processing-barrier-on-the-web-with-krisp-js-sdk\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/krisp.ai\/blog\/"},{"@type":"ListItem","position":2,"name":"Breaking the audio processing barrier on the web with Krisp JS SDK"}]},{"@type":"WebSite","@id":"https:\/\/krisp.ai\/blog\/#website","url":"https:\/\/krisp.ai\/blog\/","name":"Krisp","description":"Blog","publisher":{"@id":"https:\/\/krisp.ai\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/krisp.ai\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/krisp.ai\/blog\/#organization","name":"Krisp","url":"https:\/\/krisp.ai\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/krisp.ai\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2024\/10\/K.png","contentUrl":"https:\/\/krisp.ai\/blog\/wp-content\/uploads\/2024\/10\/K.png","width":696,"height":696,"caption":"Krisp"},"image":{"@id":"https:\/\/krisp.ai\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/krispHQ\/","https:\/\/x.com\/krispHQ","https:\/\/www.linkedin.com\/company\/krisphq\/","https:\/\/www.youtube.com\/channel\/UCAMZinJdR9P33fZUNpuxXtg"]},{"@type":"Person","@id":"https:\/\/krisp.ai\/blog\/#\/schema\/person\/e9f59158d89de3002958d323d2e788f5","name":"Krisp Engineering Team","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/krisp.ai\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/26475ad8219056696662f819691ee49d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/26475ad8219056696662f819691ee49d?s=96&d=mm&r=g","caption":"Krisp Engineering Team"},"url":"https:\/\/krisp.ai\/blog\/author\/eng-team\/"}]}},"_links":{"self":[{"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/posts\/9878"}],"collection":[{"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/users\/71"}],"replies":[{"embeddable":true,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/comments?post=9878"}],"version-history":[{"count":17,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/posts\/9878\/revisions"}],"predecessor-version":[{"id":21003,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/posts\/9878\/revisions\/21003"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/media\/9896"}],"wp:attachment":[{"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/media?parent=9878"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/categories?post=9878"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/krisp.ai\/blog\/wp-json\/wp\/v2\/tags?post=9878"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}