Has IOS13 broken <audio> tags used as audio buffers connected to the audio context? - web-audio-api

We are currently developing a website that allows users to play simple audio tags connected to the audiocontext. We are aware of technical issues with IOS such as playback initiated by user gestures. Everything is working fine up to IOS12.
Now that IOS13 is out, nothing works anymore.
It works on all desktops, android and IOS up to IOS13.
Any idea on what is going on?
There are no error messages in the console when debugging with Safari on Desktop connected to the iphone.
https://codepen.io/gchad/pen/WNNvzzd
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<body>
<div>
<h1>Play Audio Tag connected to audio context</h1>
<div id="playbutton" style="width:100px; height:100px; background:blue; color:white; margin:auto; text-align: center; font-size: 30px; cursor: pointer;">
Play
</div>
<audio id="myPlayer" crossorigin="anonymous" >
<source src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/858/outfoxing.mp3"/>
<!--http://commondatastorage.googleapis.com/codeskulptor-assets/week7-brrring.m4a-->
</audio>
</div>
<script>
var player = document.getElementById('myPlayer'),
playbutton = document.getElementById('playbutton'),
playStatus = 'paused';
var audioContext = new(window.AudioContext || window.webkitAudioContext)();
var audioSource = audioContext.createMediaElementSource(player);
audioSource.connect(audioContext.destination);
playbutton.addEventListener('click',function(ev){
if( playStatus == 'paused'){
audioContext.resume();
player.play();
playbutton.innerHTML = "Pause";
playStatus = 'isPlaying';
} else {
player.pause();
playbutton.innerHTML = "Play";
playStatus = 'paused';
}
});
</script>
</body>

This issue was mistakenly reported as fixed in iOS 13.3.1 (January 28, 2020). Nevertheless, as anyone can read from this WebKit bug report 203435, the problem is still there as of April 7, 2020, the release date of iOS 13.4.1.
The bug report doesn't provide any further information in regards to the estimated date this bug is going to be fixed. Sadly, 80% of iOS users (about 14% of the total mobile market, according to Statcounter) have been mistakenly incapacitated from using WebAudio on their devices for months, now.
What makes things worse for us developers is that Safari doesn't report any error. Thus, even trying to imagine a fallback is not possible or very hard, anyway.

Unfortunately, AudioContext.createMediaElementSource has been broken since the release of iOS 13. The bug was reported to be fixed in Safari Technology Preview 99: https://bugs.webkit.org/show_bug.cgi?id=203435, but it's still broken in the recent release of iOS, so a new bug report was filed which can be found here: https://bugs.webkit.org/show_bug.cgi?id=211394

Related

Flutter web with canvaskit on iOS 15 beta

