ChatGPT解决这个技术问题 Extra ChatGPT

Autoplay audio files on an iPad with HTML5

I'm trying to get an audio file to autoplay in Safari on an iPad. If I go to the page using Safari on my Mac, it's fine. On the iPad, autoplay does not work.

This is not an answer but just an observation. When I put WireShark on my connection to the iPad I noticed that it wouldn't autoplay but is still downloaded the Wave file anyway. The first HTTP Get just asks for the first 2 bytes of the file but then the iPad asks for the rest of the Wave file in some more Get requests. What's even stranger is when you click on the 'Play' button of the Audio component the iPad reloads the Wave file again.

R
Rick M

I would like to also emphasize that the reason you cannot do this is a business decision that Apple made, not a technical decision. To wit, there was no rational technical justification for Apple to disable sound from web apps on the iPod Touch. That is a WiFi device only, not a phone that may incur expensive bandwidth charges, so that argument has zero merit for that device. They may say they are helping with WiFi network management, but any issues with bandwidth on my WiFi network is my concern, not Apple's.

Also, if what they really cared about was preventing unwanted, excessive bandwidth consumption, they would provide a setting to allow users to opt-in to web apps sounds. Also, they would do something to restrict web sites from consuming equivalent bandwidth by other means. But there are no such restrictions. A web site can download huge files in the background over and over and Apple could care less about that. And finally, I believe the sounds can be downloaded anyway, so NO BANDWIDTH IS ACTUALLY SAVED! Apple just does not allow them to play automatically without user interaction, making them unusable for games, which of course is their real intent.

Apple blocked sound because they started to notice that HTML5 apps can be just as capable as native apps, if not more so. If you want sound in Web Apps you need to lobby Apple to stop being anti-competitive like Microsoft. There is no technical problem that can be fixed here.


Is it not the same for Android?
@Rune Jeppesen No. I have a PhoneGap/Cordova app which has an audio player and it works perfectly on Android. The only reason why I've reached this topic here in StackOverflow is iOS' restrictions regarding audio playback.
Now it Chrome for Android and for desktop have a policy similar to iOS
a
andrewb

UPDATE: This is a hack and it's not working anymore on IOS 4.X and above. This one worked on IOS 3.2.X.

It's not true. Apple doesn't want to autoplay video and audio on IPad because of the high amout of traffic you can use on mobile networks. I wouldn't use autoplay for online content. For Offline HTML sites it's a great feature and thats what I've used it for.

Here is a "javascript fake click" solution: http://www.roblaplaca.com/examples/html5AutoPlay/

Copy & Pasted Code from the site:

<script type="text/javascript"> 
        function fakeClick(fn) {
            var $a = $('<a href="#" id="fakeClick"></a>');
                $a.bind("click", function(e) {
                    e.preventDefault();
                    fn();
                });

            $("body").append($a);

            var evt, 
                el = $("#fakeClick").get(0);

            if (document.createEvent) {
                evt = document.createEvent("MouseEvents");
                if (evt.initMouseEvent) {
                    evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                    el.dispatchEvent(evt);
                }
            }

            $(el).remove();
        }

        $(function() {
            var video = $("#someVideo").get(0);

            fakeClick(function() {
                video.play();
            });
        });

        </script> 

This is not my source. I've found this some time ago and tested the code on an IPad and IPhone with IOS 3.2.X.


Here's another workaround: codeblog.co/getting-autoplay-working-on-ios I just verified that this works on iPad with iOS 3.2.
Don't waste your time with this as it no longer works with iOS 4+
k
kaleazy

Apple annoyingly rejects many HTML5 web standards on their iOS devices, for a variety of business reasons. Ultimately, you can't pre-load or auto-play sound files before a touch event, it only plays one sound at a time, and it doesn't support Ogg/Vorbis. However, I did find one nifty workaround to let you have a little more control over the audio.

<audio id="soundHandle" style="display:none;"></audio>

<script type="text/javascript">

var soundHandle = document.getElementById('soundHandle');

