Multi-stream WebRTC application not working on Safari - javascript

I have a custom WebRTC application that uses two video streams and one audio stream.
Everything is working nicely on Chrome (93.0) and Firefox (92.0), but Safari (14.1) refuses to play one of the streams (the one for the first video element with ID "stream").
HTML looks as follows (mostly placeholders):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="icon" href="data:;base64,iVBORw0KGgo="/>
<script src="stream.js"></script>
<style>
</style>
</head>
<body>
<div style="display:grid">
<video style="grid-column:1;grid-row:1;width:720px;z-index:5" id="stream" autoplay playsinline>Your browser does not support video</video>
<canvas style="grid-column:1;grid-row:1;justify-self:end;width:1280px;height:720px;z-index:10" id="canvas"></canvas>
<video style="grid-column:1;grid-row:1;justify-self:end;width:1280px;height:720px" id="stream2" autoplay playsinline>Your browser does not support video</video>
</div>
</body>
</html>
The relevant part of the Javascript code (html5VideoElement == ID "stream", html5VideoElement2 == ID "stream2"):
function onAddRemoteStream(event) {
if (event.transceiver.mid == remotemap["front"]) {
frontstream.addTrack(event.track);
html5VideoElement.srcObject = frontstream;
html5VideoElement.play();
}
if (event.transceiver.mid == remotemap["audio"]) {
frontstream.addTrack(event.track);
}
if (event.transceiver.mid == remotemap["surface"]) {
surfacestream.addTrack(event.track);
html5VideoElement2.srcObject = surfacestream;
html5VideoElement2.play();
}
}
onAddRemoteStream is the onTrack method for the RTCPeerConnection object. remotemap contains a mapping from track type to MID value, sent by the remote peer. frontstream and surfacestream are two (initially empty) MediaStream objects.
Weirdly enough, there are no exceptions or warnings with any browser, the first video element just stays empty and silent with Safari.
All outgoing streams (camera, audio, canvas) work on all three browsers.
Related issue: https://github.com/floe/surfacestreams/issues/6
Bountysource: https://app.bountysource.com/issues/105533187-html5-client-is-b0rken-on-safari
Any suggestions welcome!
UPDATE 01/23: So after almost one year, I can finally confirm that this was apparently a bug in Safari 14/15. It's now working, without any change in the relevant code bits, on Safari 16+.

Related

Audio object not playing in callbacks on mobile devices

It seems to me that the Audio object can not be easily played inside a JavaScript callback when running on a mobile device. The code below shows an onload function which, on a PC, plays the sound when the web page is loaded, but on Android phones plays nothing.
My uninformed guess is that the callback returns before the Audio object starts to play, and thus, for some deep reason, dies.
Is there any way over this? In the full version the JavaScript would read the sound to play from the URL.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Play Me</title>
<style>
body {background-color:lightgrey}
h1 {color:blue}
p {color:green;font-size:50px}
</style>
</head>
<body onload="playMySound()">
<P>
PLAY ME
<button onclick="playMySound()">sound me</button>
</P>
<br>
<script>
var mySound ;
function playMySound () {
var soundUrl = "http://www.letiketa.com/myapp/sound.ashx?sound=sound1" ;
var mySound = new Audio(soundUrl);
// Actually play the sound
mySound.play() ;
}
</script>
The button plays the sound correctly, on all devices and I suppose that is a callback...? Is there something special about the onload callback?
Argh, it is all to do with the fact that on mobile devices, currently, HTML5 disallows sounds to be played unless the user has done some input, presumably saying "I allow you to play sounds." The latest Firefox browser, V34 anyway, seems to have lifted the restrictions and all works as it should.
There is a fix in Chrome too, you need to, in the address bar, goto "about:flags" and find the "gesture required" option, disabling it.
After all this the program which I wrote two days ago now works...

Can't run very first tracking.js example on Chrome

