> ## Documentation Index
> This page is part of the Image and Video APIs product. Fetch the complete documentation index for Image and Video APIs at: https://cloudinary.com/documentation/llms-image-and-video-apis.txt?referrer=docpage and then use it to discover all relevant pages before exploring further.
> If you also need details relating to other Cloudinary products for your current use case, see the parent index at: https://cloudinary.com/documentation/llms.txt?referrer=docpage

# Audio controls and mixing



Providing users with control over audio levels is a key WCAG requirement. This page covers programmatic volume adjustment using Cloudinary transformations, the Cloudinary Video Player's built-in controls, and mixing multiple audio tracks to achieve the correct foreground-to-background separation.

> **See also:**:
>
> * [Color accessibility](accessible_media_visual_audio_clarity#assist_people_with_color_blind_conditions): Simulate and assist color blind conditions, analyze color accessibility, and replace colors for light and dark themes.

> * [Text, contrast, and color](accessible_media_visual_audio_clarity_text): Customizable caption styling, text overlays on images and videos, contrast and brightness adjustments, customizable text overlay parameters, and OCR text extraction.

## Adjust audio volume

For people with hearing impairments or those in different listening environments, providing volume control options ensures your audio and video content is accessible. The WCAG guidelines specify that if audio plays automatically for more than 3 seconds, users must have a mechanism to pause, stop, or control the volume independently.

With Cloudinary, you can implement this mechanism both programmatically and using the Cloudinary Video Player.

### Programmatic volume adjustment

Programmatically adjust the volume directly in your media transformations using the `volume` effect (`e_volume`). This allows you to give control to your users via external controls ([as shown in the demo](#demo_external_volume_controls_using_transformations)).

For example, to reduce the volume to 50% (`e_volume:-50`):

![Video with reduced volume](https://res.cloudinary.com/demo/video/upload/e_volume:-50/docs/grocery-store.mp4 "thumb:c_scale,w_300, muted:false")

```nodejs
cloudinary.video("docs/grocery-store", {effect: "volume:-50"})
```

```react
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(-50));
```

```vue
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(-50));
```

```angular
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(-50));
```

```js
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(-50));
```

```python
CloudinaryVideo("docs/grocery-store").video(effect="volume:-50")
```

```php
use Cloudinary\Transformation\VideoEdit;

(new VideoTag('docs/grocery-store.mp4'))
	->videoEdit(VideoEdit::volume(-50));
```

```java
cloudinary.url().transformation(new Transformation().effect("volume:-50")).videoTag("docs/grocery-store");
```

```ruby
cl_video_tag("docs/grocery-store", effect: "volume:-50")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().Effect("volume:-50")).BuildVideoTag("docs/grocery-store")
```

```dart
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(-50)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setEffect("volume:-50")).generate("docs/grocery-store.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().effect("volume:-50")).resourceType("video").generate("docs/grocery-store.mp4");
```

```flutter
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(-50)));
```

```kotlin
cloudinary.video {
	publicId("docs/grocery-store.mp4")
	 videoEdit(VideoEdit.volume(-50)) 
}.generate()
```

```jquery
$.cloudinary.video("docs/grocery-store", {effect: "volume:-50"})
```

```react_native
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(-50));
```

To increase the volume by 150% (`e_volume:150`):

![Video with increased volume](https://res.cloudinary.com/demo/video/upload/e_volume:150/docs/grocery-store.mp4 "thumb:c_scale,w_300, muted:false")

```nodejs
cloudinary.video("docs/grocery-store", {effect: "volume:150"})
```

```react
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(150));
```

```vue
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(150));
```

```angular
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(150));
```

```js
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(150));
```

```python
CloudinaryVideo("docs/grocery-store").video(effect="volume:150")
```

```php
use Cloudinary\Transformation\VideoEdit;

(new VideoTag('docs/grocery-store.mp4'))
	->videoEdit(VideoEdit::volume(150));
```

```java
cloudinary.url().transformation(new Transformation().effect("volume:150")).videoTag("docs/grocery-store");
```

```ruby
cl_video_tag("docs/grocery-store", effect: "volume:150")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().Effect("volume:150")).BuildVideoTag("docs/grocery-store")
```

```dart
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(150)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setEffect("volume:150")).generate("docs/grocery-store.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().effect("volume:150")).resourceType("video").generate("docs/grocery-store.mp4");
```

```flutter
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(150)));
```

```kotlin
cloudinary.video {
	publicId("docs/grocery-store.mp4")
	 videoEdit(VideoEdit.volume(150)) 
}.generate()
```

```jquery
$.cloudinary.video("docs/grocery-store", {effect: "volume:150"})
```

```react_native
import { volume } from "@cloudinary/url-gen/actions/videoEdit";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(150));
```

You can also mute audio completely by setting the volume to `mute`:

![Video with muted audio](https://res.cloudinary.com/demo/video/upload/e_volume:mute/docs/grocery-store.mp4 "thumb:c_scale,w_300, muted:false")

```nodejs
cloudinary.video("docs/grocery-store", {effect: "volume:mute"})
```

```react
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { mute } from "@cloudinary/url-gen/qualifiers/volume";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(mute()));
```

```vue
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { mute } from "@cloudinary/url-gen/qualifiers/volume";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(mute()));
```

```angular
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { mute } from "@cloudinary/url-gen/qualifiers/volume";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(mute()));
```

```js
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { mute } from "@cloudinary/url-gen/qualifiers/volume";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(mute()));
```

```python
CloudinaryVideo("docs/grocery-store").video(effect="volume:mute")
```

```php
use Cloudinary\Transformation\VideoEdit;
use Cloudinary\Transformation\Volume;

(new VideoTag('docs/grocery-store.mp4'))
	->videoEdit(VideoEdit::volume(
	Volume::mute()));
```

```java
cloudinary.url().transformation(new Transformation().effect("volume:mute")).videoTag("docs/grocery-store");
```

```ruby
cl_video_tag("docs/grocery-store", effect: "volume:mute")
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation().Effect("volume:mute")).BuildVideoTag("docs/grocery-store")
```

```dart
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(
	Volume.mute())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation().setEffect("volume:mute")).generate("docs/grocery-store.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation().effect("volume:mute")).resourceType("video").generate("docs/grocery-store.mp4");
```

```flutter
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.videoEdit(VideoEdit.volume(
	Volume.mute())));
```

```kotlin
cloudinary.video {
	publicId("docs/grocery-store.mp4")
	 videoEdit(VideoEdit.volume(
	Volume.mute())) 
}.generate()
```

```jquery
$.cloudinary.video("docs/grocery-store", {effect: "volume:mute"})
```

```react_native
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { mute } from "@cloudinary/url-gen/qualifiers/volume";

new CloudinaryVideo("docs/grocery-store.mp4").videoEdit(volume(mute()));
```

> **NOTE**: You can also adjust volume programmatically using the [HTMLMediaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume) volume property:

```js
const obj = document.createElement("audio");
console.log(obj.volume); // 1
obj.volume = 0.75;

```

### Demo: External volume controls using transformations

For users with restricted movement or motor disabilities, you can create larger, more accessible volume controls outside the video player. These external controls use Cloudinary's volume transformations to deliver videos at different volume levels, making them easier to interact with than the built-in player controls. You can see the delivery URL change when you choose a different volume.

  🔉 Quiet (-50%)
  🔊 Normal (100%)
  📢 Loud (200%)
  🔇 Mute
  Volume: Normal (100%)

  Current transformation URL:
  https://res.cloudinary.com/demo/video/upload/docs/grocery-store.mp4

### Video Player volume controls

The [Cloudinary Video Player](cloudinary_video_player) provides built-in volume controls that users can adjust according to their needs. The player includes both a volume button and a volume slider for precise control.

You can customize the volume controls and set default volume levels in your JavaScript:

```js
const player = cloudinary.videoPlayer('my-player', {
  cloudName: 'demo'
});

player.source('docs/grocery-store', {
  transformation: {
    effect: 'volume:-10' // Set the video volume to play 10% quieter
  }
});

player.volume(0.75); // Set the default volume of the player to 75%
```

> **READING**:
>
> * Docs: [Adjust the audio volume](audio_transformations#adjust_the_audio_volume)

> * Docs: [Cloudinary Video Player](cloudinary_video_player)

> * Docs: [Audio normalization](adaptive_bitrate_streaming#normalizing_audio)

## Mixing audio tracks

For users with hearing difficulties or auditory processing disorders, the ability to control the balance between foreground speech and background audio is crucial for accessibility. The WCAG guidelines specify that background sounds should be at least 20 decibels lower than foreground speech content, or users should have the ability to turn off background sounds entirely.

Cloudinary's audio mixing capabilities allow you to layer multiple audio tracks and control their relative volumes, ensuring your content meets accessibility requirements while maintaining audio richness.

To control the volume of different audio tracks, use the [volume](transformation_reference#e_volume) effect in each of the [audio layers](audio_transformations#mixing_audio_tracks).  In this example, the narration is set to a volume of 3dB higher than the original asset (`e_volume:3dB`), and the background wind noise is set to a volume of 18dB lower than the original asset (`e_volume:-18dB`):

![Mixed audio with accessible levels](https://res.cloudinary.com/demo/video/upload/e_volume:3dB/l_audio:docs:wind_norm/e_volume:-18dB/fl_layer_apply/docs/nanotech_norm.mp3 "with_image:false")

```nodejs
cloudinary.url("docs/nanotech_norm.mp3", {resource_type: "video", transformation: [
  {effect: "volume:3dB"},
  {overlay: "audio:docs:wind_norm"},
  {effect: "volume:-18dB"},
  {flags: "layer_apply"}
  ]})
```

```react
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { source } from "@cloudinary/url-gen/actions/overlay";
import { audio } from "@cloudinary/url-gen/qualifiers/source";

new CloudinaryVideo("docs/nanotech_norm.mp3")
  .videoEdit(volume("3dB"))
  .overlay(
    source(
      audio("docs/wind_norm").transformation(
        new Transformation().videoEdit(volume("-18dB"))
      )
    )
  );
```

```vue
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { source } from "@cloudinary/url-gen/actions/overlay";
import { audio } from "@cloudinary/url-gen/qualifiers/source";

new CloudinaryVideo("docs/nanotech_norm.mp3")
  .videoEdit(volume("3dB"))
  .overlay(
    source(
      audio("docs/wind_norm").transformation(
        new Transformation().videoEdit(volume("-18dB"))
      )
    )
  );
```

```angular
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { source } from "@cloudinary/url-gen/actions/overlay";
import { audio } from "@cloudinary/url-gen/qualifiers/source";

new CloudinaryVideo("docs/nanotech_norm.mp3")
  .videoEdit(volume("3dB"))
  .overlay(
    source(
      audio("docs/wind_norm").transformation(
        new Transformation().videoEdit(volume("-18dB"))
      )
    )
  );
```

```js
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { source } from "@cloudinary/url-gen/actions/overlay";
import { audio } from "@cloudinary/url-gen/qualifiers/source";

new CloudinaryVideo("docs/nanotech_norm.mp3")
  .videoEdit(volume("3dB"))
  .overlay(
    source(
      audio("docs/wind_norm").transformation(
        new Transformation().videoEdit(volume("-18dB"))
      )
    )
  );
```

```python
cloudinary.utils.cloudinary_url("docs/nanotech_norm.mp3", resource_type="video", transformation=[
  {'effect': "volume:3dB"},
  {'overlay': "audio:docs:wind_norm"},
  {'effect': "volume:-18dB"},
  {'flags': "layer_apply"}
  ])
```

```php
use Cloudinary\Transformation\VideoEdit;
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;

(new VideoTag('docs/nanotech_norm.mp3'))
	->videoEdit(VideoEdit::volume("3dB"))
	->overlay(Overlay::source(
	Source::audio("docs/wind_norm")
	->transformation((new Transformation())
	->videoEdit(VideoEdit::volume("-18dB")))
	));
```

```java
cloudinary.url().transformation(new Transformation()
  .effect("volume:3dB").chain()
  .overlay(new Layer().publicId("audio:docs:wind_norm")).chain()
  .effect("volume:-18dB").chain()
  .flags("layer_apply")).resourceType("video").generate("docs/nanotech_norm.mp3")
```

```ruby
cloudinary_url("docs/nanotech_norm.mp3", resource_type: "video", transformation: [
  {effect: "volume:3dB"},
  {overlay: "audio:docs:wind_norm"},
  {effect: "volume:-18dB"},
  {flags: "layer_apply"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Effect("volume:3dB").Chain()
  .Overlay(new Layer().PublicId("audio:docs:wind_norm")).Chain()
  .Effect("volume:-18dB").Chain()
  .Flags("layer_apply")).BuildUrl("docs/nanotech_norm.mp3")
```

```dart
cloudinary.video('docs/nanotech_norm.mp3').transformation(Transformation()
	.videoEdit(VideoEdit.volume("3dB"))
	.overlay(Overlay.source(
	Source.audio("docs/wind_norm")
	.transformation(new Transformation()
	.videoEdit(VideoEdit.volume("-18dB")))
	)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setEffect("volume:3dB").chain()
  .setOverlay("audio:docs:wind_norm").chain()
  .setEffect("volume:-18dB").chain()
  .setFlags("layer_apply")).generate("docs/nanotech_norm.mp3")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .effect("volume:3dB").chain()
  .overlay(new Layer().publicId("audio:docs:wind_norm")).chain()
  .effect("volume:-18dB").chain()
  .flags("layer_apply")).resourceType("video").generate("docs/nanotech_norm.mp3");
```

```flutter
cloudinary.video('docs/nanotech_norm.mp3').transformation(Transformation()
	.videoEdit(VideoEdit.volume("3dB"))
	.overlay(Overlay.source(
	Source.audio("docs/wind_norm")
	.transformation(new Transformation()
	.videoEdit(VideoEdit.volume("-18dB")))
	)));
```

```kotlin
cloudinary.video {
	publicId("docs/nanotech_norm.mp3")
	 videoEdit(VideoEdit.volume("3dB"))
	 overlay(Overlay.source(
	Source.audio("docs/wind_norm") {
	 transformation(Transformation {
	 videoEdit(VideoEdit.volume("-18dB")) })
	 })) 
}.generate()
```

```jquery
$.cloudinary.url("docs/nanotech_norm.mp3", {resource_type: "video", transformation: [
  {effect: "volume:3dB"},
  {overlay: new cloudinary.Layer().publicId("audio:docs:wind_norm")},
  {effect: "volume:-18dB"},
  {flags: "layer_apply"}
  ]})
```

```react_native
import { volume } from "@cloudinary/url-gen/actions/videoEdit";
import { source } from "@cloudinary/url-gen/actions/overlay";
import { audio } from "@cloudinary/url-gen/qualifiers/source";

new CloudinaryVideo("docs/nanotech_norm.mp3")
  .videoEdit(volume("3dB"))
  .overlay(
    source(
      audio("docs/wind_norm").transformation(
        new Transformation().videoEdit(volume("-18dB"))
      )
    )
  );
```

### Audio normalization for consistent levels

Before mixing audio tracks, it helps to normalize them to consistent baseline levels. Different audio recordings often have varying baseline volumes, which can make it difficult to achieve predictable dB differences for accessibility compliance.

To normalize your audio files before uploading them to Cloudinary, you can use audio processing tools, such as FFmpeg. 

For example, normalize the audio file nantech.mp3 to -16 LUFS:

```bash
ffmpeg -i nanotech.mp3 -af loudnorm=I=-16:LRA=11:TP=-1.5 nanotech_normalized.mp3
```

This ensures that when you apply `-20dB` or `-25dB` adjustments in Cloudinary, you get the exact dB separation needed for WCAG compliance.

### Interactive audio mixing demo

This demo shows how Cloudinary can mix a primary audio track (nanotechnology narration) with a background audio layer (wind sounds). Use the controls to adjust the volume levels and observe how the dB difference affects accessibility:

Your browser doesn't support the audio element.

  
    
    
      🎙️ Narration (Foreground)
      Volume: +3 dB
      
      Range: -20 dB to +20 dB
    
    
    
      🌬️ Wind (Background)
      Volume: -18 dB
      
      Range: -50 dB to 0 dB
    
    
  
  
  
    
      dB Difference:
      21 dB
    
    
      ✅ WCAG Compliant: Background is 21 dB lower than foreground (exceeds 20 dB requirement)
    
  
    
  
    📢 WCAG Compliant (25+ dB)
    ⚖️ Balanced Mix
    🔇 No Background
  

  Current transformation URL:
  https://res.cloudinary.com/demo/video/upload/e_volume:3dB/l_audio:docs:wind_norm/e_volume:-18dB/fl_layer_apply/docs/nanotech_norm.mp3

### User-controlled audio track levels

Similar to the above demo, you could provide controls in your application to let the user decide on the levels of each track to meet their needs.  Here's some example React code that you could use:

```react
import React, { useState } from 'react';

const AccessibleAudioPlayer = ({ baseTrack, backgroundTrack }) => {
  const [speechLevel, setSpeechLevel] = useState(0);
  const [backgroundLevel, setBackgroundLevel] = useState(-20);
  const [showBackground, setShowBackground] = useState(true);
  
  // Calculate if mix meets WCAG requirements
  const dbDifference = speechLevel - backgroundLevel;
  const isWCAGCompliant = !showBackground || dbDifference >= 20;
  
  // Generate Cloudinary URL based on settings
  const generateAudioUrl = () => {
    if (!showBackground) {
      return `https://res.cloudinary.com/demo/video/upload/e_volume:${speechLevel}dB/${baseTrack}_norm.mp3`;
    }
    
    const speechVolume = `e_volume:${speechLevel}dB/`;
    const bgVolume = backgroundLevel <= -40 ? 'e_volume:mute/' : `e_volume:${backgroundLevel}dB/`;
    
    // Using normalized audio files for predictable dB separation
    return `https://res.cloudinary.com/demo/video/upload/${speechVolume}l_audio:${backgroundTrack}_norm/${bgVolume}fl_layer_apply/${baseTrack}_norm.mp3`;
  };
  
  return (
    <div className="accessible-audio-player">
      <audio controls src={generateAudioUrl()} />
      
      <div className="audio-controls">
        <div className="control-group">
          <label>Speech Volume: {speechLevel} dB</label>
          <input 
            type="range" 
            min="-10" 
            max="10" 
            value={speechLevel}
            onChange={(e) => setSpeechLevel(parseInt(e.target.value))}
          />
        </div>
        
        <div className="control-group">
          <label>
            <input 
              type="checkbox" 
              checked={showBackground}
              onChange={(e) => setShowBackground(e.target.checked)}
            />
            Enable Background Audio
          </label>
          
          {showBackground && (
            <>
              <label>Background Volume: {backgroundLevel} dB</label>
              <input 
                type="range" 
                min="-40" 
                max="0" 
                value={backgroundLevel}
                onChange={(e) => setBackgroundLevel(parseInt(e.target.value))}
              />
            </>
          )}
        </div>
        
        <div className={`accessibility-indicator ${isWCAGCompliant ? 'compliant' : 'non-compliant'}`}>
          {isWCAGCompliant ? 
            '✅ WCAG Compliant' : 
            `⚠️ Needs ${20 - dbDifference} dB more separation`
          }
        </div>
      </div>
    </div>
  );
};

export default AccessibleAudioPlayer;
```
> **TIP**:
>
> :title=Best practices for accessible audio mixing

> * **Always provide a no-background option**: Some users need complete silence behind speech

> * **Maintain 20+ dB separation**: When background audio is present, ensure it's at least 20 dB lower

> * **Test with real users**: Audio perception varies greatly between individuals

> * **Consider frequency content**: Low-frequency background sounds are less distracting than mid-range frequencies

> * **Provide visual indicators**: Show users the current dB levels and compliance status

> * **Use consistent levels**: Maintain the same audio balance throughout your content

> **READING**:
>
> * Docs: [Mixing audio tracks](audio_transformations#mixing_audio_tracks)

> * Docs: [Audio transformations](audio_transformations)
