{"id":28494,"date":"2022-08-12T15:39:42","date_gmt":"2022-08-12T15:39:42","guid":{"rendered":"http:\/\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary"},"modified":"2023-12-12T10:41:42","modified_gmt":"2023-12-12T18:41:42","slug":"building-a-music-streaming-app-with-web-audio-api-and-cloudinary","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/","title":{"rendered":"Audio Streaming with Web Audio API and Cloudinary"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Once upon a time, if you wanted to play audio on the web, you will require Flash, Quicktime, or another plugin. Then came the <code>HTML5<\/code> audio tag which allowed you to play audio without requiring any plugins and some other functionalities. Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that.\nHowever, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.<\/p>\n<h2>What is Web Audio API<\/h2>\n<p>The Web Audio API provides a system for controlling audio on the Web, allowing us to choose audio sources, add audio effects, audio visualizations, apply spatial effects and much more. Some of the features of this high level web API are:<\/p>\n<ul>\n<li>Processing of audio sources from an <a href=\"https:\/\/html.spec.whatwg.org\/multipage\/media.html#audio\">audio<\/a> or <a href=\"https:\/\/html.spec.whatwg.org\/multipage\/media.html#video\">video<\/a> <a href=\"https:\/\/www.w3.org\/TR\/webaudio\/#mediaelementaudiosourcenode\">media element<\/a>.<\/li>\n<li>Processing live audio input using a <a href=\"https:\/\/www.w3.org\/TR\/webaudio\/#mediastreamtrackaudiosourcenode\">MediaStream<\/a> from <a href=\"https:\/\/www.w3.org\/TR\/mediacapture-streams\/#dom-mediadevices-getusermedia\">getUserMedia()<\/a>.<\/li>\n<li>\n<a href=\"https:\/\/www.w3.org\/TR\/webaudio\/#Spatialization\">Spatialized audio<\/a> supporting a wide range of 3D games and immersive environments<\/li>\n<li>A wide range of very high quality room effects including:\n<ul>\n<li>Small \/ large room<\/li>\n<li>Cathedral<\/li>\n<li>Concert hall<\/li>\n<li>Cave<\/li>\n<li>Tunnel e.t.c<\/li>\n<\/ul>\n<\/li>\n<li>\n<a href=\"https:\/\/www.w3.org\/TR\/webaudio\/#ModularRouting\">Modular routing<\/a> for simple or complex mixing\/effect architectures.<\/li>\n<\/ul>\n<p>We now have an overview of the web audio api, let\u2019s see how it\u2019s used.<\/p>\n<h2>Usage<\/h2>\n<p>It\u2019s important to know that the Web audio API doesn\u2019t replace the <code>audio<\/code> tag, rather it complements it. It depends on the context you\u2019re working with, for instance if you want to control audio playback (operations such as volume, play\/pause, previous\/next), the audio tag is recommended. On the other hand, if you want to perform complex audio operations such as adding audio effects, streaming live audio input,  and also playback, the audio API is best suited to handle those operations.\nLet\u2019s briefly illustrate how the API works:<\/p>\n<ul>\n<li>Firstly, create an Audio context. The Audio context gives us full access to the features and functionalities of the Web Audio API.<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/javascript<\/span>\n<span class=\"hljs-keyword\">const<\/span> audioContext = <span class=\"hljs-keyword\">new<\/span> AudioContext();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>Next, we will create an audio source and pass it into the audio context.<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/javascript<\/span>\n&lt;audio src=<span class=\"hljs-string\">\"newTrack.mp3\"<\/span> id=<span class=\"hljs-string\">\"audio\"<\/span>&gt;&lt;\/audio&gt;\n<span class=\"hljs-comment\">\/\/ get the audio element<\/span>\n<span class=\"hljs-keyword\">const<\/span> audioElement = document.getElementById(<span class=\"hljs-string\">'audio'<\/span>);\n    \n<span class=\"hljs-comment\">\/\/ pass it into the audio context<\/span>\n<span class=\"hljs-keyword\">const<\/span> track = audioContext.createMediaElementSource(audioElement);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>createMediaElementSource()<\/code> here is used to create a new <code>MediaElementAudioSourceNode<\/code> object, given an existing HTML <code>&lt;audio&gt;<\/code> or <code>&lt;video&gt;<\/code> element, the audio from which can then be played and manipulated.<\/p>\n<ul>\n<li>Next, we can now create effect node to the audio such as reverb, panner, e.t.c<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/javascript<\/span>\n<span class=\"hljs-keyword\">const<\/span> pannerOptions = { <span class=\"hljs-attr\">pan<\/span>: <span class=\"hljs-number\">0<\/span> };\n<span class=\"hljs-keyword\">const<\/span> panner = <span class=\"hljs-keyword\">new<\/span> StereoPannerNode(audioCtx, pannerOptions);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<ul>\n<li>Finally, we have to connect our audio source\/input to a destination preferably our speakers.<\/li>\n<\/ul>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/javascript<\/span>\ntrack.connect(audioContext.destination);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now we\u2019ve understood how the web audio API works, let\u2019s go ahead to building a web app that requires <code>audio<\/code> functionality.<\/p>\n<h2>Pre-requisites<\/h2>\n<ul>\n<li>Knowledge of JavaScript and React<\/li>\n<li>Node &gt;v14 installed<\/li>\n<li>A Cloudinary account. <a href=\"https:\/\/cloudinary.com\/users\/login\">Sign in<\/a> here<\/li>\n<li>A Supabase account. <a href=\"https:\/\/app.supabase.com\/\">Create<\/a> one here.<\/li>\n<li>A code editor VS Code preferably<\/li>\n<\/ul>\n<p>The complete code for this tutorial is on <a href=\"https:\/\/codesandbox.io\/embed\/goofy-lake-fpdu4b?autoresize=1&amp;fontsize=14&amp;hidenavigation=1&amp;theme=dark\">Codesandbox<\/a>.<\/p>\n<\/div>\n\n\n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/goofy-lake-fpdu4b?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"goofy-lake-fpdu4b?\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><h2>Getting Started<\/h2>\n<p>Let\u2019s start by setting up a react project with create-react-app. Run this command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-id\">#bash<\/span>\n<span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">create-react-app<\/span> <span class=\"hljs-selector-tag\">music-app<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>When it\u2019s done installing, change directory to <code>music-app<\/code> and open it on your code editor. Go ahead and install the following packages:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-keyword\">@chakra-ui<\/span>\/react @emotion\/react @emotion\/styled framer-motion\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This adds chakra ui to your project dependencies, and go ahead to update your <code>index.js<\/code> to look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">\n<span class=\"hljs-comment\">#src\/index.js<\/span>\nimport React from <span class=\"hljs-string\">'react'<\/span>;\nimport ReactDOM from <span class=\"hljs-string\">'react-dom\/client'<\/span>;\nimport App from <span class=\"hljs-string\">'.\/App'<\/span>;\nimport { ChakraProvider } from <span class=\"hljs-string\">'@chakra-ui\/react'<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> root = ReactDOM.createRoot(document.getElementById(<span class=\"hljs-string\">'root'<\/span>));\n    root.render(\n      &lt;ChakraProvider&gt;\n        &lt;React.StrictMode&gt;\n          &lt;App \/&gt;\n        &lt;\/React.StrictMode&gt;\n      &lt;\/ChakraProvider&gt;\n    );\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s go ahead and create our components. Firstly, create a components folder in the <code>src<\/code> directory and add these files <code>Upload.js<\/code>, <code>MusicList.js<\/code>, <code>MusicPlayer.js<\/code>.<\/p>\n<h2>Adding the Cloudinary Upload widget<\/h2>\n<p>We will be using cloudinary upload widget to add songs to our music list. We will make use of the CDN to integrate the upload widget into our app. We will add this CDN using React Helmet. Helmet is a reusable React component will manage all of your changes to the document head.\nInstall helmet by running <code>npm i react-helmet<\/code><\/p>\n<p>Go ahead and modify your <code>App.js<\/code> to look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/javascript<\/span>\n<span class=\"hljs-keyword\">import<\/span> { Box } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> MusicList <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/music\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">\".\/App.css\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Helmet } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-helmet\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Upload <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/Upload\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"1200px\"<\/span> <span class=\"hljs-attr\">margin<\/span>=<span class=\"hljs-string\">\"auto\"<\/span> <span class=\"hljs-attr\">padding<\/span>=<span class=\"hljs-string\">\"2rem\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Helmet<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"UTF-8\"<\/span> \/&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/widget.Cloudinary.com\/v2.0\/global\/all.js\"<\/span>\n                    <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>\n                &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Helmet<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Upload<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">MusicList<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span><\/span>\n    );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The widget requires your cloudinary <code>upload_preset<\/code> and <code>cloud_name<\/code>. Head over to Cloudinary Settings and click on the Upload tab, and scroll down to upload presets to create one.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_F080F982B581A05FFC62F43408E755845D42F4871A811A61F30CB1AF003A0D05_1658226062227_Screenshot+2022-07-19+at+11.20.19.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1001\"\/><\/p>\n<p>I have already created some for myself, you can go ahead to create an upload preset by clicking on the <strong>Add upload preset<\/strong> link. Take note of the preset name, we\u2019ll be using it soon. You can find your cloudinary cloud name on the <strong>Dashboard<\/strong> tab.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_F080F982B581A05FFC62F43408E755845D42F4871A811A61F30CB1AF003A0D05_1658226730180_Screenshot+2022-07-19+at+11.23.01.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"651\"\/><\/p>\n<p>Now go ahead to update your <code>Update.js<\/code> fie with the following lines of code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/src\/components\/Upload.js<\/span>\n    \n<span class=\"hljs-keyword\">import<\/span> { Box, Button } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Upload<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<span class=\"hljs-keyword\">const<\/span> &#91;title, setTitle] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> &#91;url, setUrl] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n\n<span class=\"hljs-keyword\">const<\/span> openWidget = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n            <span class=\"hljs-comment\">\/\/ create the widget<\/span>\n    <span class=\"hljs-keyword\">const<\/span> widget = <span class=\"hljs-built_in\">window<\/span>.cloudinary.createUploadWidget(\n        {\n            <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"&lt;your cloud name&gt;\"<\/span>,\n            <span class=\"hljs-attr\">uploadPreset<\/span>: <span class=\"hljs-string\">\"&lt;your upload preset&gt;\"<\/span>\n        },\n        (error, result) =&gt; {\n            <span class=\"hljs-keyword\">if<\/span> (result.event === <span class=\"hljs-string\">\"success\"<\/span>) {\n                <span class=\"hljs-keyword\">if<\/span> (result.info.is_audio === <span class=\"hljs-literal\">true<\/span>) {\n                    <span class=\"hljs-built_in\">console<\/span>.log(result)\n                }\n            } <span class=\"hljs-keyword\">else<\/span> {\n                <span class=\"hljs-built_in\">console<\/span>.log(error)\n            }\n        }\n    );\n    widget.open(); <span class=\"hljs-comment\">\/\/ open up the widget after creation<\/span>\n};\n    \n\n<span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>\n    <span class=\"hljs-attr\">p<\/span>=<span class=\"hljs-string\">\"3\"<\/span>\n    <span class=\"hljs-attr\">px<\/span>=<span class=\"hljs-string\">\"4\"<\/span>\n    <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">\"3\"<\/span>\n    &gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span>\n            <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> openWidget()}\n            variant=\"solid\"\n            width=\"10rem\"\n            padding=\".5rem\"\n            colorScheme='teal'\n        &gt;\n            Upload Song\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span><\/span>\n)\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we have a button that triggers our upload widget open. Save and run the app. You should see something like this when you click the upload button.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_F080F982B581A05FFC62F43408E755845D42F4871A811A61F30CB1AF003A0D05_1658227424555_Screenshot+2022-07-19+at+11.43.20.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1097\"\/><\/p>\n<p>Awesome. Right now we can use the upload widget but we have not yet added functionality on our app. Let\u2019s go ahead to save the music we will be uploading with a supabase db.<\/p>\n<h2>Adding Supabase DB<\/h2>\n<p>Supabase claims to be the open source version of Firebase. It provides all the backend services you need to build a product. For the purpose of our article, we\u2019ll be using the DB service only. Go ahead and install the JavaScript package with <code>npm i @supabase\/supabase-js<\/code>.\nEnsure you\u2019ve created a supabase account. Follow these steps:<\/p>\n<ul>\n<li>Create a new project<\/li>\n<li>Copy the <code>annon<\/code>  <code>public<\/code> key<\/li>\n<li>Copy the URL<\/li>\n<\/ul>\n<p>Create a <code>src\/client.js<\/code> file and add these lines of code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/client.js<\/span>\n<span class=\"hljs-keyword\">import<\/span> { createClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@supabase\/supabase-js\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> URL = process.env.REACT_APP_SUPABASE_URL;\n<span class=\"hljs-keyword\">const<\/span> PUBLIC_SECRET =process.env.REACT_APP_SUPABASE_PUBLIC_SECRET;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> supabase = createClient(URL, PUBLIC_SECRET)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Create a <code>.env<\/code> file and add the required values.<\/p>\n<p>Create a table in supabase and call it any name of your choice, i called mine <code>audio-player<\/code>. Also create columns for url and title.\nYou should have a screen that looks like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_F080F982B581A05FFC62F43408E755845D42F4871A811A61F30CB1AF003A0D05_1658242531498_Screenshot+2022-07-19+at+15.55.17.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"886\"\/><\/p>\n<p>Now, we will go ahead and update our <code>components\/Upload.js<\/code> file to look like<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/components\/Upload.js<\/span>\n    \n<span class=\"hljs-keyword\">import<\/span> { Box, Button } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/client\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Upload<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> &#91;title, setTitle] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> &#91;url, setUrl] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> openWidget = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n            <span class=\"hljs-comment\">\/\/ create the widget<\/span>\n        <span class=\"hljs-keyword\">const<\/span> widget = <span class=\"hljs-built_in\">window<\/span>.cloudinary.createUploadWidget(\n            {\n            <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"sammy365\"<\/span>,\n            <span class=\"hljs-attr\">uploadPreset<\/span>: <span class=\"hljs-string\">\"tutorial\"<\/span>\n            },\n            (error, result) =&gt; {\n            <span class=\"hljs-keyword\">if<\/span> (result.event === <span class=\"hljs-string\">\"success\"<\/span>) {\n                <span class=\"hljs-keyword\">if<\/span> (result.info.is_audio === <span class=\"hljs-literal\">true<\/span>) {\n                    setUrl(result.info.secure_url);\n                    setTitle(result.info.original_filename);\n                        <span class=\"hljs-built_in\">console<\/span>.log(result)\n                }\n            } <span class=\"hljs-keyword\">else<\/span> {\n                <span class=\"hljs-built_in\">console<\/span>.log(error)\n            }\n        }\n    );\n    widget.open(); <span class=\"hljs-comment\">\/\/ open up the widget after creation<\/span>\n};\n\n<span class=\"hljs-keyword\">const<\/span> createSong = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    <span class=\"hljs-keyword\">await<\/span> supabase\n        .from(<span class=\"hljs-string\">\"audio-player\"<\/span>)\n        .insert(&#91;\n            {\n            url, title\n            }\n        ]).single();\n    }\n\n<span class=\"hljs-keyword\">if<\/span> (url &amp;&amp; title) {\n    createSong();\n    }\n    \n<span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>\n    <span class=\"hljs-attr\">p<\/span>=<span class=\"hljs-string\">\"3\"<\/span>\n    <span class=\"hljs-attr\">px<\/span>=<span class=\"hljs-string\">\"4\"<\/span>\n    <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">\"3\"<\/span>\n    &gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span>\n        <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> openWidget()}\n        variant=\"solid\"\n        width=\"10rem\"\n        padding=\".5rem\"\n        colorScheme='teal'\n        &gt;\n            Upload Song\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span><\/span>\n)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we have a <code>createSong()<\/code> function inserts the value of <code>url<\/code> and <code>title<\/code> to the table. Let\u2019s now go ahead to create our component that retrieves and displays the songs we saved in our db. Naviage to your <code>MusicList.js<\/code> and add these lines of code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/components\/MusicList.js<\/span>\n    \n<span class=\"hljs-keyword\">import<\/span> { Box, Center, Heading } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> MusicPlayer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/MusicPlayer\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { supabase } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/client\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useState, useEffect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Music<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> &#91;music, setMusic] = useState(&#91;]);\n    <span class=\"hljs-keyword\">const<\/span> fetchSongs = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> supabase.from(<span class=\"hljs-string\">\"audio-player\"<\/span>).select();\n            setMusic(data);\n    }\n    \nuseEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    fetchSongs()\n}, &#91;]);\n       \n<span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h2\"<\/span>&gt;<\/span> Uploaded Songs <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">display<\/span>=<span class=\"hljs-string\">\"grid\"<\/span> <span class=\"hljs-attr\">gridTemplateColumns<\/span>=<span class=\"hljs-string\">'repeat(3, 1fr)'<\/span> <span class=\"hljs-attr\">gridGap<\/span>=<span class=\"hljs-string\">{4}<\/span> <span class=\"hljs-attr\">mt<\/span>=<span class=\"hljs-string\">\"8\"<\/span>&gt;<\/span>\n                {music.map((m, key) =&gt; (\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">MusicPlayer<\/span> <span class=\"hljs-attr\">music<\/span>=<span class=\"hljs-string\">{m}<\/span> <span class=\"hljs-attr\">index<\/span>=<span class=\"hljs-string\">{key}<\/span> \/&gt;<\/span>\n                ))}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Center<\/span>&gt;<\/span>\n                {\n                music.length === 0 ?\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h6\"<\/span> <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">\"lg\"<\/span>&gt;<\/span> No song has been uploaded<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n                    : \"\"\n                }\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Center<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we are simply fetching music data from our supabase table  and passing it to a <code>MusicPlayer<\/code> component. Let\u2019s go ahead to create the <code>MusicPlayer<\/code> component. Add the following lines of code in <code>components\/MusicPlayer.js<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ components\/MusicPlayer.js<\/span>\n    \n<span class=\"hljs-keyword\">import<\/span> moment <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"moment\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Box, Heading, Spacer } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">MusicPlayer<\/span>(<span class=\"hljs-params\">{ music, index }<\/span>) <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span> <span class=\"hljs-attr\">border<\/span>=<span class=\"hljs-string\">'1px'<\/span> <span class=\"hljs-attr\">borderColor<\/span>=<span class=\"hljs-string\">'gray.200'<\/span> <span class=\"hljs-attr\">boxShadow<\/span>=<span class=\"hljs-string\">'lg'<\/span> <span class=\"hljs-attr\">p<\/span>=<span class=\"hljs-string\">\"6\"<\/span> &gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Spacer<\/span> <span class=\"hljs-attr\">mt<\/span>=<span class=\"hljs-string\">\"6\"<\/span>&gt;<\/span>\n                {moment(music.created_at).format(\"MMMM Do YYYY\")}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Spacer<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span> <span class=\"hljs-attr\">mt<\/span>=<span class=\"hljs-string\">\"8\"<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h3\"<\/span> <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">\"lg\"<\/span> <span class=\"hljs-attr\">mb<\/span>=<span class=\"hljs-string\">\"4\"<\/span>&gt;<\/span> {music.title} <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">audio<\/span>\n                    <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{music.url}<\/span>\n                    <span class=\"hljs-attr\">controls<\/span>\n                    <span class=\"hljs-attr\">volume<\/span>=<span class=\"hljs-string\">{0.5}<\/span>\n                \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span><\/span>\n        )\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we are retrieving data from our db table. If you also recognize, we use the HTML5 <code>audio<\/code> tag as our music player.\nYou can now go ahead to save and run the app.<\/p>\n<p><a href=\"https:\/\/www.dropbox.com\/s\/ablauh3ezea0rpx\/screencast-nimbus-capture-2022.07.19-16_05_21.webm?dl=0\">https:\/\/www.dropbox.com\/s\/ablauh3ezea0rpx\/screencast-nimbus-capture-2022.07.19-16_05_21.webm?dl=0<\/a><\/p>\n<p>Awesome.\nIf you notice they are two problems:<\/p>\n<ol>\n<li>On our supabase table, 2 rows are created instead of ome<\/li>\n<li>When we click on <strong>Done<\/strong> on cloudinary, our app should show the uploaded files, instead of refreshing manually to see the uploaded files.<\/li>\n<\/ol>\n<p>I\u2019ll encourage you to take a look at these problems and solve them.<\/p>\n<h2>Exploring Other Streaming APIs<\/h2>\n<p>\nWhile our focus has been primarily on utilizing the Web Audio API and Supabase for our music app, there are several other potent APIs and services available for audio and video streaming. For instance:\n<\/p>\n<ul>\n<li>TheAudioDB: A community-driven platform offering rich audio metadata.\n<li>YouTube Video Info: Extract essential information from YouTube videos, including their audio and video streams.\n<li>Audio File Stream Services: Enables parsing of streamed audio files as they are received on the user&#8217;s end.\n<\/li>\n<\/ul>\n<p>\nIf you&#8217;re looking to explore live streaming further, consider diving into these APIs:\n<\/p>\n<ul>\n<li>Video SDK\n<li>Mux\n<li>Agora\n<li>api.video\n<li>AWS IVS\n<li>100ms\n<li>DaCast\n<li>Wowza\n<li>Vonage\n<li>Dolby.io\n<\/li>\n<\/ul>\n<p>\nEach of these provides unique features and functionalities tailored for different use cases, from basic audio streaming to comprehensive live broadcasting.\n<\/p>\n<h2>Conclusion<\/h2>\n<p>In this post, we learned about the Web audio API, and how it works. We then went on to build a music app with Reactjs and Cloudinary. I hope you\u2019ve learned something valuable from this piece.<\/p>\n<p>Happy Coding!<\/p>\n<h2>Further Reading<\/h2>\n<ul>\n<li>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Audio_API\">Web Audio API<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/cloudinary.com\/documentation\/image_upload_api_reference\">Cloudinary Upload API<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28495,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[389,134,177,246,371],"class_list":["post-28494","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-audio","tag-guest-post","tag-javascript","tag-react","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Audio Streaming with Web Audio API and Cloudinary<\/title>\n<meta name=\"description\" content=\"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Audio Streaming with Web Audio API and Cloudinary\" \/>\n<meta property=\"og:description\" content=\"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-08-12T15:39:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-12T18:41:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1728\" \/>\n\t<meta property=\"og:image:height\" content=\"790\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Audio Streaming with Web Audio API and Cloudinary\",\"datePublished\":\"2022-08-12T15:39:42+00:00\",\"dateModified\":\"2023-12-12T18:41:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA\",\"keywords\":[\"Audio\",\"Guest Post\",\"Javascript\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\",\"name\":\"Audio Streaming with Web Audio API and Cloudinary\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA\",\"datePublished\":\"2022-08-12T15:39:42+00:00\",\"dateModified\":\"2023-12-12T18:41:42+00:00\",\"description\":\"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA\",\"width\":1728,\"height\":790},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Audio Streaming with Web Audio API and Cloudinary\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Audio Streaming with Web Audio API and Cloudinary","description":"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.","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:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary","og_locale":"en_US","og_type":"article","og_title":"Audio Streaming with Web Audio API and Cloudinary","og_description":"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary","og_site_name":"Cloudinary Blog","article_published_time":"2022-08-12T15:39:42+00:00","article_modified_time":"2023-12-12T18:41:42+00:00","og_image":[{"width":1728,"height":790,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/"},"author":{"name":"","@id":""},"headline":"Audio Streaming with Web Audio API and Cloudinary","datePublished":"2022-08-12T15:39:42+00:00","dateModified":"2023-12-12T18:41:42+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA","keywords":["Audio","Guest Post","Javascript","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary","name":"Audio Streaming with Web Audio API and Cloudinary","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA","datePublished":"2022-08-12T15:39:42+00:00","dateModified":"2023-12-12T18:41:42+00:00","description":"Essentially, if you wanted to embed sound on a web page, or stream audio using the MediaStream API; the HTML5 audio tag could handle that. However, as technology keeps advancing and the demand for web browsers and applications to handle more complex functionalities, the audio tag is very limited. Hence, the Web Audio API.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA","width":1728,"height":790},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/building-a-music-streaming-app-with-web-audio-api-and-cloudinary#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Audio Streaming with Web Audio API and Cloudinary"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924189\/Web_Assets\/blog\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160\/aaf1e61d919a4383ed5f3e9dbeab5d832be20813-1728x790-1_2849512160.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28494","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28494"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28494\/revisions"}],"predecessor-version":[{"id":31677,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28494\/revisions\/31677"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28495"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28494"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28494"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}