Merge pull request #18453 from gustavotrott/merge-27-into-develop-4ago2023

Merge 2.7 into Develop
This commit is contained in:
Gustavo Trott 2023-08-04 17:46:50 -03:00 committed by GitHub
commit dc75850f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 632 additions and 176 deletions

View File

@ -16,26 +16,99 @@ on:
permissions:
contents: read
jobs:
build-install-and-test:
build-bbb-apps-akka:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_AKKA_APPS_KEY=$(git log -1 --format=%H -- akka-bbb-apps)" >> $GITHUB_ENV
- run: echo "CACHE_COMMON_MSG_KEY=$(git log -1 --format=%H -- bbb-common-message)" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-apps-akka-${{ env.CACHE_AKKA_APPS_KEY }}-${{ env.CACHE_COMMON_MSG_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-apps-akka
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-apps-akka.tar
path: |
artifacts.tar
build-bbb-config:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-config
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-config.tar
path: artifacts.tar
build-bbb-export-annotations:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-export-annotations
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-export-annotations.tar
path: artifacts.tar
build-bbb-learning-dashboard:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_LEARNING_DASHBOARD_KEY=$(git log -1 --format=%H -- bbb-learning-dashboard)" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-learning-dashboard-${{ env.CACHE_LEARNING_DASHBOARD_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-learning-dashboard
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-learning-dashboard.tar
path: artifacts.tar
build-bbb-playback-record:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: ./build/get_external_dependencies.sh
- run: ./build/setup.sh bbb-apps-akka
- run: ./build/setup.sh bbb-config
- run: ./build/setup.sh bbb-etherpad
- run: ./build/setup.sh bbb-export-annotations
- run: ./build/setup.sh bbb-freeswitch-core
- run: ./build/setup.sh bbb-freeswitch-sounds
- run: ./build/setup.sh bbb-fsesl-akka
- run: ./build/setup.sh bbb-graphql-middleware
- run: ./build/setup.sh bbb-graphql-server
- run: ./build/setup.sh bbb-html5-nodejs
- run: ./build/setup.sh bbb-html5
- run: ./build/setup.sh bbb-learning-dashboard
- run: ./build/setup.sh bbb-libreoffice-docker
- run: ./build/setup.sh bbb-mkclean
- run: ./build/setup.sh bbb-pads
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- run: ./build/setup.sh bbb-playback
- run: ./build/setup.sh bbb-playback-notes
- run: ./build/setup.sh bbb-playback-podcast
@ -43,7 +116,191 @@ jobs:
- run: ./build/setup.sh bbb-playback-screenshare
- run: ./build/setup.sh bbb-playback-video
- run: ./build/setup.sh bbb-record-core
- run: ./build/setup.sh bbb-web
- run: tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-playback-record.tar
path: |
artifacts.tar
build-bbb-graphql-server:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: ./build/get_external_dependencies.sh
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- run: ./build/setup.sh bbb-graphql-middleware
- run: ./build/setup.sh bbb-graphql-server
- run: tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-graphql-server.tar
path: |
artifacts.tar
build-bbb-etherpad:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_ETHERPAD_VERSION_KEY=$(git log -1 --format=%H -- bbb-etherpad.placeholder.sh)" >> $GITHUB_ENV
- run: echo "CACHE_ETHERPAD_BUILD_KEY=$(git log -1 --format=%H -- build/packages-template/bbb-etherpad)" >> $GITHUB_ENV
- run: echo "CACHE_URL1_KEY=$(curl -s https://api.github.com/repos/mconf/ep_pad_ttl/commits | md5sum | awk '{ print $1 }')" >> $GITHUB_ENV
- run: echo "CACHE_URL2_KEY=$(curl -s https://api.github.com/repos/alangecker/bbb-etherpad-plugin/commits | md5sum | awk '{ print $1 }')" >> $GITHUB_ENV
- run: echo "CACHE_URL3_KEY=$(curl -s https://api.github.com/repos/mconf/ep_redis_publisher/commits | md5sum | awk '{ print $1 }')" >> $GITHUB_ENV
- run: echo "CACHE_URL4_KEY=$(curl -s https://api.github.com/repos/alangecker/bbb-etherpad-skin/commits | md5sum | awk '{ print $1 }')" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-etherpad-${{ env.CACHE_ETHERPAD_VERSION_KEY }}-${{ env.CACHE_ETHERPAD_BUILD_KEY }}-${{ env.CACHE_URL1_KEY }}-${{ env.CACHE_URL2_KEY }}-${{ env.CACHE_URL3_KEY }}-${{ env.CACHE_URL4_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-etherpad
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-etherpad.tar
path: |
artifacts.tar
build-bbb-bbb-web:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_BBB_WEB_KEY=$(git log -1 --format=%H -- bigbluebutton-web)" >> $GITHUB_ENV
- run: echo "CACHE_COMMON_MSG_KEY=$(git log -1 --format=%H -- bbb-common-message)" >> $GITHUB_ENV
- run: echo "CACHE_COMMON_WEB_KEY=$(git log -1 --format=%H -- bbb-common-web)" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-web-${{ env.CACHE_BBB_WEB_KEY }}-${{ env.CACHE_COMMON_MSG_KEY }}-${{ env.CACHE_COMMON_WEB_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-web
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-web.tar
path: |
artifacts.tar
build-bbb-fsesl-akka:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_AKKA_FSESL_KEY=$(git log -1 --format=%H -- akka-bbb-fsesl)" >> $GITHUB_ENV
- run: echo "CACHE_COMMON_MSG_KEY=$(git log -1 --format=%H -- bbb-common-message)" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-fsesl-akka-${{ env.CACHE_AKKA_FSESL_KEY }}-${{ env.CACHE_COMMON_MSG_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-fsesl-akka
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-fsesl-akka.tar
path: |
artifacts.tar
build-bbb-html5:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_KEY=$(git log -1 --format=%H -- bigbluebutton-html5)" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-html5-${{ env.CACHE_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-html5-nodejs
./build/setup.sh bbb-html5
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-html5.tar
path: |
artifacts.tar
build-bbb-freeswitch:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history
- run: echo "CACHE_FREESWITCH_KEY=$(git log -1 --format=%H -- build/packages-template/bbb-freeswitch-core)" >> $GITHUB_ENV
- run: echo "CACHE_FREESWITCH_SOUNDS_KEY=$(git log -1 --format=%H -- build/packages-template/bbb-freeswitch-sounds)" >> $GITHUB_ENV
- run: echo "CACHE_SOUNDS_KEY=$(curl -Is http://bigbluebutton.org/downloads/sounds.tar.gz | grep "Last-Modified" | md5sum | awk '{ print $1 }')" >> $GITHUB_ENV
- run: echo "CACHE_BBB_RELEASE_KEY=$(git log -1 --format=%H -- bigbluebutton-config/bigbluebutton-release)" >> $GITHUB_ENV
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- name: Handle cache
id: cache-action
uses: actions/cache@v3
with:
path: artifacts.tar
key: ${{ runner.os }}-bbb-freeswitch-${{ env.CACHE_FREESWITCH_KEY }}-${{ env.CACHE_FREESWITCH_SOUNDS_KEY }}-${{ env.CACHE_SOUNDS_KEY }}-${{ env.CACHE_BBB_RELEASE_KEY }}
- if: ${{ steps.cache-action.outputs.cache-hit != 'true' }}
name: Generate artifacts
run: |
./build/get_external_dependencies.sh
./build/setup.sh bbb-freeswitch-core
./build/setup.sh bbb-freeswitch-sounds
tar cvf artifacts.tar artifacts/
- name: Archive packages
uses: actions/upload-artifact@v3
with:
name: artifacts_bbb-freeswitch.tar
path: |
artifacts.tar
build-others:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: ./build/get_external_dependencies.sh
- run: echo "FORCE_GIT_REV=0" >> $GITHUB_ENV #used by setup.sh
- run: echo "FORCE_COMMIT_DATE=0" >> $GITHUB_ENV #used by setup.sh
- run: ./build/setup.sh bbb-mkclean
- run: ./build/setup.sh bbb-pads
- run: ./build/setup.sh bbb-libreoffice-docker
- run: ./build/setup.sh bbb-webrtc-sfu
- run: ./build/setup.sh bbb-webrtc-recorder
- run: ./build/setup.sh bbb-transcription-controller
@ -57,37 +314,114 @@ jobs:
artifacts.tar
# - name: Fake package build
# run: |
# sudo sh -c '
# sudo -i <<EOF
# set -e
# echo "Faking a package build (to speed up installation test)"
# cd /
# wget -q "http://ci.bbb.imdt.dev/artifacts.tar"
# wget -nv "http://ci.bbb.imdt.dev/artifacts.tar"
# tar xf artifacts.tar
# '
# mv artifacts /home/runner/work/bigbluebutton/bigbluebutton/artifacts/
# EOF
install-and-run-tests:
needs: [build-bbb-apps-akka, build-bbb-config, build-bbb-export-annotations, build-bbb-learning-dashboard, build-bbb-playback-record, build-bbb-graphql-server, build-bbb-etherpad, build-bbb-bbb-web, build-bbb-fsesl-akka, build-bbb-html5, build-bbb-freeswitch, build-others]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- run: ./build/get_external_dependencies.sh
- name: Download artifacts_bbb-apps-akka
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-apps-akka.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-config
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-config.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-export-annotations
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-export-annotations.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-learning-dashboard
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-learning-dashboard.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-playback-record
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-playback-record.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-graphql-server
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-graphql-server.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-etherpad
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-etherpad.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-freeswitch
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-freeswitch.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-web
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-web.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-fsesl-akka
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-fsesl-akka.tar
- run: tar xf artifacts.tar
- name: Download artifacts_bbb-html5
uses: actions/download-artifact@v3
with:
name: artifacts_bbb-html5.tar
- run: tar xf artifacts.tar
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: artifacts.tar
- run: tar xf artifacts.tar
- name: Extracting files .tar
run: |
set -e
pwd
echo "----ls artifacts/----"
ls artifacts/
echo "Done"
- name: Generate CA
run: |
sudo sh -c '
sudo -i <<EOF
set -e
mkdir /root/bbb-ci-ssl/
cd /root/bbb-ci-ssl/
openssl rand -base64 48 > /root/bbb-ci-ssl/bbb-dev-ca.pass ;
chmod 600 /root/bbb-ci-ssl/bbb-dev-ca.pass ;
openssl genrsa -des3 -out bbb-dev-ca.key -passout file:/root/bbb-ci-ssl/bbb-dev-ca.pass 2048 ;
openssl req -x509 -new -nodes -key bbb-dev-ca.key -sha256 -days 1460 -passin file:/root/bbb-ci-ssl/bbb-dev-ca.pass -out bbb-dev-ca.crt -subj "/C=CA/ST=BBB/L=BBB/O=BBB/OU=BBB/CN=BBB-DEV" ;
'
EOF
- name: Trust CA
run: |
sudo sh -c '
sudo -i <<EOF
set -e
sudo mkdir /usr/local/share/ca-certificates/bbb-dev/
sudo cp /root/bbb-ci-ssl/bbb-dev-ca.crt /usr/local/share/ca-certificates/bbb-dev/
sudo chmod 644 /usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt
sudo update-ca-certificates
'
EOF
- name: Generate certificate
run: |
sudo sh -c '
cd /root/bbb-ci-ssl/
echo "$(hostname -I | cut -d" " -f1) bbb-ci.test" >> /etc/hosts
openssl genrsa -out bbb-ci.test.key 2048
rm bbb-ci.test.csr bbb-ci.test.crt bbb-ci.test.key
rm -f bbb-ci.test.csr bbb-ci.test.crt bbb-ci.test.key
cat > bbb-ci.test.ext << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
@ -107,32 +441,33 @@ jobs:
cat /root/bbb-ci-ssl/bbb-ci.test.key > /local/certs/privkey.pem
'
- name: Setup local repository
shell: bash
run: |
sudo sh -c '
sudo -i <<EOF
set -e
apt install -yq dpkg-dev
cd /root && wget -q http://ci.bbb.imdt.dev/cache-3rd-part-packages.tar
cd /root && wget -nv http://ci.bbb.imdt.dev/cache-3rd-part-packages.tar
cp -r /home/runner/work/bigbluebutton/bigbluebutton/artifacts/ /artifacts/
cd /artifacts && tar xf /root/cache-3rd-part-packages.tar
cd /artifacts && dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
echo "deb [trusted=yes] file:/artifacts/ ./" >> /etc/apt/sources.list
'
EOF
- name: Prepare for install
run: |
sudo sh -c '
apt --purge -y remove apache2-bin
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y
'
- name: Install BBB
run: |
sudo sh -c '
sudo -i <<EOF
set -e
cd /root/ && wget -q https://raw.githubusercontent.com/bigbluebutton/bbb-install/v2.8.x-release/bbb-install.sh -O bbb-install.sh
cat bbb-install.sh | sed "s|> /etc/apt/sources.list.d/bigbluebutton.list||g" | bash -s -- -v jammy-28-develop -s bbb-ci.test -j -d /certs/
bbb-conf --salt bbbci
echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/bbb-dev/bbb-dev-ca.crt" >> /usr/share/meteor/bundle/bbb-html5-with-roles.conf
sed -i "s/\"minify\": true,/\"minify\": false,/" /usr/share/etherpad-lite/settings.json
bbb-conf --restart
'
EOF
- name: Install test dependencies
working-directory: ./bigbluebutton-tests/playwright
run: |
@ -174,7 +509,7 @@ jobs:
- if: failure()
name: Prepare artifacts (configs and logs)
run: |
sudo sh -c '
sudo -i <<EOF
mkdir configs
cp /etc/haproxy/haproxy.cfg configs/haproxy.cfg
touch /etc/bigbluebutton/turn-stun-servers.xml
@ -191,10 +526,11 @@ jobs:
cp /etc/bbb-webrtc-recorder/bbb-webrtc-recorder.yml configs/bbb-webrtc-recorder-default.yml
cp /usr/share/bigbluebutton/nginx/sip.nginx configs/nginx_sip.nginx
cp /etc/hosts /configs/hosts
chmod a+r -R configs
mv configs /home/runner/work/bigbluebutton/bigbluebutton/configs
chmod a+r -R /home/runner/work/bigbluebutton/bigbluebutton/configs
bbb-conf --zip
cp $(ls -t /root/*.tar.gz | head -1) ./bbb-logs.tar.gz
'
ls -t /root/*.tar.gz | head -1 | xargs -I '{}' cp '{}' /home/runner/work/bigbluebutton/bigbluebutton/bbb-logs.tar.gz
EOF
- if: failure()
uses: actions/upload-artifact@v3
with:

View File

@ -24,9 +24,10 @@ const TRACE_LOGS = Meteor.settings.public.kurento.traceLogs;
const GATHERING_TIMEOUT = Meteor.settings.public.kurento.gatheringTimeout;
const MEDIA = Meteor.settings.public.media;
const DEFAULT_FULLAUDIO_MEDIA_SERVER = MEDIA.audio.fullAudioMediaServer;
const RETRY_THROUGH_RELAY = MEDIA.audio.retryThroughRelay || false;
const LISTEN_ONLY_OFFERING = MEDIA.listenOnlyOffering;
const MEDIA_TAG = MEDIA.mediaTag.replace(/#/g, '');
const RECONNECT_TIMEOUT_MS = MEDIA.listenOnlyCallTimeout || 15000;
const CONNECTION_TIMEOUT_MS = MEDIA.listenOnlyCallTimeout || 15000;
const { audio: NETWORK_PRIORITY } = MEDIA.networkPriorities || {};
const SENDRECV_ROLE = 'sendrecv';
const RECV_ROLE = 'recv';
@ -44,6 +45,9 @@ const errorCodeMap = {
1307: 1007,
};
// Error codes that are prone to a retry according to RETRY_THROUGH_RELAY
const RETRYABLE_ERRORS = [1007, 1010];
const mapErrorCode = (error) => {
const { errorCode } = error;
const mappedErrorCode = errorCodeMap[errorCode];
@ -76,8 +80,9 @@ export default class SFUAudioBridge extends BaseAudioBridge {
this.broker = null;
this.reconnecting = false;
this.iceServers = [];
this.inEchoTest = false;
this.bridgeName = BRIDGE_NAME;
this.handleTermination = this.handleTermination.bind(this);
}
get inputStream() {
@ -111,73 +116,104 @@ export default class SFUAudioBridge extends BaseAudioBridge {
return doGUM(constraints, true);
}
handleTermination() {
return this.callback({ status: this.baseCallStates.ended, bridge: this.bridgeName });
setConnectionTimeout() {
if (this.connectionTimeout) this.clearConnectionTimeout();
this.connectionTimeout = setTimeout(() => {
const error = new Error(`ICE negotiation timeout after ${CONNECTION_TIMEOUT_MS / 1000}s`);
error.errorCode = 1010;
// Duplicating key-vals because I can'decide settle on an error pattern - prlanzarin again
error.errorCause = error.message;
error.errorMessage = error.message;
this.handleBrokerFailure(error);
}, CONNECTION_TIMEOUT_MS);
}
clearReconnectionTimeout() {
this.reconnecting = false;
if (this.reconnectionTimeout) {
clearTimeout(this.reconnectionTimeout);
this.reconnectionTimeout = null;
clearConnectionTimeout() {
if (this.connectionTimeout) {
clearTimeout(this.connectionTimeout);
this.connectionTimeout = null;
}
}
reconnect() {
this.broker.stop();
this.callback({ status: this.baseCallStates.reconnecting, bridge: this.bridgeName });
this.reconnecting = true;
// Set up a reconnectionTimeout in case the server is unresponsive
// for some reason. If it gets triggered, end the session and stop
// trying to reconnect
this.reconnectionTimeout = setTimeout(() => {
this.callback({
status: this.baseCallStates.failed,
error: 1010,
bridgeError: 'Reconnection timeout',
bridge: this.bridgeName,
});
this.broker.stop();
this.clearReconnectionTimeout();
}, RECONNECT_TIMEOUT_MS);
this.joinAudio({ isListenOnly: this.isListenOnly }, this.callback).then(
() => this.clearReconnectionTimeout(),
).catch((error) => {
// Error handling is a no-op because it will be "handled" in handleBrokerFailure
logger.debug({
logCode: 'sfuaudio_reconnect_failed',
extraInfo: {
errorMessage: error.errorMessage,
reconnecting: this.reconnecting,
bridge: this.bridgeName,
role: this.role,
},
}, 'SFU audio reconnect failed');
dispatchAutoplayHandlingEvent(mediaElement) {
const tagFailedEvent = new CustomEvent('audioPlayFailed', {
detail: { mediaElement },
});
window.dispatchEvent(tagFailedEvent);
this.callback({ status: this.baseCallStates.autoplayBlocked, bridge: this.bridgeName });
}
reconnect(options = {}) {
// If broker has already started, fire the reconnecting callback so the user
// knows what's going on
if (this.broker.started) {
this.callback({ status: this.baseCallStates.reconnecting, bridge: this.bridgeName });
} else {
// Otherwise: override termination handler so the ended callback doesn't get
// triggered - this is a retry attempt and the user shouldn't be notified
// yet.
this.broker.onended = () => {};
}
this.broker.stop();
this.reconnecting = true;
this._startBroker({ isListenOnly: this.isListenOnly, ...options })
.catch((error) => {
// Error handling is a no-op because it will be "handled" in handleBrokerFailure
logger.debug({
logCode: 'sfuaudio_reconnect_failed',
extraInfo: {
errorMessage: error.errorMessage,
reconnecting: this.reconnecting,
bridge: this.bridgeName,
role: this.role,
},
}, 'SFU audio reconnect failed');
});
}
handleBrokerFailure(error) {
return new Promise((resolve, reject) => {
this.clearConnectionTimeout();
mapErrorCode(error);
const { errorMessage, errorCause, errorCode } = error;
if (this.broker.started && !this.reconnecting) {
logger.error({
logCode: 'sfuaudio_error_try_to_reconnect',
extraInfo: {
errorMessage,
errorCode,
errorCause,
bridge: this.bridgeName,
role: this.role,
},
}, 'SFU audio failed, try to reconnect');
this.reconnect();
return resolve();
if (!this.reconnecting) {
if (this.broker.started) {
logger.error({
logCode: 'sfuaudio_error_try_to_reconnect',
extraInfo: {
errorMessage,
errorCode,
errorCause,
bridge: this.bridgeName,
role: this.role,
},
}, 'SFU audio failed, try to reconnect');
this.reconnect();
return resolve();
}
if (RETRYABLE_ERRORS.includes(errorCode) && RETRY_THROUGH_RELAY) {
logger.error({
logCode: 'sfuaudio_error_retry_through_relay',
extraInfo: {
errorMessage,
errorCode,
errorCause,
bridge: this.bridgeName,
role: this.role,
},
}, 'SFU audio failed to connect, retry through relay');
this.reconnect({ forceRelay: true });
return resolve();
}
}
// Already tried reconnecting once OR the user handn't succesfully
// connected firsthand. Just finish the session and reject with error
// connected firsthand and retrying isn't an option. Finish the session
// and reject with the error
logger.error({
logCode: 'sfuaudio_error',
extraInfo: {
@ -189,7 +225,7 @@ export default class SFUAudioBridge extends BaseAudioBridge {
role: this.role,
},
}, 'SFU audio failed');
this.clearReconnectionTimeout();
this.clearConnectionTimeout();
this.broker.stop();
this.callback({
status: this.baseCallStates.failed,
@ -201,23 +237,23 @@ export default class SFUAudioBridge extends BaseAudioBridge {
});
}
dispatchAutoplayHandlingEvent(mediaElement) {
const tagFailedEvent = new CustomEvent('audioPlayFailed', {
detail: { mediaElement },
});
window.dispatchEvent(tagFailedEvent);
this.callback({ status: this.baseCallStates.autoplayBlocked, bridge: this.bridgeName });
handleTermination() {
this.clearConnectionTimeout();
return this.callback({ status: this.baseCallStates.ended, bridge: this.bridgeName });
}
handleStart() {
const stream = this.broker.webRtcPeer.getRemoteStream();
const mediaElement = document.getElementById(MEDIA_TAG);
return loadAndPlayMediaStream(stream, mediaElement, false).then(() => this
.callback({
return loadAndPlayMediaStream(stream, mediaElement, false).then(() => {
this.callback({
status: this.baseCallStates.started,
bridge: this.bridgeName,
})).catch((error) => {
});
this.clearConnectionTimeout();
this.reconnecting = false;
}).catch((error) => {
// NotAllowedError equals autoplay issues, fire autoplay handling event.
// This will be handled in audio-manager.
if (error.name === 'NotAllowedError') {
@ -247,9 +283,32 @@ export default class SFUAudioBridge extends BaseAudioBridge {
}
async _startBroker(options) {
try {
this.iceServers = await fetchWebRTCMappedStunTurnServers(this.sessionToken);
} catch (error) {
logger.error({ logCode: 'sfuaudio_stun-turn_fetch_failed' },
'SFU audio bridge failed to fetch STUN/TURN info, using default servers');
this.iceServers = getMappedFallbackStun();
}
return new Promise((resolve, reject) => {
const {
isListenOnly,
extension,
inputStream,
forceRelay: _forceRelay = false,
} = options;
const handleInitError = (_error) => {
mapErrorCode(_error);
if (RETRYABLE_ERRORS.includes(_error?.errorCode)
|| !RETRY_THROUGH_RELAY
|| this.reconnecting) {
reject(_error);
}
};
try {
const { isListenOnly, extension, inputStream } = options;
this.inEchoTest = !!extension;
this.isListenOnly = isListenOnly;
@ -259,7 +318,7 @@ export default class SFUAudioBridge extends BaseAudioBridge {
iceServers: this.iceServers,
mediaServer: getMediaServerAdapter(isListenOnly),
constraints: getAudioConstraints({ deviceId: this.inputDeviceId }),
forceRelay: shouldForceRelay(),
forceRelay: _forceRelay || shouldForceRelay(),
stream: (inputStream && inputStream.active) ? inputStream : undefined,
offering: isListenOnly ? LISTEN_ONLY_OFFERING : true,
signalCandidates: SIGNAL_CANDIDATES,
@ -283,25 +342,19 @@ export default class SFUAudioBridge extends BaseAudioBridge {
this.handleStart().then(resolve).catch(reject);
};
this.broker.joinAudio().catch(reject);
// Set up a connectionTimeout in case the server or network are botching
// negotiation or conn checks.
this.setConnectionTimeout();
this.broker.joinAudio().catch(handleInitError);
} catch (error) {
logger.warn({ logCode: 'sfuaudio_bridge_broker_init_fail' },
'Problem when initializing SFU broker for fullaudio bridge');
reject(error);
handleInitError(error);
}
});
}
async joinAudio(options, callback) {
this.callback = callback;
try {
this.iceServers = await fetchWebRTCMappedStunTurnServers(this.sessionToken);
} catch (error) {
logger.error({ logCode: 'sfuaudio_stun-turn_fetch_failed' },
'SFU audio bridge failed to fetch STUN/TURN info, using default servers');
this.iceServers = getMappedFallbackStun();
}
this.reconnecting = false;
return this._startBroker(options);
}
@ -390,7 +443,8 @@ export default class SFUAudioBridge extends BaseAudioBridge {
exitAudio() {
const mediaElement = document.getElementById(MEDIA_TAG);
this.clearReconnectionTimeout();
this.clearConnectionTimeout();
this.reconnecting = false;
if (this.broker) {
this.broker.stop();

View File

@ -142,6 +142,7 @@ const IsTalkingWrapper = styled.div`
flex-direction: row;
position: relative;
overflow: hidden;
margin-top: 0.5rem;
`;
const Speaking = styled.div`

View File

@ -20,7 +20,8 @@ import { isPresentationEnabled } from '/imports/ui/services/features';
const { isMobile } = deviceInfo;
const propTypes = {
allowDownloadable: PropTypes.bool.isRequired,
allowDownloadOriginal: PropTypes.bool.isRequired,
allowDownloadWithAnnotations: PropTypes.bool.isRequired,
intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
}).isRequired,
@ -804,7 +805,7 @@ class PresentationUploader extends Component {
renderPresentationList() {
const { presentations } = this.state;
const { intl, allowDownloadable } = this.props;
const { intl } = this.props;
let presentationsSorted = presentations;
@ -846,9 +847,7 @@ class PresentationUploader extends Component {
</tr>
<Styled.Head>
<th colSpan={4}>{intl.formatMessage(intlMessages.currentLabel)}</th>
{
allowDownloadable ? <th>{intl.formatMessage(intlMessages.actionsLabel)}</th> : null
}
<th>{intl.formatMessage(intlMessages.actionsLabel)}</th>
</Styled.Head>
</thead>
<tbody>
@ -978,10 +977,10 @@ class PresentationUploader extends Component {
renderDownloadableWithAnnotationsHint() {
const {
intl,
allowDownloadable,
allowDownloadWithAnnotations,
} = this.props;
return allowDownloadable ? (
return allowDownloadWithAnnotations ? (
<Styled.ExportHint>
{intl.formatMessage(intlMessages.exportHint)}
</Styled.ExportHint>
@ -994,7 +993,8 @@ class PresentationUploader extends Component {
const {
intl,
selectedToBeNextCurrent,
allowDownloadable,
allowDownloadOriginal,
allowDownloadWithAnnotations,
renderPresentationItemStatus,
hasAnnotations,
} = this.props;
@ -1068,8 +1068,8 @@ class PresentationUploader extends Component {
</Styled.TableItemStatus>
{
hasError ? null : (
<Styled.TableItemActions notDownloadable={!allowDownloadable}>
{allowDownloadable ? (
<Styled.TableItemActions notDownloadable={!allowDownloadOriginal}>
{allowDownloadOriginal || allowDownloadWithAnnotations ? (
<PresentationDownloadDropdown
hasAnnotations={hasAnyAnnotation}
disabled={shouldDisableExportButton}
@ -1077,6 +1077,8 @@ class PresentationUploader extends Component {
aria-label={formattedDownloadAriaLabel}
color="primary"
isDownloadable={isDownloadable}
allowDownloadOriginal={allowDownloadOriginal}
allowDownloadWithAnnotations={allowDownloadWithAnnotations}
handleToggleDownloadable={this.handleToggleDownloadable}
item={item}
closeModal={() => Session.set('showUploadPresentationView', false)}

View File

@ -8,7 +8,11 @@ import PresUploaderToast from '/imports/ui/components/presentation/presentation-
import PresentationUploader from './component';
import { UsersContext } from '/imports/ui/components/components-data/users-context/context';
import Auth from '/imports/ui/services/auth';
import { isDownloadPresentationWithAnnotationsEnabled, isPresentationEnabled } from '/imports/ui/services/features';
import {
isDownloadPresentationWithAnnotationsEnabled,
isDownloadOriginalPresentationEnabled,
isPresentationEnabled,
} from '/imports/ui/services/features';
import { hasAnnotations } from '/imports/ui/components/whiteboard/service';
const PRESENTATION_CONFIG = Meteor.settings.public.presentation;
@ -44,7 +48,8 @@ export default withTracker(() => {
fileSizeMax: PRESENTATION_CONFIG.mirroredFromBBBCore.uploadSizeMax,
filePagesMax: PRESENTATION_CONFIG.mirroredFromBBBCore.uploadPagesMax,
fileValidMimeTypes: PRESENTATION_CONFIG.uploadValidMimeTypes,
allowDownloadable: isDownloadPresentationWithAnnotationsEnabled(),
allowDownloadOriginal: isDownloadOriginalPresentationEnabled(),
allowDownloadWithAnnotations: isDownloadPresentationWithAnnotationsEnabled(),
handleSave: Service.handleSavePresentation,
handleDismissToast: PresUploaderToast.handleDismissToast,
renderToastList: Service.renderToastList,

View File

@ -74,6 +74,8 @@ class PresentationDownloadDropdown extends PureComponent {
handleDownloadingOfPresentation,
handleToggleDownloadable,
isDownloadable,
allowDownloadOriginal,
allowDownloadWithAnnotations,
item,
closeModal,
} = this.props;
@ -88,31 +90,35 @@ class PresentationDownloadDropdown extends PureComponent {
closeModal();
};
if (!isDownloadable) {
if (allowDownloadOriginal) {
if (!isDownloadable) {
this.menuItems.push({
key: this.actionsKey[0],
dataTest: 'enableOriginalPresentationDownload',
label: intl.formatMessage(intlMessages.enableOriginalPresentationDownload),
onClick: () => toggleDownloadOriginalPresentation(true),
});
} else {
this.menuItems.push({
key: this.actionsKey[0],
dataTest: 'disableOriginalPresentationDownload',
label: intl.formatMessage(intlMessages.disableOriginalPresentationDownload),
onClick: () => toggleDownloadOriginalPresentation(false),
});
}
}
if (allowDownloadWithAnnotations) {
this.menuItems.push({
key: this.actionsKey[0],
dataTest: 'enableOriginalPresentationDownload',
label: intl.formatMessage(intlMessages.enableOriginalPresentationDownload),
onClick: () => toggleDownloadOriginalPresentation(true),
});
} else {
this.menuItems.push({
key: this.actionsKey[0],
dataTest: 'disableOriginalPresentationDownload',
label: intl.formatMessage(intlMessages.disableOriginalPresentationDownload),
onClick: () => toggleDownloadOriginalPresentation(false),
key: this.actionsKey[1],
id: 'sendCurrentStateDocument',
dataTest: 'sendCurrentStateDocument',
label: intl.formatMessage(intlMessages.sendCurrentStateDocument),
onClick: () => {
closeModal();
handleDownloadingOfPresentation('Annotated');
},
});
}
this.menuItems.push({
key: this.actionsKey[1],
id: 'sendCurrentStateDocument',
dataTest: 'sendCurrentStateDocument',
label: intl.formatMessage(intlMessages.sendCurrentStateDocument),
onClick: () => {
closeModal();
handleDownloadingOfPresentation('Annotated');
},
});
return this.menuItems;
}

View File

@ -22,6 +22,7 @@ const TimerWrapper = styled.div`
`;
const Timer = styled.div`
margin-top: 0.5rem;
display: flex;
max-height: ${timerPaddingXL});
`;

View File

@ -80,7 +80,7 @@ const UserAvatar = ({
}}
>
<Styled.Talking talking={talking && !muted && avatar.length === 0} animations={animations} />
<Styled.Talking talking={talking && !muted} animations={animations} />
{avatar.length !== 0 && !emoji
? (

View File

@ -34,6 +34,11 @@ const Image = styled.div`
height: 100%;
width: 100%;
justify-content: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
`;
const Img = styled.img`

View File

@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types';
import Styled from './styles';
import { notify } from '/imports/ui/services/notification';
const ASK_MODERATOR = 'ASK_MODERATOR';
const ALWAYS_ACCEPT = 'ALWAYS_ACCEPT';
@ -36,6 +37,10 @@ const intlMessages = defineMessages({
id: 'app.guest-policy.button.alwaysDeny',
description: 'Always deny button label',
},
feedbackMessage: {
id: 'app.guest-policy.feedbackMessage',
description: 'Feedback message for guest policy change',
},
});
const propTypes = {
@ -47,18 +52,31 @@ const propTypes = {
};
class GuestPolicyComponent extends PureComponent {
constructor(props) {
super(props);
this.handleChangePolicy = this.handleChangePolicy.bind(this);
}
componentWillUnmount() {
const { setIsOpen } = this.props;
setIsOpen(false);
}
handleChangePolicy(policyRule, messageId) {
const { intl, changeGuestPolicy } = this.props;
changeGuestPolicy(policyRule);
notify(intl.formatMessage(intlMessages.feedbackMessage) + intl.formatMessage(messageId), 'success');
}
render() {
const {
setIsOpen,
intl,
guestPolicy,
changeGuestPolicy,
isOpen,
onRequestClose,
priority,
@ -91,7 +109,7 @@ class GuestPolicyComponent extends PureComponent {
aria-pressed={guestPolicy === ASK_MODERATOR}
data-test="askModerator"
onClick={() => {
changeGuestPolicy(ASK_MODERATOR);
this.handleChangePolicy(ASK_MODERATOR, intlMessages.askModerator);
setIsOpen(false);
}}
/>
@ -103,7 +121,7 @@ class GuestPolicyComponent extends PureComponent {
aria-pressed={guestPolicy === ALWAYS_ACCEPT}
data-test="alwaysAccept"
onClick={() => {
changeGuestPolicy(ALWAYS_ACCEPT);
this.handleChangePolicy(ALWAYS_ACCEPT, intlMessages.alwaysAccept);
setIsOpen(false);
}}
/>
@ -115,7 +133,7 @@ class GuestPolicyComponent extends PureComponent {
aria-pressed={guestPolicy === ALWAYS_DENY}
data-test="alwaysDeny"
onClick={() => {
changeGuestPolicy(ALWAYS_DENY);
this.handleChangePolicy(ALWAYS_DENY, intlMessages.alwaysDeny);
setIsOpen(false);
}}
/>

View File

@ -61,7 +61,11 @@ export function isCustomVirtualBackgroundsEnabled() {
}
export function isDownloadPresentationWithAnnotationsEnabled() {
return getDisabledFeatures().indexOf('downloadPresentationWithAnnotations') === -1 && Meteor.settings.public.presentation.allowDownloadable;
return getDisabledFeatures().indexOf('downloadPresentationWithAnnotations') === -1 && Meteor.settings.public.presentation.allowDownloadWithAnnotations;
}
export function isDownloadOriginalPresentationEnabled() {
return getDisabledFeatures().indexOf('downloadOriginalPresentation') === -1 && Meteor.settings.public.presentation.allowDownloadOriginal;
}
export function isSnapshotOfCurrentSlideEnabled() {

View File

@ -59,13 +59,13 @@ public:
# the default logoutUrl matches window.location.origin i.e. bigbluebutton.org for demo.bigbluebutton.org
# in some cases we want only custom logoutUrl to be used when provided on meeting create. Default value: true
askForConfirmationOnLeave: true
wakeLock:
wakeLock:
enabled: false
allowDefaultLogoutUrl: true
allowUserLookup: false
dynamicGuestPolicy: true
enableGuestLobbyMessage: true
guestPolicyExtraAllowOptions: true
guestPolicyExtraAllowOptions: false
alwaysShowWaitingRoomUI: true
enableLimitOfViewersInWebcam: false
enableMultipleCameras: true
@ -169,7 +169,7 @@ public:
enableCopyNetworkStatsButton: true
# where should client settings be stored? if you run a single BBB server or
# a cluster with a reverse proxy in front of it, you may set this to 'local'
# See https://docs.bigbluebutton.org/administration/cluster-proxy
# See See https://docs.bigbluebutton.org/administration/cluster-proxy
# allowed values:
# 'session' -> settings are stored in browser sessionStorage
# 'local' -> settings are stored in browser localStorage
@ -563,7 +563,7 @@ public:
type_private: PRIVATE_ACCESS
system_userid: SYSTEM_MESSAGE
system_username: SYSTEM_MESSAGE
public_id: MAIN-PUBLIC-GROUP-CHAT
public_id: public
public_group_id: MAIN-PUBLIC-GROUP-CHAT
public_userid: public_chat_userid
public_username: public_chat_username
@ -639,6 +639,9 @@ public:
path: 'bridge/sip'
- name: fullaudio
path: 'bridge/sfu-audio-bridge'
# Forces a retry with iceTransportPolicy = 'relay' if the first attempt
# fails with a few selected errors codes (eg 1007, 1010)
retryThroughRelay: false
stunTurnServersFetchAddress: '/bigbluebutton/api/stuns'
cacheStunTurnServers: true
fallbackStunServer: ''
@ -653,7 +656,7 @@ public:
callHangupTimeout: 2000
callHangupMaximumRetries: 10
echoTestNumber: 'echo'
listenOnlyCallTimeout: 25000
listenOnlyCallTimeout: 15000
# Experimental. True is the canonical behavior. Flip to false to reverse
# the negotiation flow for LO subscribers.
listenOnlyOffering: false
@ -742,7 +745,8 @@ public:
- critical
help: STATS_HELP_URL
presentation:
allowDownloadable: true
allowDownloadOriginal: true
allowDownloadWithAnnotations: true
allowSnapshotOfCurrentSlide: true
panZoomThrottle: 32
restoreOnUpdate: true

View File

@ -288,7 +288,7 @@
"app.presentationUploader.sent": "Sent",
"app.presentationUploader.exportingTimeout": "The export is taking too long...",
"app.presentationUploader.export": "Send to chat",
"app.presentationUploader.exportCurrentStatePresentation": "Send out a download link for the presentation in the current state of it",
"app.presentationUploader.exportCurrentStatePresentation": "Send out a download link for the presentation in its current state",
"app.presentationUploader.enableOriginalPresentationDownload": "Enable download of the original presentation",
"app.presentationUploader.disableOriginalPresentationDownload": "Disable download of the original presentation",
"app.presentationUploader.dropdownExportOptions": "Export options",
@ -969,6 +969,7 @@
"app.guest-policy.button.alwaysAccept": "Always accept",
"app.guest-policy.button.alwaysDeny": "Always deny",
"app.guest-policy.policyBtnDesc": "Sets meeting guest policy",
"app.guest-policy.feedbackMessage": "The guest policy is now: ",
"app.connection-status.ariaTitle": "Connection status modal",
"app.connection-status.title": "Connection status",
"app.connection-status.description": "View users' connection status",

View File

@ -28,7 +28,8 @@ async function generateSettingsData(page) {
pollEnabled: settingsData.poll.enabled,
pollChatMessage: settingsData.poll.chatMessage,
// Presentation
presentationDownloadable: settingsData.presentation.allowDownloadable,
originalPresentationDownloadable: settingsData.presentation.allowDownloadOriginal,
presentationWithAnnotationsDownloadable: settingsData.presentation.allowDownloadWithAnnotations,
externalVideoPlayer: settingsData.externalVideoPlayer.enabled,
presentationHidden: settingsData.layout.hidePresentation,
// Screensharing

View File

@ -5,8 +5,8 @@
"test:filter": "npx playwright test -g",
"test:headed": "npx playwright test --headed",
"test:debug": "npx playwright test --debug -g",
"test-chromium-ci": "export CI='true' && npx playwright test --project=chromium --grep @ci",
"test-firefox-ci": "export CI='true' && npx playwright test --project=firefox --grep @ci",
"test-chromium-ci": "export CI='true' && npx playwright test --project=chromium --grep @ci --grep-invert @flaky",
"test-firefox-ci": "export CI='true' && npx playwright test --project=firefox --grep @ci --grep-invert @flaky",
"rewrite-snapshots": "read -p 'CAUTION: You will delete ALL testing folders containing snapshots and run the tests to rewrite these files.\nProceed? (y/n) ' confirm && test $confirm = 'y' && sh core/scripts/rewrite-snapshots.sh"
},
"dependencies": {
@ -19,4 +19,4 @@
"sha1": "^1.1.1",
"xml2js": "^0.6.0"
}
}
}

View File

@ -4,6 +4,7 @@ const { DisabledFeatures } = require('./disabledFeatures');
const c = require('./constants');
const { encodeCustomParams, getAllShortcutParams, hexToRgb } = require('./util');
const { CreateParameters } = require('./createParameters');
const { linkIssue } = require('../core/helpers');
test.describe.parallel('Create Parameters', () => {
test('Record Meeting', async ({ browser, context, page }) => {
@ -257,7 +258,7 @@ test.describe.parallel('Create Parameters', () => {
await disabledFeatures.downloadPresentationWithAnnotationsExclude();
});
});
test.describe.serial(() => {
test('Import Presentation With Annotations From Breakout Rooms', async ({ browser, context, page }) => {
const disabledFeatures = new DisabledFeatures(browser, context);

View File

@ -122,8 +122,8 @@ class Presentation extends MultiUsers {
}
async enableAndDisablePresentationDownload(testInfo) {
const { presentationDownloadable } = getSettings();
test.fail(!presentationDownloadable, 'Presentation download is disable');
const { originalPresentationDownloadable } = getSettings();
test.fail(!originalPresentationDownloadable, 'Presentation download is disable');
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
// enable original presentation download
@ -152,8 +152,8 @@ class Presentation extends MultiUsers {
}
async sendPresentationToDownload(testInfo) {
const { presentationDownloadable } = getSettings();
test.fail(!presentationDownloadable, 'Presentation download is disable');
const { presentationWithAnnotationsDownloadable } = getSettings();
test.fail(!presentationWithAnnotationsDownloadable, 'Presentation download is disable');
await this.modPage.waitForSelector(e.whiteboard, ELEMENT_WAIT_LONGER_TIME);
await this.modPage.waitAndClick(e.actions);

View File

@ -89,7 +89,7 @@ test.describe.parallel('Presentation', () => {
await presentation.initPages(page);
await presentation.enableAndDisablePresentationDownload(testInfo);
});
test('Send presentation in the current state (with annotations) to chat for downloading @ci', async ({ browser, context, page }, testInfo) => {
const presentation = new Presentation(browser, context);
await presentation.initPages(page);

View File

@ -2,9 +2,9 @@ const { test } = require('@playwright/test');
const { MultiUsers } = require('../user/multiusers');
const { Webcam } = require('./webcam');
test.describe.parallel('Webcam @ci', () => {
test.describe.parallel('Webcam', () => {
// https://docs.bigbluebutton.org/2.6/release-tests.html#joining-webcam-automated
test('Shares webcam', async ({ browser, page }) => {
test('Shares webcam @ci', async ({ browser, page }) => {
const webcam = new Webcam(browser, page);
await webcam.init(true, true);
await webcam.share();
@ -49,7 +49,9 @@ test.describe.parallel('Webcam @ci', () => {
await webcam.applyBackground();
});
test('Managing new background', async ({ browser, page }) => {
// following test is throwing failures due to mis-comparison screenshot
// as the emulated video is not static, we may add a mask in the middle part - where it moves the most
test('Managing new background @flaky', async ({ browser, page }) => {
const webcam = new Webcam(browser, page);
await webcam.init(true, true);
await webcam.managingNewBackground();

View File

@ -432,7 +432,8 @@ endWhenNoModeratorDelayInMinutes=1
# Available options:
# chat, sharedNotes, polls, screenshare, externalVideos, presentation, downloadPresentationWithAnnotations
# learningDashboard, layouts, captions, liveTranscription, virtualBackgrounds, customVirtualBackgrounds
# breakoutRooms, importSharedNotesFromBreakoutRooms, importPresentationWithAnnotationsFromBreakoutRooms
# breakoutRooms, importSharedNotesFromBreakoutRooms, importPresentationWithAnnotationsFromBreakoutRooms,
# downloadOriginalPresentation
disabledFeatures=
# Notify users that recording is on

View File

@ -24,6 +24,15 @@ else
fi
COMMIT_DATE="$(git log -n1 --pretty='format:%cd' --date=format:'%Y%m%dT%H%M%S')"
# FORCE_GIT_REV and FORCE_COMMIT_DATE are useful for Github Actions be able to cache previous packages
# It sets FORCE_GIT_REV=0 and FORCE_COMMIT_DATE=0 in order to keep the same package version always
if [ ! -z "$FORCE_GIT_REV" ]; then
GIT_REV=$FORCE_GIT_REV
fi
if [ ! -z "$FORCE_COMMIT_DATE" ]; then
COMMIT_DATE=$FORCE_COMMIT_DATE
fi
# Arrange to write the docker container ID to a temp file, then run
# the container detached and immediately attach it (without stdin) so
# we can catch CTRL-C in this script and kill the container if so.

View File

@ -118,6 +118,7 @@ For full details on what is new in BigBlueButton 2.7, see the release notes.
Recent releases:
- [2.7.0-beta.3](https://github.com/bigbluebutton/bigbluebutton/releases/tag/v2.7.0-beta.3)
- [2.7.0-beta.2](https://github.com/bigbluebutton/bigbluebutton/releases/tag/v2.7.0-beta.2)
- [2.7.0-beta.1](https://github.com/bigbluebutton/bigbluebutton/releases/tag/v2.7.0-beta.1)
- [2.7.0-alpha.3](https://github.com/bigbluebutton/bigbluebutton/releases/tag/v2.7.0-alpha.3)
@ -130,6 +131,10 @@ Recent releases:
If you are using bbb-install to configure your servers, be aware that starting with BigBlueButton 2.6's version of bbb-install by default we install a local TURN server. For more information: https://github.com/bigbluebutton/bbb-install/pull/579 and https://docs.bigbluebutton.org/administration/turn-server
#### Changing the default setting `guestPolicyExtraAllowOptions`
Starting with BigBlueButton 2.7.0-beta.3 we are hiding by default a couple extra options in the guest approve panel. 'Allow all authenticated users' and 'Allow all guests' options will be hidden unless you override the option `app.public.guestPolicyExtraAllowOptions` in `bbb-html5` config file `settings.yml`. These extra options were not relevant to the vast majority of the use cases and when hidden, the interface becomes much simpler.
### Development
For information on developing in BigBlueButton, see [setting up a development environment for 2.7](/development/guide).