Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <h1>Intro</h1>
<p>With HTML5 it's pretty straight-forward to play a sound from a javascript function. However, iOS does not always allow that. Safari on iOS only plays sounds from functions that are directly called from user interactions, like a button click. The solution to that is using the web audio API. This is still not straight-forward though. In order to play a sound programmatically on iOS Safari, the so-called audio context needs to be unlocked first. That unlocking has to be done, again, by playing a sound as a reaction to user interaction. Luckily, the audio context can be unlocked once and then forever be used to play sounds. So any touch event on the screen can be used for that. Or, as in this example, by pressing the unmute button. If you don't see an unmute button: you're lucky. You're using a browser that doesn't require unlocking!</p>
<h1>Demo</h1>
<p>If you are on iOS, then you should not hear any sounds playing yet and initially there should be an unmute button here:</p>
<button id="unmute">Unmute</button>
<p>If it is hidden, the audio context is unlocked and a sound is playing.</p>
<p>Manually starting a sound to play should always work in all browsers with web audio:</p>
<button id="play">Play</button>
              
            
!

CSS

              
                body{
    font-family: sans-serif;
    line-height: 1.6;
}

button{
    padding: 10px 20px;
    border-radius: 20px;
}
              
            
!

JS

              
                
  (function () {

    // Check if the browser supports web audio. Safari wants a prefix.
    if ('AudioContext' in window || 'webkitAudioContext' in window) {

      //////////////////////////////////////////////////
      // Here's the part for just playing an audio file.
      //////////////////////////////////////////////////
      var play = function play(audioBuffer) {
        var source = context.createBufferSource();
        source.buffer = audioBuffer;
        source.connect(context.destination);
        source.start();
      };

      var URL = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/Yodel_Sound_Effect.mp3';
      var AudioContext = window.AudioContext || window.webkitAudioContext;
      var context = new AudioContext(); // Make it crossbrowser
      var gainNode = context.createGain();
      gainNode.gain.value = 1; // set volume to 100%
      var playButton = document.querySelector('#play');
      var yodelBuffer = void 0;

      // The Promise-based syntax for BaseAudioContext.decodeAudioData() is not supported in Safari(Webkit).
      window.fetch(URL)
        .then(response => response.arrayBuffer())
        .then(arrayBuffer => context.decodeAudioData(arrayBuffer,
           audioBuffer => {
              yodelBuffer = audioBuffer;
            },
            error =>
              console.error(error)
          ))

      playButton.onclick = function () {
        return play(yodelBuffer);
      };

      // Play the file every 2 seconds. You won't hear it in iOS until the audio context is unlocked.
      window.setInterval(function(){
        play(yodelBuffer);
      }, 5000);


      //////////////////////////////////////////////////
      // Here's the part for unlocking the audio context, probably for iOS only
      //////////////////////////////////////////////////

      // From https://paulbakaus.com/tutorials/html5/web-audio-on-ios/
      // "The only way to unmute the Web Audio context is to call noteOn() right after a user interaction. This can be a click or any of the touch events (AFAIK – I only tested click and touchstart)."
      
      var unmute = document.getElementById('unmute');
      unmute.addEventListener('click', unlock);

      function unlock() {
        console.log("unlocking")
        // create empty buffer and play it
        var buffer = context.createBuffer(1, 1, 22050);
        var source = context.createBufferSource();
        source.buffer = buffer;
        source.connect(context.destination);

        // play the file. noteOn is the older version of start()
        source.start ? source.start(0) : source.noteOn(0);

        // by checking the play state after some time, we know if we're really unlocked
        setTimeout(function() {
          if((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
            // Hide the unmute button if the context is unlocked.
            unmute.style.display = "none";
          }
        }, 0);
      }

      // Try to unlock, so the unmute is hidden when not necessary (in most browsers).
      unlock();
    }
  }
)();
              
            
!
999px

Console