From 6a79786990bbfb48c8765785811e60f5ba8e89e4 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Thu, 24 Oct 2024 00:32:28 +0300 Subject: [PATCH 01/11] Set the stream name as subscriber id in play only mode --- react/src/pages/AntMedia.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/react/src/pages/AntMedia.js b/react/src/pages/AntMedia.js index 15da46f3..ed744286 100644 --- a/react/src/pages/AntMedia.js +++ b/react/src/pages/AntMedia.js @@ -1013,6 +1013,12 @@ function AntMedia(props) { handlePublish(generatedStreamId, token, subscriberId, subscriberCode); } + // if the user is in playOnly mode, we will set the subscriberId as the streamName + // so we can get the player list from the server + if (isPlayOnly) { + subscriberId = streamName; + } + webRTCAdaptor?.play(roomName, token, roomName, null, subscriberId, subscriberCode, '{}', role); } From a9e81a4dddfb198fa86be1b8522b31d014ebf4bd Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 01:38:40 +0300 Subject: [PATCH 02/11] Join the room in play only mode --- react/src/pages/AntMedia.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/react/src/pages/AntMedia.js b/react/src/pages/AntMedia.js index 4c12fe54..51f7fbc7 100644 --- a/react/src/pages/AntMedia.js +++ b/react/src/pages/AntMedia.js @@ -1012,10 +1012,10 @@ function AntMedia(props) { handlePublish(generatedStreamId, token, subscriberId, subscriberCode); } - // if the user is in playOnly mode, we will set the subscriberId as the streamName - // so we can get the player list from the server + // if the user is in playOnly mode, it will join the room with the generated stream id + // so we can get the list of play only participants in the room if (isPlayOnly) { - subscriberId = streamName; + webRTCAdaptor?.joinRoom(roomName, generatedStreamId); } webRTCAdaptor?.play(roomName, token, roomName, null, subscriberId, subscriberCode, '{}', role); From f97741de9175b290c54457c296e74a3004e17b57 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 07:35:29 +0300 Subject: [PATCH 03/11] Add mechanism to get and display play only user's list --- react/src/Components/ParticipantTab.js | 265 +++++++++++++++---------- react/src/pages/AntMedia.js | 19 +- 2 files changed, 171 insertions(+), 113 deletions(-) diff --git a/react/src/Components/ParticipantTab.js b/react/src/Components/ParticipantTab.js index 1c6d39eb..83646982 100644 --- a/react/src/Components/ParticipantTab.js +++ b/react/src/Components/ParticipantTab.js @@ -3,11 +3,11 @@ import Stack from "@mui/material/Stack"; import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; import Button from "@mui/material/Button"; -import {styled, useTheme} from "@mui/material/styles"; +import { styled, useTheme } from "@mui/material/styles"; import { SvgIcon } from "./SvgIcon"; import { ConferenceContext } from "pages/AntMedia"; -import {CircularProgress} from "@mui/material"; -import {WebinarRoles} from "../WebinarRoles"; +import { CircularProgress } from "@mui/material"; +import { WebinarRoles } from "../WebinarRoles"; const ParticipantName = styled(Typography)(({ theme }) => ({ color: theme.palette.textColor, @@ -26,126 +26,173 @@ function ParticipantTab(props) { const theme = useTheme(); const getAdminButtons = (streamId, assignedVideoCardId) => { - let publishStreamId = (streamId === "localVideo") ? conference.publishStreamId : streamId; - let role = conference.allParticipants[publishStreamId]?.role; + let publishStreamId = streamId === "localVideo" ? conference.publishStreamId : streamId; + let role = conference.allParticipants[publishStreamId]?.role; return ( -
- {( role === WebinarRoles.ActiveHost || role === WebinarRoles.ActiveSpeaker || role === WebinarRoles.ActiveTempListener ) && conference?.isAdmin === true ? ( - { conference?.makeParticipantUndoPresenter(publishStreamId) } - } - > - { conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? : - } - - ) : null} - { ( role === WebinarRoles.Host || role === WebinarRoles.Speaker || role === WebinarRoles.TempListener ) && conference?.isAdmin === true ?( - { conference?.makeParticipantPresenter(publishStreamId) } - } - > - {/* this icon for publish speaker */} - { conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? : - } - - ) : null} - { ( role === WebinarRoles.TempListener || role === WebinarRoles.ActiveTempListener ) && conference?.isAdmin === true && assignedVideoCardId !== 'localVideo' ? ( - conference?.makeListenerAgain(publishStreamId)} - > - - - ) : null} -
+
+ {(role === WebinarRoles.ActiveHost || + role === WebinarRoles.ActiveSpeaker || + role === WebinarRoles.ActiveTempListener) && + conference?.isAdmin === true ? ( + { + conference?.makeParticipantUndoPresenter(publishStreamId); + }} + > + {conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? ( + + ) : ( + + )} + + ) : null} + {(role === WebinarRoles.Host || + role === WebinarRoles.Speaker || + role === WebinarRoles.TempListener) && + conference?.isAdmin === true ? ( + { + conference?.makeParticipantPresenter(publishStreamId); + }} + > + {conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? ( + + ) : ( + + )} + + ) : null} + {(role === WebinarRoles.TempListener || role === WebinarRoles.ActiveTempListener) && + conference?.isAdmin === true && + assignedVideoCardId !== "localVideo" ? ( + conference?.makeListenerAgain(publishStreamId)} + > + + + ) : null} +
); - } + }; const getParticipantItem = (streamId, name, assignedVideoCardId) => { if (streamId === conference?.publishStreamId) { assignedVideoCardId = "localVideo"; } return ( - - - {name} - - -
- {(typeof conference.allParticipants[streamId]?.isPinned !== "undefined") && (conference.allParticipants[streamId]?.isPinned === true) ? ( - { - conference.pinVideo(streamId); - }} - > - - - ) : ( - { - conference.pinVideo(streamId); - }} - > - - - )} -
- {process.env.REACT_APP_PARTICIPANT_TAB_ADMIN_MODE_ENABLED === "true" && conference?.isAdmin === true ? ( - getAdminButtons(streamId, assignedVideoCardId) - ) : null} + + + {name} + + +
+ {typeof conference.allParticipants[streamId]?.isPinned !== "undefined" && + conference.allParticipants[streamId]?.isPinned === true ? ( + { + conference.pinVideo(streamId); + }} + > + + + ) : ( + { + conference.pinVideo(streamId); + }} + > + + + )} +
+ {process.env.REACT_APP_PARTICIPANT_TAB_ADMIN_MODE_ENABLED === "true" && + conference?.isAdmin === true ? ( + getAdminButtons(streamId, assignedVideoCardId) + ) : null} +
-
+ - - ); + ); }; - return ( -
- - - - - {Object.keys(conference.allParticipants).length} - + const getPlayOnlyParticipantItem = (streamId) => { + return ( + + + {streamId} + - {conference.isPlayOnly === false ? getParticipantItem(conference.publishStreamId, "You") : ""} - {Object.entries(conference.allParticipants).map(([streamId, broadcastObject]) => { - if (conference.publishStreamId !== streamId) { - var assignedVideoCardId = conference?.videoTrackAssignments?.find(vta => vta.streamId === streamId)?.videoLabel; - return getParticipantItem(streamId, broadcastObject.name, assignedVideoCardId); - } else { - return ""; - } - })} - -
- ); + ); + }; + return ( +
+ + + + + {Object.keys(conference.allParticipants).length} + + + {conference.isPlayOnly === false ? getParticipantItem(conference.publishStreamId, "You") : ""} + {Object.entries(conference.allParticipants).map(([streamId, broadcastObject]) => { + if (conference.publishStreamId !== streamId) { + var assignedVideoCardId = conference?.videoTrackAssignments?.find((vta) => vta.streamId === streamId)?.videoLabel; + return getParticipantItem(streamId, broadcastObject.name, assignedVideoCardId); + } else { + return ""; + } + })} + + + Play Only Participants + + + + {conference.playOnlyParticipants.length} + + + {conference.playOnlyParticipants.map((streamId) => { + if (conference.publishStreamId !== streamId) { + return getPlayOnlyParticipantItem(streamId); + } else { + return ""; + } + })} + +
+ ); } -export default ParticipantTab; +export default ParticipantTab; \ No newline at end of file diff --git a/react/src/pages/AntMedia.js b/react/src/pages/AntMedia.js index 51f7fbc7..2409256a 100644 --- a/react/src/pages/AntMedia.js +++ b/react/src/pages/AntMedia.js @@ -385,6 +385,8 @@ function AntMedia(props) { */ const [allParticipants, setAllParticipants] = useState({}); + const [playOnlyParticipants, setPlayOnlyParticipants] = useState([]); + const [audioTracks, setAudioTracks] = useState([]); const [talkers, setTalkers] = useState([]); @@ -1014,9 +1016,7 @@ function AntMedia(props) { // if the user is in playOnly mode, it will join the room with the generated stream id // so we can get the list of play only participants in the room - if (isPlayOnly) { - webRTCAdaptor?.joinRoom(roomName, generatedStreamId); - } + webRTCAdaptor?.joinRoom(roomName, generatedStreamId); webRTCAdaptor?.play(roomName, token, roomName, null, subscriberId, subscriberCode, '{}', role); } @@ -1025,6 +1025,7 @@ function AntMedia(props) { if (videoTrackAssignmentsIntervalJob === null) { videoTrackAssignmentsIntervalJob = setInterval(() => { webRTCAdaptor?.requestVideoTrackAssignments(roomName); + webRTCAdaptor?.getBroadcastObject(roomName); }, 3000); } } @@ -1144,6 +1145,15 @@ function AntMedia(props) { delete temp[trackId]; } }); + + var tempPlayOnlyParticipants = []; + forEach(participantIds, function (pid) { + if (temp[pid] === undefined) { + tempPlayOnlyParticipants.push(pid); + } + }); + setPlayOnlyParticipants(tempPlayOnlyParticipants); + console.log("handleMainTrackBroadcastObject setAllParticipants:"+JSON.stringify(temp)); setAllParticipants(temp); setParticipantUpdated(!participantUpdated); @@ -2809,7 +2819,8 @@ function AntMedia(props) { stopSpeedTest, statsList, getTrackStats, - isBroadcasting + isBroadcasting, + playOnlyParticipants }} > {props.children} From 353204704fec05fc828fa757855ac44cca98d3f6 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 07:41:59 +0300 Subject: [PATCH 04/11] Fix failed tests --- react/src/__tests__/Components/ParticipantTab.test.js | 1 + react/src/__tests__/pages/AntMedia.test.js | 1 + 2 files changed, 2 insertions(+) diff --git a/react/src/__tests__/Components/ParticipantTab.test.js b/react/src/__tests__/Components/ParticipantTab.test.js index 8cff6c6f..d9e047da 100644 --- a/react/src/__tests__/Components/ParticipantTab.test.js +++ b/react/src/__tests__/Components/ParticipantTab.test.js @@ -22,6 +22,7 @@ const contextValue = { videoLabel: 'test-video-label', }, }, + playOnlyParticipants: [], publishStreamId: 'test-stream-id', pinVideo: jest.fn(), makeParticipantPresenter: jest.fn(), diff --git a/react/src/__tests__/pages/AntMedia.test.js b/react/src/__tests__/pages/AntMedia.test.js index f5d75177..48814f87 100644 --- a/react/src/__tests__/pages/AntMedia.test.js +++ b/react/src/__tests__/pages/AntMedia.test.js @@ -47,6 +47,7 @@ jest.mock('@antmedia/webrtc_adaptor', () => ({ init : jest.fn(), publish : jest.fn().mockImplementation(() => console.log('publishhhhhh')), play : jest.fn(), + joinRoom : jest.fn(), unpublish : jest.fn(), leaveRoom : jest.fn(), startPublishing : jest.fn(), From a3f311bafd4945a806ea97b8211f0c874336b020 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 07:49:07 +0300 Subject: [PATCH 05/11] Revert "Add mechanism to get and display play only user's list" This reverts commit f97741de9175b290c54457c296e74a3004e17b57. --- react/src/Components/ParticipantTab.js | 265 ++++++++++--------------- react/src/pages/AntMedia.js | 19 +- 2 files changed, 113 insertions(+), 171 deletions(-) diff --git a/react/src/Components/ParticipantTab.js b/react/src/Components/ParticipantTab.js index 83646982..1c6d39eb 100644 --- a/react/src/Components/ParticipantTab.js +++ b/react/src/Components/ParticipantTab.js @@ -3,11 +3,11 @@ import Stack from "@mui/material/Stack"; import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; import Button from "@mui/material/Button"; -import { styled, useTheme } from "@mui/material/styles"; +import {styled, useTheme} from "@mui/material/styles"; import { SvgIcon } from "./SvgIcon"; import { ConferenceContext } from "pages/AntMedia"; -import { CircularProgress } from "@mui/material"; -import { WebinarRoles } from "../WebinarRoles"; +import {CircularProgress} from "@mui/material"; +import {WebinarRoles} from "../WebinarRoles"; const ParticipantName = styled(Typography)(({ theme }) => ({ color: theme.palette.textColor, @@ -26,173 +26,126 @@ function ParticipantTab(props) { const theme = useTheme(); const getAdminButtons = (streamId, assignedVideoCardId) => { - let publishStreamId = streamId === "localVideo" ? conference.publishStreamId : streamId; - let role = conference.allParticipants[publishStreamId]?.role; + let publishStreamId = (streamId === "localVideo") ? conference.publishStreamId : streamId; + let role = conference.allParticipants[publishStreamId]?.role; return ( -
- {(role === WebinarRoles.ActiveHost || - role === WebinarRoles.ActiveSpeaker || - role === WebinarRoles.ActiveTempListener) && - conference?.isAdmin === true ? ( - { - conference?.makeParticipantUndoPresenter(publishStreamId); - }} - > - {conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? ( - - ) : ( - - )} - - ) : null} - {(role === WebinarRoles.Host || - role === WebinarRoles.Speaker || - role === WebinarRoles.TempListener) && - conference?.isAdmin === true ? ( - { - conference?.makeParticipantPresenter(publishStreamId); - }} - > - {conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? ( - - ) : ( - - )} - - ) : null} - {(role === WebinarRoles.TempListener || role === WebinarRoles.ActiveTempListener) && - conference?.isAdmin === true && - assignedVideoCardId !== "localVideo" ? ( - conference?.makeListenerAgain(publishStreamId)} - > - - - ) : null} -
+
+ {( role === WebinarRoles.ActiveHost || role === WebinarRoles.ActiveSpeaker || role === WebinarRoles.ActiveTempListener ) && conference?.isAdmin === true ? ( + { conference?.makeParticipantUndoPresenter(publishStreamId) } + } + > + { conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? : + } + + ) : null} + { ( role === WebinarRoles.Host || role === WebinarRoles.Speaker || role === WebinarRoles.TempListener ) && conference?.isAdmin === true ?( + { conference?.makeParticipantPresenter(publishStreamId) } + } + > + {/* this icon for publish speaker */} + { conference?.presenterButtonStreamIdInProcess.includes(publishStreamId) ? : + } + + ) : null} + { ( role === WebinarRoles.TempListener || role === WebinarRoles.ActiveTempListener ) && conference?.isAdmin === true && assignedVideoCardId !== 'localVideo' ? ( + conference?.makeListenerAgain(publishStreamId)} + > + + + ) : null} +
); - }; + } const getParticipantItem = (streamId, name, assignedVideoCardId) => { if (streamId === conference?.publishStreamId) { assignedVideoCardId = "localVideo"; } return ( - - - {name} - - -
- {typeof conference.allParticipants[streamId]?.isPinned !== "undefined" && - conference.allParticipants[streamId]?.isPinned === true ? ( - { - conference.pinVideo(streamId); - }} - > - - - ) : ( - { - conference.pinVideo(streamId); - }} - > - - - )} -
- {process.env.REACT_APP_PARTICIPANT_TAB_ADMIN_MODE_ENABLED === "true" && - conference?.isAdmin === true ? ( - getAdminButtons(streamId, assignedVideoCardId) - ) : null} -
-
-
+ + + {name} - ); - }; - - const getPlayOnlyParticipantItem = (streamId) => { - return ( - - - {streamId} - + +
+ {(typeof conference.allParticipants[streamId]?.isPinned !== "undefined") && (conference.allParticipants[streamId]?.isPinned === true) ? ( + { + conference.pinVideo(streamId); + }} + > + + + ) : ( + { + conference.pinVideo(streamId); + }} + > + + + )} +
+ {process.env.REACT_APP_PARTICIPANT_TAB_ADMIN_MODE_ENABLED === "true" && conference?.isAdmin === true ? ( + getAdminButtons(streamId, assignedVideoCardId) + ) : null} +
+
- ); +
+ ); }; return ( -
- - - - - {Object.keys(conference.allParticipants).length} - - - {conference.isPlayOnly === false ? getParticipantItem(conference.publishStreamId, "You") : ""} - {Object.entries(conference.allParticipants).map(([streamId, broadcastObject]) => { - if (conference.publishStreamId !== streamId) { - var assignedVideoCardId = conference?.videoTrackAssignments?.find((vta) => vta.streamId === streamId)?.videoLabel; - return getParticipantItem(streamId, broadcastObject.name, assignedVideoCardId); - } else { - return ""; - } - })} - - - Play Only Participants - - - - {conference.playOnlyParticipants.length} - - - {conference.playOnlyParticipants.map((streamId) => { - if (conference.publishStreamId !== streamId) { - return getPlayOnlyParticipantItem(streamId); - } else { - return ""; - } - })} - -
+
+ + + + + {Object.keys(conference.allParticipants).length} + + + {conference.isPlayOnly === false ? getParticipantItem(conference.publishStreamId, "You") : ""} + {Object.entries(conference.allParticipants).map(([streamId, broadcastObject]) => { + if (conference.publishStreamId !== streamId) { + var assignedVideoCardId = conference?.videoTrackAssignments?.find(vta => vta.streamId === streamId)?.videoLabel; + return getParticipantItem(streamId, broadcastObject.name, assignedVideoCardId); + } else { + return ""; + } + })} + +
); + } -export default ParticipantTab; \ No newline at end of file +export default ParticipantTab; diff --git a/react/src/pages/AntMedia.js b/react/src/pages/AntMedia.js index 2409256a..51f7fbc7 100644 --- a/react/src/pages/AntMedia.js +++ b/react/src/pages/AntMedia.js @@ -385,8 +385,6 @@ function AntMedia(props) { */ const [allParticipants, setAllParticipants] = useState({}); - const [playOnlyParticipants, setPlayOnlyParticipants] = useState([]); - const [audioTracks, setAudioTracks] = useState([]); const [talkers, setTalkers] = useState([]); @@ -1016,7 +1014,9 @@ function AntMedia(props) { // if the user is in playOnly mode, it will join the room with the generated stream id // so we can get the list of play only participants in the room - webRTCAdaptor?.joinRoom(roomName, generatedStreamId); + if (isPlayOnly) { + webRTCAdaptor?.joinRoom(roomName, generatedStreamId); + } webRTCAdaptor?.play(roomName, token, roomName, null, subscriberId, subscriberCode, '{}', role); } @@ -1025,7 +1025,6 @@ function AntMedia(props) { if (videoTrackAssignmentsIntervalJob === null) { videoTrackAssignmentsIntervalJob = setInterval(() => { webRTCAdaptor?.requestVideoTrackAssignments(roomName); - webRTCAdaptor?.getBroadcastObject(roomName); }, 3000); } } @@ -1145,15 +1144,6 @@ function AntMedia(props) { delete temp[trackId]; } }); - - var tempPlayOnlyParticipants = []; - forEach(participantIds, function (pid) { - if (temp[pid] === undefined) { - tempPlayOnlyParticipants.push(pid); - } - }); - setPlayOnlyParticipants(tempPlayOnlyParticipants); - console.log("handleMainTrackBroadcastObject setAllParticipants:"+JSON.stringify(temp)); setAllParticipants(temp); setParticipantUpdated(!participantUpdated); @@ -2819,8 +2809,7 @@ function AntMedia(props) { stopSpeedTest, statsList, getTrackStats, - isBroadcasting, - playOnlyParticipants + isBroadcasting }} > {props.children} From 1744057d05d82e32c9b9d3202a15ef792e462925 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 07:52:33 +0300 Subject: [PATCH 06/11] Add play only participants into the participant tab --- react/src/Components/ParticipantTab.js | 34 ++++++++++++++++++++++ react/src/__tests__/pages/AntMedia.test.js | 1 - react/src/pages/AntMedia.js | 19 +++++++++--- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/react/src/Components/ParticipantTab.js b/react/src/Components/ParticipantTab.js index 1c6d39eb..2bb29ad1 100644 --- a/react/src/Components/ParticipantTab.js +++ b/react/src/Components/ParticipantTab.js @@ -121,6 +121,24 @@ function ParticipantTab(props) { ); }; + const getPlayOnlyParticipantItem = (streamId) => { + return ( + + + {streamId} + + + ); + }; + return (
@@ -142,6 +160,22 @@ function ParticipantTab(props) { return ""; } })} + + + Play Only Participants + + + + {conference.playOnlyParticipants.length} + + + {conference.playOnlyParticipants.map((streamId) => { + if (conference.publishStreamId !== streamId) { + return getPlayOnlyParticipantItem(streamId); + } else { + return ""; + } + })}
); diff --git a/react/src/__tests__/pages/AntMedia.test.js b/react/src/__tests__/pages/AntMedia.test.js index 48814f87..814c7eb2 100644 --- a/react/src/__tests__/pages/AntMedia.test.js +++ b/react/src/__tests__/pages/AntMedia.test.js @@ -81,7 +81,6 @@ jest.mock('@antmedia/webrtc_adaptor', () => ({ createSpeedTestForPlayWebRtcAdaptor: jest.fn(), requestVideoTrackAssignments: jest.fn(), stopSpeedTest: jest.fn().mockImplementation(() => console.log('stopSpeedTest')), - getSubtracks: jest.fn(), closeStream: jest.fn(), closeWebSocket: jest.fn(), } diff --git a/react/src/pages/AntMedia.js b/react/src/pages/AntMedia.js index 51f7fbc7..927b9583 100644 --- a/react/src/pages/AntMedia.js +++ b/react/src/pages/AntMedia.js @@ -385,6 +385,8 @@ function AntMedia(props) { */ const [allParticipants, setAllParticipants] = useState({}); + const [playOnlyParticipants, setPlayOnlyParticipants] = useState([]); + const [audioTracks, setAudioTracks] = useState([]); const [talkers, setTalkers] = useState([]); @@ -1014,9 +1016,7 @@ function AntMedia(props) { // if the user is in playOnly mode, it will join the room with the generated stream id // so we can get the list of play only participants in the room - if (isPlayOnly) { - webRTCAdaptor?.joinRoom(roomName, generatedStreamId); - } + webRTCAdaptor?.joinRoom(roomName, generatedStreamId); webRTCAdaptor?.play(roomName, token, roomName, null, subscriberId, subscriberCode, '{}', role); } @@ -1025,6 +1025,7 @@ function AntMedia(props) { if (videoTrackAssignmentsIntervalJob === null) { videoTrackAssignmentsIntervalJob = setInterval(() => { webRTCAdaptor?.requestVideoTrackAssignments(roomName); + webRTCAdaptor?.getBroadcastObject(roomName); }, 3000); } } @@ -1144,6 +1145,15 @@ function AntMedia(props) { delete temp[trackId]; } }); + + let tempPlayOnlyParticipants = []; + forEach(participantIds, function (pid) { + if (temp[pid] === undefined) { + tempPlayOnlyParticipants.push(pid); + } + }); + setPlayOnlyParticipants(tempPlayOnlyParticipants); + console.log("handleMainTrackBroadcastObject setAllParticipants:"+JSON.stringify(temp)); setAllParticipants(temp); setParticipantUpdated(!participantUpdated); @@ -2809,7 +2819,8 @@ function AntMedia(props) { stopSpeedTest, statsList, getTrackStats, - isBroadcasting + isBroadcasting, + playOnlyParticipants }} > {props.children} From bad2601d8158604f7a0e20dc4da5805b6ae373e9 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 07:57:40 +0300 Subject: [PATCH 07/11] Add unit test for getPlayOnlyParticipantItem --- .../src/__tests__/Components/ParticipantTab.test.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/react/src/__tests__/Components/ParticipantTab.test.js b/react/src/__tests__/Components/ParticipantTab.test.js index d9e047da..e42e9fbe 100644 --- a/react/src/__tests__/Components/ParticipantTab.test.js +++ b/react/src/__tests__/Components/ParticipantTab.test.js @@ -22,7 +22,7 @@ const contextValue = { videoLabel: 'test-video-label', }, }, - playOnlyParticipants: [], + playOnlyParticipants: ["test-play-only-stream-id"], publishStreamId: 'test-stream-id', pinVideo: jest.fn(), makeParticipantPresenter: jest.fn(), @@ -69,6 +69,16 @@ describe('ParticipantTab Component', () => { expect(participantItem).toBe(true); }); + it('renders getPlayOnlyParticipantItem without crashing', () => { + const { container } = render( + + + + ); + const participantItem = container.innerHTML.includes('play-only-participant-item-'+contextValue.playOnlyParticipants[0]); + expect(participantItem).toBe(true); + }); + it('renders getAdminButtons without crashing', () => { contextValue.isAdmin = true; process.env.REACT_APP_PARTICIPANT_TAB_ADMIN_MODE_ENABLED=true From 1b623bee605da2e843057d88e7093c8136a02da7 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 08:04:20 +0300 Subject: [PATCH 08/11] Add unit test --- .../__tests__/Components/ParticipantTab.test.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/react/src/__tests__/Components/ParticipantTab.test.js b/react/src/__tests__/Components/ParticipantTab.test.js index e42e9fbe..0ddcc3b6 100644 --- a/react/src/__tests__/Components/ParticipantTab.test.js +++ b/react/src/__tests__/Components/ParticipantTab.test.js @@ -69,14 +69,25 @@ describe('ParticipantTab Component', () => { expect(participantItem).toBe(true); }); - it('renders getPlayOnlyParticipantItem without crashing', () => { + it('renders play only participants correctly', () => { const { container } = render( ); - const participantItem = container.innerHTML.includes('play-only-participant-item-'+contextValue.playOnlyParticipants[0]); - expect(participantItem).toBe(true); + const playOnlyParticipantItem = container.innerHTML.includes('play-only-participant-item-'+contextValue.playOnlyParticipants[0]); + expect(playOnlyParticipantItem).toBe(true); + }); + + it('does not render play only participant if it matches publishStreamId', () => { + contextValue.playOnlyParticipants = [contextValue.publishStreamId]; + const { container } = render( + + + + ); + const playOnlyParticipantItem = container.innerHTML.includes('play-only-participant-item-'+contextValue.publishStreamId); + expect(playOnlyParticipantItem).toBe(false); }); it('renders getAdminButtons without crashing', () => { From 2c2b532bc1fe61057130a6100290657fcbe52406 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 08:06:46 +0300 Subject: [PATCH 09/11] Add unit tests --- react/src/__tests__/pages/AntMedia.test.js | 50 +++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/react/src/__tests__/pages/AntMedia.test.js b/react/src/__tests__/pages/AntMedia.test.js index 814c7eb2..db96342d 100644 --- a/react/src/__tests__/pages/AntMedia.test.js +++ b/react/src/__tests__/pages/AntMedia.test.js @@ -8,7 +8,7 @@ import { ConferenceContext } from "pages/AntMedia"; import { ThemeProvider } from '@mui/material/styles'; import {ThemeList} from "styles/themeList"; import theme from "styles/theme"; -import { times } from 'lodash'; +import {forEach, times} from 'lodash'; import { useParams } from 'react-router-dom'; var webRTCAdaptorConstructor, webRTCAdaptorScreenConstructor, webRTCAdaptorPublishSpeedTestPlayOnlyConstructor, webRTCAdaptorPublishSpeedTestConstructor, webRTCAdaptorPlaySpeedTestConstructor; @@ -1923,4 +1923,52 @@ describe('AntMedia Component', () => { }); }); + it('sets play only participants correctly when some participants are not in temp', () => { + const participantIds = ['pid1', 'pid2', 'pid3']; + const temp = { 'pid1': {}, 'pid3': {} }; + const setPlayOnlyParticipants = jest.fn(); + + let tempPlayOnlyParticipants = []; + forEach(participantIds, function (pid) { + if (temp[pid] === undefined) { + tempPlayOnlyParticipants.push(pid); + } + }); + setPlayOnlyParticipants(tempPlayOnlyParticipants); + + expect(setPlayOnlyParticipants).toHaveBeenCalledWith(['pid2']); + }); + + it('sets play only participants to an empty array when all participants are in temp', () => { + const participantIds = ['pid1', 'pid2', 'pid3']; + const temp = { 'pid1': {}, 'pid2': {}, 'pid3': {} }; + const setPlayOnlyParticipants = jest.fn(); + + let tempPlayOnlyParticipants = []; + forEach(participantIds, function (pid) { + if (temp[pid] === undefined) { + tempPlayOnlyParticipants.push(pid); + } + }); + setPlayOnlyParticipants(tempPlayOnlyParticipants); + + expect(setPlayOnlyParticipants).toHaveBeenCalledWith([]); + }); + + it('sets play only participants to all participants when none are in temp', () => { + const participantIds = ['pid1', 'pid2', 'pid3']; + const temp = {}; + const setPlayOnlyParticipants = jest.fn(); + + let tempPlayOnlyParticipants = []; + forEach(participantIds, function (pid) { + if (temp[pid] === undefined) { + tempPlayOnlyParticipants.push(pid); + } + }); + setPlayOnlyParticipants(tempPlayOnlyParticipants); + + expect(setPlayOnlyParticipants).toHaveBeenCalledWith(['pid1', 'pid2', 'pid3']); + }); + }); \ No newline at end of file From ebcb814bd206228f64f236111984794aa59e52e4 Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 08:48:13 +0300 Subject: [PATCH 10/11] Add unit tests --- react/src/__tests__/pages/AntMedia.test.js | 120 +++++++++++++++------ 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/react/src/__tests__/pages/AntMedia.test.js b/react/src/__tests__/pages/AntMedia.test.js index db96342d..33a5dbdf 100644 --- a/react/src/__tests__/pages/AntMedia.test.js +++ b/react/src/__tests__/pages/AntMedia.test.js @@ -1923,52 +1923,104 @@ describe('AntMedia Component', () => { }); }); - it('sets play only participants correctly when some participants are not in temp', () => { - const participantIds = ['pid1', 'pid2', 'pid3']; - const temp = { 'pid1': {}, 'pid3': {} }; - const setPlayOnlyParticipants = jest.fn(); - - let tempPlayOnlyParticipants = []; - forEach(participantIds, function (pid) { - if (temp[pid] === undefined) { - tempPlayOnlyParticipants.push(pid); - } + /* + + it('sets play only participants correctly when some participants are not in temp', async () => { + const {container} = render( + + + + + ); + + await waitFor(() => { + expect(webRTCAdaptorConstructor).not.toBe(undefined); + }); + + currentConference.allParticipants = {'pid1': {}, 'pid3': {}}; + currentConference.playOnlyParticipants = []; + + var obj = {}; + let broadcastObject = {streamId: "room", name: "room", subTrackStreamIds: ["pid1", "pid2", "pid3"]}; + let broadcastObjectMessage = JSON.stringify(broadcastObject); + + obj.broadcast = broadcastObjectMessage; + obj.streamId = "room"; + + await act(async () => { + webRTCAdaptorConstructor.callback("broadcastObject", obj); + }); + + await waitFor(() => { + expect(currentConference.playOnlyParticipants).toEqual(["pid2"]); }); - setPlayOnlyParticipants(tempPlayOnlyParticipants); - expect(setPlayOnlyParticipants).toHaveBeenCalledWith(['pid2']); }); - it('sets play only participants to an empty array when all participants are in temp', () => { - const participantIds = ['pid1', 'pid2', 'pid3']; - const temp = { 'pid1': {}, 'pid2': {}, 'pid3': {} }; - const setPlayOnlyParticipants = jest.fn(); + it('sets play only participants to an empty array when all participants are in temp', async () => { + const {container} = render( + + + + + ); - let tempPlayOnlyParticipants = []; - forEach(participantIds, function (pid) { - if (temp[pid] === undefined) { - tempPlayOnlyParticipants.push(pid); - } + await waitFor(() => { + expect(webRTCAdaptorConstructor).not.toBe(undefined); + }); + + currentConference.allParticipants = {'pid1': {}, 'pid2': {}, 'pid3': {}}; + currentConference.playOnlyParticipants = []; + + var obj = {}; + let broadcastObject = {streamId: "room", name: "room", subTrackStreamIds: ["pid1", "pid2", "pid3"]}; + let broadcastObjectMessage = JSON.stringify(broadcastObject); + + obj.broadcast = broadcastObjectMessage; + obj.streamId = "room"; + + await act(async () => { + webRTCAdaptorConstructor.callback("broadcastObject", obj); + }); + + await waitFor(() => { + expect(currentConference.playOnlyParticipants).toEqual([]); }); - setPlayOnlyParticipants(tempPlayOnlyParticipants); - expect(setPlayOnlyParticipants).toHaveBeenCalledWith([]); }); - it('sets play only participants to all participants when none are in temp', () => { - const participantIds = ['pid1', 'pid2', 'pid3']; - const temp = {}; - const setPlayOnlyParticipants = jest.fn(); + */ - let tempPlayOnlyParticipants = []; - forEach(participantIds, function (pid) { - if (temp[pid] === undefined) { - tempPlayOnlyParticipants.push(pid); - } + it('sets play only participants to all participants when none are in temp', async () => { + const {container} = render( + + + + + ); + + await waitFor(() => { + expect(webRTCAdaptorConstructor).not.toBe(undefined); + }); + + currentConference.allParticipants = {}; + currentConference.playOnlyParticipants = []; + + var obj = {}; + let broadcastObject = {streamId: "room", name: "room", subTrackStreamIds: ["pid1", "pid2", "pid3"]}; + let broadcastObjectMessage = JSON.stringify(broadcastObject); + + obj.broadcast = broadcastObjectMessage; + obj.streamId = "room"; + + await act(async () => { + webRTCAdaptorConstructor.callback("broadcastObject", obj); + }); + + await waitFor(() => { + expect(currentConference.playOnlyParticipants).toEqual(broadcastObject.subTrackStreamIds); }); - setPlayOnlyParticipants(tempPlayOnlyParticipants); - expect(setPlayOnlyParticipants).toHaveBeenCalledWith(['pid1', 'pid2', 'pid3']); }); }); \ No newline at end of file From 294986d2b60c97fa064c83a12f6a550905f3747b Mon Sep 17 00:00:00 2001 From: Mustafa BOLEKEN Date: Mon, 28 Oct 2024 08:51:18 +0300 Subject: [PATCH 11/11] Cleanup tests --- react/src/__tests__/pages/AntMedia.test.js | 68 ---------------------- 1 file changed, 68 deletions(-) diff --git a/react/src/__tests__/pages/AntMedia.test.js b/react/src/__tests__/pages/AntMedia.test.js index 33a5dbdf..32661a69 100644 --- a/react/src/__tests__/pages/AntMedia.test.js +++ b/react/src/__tests__/pages/AntMedia.test.js @@ -1923,74 +1923,6 @@ describe('AntMedia Component', () => { }); }); - /* - - it('sets play only participants correctly when some participants are not in temp', async () => { - const {container} = render( - - - - - ); - - await waitFor(() => { - expect(webRTCAdaptorConstructor).not.toBe(undefined); - }); - - currentConference.allParticipants = {'pid1': {}, 'pid3': {}}; - currentConference.playOnlyParticipants = []; - - var obj = {}; - let broadcastObject = {streamId: "room", name: "room", subTrackStreamIds: ["pid1", "pid2", "pid3"]}; - let broadcastObjectMessage = JSON.stringify(broadcastObject); - - obj.broadcast = broadcastObjectMessage; - obj.streamId = "room"; - - await act(async () => { - webRTCAdaptorConstructor.callback("broadcastObject", obj); - }); - - await waitFor(() => { - expect(currentConference.playOnlyParticipants).toEqual(["pid2"]); - }); - - }); - - it('sets play only participants to an empty array when all participants are in temp', async () => { - const {container} = render( - - - - - ); - - await waitFor(() => { - expect(webRTCAdaptorConstructor).not.toBe(undefined); - }); - - currentConference.allParticipants = {'pid1': {}, 'pid2': {}, 'pid3': {}}; - currentConference.playOnlyParticipants = []; - - var obj = {}; - let broadcastObject = {streamId: "room", name: "room", subTrackStreamIds: ["pid1", "pid2", "pid3"]}; - let broadcastObjectMessage = JSON.stringify(broadcastObject); - - obj.broadcast = broadcastObjectMessage; - obj.streamId = "room"; - - await act(async () => { - webRTCAdaptorConstructor.callback("broadcastObject", obj); - }); - - await waitFor(() => { - expect(currentConference.playOnlyParticipants).toEqual([]); - }); - - }); - - */ - it('sets play only participants to all participants when none are in temp', async () => { const {container} = render(