mirror of https://github.com/OpenVidu/openvidu.git
openvidu-browser: OpenVidu.getUserMedia works for screen videoSource
parent
f37f030d98
commit
47312205c5
|
@ -521,11 +521,61 @@ export class OpenVidu {
|
|||
*/
|
||||
getUserMedia(options: PublisherProperties): Promise<MediaStream> {
|
||||
return new Promise<MediaStream>((resolve, reject) => {
|
||||
|
||||
const askForAudioStreamOnly = (previousMediaStream: MediaStream, constraints: MediaStreamConstraints) => {
|
||||
const definedAudioConstraint = ((constraints.audio === undefined) ? true : constraints.audio);
|
||||
const constraintsAux: MediaStreamConstraints = { audio: definedAudioConstraint, video: false };
|
||||
navigator.mediaDevices.getUserMedia(constraintsAux)
|
||||
.then(audioOnlyStream => {
|
||||
previousMediaStream.addTrack(audioOnlyStream.getAudioTracks()[0]);
|
||||
resolve(previousMediaStream);
|
||||
})
|
||||
.catch(error => {
|
||||
previousMediaStream.getAudioTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
previousMediaStream.getVideoTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
reject(this.generateAudioDeviceError(error, constraintsAux));
|
||||
});
|
||||
}
|
||||
|
||||
this.generateMediaConstraints(options)
|
||||
.then(constraints => {
|
||||
navigator.mediaDevices.getUserMedia(constraints)
|
||||
let mustAskForAudioTrackLater = false;
|
||||
if (typeof options.videoSource === 'string') {
|
||||
if (options.videoSource === 'screen' ||
|
||||
(platform.name!.indexOf('Firefox') !== -1 && options.videoSource === 'window')) {
|
||||
// Screen sharing
|
||||
mustAskForAudioTrackLater = options.audioSource !== null && options.audioSource !== false;
|
||||
if (navigator.mediaDevices['getDisplayMedia'] && platform.name !== 'Electron') {
|
||||
navigator.mediaDevices['getDisplayMedia']({ video: true })
|
||||
.then(mediaStream => {
|
||||
if (mustAskForAudioTrackLater) {
|
||||
askForAudioStreamOnly(mediaStream, constraints);
|
||||
return;
|
||||
} else {
|
||||
resolve(mediaStream);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
let errorName: OpenViduErrorName = OpenViduErrorName.SCREEN_CAPTURE_DENIED;
|
||||
const errorMessage = error.toString();
|
||||
reject(new OpenViduError(errorName, errorMessage));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const constraintsAux = mustAskForAudioTrackLater ? { video: constraints.video } : constraints;
|
||||
navigator.mediaDevices.getUserMedia(constraintsAux)
|
||||
.then(mediaStream => {
|
||||
resolve(mediaStream);
|
||||
if (mustAskForAudioTrackLater) {
|
||||
askForAudioStreamOnly(mediaStream, constraints);
|
||||
return;
|
||||
} else {
|
||||
resolve(mediaStream);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
let errorName: OpenViduErrorName;
|
||||
|
@ -599,6 +649,11 @@ export class OpenVidu {
|
|||
};
|
||||
}
|
||||
|
||||
if (audio === false && video === false) {
|
||||
reject(new OpenViduError(OpenViduErrorName.NO_INPUT_SOURCE_SET,
|
||||
"Properties 'audioSource' and 'videoSource' cannot be set to false or null at the same time"));
|
||||
}
|
||||
|
||||
const mediaConstraints: MediaStreamConstraints = {
|
||||
audio,
|
||||
video
|
||||
|
@ -808,6 +863,42 @@ export class OpenVidu {
|
|||
return this.recorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
generateAudioDeviceError(error, constraints: MediaStreamConstraints): OpenViduError {
|
||||
if (error.name === 'Error') {
|
||||
// Safari OverConstrainedError has as name property 'Error' instead of 'OverConstrainedError'
|
||||
error.name = error.constructor.name;
|
||||
}
|
||||
let errorName, errorMessage: string;
|
||||
switch (error.name.toLowerCase()) {
|
||||
case 'notfounderror':
|
||||
errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND;
|
||||
errorMessage = error.toString();
|
||||
return new OpenViduError(errorName, errorMessage);
|
||||
case 'notallowederror':
|
||||
errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
|
||||
errorMessage = error.toString();
|
||||
return new OpenViduError(errorName, errorMessage);
|
||||
case 'overconstrainederror':
|
||||
if (error.constraint.toLowerCase() === 'deviceid') {
|
||||
errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND;
|
||||
errorMessage = "Audio input device with deviceId '" + (<ConstrainDOMStringParameters>(<MediaTrackConstraints>constraints.audio).deviceId!!).exact + "' not found";
|
||||
} else {
|
||||
errorName = OpenViduErrorName.PUBLISHER_PROPERTIES_ERROR;
|
||||
errorMessage = "Audio input device doesn't support the value passed for constraint '" + error.constraint + "'";
|
||||
}
|
||||
return new OpenViduError(errorName, errorMessage);
|
||||
case 'notreadableerror':
|
||||
errorName = OpenViduErrorName.DEVICE_ALREADY_IN_USE;
|
||||
errorMessage = error.toString();
|
||||
return (new OpenViduError(errorName, errorMessage));
|
||||
default:
|
||||
return new OpenViduError(OpenViduErrorName.INPUT_AUDIO_DEVICE_GENERIC_ERROR, error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Private methods */
|
||||
|
||||
|
|
|
@ -270,8 +270,7 @@ export class Publisher extends StreamManager {
|
|||
*
|
||||
* You can get this new MediaStreamTrack by using the native Web API or simply with [[OpenVidu.getUserMedia]] method.
|
||||
*
|
||||
* **WARNING: this method has been proven to work, but there may be some combinations of published/replaced tracks that may be incompatible between them and break the connection in OpenVidu Server.**
|
||||
* **A complete renegotiation may be the only solution in this case**
|
||||
* **WARNING: this method has been proven to work, but there may be some combinations of published/replaced tracks that may be incompatible between them and break the connection in OpenVidu Server. A complete renegotiation may be the only solution in this case**
|
||||
*
|
||||
* @param track The [MediaStreamTrack](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) object to replace the current one. If it is an audio track, the current audio track will be the replaced one. If it
|
||||
* is a video track, the current video track will be the replaced one.
|
||||
|
@ -281,6 +280,15 @@ export class Publisher extends StreamManager {
|
|||
replaceTrack(track: MediaStreamTrack): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.stream.getRTCPeerConnection().getSenders()[0].replaceTrack(track).then(() => {
|
||||
let removedTrack: MediaStreamTrack;
|
||||
if (track.kind === 'video') {
|
||||
removedTrack = this.stream.getMediaStream().getVideoTracks()[0];
|
||||
} else {
|
||||
removedTrack = this.stream.getMediaStream().getAudioTracks()[0];
|
||||
}
|
||||
this.stream.getMediaStream().removeTrack(removedTrack);
|
||||
removedTrack.stop();
|
||||
this.stream.getMediaStream().addTrack(track);
|
||||
resolve();
|
||||
}).catch(error => {
|
||||
reject(error);
|
||||
|
@ -471,33 +479,14 @@ export class Publisher extends StreamManager {
|
|||
})
|
||||
.catch(error => {
|
||||
this.clearPermissionDialogTimer(startTime, timeForDialogEvent);
|
||||
if (error.name === 'Error') {
|
||||
// Safari OverConstrainedError has as name property 'Error' instead of 'OverConstrainedError'
|
||||
error.name = error.constructor.name;
|
||||
}
|
||||
let errorName, errorMessage;
|
||||
switch (error.name.toLowerCase()) {
|
||||
case 'notfounderror':
|
||||
errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND;
|
||||
errorMessage = error.toString();
|
||||
errorCallback(new OpenViduError(errorName, errorMessage));
|
||||
break;
|
||||
case 'notallowederror':
|
||||
errorName = OpenViduErrorName.DEVICE_ACCESS_DENIED;
|
||||
errorMessage = error.toString();
|
||||
errorCallback(new OpenViduError(errorName, errorMessage));
|
||||
break;
|
||||
case 'overconstrainederror':
|
||||
if (error.constraint.toLowerCase() === 'deviceid') {
|
||||
errorName = OpenViduErrorName.INPUT_AUDIO_DEVICE_NOT_FOUND;
|
||||
errorMessage = "Audio input device with deviceId '" + (<ConstrainDOMStringParameters>(<MediaTrackConstraints>constraints.video).deviceId!!).exact + "' not found";
|
||||
} else {
|
||||
errorName = OpenViduErrorName.PUBLISHER_PROPERTIES_ERROR;
|
||||
errorMessage = "Audio input device doesn't support the value passed for constraint '" + error.constraint + "'";
|
||||
}
|
||||
errorCallback(new OpenViduError(errorName, errorMessage));
|
||||
break;
|
||||
}
|
||||
mediaStream.getAudioTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
mediaStream.getVideoTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
errorCallback(this.openvidu.generateAudioDeviceError(error, constraints));
|
||||
return;
|
||||
});
|
||||
} else {
|
||||
successCallback(mediaStream);
|
||||
|
@ -607,41 +596,35 @@ export class Publisher extends StreamManager {
|
|||
mediaConstraints: constraints,
|
||||
publisherProperties: this.properties
|
||||
};
|
||||
|
||||
this.stream.setOutboundStreamOptions(outboundStreamOptions);
|
||||
|
||||
if (this.stream.isSendVideo() || this.stream.isSendAudio()) {
|
||||
const definedAudioConstraint = ((constraints.audio === undefined) ? true : constraints.audio);
|
||||
constraintsAux.audio = this.stream.isSendScreen() ? false : definedAudioConstraint;
|
||||
constraintsAux.video = constraints.video;
|
||||
startTime = Date.now();
|
||||
this.setPermissionDialogTimer(timeForDialogEvent);
|
||||
const definedAudioConstraint = ((constraints.audio === undefined) ? true : constraints.audio);
|
||||
constraintsAux.audio = this.stream.isSendScreen() ? false : definedAudioConstraint;
|
||||
constraintsAux.video = constraints.video;
|
||||
startTime = Date.now();
|
||||
this.setPermissionDialogTimer(timeForDialogEvent);
|
||||
|
||||
if (this.stream.isSendScreen() && navigator.mediaDevices['getDisplayMedia'] && platform.name !== 'Electron') {
|
||||
if (this.stream.isSendScreen() && navigator.mediaDevices['getDisplayMedia'] && platform.name !== 'Electron') {
|
||||
|
||||
navigator.mediaDevices['getDisplayMedia']({ video: true })
|
||||
.then(mediaStream => {
|
||||
getMediaSuccess(mediaStream, definedAudioConstraint);
|
||||
})
|
||||
.catch(error => {
|
||||
getMediaError(error);
|
||||
});
|
||||
navigator.mediaDevices['getDisplayMedia']({ video: true })
|
||||
.then(mediaStream => {
|
||||
getMediaSuccess(mediaStream, definedAudioConstraint);
|
||||
})
|
||||
.catch(error => {
|
||||
getMediaError(error);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
navigator.mediaDevices.getUserMedia(constraintsAux)
|
||||
.then(mediaStream => {
|
||||
getMediaSuccess(mediaStream, definedAudioConstraint);
|
||||
})
|
||||
.catch(error => {
|
||||
getMediaError(error);
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
reject(new OpenViduError(OpenViduErrorName.NO_INPUT_SOURCE_SET,
|
||||
"Properties 'audioSource' and 'videoSource' cannot be set to false or null at the same time when calling 'OpenVidu.initPublisher'"));
|
||||
|
||||
navigator.mediaDevices.getUserMedia(constraintsAux)
|
||||
.then(mediaStream => {
|
||||
getMediaSuccess(mediaStream, definedAudioConstraint);
|
||||
})
|
||||
.catch(error => {
|
||||
getMediaError(error);
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.catch((error: OpenViduError) => {
|
||||
errorCallback(error);
|
||||
|
|
|
@ -34,7 +34,8 @@ export enum OpenViduErrorName {
|
|||
|
||||
/**
|
||||
* The required input device is probably being used by other process when the browser asked for it.
|
||||
* Accuracy of this property is only granted for Chrome and Firefox clients.
|
||||
* This error can also be triggered when the user granted permission to use the devices but a hardware
|
||||
* error occurred at the OS, browser or web page level, which prevented access to the device.
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
DEVICE_ALREADY_IN_USE = "DEVICE_ALREADY_IN_USE",
|
||||
|
@ -47,36 +48,42 @@ export enum OpenViduErrorName {
|
|||
|
||||
/**
|
||||
* Browser does not support screen sharing.
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
SCREEN_SHARING_NOT_SUPPORTED = 'SCREEN_SHARING_NOT_SUPPORTED',
|
||||
|
||||
/**
|
||||
* Only for Chrome, there's no screen sharing extension installed
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
SCREEN_EXTENSION_NOT_INSTALLED = 'SCREEN_EXTENSION_NOT_INSTALLED',
|
||||
|
||||
/**
|
||||
* Only for Chrome, the screen sharing extension is installed but is disabled
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
SCREEN_EXTENSION_DISABLED = 'SCREEN_EXTENSION_DISABLED',
|
||||
|
||||
/**
|
||||
* No video input device found with the provided deviceId (property [[PublisherProperties.videoSource]])
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
INPUT_VIDEO_DEVICE_NOT_FOUND = 'INPUT_VIDEO_DEVICE_NOT_FOUND',
|
||||
|
||||
/**
|
||||
* No audio input device found with the provided deviceId (property [[PublisherProperties.audioSource]])
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
INPUT_AUDIO_DEVICE_NOT_FOUND = 'INPUT_AUDIO_DEVICE_NOT_FOUND',
|
||||
|
||||
/**
|
||||
* Method [[OpenVidu.initPublisher]] has been called with properties `videoSource` and `audioSource` of
|
||||
* There was an unknown error when trying to access the specified audio device
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
INPUT_AUDIO_DEVICE_GENERIC_ERROR = 'INPUT_AUDIO_DEVICE_GENERIC_ERROR',
|
||||
|
||||
/**
|
||||
* Method [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]] has been called with properties `videoSource` and `audioSource` of
|
||||
* [[PublisherProperties]] parameter both set to *false* or *null*
|
||||
*/
|
||||
NO_INPUT_SOURCE_SET = 'NO_INPUT_SOURCE_SET',
|
||||
|
@ -84,7 +91,7 @@ export enum OpenViduErrorName {
|
|||
/**
|
||||
* Some media property of [[PublisherProperties]] such as `frameRate` or `resolution` is not supported
|
||||
* by the input devices (whenever it is possible they are automatically adjusted to the most similar value).
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]]
|
||||
* Returned upon unsuccessful [[OpenVidu.initPublisher]] or [[OpenVidu.getUserMedia]]
|
||||
*/
|
||||
PUBLISHER_PROPERTIES_ERROR = 'PUBLISHER_PROPERTIES_ERROR',
|
||||
|
||||
|
|
Loading…
Reference in New Issue