The MDN docs on video.play detail how it returns a Promise in modern browsers and that it will be rejected if the video cannot be played.
In my tests, I have found that this works well for when a video is not played, because of autoplay policies issues, such as not being muted, however, I am also seeing that it does not get rejected if the URL for the video 404s or is of the wrong content type.
Is there any way to catch loading errors like this? Or would this be a feature request for Chrome, Firefox, Safari, and others?
I have a sample codepen here: https://codepen.io/mrcoles/pen/abzJPaQ
In it I generate videos based on the following configs:
const ROWS = [
{
title: 'Video URL is good',
src: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
muted: true
},
{
title: 'Video URL is a 404',
src: '/DOES-NOT-EXIST.mp4',
muted: true
},
{
title: 'Video URL is a bad source type (HTML page instead of video)',
src: 'https://www.example.com/',
muted: true
},
{
title: 'Video URL is good, but not muted',
src: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
muted: false
}
];
Here’s a screenshot of the results:
Failure to load files needs to be watched separately by attaching an "error" event to the source elements inside the video (or maybe the video if the src is specified directly on it without source elements).
sourceElt.addEventListener('error', evt => {
console.log('Error');
});
I updated my codepen to add an example with multiple source elements inside a video. Since videos elements are built to try multiple, you should only listen for errors on the last source element (or maybe sum errors until you match the # of sources—I haven’t verified if things can expect to run top down).
Helpful info was provided in comments by #AdamH pointing to this other post: https://stackoverflow.com/a/33471125/376489
Related
I am attempting to write a chrome extension (for personal use) to swap/replace images loaded by a webpage with alternate images. I'd had this working for some time using chrome.webRequest, but am attempting to bring it up-to-speed with manifest v3.
My general solution is that I am hosting my replacement images on my own server, including a script to retrieve as json a list of such images. I fetch that list and, for each image, create a dynamic redirect rule with chrome.declarativeNetRequest.updateDynamicRules.
This all works beautifully if I request an image to be replaced in a main frame. I can see the successful match with an onRuleMatchedDebug listener, and (of course) the path is dutifully redirected.
However, when I load the web app that in turn loads the image (with javascript, presumably with xmlhttprequest?), the redirect rule does not trigger. The initiator (a javascript source file) is on the same domain and similar path to the images being replaced.
//manifest.json
{
"name": "Image replace",
"description": "Replace images in web app",
"version": "2.0",
"manifest_version": 3,
"background": {"service_worker": "background.js"},
"permissions": [
"declarativeNetRequestWithHostAccess",
// "declarativeNetRequestFeedback" // Not necessary once tested
],
"host_permissions" : [
// "https://domain1.com/outerframe/*", // Not necessary
"https://domain2.com/innerframe/*",
"https://domain3.com/*",
"https://myexample.com/*"
]
}
// background.js
//chrome.declarativeNetRequest.onRuleMatchedDebug.addListener((info) => console.log(info)); // Not necessary once tested
var rules = [];
var idx = 1;
fetch("https://myexample.com/list") // returns json list like: ["subdir1\/image1.png", "subdir1\/image2.png", "subdir2\/image1.png"]
.then((response) => response.json())
.then((data) => {
console.log(data);
for (const path of data) {
var src = "https://domain2.com/innerframe/v*/files/" + path; // wildcards a version number
var dst = "https://myexample.com/files/" + path;
rules.push({
"id" : idx++,
"action" : {
"type": "redirect",
"redirect": {
"url": dst
}
},
"condition" : {
"urlFilter": src,
// In the end I only needed main_frame, image, and not xmlhttprequest
"resourceTypes": ["main_frame", "image"]
}
});
}
chrome.declarativeNetRequest.updateDynamicRules({"addRules": rules, "removeRuleIds" : rules.map(r => r.id)});
});
Again, this DOES all work IF I load a source image directly in chrome, but fails when it's being loaded by the javascript app.
I also attempted to test the match by specifying the proper initiator with testMatchOutcome, but my browser seems to claim this API does not exist. Not at all sure what could be wrong here.
// snippet attempted after above updateDynamicRules call
chrome.declarativeNetRequest.testMatchOutcome({
"initiator": "https://domain2.com/innerframe/files/script.js",
"type": "xmlhttprequest",
"url": "https://domain2.com/innerframe/v001/files/subdir/image1.png"
}, (outcome) => console.log(outcome));
I would expect a redirect to "https://myexample.com/files/subdir/image1.png"
Instead, I get this error:
Uncaught (in promise) TypeError: chrome.declarativeNetRequest.testMatchOutcome is not a function
Documentation https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#method-testMatchOutcome says it's supported in chrome 103+. I'm running chrome 108.0.5359.72
Thanks!
Edit: Example code updated to reflect my answer below.
I've managed to work out why direct requests were redirected while script loaded ones were not. My problem was with the initiator and host permissions. I had been relying on Chrome developer tools to provide the initiator, which in the above example originated with domain2.com. However, the actual host permission I needed was from a third domain (call it domain3.com), which seems to be the source of the content that loaded scripts from domain2.com.
I discovered this when I recalled that host permissions allows "<all_urls>", which is not a good idea long term, but it did allow the redirects to complete. From there, my onRuleMatchedDebug listener could fire and log to the console the characteristics of the redirect, which showed me the proper initiator I was missing.
Having a concise view of the redirects I need, I can now truncate some of these options to only the ones actually needed (edited in original question).
Subsequent to that I thought to look back at the HTTP requests in developer tools and inspect the Referer header, which also had what I was needing.
So, silly oversights aside, I would like to leave this question open a little while longer in case anyone has any idea why chrome.declarativeNetRequest.testMatchOutcome seems unavailable in Chrome 108.0.5359.72 but is documented for 103+. I'd chalk it up to the documentation just being wrong, but it seems this function must have shipped at some point and somehow was erroneously removed? Barring any insights, I might just submit it as a bug.
I’m using in my project phaser#3.24.0 and I have a problem with games on Safari 13.1.
In my preload method I have my loadConfig object with sound data:
var data = {
mediaURL: "../../../static/sound/",
dataObjects: [
{ type: "sound", name: "ok", file: "ok.ogg" },
{ type: "sound", name: "wrong", file: "wrong.ogg" },
{ type: "sound", name: "missing", file: "missing.png" },
],
};
loadData(data, this);
Helper function:
function loadData(data, game) {
data.loadObjects.forEach((element) => {
game.load.audio(element.name, config.mediaURL + element.file);
}
}
In my create method:
this.sound.add("ok")
When I load the scene I get:
Error: There is no audio asset with key “ok” in the audio cache
initialize — phaser.min.js
add — phaser.min.js
create — culture.js
create — phaser.min.js
On other browsers everything works fine, I don’t have problems with this.
**: this.sound.add("ok")
This is not working, I have all my paths to the file etc in the game scene entries/data. But it seems no to be added in a create method - only in safari.
Safari doesn't support Ogg Vorbis.
Solution: there need to be an alternative in .mp3 format for Safari. Safari cannot proceed .oog files.
As other said here, Safari doesn't support .ogg format - https://caniuse.com/ogg-vorbis
So you should create a substitute sound with the extension mp3, m4a or something else depend on your research(I personally use m4a).
In order to load 2 sounds, one as back up, in Phaser do something like this:
scene.load.audio("ok", ["ok.ogg", "ok.m4a"]);
You can load an array of sounds with the same key, and the successful sound will play.
https://rexrainbow.github.io/phaser3-rex-notes/docs/site/audio/#load-audio-file
Although you would need to change a bit your loadData() function to match an array of files.
recently tried to modify one of my webpages with granim.js. I'd like to have
something like this - third example with forest
Unfortunately while it works perfectly during development on my local machine it doesn't work on gh-pages. It throws an error
Error: Granim: The image source is invalid.
And displays only gradient and not gradient image.I have checked also option with full path from gh-pages:
https://github.com/Kiszuriwalilibori/portfolio_granim/blob/master/project_images/moon.jpg
and few similar. None of them works, always the same error.
Examples of granim use bot full paths and local paths, so expected that any of tried paths will work. But not. Here is the part of my code responsible for granim:
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
var granimInstance = new Granim({
element: 'canvas',
direction: 'top-bottom',
isPausedWhenNotInView: true,
image: {
source: '../project_images/moon.jpg',
blendingMode: 'multiply'
},
states: {
"default-state": {
gradients: [
['#29323c', '#485563'],
['#FF6B6B', '#556270'],
['#80d3fe', '#7ea0c4'],
['#f0ab51', '#eceba3']
],
transitionSpeed: 7000
}
}
})
});
Here's link to not working properly item:
https://kiszuriwalilibori.github.io/portfolio_granim/#Home
Has anyone an idea what's wrong? As written at the beginning on local machine it renders perfectly. That is not the only image used by that page (the rest renders OK; but the only used by granim).
I have an asterisk for web(calls in the website only) working, on PC, but when I run the same client on my android 5 no sound, at least not in my android, it does send voice to PC, but just cant reproduce the incomming voice.
Everthing seems to be just fine with my asterisk, it shows in call:
servidor-asterisk*CLI> core show channels
Channel Location State Application(Data)
SIP/002670-0000003d (None) Up AppDial((Outgoing Line))
SIP/000001-0000003c 002670#from-internal Up Dial(SIP/002670,60)
2 active channels
1 active call
31 calls processed
But in eclipse console i receive code 405 from android:
"__tsip_transport_ws_onmessage", source: http://IP/videoNodeJs/scripts/sip_api.js (1)
"recv=OPTIONS sip:000001#df7jal23ls0d.invalid;rtcweb-breaker=no;transport=ws SIP/2.0
"Not implemented", source: http://IP/videoNodeJs/scripts/sip_api.js (1)
"SEND: SIP/2.0 405 Method Not Allowed
Any suggestions?
UPDATE:
SIPML5 Client:
<audio id="audio-remote"/>
var opcoes_chamada = {
audio_remote: document.getElementById('audio-remote'),
screencast_window_id: 0x00000000, // entire desktop
bandwidth: { audio:undefined, video:undefined },
video_size: { minWidth:undefined, minHeight:undefined, maxWidth:undefined, maxHeight:undefined },
events_listener: { events: '*', listener: sipEventsListener },
sip_caps: [
{ name: '+g.oma.sip-im' },
{ name: 'language', value: '\"en,fr\"' }
]
};
To make a call:
callSession = sipStack.newSession('call-audio', opcoes_chamada);
callSession.call(sip_id_d);
To answere a call:
e.newSession.setConfiguration(opcoes_chamada);
e.newSession.accept();
405 Method Not Allowed
The method specified in the Request-Line is understood, but not
allowed for the address identified by the Request-URI.
The response MUST include an Allow header field containing a
list of valid methods for the indicated address.
Some interpretation of this, any chance that everthing is fine but the audio TAG is the problem in the mobile client? If not, what is the 'address identified by the Request-URI'?
So, it's working.
Here is the deal, the SIP was just fine, the client to. The hole problem was a chrome limitation that makes necessary a click from the user to play any sound in the browser, it's something like this:
I have my audio tag:
<audio id="audio-remote"/>
and later I feed the source with sipml5:
var opcoes_chamada = {
audio_remote: document.getElementById('audio-remote'),
screencast_window_id: 0x00000000, // entire desktop
bandwidth: { audio:undefined, video:undefined },
video_size: { minWidth:undefined, minHeight:undefined, maxWidth:undefined, maxHeight:undefined },
events_listener: { events: '*', listener: sipEventsListener },
sip_caps: [
{ name: '+g.oma.sip-im' },
{ name: 'language', value: '\"en,fr\"' }
]
};
And here is the catch, the audio tag it's been feed with the SIPML5 source, but it's in pause( or hold, dont know what...) as long the user don't give a onclick action, so right after the 2 lines to make and answere a call I add a button with:
onClick="document.getElementById('audio-remote').play();"
and everthing finally works!
I'm currently working with soundmanager2 in an IE/flash context (not html5). The issue is that audio playback of mp3 content does not occur for the following case where the 'onload' callback function is defined as null OR as a function that does almost nothing.
soundManager.createSound({
id: 'someidforasoundfile',
url: 'pathtoaudiofile.mp3',
autoLoad: true,
autoPlay: true,
onload: function() {
return 1;
},
volume: 50
});
If I define the "onload" callback as:
function() { alert('zing'); }
soundmanager2 will actually start playing the audio file...but there's an annoying alert pop up that the user has to contend with.
Is this a soundmanager2 configuration issue or something else?
Thanks in advance!
ct
I think im understanding is that when a user indicates a stream, theres a message alert to indicate that the song is starting or they have to let permission.
I would say its soundmanager, As flash can stream or download media content with out any "USER" permissions.
this is limited/ restricted of course to:Examples mp3,video,other SWF files.ect
but say downloading zipfiles or other media types may need permissions.
They maybe something in the (alert) function, to create this message or pop up to appear, check that source code and follow its script.
if you have some source code for this please post i will take a look at it