$(document).ready(function() {
    addEventListener('touchstart', function (e) {
        soundHandle.src = 'audio.mp3';
        soundHandle.loop = true;
        soundHandle.play();
        soundHandle.pause();
    });
});

</script>

Basically, you start playing the audio file on the very first touch event, then you pause it immediately. Now, you can use the soundHandle.play() and soundHandle.pause() commands throughout your Javascript and control the audio without touch events. If you can time it perfectly, just have the pause come in right after the sound is over. Then next time you play it again, it will loop back to the beginning. This won't resolve all the mess Apple has made here, but it's one solution.


I haven't tried this yet, but if it actually works, this is brilliant.
Suprised that more people aren't interested in this.
Is this still working? I can seem to be able to get this to function...
@MastaBaba This should be the accepted answer. Why? It doesn't answer the question, since this is what OP asks for: I'm trying to get an audio file to autoplay in Safari and this answer doesn't help with autoplay.
D
David Gouldin

As of iOS 4.2.1, neither the fake click nor the .load() trick will work to autoplay audio on any iOS device. The only option I know of is to have the user actually perform a click action and begin playback in the click event handler without wrapping the .play() call in anything asynchronous (ajax, setTimeout, etc).

Someone please tell me if I'm mistaken. I had working loopholes for both iPad and iPhone before the most recent update, and all of them look like they've been closed.


I can verify that I had code working to autoplay audio without user intervention on both iPad and iPod touch, pre 4.2.1. I just updated my iPad to 4.2.1 today (in the middle of testing my audio preloader as it happens), and watched in horror as it simply stopped working.
On <video> with 4.2.1, I have verified that as long as the .load() then .play() come within a synchronous click/tap handler, it will work. Otherwise, it fails.
It seems the programmatic control of media (audio and video) elements is enabled after user interaction per media element. I.e. if you have audio element A and B and you begin playback of A via code within scope of a click (or touch) event handler, it works. But that does not mean that you can later begin playback of B outside the scope of a click event handler. Treat media elements in iOS as a singleton and swap sources on one instance rather than multiplying instances by sources.
J
Jacob Mouka

I confirm that the audio isn't working as described (at least on iPad running 4.3.5). The specific issue is the audio won't load in an asynchronous method (ajax, timer event, etc) but it will play if it was preloaded. The problem is the load has to be on a user-triggered event. So if you can have a button for the user to initiate the playing you can do something like:

function initSounds() {
    window.sounds = new Object();
    var sound = new Audio('assets/sounds/clap.mp3');
    sound.load();
    window.sounds['clap.mp3'] = sound;
}

Then to play it, eg in an ajax request, you can do

function doSomething() {
    $.post('testReply.php',function(data){
        window.sounds['clap.mp3'].play();
    }); 
}

Not the greatest solution, but it may help, especially knowing the culprit is the load function in a non-user-triggered event.

Edit: I found Apple's explanation, and it affects iOS 4+: http://developer.apple.com/library/safari/#documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html


This is Gold answer. You can fill sounds object with multiple sounds. And after ajax call on success/error cases play any you want. Works for me on every device! Big tnx!!!
B
Brian Brown

Try calling the .load() method before the .play() method on the audio or video tag... which will be HTMLAudioElement or HTMLVideoElement respectively. That was the only way it would work on the iPad for me!


According to the apple developer documents neither .load nor .play will work except when triggered by a user.
A
Andrew

Autoplay doesn't work on the iPad or iPhone for either the video or the audio tags. This is a restriction set in place by Apple to save the users bandwidth.


A
Adrian

It seems to me that the answer to this question is (at least now) clearly documented on the Safari HTML5 docs:

User Control of Downloads Over Cellular Networks

In Safari on iOS (for all devices, including iPad), where the user may be on a cellular network and be charged per data unit, preload and autoplay are disabled. No data is loaded until the user initiates it. This means the JavaScript play() and load() methods are also inactive until the user initiates playback, unless the play() or load() method is triggered by user action. In other words, a user-initiated Play button works, but an onLoad="play()" event does not.