I'm trying to get familiar with tracking.js, but when I try to run the very same example given on the project's page (http://trackingjs.com/docs.html#introduction), nothing happens.
Google-chrome doesn't even shows the prompt asking if I want to allow the page to access to my webcam. The same thing happens for Firefox.
I have already ran the other examples from the tracking.js-master/ package, and the only one that fails is the one described on the tutorial, which I've added.
Below is the code which I copied and pasted from the tracking.js intro page to my first_tracking.html file.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>tracking.js - first tracking</title>
<script src="../build/tracking-min.js"></script>
</head>
<body>
<p>This shows in the browser</p>
<video id="myVideo" width="400" height="300" preload autoplay loop muted></video>
<script>
var colors = new tracking.ColorTracker(['magenta', 'cyan', 'yellow']);
colors.on('track', function(event) {
if (event.data.length === 0) {
// No colors were detected in this frame.
} else {
event.data.forEach(function(rect) {
console.log(rect.x, rect.y, rect.height, rect.width, rect.color);
});
}
});
tracking.track('#myVideo', colors);
</script>
</body>
</html>
Has anyone tried and succeeded in running the introduction examples listed on the tracking.js page and have any pointers?
Research: Most of the stuff found on a google search relate to Google Analytics, Node.js and other JS frameworks. I also found some people suggesting setting the preload option to auto, resulting in preload="auto", but it didn't work.
I was able to get the example working with the webcam. Here's how.
First, Go into to root tracking.js directory and start a simple server. If you have python installed, try running python -m SimpleHTTPServer, then visit http://localhost:8000/examples/first_tracking.html to see your example, assuming your file is located in the examples directory of the unzipped file. This is important. If you just open the file in your browser, you will get an error: Canvas tainted by cross-origin data
Save the following code to first_tracking.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>tracking.js - first tracking</title>
<script src="../build/tracking-min.js"></script>
</head>
<body>
<video id="myVideo" width="400" height="300" preload autoplay loop muted></video>
<script>
var colors = new tracking.ColorTracker(['magenta', 'cyan', 'yellow']);
colors.on('track', function(event) {
if (event.data.length === 0) {
// No colors were detected in this frame.
} else {
event.data.forEach(function(rect) {
console.log(rect.x, rect.y, rect.height, rect.width, rect.color);
});
}
});
window.onload = function() {
// note here that 'camera' is set to true, I believe this tells tracking.js to use
// the webcam.
tracking.track('#myVideo', colors, {camera: true});
}
</script>
</body>
</html>
Make sure your server is still running, then visit http://localhost:8000/examples/first_tracking.html and inspect the console. You should see output like the following
260 47 37 47 "cyan" first_tracking.html:18
I recently ran into this problem myself and the issue for me was a missing parameter to the tracking.track() call...
The example online shows this:
tracking.track('#myVideo', colors);
When it should be this:
tracking.track('#myVideo', colors, { camera: true });
Technically Julia's post includes this param so I'm ok with that as the accepted answer, but just in case someone else runs into this problem, this is what fixed it for me. With the camera flag, I was able to run the example without waiting for dom load as well, if that matters for anyone else.
{ camera: true } is missing from the example code. As previous answers mention, include tracking.track('#myVideo', colors, { camera: true });

window.print() breaks on html video tag

My window.print() statements have been acting very strange and I finally narrowed it down to the videos in my html. I'll clarify strange, the print dialog only pops up after a page refresh or after an alert(which I find bizarre), and subsequent clicks on the print button result in inconsistent and flaky firing of the print dialog.
If I move the video files out of the expected dir so the html can't find them or remove the video tags the print functionality works perfectly. Currently the videos are sitting directly under the end of the jquery mobile content </div> tag, but I've tried moving them around in the page content with no change in behavior.
Has anyone encountered this problem or know how I might fix it?
EDIT: Tried grabbing the videos with jquery and calling .remove() on them to see if I could get it to fire properly on click but no go.
Maybe #media property will be helpful?
Example that works for me (please note styles applied):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#media print {
video { display: none; }
}
</style>
</head>
<body onload="window.print();">
<h1>Sample Text</h1>
<video width="320" height="240" controls>
<source src="example_video_file.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<p>To be printed out</p>
</body>
</html>
Calling this function as a workaround for this Chrome bug did the trick for me:
function printPage() {
window.print();
//workaround for Chrome bug - https://code.google.com/p/chromium/issues/detail?id=141633
if (window.stop) {
location.reload(); //triggering unload (e.g. reloading the page) makes the Print dialog appear
window.stop(); //immediately stop reloading
}
return false;
}

