Add support for leave call

This commit is contained in:
Robert Long 2021-07-27 13:26:18 -07:00
parent ed4ddc8e8c
commit d040a7b733
4 changed files with 81 additions and 19 deletions

View file

@ -140,7 +140,6 @@ export class ConferenceCallManager extends EventEmitter {
feed: null, feed: null,
call: null, call: null,
muted: true, muted: true,
calls: [],
}; };
this.participants = [this.localParticipant]; this.participants = [this.localParticipant];
@ -284,7 +283,7 @@ export class ConferenceCallManager extends EventEmitter {
_addCall(call, userId) { _addCall(call, userId) {
const existingCall = this.participants.find( 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) { if (existingCall) {
@ -299,7 +298,6 @@ export class ConferenceCallManager extends EventEmitter {
userId, userId,
feed: null, feed: null,
call, call,
calls: [call],
}); });
console.debug("_addCall", `Added new participant ${userId}`); console.debug("_addCall", `Added new participant ${userId}`);
@ -324,12 +322,15 @@ export class ConferenceCallManager extends EventEmitter {
let participantsChanged = false; let participantsChanged = false;
if (!this.localParticipant.feed && localFeeds.length > 0) { if (!this.localParticipant.feed && localFeeds.length > 0) {
this.localParticipant.call = call;
this.localParticipant.feed = localFeeds[0]; this.localParticipant.feed = localFeeds[0];
participantsChanged = true; participantsChanged = true;
} }
const remoteFeeds = call.getRemoteFeeds(); 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]) { if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) {
remoteParticipant.feed = remoteFeeds[0]; remoteParticipant.feed = remoteFeeds[0];
@ -349,7 +350,7 @@ export class ConferenceCallManager extends EventEmitter {
} }
const participantIndex = this.participants.findIndex( const participantIndex = this.participants.findIndex(
(p) => p.call === call (p) => !p.local && p.call === call
); );
if (participantIndex === -1) { if (participantIndex === -1) {
@ -358,6 +359,27 @@ export class ConferenceCallManager extends EventEmitter {
this.participants.splice(participantIndex, 1); 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"); this.emit("participants_changed");
}; };
@ -367,10 +389,11 @@ export class ConferenceCallManager extends EventEmitter {
`Call ${call.callId} replaced with ${newCall.callId}` `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.call = newCall;
remoteParticipant.calls.push(newCall);
newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall)); newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall));
newCall.on("hangup", () => this._onCallHangup(newCall)); newCall.on("hangup", () => this._onCallHangup(newCall));
@ -381,4 +404,18 @@ export class ConferenceCallManager extends EventEmitter {
this.emit("participants_changed"); 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");
}
} }

View file

@ -201,7 +201,17 @@ export function useVideoRoom(manager, roomId, timeout = 5000) {
}; };
}, [manager, roomId]); }, [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) { export function useRooms(manager) {

View file

@ -21,10 +21,8 @@ import { useVideoRoom } from "./ConferenceCallManagerHooks";
export function Room({ manager }) { export function Room({ manager }) {
const { roomId } = useParams(); const { roomId } = useParams();
const { loading, joined, room, participants, error, joinCall } = useVideoRoom( const { loading, joined, room, participants, error, joinCall, leaveCall } =
manager, useVideoRoom(manager, roomId);
roomId
);
return ( return (
<div className={styles.room}> <div className={styles.room}>
@ -61,34 +59,43 @@ export function Room({ manager }) {
{!loading && room && joined && participants.length > 0 && ( {!loading && room && joined && participants.length > 0 && (
<div className={styles.roomContainer}> <div className={styles.roomContainer}>
{participants.map((participant) => ( {participants.map((participant) => (
<Participant key={participant.userId} participant={participant} /> <Participant key={participant.userId} {...participant} />
))} ))}
</div> </div>
)} )}
{!loading && room && joined && (
<div className={styles.footer}>
<button className={styles.leaveButton} onClick={leaveCall}>
Leave Call
</button>
</div>
)}
</div> </div>
); );
} }
function Participant({ participant }) { function Participant({ userId, feed, muted, local }) {
const videoRef = useRef(); const videoRef = useRef();
useEffect(() => { useEffect(() => {
if (participant.feed) { if (feed) {
if (participant.muted) { if (muted) {
videoRef.current.muted = true; videoRef.current.muted = true;
} }
videoRef.current.srcObject = participant.feed.stream; videoRef.current.srcObject = feed.stream;
videoRef.current.play(); videoRef.current.play();
} else {
videoRef.current.srcObject = null;
} }
}, [participant.feed]); }, [feed]);
return ( return (
<div className={styles.participant}> <div className={styles.participant}>
<video ref={videoRef}></video> <video ref={videoRef}></video>
<div className={styles.participantLabel}> <div className={styles.participantLabel}>
<p> <p>
{participant.userId} {participant.local && "(You)"} {userId} {local && "(You)"}
</p> </p>
</div> </div>
</div> </div>

View file

@ -107,6 +107,14 @@ limitations under the License.
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
} }
.footer {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 64px;
}
@media(min-width: 800px) { @media(min-width: 800px) {
.roomContainer { .roomContainer {
flex-direction: row; flex-direction: row;