Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow circle settings to be configured through customSettings #424

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function RoomCreationPasswordDialog(props) {
placeholder="Enter room name"
/> */}
<Input
id={'room_creation_password'}
style={{marginTop:'15px'}}
type='password'
value={password}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// src/BecomePublisherConfirmationDialog.test.js
import React from 'react';
import { render } from '@testing-library/react';
import EffectsDrawer from "../../Components/EffectsDrawer";
import BecomePublisherConfirmationDialog from "../../Components/BecomePublisherConfirmationDialog";

// Mock the props
const props = {
}

describe('Become Publisher Confirmation Dialog Component', () => {

beforeEach(() => {
// Reset the mock implementation before each test
jest.clearAllMocks();
});


it('renders without crashing', () => {
render(
<BecomePublisherConfirmationDialog
{...props}
/>
);
});

});
32 changes: 32 additions & 0 deletions react/src/__tests__/Components/DrawerButton.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// src/DrawerButton.test.js
import React from 'react';
import { render } from '@testing-library/react';
import EffectsDrawer from "../../Components/EffectsDrawer";
import BecomePublisherConfirmationDialog from "../../Components/BecomePublisherConfirmationDialog";
import DrawerButton from "../../Components/DrawerButton";

// Mock the props
const props = {
handleMessageDrawerOpen: jest.fn(),
handleParticipantListOpen: jest.fn(),
handleEffectsOpen: jest.fn(),
setPublisherRequestListDrawerOpen: jest.fn(),
}

describe('Drawer Button Component', () => {

beforeEach(() => {
// Reset the mock implementation before each test
jest.clearAllMocks();
});


it('renders without crashing', () => {
render(
<DrawerButton
{...props}
/>
);
});

});
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// src/EffectsDrawer.test.js
import React from 'react';
import { render } from '@testing-library/react';
import EffectsDrawer from "../../../../Components/EffectsDrawer";
import EffectsDrawer from "../../Components/EffectsDrawer";

