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 html = require('choo/html')
|
||||||
const Component = require('choo/component')
|
const Component = require('choo/component')
|
||||||
const HydraSynth = require('hydra-synth')
|
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 {
|
module.exports = class Hydra extends Component {
|
||||||
constructor (id, state, emit) {
|
constructor (id, state, emit) {
|
||||||
@@ -10,10 +14,27 @@ module.exports = class Hydra extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load (element) {
|
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)
|
console.log(hydra)
|
||||||
this.hydra = hydra
|
this.hydra = hydra
|
||||||
osc().out()
|
osc().out()
|
||||||
|
|
||||||
|
pb.init(hydra.captureStream, {
|
||||||
|
server: window.location.origin,
|
||||||
|
room: 'iclc'
|
||||||
|
})
|
||||||
|
|
||||||
|
window.P5 = P5
|
||||||
|
window.pb = pb
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update (center) {
|
update (center) {
|
||||||
|
|||||||
@@ -2,22 +2,17 @@ const html = require('choo/html')
|
|||||||
const info = require('./info.js')
|
const info = require('./info.js')
|
||||||
const Hydra = require('./Hydra.js')
|
const Hydra = require('./Hydra.js')
|
||||||
const Editor = require('./EditorComponent.js')
|
const Editor = require('./EditorComponent.js')
|
||||||
module.exports = function mainView (state, emit) {
|
|
||||||
return html`
|
module.exports = function mainView(state, emit) {
|
||||||
<body>
|
return html`
|
||||||
|
<body>
|
||||||
<div id="hydra-ui">
|
<div id="hydra-ui">
|
||||||
|
${state.cache(Hydra, 'hydra-canvas').render(state, emit)}
|
||||||
${state.cache(Hydra, 'hydra-canvas').render(state, emit)}
|
<!---<canvas id="audio-canvas">
|
||||||
<!---<canvas id="audio-canvas">
|
</canvas>--->
|
||||||
</canvas>--->
|
</div>
|
||||||
</div>
|
|
||||||
${info(state, emit)}
|
${info(state, emit)}
|
||||||
${state.cache(Editor, 'editor').render(state, emit)}
|
${state.cache(Editor, 'editor').render(state, emit)}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
`
|
`
|
||||||
|
}
|
||||||
function onclick () {
|
|
||||||
emit('increment', 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user