When showing a camera feed through a <video> tag, I observe different behavior between Firefox and Chrome when suspending the operating system (i.e. closing/clamshelling the laptop on my Macbook). Afterwards, when resuming the OS:
on Firefox, the camera feed is immediately re-established
on Chrome, the camera feed goes black
As an aside, I've also noticed that the suspend event behaves differently:
on Firefox, it is sent when the camera feed is first connected to the video tag (i.e. nothing to do with OS suspend/resume, as far as I can tell)
on Chrome, it is sent when the OS resumes (i.e. after re-opening the laptop)
I'd like to have Chrome match Firefox's behavior, i.e. show the video feed after resuming from a suspend situation. Is this possible?
While I don't understand the underlying difference between browsers, I have a workaround:
Ignore any "suspend" event if it happens immediately after the video component is mounted. However, if a "suspend" event is received thereafter, do the following:
Wait at least 2 seconds (any sooner and it seems an error will occur when re-querying for permission; another strategy could be to "keep trying" until success)
Re-query for permission to use the camera/audio (Chrome will automatically grant it)
Re-mount the video & audio tags, and establish a video stream again.
The camera stream will show in the video tag again.
Related
When playing a live audio stream, like web radio, through <audio> or Audio(), the pause event can fire in (at least) three ways:
user clicks on the pause button (with <audio controls>)
user clicks the browsers global audio controls
iOS: Control Center
Android: browser's notification drawer (at least Chrome, Opera, Firefox)
Desktop: Media Session API controls, but uninitialized, without explicit setActionHandler (might be hidden behind a flag as of now)
a buffer underrun caused by various network conditions
Is it possible to distinguish between 1/2 and 3?
Ideally, there would be an event property like isTrusted, which I am missing
I have tried to guess, looking esp. at readyState and networkState, but both are very inconclusive, especially across browsers (e.g. the interpretation/semantics of HAVE_FUTURE_DATA vs HAVE_ENOUGH_DATA)
I have shied away from making a "decaying state machine", juggling other events. A buffer underrun is often preceded by stalled events, and sometimes followed by ended events. A cross-browser implementation seems crazy complex and the danger of false positives very high.
Am I out of luck until Media Session lands everywhere?
Note: this question looks like a solution, but unfortunately isn't -- browsers handle live streams' "ends" differently and inconsistently.
The waiting event should fit your needs.
You can try this demo while you simulate bad network with the dropdown in Chrome's Network tab (e.g: Slow 3G)
const video = document.getElementById('mwe_player_0');
video.onwaiting = function() { console.log('onwaiting'); };
<video id="mwe_player_0" controls="" preload="none" style="width:800px;height:450px"><source src="https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm" type="video/webm; codecs="vp8, vorbis""></video>
Note that this demo works with HTMLAudioElement as well (because it inherits HTMLMediaElement). The video demo is just easier to test.
If you want to start an event when the user pauses the audio then this snippet will do the job. I didn't test it on mobile in the notification drawer but I think it'll work.
const video = document.querySelector('video');
video.addEventListener('pause', (event) => {
console.log('The Boolean paused property is now true. Either the ' +
'pause() method was called or the autoplay attribute was toggled.');
});
resource: audio element events
resource: pause event
I also found a helpful answer to what you are trying to do 2 (at least from what I understand) and why it's a bad technique. Link to question
3 Events: stalled / waiting check the events resource
playSound : function() {
var audio = new Audio(audio.mp3);
audio.play();
}
I am using the above code to simply play audio. But I am facing two issues below:
The sound never plays till I click on the tab (for this I go to another tab and then click the current tab). Seems it needs an event before playing sound.
Sometimes I get exception and audio never plays "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first."
I don't want to mess with HTML element.
You're likely seeing the policy change for autoplaying media on websites issued by Chrome: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
In essence, the policy says that unless the user interacts on your media and your handler* does not start the media synchronously, it will not play.
Notice the word synchronously - you can't even use setTimeout or some such. This is to protect the user from spammy ads and alike. The other browsers have this as well, as a setting, but they might and likely will enable this by default, so you better get ready for it.
[*] - (e.g. click handler)
We play streaming audio with javascript that is running in a WKWebView object on iOS. If that WKWebView is destroyed or no longer displayed, the audio will oftentimes continue playing to completion. The only way for the user to stop the audio is to swipe up to get the lock screen playback controls and hit 'pause'.
Is there a way for the javascript in the WKWebView to be notified that it is about to be shut down, so that it can stop playback of the audio before the WKWebView is destroyed?
I've tried hooking into 'pagehide', 'unload', 'beforeunload', and 'visibilitychange' events, with no luck.
I'm sure a custom event could be triggered from the native code, but I don't have control of that side of things. Is there anything else that works?
This bug was apparently fixed in iOS 8.3+, but the suggested answer of loading a blank page as the view disappears works very well and could be useful if supporting apps running on older OS versions. This approach is also much more resilient than relying on each JS implementation running in the WKWebView to stop its own media playback after being notified of the impending 'shutdown' of the web view:
In your WKWebView view controller class' -(void)viewDidDisappear:(BOOL)animated method, run the following code to load a blank page into your web view. The code assumes your reference to your web view is self.webView, thus modify as needed.
// fix to prevent embedded audio/video from playing once the view has closed...
[self.webView loadHTMLString:#"<html/>" baseURL:nil];
See WKWebView embed video keeps playing sound after release for more details...
Considering the limitations imposed by iOS Safari about the play/load call on a video element I use to initiate it at the first user touchend with a preplay action (play() followed by pause()). From that time I can play with the video as I want (this solution is partially described here).
The problem I encountered is a failed preplay (any next call to play() will be ignored) when the first touchend follows a swipe/drag interaction.
There is a way to let it works also with a swipe? or there is a reliable way to detect if the preplay was succeeded?
I have an embedded Windows Media Player object in my website and I'd like to make it skip ahead to a certain point when the page loads. Most sites suggest using:
mediaplayerID.controls.currentPosition=xxx
That works great in Chrome but IE throws up a JavaScript error saying that mediaplayerID is undefined. I assume the issue is that the script is running before the media player object is fully loaded -- after the video starts playing, I can run set the currentPosition in the Developer Tools console and it skips ahead like it should. Is there a way in JavaScript to detect when (or wait until) media player is loaded and then change position?