summaryrefslogtreecommitdiff
path: root/threads.js
diff options
context:
space:
mode:
authorGubolin <gubolin@fantasymail.de>2014-08-10 20:04:52 +0200
committerGubolin <gubolin@fantasymail.de>2014-08-10 20:04:52 +0200
commit4b71fef0c1e29c89f06389b6db81cd578d028f12 (patch)
tree210e8a83543e39e6846812a24095e4f9768bf862 /threads.js
parent0333925e916acc47c25cdcfec0c3be3d695a825f (diff)
downloadsnap-4b71fef0c1e29c89f06389b6db81cd578d028f12.tar.gz
snap-4b71fef0c1e29c89f06389b6db81cd578d028f12.zip
add camera streaming blocks (fix #460)
Diffstat (limited to 'threads.js')
-rw-r--r--threads.js71
1 files changed, 70 insertions, 1 deletions
diff --git a/threads.js b/threads.js
index 3324ac6..cb6dab7 100644
--- a/threads.js
+++ b/threads.js
@@ -1,5 +1,5 @@
/*
-
+
threads.js
a tail call optimized blocks-based programming language interpreter
@@ -2732,6 +2732,73 @@ Process.prototype.doPlayNoteForSecs = function (pitch, secs) {
this.pushContext();
};
+// Process camera streaming primitives
+
+Process.prototype.doStreamCamera = function () {
+ var myself = this;
+ var video = this.context.activeStream || null;
+
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+ if (!stage.trailsCanvas) {
+ stage.trailsCanvas = newCanvas(stage.dimensions);
+ }
+
+ if (video === null) {
+ video = document.createElement('video');
+ video.width = stage.dimensions.x;
+ video.height = stage.dimensions.y;
+
+ this.context.activeStream = video;
+
+ var videoObject = {'video': true, 'audio': false};
+
+ if (navigator.getUserMedia) {
+ navigator.getUserMedia(videoObject, function (stream) {
+ video.src = stream;
+ video.play();
+ }, this.handleError); // TODO: improve error handling
+ } else if (navigator.webkitGetUserMedia) {
+ navigator.webkitGetUserMedia(videoObject, function (stream) {
+ video.src = window.webkitURL.createObjectURL(stream);
+ video.play();
+ }, this.handleError);
+ } else if (navigator.mozGetUserMedia) {
+ navigator.mozGetUserMedia(videoObject, function (stream) {
+ video.src = window.URL.createObjectURL(stream);
+ video.play();
+ }, this.handleError);
+ }
+ } else {
+ var canvas = stage.trailsCanvas;
+ var context = canvas.getContext('2d');
+
+ if (video.readyState !== 0) {
+ try {
+ context.drawImage(video, 0, 0, video.width, video.height);
+ stage.changed();
+ } catch (e) {
+ if (e.name !== 'NS_ERROR_NOT_AVAILABLE') {
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=879717
+ throw e;
+ }
+ }
+ }
+ }
+ this.pushContext('doYield');
+ this.pushContext();
+};
+
+Process.prototype.doStopCamera = function () {
+ var stage = this.homeContext.receiver.parentThatIsA(StageMorph);
+ if (stage) {
+ stage.threads.processes.forEach(function (thread) {
+ if (thread.context.activeStream) {
+ thread.popContext();
+ }
+ });
+ }
+};
+
// Process constant input options
Process.prototype.inputOption = function (dta) {
@@ -2808,6 +2875,7 @@ Process.prototype.reportFrameCount = function () {
startValue initial value for interpolated operations
activeAudio audio buffer for interpolated operations, don't persist
activeNote audio oscillator for interpolated ops, don't persist
+ activeStream video element for camera streaming, don't persist
isLambda marker for return ops
isImplicitLambda marker for return ops
isCustomBlock marker for return ops
@@ -2835,6 +2903,7 @@ function Context(
this.startTime = null;
this.activeAudio = null;
this.activeNote = null;
+ this.activeStream = null;
this.isLambda = false; // marks the end of a lambda
this.isImplicitLambda = false; // marks the end of a C-shaped slot
this.isCustomBlock = false; // marks the end of a custom block's stack