mirror of
https://github.com/hydra-synth/hydra.git
synced 2025-12-17 20:29:58 +01:00
added P5 and pb
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,138 +0,0 @@
|
||||
/* globals sessionStorage */
|
||||
// Extends rtc-patch-bay to include support for nicknames and persistent session storage
|
||||
|
||||
var PatchBay = require('./rtc-patch-bay.js')
|
||||
//var PatchBay = require('./../../../../rtc-patch-bay')
|
||||
var inherits = require('inherits')
|
||||
|
||||
var PBLive = function () {
|
||||
this.session = {}
|
||||
|
||||
// lookup tables for converting id to nickname
|
||||
this.nickFromId = {}
|
||||
this.idFromNick = {}
|
||||
|
||||
this.loadFromStorage()
|
||||
}
|
||||
// inherits from PatchBay module
|
||||
inherits(PBLive, PatchBay)
|
||||
|
||||
PBLive.prototype.init = function (stream, opts) {
|
||||
this.settings = {
|
||||
server: opts.server || 'https://patch-bay.glitch.me/',
|
||||
room: opts.room || 'patch-bay',
|
||||
stream: stream
|
||||
}
|
||||
|
||||
this.makeGlobal = opts.makeGlobal || true
|
||||
this.setPageTitle = opts.setTitle || true
|
||||
|
||||
if (this.session.id) this.settings.id = this.session.id
|
||||
|
||||
PatchBay.call(this, this.settings)
|
||||
|
||||
if (this.makeGlobal) window.pb = this
|
||||
|
||||
this.on('ready', () => {
|
||||
if (!this.nick) {
|
||||
if (this.session.nick) {
|
||||
this.setName(this.session.nick)
|
||||
} else {
|
||||
this.session.id = this.id
|
||||
this.setName(this.session.id)
|
||||
}
|
||||
}
|
||||
console.log('connected to server ' + this.settings.server + ' with name ' + this.settings.id)
|
||||
})
|
||||
// received a broadcast
|
||||
this.on('broadcast', this._processBroadcast.bind(this))
|
||||
this.on('new peer', this.handleNewPeer.bind(this))
|
||||
|
||||
window.onbeforeunload = () => {
|
||||
this.session.id = window.pb.id
|
||||
this.session.nick = this.nick
|
||||
sessionStorage.setItem('pb', JSON.stringify(this.session))
|
||||
}
|
||||
|
||||
var self = this
|
||||
this.on('stream', function (id, stream) {
|
||||
console.log('got stream!', id, stream)
|
||||
const video = document.createElement('video')
|
||||
if ('srcObject' in video) {
|
||||
video.srcObject = stream
|
||||
} else {
|
||||
// Avoid using this in new browsers, as it is going away.
|
||||
video.src = window.URL.createObjectURL(stream)
|
||||
}
|
||||
// video.src = window.URL.createObjectURL(stream)
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
// console.log("loaded meta22")
|
||||
video.play()
|
||||
self.video = video
|
||||
self.emit('got video', self.nickFromId[id], video)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
PBLive.prototype.loadFromStorage = function () {
|
||||
if (sessionStorage.getItem('pb') !== null) {
|
||||
this.session = JSON.parse(sessionStorage.getItem('pb'))
|
||||
}
|
||||
}
|
||||
|
||||
PBLive.prototype.initSource = function (nick, callback) {
|
||||
this.initConnectionFromId(this.idFromNick[nick], callback)
|
||||
// this.peers[this.idFromNick[nick]].streamCallback = callback
|
||||
}
|
||||
|
||||
// default nickname is just peer id.
|
||||
// to do: save nickname information between sessions
|
||||
PBLive.prototype.handleNewPeer = function (peer) {
|
||||
// console.log("new peer", peer)
|
||||
this.nickFromId[peer] = peer
|
||||
this.idFromNick[peer] = peer
|
||||
// console.log("THIS IS THE PEER", peer)
|
||||
// to do: only send to new peer, not to all
|
||||
if (this.nick) {
|
||||
this.broadcast({
|
||||
type: 'update-nick',
|
||||
id: this.id,
|
||||
nick: this.nick
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
PBLive.prototype.list = function () {
|
||||
var l = Object.keys(this.idFromNick)
|
||||
//console.log(l)
|
||||
return Object.keys(this.idFromNick)
|
||||
}
|
||||
|
||||
// choose an identifying name
|
||||
PBLive.prototype.setName = function (nick) {
|
||||
this.broadcast({
|
||||
type: 'update-nick',
|
||||
id: this.id,
|
||||
nick: nick,
|
||||
previous: this.nick
|
||||
})
|
||||
this.nick = nick
|
||||
if (this.setPageTitle) document.title = nick
|
||||
}
|
||||
|
||||
PBLive.prototype._processBroadcast = function (data) {
|
||||
if (data.type === 'update-nick') {
|
||||
if (data.previous !== data.nick) {
|
||||
delete this.idFromNick[this.nickFromId[data.id]]
|
||||
this.nickFromId[data.id] = data.nick
|
||||
this.idFromNick[data.nick] = data.id
|
||||
if (data.previous) {
|
||||
//console.log(data.previous + ' changed to ' + data.nick)
|
||||
} else {
|
||||
//console.log('connected to ' + data.nick)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// PBExtended.prototype.
|
||||
module.exports = PBLive
|
||||
@@ -1,251 +0,0 @@
|
||||
// Module for handling connections to multiple peers.
|
||||
|
||||
|
||||
var io = require('socket.io-client')
|
||||
var SimplePeer = require('simple-peer')
|
||||
var extend = Object.assign
|
||||
var events = require('events').EventEmitter
|
||||
var inherits = require('inherits')
|
||||
const shortid = require('shortid')
|
||||
|
||||
var PatchBay = function (options) {
|
||||
// connect to websocket signalling server. To DO: error validation
|
||||
this.signaller = io(options.server)
|
||||
|
||||
//assign unique id to this peer, or use id passed in
|
||||
|
||||
this.id = options.id || shortid.generate()
|
||||
|
||||
this.stream = options.stream || null
|
||||
|
||||
//options to be sent to simple peer
|
||||
this._peerOptions = options.peerOptions || {}
|
||||
this._room = options.room
|
||||
|
||||
|
||||
this.settings['shareMediaWhenRequested'] = true
|
||||
this.settings['shareMediaWhenInitiating'] = false
|
||||
this.settings['requestMediaWhenInitiating'] = true
|
||||
this.settings['autoconnect'] = false
|
||||
|
||||
//object containing ALL peers in room
|
||||
this.peers = {}
|
||||
|
||||
//object containing peers connected via webrtc
|
||||
this.rtcPeers = {}
|
||||
|
||||
// Handle events from signalling server
|
||||
this.signaller.on('ready', this._readyForSignalling.bind(this))
|
||||
// this.signaller.on('peers', )
|
||||
// this.signaller.on('signal', this._handleSignal.bind(this))
|
||||
this.signaller.on('message', this._handleMessage.bind(this))
|
||||
// Received message via websockets to all peers in room
|
||||
this.signaller.on('broadcast', this._receivedBroadcast.bind(this))
|
||||
|
||||
// emit 'join' event to signalling server
|
||||
this.signaller.emit('join', this._room, {uuid: this.id})
|
||||
|
||||
this.signaller.on('new peer', this._newPeer.bind(this))
|
||||
}
|
||||
// inherits from events module in order to trigger events
|
||||
inherits(PatchBay, events)
|
||||
|
||||
// send data to all connected peers via data channels
|
||||
PatchBay.prototype.sendToAll = function (data) {
|
||||
Object.keys(this.rtcPeers).forEach(function (id) {
|
||||
this.rtcPeers[id].send(data)
|
||||
}, this)
|
||||
}
|
||||
|
||||
// sends to peer specified b
|
||||
PatchBay.prototype.sendToPeer = function (peerId, data) {
|
||||
if (peerId in this.rtcPeers) {
|
||||
this.rtcPeers[peerId].send(data)
|
||||
}
|
||||
}
|
||||
|
||||
PatchBay.prototype.reinitAll = function(){
|
||||
Object.keys(this.rtcPeers).forEach(function (id) {
|
||||
this.reinitPeer(id)
|
||||
}.bind(this))
|
||||
// this._connectToPeers.bind(this)
|
||||
}
|
||||
|
||||
PatchBay.prototype.initRtcPeer = function(id, opts) {
|
||||
this.emit('new peer', {id: id})
|
||||
var newOptions = opts
|
||||
// console.log()
|
||||
if(this.iceServers) {
|
||||
opts['config'] = {
|
||||
iceServers: this.iceServers
|
||||
}
|
||||
}
|
||||
|
||||
if(opts.initiator === true) {
|
||||
if (this.stream != null) {
|
||||
if(this.settings.shareMediaWhenInitiating === true){
|
||||
newOptions.stream = this.stream
|
||||
}
|
||||
}
|
||||
if(this.settings.requestMediaWhenInitiating === true){
|
||||
newOptions.offerConstraints = {
|
||||
offerToReceiveVideo: true,
|
||||
offerToReceiveAudio: true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(this.settings.shareMediaWhenRequested === true){
|
||||
if (this.stream != null) {
|
||||
newOptions.stream = this.stream
|
||||
}
|
||||
}
|
||||
}
|
||||
var options = extend(this._peerOptions, newOptions)
|
||||
//console.log("OPTIONS", options)
|
||||
this.rtcPeers[id] = new SimplePeer(options)
|
||||
this._attachPeerEvents(this.rtcPeers[id], id)
|
||||
}
|
||||
|
||||
PatchBay.prototype.reinitRtcConnection = function(id, opts){
|
||||
// Because renegotiation is not implemeneted in SimplePeer, reinitiate connection when configuration has changed
|
||||
this.rtcPeers[id]._destroy(null, function(e){
|
||||
this.initRtcPeer(id, {
|
||||
stream: this.stream,
|
||||
initiator: true
|
||||
})
|
||||
}.bind(this))
|
||||
}
|
||||
// //new peer connected to signalling server
|
||||
PatchBay.prototype._newPeer = function (peer){
|
||||
// this.connectedIds.push(peer)
|
||||
|
||||
|
||||
// Configuration for specified peer.
|
||||
// Individual configuration controls whether will receive media from
|
||||
// and/or send media to a specific peer.
|
||||
|
||||
this.peers[peer] = {
|
||||
rtcPeer: null
|
||||
}
|
||||
|
||||
this.emit('new peer', peer)
|
||||
// this.emit('updated peer list', this.connectedIds)
|
||||
}
|
||||
// // Once the new peer receives a list of connected peers from the server,
|
||||
// // creates new simple peer object for each connected peer.
|
||||
PatchBay.prototype._readyForSignalling = function ({ peers, servers }) {
|
||||
// console.log("received peer list", _t, this.peers)
|
||||
|
||||
peers.forEach((peer) => {
|
||||
this._newPeer(peer)
|
||||
})
|
||||
|
||||
// if received ice and turn server information from signalling server, use in establishing
|
||||
if(servers) {
|
||||
this.iceServers = servers
|
||||
}
|
||||
// this.peers = peers
|
||||
this.emit('ready')
|
||||
}
|
||||
|
||||
// Init connection to RECEIVE video
|
||||
PatchBay.prototype.initConnectionFromId = function(id, callback){
|
||||
// console.log("initianing connection")
|
||||
if(id in this.rtcPeers){
|
||||
console.log("Already connected to..", id, this.rtcPeers)
|
||||
//if this peer was originally only sending a stream (not receiving), recreate connecting but this time two-way
|
||||
if(this.rtcPeers[id].initiator===false){
|
||||
this.reinitRtcConnection(id)
|
||||
} else {
|
||||
//already connected, do nothing
|
||||
|
||||
}
|
||||
} else {
|
||||
this.initRtcPeer(id, {
|
||||
initiator: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// receive signal from signalling server, forward to simple-peer
|
||||
PatchBay.prototype._handleMessage = function (data) {
|
||||
// if there is currently no peer object for a peer id, that peer is initiating a new connection.
|
||||
|
||||
if (data.type === 'signal'){
|
||||
this._handleSignal(data)
|
||||
} else {
|
||||
this.emit('message', data)
|
||||
}
|
||||
}
|
||||
// receive signal from signalling server, forward to simple-peer
|
||||
PatchBay.prototype._handleSignal = function (data) {
|
||||
// if there is currently no peer object for a peer id, that peer is initiating a new connection.
|
||||
if (!this.rtcPeers[data.id]) {
|
||||
// this.emit('new peer', data)
|
||||
// var options = extend({stream: this.stream}, this._peerOptions)
|
||||
// this.rtcPeers[data.id] = new SimplePeer(options)
|
||||
// this._attachPeerEvents(this.rtcPeers[data.id], data.id)
|
||||
|
||||
this.initRtcPeer(data.id, {initiator: false})
|
||||
}
|
||||
this.rtcPeers[data.id].signal(data.message)
|
||||
}
|
||||
// sendToAll send through rtc connections, whereas broadcast
|
||||
// send through the signalling server. Useful in cases where
|
||||
// not all peers are connected via webrtc with other peers
|
||||
PatchBay.prototype._receivedBroadcast = function(data) {
|
||||
//console.log("RECEIVED BROADCAST", data)
|
||||
this.emit('broadcast', data)
|
||||
}
|
||||
|
||||
//sends via signalling server
|
||||
PatchBay.prototype.broadcast = function (data) {
|
||||
this.signaller.emit('broadcast', data)
|
||||
}
|
||||
// handle events for each connected peer
|
||||
PatchBay.prototype._attachPeerEvents = function (p, _id) {
|
||||
p.on('signal', function (id, signal) {
|
||||
// console.log('signal', id, signal)
|
||||
// console.log("peer signal sending over sockets", id, signal)
|
||||
// this.signaller.emit('signal', {id: id, signal: signal})
|
||||
this.signaller.emit('message', {id: id, message: signal, type: 'signal'})
|
||||
}.bind(this, _id))
|
||||
|
||||
p.on('stream', function (id, stream) {
|
||||
this.rtcPeers[id].stream = stream
|
||||
// console.log('E: stream', id, stream)
|
||||
// console.log("received a stream", stream)
|
||||
this.emit('stream', id, stream)
|
||||
}.bind(this, _id))
|
||||
|
||||
p.on('connect', function (id) {
|
||||
// console.log("connected to ", id)
|
||||
this.emit('connect', id)
|
||||
}.bind(this, _id))
|
||||
|
||||
p.on('data', function (id, data) {
|
||||
// console.log('data', id)
|
||||
this.emit('data', {id: id, data: JSON.parse(data)})
|
||||
}.bind(this, _id))
|
||||
|
||||
p.on('close', function (id) {
|
||||
//console.log('CLOSED')
|
||||
delete (this.rtcPeers[id])
|
||||
this.emit('close', id)
|
||||
}.bind(this, _id))
|
||||
|
||||
p.on('error', function(e){
|
||||
console.warn("simple peer error", e)
|
||||
})
|
||||
}
|
||||
|
||||
PatchBay.prototype._destroy = function () {
|
||||
Object.values(this.rtcPeers).forEach( function (peer) {
|
||||
peer.destroy()
|
||||
})
|
||||
this.signaller.close()
|
||||
}
|
||||
|
||||
|
||||
module.exports = PatchBay
|
||||
@@ -1,6 +1,10 @@
|
||||
const html = require('choo/html')
|
||||
const Component = require('choo/component')
|
||||
const HydraSynth = require('hydra-synth')
|
||||
const P5 = require('./../lib/p5-wrapper.js')
|
||||
const PatchBay = require('./../lib/patch-bay/pb-live.js')
|
||||
|
||||
|
||||
|
||||
module.exports = class Hydra extends Component {
|
||||
constructor (id, state, emit) {
|
||||
@@ -10,10 +14,27 @@ module.exports = class Hydra extends Component {
|
||||
}
|
||||
|
||||
load (element) {
|
||||
const hydra = new HydraSynth({ detectAudio: true, canvas: element.querySelector("canvas")})
|
||||
let isIOS =
|
||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
|
||||
!window.MSStream;
|
||||
let precisionValue = isIOS ? 'highp' : 'mediump'
|
||||
|
||||
const pb = new PatchBay()
|
||||
|
||||
const hydra = new HydraSynth({ pb: pb, detectAudio: true, canvas: element.querySelector("canvas"), precision: precisionValue})
|
||||
console.log(hydra)
|
||||
this.hydra = hydra
|
||||
osc().out()
|
||||
|
||||
pb.init(hydra.captureStream, {
|
||||
server: window.location.origin,
|
||||
room: 'iclc'
|
||||
})
|
||||
|
||||
window.P5 = P5
|
||||
window.pb = pb
|
||||
|
||||
}
|
||||
|
||||
update (center) {
|
||||
|
||||
@@ -2,22 +2,17 @@ const html = require('choo/html')
|
||||
const info = require('./info.js')
|
||||
const Hydra = require('./Hydra.js')
|
||||
const Editor = require('./EditorComponent.js')
|
||||
module.exports = function mainView (state, emit) {
|
||||
|
||||
module.exports = function mainView(state, emit) {
|
||||
return html`
|
||||
<body>
|
||||
<div id="hydra-ui">
|
||||
|
||||
${state.cache(Hydra, 'hydra-canvas').render(state, emit)}
|
||||
<!---<canvas id="audio-canvas">
|
||||
</canvas>--->
|
||||
</div>
|
||||
${info(state, emit)}
|
||||
${state.cache(Editor, 'editor').render(state, emit)}
|
||||
|
||||
</body>
|
||||
`
|
||||
|
||||
function onclick () {
|
||||
emit('increment', 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user