diff --git a/demos/browser/app/meetingV2/meetingV2.html b/demos/browser/app/meetingV2/meetingV2.html
index daf82cf383..75eb135bc9 100644
--- a/demos/browser/app/meetingV2/meetingV2.html
+++ b/demos/browser/app/meetingV2/meetingV2.html
@@ -67,7 +67,7 @@
Join a meeting
-
+
diff --git a/demos/browser/app/meetingV2/meetingV2.ts b/demos/browser/app/meetingV2/meetingV2.ts
index d4a95fa8d5..ebb56dd6cc 100644
--- a/demos/browser/app/meetingV2/meetingV2.ts
+++ b/demos/browser/app/meetingV2/meetingV2.ts
@@ -628,149 +628,14 @@ export class DemoMeetingApp
(document.getElementById('primary-meeting-external-id') as HTMLInputElement).value = "";
});
- document.getElementById('form-authenticate').addEventListener('submit', e => {
+ document.getElementById('quick-join').addEventListener('click', e => {
e.preventDefault();
- this.meeting = (document.getElementById('inputMeeting') as HTMLInputElement).value;
- this.name = (document.getElementById('inputName') as HTMLInputElement).value;
- this.region = (document.getElementById('inputRegion') as HTMLInputElement).value;
- this.enableSimulcast = (document.getElementById('simulcast') as HTMLInputElement).checked;
- this.enableEventReporting = (document.getElementById('event-reporting') as HTMLInputElement).checked;
- this.deleteOwnAttendeeToLeave = (document.getElementById('delete-attendee') as HTMLInputElement).checked;
- this.enableWebAudio = (document.getElementById('webaudio') as HTMLInputElement).checked;
- this.usePriorityBasedDownlinkPolicy = (document.getElementById('priority-downlink-policy') as HTMLInputElement).checked;
- this.echoReductionCapability = (document.getElementById('echo-reduction-capability') as HTMLInputElement).checked;
- this.primaryExternalMeetingId = (document.getElementById('primary-meeting-external-id') as HTMLInputElement).value;
-
- const chosenLogLevel = (document.getElementById('logLevelSelect') as HTMLSelectElement).value;
- switch (chosenLogLevel) {
- case 'INFO':
- this.logLevel = LogLevel.INFO;
- break;
- case 'DEBUG':
- this.logLevel = LogLevel.DEBUG;
- break;
- case 'WARN':
- this.logLevel = LogLevel.WARN;
- break;
- case 'ERROR':
- this.logLevel = LogLevel.ERROR;
- break;
- default:
- this.logLevel = LogLevel.OFF;
- break;
- }
-
- const chosenVideoSendCodec = (document.getElementById('videoCodecSelect') as HTMLSelectElement).value;
- switch (chosenVideoSendCodec) {
- case 'vp8':
- this.videoCodecPreferences = [VideoCodecCapability.vp8()];
- break;
- case 'h264ConstrainedBaselineProfile':
- this.videoCodecPreferences = [VideoCodecCapability.h264ConstrainedBaselineProfile(), VideoCodecCapability.vp8()];
- break;
- default:
- // If left on 'Meeting Default', use the existing behavior when `setVideoCodecSendPreferences` is not called
- // which should be equivalent to `this.videoCodecPreferences = [VideoCodecCapability.h264ConstrainedBaselineProfile()]`
- break;
- }
-
- AsyncScheduler.nextTick(
- async (): Promise => {
- let chimeMeetingId: string = '';
- this.showProgress('progress-authenticate');
- try {
- chimeMeetingId = await this.authenticate();
- } catch (error) {
- console.error(error);
- const httpErrorMessage =
- 'UserMedia is not allowed in HTTP sites. Either use HTTPS or enable media capture on insecure sites.';
- (document.getElementById(
- 'failed-meeting'
- ) as HTMLDivElement).innerText = `Meeting ID: ${this.meeting}`;
- (document.getElementById('failed-meeting-error') as HTMLDivElement).innerText =
- window.location.protocol === 'http:' ? httpErrorMessage : error.message;
- this.switchToFlow('flow-failed-meeting');
- return;
- }
- (document.getElementById(
- 'meeting-id'
- ) as HTMLSpanElement).innerText = `${this.meeting} (${this.region})`;
- (document.getElementById(
- 'chime-meeting-id'
- ) as HTMLSpanElement).innerText = `Meeting ID: ${chimeMeetingId}`;
- (document.getElementById(
- 'mobile-chime-meeting-id'
- ) as HTMLSpanElement).innerText = `Meeting ID: ${chimeMeetingId}`;
- (document.getElementById(
- 'mobile-attendee-id'
- ) as HTMLSpanElement).innerText = `Attendee ID: ${this.meetingSession.configuration.credentials.attendeeId}`;
- (document.getElementById(
- 'desktop-attendee-id'
- ) as HTMLSpanElement).innerText = `Attendee ID: ${this.meetingSession.configuration.credentials.attendeeId}`;
- (document.getElementById('info-meeting') as HTMLSpanElement).innerText = this.meeting;
- (document.getElementById('info-name') as HTMLSpanElement).innerText = this.name;
-
- if (this.isViewOnly) {
- this.updateUXForViewOnlyMode();
- await this.openAudioOutputFromSelection();
- await this.join();
- this.switchToFlow('flow-meeting');
- this.hideProgress('progress-authenticate');
- return;
- }
- await this.initVoiceFocus();
- await this.initBackgroundBlur();
- await this.initBackgroundReplacement();
- await this.populateAllDeviceLists();
- await this.populateVideoFilterInputList(false);
- await this.populateVideoFilterInputList(true);
- if (this.enableSimulcast) {
- const videoInputQuality = document.getElementById(
- 'video-input-quality'
- ) as HTMLSelectElement;
- videoInputQuality.value = '720p';
- this.audioVideo.chooseVideoInputQuality(1280, 720, 15);
- videoInputQuality.disabled = true;
- }
-
- // `this.primaryExternalMeetingId` may by the join request
- const buttonPromoteToPrimary = document.getElementById('button-promote-to-primary');
- if (!this.primaryExternalMeetingId) {
- buttonPromoteToPrimary.style.display = 'none';
- } else {
- this.setButtonVisibility('button-record-cloud', false);
- this.updateUXForReplicaMeetingPromotionState('demoted');
- }
- /* @ts-ignore */
- if ((e as SubmitEvent).submitter.id == 'quick-join') {
- await this.openAudioInputFromSelectionAndPreview();
- await this.openAudioOutputFromSelection();
- await this.join();
- this.displayButtonStates();
- this.switchToFlow('flow-meeting');
- this.hideProgress('progress-authenticate');
- return;
- }
- this.switchToFlow('flow-devices');
- await this.openAudioInputFromSelectionAndPreview();
- try {
- await this.openVideoInputFromSelection(
- (document.getElementById('video-input') as HTMLSelectElement).value,
- true
- );
- } catch (err) {
- fatal(err);
- }
- await this.openAudioOutputFromSelection();
- this.hideProgress('progress-authenticate');
+ this.redirectFromAuthentication(true);
+ });
- // Open the signaling connection while the user is checking their input devices.
- const preconnect = document.getElementById('preconnect') as HTMLInputElement;
- if (preconnect.checked) {
- this.audioVideo.start({ signalingOnly: true });
- }
- }
- );
+ document.getElementById('form-authenticate').addEventListener('submit', e => {
+ e.preventDefault();
+ this.redirectFromAuthentication();
});
const earlyConnectCheckbox = document.getElementById('preconnect') as HTMLInputElement;
@@ -2003,8 +1868,8 @@ export class DemoMeetingApp
new DefaultModality(attendeeId).base() === this.meetingSession.configuration.credentials.attendeeId
|| new DefaultModality(attendeeId).base() === this.primaryMeetingSessionCredentials?.attendeeId
if (!present) {
- this.roster.removeAttendee(attendeeId);
- this.audioVideo.realtimeUnsubscribeFromVolumeIndicator(attendeeId, this.volumeIndicatorHandler);
+ this.roster.removeAttendee(attendeeId);
+ this.audioVideo.realtimeUnsubscribeFromVolumeIndicator(attendeeId, this.volumeIndicatorHandler);
this.log(`${attendeeId} dropped = ${dropped} (${externalUserId})`);
return;
}
@@ -2020,7 +1885,7 @@ export class DemoMeetingApp
const attendeeName = externalUserId.split('#').slice(-1)[0] + (isContentAttendee ? ' «Content»' : '');
this.roster.addAttendee(attendeeId, attendeeName);
- this.volumeIndicatorHandler = async (
+ this.volumeIndicatorHandler = async (
attendeeId: string,
volume: number | null,
muted: boolean | null,
@@ -2043,7 +1908,7 @@ export class DemoMeetingApp
this.activeSpeakerHandler = (attendeeIds: string[]): void => {
// First reset all roster active speaker information
for (const id of this.roster.getAllAttendeeIds()) {
- this.roster.setAttendeeSpeakingStatus(id, false);
+ this.roster.setAttendeeSpeakingStatus(id, false);
}
// Then re-update roster and tile collection with latest information
@@ -3674,6 +3539,140 @@ export class DemoMeetingApp
}
}
+ private redirectFromAuthentication(quickjoin: boolean = false): void {
+ this.meeting = (document.getElementById('inputMeeting') as HTMLInputElement).value;
+ this.name = (document.getElementById('inputName') as HTMLInputElement).value;
+ this.region = (document.getElementById('inputRegion') as HTMLInputElement).value;
+ this.enableSimulcast = (document.getElementById('simulcast') as HTMLInputElement).checked;
+ this.enableEventReporting = (document.getElementById('event-reporting') as HTMLInputElement).checked;
+ this.deleteOwnAttendeeToLeave = (document.getElementById('delete-attendee') as HTMLInputElement).checked;
+ this.enableWebAudio = (document.getElementById('webaudio') as HTMLInputElement).checked;
+ this.usePriorityBasedDownlinkPolicy = (document.getElementById('priority-downlink-policy') as HTMLInputElement).checked;
+ this.echoReductionCapability = (document.getElementById('echo-reduction-capability') as HTMLInputElement).checked;
+ this.primaryExternalMeetingId = (document.getElementById('primary-meeting-external-id') as HTMLInputElement).value;
+
+ const chosenLogLevel = (document.getElementById('logLevelSelect') as HTMLSelectElement).value;
+ switch (chosenLogLevel) {
+ case 'INFO':
+ this.logLevel = LogLevel.INFO;
+ break;
+ case 'DEBUG':
+ this.logLevel = LogLevel.DEBUG;
+ break;
+ case 'WARN':
+ this.logLevel = LogLevel.WARN;
+ break;
+ case 'ERROR':
+ this.logLevel = LogLevel.ERROR;
+ break;
+ default:
+ this.logLevel = LogLevel.OFF;
+ break;
+ }
+
+ AsyncScheduler.nextTick(
+ async (): Promise => {
+ let chimeMeetingId: string = '';
+ this.showProgress('progress-authenticate');
+ try {
+ chimeMeetingId = await this.authenticate();
+ } catch (error) {
+ console.error(error);
+ const httpErrorMessage =
+ 'UserMedia is not allowed in HTTP sites. Either use HTTPS or enable media capture on insecure sites.';
+ (document.getElementById(
+ 'failed-meeting'
+ ) as HTMLDivElement).innerText = `Meeting ID: ${this.meeting}`;
+ (document.getElementById('failed-meeting-error') as HTMLDivElement).innerText =
+ window.location.protocol === 'http:' ? httpErrorMessage : error.message;
+ this.switchToFlow('flow-failed-meeting');
+ return;
+ }
+ (document.getElementById(
+ 'meeting-id'
+ ) as HTMLSpanElement).innerText = `${this.meeting} (${this.region})`;
+ (document.getElementById(
+ 'chime-meeting-id'
+ ) as HTMLSpanElement).innerText = `Meeting ID: ${chimeMeetingId}`;
+ (document.getElementById(
+ 'mobile-chime-meeting-id'
+ ) as HTMLSpanElement).innerText = `Meeting ID: ${chimeMeetingId}`;
+ (document.getElementById(
+ 'mobile-attendee-id'
+ ) as HTMLSpanElement).innerText = `Attendee ID: ${this.meetingSession.configuration.credentials.attendeeId}`;
+ (document.getElementById(
+ 'desktop-attendee-id'
+ ) as HTMLSpanElement).innerText = `Attendee ID: ${this.meetingSession.configuration.credentials.attendeeId}`;
+ (document.getElementById('info-meeting') as HTMLSpanElement).innerText = this.meeting;
+ (document.getElementById('info-name') as HTMLSpanElement).innerText = this.name;
+
+ if (this.isViewOnly) {
+ this.updateUXForViewOnlyMode();
+ await this.skipDeviceSelection(false);
+ return;
+ }
+ await this.initVoiceFocus();
+ await this.initBackgroundBlur();
+ await this.initBackgroundReplacement();
+ await this.populateAllDeviceLists();
+ await this.populateVideoFilterInputList(false);
+ await this.populateVideoFilterInputList(true);
+ if (this.enableSimulcast) {
+ const videoInputQuality = document.getElementById(
+ 'video-input-quality'
+ ) as HTMLSelectElement;
+ videoInputQuality.value = '720p';
+ this.audioVideo.chooseVideoInputQuality(1280, 720, 15);
+ videoInputQuality.disabled = true;
+ }
+
+ // `this.primaryExternalMeetingId` may by the join request
+ const buttonPromoteToPrimary = document.getElementById('button-promote-to-primary');
+ if (!this.primaryExternalMeetingId) {
+ buttonPromoteToPrimary.style.display = 'none';
+ } else {
+ this.setButtonVisibility('button-record-cloud', false);
+ this.updateUXForReplicaMeetingPromotionState('demoted');
+ }
+
+ if (quickjoin) {
+ await this.skipDeviceSelection();
+ this.displayButtonStates();
+ return;
+ }
+ this.switchToFlow('flow-devices');
+ await this.openAudioInputFromSelectionAndPreview();
+ try {
+ await this.openVideoInputFromSelection(
+ (document.getElementById('video-input') as HTMLSelectElement).value,
+ true
+ );
+ } catch (err) {
+ fatal(err);
+ }
+ await this.openAudioOutputFromSelection();
+ this.hideProgress('progress-authenticate');
+
+ // Open the signaling connection while the user is checking their input devices.
+ const preconnect = document.getElementById('preconnect') as HTMLInputElement;
+ if (preconnect.checked) {
+ this.audioVideo.start({ signalingOnly: true });
+ }
+ }
+ );
+ }
+
+ // to call from form-authenticate form
+ private async skipDeviceSelection(autoSelectAudioInput: boolean = true): Promise {
+ if (autoSelectAudioInput) {
+ await this.openAudioInputFromSelection();
+ }
+ await this.openAudioOutputFromSelection();
+ await this.join();
+ this.switchToFlow('flow-meeting');
+ this.hideProgress('progress-authenticate');
+ }
+
allowMaxContentShare(): boolean {
const allowed = new URL(window.location.href).searchParams.get('max-content-share') === 'true';
if (allowed) {