mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: full video dimensions refactoring
parent
928514d57c
commit
ef013ca5e0
|
@ -116,85 +116,71 @@ export class OpenVidu {
|
||||||
*/
|
*/
|
||||||
ee = new EventEmitter()
|
ee = new EventEmitter()
|
||||||
|
|
||||||
|
onOrientationChanged(handler): void {
|
||||||
|
(<any>window).addEventListener('orientationchange', handler);
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
platform = PlatformUtils.getInstance();
|
platform = PlatformUtils.getInstance();
|
||||||
this.libraryVersion = packageJson.version;
|
this.libraryVersion = packageJson.version;
|
||||||
logger.info("'OpenVidu' initialized");
|
logger.info("OpenVidu initialized");
|
||||||
logger.info("openvidu-browser version: " + this.libraryVersion);
|
logger.info('Platform detected: ' + platform.getDescription());
|
||||||
|
logger.info('openvidu-browser version: ' + this.libraryVersion);
|
||||||
|
|
||||||
if (platform.isMobileDevice()) {
|
if (platform.isMobileDevice() || platform.isReactNative()) {
|
||||||
// Listen to orientationchange only on mobile devices
|
// Listen to orientationchange only on mobile devices
|
||||||
(<any>window).addEventListener('orientationchange', () => {
|
this.onOrientationChanged(() => {
|
||||||
this.publishers.forEach(publisher => {
|
this.publishers.forEach(publisher => {
|
||||||
if (publisher.stream.isLocalStreamPublished && !!publisher.stream && !!publisher.stream.hasVideo && !!publisher.stream.streamManager.videos[0]) {
|
if (publisher.stream.isLocalStreamPublished && !!publisher.stream && !!publisher.stream.hasVideo) {
|
||||||
|
this.sendNewVideoDimensionsIfRequired(publisher, 'deviceRotated', 75, 10);
|
||||||
let attempts = 0;
|
|
||||||
|
|
||||||
const oldWidth = publisher.stream.videoDimensions.width;
|
|
||||||
const oldHeight = publisher.stream.videoDimensions.height;
|
|
||||||
|
|
||||||
const getNewVideoDimensions = (): Promise<{ newWidth: number, newHeight: number }> => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (platform.isIonicIos()) {
|
|
||||||
// iOS Ionic. Limitation: must get new dimensions from an existing video element already inserted into DOM
|
|
||||||
resolve({
|
|
||||||
newWidth: publisher.stream.streamManager.videos[0].video.videoWidth,
|
|
||||||
newHeight: publisher.stream.streamManager.videos[0].video.videoHeight
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Rest of platforms
|
|
||||||
// New resolution got from different places for Chrome and Firefox. Chrome needs a videoWidth and videoHeight of a videoElement.
|
|
||||||
// Firefox needs getSettings from the videoTrack
|
|
||||||
const firefoxSettings = publisher.stream.getMediaStream().getVideoTracks()[0].getSettings();
|
|
||||||
const newWidth = <number>((platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) ? firefoxSettings.width : publisher.videoReference.videoWidth);
|
|
||||||
const newHeight = <number>((platform.isFirefoxBrowser() || platform.isFirefoxMobileBrowser()) ? firefoxSettings.height : publisher.videoReference.videoHeight);
|
|
||||||
resolve({ newWidth, newHeight });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const repeatUntilChange = setInterval(() => {
|
|
||||||
getNewVideoDimensions().then(newDimensions => {
|
|
||||||
sendStreamPropertyChangedEvent(oldWidth, oldHeight, newDimensions.newWidth, newDimensions.newHeight);
|
|
||||||
});
|
|
||||||
}, 75);
|
|
||||||
|
|
||||||
const sendStreamPropertyChangedEvent = (oldWidth, oldHeight, newWidth, newHeight) => {
|
|
||||||
attempts++;
|
|
||||||
if (attempts > 10) {
|
|
||||||
clearTimeout(repeatUntilChange);
|
|
||||||
}
|
|
||||||
if (newWidth !== oldWidth || newHeight !== oldHeight) {
|
|
||||||
publisher.stream.videoDimensions = {
|
|
||||||
width: newWidth || 0,
|
|
||||||
height: newHeight || 0
|
|
||||||
};
|
|
||||||
this.sendRequest(
|
|
||||||
'streamPropertyChanged',
|
|
||||||
{
|
|
||||||
streamId: publisher.stream.streamId,
|
|
||||||
property: 'videoDimensions',
|
|
||||||
newValue: JSON.stringify(publisher.stream.videoDimensions),
|
|
||||||
reason: 'deviceRotated'
|
|
||||||
},
|
|
||||||
(error, response) => {
|
|
||||||
if (error) {
|
|
||||||
logger.error("Error sending 'streamPropertyChanged' event", error);
|
|
||||||
} else {
|
|
||||||
this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
|
|
||||||
publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, 'deviceRotated')]);
|
|
||||||
this.session.sendVideoData(publisher);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
clearTimeout(repeatUntilChange);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendNewVideoDimensionsIfRequired(publisher: Publisher, reason: string, WAIT_INTERVAL: number, MAX_ATTEMPTS: number) {
|
||||||
|
let attempts = 0;
|
||||||
|
const oldWidth = publisher.stream.videoDimensions.width;
|
||||||
|
const oldHeight = publisher.stream.videoDimensions.height;
|
||||||
|
|
||||||
|
const repeatUntilChangeOrMaxAttempts: NodeJS.Timeout = setInterval(() => {
|
||||||
|
attempts++;
|
||||||
|
if (attempts > MAX_ATTEMPTS) {
|
||||||
|
clearTimeout(repeatUntilChangeOrMaxAttempts);
|
||||||
|
}
|
||||||
|
publisher.getVideoDimensions(publisher.stream.getMediaStream()).then(newDimensions => {
|
||||||
|
if (newDimensions.width !== oldWidth || newDimensions.height !== oldHeight) {
|
||||||
|
clearTimeout(repeatUntilChangeOrMaxAttempts);
|
||||||
|
this.sendVideoDimensionsChangedEvent(publisher, reason, oldWidth, oldHeight, newDimensions.width, newDimensions.height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, WAIT_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendVideoDimensionsChangedEvent(publisher: Publisher, reason: string, oldWidth: number, oldHeight: number, newWidth: number, newHeight: number) {
|
||||||
|
publisher.stream.videoDimensions = {
|
||||||
|
width: newWidth || 0,
|
||||||
|
height: newHeight || 0
|
||||||
|
};
|
||||||
|
this.sendRequest(
|
||||||
|
'streamPropertyChanged',
|
||||||
|
{
|
||||||
|
streamId: publisher.stream.streamId,
|
||||||
|
property: 'videoDimensions',
|
||||||
|
newValue: JSON.stringify(publisher.stream.videoDimensions),
|
||||||
|
reason
|
||||||
|
},
|
||||||
|
(error, response) => {
|
||||||
|
if (error) {
|
||||||
|
logger.error("Error sending 'streamPropertyChanged' event", error);
|
||||||
|
} else {
|
||||||
|
this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, reason)]);
|
||||||
|
publisher.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(publisher, publisher.stream, 'videoDimensions', publisher.stream.videoDimensions, { width: oldWidth, height: oldHeight }, reason)]);
|
||||||
|
this.session.sendVideoData(publisher);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns new session
|
* Returns new session
|
||||||
|
|
|
@ -315,7 +315,10 @@ export class Publisher extends StreamManager {
|
||||||
mediaStream.removeTrack(removedTrack);
|
mediaStream.removeTrack(removedTrack);
|
||||||
removedTrack.stop();
|
removedTrack.stop();
|
||||||
mediaStream.addTrack(track);
|
mediaStream.addTrack(track);
|
||||||
this.session.sendVideoData(this.stream.streamManager, 5, true, 5);
|
if (this.stream.isLocalStreamPublished) {
|
||||||
|
this.openvidu.sendNewVideoDimensionsIfRequired(this, 'trackReplaced', 50, 30);
|
||||||
|
this.session.sendVideoData(this.stream.streamManager, 5, true, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -326,17 +329,20 @@ export class Publisher extends StreamManager {
|
||||||
if (track.kind === 'video') {
|
if (track.kind === 'video') {
|
||||||
sender = senders.find(s => !!s.track && s.track.kind === 'video');
|
sender = senders.find(s => !!s.track && s.track.kind === 'video');
|
||||||
if (!sender) {
|
if (!sender) {
|
||||||
reject(new Error('There\'s no replaceable track for that kind of MediaStreamTrack in this Publisher object'))
|
reject(new Error('There\'s no replaceable track for that kind of MediaStreamTrack in this Publisher object'));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else if (track.kind === 'audio') {
|
} else if (track.kind === 'audio') {
|
||||||
sender = senders.find(s => !!s.track && s.track.kind === 'audio');
|
sender = senders.find(s => !!s.track && s.track.kind === 'audio');
|
||||||
if (!sender) {
|
if (!sender) {
|
||||||
reject(new Error('There\'s no replaceable track for that kind of MediaStreamTrack in this Publisher object'))
|
reject(new Error('There\'s no replaceable track for that kind of MediaStreamTrack in this Publisher object'));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('Unknown track kind ' + track.kind));
|
reject(new Error('Unknown track kind ' + track.kind));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
(<any>sender).replaceTrack(track).then(() => {
|
(sender as RTCRtpSender).replaceTrack(track).then(() => {
|
||||||
replaceMediaStreamTrack();
|
replaceMediaStreamTrack();
|
||||||
resolve();
|
resolve();
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
@ -360,7 +366,7 @@ export class Publisher extends StreamManager {
|
||||||
|
|
||||||
let constraints: MediaStreamConstraints = {};
|
let constraints: MediaStreamConstraints = {};
|
||||||
let constraintsAux: MediaStreamConstraints = {};
|
let constraintsAux: MediaStreamConstraints = {};
|
||||||
const timeForDialogEvent = 1250;
|
const timeForDialogEvent = 1500;
|
||||||
let startTime;
|
let startTime;
|
||||||
|
|
||||||
const errorCallback = (openViduError: OpenViduError) => {
|
const errorCallback = (openViduError: OpenViduError) => {
|
||||||
|
@ -403,102 +409,38 @@ export class Publisher extends StreamManager {
|
||||||
delete this.firstVideoElement;
|
delete this.firstVideoElement;
|
||||||
|
|
||||||
if (this.stream.isSendVideo()) {
|
if (this.stream.isSendVideo()) {
|
||||||
if (!this.stream.isSendScreen()) {
|
// Has video track
|
||||||
|
this.getVideoDimensions(mediaStream).then(dimensions => {
|
||||||
|
this.stream.videoDimensions = {
|
||||||
|
width: dimensions.width,
|
||||||
|
height: dimensions.height
|
||||||
|
};
|
||||||
|
|
||||||
if (platform.isIonicIos() || platform.isSafariBrowser()) {
|
if (this.stream.isSendScreen()) {
|
||||||
// iOS Ionic or Safari. Limitation: cannot set videoDimensions directly, as the videoReference is not loaded
|
// Set interval to listen for screen resize events
|
||||||
// if not added to DOM. Must add it to DOM and wait for videoWidth and videoHeight properties to be defined
|
|
||||||
|
|
||||||
this.videoReference.style.display = 'none';
|
|
||||||
document.body.appendChild(this.videoReference);
|
|
||||||
|
|
||||||
const videoDimensionsSet = () => {
|
|
||||||
this.stream.videoDimensions = {
|
|
||||||
width: this.videoReference.videoWidth,
|
|
||||||
height: this.videoReference.videoHeight
|
|
||||||
};
|
|
||||||
this.stream.isLocalStreamReadyToPublish = true;
|
|
||||||
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
|
||||||
document.body.removeChild(this.videoReference);
|
|
||||||
};
|
|
||||||
|
|
||||||
let interval;
|
|
||||||
this.videoReference.addEventListener('loadedmetadata', () => {
|
|
||||||
if (this.videoReference.videoWidth === 0) {
|
|
||||||
interval = setInterval(() => {
|
|
||||||
if (this.videoReference.videoWidth !== 0) {
|
|
||||||
clearInterval(interval);
|
|
||||||
videoDimensionsSet();
|
|
||||||
}
|
|
||||||
}, 40);
|
|
||||||
} else {
|
|
||||||
videoDimensionsSet();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Rest of platforms
|
|
||||||
// With no screen share, video dimension can be set directly from MediaStream (getSettings)
|
|
||||||
// Orientation must be checked for mobile devices (width and height are reversed)
|
|
||||||
const { width, height } = this.getVideoDimensions(mediaStream);
|
|
||||||
|
|
||||||
if (platform.isMobileDevice() && (window.innerHeight > window.innerWidth)) {
|
|
||||||
// Mobile portrait mode
|
|
||||||
this.stream.videoDimensions = {
|
|
||||||
width: height || 0,
|
|
||||||
height: width || 0
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this.stream.videoDimensions = {
|
|
||||||
width: width || 0,
|
|
||||||
height: height || 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.stream.isLocalStreamReadyToPublish = true;
|
|
||||||
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// With screen share, video dimension must be got from a video element (onloadedmetadata event)
|
|
||||||
this.videoReference.addEventListener('loadedmetadata', () => {
|
|
||||||
this.stream.videoDimensions = {
|
|
||||||
width: this.videoReference.videoWidth,
|
|
||||||
height: this.videoReference.videoHeight
|
|
||||||
};
|
|
||||||
this.screenShareResizeInterval = setInterval(() => {
|
this.screenShareResizeInterval = setInterval(() => {
|
||||||
const firefoxSettings = mediaStream.getVideoTracks()[0].getSettings();
|
const settings: MediaTrackSettings = mediaStream.getVideoTracks()[0].getSettings();
|
||||||
const newWidth = (platform.isChromeBrowser() || platform.isOperaBrowser()) ? this.videoReference.videoWidth : firefoxSettings.width;
|
const newWidth = settings.width;
|
||||||
const newHeight = (platform.isChromeBrowser() || platform.isOperaBrowser()) ? this.videoReference.videoHeight : firefoxSettings.height;
|
const newHeight = settings.height;
|
||||||
if (this.stream.isLocalStreamPublished &&
|
if (this.stream.isLocalStreamPublished &&
|
||||||
(newWidth !== this.stream.videoDimensions.width ||
|
(newWidth !== this.stream.videoDimensions.width || newHeight !== this.stream.videoDimensions.height)) {
|
||||||
newHeight !== this.stream.videoDimensions.height)) {
|
this.openvidu.sendVideoDimensionsChangedEvent(
|
||||||
const oldValue = { width: this.stream.videoDimensions.width, height: this.stream.videoDimensions.height };
|
this,
|
||||||
this.stream.videoDimensions = {
|
'screenResized',
|
||||||
width: newWidth || 0,
|
this.stream.videoDimensions.width,
|
||||||
height: newHeight || 0
|
this.stream.videoDimensions.height,
|
||||||
};
|
newWidth || 0,
|
||||||
this.session.openvidu.sendRequest(
|
newHeight || 0
|
||||||
'streamPropertyChanged',
|
);
|
||||||
{
|
|
||||||
streamId: this.stream.streamId,
|
|
||||||
property: 'videoDimensions',
|
|
||||||
newValue: JSON.stringify(this.stream.videoDimensions),
|
|
||||||
reason: 'screenResized'
|
|
||||||
},
|
|
||||||
(error, response) => {
|
|
||||||
if (error) {
|
|
||||||
logger.error("Error sending 'streamPropertyChanged' event", error);
|
|
||||||
} else {
|
|
||||||
this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'videoDimensions', this.stream.videoDimensions, oldValue, 'screenResized')]);
|
|
||||||
this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'videoDimensions', this.stream.videoDimensions, oldValue, 'screenResized')]);
|
|
||||||
this.session.sendVideoData(this.stream.streamManager);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 650);
|
||||||
this.stream.isLocalStreamReadyToPublish = true;
|
}
|
||||||
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
|
||||||
});
|
this.stream.isLocalStreamReadyToPublish = true;
|
||||||
}
|
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// Only audio track (no videoDimensions)
|
||||||
this.stream.isLocalStreamReadyToPublish = true;
|
this.stream.isLocalStreamReadyToPublish = true;
|
||||||
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
this.stream.ee.emitEvent('stream-ready-to-publish', []);
|
||||||
}
|
}
|
||||||
|
@ -665,9 +607,66 @@ export class Publisher extends StreamManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hidden
|
* @hidden
|
||||||
|
*
|
||||||
|
* To obtain the videoDimensions we wait for the video reference to have enough metadata
|
||||||
|
* and then try to use MediaStreamTrack.getSettingsMethod(). If not available, then we
|
||||||
|
* use the HTMLVideoElement properties videoWidth and videoHeight
|
||||||
*/
|
*/
|
||||||
getVideoDimensions(mediaStream: MediaStream): MediaTrackSettings {
|
getVideoDimensions(mediaStream: MediaStream): Promise<{ width: number, height: number }> {
|
||||||
return mediaStream.getVideoTracks()[0].getSettings();
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
// Ionic iOS and Safari iOS supposedly require the video element to actually exist inside the DOM
|
||||||
|
const requiresDomInsertion: boolean = platform.isIonicIos() || platform.isIOSWithSafari();
|
||||||
|
|
||||||
|
let loadedmetadataListener;
|
||||||
|
const resolveDimensions = () => {
|
||||||
|
let width: number;
|
||||||
|
let height: number;
|
||||||
|
if (typeof this.stream.getMediaStream().getVideoTracks()[0].getSettings === 'function') {
|
||||||
|
const settings = this.stream.getMediaStream().getVideoTracks()[0].getSettings();
|
||||||
|
width = settings.width || this.videoReference.videoWidth;
|
||||||
|
height = settings.height || this.videoReference.videoHeight;
|
||||||
|
} else {
|
||||||
|
logger.warn('MediaStreamTrack does not have getSettings method on ' + platform.getDescription());
|
||||||
|
width = this.videoReference.videoWidth;
|
||||||
|
height = this.videoReference.videoHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadedmetadataListener != null) {
|
||||||
|
this.videoReference.removeEventListener('loadedmetadata', loadedmetadataListener);
|
||||||
|
}
|
||||||
|
if (requiresDomInsertion) {
|
||||||
|
document.body.removeChild(this.videoReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({ width, height });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.videoReference.readyState >= 1) {
|
||||||
|
// The video already has metadata available
|
||||||
|
// No need of loadedmetadata event
|
||||||
|
resolveDimensions();
|
||||||
|
} else {
|
||||||
|
// The video does not have metadata available yet
|
||||||
|
// Must listen to loadedmetadata event
|
||||||
|
loadedmetadataListener = () => {
|
||||||
|
if (!this.videoReference.videoWidth) {
|
||||||
|
let interval = setInterval(() => {
|
||||||
|
if (!!this.videoReference.videoWidth) {
|
||||||
|
clearInterval(interval);
|
||||||
|
resolveDimensions();
|
||||||
|
}
|
||||||
|
}, 40);
|
||||||
|
} else {
|
||||||
|
resolveDimensions();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.videoReference.addEventListener('loadedmetadata', loadedmetadataListener);
|
||||||
|
if (requiresDomInsertion) {
|
||||||
|
document.body.appendChild(this.videoReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -684,17 +683,15 @@ export class Publisher extends StreamManager {
|
||||||
*/
|
*/
|
||||||
initializeVideoReference(mediaStream: MediaStream) {
|
initializeVideoReference(mediaStream: MediaStream) {
|
||||||
this.videoReference = document.createElement('video');
|
this.videoReference = document.createElement('video');
|
||||||
|
this.videoReference.setAttribute('muted', 'true');
|
||||||
|
this.videoReference.style.display = 'none';
|
||||||
if (platform.isSafariBrowser()) {
|
if (platform.isSafariBrowser()) {
|
||||||
this.videoReference.setAttribute('playsinline', 'true');
|
this.videoReference.setAttribute('playsinline', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stream.setMediaStream(mediaStream);
|
this.stream.setMediaStream(mediaStream);
|
||||||
|
|
||||||
if (!!this.firstVideoElement) {
|
if (!!this.firstVideoElement) {
|
||||||
this.createVideoElement(this.firstVideoElement.targetElement, <VideoInsertMode>this.properties.insertMode);
|
this.createVideoElement(this.firstVideoElement.targetElement, <VideoInsertMode>this.properties.insertMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.videoReference.srcObject = mediaStream;
|
this.videoReference.srcObject = mediaStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1193,7 +1193,7 @@ export class Session extends EventDispatcher {
|
||||||
platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() ||
|
platform.isChromeBrowser() || platform.isChromeMobileBrowser() || platform.isOperaBrowser() ||
|
||||||
platform.isOperaMobileBrowser() || platform.isEdgeBrowser() || platform.isEdgeMobileBrowser() || platform.isElectron() ||
|
platform.isOperaMobileBrowser() || platform.isEdgeBrowser() || platform.isEdgeMobileBrowser() || platform.isElectron() ||
|
||||||
(platform.isSafariBrowser() && !platform.isIonicIos()) || platform.isAndroidBrowser() ||
|
(platform.isSafariBrowser() && !platform.isIonicIos()) || platform.isAndroidBrowser() ||
|
||||||
platform.isSamsungBrowser() || platform.isIonicAndroid() || (platform.isIPhoneOrIPad() && platform.isIOSWithSafari())
|
platform.isSamsungBrowser() || platform.isIonicAndroid() || platform.isIOSWithSafari()
|
||||||
) {
|
) {
|
||||||
const obtainAndSendVideo = async () => {
|
const obtainAndSendVideo = async () => {
|
||||||
const pc = streamManager.stream.getRTCPeerConnection();
|
const pc = streamManager.stream.getRTCPeerConnection();
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class StreamPropertyChangedEvent extends Event {
|
||||||
* Cause of the change on the stream's property:
|
* Cause of the change on the stream's property:
|
||||||
* - For `videoActive`: `"publishVideo"`
|
* - For `videoActive`: `"publishVideo"`
|
||||||
* - For `audioActive`: `"publishAudio"`
|
* - For `audioActive`: `"publishAudio"`
|
||||||
* - For `videoDimensions`: `"deviceRotated"` or `"screenResized"`
|
* - For `videoDimensions`: `"deviceRotated"`, `"screenResized"` or `"trackReplaced"`
|
||||||
* - For `filter`: `"applyFilter"`, `"execFilterMethod"` or `"removeFilter"`
|
* - For `filter`: `"applyFilter"`, `"execFilterMethod"` or `"removeFilter"`
|
||||||
*/
|
*/
|
||||||
reason: string;
|
reason: string;
|
||||||
|
|
|
@ -118,7 +118,7 @@ export class PlatformUtils {
|
||||||
*/
|
*/
|
||||||
public isIOSWithSafari(): boolean {
|
public isIOSWithSafari(): boolean {
|
||||||
const userAgent = !!platform.ua ? platform.ua : navigator.userAgent;
|
const userAgent = !!platform.ua ? platform.ua : navigator.userAgent;
|
||||||
return (
|
return this.isIPhoneOrIPad() && (
|
||||||
/\b(\w*Apple\w*)\b/.test(navigator.vendor) &&
|
/\b(\w*Apple\w*)\b/.test(navigator.vendor) &&
|
||||||
/\b(\w*Safari\w*)\b/.test(userAgent) &&
|
/\b(\w*Safari\w*)\b/.test(userAgent) &&
|
||||||
!/\b(\w*CriOS\w*)\b/.test(userAgent) &&
|
!/\b(\w*CriOS\w*)\b/.test(userAgent) &&
|
||||||
|
|
Loading…
Reference in New Issue