master
Boyana 1 year ago
commit 74708e5b3e

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="https://p5livemedia.itp.io/simplepeer.min.js"></script>
<script type="text/javascript" src="https://p5livemedia.itp.io/socket.io.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/addons/p5.sound.min.js"></script>
<script type="text/javascript" src="https://p5livemedia.itp.io/p5livemedia.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,380 @@
/**
*
* @class p5LiveMedia
* @constructor
* @param {p5.sketch} [something] blah blah blah.
* @param {p5LiveMedia.MEDIA TYPE}
* @param {WebRTC stream}
* @example
*
function setup() {
// Stream Audio/Video
createCanvas(400, 300);
// For A/V streams, we need to use the createCapture callback method to get the "stream" object
video = createCapture(VIDEO, function(stream) {
let p5lm = new p5LiveMedia(this,"CAPTURE",stream)
p5lm.on('stream', gotStream);
p5lm.on('data', gotData);
p5lm.on('disconnect', gotDisconnect);
});
video.muted = true;
video.hide();
// OR //
// Stream Canvas as Video
let c = createCanvas(400, 300);
video = createCapture(VIDEO);
video.muted = true;
video.hide();
let p5lm = new p5LiveMedia(this,"CANVAS",c);
p5lm.on('stream', gotStream);
p5lm.on('data', gotData);
p5lm.on('disconnect', gotDisconnect);
// OR //
// Just Data
createCanvas(400, 300);
let p5lm = new p5LiveMedia(this,"DATA");
p5lm.on('data', gotData);
p5lm.on('disconnect', gotDisconnect);
}
function draw() {
image(video,0,0,width/2,height);
ellipse(mouseX,mouseY,100,100);
if (ovideo != null) {
rect(10,10,10,10);
image(ovideo,width/2,0,width/2,height);
}
}
// We got a new stream!
function gotStream(stream, id) {
print("New Stream from " + id);
// This is just like a video/stream from createCapture(VIDEO)
ovideo = stream;
//ovideo.hide();
}
function gotData(data, id) {
print("New Data from " + id);
// Got some data from a peer
print(data);
}
function gotDisconnect(id) {
print(id + " disconnected");
}
*/
class p5LiveMedia {
constructor(sketch, type, elem, room, host) {
this.sketch = sketch;
//sketch.disableFriendlyErrors = true;
this.simplepeers = [];
this.mystream;
this.onStreamCallback;
this.onDataCallback;
this.onDisconnectCallback;
if (!host) {
this.socket = io.connect("https://p5livemedia.itp.io/");
} else {
this.socket = io.connect(host);
}
//console.log(elem.elt);
if (type == "CANVAS") {
this.mystream = elem.elt.captureStream(30);
} else if (type == "CAPTURE") {
this.mystream = elem;
} else {
// Assume it is just "DATA"
}
this.socket.on('connect', () => {
//console.log("Socket Connected");
//console.log("My socket id: ", this.socket.id);
//console.log("***"+window.location.href);
// Sends back a list of users in the room
if (!room) {
this.socket.emit("room_connect", window.location.href);
} else {
this.socket.emit("room_connect", room);
}
});
this.socket.on('disconnect', (data) => {
// console.log("Socket disconnected");
});
this.socket.on('peer_disconnect', (data) => {
//console.log("simplepeer has disconnected " + data);
for (let i = 0; i < this.simplepeers.length; i++) {
if (this.simplepeers[i].socket_id == data) {
//console.log("Removed the DOM Element if it exits");
this.removeDomElement(this.simplepeers[i]);
//console.log("Removing simplepeer: " + i);
this.simplepeers.splice(i,1);
break;
}
}
this.callOnDisconnectCallback(data);
});
// Receive listresults from server
this.socket.on('listresults', (data) => {
//console.log(data);
for (let i = 0; i < data.length; i++) {
// Make sure it's not us
if (data[i] != this.socket.id) {
// create a new simplepeer and we'll be the "initiator"
let simplepeer = new SimplePeerWrapper(this,
true, data[i], this.socket, this.mystream
);
// Push into our array
this.simplepeers.push(simplepeer);
}
}
});
this.socket.on('signal', (to, from, data) => {
//console.log("Got a signal from the server: ", to, from, data);
// // to should be us
// if (to != this.socket.id) {
// console.log("Socket IDs don't match");
// }
// Look for the right simplepeer in our array
let found = false;
for (let i = 0; i < this.simplepeers.length; i++)
{
if (this.simplepeers[i].socket_id == from) {
//console.log("Found right object");
// Give that simplepeer the signal
this.simplepeers[i].inputsignal(data);
found = true;
break;
}
}
if (!found) {
//console.log("Never found right simplepeer object");
// Let's create it then, we won't be the "initiator"
let simplepeer = new SimplePeerWrapper(this,
false, from, this.socket, this.mystream
);
// Push into our array
this.simplepeers.push(simplepeer);
// Tell the new simplepeer that signal
simplepeer.inputsignal(data);
}
});
}
// // use this to add a track to a stream - assuming this is a stream, it will have to extract the track out
// addtrack(stream, type) {
// if (type == "CANVAS") {
// this.mystream = elem.elt.captureStream(30);
// } else if (type == "CAPTURE") {
// this.mystream = elem;
// }
// }
send(data) {
for (let i = 0; i < this.simplepeers.length; i++) {
if (this.simplepeers[i] != null) {
this.simplepeers[i].send(data);
}
}
}
on(event, callback) {
if (event == 'stream') {
this.onStream(callback);
} else if (event == 'data') {
this.onData(callback);
} else if (event == "disconnect") {
this.onDisconnect(callback);
}
}
onDisconnect(callback) {
this.onDisconnectCallback = callback;
}
onStream(callback) {
this.onStreamCallback = callback;
}
onData(callback) {
this.onDataCallback = callback;
}
callOnDisconnectCallback(id) {
if (this.onDisconnectCallback) {
this.onDisconnectCallback(id);
}
}
callOnDataCallback(data, id) {
if (this.onDataCallback) {
this.onDataCallback(data, id);
}
}
removeDomElement(ssp) {
if (ssp.domElement) {
document.body.removeChild(ssp.domElement);
}
}
callOnStreamCallback(domElement, id) {
if (this.onStreamCallback) {
//////////////////////
// Copied from createCapture and addElement in p5.js source 10/12/2020
//const videoEl = addElement(domElement, this.sketch, true);
document.body.appendChild(domElement);
let videoEl = new p5.MediaElement(domElement, this.sketch);
this.sketch._elements.push(videoEl);
videoEl.loadedmetadata = false;
// set width and height onload metadata
domElement.addEventListener('loadedmetadata', function() {
domElement.play();
if (domElement.width) {
videoEl.width = domElement.width;
videoEl.height = domElement.height;
} else {
videoEl.width = videoEl.elt.width = domElement.videoWidth;
videoEl.height = videoEl.elt.height = domElement.videoHeight;
}
videoEl.loadedmetadata = true;
});
/////////////////////////////
this.onStreamCallback(videoEl, id);
}
else {
//console.log("no onStreamCallback set");
}
}
}
// A wrapper for simplepeer as we need a bit more than it provides
class SimplePeerWrapper {
constructor(p5lm, initiator, socket_id, socket, stream) {
this.simplepeer = new SimplePeer({
initiator: initiator,
trickle: false
});
this.p5livemedia = p5lm;
// Their socket id, our unique id for them
this.socket_id = socket_id;
// Socket.io Socket
this.socket = socket;
// Are we connected?
this.connected = false;
// Our video stream
this.stream = stream;
// Dom Element
this.domElement = null;
// simplepeer generates signals which need to be sent across socket
this.simplepeer.on('signal', data => {
this.socket.emit('signal', this.socket_id, this.socket.id, data);
});
// When we have a connection, send our stream
this.simplepeer.on('connect', () => {
//console.log('simplepeer connection')
//console.log(this.simplepeer);
//p.send('whatever' + Math.random())
// We are connected
this.connected = true;
// Let's give them our stream, if we have a stream that is
if (stream != null) {
this.simplepeer.addStream(stream);
//console.log("Send our stream");
}
});
// Stream coming in to us
this.simplepeer.on('stream', stream => {
//console.log('Incoming Stream');
// This should really be a callback
// Create a video object
this.domElement = document.createElement("VIDEO");
this.domElement.id = this.socket_id;
this.domElement.srcObject = stream;
this.domElement.muted = false;
this.domElement.onloadedmetadata = function(e) {
e.target.play();
};
//document.body.appendChild(ovideo);
//console.log(this.domElement);
this.p5livemedia.callOnStreamCallback(this.domElement, this.socket_id);
});
this.simplepeer.on('data', data => {
let stringData = String(data);
this.p5livemedia.callOnDataCallback(stringData, this.socket_id);
});
this.simplepeer.on('error', (err) => {
// ERR_WEBRTC_SUPPORT
// ERR_CREATE_OFFER
// ERR_CREATE_ANSWER
// ERR_SET_LOCAL_DESCRIPTION
// ERR_SET_REMOTE_DESCRIPTION
// ERR_ADD_ICE_CANDIDATE
// ERR_ICE_CONNECTION_FAILURE
// ERR_SIGNALING
// ERR_DATA_CHANNEL
// ERR_CONNECTION_FAILURE
console.log(err);
});
}
send(data) {
if (this.connected) {
this.simplepeer.send(data);
} else {
//console.log("Can't send, not connected");
}
}
inputsignal(sig) {
this.simplepeer.signal(sig);
}
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,36 @@
let myVideo;
let otherVideo;
function setup() {
createCanvas(windowHeight, windowWidth);
let constraints = {audio: true, video: true};
myVideo = createCapture(constraints,
function(stream) {
let p5l = new p5LiveMedia(this, "CAPTURE", stream, "NYCAMST")
p5l.on('stream', gotStream);
}
);
myVideo.elt.muted = true;
myVideo.hide();
}
function draw() {
background(220);
stroke(255);
image(myVideo,0,0,width,height);
if (otherVideo) {
blend(otherVideo, 0, 0, otherVideo.width, otherVideo.height, 0, 0, width, height, MULTIPLY);
}
}
// We got a new stream!
function gotStream(stream, id) {
// This is just like a video/stream from createCapture(VIDEO)
otherVideo = stream;
//otherVideo.id and id are the same and unique identifiers
otherVideo.hide();
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,7 @@
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}

@ -0,0 +1,2 @@
GESTURE_APPLICATION_ROOT=/breadcube/gesture
GESTURE_PORTNUMBER=5002

@ -0,0 +1,10 @@
include .env
export
default: local
local:
@flask run --debug
breadcube:
@SCRIPT_NAME=${GESTURE_APPLICATION_ROOT} gunicorn -b localhost:${GESTURE_PORTNUMBER} --reload app:app

@ -2,15 +2,17 @@ from flask import Flask, request, redirect, render_template
import os import os
app = Flask(__name__) app = Flask(__name__)
app.config.from_pyfile('settings.py')
UPLOAD_FOLDER = os.path.join("static", "media") UPLOAD_FOLDER = os.path.join("static", "media")
media = { media = {
"beer.gif": ["beer"], "beer.gif": ["beer"],
"bell.gif": ["beer", "cafe de bel", "bell"], "bell.gif": ["beer", "cafe de bel", "bell"],
"box.gif": ["box"], "box.gif": ["box"],
"cafe-de-bel": ["coffee", "bell", "beer", "cafe de bel"], "cafe-de-bel.gif": ["coffee", "bell", "beer", "cafe de bel"],
"cloud-storm.gif": ["cloud", "storm"], "cloud-storm.gif": ["cloud", "storm"],
"cloud.gif": ["cloud"], "cloud.gif": ["cloud"],
"coffee.gif": ["coffee", "cafe fe bel"], "coffee.gif": ["coffee", "cafe de bel"],
"er-beer.gif": ["emergency beer"], "er-beer.gif": ["emergency beer"],
"hands.gif": ["joking", "okay", "sure"], "hands.gif": ["joking", "okay", "sure"],
"hurry.gif": ["time", "hurry", "pebbles"], "hurry.gif": ["time", "hurry", "pebbles"],
@ -21,13 +23,20 @@ media = {
"pebbles.gif": ["time", "clockwise"], "pebbles.gif": ["time", "clockwise"],
"reverse-pebbles.gif": ["time", "anticlockwise"], "reverse-pebbles.gif": ["time", "anticlockwise"],
"strike.gif": ["strike", "worker", "woman", "operator"] "strike.gif": ["strike", "worker", "woman", "operator"]
} }
# media = ["operator", "worker", "woman"]
@app.route("/") @app.route("/")
def home(): def home():
text = ["operator", "worker", "operator strike", "strike", "(k)not","pebbles","time","hurry","clockwise","anticlockwise","cloud","teletype","box","emergency beer","beer","cafe de bel","coffee","bell","food","breakfast","I love you"] text = []
for x in media:
for y in media[x]:
print(y)
if y not in text:
text.append(y)
# print("added")
# print(text)
else:
print("already there")
return render_template("template-index.html", text=text) return render_template("template-index.html", text=text)
@app.route("/<word>") @app.route("/<word>")
@ -38,4 +47,4 @@ def word(word):
wordmedia.append(item) wordmedia.append(item)
print("wordmedia: ") print("wordmedia: ")
print(wordmedia) print(wordmedia)
return render_template("template-word.html", word=word, wordmedia=wordmedia, media=media, path=UPLOAD_FOLDER) return render_template("template-word.html", word=word, wordmedia=wordmedia, media=media, path=UPLOAD_FOLDER)

@ -0,0 +1,10 @@
import os
from dotenv import main
# Load environment variables from the .env file
main.load_dotenv()
# Bind them to Python variables
APPLICATION_ROOT = os.environ.get('GESTURE_APPLICATION_ROOT', '/')
PORTNUMBER = int(os.environ.get('GESTURE_PORTNUMBER', 5001))

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

@ -12,6 +12,7 @@ body{
font-size: 1.5rem; font-size: 1.5rem;
margin: 2rem auto; margin: 2rem auto;
max-width: 60rem; max-width: 60rem;
padding: 1rem;
} }
.button{ .button{
font-family: monospace; font-family: monospace;
@ -19,15 +20,18 @@ body{
border-radius: 2em; border-radius: 2em;
background: var(--color2); background: var(--color2);
color: var(--color1); color: var(--color1);
border: none;
margin: 0 0.25rem 0.25rem 0;
} }
button:after{ button:after{
content: " →"; content: " →";
break-before: avoid; break-before: avoid;
} }
h1.button{font-size: 1.4rem;}
.button:hover{opacity: 0.7; cursor: pointer;} .button:hover{opacity: 0.7; cursor: pointer;}
.close{float: right; text-decoration: none;} .close{float: right; text-decoration: none;}
.close:hover{opacity: 0.7} .close:hover{opacity: 0.7}
img{max-width: 100%; margin-bottom: 1rem;} img{width: 100%; margin-bottom: 1rem;}
input{ input{
margin: 0 0 0.5rem; margin: 0 0 0.5rem;
} }
@ -61,6 +65,7 @@ textarea{
max-width: calc(50% - 4rem); max-width: calc(50% - 4rem);
float: left; float: left;
padding-right: 2rem; padding-right: 2rem;
margin: 1rem 0;
} }
p{font-size: 1rem;}

@ -5,7 +5,8 @@
<body> <body>
<h1>gesture glossary ✌️</h1> <h1>gesture glossary ✌️</h1>
<div class="two-col"> <div class="two-col">
<h4>This is the home page for the gesture glossary. It has every word in the glossary to the right. Click a word to visit its page. This is the introduction.</h4> <h4>This is the the gesture glossary. Click a word to the right to see the gestures related to it. </h4>
<p>The aim is to see if a gesture glossary works and how it will work best. Also to see what kind of different interpretations there will be on gestures of our memory. To test the gesture glossary idea, and see what different meanings appear or already exist in the current vocabulary. Putting next to each other different agreements on linguistic and body units, testing what makes sense. Investigating and playing with communicational channel in between us, how a body language is documented, how it expands, how it is capable of creating or enhancing identities. To be an xpub means to speak/perform the xpub language?</p>
</div> </div>
<div class="two-col"> <div class="two-col">
{% for word in text {% for word in text

@ -6,7 +6,7 @@
<a href="/" ><h1 class="button">{{word}} <span class="close">x</span></h1></a> <a href="/" ><h1 class="button">{{word}} <span class="close">x</span></h1></a>
{% for file in wordmedia %} {% for file in wordmedia %}
<div class="two-col"> <div class="two-col">
<h2>Video {{file}}</h2> <!-- <h2>Video {{file}}</h2> -->
<!-- This file path might need to change --> <!-- This file path might need to change -->
<img src="{{path}}/{{file}}" /> <img src="{{path}}/{{file}}" />
{% for tag in media[file] {% for tag in media[file]

Loading…
Cancel
Save