This plays the movie: <input type="button" value="Play" onClick="document.myMovie.play()">

This does nothing on iOS: <body onLoad="document.myMovie.play()">


J
Jon Jardine

Have puzzled over this whilst developing a quick prototype web app under iOS4.2 (dev build). Solution is actually quite simple. Note that you can't seem to already have the tag in your HTML page, you actually need to insert the tag into the document dynamically (note this example uses Prototype 1.7 for some extra Javascript snazziness):

this.soundFile = new Element("audio", {id: "audio-1", src: "audio-1.mp3", controls: ""});
document.body.appendChild(this.soundFile);
this.soundFile.load();
this.soundFile.play();

As you've not set a controller, there shouldn't be any need to do anything tricksy with CSS to hide it / position it off-screen.

This seems to work perfectly.


b
bmidgley

Apple does not support the standard completely, but there is a workaround. Their justification is cellular network congestion, maybe because you'll land on pages that play random audio. This behavior doesn't change when a device goes on wifi, maybe for consistency. By the way, those pages are usually a bad idea anyway. You should not be trying to put a soundtrack on every web page. That's just wrong. :)

html5 audio will play if it is started as the result of a user action. Loading a page does not count. So you need to restructure your web app to be an all-in-one-page app. Instead of a link that opens a page that plays audio, you need that link to play it on the current page, without a page change. This "user interaction" rule applies to the html5 methods you can call on an audio or video element. The calls return without any effect if they are fired automatically on page load, but they work when called from event handlers.


C
Cameron

If you create an Audio element using:

var a = new Audio("my_audio_file.wav");

And add a suspend event listener via:

a.addEventListener("suspend", function () {console.log('suspended')}, false);

And then load the file into mobile Safari (iPad or iPhone), you'll see the 'suspended' get logged in the developer console. According to the HTML5 spec, this means, "The user agent is intentionally not currently fetching media data, but does not have the entire media resource downloaded."

Calling a subsequent a.load(), testing for the "canplay" event and then using a.play() seems like a suitable method for auto triggering the sound.


I tried this but it doesn't seem to work. Any update? sandbox.coolaj86.info/html5-audio-tag-ios4.html
L
Luke Stanley

My solution is trigger from a real touch event in a prior menu. They don't force you to use a specific player interface of course. For my purposes, this works well. If you don't have an existing interface to use, afaik you're buggered. Maybe you could try tilt events or something...


A
Adrian

Works with jQuery, tested on Ipad v.5.1.1

$('video').get(0).play();

You have to append/remove the video element from the page.


Does not work on iPad 1 iOS 5.1.1 ... although does work on iPod 6.0 and iPhone
A
Andrew Hancox

I handled this by attaching an event handler for all the events for which you are allowed to trigger audio to the body element which triggers any html audio elements with autoplay to play once.

var mobile = /iPad|iPhone|iPod|android/.test(navigator.userAgent) && !window.MSStream;
if (mobile) {
    $('body').on('touchstart click doubleclick keydown', function() {
        $("audio[autoplay='autoplay']").each(
            function(){
                this.play();
                this.removeAttribute('autoplay');
            });
    });
}

N
Nisse Engström

This seems to work:

<html>
<title>
iPad Sound Test  - Auto Play
</title>
</head>
<body>
<audio id="audio" src="mp3test.mp3" controls="controls" loop="loop">
</audio>
<script type="text/javascript"> 
    window.onload = function() {
        var audioPlayer = document.getElementById("audio");
        audioPlayer.load();
        audioPlayer.play();
    };
    </script> 

</body>
</html>

See it in action here: http://www.johncoles.co.uk/ipad/test/1.html (Archived)

As of iOS 4.2 this no-longer works. Sorry.


@NisseEngström Seems to me that the mp3 file isn't archived as well, so this the archive link edit is quite moot.
@FrankerZ: There's an mp3 link? I missed that. Thanks.