That error seems to indicate that Jitsi in your browser does not have access to local storage. Are you using a browser with restrictive security settings that could block iframes from using local storage?
something âfunnyâ in my console, a few errors too, such as :
Content Security Policy: The pageâs settings blocked the loading of a resource at eval (âscript-srcâ). Source: (function injected(eventName, injectedIntoContentWindow)
{
âŚ
although it works
you may try any of these instances :
https://framatalk.org/accueil/fr/info/
Yes - I have chrome set up to not allow third party cookies. Disabling that setting fixes this problem. Would be nice to have some way to be alerted to that cause, but I guess this is a rare enough issue.
Is there a way in jitsi to open a video call in a new tab or separate popup? I wonder if people will click away during the call to keep browsing in the forum while talking or to add a reply to the topic.
perhaps not, as it would complicate the csp_extensions in about.json
No, the current version of the theme component already adds the Jitsi API path to the CSP sources. Itâs done by this line of about.json as @Benjamin_D noted:
https://github.com/pmusaraj/discourse-jitsi/blob/master/about.json#L9
@pmusaraj Is that newer step possible to set within Discourse itself?
yes iâm figuring it out as I goâŚ
Iâm still wondering why this function: injected(eventName, injectedIntoContentWindow) etc⌠doesnât pass the csp
console
Content Security Policy: The pageâs settings blocked the loading of a resource at eval (âscript-srcâ). Source: (function injected(eventName, injectedIntoContentWindow)
{
let checkRequest;
/*
- Frame context wrapper
- For some edge-cases Chrome will not run content scripts inside of frames.
- Website have started to abuse this fact to access unwrapped APIs via a
- frameâs contentWindow (#4586, 5207). Therefore until Chrome runs content
- scripts consistently for all frames we must take care to (re)inject our
- wrappers when the contentWindow is accessed.
*/
let injectedToString = Function.prototype.toString.bind(injected);
let injectedFrames = new WeakSet();
let injectedFramesAdd = WeakSet.prototype.add.bind(injectedFrames);
let injectedFramesHas = WeakSet.prototype.has.bind(injectedFrames);
function injectIntoContentWindow(contentWindow)
{
if (contentWindow && !injectedFramesHas(contentWindow))
{
injectedFramesAdd(contentWindow);
try
{
contentWindow[eventName] = checkRequest;
contentWindow.eval(
â(â + injectedToString() + â)(ââ + eventName + ââ, true);â
);
delete contentWindow[eventName];
}
catch (e) {}
}
}
for (let element of [HTMLFrameElement, HTMLIFrameElement, HTMLObjectElement])
{
let contentDocumentDesc = Object.getOwnPropertyDescriptor(
element.prototype, âcontentDocumentâ
);
let contentWindowDesc = Object.getOwnPropertyDescriptor(
element.prototype, âcontentWindowâ
);
// Apparently in HTMLObjectElement.prototype.contentWindow does not exist
// in older versions of Chrome such as 51.
if (!contentWindowDesc)
continue;
let getContentDocument = Function.prototype.call.bind(
contentDocumentDesc.get
);
let getContentWindow = Function.prototype.call.bind(
contentWindowDesc.get
);
contentWindowDesc.get = function()
{
let contentWindow = getContentWindow(this);
injectIntoContentWindow(contentWindow);
return contentWindow;
};
contentDocumentDesc.get = function()
{
injectIntoContentWindow(getContentWindow(this));
return getContentDocument(this);
};
Object.defineProperty(element.prototype, "contentWindow",
contentWindowDesc);
Object.defineProperty(element.prototype, "contentDocument",
contentDocumentDesc);
}
/*
- RTCPeerConnection wrapper
- The webRequest API in Chrome does not yet allow the blocking of
- WebRTC connections.
- See 707683 - chromium - An open-source project to help move the web forward. - Monorail
*/
let RealCustomEvent = window.CustomEvent;
// If weâve been injected into a frame via contentWindow then we can simply
// grab the copy of checkRequest left for us by the parent document. Otherwise
// we need to set it up now, along with the event handling functions.
if (injectedIntoContentWindow)
checkRequest = window[eventName];
else
{
let addEventListener = document.addEventListener.bind(document);
let dispatchEvent = document.dispatchEvent.bind(document);
let removeEventListener = document.removeEventListener.bind(document);
checkRequest = (url, callback) =>
{
let incomingEventName = eventName + â-â + url;
function listener(event)
{
callback(event.detail);
removeEventListener(incomingEventName, listener);
}
addEventListener(incomingEventName, listener);
dispatchEvent(new RealCustomEvent(eventName, {detail: {url}}));
};
}
// Only to be called before the pageâs code, not hardened.
function copyProperties(src, dest, properties)
{
for (let name of properties)
{
if (Object.prototype.hasOwnProperty.call(src, name))
{
Object.defineProperty(dest, name,
Object.getOwnPropertyDescriptor(src, name));
}
}
}
let RealRTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection;
// Firefox has the option (media.peerconnection.enabled) to disable WebRTC
// in which case RealRTCPeerConnection is undefined.
if (typeof RealRTCPeerConnection != âundefinedâ)
{
let closeRTCPeerConnection = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.close
);
let RealArray = Array;
let RealString = String;
let {create: createObject, defineProperty} = Object;
let normalizeUrl = url =>
{
if (typeof url != "undefined")
return RealString(url);
};
let safeCopyArray = (originalArray, transform) =>
{
if (originalArray == null || typeof originalArray != "object")
return originalArray;
let safeArray = RealArray(originalArray.length);
for (let i = 0; i < safeArray.length; i++)
{
defineProperty(safeArray, i, {
configurable: false, enumerable: false, writable: false,
value: transform(originalArray[i])
});
}
defineProperty(safeArray, "length", {
configurable: false, enumerable: false, writable: false,
value: safeArray.length
});
return safeArray;
};
// It would be much easier to use the .getConfiguration method to obtain
// the normalized and safe configuration from the RTCPeerConnection
// instance. Unfortunately its not implemented as of Chrome unstable 59.
// See https://www.chromestatus.com/feature/5271355306016768
let protectConfiguration = configuration =>
{
if (configuration == null || typeof configuration != "object")
return configuration;
let iceServers = safeCopyArray(
configuration.iceServers,
iceServer =>
{
let {url, urls} = iceServer;
// RTCPeerConnection doesn't iterate through pseudo Arrays of urls.
if (typeof urls != "undefined" && !(urls instanceof RealArray))
urls = [urls];
return createObject(iceServer, {
url: {
configurable: false, enumerable: false, writable: false,
value: normalizeUrl(url)
},
urls: {
configurable: false, enumerable: false, writable: false,
value: safeCopyArray(urls, normalizeUrl)
}
});
}
);
return createObject(configuration, {
iceServers: {
configurable: false, enumerable: false, writable: false,
value: iceServers
}
});
};
let checkUrl = (peerconnection, url) =>
{
checkRequest(url, blocked =>
{
if (blocked)
{
// Calling .close() throws if already closed.
try
{
closeRTCPeerConnection(peerconnection);
}
catch (e) {}
}
});
};
let checkConfiguration = (peerconnection, configuration) =>
{
if (configuration && configuration.iceServers)
{
for (let i = 0; i < configuration.iceServers.length; i++)
{
let iceServer = configuration.iceServers[i];
if (iceServer)
{
if (iceServer.url)
checkUrl(peerconnection, iceServer.url);
if (iceServer.urls)
{
for (let j = 0; j < iceServer.urls.length; j++)
checkUrl(peerconnection, iceServer.urls[j]);
}
}
}
}
};
// Chrome unstable (tested with 59) has already implemented
// setConfiguration, so we need to wrap that if it exists too.
// https://www.chromestatus.com/feature/5596193748942848
if (RealRTCPeerConnection.prototype.setConfiguration)
{
let realSetConfiguration = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.setConfiguration
);
RealRTCPeerConnection.prototype.setConfiguration = function(configuration)
{
configuration = protectConfiguration(configuration);
// Call the real method first, so that validates the configuration for
// us. Also we might as well since checkRequest is asynchronous anyway.
realSetConfiguration(this, configuration);
checkConfiguration(this, configuration);
};
}
let WrappedRTCPeerConnection = function(...args)
{
if (!(this instanceof WrappedRTCPeerConnection))
return RealRTCPeerConnection();
let configuration = protectConfiguration(args[0]);
// Since the old webkitRTCPeerConnection constructor takes an optional
// second argument we need to take care to pass that through. Necessary
// for older versions of Chrome such as 51.
let constraints = undefined;
if (args.length > 1)
constraints = args[1];
let peerconnection = new RealRTCPeerConnection(configuration,
constraints);
checkConfiguration(peerconnection, configuration);
return peerconnection;
};
WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype;
let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind();
copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection,
["generateCertificate", "name", "prototype"]);
RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection;
if ("RTCPeerConnection" in window)
window.RTCPeerConnection = boundWrappedRTCPeerConnection;
if ("webkitRTCPeerConnection" in window)
window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection;
}
})(âabp-request-o6i81ij12xâ, true);. bd833f87-4c58-41b0-a0cd-15b978834599:27:22
Did you enable your content security policy?
Also, please dm me how you added that slick console
drop down. Gracias.
Got it !
thatâs adblock, nothing to do with jitsiâŚ
@sunjam there is no new step, the component automatically whitelists the script it needs to whitelist.
Currently no, but this would be a good improvement, Iâll work on it when I get a chance.
Very cool! Couple quick commentsâ
For mobile, after clicking the button to start the event, the âContinue to the appâ link is sometimes non-clickable! It works when viewing directly in Safari, but not in Chrome, and not in the Discourse Hub iOS appâŚ
Seconding this as well, a quick way to auto-generate a room ID could be quite useful. I think particularly for anyone not already super familiar with Jitsi, itâs not totally clear if you need to enter an existing room in that field, or if youâre generating one on the fly just by using any arbitrary random string.
Nice catch! This is because the âContinue to the appâ link makes a custom URL request that starts with org.jitsi.meet://
. I have whitelisted that custom query scheme in DiscourseHub, which should fix the issue there on the next app release. (I donât think there is a fix for this in Chrome, alas.)
I have added a randomly-generated option, users just need to leave the ID field empty, and an ID will be generated. I also added some copy to explain this:
Note that the ID wonât have words, it will be a random mix of letters and numbers.
Any chance you could prioritise this? Weâve been playing with using Jitsi for our internal chats.
The problem is this:
- we start a thread as an Event using the Calendar plugin, and include a Jitsi call to go at that time. Sometimes do this after a Doodle-esque poll in the same thread. The Jitsi link goes in the OP.
- The call launches, all good.
- Someone uses that same tab to search for something, or reply in the thread (for example to write minutes on the fly) - and they crash out of the call.
It shouldnât be too hard to make the link go to Blank rather than being in an iframe, eh? Not that I have the skills!
Well, @nathank this component is a bit of overkill if you want just a link to a jitsi room. You can add https://meet.jit.si/ROOMID
to a link, and that should do the job without a fancy-shmancy theme component.
However, I did add this option to the component, you can now choose whether you want the iframed for mobile or desktop or both:
By default, the video conference is loaded in an iframe. When unchecked, it will go to the video call in the full window. With the BigBlueButton video conference this was desirable especially on mobile, so Iâve done the same here.
Note also that the link to the full window Jitsi room does not open in a new tab. If you want that, use an anchor with target="_blank"
.
Fine for me, less fine for my less techy users! Thanks for the iframe enhancement, super helpful. Iâm not sure it makes sense for iframe to be the default for mobile; would you consider changing that?
I have discovered elsewhere that you can bypass the âdownload the Jitsi appâ page which appears on mobile by adding #config.disableDeepLinking=true to the room ID:
https://meet.jit.si/YourMeetingNameHere#config.disableDeepLinking=true
Just tried to add this theme component to our discourse 2.7.0.beta3 instance, but whatever I do, I do not see an additional icon in the composer bar to link to the conference ID.
âshow in options dropdownâ in the theme comp config is checked, therefore it should be visible. Any idea where I can look for the error?
yep, issue is solved now, maybe was some caching issue.
Nevertheless thanks for your reply.
I really love how this theme-componet works. I am still battling with jitsi audio issues otherwise everything would have work smoothly. I was wondering if anyone is currently using Jitsi in their forum and have no complains about it. My audio issues are perhaps due to WebRTC ---- anyone also have similar experience?