// Mock the props
const props = {
Expand All @@ -28,7 +28,7 @@ jest.mock('react', () => ({
...jest.requireActual('react'),
}));

describe('Camera Button Component', () => {
describe('Effects Drawer Component', () => {

beforeEach(() => {
// Reset the mock implementation before each test
Expand Down
35 changes: 35 additions & 0 deletions react/src/__tests__/Components/MessageDrawer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// src/MessageDrawer.test.js
import React from 'react';
import { render } from '@testing-library/react';
import EffectsDrawer from "../../Components/EffectsDrawer";
import BecomePublisherConfirmationDialog from "../../Components/BecomePublisherConfirmationDialog";
import MessageDrawer from "../../Components/MessageDrawer";

// Mock the props
const props = {
handleMessageDrawerOpen: jest.fn(),
handleParticipantListOpen: jest.fn(),
handleEffectsOpen: jest.fn(),
setPublisherRequestListDrawerOpen: jest.fn(),
messages: [],
sendMessage: jest.fn(),
handleSetMessages: jest.fn(),
}

describe('Message Drawer Component', () => {

beforeEach(() => {
// Reset the mock implementation before each test
jest.clearAllMocks();
});


it('renders without crashing', () => {
render(
<MessageDrawer
{...props}
/>
);
});

});
77 changes: 77 additions & 0 deletions test/test_join_leave.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from browser import Browser
from selenium.webdriver.common.by import By
from rest_helper import RestHelper
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


import subprocess
Expand Down Expand Up @@ -113,6 +115,16 @@ def join_room_in_new_tab(self, participant, room, play_only=False):
assert(meeting_gallery.is_displayed())

return handle

def open_home_page_in_new_tab(self, participant):
print("url: "+self.url+"/"+self.test_app_name+"/")
app = "/"+self.test_app_name
if self.url.endswith("localhost:3000"):
app = ""

handle = self.chrome.open_in_new_tab(self.url + app + "/")

return handle

def get_videoTrackAssignments(self, expected_value=None):
script = "return window.conference;"
Expand Down Expand Up @@ -1860,6 +1872,71 @@ def test_theme(self):

self.chrome.close_all()

def test_create_meeting_with_password(self):
wait = WebDriverWait(self.chrome, 10)
roomPassword = "123123"

# create room without password
room = "room"+str(random.randint(100, 999))
handle_0 = self.open_home_page_in_new_tab("participantA")

create_meeting_element = wait.until(
EC.element_to_be_clickable((By.XPATH, "//Typography[text()='Create Meeting']"))
)

create_meeting_element.click()

time.sleep(1)

localVideo = self.chrome.get_element_with_retry(By.ID, 'localVideo')

assert(localVideo.is_displayed())

self.chrome.close_all()

# join room with password
self.rest_helper
time.sleep(10)
app_settings = self.rest_helper.call_get_app_settings(self.test_app_name)
app_settings["customSettings"] = {
"circle":{
"roomCreationPassword": roomPassword
}
}
response = self.rest_helper.call_set_app_settings(self.test_app_name, app_settings)
assert(response["success"])
time.sleep(10)

room = "room"+str(random.randint(100, 999))
handle_1 = self.open_home_page_in_new_tab("participantB")

create_meeting_element = wait.until(
EC.element_to_be_clickable((By.XPATH, "//Typography[text()='Create Meeting']"))
)

create_meeting_element.click()

time.sleep(1)

input_field = wait.until(
EC.presence_of_element_located((By.ID, "room_creation_password"))
)

input_field.send_keys(roomPassword)

create_room_button = wait.until(
EC.element_to_be_clickable((By.ID, "create_room_button"))
)

create_room_button.click()

time.sleep(1)

localVideo = self.chrome.get_element_with_retry(By.ID, 'localVideo')

assert(localVideo.is_displayed())

self.chrome.close_all()

def test_language(self):
room = "room"+str(random.randint(100, 999))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package io.antmedia.enterprise.streamapp;

import com.google.gson.Gson;
import io.antmedia.AntMediaApplicationAdapter;
import io.antmedia.AppSettings;
import io.antmedia.datastore.db.DataStore;
import io.antmedia.datastore.db.DataStoreFactory;
import io.antmedia.datastore.db.IDataStoreFactory;
import io.antmedia.datastore.db.types.Broadcast;
import io.antmedia.datastore.db.types.BroadcastUpdate;
import io.antmedia.muxer.IAntMediaStreamHandler;
import io.antmedia.rest.model.Result;
import io.antmedia.rest.RestServiceBase;
import org.jetbrains.annotations.NotNull;
Expand All @@ -21,14 +24,17 @@ public class AMSBroadcastManager implements ApplicationContextAware {

private ApplicationContext applicationContext;
private AntMediaApplicationAdapter appAdaptor;
private ConferenceRoomSettings conferenceRoomSettings;
private AppSettings appSettings;
private Gson gson = new Gson();

@Override
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

public ApplicationContext getApplicationContext() {
return applicationContext;
IAntMediaStreamHandler app = getApplication();
appSettings = app.getAppSettings();
fetchConferenceRoomSettings();
}

public AntMediaApplicationAdapter getApplication() {
Expand Down Expand Up @@ -78,4 +84,39 @@ public boolean updateBroadcastRole(String streamId, String role) {

return result;
}

public void fetchConferenceRoomSettings() {
Object circleSettingsString = appSettings.getCustomSetting("circle");
if (circleSettingsString == null) {
logger.error("Using default settings for Conference Room Settings because no Circle settings in the AppSettings");

conferenceRoomSettings = new ConferenceRoomSettings();
}
else {
try {
conferenceRoomSettings = gson.fromJson(circleSettingsString.toString(), ConferenceRoomSettings.class);
}
catch (Exception e)
{
logger.error("Invalid Conference room settings, using default conference room settings");
conferenceRoomSettings = new ConferenceRoomSettings();
}
}
conferenceRoomSettings.init();

String participantVisibilityMatrix = appSettings.getParticipantVisibilityMatrix().toString();

if (participantVisibilityMatrix != null && conferenceRoomSettings.getParticipantVisibilityMatrix() == null) {
conferenceRoomSettings.setParticipantVisibilityMatrix(participantVisibilityMatrix);
}

int maxVideoTrackCount = appSettings.getMaxVideoTrackCount();

conferenceRoomSettings.setMaxVideoTrackCount(maxVideoTrackCount);
}

public ConferenceRoomSettings getConferenceRoomSettings() {
return conferenceRoomSettings;
}

}
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
package io.antmedia.enterprise.streamapp;


import com.google.gson.annotations.Expose;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

import com.google.gson.annotations.Expose;

import jakarta.annotation.PostConstruct;

@PropertySource("/WEB-INF/red5-web.properties")

public class ConferenceRoomSettings {

protected static Logger logger = LoggerFactory.getLogger(ConferenceRoomSettings.class);


@Value("${roomCreationPassword:#{null}}")
private String roomCreationPassword;

@Expose
@Expose
private boolean roomCreationPasswordEnabled = false;
@Expose

@Expose
private boolean isRecordingFeatureAvailable = false;

@Expose
private String participantVisibilityMatrix;
@Expose
private String participantVisibilityMatrix;

@Expose
private int maxVideoTrackCount = 6;

@PostConstruct
public void init() {
roomCreationPasswordEnabled = StringUtils.isNotBlank(roomCreationPassword);
logger.info("roomCreationPasswordEnabled is {}", StringUtils.isNotBlank(roomCreationPassword));

try {
Class.forName("io.antmedia.plugin.IMediaPushPlugin");
Expand All @@ -46,6 +39,7 @@ public void init() {

isRecordingFeatureAvailable = false;
}
roomCreationPasswordEnabled = StringUtils.isNotBlank(roomCreationPassword);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,8 @@ private AMSBroadcastManager getAMSBroadcastManager() {
}

private void setConferenceRoomSettings(){
if(context != null){
conferenceRoomSettings = (ConferenceRoomSettings) context.getBean("conferenceRoomSettings");
}
getAMSBroadcastManager().fetchConferenceRoomSettings();
conferenceRoomSettings = getAMSBroadcastManager().getConferenceRoomSettings();
}

private void setAppSettings() {
Expand Down Expand Up @@ -323,17 +322,6 @@ private Object getMediaPushPlugin() {
}

private void responseRoomSettings(Session session) {

String participantVisibilityMatrix = appSettings.getParticipantVisibilityMatrix().toString();

if (participantVisibilityMatrix != null) {
conferenceRoomSettings.setParticipantVisibilityMatrix(participantVisibilityMatrix);
}

int maxVideoTrackCount = appSettings.getMaxVideoTrackCount();

conferenceRoomSettings.setMaxVideoTrackCount(maxVideoTrackCount);

JSONObject jsonResponse = new JSONObject();
jsonResponse.put(WebSocketConstants.COMMAND, WebSocketApplicationConstants.SET_SETTINGS_COMMAND);
jsonResponse.put(WebSocketApplicationConstants.SETTINGS, gsonOnlyExposedFields.toJson(conferenceRoomSettings));
Expand Down
Loading