This JavaScript code is not working in an HTML5 application

I am trying to make a simple application in HTML5 with JavaScript. It's supposed to play a random sound, when you push the button.
It works fine, when uploaded to a website, but it doesen't work on my smartphone.
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script>
function playSounds() {
var sounds = new Array(
"musik/shut the f**k up.mp3",
"musik/My gun's bigger than yours!.mp3"
);
var index = Math.floor(Math.random() * (sounds.length));
$("#element").html("<embed src=\"" + sounds[index] + "\" hidden=\"true\" autostart=\"false\" />");
}
</script>
<title></title>
<meta charset="utf-8">
</head>
<body= "javascript:playSounds()">
<button onClick="playSounds()">
LAUGH</button>
<div id="element">
</div>
</body>
</html>
I copied the content in file jquery.min.js from a site and linked it directly in the application to the mainpage, where the sound needs to play.
The source is here:
http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
I tried debugging the JavaScript code, but I can't seem to find the issue.
How do I solve this?
Mobile devices in general do not support <embed>.
Your use of <embed> shows you have an imperfect understanding of what an "HTML5 app" is. Such an app would use <audio> and check canPlayType("audio/mpeg") to see if the browser supports MP3 playback.

Cannot call method addEventListener() of null - even using jQuery DOM ready event

I'm using jQuery for/with javascript in order to try to modify the inner HTML code of a div in the .htm file. I'm using jQuery DOM ready event as recommended here (http://stackoverflow.com/questions/9856140/javascript-uncaught-typeerror-cannot-call-method-addeventlistener-of-null) in order to avoid the script to be run before the div is ready, but that doesn't matter; I keep getting that error.
I must say it's just a few days since I'm into Javascript and it is a very long time since I last used HTML so please don't discard any noob-typical errors because most likely it may be that.
Here are the files I'm using, hosted in Skydrive:
AMPlayer.htm
playlister.js
As it can be guessed, I'm using videoJS as video player. The CSS and JS files of videojs can be referenced either online (http://videojs.com/#section5) or offline, as can be seen in AMPlayer.htm, but this is just circumstancial information since it looks more like a problem with javascript rather than a problem with videojs.
EDIT: What I think is the important part of the files:
AMPlayer.htm (I think the problem is here, so I'm pasting the whole file):
<!DOCTYPE html>
<html>
<head>
<link href="video-js.css" rel="stylesheet" type="text/css">
<script src="video-js.js"></script>
<script src="jquery-1.7.2.min.js"></script>
<script src="playlister.js" type="text/javascript"></script>
<title>AMPlayer</title>
</head>
<body>
<div id="the-video" class="video-js-box">
<span> </span>
</div>
</body>
</html>
playlister.js:
function postVideo()
{
getNextVideo();
document.write("NEXT VIDEO: "+videoNames[iNewVideoId]+"<br>");
var video1 = '<video id="AMPlayer" class="video-js vjs-default-skin" preload="auto" width="650" height="365" data-setup="{}" autoplay> <source src="videos/AVANCE/vid.mp4" type="video/mp4" /><source src="videos/AVANCE/vid.webm" type="video/webm" /></video>';
//document.write(video1); This writes the text so the video is played, but it drives me to an undesired behaviour
document.write("BEFORE THE .SETUP<br>");
//$("#the-video").html(video1); This doesn't work
//document.getElementById("the-video").innerHTML=video1; This does neither work
//window.VideoJS.setup($'video1'));
document.write("AFTER THE .SETUP<br>");
document.getElementById("AMPlayer").addEventListener('ended', postVideo, true);
//$(".video-js")[0].player.play();
document.write("AFTER THE .PLAY<br>");
//postVideo();
}
Any provided help will be very useful for sure. Thanks in advance.
You are trying to get the element with the id AMPlayer, but you don't have one.
You have a string containing the HTML to create one, but it hasn't been added to the DOM.

Categories

Resources