I decided to try iOS15 beta and to my surprise a Flutter Web application am testing will not run with canvas kit renderer (it runs perfectly fine with the html renderer). The screen appears blank and I get no errors in Safari's developer console. Does anybody else have this issue? Any clues to what might be happening? I don't even know if this is a Flutter bug uncovered by some specificity about iOS15 or if it is an actual iOS15 bug. The native app runs perfectly well. The web app with canvas kit also runs perfectly well on every other browser I threw it at, except, obviously for Internet Explorer (this includes Android with Chrome, Android with Firefox, several browsers on Linux, several browsers on Windows, and even several browsers on iOS 14.x. On the other hand, I am running other web assembly apps on iOS 15.
Recently it was discovered that the cause of this issue was WebGL 2.0 on Safari/WebKit (Source). This issue should be resolved if you are currently running Flutter 2.7 in the stable channel.
Each source link in this answer leads you to the actual comments and respective authors of these workarounds at https://github.com/flutter/flutter/issues/89655
Best Solution
Since disabling WebGL 2.0 through Safari's Experimental Features will only affect your own computer AND switching to the master channel is not a viable solution for apps in production, you'll need to tell the browser that Flutter's engine does not support WebGL 2.0 on Safari (Source). This snippet of code needs to be called in the head tag before your main.dart.js is called in the index.html file.
<!-- Apple WebGL 2.0 fix (https://github.com/flutter/flutter/issues/89655#issuecomment-919685843) -->
<!-- TODO: Remove when https://github.com/flutter/engine/pull/29038 is merged to stable -->
<script src="https://unpkg.com/platform#1.3.5/platform.js"></script>
<script type="text/javascript">
let isSafari = /^((?!chrome|android).)*safari/i.test(platform.ua);
if (isSafari) {
HTMLCanvasElement.prototype.getContext = function (orig) {
return function (type) {
return type !== "webgl2" ? orig.apply(this, arguments) : null
}
}(HTMLCanvasElement.prototype.getContext)
}
</script>
TextStyle Workaround
The previously proposed solution to this issue was to set a slightly transparent underline for all text in your app by using the DefaultTextStyle widget. (Source)
TextStyle(
decoration: TextDecoration.underline,
decorationColor: Colors.white.withOpacity(0.01),
)
CanvasKit Workaround
If these solutions did not help, you can also try disabling CanvasKit as a last resort. (Source)
<head>
<!-- * Safari Renderer * -->
<script src="https://unpkg.com/platform#1.3.5/platform.js"></script>
<script>
if (platform.name.toLowerCase() == "safari" && parseInt(platform.version.split(".")[0]) >= 15) {
window.flutterWebRenderer = "html";
} else {
// Optional, default is `auto`
window.flutterWebRenderer = "canvaskit";
}
</script>
...
</head>
<body>
...
<!-- * Initialize Website * -->
<script src="main.dart.js" type="application/javascript"></script>
</body>
For this workaround to work you will need to set the web-renderer to auto when running or building the project in the terminal:
flutter build web --release --web-renderer auto
You might have to replace some widgets that only work nicely with the CanvasKit renderer since this workaround will force Safari 15 to use the HTML renderer:
import 'dart:js' as js;
// ** //
bool isCanvasKit() => js.context['flutterCanvasKit'] != null;
Widget dynamicText = isCanvasKit()
? Text("CanvasKit")
: Text("HTML");
If any of these solutions fixed your issue, please consider marking it as accepted.
The issue is with html renderer. Try using canvaskit for Safari.
<script src="https://unpkg.com/platform#1.3.5/platform.js"></script>
<script type="text/javascript">
if (platform.name.toLowerCase() == "safari" ) {
window.flutterWebRenderer = "canvaskit";
} else {
window.flutterWebRenderer = "html";
}
I have found this issue: https://github.com/flutter/flutter/issues/89655
Right now I fixed with this code:
<head>
<!-- * Safari Renderer * -->
<script src="https://unpkg.com/platform#1.3.5/platform.js"></script>
<script>
if (platform.name.toLowerCase() == "safari" && parseInt(platform.version.split(".")[0]) >= 15) {
window.flutterWebRenderer = "html";
} else {
// Optional, default is `auto`
window.flutterWebRenderer = "canvaskit";
}
</script>
...
</head>
<body>
...
<!-- * Initialize Website * -->
<script src="main.dart.js" type="application/javascript"></script>
</body>
Then when building your app, use:
flutter build web --release --web-renderer auto
Another workaround is to disable WebGL 2.0 on the iPhone (Settings/Safari), works fine too.
I've found a workaround and posted under the GitHub issue. Let me also post it here:
Websites that contain Chinese or Japanese characters currently crash on iOS 15 iPad and iOS 15 iPhone; they work fine on iOS 14 iPad, and other platforms (Android, macOS).
Also, neither Safari nor Chrome works on iOS 15. They both show a blank screen without any error messages.
I've tested above using html:
flutter build web --web-renderer html --release
A temp workaround so far is to add an "almost transparent" underline to Texts:
TextStyle(
decoration: TextDecoration.underline,
decorationColor: Colors.white.withOpacity(0.01),
)
Passing an actual transparent color causes the underline to render in black for me, so I'm just using a very faint color here.
I'm using a DefaultTextStyle widget to modify it for most texts, and manually adding it to a few particular ones that didn't cover. During debugging, I made the underline color visible, so I can observe which texts do not have underline yet. Once I make sure they all have underline, I turn the color off for release mode.
This issue was recently fixed in this merge request and is now on the master channel. It will most likely land on more stable channels in the coming days.
See these instructions for switching channel and then rebuild your application with your new flutter version and it should work.

Can I create a game for webgl without the Unity logo?

Can I create a game for webgl without the Unity logo when I download and without title "Unity webGL"?
. example
According to the docs you need a Pro license to remove the splash screen. (the logo in the middle of the screen)
As for the frame around the game that's easy to change, just change the HTML as documented here. You can choose either one of the defaults or create your own template.
According to those docs you create folder in Assets called WebGLTemplates and inside that create a new folder for your template like BetterTemplate. Inside that put an index.html file and any other images, css, JavaScript files you want included with your game.
The index.html could look something like this
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>%UNITY_WEB_NAME%</title>
<style>
body { margin: 0; }
#gameContainer { width: 100vw; height: 100vh; }
canvas { width: 100%; height: 100%; }
</style>
<script src="Build/UnityLoader.js"></script>
<script>
var gameInstance = UnityLoader.instantiate("gameContainer", "Build/dist.json");
</script>
</head>
<body>
<div id="gameContainer"></div>
</body>
</html>
Then you pick Edit->Project Settings->Player from the menus and under the WebGL tab choose your template
Here's an example that provides a custom logo. The part that's not removable without a Pro license is the "Made with Unity" that appears just before the game starts.
With the personal license you are unable to legally remove the Unity splash screen. You need the Plus or Pro license. Plus costs $35 a month, Pro is $125 a month.
The majority of the features of Plus and Pro are not needed for smaller projects and with no hurt your development. All engine features are the same across the board, so you can always develop you game with a personal license.
When it comes time to launch you can buy Plus or Pro and remove the splash screen and take advantage of the performance reporting and analytics features that come with it.

HTML5 Video in iPad not working after DOM changes

Here is a script that appends the markup for an html5 video to the DOM:
document.body.innerHTML = '<video id="video" controls="controls" src="http://mirror.cessen.com/blender.org/peach/trailer/trailer_iphone.m4v" type="video/mp4"></video>';
var el = document.getElementById('video');
document.body.removeChild(el);
document.body.appendChild(el);
jsfiddle demo:
http://jsfiddle.net/h8RLS/2/
This works in all browsers tested, except for Safari on iOS. In iOS, when the HTMLVideoElement is re-appended to the DOM, it is no longer playable.
Has anyone else resolved or encountered this issue?
I don't have an iPad but could reproduce your issue on an iPhone. This seems to be a Webkit error but it can be bypassed easily by changing the src attribute of the video - I hope this is sufficient for your scenario. You can see a working demo here:
http://vidhtml5.appspot.com/jsembed.html
This is the code:
var el = document.getElementById('video');
el.src= "http://mirror.cessen.com/blender.org/peach/trailer/trailer_iphone.m4v";
el.load();
I had the same problem, and I found a workaround using a timer (I'm using jQuery here).
var v = $('#videoID');
v.appendTo( $('#toDivID') );
var timer = setInterval( function() {
clearInterval( timer );
v[0].load();
v[0].play();
}, 200 );
I've only tested it on the iPad2 on iOS 6.1.
You can include two 'source' tags for your video. I've done this on a site and it works great.
<video class="video" controls="controls" id="video1">
<source type="video/mp4" src="demo.mp4">
<source type="video/webm" src="demo.webm">
</video>

Autoplay video in PhoneGap

I have created a minimal PhoneGap app that has just this in the index.html:
<!-- ... -->
<body>
<video src="test.m4v" autoplay onerror="alert('Error')"></video>
</body>
In the PhoneGap.plist I have set MediaPlaybackRequiresUserAction to NO.
Yet I still cannot get the video to autoplay when the page loads. I have tried different ways of scripting it but to no avail.
Does anybody have a clue what I'm doing wrong?
Solved it. Turned out to be a bug in PhoneGap 1.3 which was fixed in version 1.4 released yesterday(!).
From the release notes:
Fixed CB-42 – MediaPlaybackRequiresUserAction can now be set to NO
AutoPlay attribute work in ios :
<video src="test.m4v" autoplay="autoplay"></video>
Given this line autoplay function
"autoplay" attribute will not work in iOS so you need to use JavaScript to get it to play.
Here is some sample code:
var video = document.getElementById('someVideoId');
video.play();

Using HTML5 on iPhone - cannot pause

I was wondering whether anyone has tried to use the new tag that comes with HTML5 on the iPhone.
Specifically, I didn't manage to make the pause() command to work.
Below is a portion of the page. As you can see, I'm trying to pause the video 10sec after it started. It works on Safari on a Mac btw.
Has anyone managed to make this work?
<head>
<javascript language="JavaScript">
function timeUpdate()
{
var myVideo = document.getElementsByTagName('video')[0];
var time = myVideo.currentTime;
if (time > 10)
{
myVideo.pause();
}
}
function addListeners()
{
var myVideo = document.getElementsByTagName('video')[0];
myVideo.addEventListener('timeupdate',timeUpdate,false);
}
</script>
</head>
<body onload="addListeners()">
<video controls src="resources/bb_poor_cinderella_512kb.mp4"
poster="resources/background.png">
Video tag not supported!
</video>
</body>
Thanks,
Ariel
This code is invalid:
<javascript language="JavaScript">
There is no HTML tag called <Javascript>
To set the language to javascript, you should use this:
<script type="text/javascript">
// Code here
</script>
Note that the language attribute is deprecated according to the W3C standard (http://www.w3.org/TR/REC-html40/interact/scripts.html) so you should use type rather than language.
As far as i know iPhone wont let you play video inline in the mobile safari browser.
So pausing wont work ofcourse. iPhone open the video in an external videoplayer, you dont have control over browser features, so the pausing doenst work.
You should use <script>, not <javascript language="JavaScript">.