Skip to content

Commit 447dd99

Browse files
authored
Merge pull request #335 from Glimesh/multistream-player
Add Multistream player with refreshed UI
2 parents e0fa9ac + 507bdf4 commit 447dd99

16 files changed

Lines changed: 536 additions & 113 deletions

web/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
"private": true,
55
"type": "module",
66
"dependencies": {
7+
"@heroicons/react": "^2.2.0",
78
"@web3-storage/parse-link-header": "^3.1.0",
89
"react": "^19.0.0",
910
"react-dom": "^19.0.0"
1011
},
1112
"scripts": {
1213
"start": "vite",
14+
"host": "vite --host",
1315
"build": "vite build",
1416
"lint": "eslint ./src --max-warnings 0"
1517
},

web/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React from 'react'
22
import { Routes, Route } from 'react-router-dom'
33

4-
import RootWrapper from './components/rootWrapper/rootWrapper'
5-
import Frontpage from "./components/selection/frontpage";
64
import BrowserBroadcaster from "./components/broadcast/Broadcast";
75
import PlayerPage from "./components/player/PlayerPage";
6+
import RootWrapper from "./components/rootWrapper/RootWrapper";
7+
import Frontpage from "./components/selection/Frontpage";
88

99
function App() {
1010
return (

web/src/components/broadcast/Broadcast.tsx

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, {useEffect, useRef, useState} from 'react'
22
import {useLocation} from 'react-router-dom'
3-
import ErrorHeader from '../error-header/errorHeader'
3+
import ErrorHeader from '../error-header/ErrorHeader'
4+
import {useNavigate} from 'react-router-dom'
45

56
const mediaOptions = {
67
audio: true,
@@ -28,24 +29,36 @@ function getMediaErrorMessage(value: ErrorMessageEnum): string {
2829

2930
function BrowserBroadcaster() {
3031
const videoRef = useRef<HTMLVideoElement>(null)
32+
33+
//TODO: Use prop instead of location
3134
const location = useLocation()
35+
const navigate = useNavigate();
3236
const [mediaAccessError, setMediaAccessError] = useState<ErrorMessageEnum | null>(null)
3337
const [publishSuccess, setPublishSuccess] = useState(false)
34-
const [useDisplayMedia, setUseDisplayMedia] = useState(false)
38+
const [useDisplayMedia, setUseDisplayMedia] = useState<"Screen" | "Webcam" | "None">("None");
39+
const [peerConnection, _] = useState<RTCPeerConnection>(new RTCPeerConnection());
3540
const [peerConnectionDisconnected, setPeerConnectionDisconnected] = useState(false)
3641

3742
const apiPath = import.meta.env.VITE_API_PATH;
3843

44+
const endStream = () => {
45+
navigate('/')
46+
}
47+
3948
useEffect(() => {
40-
const peerConnection = new RTCPeerConnection()
49+
if (useDisplayMedia === "None" || !peerConnection) {
50+
return;
51+
}
52+
4153
let stream: MediaStream | undefined = undefined;
4254

4355
if (!navigator.mediaDevices) {
44-
setMediaAccessError(ErrorMessageEnum.NoMediaDevices);
56+
setMediaAccessError(() => ErrorMessageEnum.NoMediaDevices);
57+
setUseDisplayMedia(() => "None")
4558
return
4659
}
4760

48-
const mediaPromise = useDisplayMedia ?
61+
const mediaPromise = useDisplayMedia == "Screen" ?
4962
navigator.mediaDevices.getDisplayMedia(mediaOptions) :
5063
navigator.mediaDevices.getUserMedia(mediaOptions)
5164

@@ -91,6 +104,7 @@ function BrowserBroadcaster() {
91104
peerConnection.oniceconnectionstatechange = () => {
92105
if (peerConnection.iceConnectionState === 'connected' || peerConnection.iceConnectionState === 'completed') {
93106
setPublishSuccess(true)
107+
setMediaAccessError(() => null)
94108
setPeerConnectionDisconnected(false)
95109
} else if (peerConnection.iceConnectionState === 'disconnected' || peerConnection.iceConnectionState === 'failed') {
96110
setPublishSuccess(false)
@@ -102,7 +116,7 @@ function BrowserBroadcaster() {
102116
.createOffer()
103117
.then(offer => {
104118
peerConnection.setLocalDescription(offer)
105-
.catch((err) => console.error(err));
119+
.catch((err) => console.error("SetLocalDescription", err));
106120

107121
fetch(`${apiPath}/whip`, {
108122
method: 'POST',
@@ -117,10 +131,13 @@ function BrowserBroadcaster() {
117131
sdp: answer,
118132
type: 'answer'
119133
})
120-
.catch((err) => console.error(err))
134+
.catch((err) => console.error("SetRemoveDescription",err))
121135
})
122136
})
123-
}, setMediaAccessError)
137+
}, (reason: ErrorMessageEnum) => {
138+
setMediaAccessError(() => reason)
139+
setUseDisplayMedia("None");
140+
})
124141

125142
return function cleanup() {
126143
peerConnection.close()
@@ -147,12 +164,28 @@ function BrowserBroadcaster() {
147164
className='w-full h-full'
148165
/>
149166

150-
<button
151-
onClick={() => setUseDisplayMedia(!useDisplayMedia)}
152-
className="appearance-none border w-full mt-5 py-2 px-3 leading-tight focus:outline-hidden focus:shadow-outline bg-gray-700 border-gray-700 text-white rounded-sm shadow-md placeholder-gray-200">
153-
{!useDisplayMedia && <> Publish Screen/Window/Tab instead </>}
154-
{useDisplayMedia && <> Publish Webcam instead </>}
155-
</button>
167+
<div className="flex flex-row gap-2">
168+
<button
169+
onClick={() => setUseDisplayMedia("Screen")}
170+
className="appearance-none border w-full mt-5 py-2 px-3 leading-tight focus:outline-hidden focus:shadow-outline bg-blue-900 hover:bg-blue-800 border-gray-700 text-white rounded-sm shadow-md placeholder-gray-200">
171+
Publish Screen/Window/Tab
172+
</button>
173+
<button
174+
onClick={() => setUseDisplayMedia("Webcam")}
175+
className="appearance-none border w-full mt-5 py-2 px-3 leading-tight focus:outline-hidden focus:shadow-outline bg-blue-900 hover:bg-blue-800 border-gray-700 text-white rounded-sm shadow-md placeholder-gray-200">
176+
Publish Webcam
177+
</button>
178+
</div>
179+
180+
{publishSuccess && (
181+
<div>
182+
<button
183+
onClick={endStream}
184+
className="appearance-none border w-full mt-5 py-2 px-3 leading-tight focus:outline-hidden focus:shadow-outline bg-red-900 hover:bg-red-800 border-gray-700 text-white rounded-sm shadow-md placeholder-gray-200">
185+
End stream
186+
</button>
187+
</div>
188+
)}
156189
</div>
157190
)
158191
}
File renamed without changes.

0 commit comments

Comments
 (0)