diff --git a/src/ConferenceCallManager.js b/src/ConferenceCallManager.js index 06bd9f81..130f57f0 100644 --- a/src/ConferenceCallManager.js +++ b/src/ConferenceCallManager.js @@ -140,7 +140,6 @@ export class ConferenceCallManager extends EventEmitter { feed: null, call: null, muted: true, - calls: [], }; this.participants = [this.localParticipant]; @@ -284,7 +283,7 @@ export class ConferenceCallManager extends EventEmitter { _addCall(call, userId) { const existingCall = this.participants.find( - (p) => p.call && p.call.callId === call.callId + (p) => !p.local && p.call && p.call.callId === call.callId ); if (existingCall) { @@ -299,7 +298,6 @@ export class ConferenceCallManager extends EventEmitter { userId, feed: null, call, - calls: [call], }); console.debug("_addCall", `Added new participant ${userId}`); @@ -324,12 +322,15 @@ export class ConferenceCallManager extends EventEmitter { let participantsChanged = false; if (!this.localParticipant.feed && localFeeds.length > 0) { + this.localParticipant.call = call; this.localParticipant.feed = localFeeds[0]; participantsChanged = true; } const remoteFeeds = call.getRemoteFeeds(); - const remoteParticipant = this.participants.find((p) => p.call === call); + const remoteParticipant = this.participants.find( + (p) => !p.local && p.call === call + ); if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) { remoteParticipant.feed = remoteFeeds[0]; @@ -349,7 +350,7 @@ export class ConferenceCallManager extends EventEmitter { } const participantIndex = this.participants.findIndex( - (p) => p.call === call + (p) => !p.local && p.call === call ); if (participantIndex === -1) { @@ -358,6 +359,27 @@ export class ConferenceCallManager extends EventEmitter { this.participants.splice(participantIndex, 1); + if (this.localParticipant.call === call) { + const newLocalCallParticipant = this.participants.find( + (p) => !p.local && p.call + ); + + if (newLocalCallParticipant) { + const localFeeds = call.getLocalFeeds(); + + if (localFeeds.length > 0) { + this.localParticipant.call = call; + this.localParticipant.feed = localFeeds[0]; + } else { + this.localParticipant.call = null; + this.localParticipant.feed = null; + } + } else { + this.localParticipant.call = null; + this.localParticipant.feed = null; + } + } + this.emit("participants_changed"); }; @@ -367,10 +389,11 @@ export class ConferenceCallManager extends EventEmitter { `Call ${call.callId} replaced with ${newCall.callId}` ); - const remoteParticipant = this.participants.find((p) => p.call === call); + const remoteParticipant = this.participants.find( + (p) => !p.local && p.call === call + ); remoteParticipant.call = newCall; - remoteParticipant.calls.push(newCall); newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall)); newCall.on("hangup", () => this._onCallHangup(newCall)); @@ -381,4 +404,18 @@ export class ConferenceCallManager extends EventEmitter { this.emit("participants_changed"); }; + + leaveCall() { + for (const participant of this.participants) { + if (!participant.local && participant.call) { + participant.call.hangup("user_hangup", false); + } + } + + this.joined = false; + this.participants = [this.localParticipant]; + this.localParticipant.feed = null; + this.localParticipant.call = null; + this.emit("participants_changed"); + } } diff --git a/src/ConferenceCallManagerHooks.js b/src/ConferenceCallManagerHooks.js index 9bdd7dce..b8381002 100644 --- a/src/ConferenceCallManagerHooks.js +++ b/src/ConferenceCallManagerHooks.js @@ -201,7 +201,17 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { }; }, [manager, roomId]); - return { loading, joined, room, participants, error, joinCall }; + const leaveCall = useCallback(() => { + manager.leaveCall(); + + setState((prevState) => ({ + ...prevState, + participants: manager.participants, + joined: false, + })); + }, [manager]); + + return { loading, joined, room, participants, error, joinCall, leaveCall }; } export function useRooms(manager) { diff --git a/src/Room.jsx b/src/Room.jsx index 1a26a228..d5a2d346 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -21,10 +21,8 @@ import { useVideoRoom } from "./ConferenceCallManagerHooks"; export function Room({ manager }) { const { roomId } = useParams(); - const { loading, joined, room, participants, error, joinCall } = useVideoRoom( - manager, - roomId - ); + const { loading, joined, room, participants, error, joinCall, leaveCall } = + useVideoRoom(manager, roomId); return (
@@ -61,34 +59,43 @@ export function Room({ manager }) { {!loading && room && joined && participants.length > 0 && (
{participants.map((participant) => ( - + ))}
)} + {!loading && room && joined && ( +
+ +
+ )}
); } -function Participant({ participant }) { +function Participant({ userId, feed, muted, local }) { const videoRef = useRef(); useEffect(() => { - if (participant.feed) { - if (participant.muted) { + if (feed) { + if (muted) { videoRef.current.muted = true; } - videoRef.current.srcObject = participant.feed.stream; + videoRef.current.srcObject = feed.stream; videoRef.current.play(); + } else { + videoRef.current.srcObject = null; } - }, [participant.feed]); + }, [feed]); return (

- {participant.userId} {participant.local && "(You)"} + {userId} {local && "(You)"}

diff --git a/src/Room.module.css b/src/Room.module.css index 32812192..d39c873d 100644 --- a/src/Room.module.css +++ b/src/Room.module.css @@ -107,6 +107,14 @@ limitations under the License. background: rgba(0, 0, 0, 0.2); } +.footer { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 64px; +} + @media(min-width: 800px) { .roomContainer { flex-direction: row;