fix(iframe): Use largeVideo video element for screenshot.
Get the existing HTMLVideoElement for large video instead of creating a new video element for capturing the screenshot. This should prevent the video player from getting displayed on mobile Safari.
This commit is contained in:
parent
7a9a6855b7
commit
09124ad7e9
|
@ -639,8 +639,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* Captures the screenshot of the large video.
|
* Captures the screenshot of the large video.
|
||||||
*
|
*
|
||||||
* @returns {dataURL} - Base64 encoded image data of the screenshot if large
|
* @returns {Promise<string>} - Resolves with a base64 encoded image data of the screenshot
|
||||||
* video is detected, an error otherwise.
|
* if large video is detected, an error otherwise.
|
||||||
*/
|
*/
|
||||||
captureLargeVideoScreenshot() {
|
captureLargeVideoScreenshot() {
|
||||||
return this._transport.sendRequest({
|
return this._transport.sendRequest({
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
import { _handleParticipantError } from '../base/conference';
|
import { _handleParticipantError } from '../base/conference';
|
||||||
import { MEDIA_TYPE } from '../base/media';
|
import { MEDIA_TYPE } from '../base/media';
|
||||||
import { getParticipants } from '../base/participants';
|
import { getParticipants } from '../base/participants';
|
||||||
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
|
|
||||||
import { reportError } from '../base/util';
|
import { reportError } from '../base/util';
|
||||||
import { shouldDisplayTileView } from '../video-layout';
|
import { shouldDisplayTileView } from '../video-layout';
|
||||||
|
|
||||||
|
@ -18,57 +17,6 @@ import {
|
||||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures a screenshot of the video displayed on the large video.
|
|
||||||
*
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
export function captureLargeVideoScreenshot() {
|
|
||||||
return (dispatch: Dispatch<any>, getState: Function): Promise<Object> => {
|
|
||||||
const state = getState();
|
|
||||||
const largeVideo = state['features/large-video'];
|
|
||||||
|
|
||||||
if (!largeVideo) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
const tracks = state['features/base/tracks'];
|
|
||||||
const { jitsiTrack } = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
|
|
||||||
const videoStream = jitsiTrack.getOriginalStream();
|
|
||||||
|
|
||||||
// Create a HTML canvas and draw video from the track on to the canvas.
|
|
||||||
const [ track ] = videoStream.getVideoTracks();
|
|
||||||
const { height, width } = track.getSettings() ?? track.getConstraints();
|
|
||||||
const canvasElement = document.createElement('canvas');
|
|
||||||
const ctx = canvasElement.getContext('2d');
|
|
||||||
const videoElement = document.createElement('video');
|
|
||||||
|
|
||||||
videoElement.height = parseInt(height, 10);
|
|
||||||
videoElement.width = parseInt(width, 10);
|
|
||||||
videoElement.autoplay = true;
|
|
||||||
videoElement.srcObject = videoStream;
|
|
||||||
canvasElement.height = videoElement.height;
|
|
||||||
canvasElement.width = videoElement.width;
|
|
||||||
|
|
||||||
// Wait for the video to load before drawing on to the canvas.
|
|
||||||
const promise = new Promise(resolve => {
|
|
||||||
videoElement.onloadeddata = () => resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise.then(() => {
|
|
||||||
ctx.drawImage(videoElement, 0, 0, videoElement.width, videoElement.height);
|
|
||||||
const dataURL = canvasElement.toDataURL('image/png', 1.0);
|
|
||||||
|
|
||||||
// Cleanup.
|
|
||||||
ctx.clearRect(0, 0, videoElement.width, videoElement.height);
|
|
||||||
videoElement.srcObject = null;
|
|
||||||
canvasElement.remove();
|
|
||||||
videoElement.remove();
|
|
||||||
|
|
||||||
return Promise.resolve(dataURL);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals conference to select a participant.
|
* Signals conference to select a participant.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,9 +3,56 @@
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
|
||||||
|
import { MEDIA_TYPE } from '../base/media';
|
||||||
|
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
|
||||||
|
|
||||||
export * from './actions.any';
|
export * from './actions.any';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures a screenshot of the video displayed on the large video.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function captureLargeVideoScreenshot() {
|
||||||
|
return (dispatch: Dispatch<any>, getState: Function): Promise<string> => {
|
||||||
|
const state = getState();
|
||||||
|
const largeVideo = state['features/large-video'];
|
||||||
|
|
||||||
|
if (!largeVideo) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
const tracks = state['features/base/tracks'];
|
||||||
|
const { jitsiTrack } = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
|
||||||
|
const videoStream = jitsiTrack.getOriginalStream();
|
||||||
|
|
||||||
|
// Get the video element for the large video, cast HTMLElement to HTMLVideoElement to make flow happy.
|
||||||
|
/* eslint-disable-next-line no-extra-parens*/
|
||||||
|
const videoElement = ((document.getElementById('largeVideo'): any): HTMLVideoElement);
|
||||||
|
|
||||||
|
if (!videoElement) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a HTML canvas and draw video on to the canvas.
|
||||||
|
const [ track ] = videoStream.getVideoTracks();
|
||||||
|
const { height, width } = track.getSettings() ?? track.getConstraints();
|
||||||
|
const canvasElement = document.createElement('canvas');
|
||||||
|
const ctx = canvasElement.getContext('2d');
|
||||||
|
|
||||||
|
canvasElement.style.display = 'none';
|
||||||
|
canvasElement.height = parseInt(height, 10);
|
||||||
|
canvasElement.width = parseInt(width, 10);
|
||||||
|
ctx.drawImage(videoElement, 0, 0);
|
||||||
|
const dataURL = canvasElement.toDataURL('image/png', 1.0);
|
||||||
|
|
||||||
|
// Cleanup.
|
||||||
|
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
|
||||||
|
canvasElement.remove();
|
||||||
|
|
||||||
|
return Promise.resolve(dataURL);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the large video container based on the dimensions provided.
|
* Resizes the large video container based on the dimensions provided.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue