Skip to content

Commit

Permalink
add POC of local streaming
Browse files Browse the repository at this point in the history
  • Loading branch information
FrederickEngelhardt committed Nov 22, 2021
1 parent 725ef4d commit 5b8e4b9
Show file tree
Hide file tree
Showing 11 changed files with 600 additions and 244 deletions.
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@
"express": "^4.17.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "6",
"react-scripts": "4.0.3",
"socket.io": "^4.4.0",
"socket.io-client": "^4.4.0",
"socket.io-p2p": "^2.2.0",
"typescript": "^4.5.2",
"web-vitals": "^1.0.1",
"webrtc-adapter": "^8.1.0"
},
"scripts": {
"start": "react-scripts start",
"start-2": "PORT=3001 react-scripts start",
"start": "TSC_COMPILE_ON_ERROR=true react-scripts start",
"start-2": "PORT=3001 yarn start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand All @@ -43,6 +45,8 @@
]
},
"devDependencies": {
"@types/react": "^17.0.35",
"@types/socket.io-p2p": "^2.2.2",
"nodemon": "^2.0.15"
}
}
24 changes: 20 additions & 4 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
const express = require('express')
const app = express()
const { Server } = require('socket.io')

let broadcaster
const port = 4000
const port = 3001

const http = require('http')
const server = http.createServer(app)

const io = require('socket.io')(server)
app.use(express.static(__dirname + '/public'))
const io = new Server(server, {
cors: {
origin: ['http://192.168.1.191:3000', 'http://localhost:3000', '*'],
credentials: true,
// allowedHeaders: ['my-custom-header'],
// credentials: true,
},
allowEIO3: true,
})

// app.use(express.static(__dirname + '/public'))

io.sockets.on('error', (e) => console.log(e))
io.sockets.on('connection', (socket) => {
console.log('connected', socket.id)
socket.on('broadcaster', () => {
broadcaster = socket.id
socket.broadcast.emit('broadcaster')
})
socket.on('watcher', () => {
console.log('watcher', socket.id)
socket.to(broadcaster).emit('watcher', socket.id)
})
socket.on('offer', (id, message) => {
Expand All @@ -26,10 +38,14 @@ io.sockets.on('connection', (socket) => {
socket.to(id).emit('answer', socket.id, message)
})
socket.on('candidate', (id, message) => {
console.log('candidate')
socket.to(id).emit('candidate', socket.id, message)
})
socket.on('disconnect', () => {
socket.to(broadcaster).emit('disconnectPeer', socket.id)
})
})
server.listen(port, () => console.log(`Server is running on port ${port}`))

server.listen(port, '192.168.1.191', () =>
console.log(`Server is running on port ${port}`)
)
238 changes: 9 additions & 229 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,237 +1,17 @@
/* eslint-disable no-undef */
import logo from './logo.svg'
import * as React from 'react'
import { Routes, Route, Link } from 'react-router-dom'
import './App.css'
import { useEffect, useRef, useState } from 'react'
import adapter from 'webrtc-adapter'
import { io } from 'socket.io-client'
import P2P from 'socket.io-p2p'

const socket = io('http://localhost:3031')
// const p2p = new P2P(socket, { useSockets: false })

// socket.on('connect', () => {
// console.log(socket.id) // ojIckSD2jqNzOqIrAGzL
// })
// p2p.on('peer-msg', function (data) {
// console.log('From a peer %s', data)
// })

// p2p.emit('peer-msg', 'hello world')
// const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }

// const peerConnection = new RTCPeerConnection(configuration)
// const signalingChannel = new SignalingChannel(remoteClientId)
const configuration = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
}

const App = () => {
const [streamUrl, setStreamUrl] = useState('')
const [peerStream, setPeerStream] = useState(null)
const startButton = useRef()
const peerConnection = useRef()
const remoteVideo = useRef()
const start = () => {
navigator.mediaDevices
.getDisplayMedia({ video: true })
.then(handleSuccess, handleError)
}

const handleSuccess = async (stream) => {
startButton.current.disabled = true
// const video = document.querySelector('video')
remoteVideo.current.srcObject = stream
// setPeerStream(stream)
stream.getTracks().forEach((track) => {
peerConnection.current.addTrack(track, stream)
})

socket.emit('stream', stream)

// demonstrates how to detect that the user has stopped
// sharing the screen via the browser UI.
// stream.getVideoTracks()[0].addEventListener('ended', () => {
// errorMsg('The user has ended sharing the screen')
// startButton.current.disabled = false
// })
}

const errorMsg = (msg, error) => {
const errorElement = document.querySelector('#errorMsg')
errorElement.innerHTML += `<p>${msg}</p>`
if (typeof error !== 'undefined') {
console.error(error)
}
}

const handleError = (error) => {
errorMsg(`getDisplayMedia error: ${error.name}`, error)
}

useEffect(() => {
// Polyfill in Firefox.
// See https://blog.mozilla.org/webrtc/getdisplaymedia-now-available-in-adapter-js/
if (!adapter) return
// initializeChannel()
// connect()

socket.on('offer-client', async (offer) => {
console.log('received offer')
if (!peerConnection.current) {
peerConnection.current = new RTCPeerConnection(configuration)
createPeerConnectionListeners()
}

peerConnection.current.setRemoteDescription(
new RTCSessionDescription(offer)
)
const answer = await peerConnection.current.createAnswer()
await peerConnection.current.setLocalDescription(answer)
socket.emit('answer', answer)
})

socket.on('stream-client', (stream) => {
console.log('STREAM')
console.log(stream)
// remoteVideo.current.srcObject = stream
})

socket.on('answer-client', async (answer) => {
console.log('received answer-client')
const remoteDesc = new RTCSessionDescription(answer)
await peerConnection.current.setRemoteDescription(remoteDesc)
const getIce = peerConnection.current.canTrickleIceCandidates

console.log(
'can trickle',
getIce,
peerConnection,
peerConnection.current.connectionState
)
})

socket.on('ice-candidate-client', async (iceCandidate) => {
console.log('ICE CANDIDATE', iceCandidate)
if (iceCandidate) {
try {
await peerConnection.current.addIceCandidate(iceCandidate)
console.log('added ice candidate')
} catch (e) {
console.error('Error adding received ice candidate', e)
}
}
})

if (adapter.browserDetails.browser === 'firefox') {
adapter.browserShim.shimGetDisplayMedia(window, 'screen')
}

if (navigator.mediaDevices && 'getDisplayMedia' in navigator.mediaDevices) {
startButton.current.disabled = false
} else {
errorMsg('getDisplayMedia is not supported')
}
}, [])

const makeCall = async () => {
peerConnection.current = new RTCPeerConnection(configuration)
socket.emit('answer-client', async (answer) => {
if (answer) {
const remoteDesc = new RTCSessionDescription(answer)
await peerConnection.current.setRemoteDescription(remoteDesc)
}
})
const offer = await peerConnection.current.createOffer()
await peerConnection.current.setLocalDescription(offer)
socket.emit('offer', offer)

createPeerConnectionListeners()
}

const createPeerConnectionListeners = () => {
peerConnection.current.onicecandidate = (event) => {
console.log('got ice', 'calling ice')
if (event.candidate) {
socket.emit('ice-candidate', event.candidate)
}
}
// peerConnection.current.addEventListener('icecandidate', (event) => {
// console.log('got ice', 'calling ice')
// if (event.candidate) {
// socket.emit('ice-candidate', event.candidate)
// }
// })

// peerConnection.current.addEventListener()

peerConnection.current.addEventListener('icecandidateerror', (event) => {
if (peerConnection.current.connectionState === 'connected') {
// Peers connected!
console.log('success')
}

console.log('peerconnect', event)
})
peerConnection.current.addEventListener(
'connectionstatechange',
(event) => {
if (peerConnection.current.connectionState === 'connected') {
// Peers connected!
console.log('success')
}

console.log('peerconnect', event)
}
)
}

useEffect(() => {
if (!peerConnection.current) return

getRemoteStream()
}, [peerConnection])

const getRemoteStream = () => {
const remoteStream = new MediaStream()
remoteVideo.current.srcObject = remoteStream

peerConnection.current.addEventListener('track', async (event) => {
console.log('track event', event.track)
remoteStream.addTrack(event.track, remoteStream)
})
}

const handleStreamUrlChange = (event) => {
setStreamUrl(event.target.value)
}

const getStreamUrl = () => {}
import Broadcaster from './components/Broadcaster'
import Reciever from './components/Receiver'

function App() {
return (
<div className='App'>
<input
value={streamUrl}
onChange={handleStreamUrlChange}
onSubmit={getStreamUrl}
/>
<button ref={startButton} onClick={start}>
start
</button>
<button onClick={makeCall}>get remote stream</button>
<video
ref={remoteVideo}
className='player'
style={{
width: '100%',
height: '100%',
borderColor: 'blue',
borderWidth: '2px',
}}
autoPlay
playsInline
muted
></video>
<div id='errorMsg'></div>
<Routes>
<Route path='/' element={<Reciever />} />
<Route path='broadcast' element={<Broadcaster />} />
</Routes>
</div>
)
}
Expand Down
Loading

0 comments on commit 5b8e4b9

Please sign in to comment.