diff --git a/IFRAME.md b/IFRAME.md
index 0b93c64..565e629 100644
--- a/IFRAME.md
+++ b/IFRAME.md
@@ -9,12 +9,12 @@ The solution decided on isn't an SDK framework, but rather the use of embeddable
Modern web browsers allow the parent website to communicate with the child webpage, giving a high-level of control to a developer, while also abstracting the complex code and hosting requirements. Functionality, we can make an OBSN video stream act much like an HTML video element tag, where you can issue commands like play, pause, or change video sources with ease.
Creating an OBSN iframe can be done in HTML or programmatically with Javascript like so:
-
- var iframe = document.createElement("iframe");
+```js
+ const iframe = document.createElement("iframe");
iframe.allow="autoplay;camera;microphone";
iframe.allowtransparency="false"
iframe.src = "https://obs.ninja/?webcam";
-
+```
Adding that iframe to the DOM will reveal a simple page accessing for a user to select and share their webcam. For a developer wishing to access a remote guest's stream, this makes the ingestion of that stream into production software like OBS Studios very easy. The level of customization and control opens up opportunities, such as a pay-to-join audience option for a streaming interactive broadcast experience.
An example of how this API is used by OBS.Ninja is with its Internet Speedtest, which has two OBS.Ninja IFrames on a single page. One iframe feeds video to the other iframe, and the speed at which it does this is a measure of the system's performance. Detailed stats of the connection are made available to the parent window, which displays the results.
@@ -52,161 +52,161 @@ As for API, allow for dynamic messaging, below are examples of the options avail
- Get notified when there is a video connection
As for the actually details for methods and options available to dynamically control child OBSN iframe, they are primarily kept up to via the iframe.html file that is mentioned previously. see: *iframe.html*. Below is a snippet from that file:
-
- var button = document.createElement("button");
- button.innerHTML = "Mute Speaker";
- button.onclick = function(){iframe.contentWindow.postMessage({"mute":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Un-Mute Speaker";
- button.onclick = function(){iframe.contentWindow.postMessage({"mute":false}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Toggle Speaker";
- button.onclick = function(){iframe.contentWindow.postMessage({"mute":"toggle"}, '*');}
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Mute Mic";
- button.onclick = function(){iframe.contentWindow.postMessage({"mic":false}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Un-Mute Mic";
- button.onclick = function(){iframe.contentWindow.postMessage({"mic":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Toggle Mic";
- button.onclick = function(){iframe.contentWindow.postMessage({"mic":"toggle"}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Disconnect";
- button.onclick = function(){iframe.contentWindow.postMessage({"close":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Low Bitrate";
- button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":30}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "High Bitrate";
- button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":5000}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Default Bitrate";
- button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":-1}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Reload";
- button.onclick = function(){iframe.contentWindow.postMessage({"reload":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "50% Volume";
- button.onclick = function(){iframe.contentWindow.postMessage({"volume":0.5}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "100% Volume";
- button.onclick = function(){iframe.contentWindow.postMessage({"volume":1.0}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Request Stats";
- button.onclick = function(){iframe.contentWindow.postMessage({"getStats":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Request Loudness Levels";
- button.onclick = function(){iframe.contentWindow.postMessage({"getLoudness":true}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Stop Sending Loudness Levels";
- button.onclick = function(){iframe.contentWindow.postMessage({"getLoudness":false}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "Say Hello";
- button.onclick = function(){iframe.contentWindow.postMessage({"sendChat":"Hello!"}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "previewWebcam()";
- button.onclick = function(){iframe.contentWindow.postMessage({"function":"previewWebcam"}, '*');};
- iframeContainer.appendChild(button);
-
- var button = document.createElement("button");
- button.innerHTML = "CLOSE IFRAME";
- button.onclick = function(){iframeContainer.parentNode.removeChild(iframeContainer);};
- iframeContainer.appendChild(button);
-
+```js
+var button = document.createElement("button");
+button.innerHTML = "Mute Speaker";
+button.onclick = function(){iframe.contentWindow.postMessage({"mute":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Un-Mute Speaker";
+button.onclick = function(){iframe.contentWindow.postMessage({"mute":false}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Toggle Speaker";
+button.onclick = function(){iframe.contentWindow.postMessage({"mute":"toggle"}, '*');}
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Mute Mic";
+button.onclick = function(){iframe.contentWindow.postMessage({"mic":false}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Un-Mute Mic";
+button.onclick = function(){iframe.contentWindow.postMessage({"mic":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Toggle Mic";
+button.onclick = function(){iframe.contentWindow.postMessage({"mic":"toggle"}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Disconnect";
+button.onclick = function(){iframe.contentWindow.postMessage({"close":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Low Bitrate";
+button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":30}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "High Bitrate";
+button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":5000}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Default Bitrate";
+button.onclick = function(){iframe.contentWindow.postMessage({"bitrate":-1}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Reload";
+button.onclick = function(){iframe.contentWindow.postMessage({"reload":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "50% Volume";
+button.onclick = function(){iframe.contentWindow.postMessage({"volume":0.5}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "100% Volume";
+button.onclick = function(){iframe.contentWindow.postMessage({"volume":1.0}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Request Stats";
+button.onclick = function(){iframe.contentWindow.postMessage({"getStats":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Request Loudness Levels";
+button.onclick = function(){iframe.contentWindow.postMessage({"getLoudness":true}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Stop Sending Loudness Levels";
+button.onclick = function(){iframe.contentWindow.postMessage({"getLoudness":false}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "Say Hello";
+button.onclick = function(){iframe.contentWindow.postMessage({"sendChat":"Hello!"}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "previewWebcam()";
+button.onclick = function(){iframe.contentWindow.postMessage({"function":"previewWebcam"}, '*');};
+iframeContainer.appendChild(button);
+
+var button = document.createElement("button");
+button.innerHTML = "CLOSE IFRAME";
+button.onclick = function(){iframeContainer.parentNode.removeChild(iframeContainer);};
+iframeContainer.appendChild(button);
+
As for listening events, where the parent listens for responses or events from the OBSN child frame:
-
- //////////// LISTEN FOR EVENTS
-
- var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
- var eventer = window[eventMethod];
- var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
-
- eventer(messageEvent, function (e) {
- if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
-
- if ("stats" in e.data){
- var outputWindow = document.createElement("div");
-
- var out = "
total_inbound_connections:"+e.data.stats.total_inbound_connections;
- out += "
total_outbound_connections:"+e.data.stats.total_outbound_connections;
-
- for (var streamID in e.data.stats.inbound_stats){
- out += "
streamID: "+streamID+"
";
- out += printValues(e.data.stats.inbound_stats[streamID]);
- }
-
- outputWindow.innerHTML = out;
- iframeContainer.appendChild(outputWindow);
- }
-
- if ("gotChat" in e.data){
- var outputWindow = document.createElement("div");
- outputWindow.innerHTML = e.data.gotChat.msg;
- outputWindow.style.border="1px dotted black";
- iframeContainer.appendChild(outputWindow);
- }
-
- if ("action" in e.data){
- var outputWindow = document.createElement("div");
- outputWindow.innerHTML = "child-page-action: "+e.data.action+"
";
- outputWindow.style.border="1px dotted black";
- iframeContainer.appendChild(outputWindow);
- }
-
- if ("loudness" in e.data){
- console.log(e.data);
- if (document.getElementById("loudness")){
- outputWindow = document.getElementById("loudness");
- } else {
- var outputWindow = document.createElement("div");
- outputWindow.style.border="1px dotted black";
- iframeContainer.appendChild(outputWindow);
- outputWindow.id = "loudness";
- }
- outputWindow.innerHTML = "child-page-action: loudness
";
- for (var key in e.data.loudness) {
- outputWindow.innerHTML += key + " Loudness: " + e.data.loudness[key] + "\n";
- }
- outputWindow.style.border="1px black";
-
- }
- });
-
+
+//////////// LISTEN FOR EVENTS
+
+var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
+var eventer = window[eventMethod];
+var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
+
+eventer(messageEvent, function (e) {
+ if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
+
+ if ("stats" in e.data){
+ var outputWindow = document.createElement("div");
+
+ var out = "
total_inbound_connections:"+e.data.stats.total_inbound_connections;
+ out += "
total_outbound_connections:"+e.data.stats.total_outbound_connections;
+
+ for (var streamID in e.data.stats.inbound_stats){
+ out += "
streamID: "+streamID+"
";
+ out += printValues(e.data.stats.inbound_stats[streamID]);
+ }
+
+ outputWindow.innerHTML = out;
+ iframeContainer.appendChild(outputWindow);
+ }
+
+ if ("gotChat" in e.data){
+ var outputWindow = document.createElement("div");
+ outputWindow.innerHTML = e.data.gotChat.msg;
+ outputWindow.style.border="1px dotted black";
+ iframeContainer.appendChild(outputWindow);
+ }
+
+ if ("action" in e.data){
+ var outputWindow = document.createElement("div");
+ outputWindow.innerHTML = "child-page-action: "+e.data.action+"
";
+ outputWindow.style.border="1px dotted black";
+ iframeContainer.appendChild(outputWindow);
+ }
+
+ if ("loudness" in e.data){
+ console.log(e.data);
+ if (document.getElementById("loudness")){
+ outputWindow = document.getElementById("loudness");
+ } else {
+ var outputWindow = document.createElement("div");
+ outputWindow.style.border="1px dotted black";
+ iframeContainer.appendChild(outputWindow);
+ outputWindow.id = "loudness";
+ }
+ outputWindow.innerHTML = "child-page-action: loudness
";
+ for (var key in e.data.loudness) {
+ outputWindow.innerHTML += key + " Loudness: " + e.data.loudness[key] + "\n";
+}
+ outputWindow.style.border="1px black";
+
+ }
+});
+```
This OBS.Ninja API is developed and expanded based on user feedback and requests. It is by no means complete.
Regarding versioning, I currently host past versions of OBS.Ninja, so using those past versions can ensure some level of consistency and expectation. https://obs.ninja/v12/ for example is the version 12 hosted version. The active and main production version of OBSN of course undergoes constant updates, and while I try to maintain backwards compatibility with changes to the API, it is still early days and changes might happen.