|
|
|
|
|
|
|
|
online: [], |
|
|
online: [], |
|
|
posts: [], |
|
|
posts: [], |
|
|
rpcs: {}, |
|
|
rpcs: {}, |
|
|
media: {}, |
|
|
|
|
|
|
|
|
streams: {}, |
|
|
options: {}, |
|
|
options: {}, |
|
|
} |
|
|
} |
|
|
const markedOptions = { |
|
|
const markedOptions = { |
|
|
|
|
|
|
|
|
if(State.username === username) { |
|
|
if(State.username === username) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
const myStream = State.media[State.username] |
|
|
|
|
|
|
|
|
const myStream = State.streams[State.username] |
|
|
if(!State.rpcs[username] && myStream) { |
|
|
if(!State.rpcs[username] && myStream) { |
|
|
const rpc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}) |
|
|
const rpc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.sipgate.net:3478'}]}) |
|
|
myStream.getTracks().forEach(track => rpc.addTrack(track, myStream)) |
|
|
myStream.getTracks().forEach(track => rpc.addTrack(track, myStream)) |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
rpc.ontrack = (e) => { |
|
|
rpc.ontrack = (e) => { |
|
|
State.media[username] = e.streams[0] |
|
|
|
|
|
|
|
|
State.streams[username] = e.streams[0] |
|
|
m.redraw() |
|
|
m.redraw() |
|
|
} |
|
|
} |
|
|
rpc.onclose = (e) => { |
|
|
rpc.onclose = (e) => { |
|
|
|
|
|
|
|
|
rpc.addIceCandidate(candidate) |
|
|
rpc.addIceCandidate(candidate) |
|
|
} |
|
|
} |
|
|
else if(message.value.type === 'stop') { |
|
|
else if(message.value.type === 'stop') { |
|
|
if(State.media[message.source]) { |
|
|
|
|
|
State.media[message.source].getTracks().map(track => track.stop()) |
|
|
|
|
|
delete State.media[message.source] |
|
|
|
|
|
|
|
|
if(State.streams[message.source]) { |
|
|
|
|
|
State.streams[message.source].getTracks().map(track => track.stop()) |
|
|
|
|
|
delete State.streams[message.source] |
|
|
} |
|
|
} |
|
|
if(State.rpcs[message.source]) { |
|
|
if(State.rpcs[message.source]) { |
|
|
State.rpcs[message.source].close() |
|
|
State.rpcs[message.source].close() |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
const Video = { |
|
|
const Video = { |
|
|
keepRatio: {observe: () => {}}, |
|
|
keepRatio: {observe: () => {}}, |
|
|
appendStream: ({username, stream}) => ({dom}) => { |
|
|
|
|
|
|
|
|
appendStream: ({username}) => ({dom}) => { |
|
|
dom.autoplay = true |
|
|
dom.autoplay = true |
|
|
dom.muted = (username === State.username) |
|
|
dom.muted = (username === State.username) |
|
|
dom.srcObject = stream |
|
|
|
|
|
|
|
|
dom.srcObject = State.streams[username] |
|
|
}, |
|
|
}, |
|
|
view({attrs}) { |
|
|
view({attrs}) { |
|
|
const classList = VideoOptions.getClassListFor(attrs.username) |
|
|
const classList = VideoOptions.getClassListFor(attrs.username) |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
turnOn: async () => { |
|
|
turnOn: async () => { |
|
|
const media = await getSelectedMedia() |
|
|
const media = await getSelectedMedia() |
|
|
State.media[State.username] = media |
|
|
|
|
|
|
|
|
State.streams[State.username] = media |
|
|
wire({kind: 'peerInfo', value: {type: 'request'}}) |
|
|
wire({kind: 'peerInfo', value: {type: 'request'}}) |
|
|
m.redraw() |
|
|
m.redraw() |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
view() { |
|
|
view() { |
|
|
return m('.media', |
|
|
return m('.media', |
|
|
m('.media-settings', |
|
|
m('.media-settings', |
|
|
State.media[State.username] |
|
|
|
|
|
|
|
|
State.streams[State.username] |
|
|
? m('button', {onclick: Media.turnOff}, 'turn off') |
|
|
? m('button', {onclick: Media.turnOff}, 'turn off') |
|
|
: m('button', {onclick: Media.turnOn}, 'turn on') |
|
|
: m('button', {onclick: Media.turnOn}, 'turn on') |
|
|
, |
|
|
, |
|
|
|
|
|
|
|
|
m('label', m('input#mute-check', {type: 'checkbox'}), 'mute'), |
|
|
m('label', m('input#mute-check', {type: 'checkbox'}), 'mute'), |
|
|
), |
|
|
), |
|
|
m('.videos', |
|
|
m('.videos', |
|
|
Object.entries(State.media).map(([username, stream]) => |
|
|
|
|
|
m(Video, {username, stream}) |
|
|
|
|
|
|
|
|
Object.keys(State.streams).map((username) => |
|
|
|
|
|
m(Video, {username}) |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
) |
|
|
) |