diff --git a/README.md b/README.md
index 30dcb30..41dd852 100644
--- a/README.md
+++ b/README.md
@@ -9,38 +9,43 @@ A simple Angular webcam component. Pure & minimal, no Flash-fallback. Live-Demo or see the Demo-Project.
## Features
-* Webcam live view
-* Photo capturing
-* Smartphone compatibility for modern OS's (OS must support [WebRTC/UserMedia API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices))
-* Access to front- and back-camera, if multiple cameras exist
-* Portrait & Landscape mode on smartphones
-* Mirrored live-view for user-facing cameras - "selfie view" on phones
-* Capturing of lossless pixel image data for better post-processing.
+- Webcam live view
+- Photo capturing
+- Smartphone compatibility for modern OS's (OS must support [WebRTC/UserMedia API](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices))
+- Access to front- and back-camera, if multiple cameras exist
+- Portrait & Landscape mode on smartphones
+- Mirrored live-view for user-facing cameras - "selfie view" on phones
+- Capturing of lossless pixel image data for better post-processing.
## Prerequisites
### Runtime Dependencies
+
**Note:** Starting from version `0.3.0` this project requires TypeScript `>= 3.7.0` (Angular 9). For older versions of Angular/TypeScript, please use version `0.2.6` of this library.
-* Angular: `>=9.0.0`
-* Typescript: `>=3.7.0`
-* RxJs: `>=5.0.0`
-* **Important:** Your app must be served on a secure context using `https://` or on localhost, for modern browsers to permit WebRTC/UserMedia access.
+
+- Angular: `>=9.0.0`
+- Typescript: `>=3.7.0`
+- RxJs: `>=5.0.0`
+- **Important:** Your app must be served on a secure context using `https://` or on localhost, for modern browsers to permit WebRTC/UserMedia access.
### Client
-* [Current browser](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Browser_compatibility) w/ HTML5 and WebRTC/UserMedia support (Chrome >53, Safari >11, Firefox >38, Edge)
-* Webcam / camera
-* User permissions to access the camera
+
+- [Current browser](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Browser_compatibility) w/ HTML5 and WebRTC/UserMedia support (Chrome >53, Safari >11, Firefox >38, Edge)
+- Webcam / camera
+- User permissions to access the camera
## Usage
-1) Install the library via standard npm command:
+
+1. Install the library via standard npm command:
`npm install --save ngx-webcam`
-2) Import the `WebcamModule` into your Angular module:
+2. Import the `WebcamModule` into your Angular module:
```typescript
import {WebcamModule} from 'ngx-webcam';
@@ -55,43 +60,53 @@ import {WebcamModule} from 'ngx-webcam';
export class AppModule { }
```
-3) Use the `WebcamComponent` on your pages:
+3. Use the `WebcamComponent` on your pages:
``
-As simple as that.
+As simple as that.
For more examples, see the code in the Demo-Project.
## Options and Events
+
This section describes the basic inputs/outputs of the component. All inputs are optional.
+
### Inputs
-* `trigger: Observable`: An `Observable` to trigger image capturing. When it fires, an image will be captured and emitted (see Outputs).
-* `width: number`: The maximal video width of the webcam live view.
-* `height: number`: The maximal video height of the webcam live view. The actual view will be placed within these boundaries, respecting the aspect ratio of the video stream.
-* `videoOptions: MediaTrackConstraints`: Defines constraints ([MediaTrackConstraints](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints)) to apply when requesting the video track.
-* `mirrorImage: string | WebcamMirrorProperties`: Flag to control image mirroring. If the attribute is missing or `null` and the camera claims to be user-facing, the image will be mirrored (x-axis) to provide a better user experience ("selfie view"). A string value of `"never"` will prevent mirroring, whereas a value of `"always"` will mirror every camera stream, even if the camera cannot be detected as user-facing. For future extensions, the `WebcamMirrorProperties` object can also be used to set these values.
-* `allowCameraSwitch: boolean`: Flag to enable/disable camera switch. If enabled, a switch icon will be displayed if multiple cameras are found.
-* `switchCamera: Observable`: Can be used to cycle through available cameras (true=forward, false=backwards), or to switch to a specific device by deviceId (string).
-* `captureImageData: boolean = false`: Flag to enable/disable capturing of a lossless pixel ImageData object when a snapshot is taken. ImageData will be included in the emitted `WebcamImage` object.
-* `imageType: string = 'image/jpeg'`: [Image type](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) to use when capturing snapshots. Default is 'image/jpeg'.
-* `imageQuality: number = 0.92`: [Image quality](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) to use when capturing snapshots. Must be a number between 0..1. Default is 0.92.
+
+- `trigger: Observable`: An `Observable` to trigger image capturing. When it fires, an image will be captured and emitted (see Outputs).
+- `width: number`: The maximal video width of the webcam live view.
+- `height: number`: The maximal video height of the webcam live view. The actual view will be placed within these boundaries, respecting the aspect ratio of the video stream.
+- `videoOptions: MediaTrackConstraints`: Defines constraints ([MediaTrackConstraints](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints)) to apply when requesting the video track.
+- `mirrorImage: string | WebcamMirrorProperties`: Flag to control image mirroring. If the attribute is missing or `null` and the camera claims to be user-facing, the image will be mirrored (x-axis) to provide a better user experience ("selfie view"). A string value of `"never"` will prevent mirroring, whereas a value of `"always"` will mirror every camera stream, even if the camera cannot be detected as user-facing. For future extensions, the `WebcamMirrorProperties` object can also be used to set these values.
+- `allowCameraSwitch: boolean`: Flag to enable/disable camera switch. If enabled, a switch icon will be displayed if multiple cameras are found.
+- `switchCamera: Observable`: Can be used to cycle through available cameras (true=forward, false=backwards), or to switch to a specific device by deviceId (string).
+- `captureImageData: boolean = false`: Flag to enable/disable capturing of a lossless pixel ImageData object when a snapshot is taken. ImageData will be included in the emitted `WebcamImage` object.
+- `imageType: string = 'image/jpeg'`: [Image type](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) to use when capturing snapshots. Default is 'image/jpeg'.
+- `imageQuality: number = 0.92`: [Image quality](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) to use when capturing snapshots. Must be a number between 0..1. Default is 0.92.
### Outputs
-* `imageCapture: EventEmitter`: Whenever an image is captured (i.e. triggered by `[trigger]`), the image is emitted via this `EventEmitter`. The image data is contained in the `WebcamImage` data structure as both, plain Base64 string and data-url.
-* `imageClick: EventEmitter`: An `EventEmitter` to signal clicks on the webcam area.
-* `initError: EventEmitter`: An `EventEmitter` to signal errors during the webcam initialization.
-* `cameraSwitched: EventEmitter`: Emits the active deviceId after the active video device has been switched.
+
+- `imageCapture: EventEmitter`: Whenever an image is captured (i.e. triggered by `[trigger]`), the image is emitted via this `EventEmitter`. The image data is contained in the `WebcamImage` data structure as both, plain Base64 string and data-url.
+- `imageClick: EventEmitter`: An `EventEmitter` to signal clicks on the webcam area.
+- `initError: EventEmitter`: An `EventEmitter` to signal errors during the webcam initialization.
+- `initSuccess: EventEmitter`: Emits when the user accepts permissions. `true` if there is a camera in the system.
+- `cameraSwitched: EventEmitter`: Emits the active deviceId after the active video device has been switched.
## Good To Know
+
### How to determine if a user has denied camera access
+
When camera initialization fails for some reason, the component emits a `WebcamInitError` via the `initError` EventEmitter. If provided by the browser, this object contains a field `mediaStreamError: MediaStreamError` which contains information about why UserMedia initialization failed. According to [Mozilla API docs](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia), this object contains a `name` attribute which gives insight about the reason.
+
> If the user denies permission, or matching media is not available, then the promise is rejected with NotAllowedError or NotFoundError respectively.
Determine if a user has denied permissions:
+
```
```
+
```
public handleInitError(error: WebcamInitError): void {
if (error.mediaStreamError && error.mediaStreamError.name === "NotAllowedError") {
@@ -101,16 +116,21 @@ Determine if a user has denied permissions:
```
## Development
+
Here you can find instructions on how to start developing this library.
### Build
+
Run `npm run packagr` to build the library. The build artifacts will be stored in the `dist/` directory.
### Start
+
Run `npm start` to build and run the surrounding demo app with the `WebcamModule`. Essential for live-developing.
### Generate docs/
+
Run `npm run docs` to generate the live-demo documentation pages in the `docs/` directory.
### Running Unit Tests
+
Run `npm run test` to run unit-tests.
diff --git a/src/app/modules/webcam/webcam/webcam.component.ts b/src/app/modules/webcam/webcam/webcam.component.ts
index 2758d5f..fd91ee6 100644
--- a/src/app/modules/webcam/webcam/webcam.component.ts
+++ b/src/app/modules/webcam/webcam/webcam.component.ts
@@ -1,18 +1,28 @@
-import {AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output, ViewChild} from '@angular/core';
-import {WebcamInitError} from '../domain/webcam-init-error';
-import {WebcamImage} from '../domain/webcam-image';
-import {Observable, Subscription} from 'rxjs';
-import {WebcamUtil} from '../util/webcam.util';
-import {WebcamMirrorProperties} from '../domain/webcam-mirror-properties';
+import {
+ AfterViewInit,
+ Component,
+ EventEmitter,
+ Input,
+ OnDestroy,
+ Output,
+ ViewChild,
+} from "@angular/core";
+import { WebcamInitError } from "../domain/webcam-init-error";
+import { WebcamImage } from "../domain/webcam-image";
+import { Observable, Subscription } from "rxjs";
+import { WebcamUtil } from "../util/webcam.util";
+import { WebcamMirrorProperties } from "../domain/webcam-mirror-properties";
@Component({
- selector: 'webcam',
- templateUrl: './webcam.component.html',
- styleUrls: ['./webcam.component.scss']
+ selector: "webcam",
+ templateUrl: "./webcam.component.html",
+ styleUrls: ["./webcam.component.scss"],
})
export class WebcamComponent implements AfterViewInit, OnDestroy {
- private static DEFAULT_VIDEO_OPTIONS: MediaTrackConstraints = {facingMode: 'environment'};
- private static DEFAULT_IMAGE_TYPE: string = 'image/jpeg';
+ private static DEFAULT_VIDEO_OPTIONS: MediaTrackConstraints = {
+ facingMode: "environment",
+ };
+ private static DEFAULT_IMAGE_TYPE: string = "image/jpeg";
private static DEFAULT_IMAGE_QUALITY: number = 0.92;
/** Defines the max width of the webcam area in px */
@@ -20,7 +30,8 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
/** Defines the max height of the webcam area in px */
@Input() public height: number = 480;
/** Defines base constraints to apply when requesting video track from UserMedia */
- @Input() public videoOptions: MediaTrackConstraints = WebcamComponent.DEFAULT_VIDEO_OPTIONS;
+ @Input() public videoOptions: MediaTrackConstraints =
+ WebcamComponent.DEFAULT_VIDEO_OPTIONS;
/** Flag to enable/disable camera switch. If enabled, a switch icon will be displayed if multiple cameras were found */
@Input() public allowCameraSwitch: boolean = true;
/** Parameter to control image mirroring (i.e. for user-facing camera). ["auto", "always", "never"] */
@@ -33,13 +44,23 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
@Input() public imageQuality: number = WebcamComponent.DEFAULT_IMAGE_QUALITY;
/** EventEmitter which fires when an image has been captured */
- @Output() public imageCapture: EventEmitter = new EventEmitter();
+ @Output() public imageCapture: EventEmitter = new EventEmitter<
+ WebcamImage
+ >();
/** Emits a mediaError if webcam cannot be initialized (e.g. missing user permissions) */
- @Output() public initError: EventEmitter = new EventEmitter();
+ @Output() public initError: EventEmitter = new EventEmitter<
+ WebcamInitError
+ >();
+ /** Emits when the user accepts permissions */
+ @Output() public initSuccess: EventEmitter = new EventEmitter<
+ Boolean
+ >();
/** Emits when the webcam video was clicked */
@Output() public imageClick: EventEmitter = new EventEmitter();
/** Emits the active deviceId after the active video device was switched */
- @Output() public cameraSwitched: EventEmitter = new EventEmitter();
+ @Output() public cameraSwitched: EventEmitter = new EventEmitter<
+ string
+ >();
/** available video devices */
public availableVideoInputs: MediaDeviceInfo[] = [];
@@ -56,9 +77,9 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
private switchCameraSubscription: Subscription;
/** MediaStream object in use for streaming UserMedia data */
private mediaStream: MediaStream = null;
- @ViewChild('video', { static: true }) private video: any;
+ @ViewChild("video", { static: true }) private video: any;
/** Canvas for Video Snapshots */
- @ViewChild('canvas', { static: true }) private canvas: any;
+ @ViewChild("canvas", { static: true }) private canvas: any;
/** width and height of the active video stream */
private activeVideoSettings: MediaTrackSettings = null;
@@ -92,15 +113,17 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
}
// Subscribe to events from this Observable to switch video device
- this.switchCameraSubscription = switchCamera.subscribe((value: boolean | string) => {
- if (typeof value === 'string') {
- // deviceId was specified
- this.switchToVideoInput(value);
- } else {
- // direction was specified
- this.rotateVideoInput(value !== false);
+ this.switchCameraSubscription = switchCamera.subscribe(
+ (value: boolean | string) => {
+ if (typeof value === "string") {
+ // deviceId was specified
+ this.switchToVideoInput(value);
+ } else {
+ // direction was specified
+ this.rotateVideoInput(value !== false);
+ }
}
- });
+ );
}
/**
@@ -109,10 +132,15 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
* @param baseMediaTrackConstraints base constraints to merge deviceId-constraint into
* @returns
*/
- private static getMediaConstraintsForDevice(deviceId: string, baseMediaTrackConstraints: MediaTrackConstraints): MediaTrackConstraints {
- const result: MediaTrackConstraints = baseMediaTrackConstraints ? baseMediaTrackConstraints : this.DEFAULT_VIDEO_OPTIONS;
+ private static getMediaConstraintsForDevice(
+ deviceId: string,
+ baseMediaTrackConstraints: MediaTrackConstraints
+ ): MediaTrackConstraints {
+ const result: MediaTrackConstraints = baseMediaTrackConstraints
+ ? baseMediaTrackConstraints
+ : this.DEFAULT_VIDEO_OPTIONS;
if (deviceId) {
- result.deviceId = {exact: deviceId};
+ result.deviceId = { exact: deviceId };
}
return result;
@@ -125,11 +153,22 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
* @param mediaStreamTrack
* @returns deviceId if found in the mediaStreamTrack
*/
- private static getDeviceIdFromMediaStreamTrack(mediaStreamTrack: MediaStreamTrack): string {
- if (mediaStreamTrack.getSettings && mediaStreamTrack.getSettings() && mediaStreamTrack.getSettings().deviceId) {
+ private static getDeviceIdFromMediaStreamTrack(
+ mediaStreamTrack: MediaStreamTrack
+ ): string {
+ if (
+ mediaStreamTrack.getSettings &&
+ mediaStreamTrack.getSettings() &&
+ mediaStreamTrack.getSettings().deviceId
+ ) {
return mediaStreamTrack.getSettings().deviceId;
- } else if (mediaStreamTrack.getConstraints && mediaStreamTrack.getConstraints() && mediaStreamTrack.getConstraints().deviceId) {
- const deviceIdObj: ConstrainDOMString = mediaStreamTrack.getConstraints().deviceId;
+ } else if (
+ mediaStreamTrack.getConstraints &&
+ mediaStreamTrack.getConstraints() &&
+ mediaStreamTrack.getConstraints().deviceId
+ ) {
+ const deviceIdObj: ConstrainDOMString = mediaStreamTrack.getConstraints()
+ .deviceId;
return WebcamComponent.getValueFromConstrainDOMString(deviceIdObj);
}
}
@@ -141,13 +180,26 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
* @param mediaStreamTrack
* @returns facingMode if found in the mediaStreamTrack
*/
- private static getFacingModeFromMediaStreamTrack(mediaStreamTrack: MediaStreamTrack): string {
+ private static getFacingModeFromMediaStreamTrack(
+ mediaStreamTrack: MediaStreamTrack
+ ): string {
if (mediaStreamTrack) {
- if (mediaStreamTrack.getSettings && mediaStreamTrack.getSettings() && mediaStreamTrack.getSettings().facingMode) {
+ if (
+ mediaStreamTrack.getSettings &&
+ mediaStreamTrack.getSettings() &&
+ mediaStreamTrack.getSettings().facingMode
+ ) {
return mediaStreamTrack.getSettings().facingMode;
- } else if (mediaStreamTrack.getConstraints && mediaStreamTrack.getConstraints() && mediaStreamTrack.getConstraints().facingMode) {
- const facingModeConstraint: ConstrainDOMString = mediaStreamTrack.getConstraints().facingMode;
- return WebcamComponent.getValueFromConstrainDOMString(facingModeConstraint);
+ } else if (
+ mediaStreamTrack.getConstraints &&
+ mediaStreamTrack.getConstraints() &&
+ mediaStreamTrack.getConstraints().facingMode
+ ) {
+ const facingModeConstraint: ConstrainDOMString = mediaStreamTrack.getConstraints()
+ .facingMode;
+ return WebcamComponent.getValueFromConstrainDOMString(
+ facingModeConstraint
+ );
}
}
}
@@ -157,25 +209,32 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
* @param mediaStreamTrack
*/
private static isUserFacing(mediaStreamTrack: MediaStreamTrack): boolean {
- const facingMode: string = WebcamComponent.getFacingModeFromMediaStreamTrack(mediaStreamTrack);
- return facingMode ? 'user' === facingMode.toLowerCase() : false;
+ const facingMode: string = WebcamComponent.getFacingModeFromMediaStreamTrack(
+ mediaStreamTrack
+ );
+ return facingMode ? "user" === facingMode.toLowerCase() : false;
}
/**
* Extracts the value from the given ConstrainDOMString
* @param constrainDOMString
*/
- private static getValueFromConstrainDOMString(constrainDOMString: ConstrainDOMString): string {
+ private static getValueFromConstrainDOMString(
+ constrainDOMString: ConstrainDOMString
+ ): string {
if (constrainDOMString) {
if (constrainDOMString instanceof String) {
return String(constrainDOMString);
- } else if (Array.isArray(constrainDOMString) && Array(constrainDOMString).length > 0) {
+ } else if (
+ Array.isArray(constrainDOMString) &&
+ Array(constrainDOMString).length > 0
+ ) {
return String(constrainDOMString[0]);
- } else if (typeof constrainDOMString === 'object') {
- if (constrainDOMString['exact']) {
- return String(constrainDOMString['exact']);
- } else if (constrainDOMString['ideal']) {
- return String(constrainDOMString['ideal']);
+ } else if (typeof constrainDOMString === "object") {
+ if (constrainDOMString["exact"]) {
+ return String(constrainDOMString["exact"]);
+ } else if (constrainDOMString["ideal"]) {
+ return String(constrainDOMString["ideal"]);
}
}
}
@@ -190,7 +249,7 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
this.switchToVideoInput(null);
})
.catch((err: string) => {
- this.initError.next({message: err});
+ this.initError.next({ message: err });
// fallback: still try to load webcam, even if device enumeration failed
this.switchToVideoInput(null);
});
@@ -207,7 +266,7 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
public takeSnapshot(): void {
// set canvas size to actual video size
const _video = this.nativeVideoElement;
- const dimensions = {width: this.width, height: this.height};
+ const dimensions = { width: this.width, height: this.height };
if (_video.videoWidth) {
dimensions.width = _video.videoWidth;
dimensions.height = _video.videoHeight;
@@ -218,12 +277,16 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
_canvas.height = dimensions.height;
// paint snapshot image to canvas
- const context2d = _canvas.getContext('2d');
+ const context2d = _canvas.getContext("2d");
context2d.drawImage(_video, 0, 0);
// read canvas content as image
- const mimeType: string = this.imageType ? this.imageType : WebcamComponent.DEFAULT_IMAGE_TYPE;
- const quality: number = this.imageQuality ? this.imageQuality : WebcamComponent.DEFAULT_IMAGE_QUALITY;
+ const mimeType: string = this.imageType
+ ? this.imageType
+ : WebcamComponent.DEFAULT_IMAGE_TYPE;
+ const quality: number = this.imageQuality
+ ? this.imageQuality
+ : WebcamComponent.DEFAULT_IMAGE_QUALITY;
const dataUrl: string = _canvas.toDataURL(mimeType, quality);
// get the ImageData object from the canvas' context.
@@ -242,9 +305,15 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
*/
public rotateVideoInput(forward: boolean) {
if (this.availableVideoInputs && this.availableVideoInputs.length > 1) {
- const increment: number = forward ? 1 : (this.availableVideoInputs.length - 1);
- const nextInputIndex = (this.activeVideoInputIndex + increment) % this.availableVideoInputs.length;
- this.switchToVideoInput(this.availableVideoInputs[nextInputIndex].deviceId);
+ const increment: number = forward
+ ? 1
+ : this.availableVideoInputs.length - 1;
+ const nextInputIndex =
+ (this.activeVideoInputIndex + increment) %
+ this.availableVideoInputs.length;
+ this.switchToVideoInput(
+ this.availableVideoInputs[nextInputIndex].deviceId
+ );
}
}
@@ -257,7 +326,6 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
this.initWebcam(deviceId, this.videoOptions);
}
-
/**
* Event-handler for video resize event.
* Triggers Angular change detection so that new video dimensions get applied
@@ -277,10 +345,10 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
}
public get videoStyleClasses() {
- let classes: string = '';
+ let classes: string = "";
if (this.isMirrorImage()) {
- classes += 'mirrored ';
+ classes += "mirrored ";
}
return classes.trim();
@@ -296,9 +364,12 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
private getVideoAspectRatio(): number {
// calculate ratio from video element dimensions if present
const videoElement = this.nativeVideoElement;
- if (videoElement.videoWidth && videoElement.videoWidth > 0 &&
- videoElement.videoHeight && videoElement.videoHeight > 0) {
-
+ if (
+ videoElement.videoWidth &&
+ videoElement.videoWidth > 0 &&
+ videoElement.videoHeight &&
+ videoElement.videoHeight > 0
+ ) {
return videoElement.videoWidth / videoElement.videoHeight;
}
@@ -309,21 +380,29 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
/**
* Init webcam live view
*/
- private initWebcam(deviceId: string, userVideoTrackConstraints: MediaTrackConstraints) {
+ private initWebcam(
+ deviceId: string,
+ userVideoTrackConstraints: MediaTrackConstraints
+ ) {
const _video = this.nativeVideoElement;
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
-
// merge deviceId -> userVideoTrackConstraints
- const videoTrackConstraints = WebcamComponent.getMediaConstraintsForDevice(deviceId, userVideoTrackConstraints);
+ const videoTrackConstraints = WebcamComponent.getMediaConstraintsForDevice(
+ deviceId,
+ userVideoTrackConstraints
+ );
- navigator.mediaDevices.getUserMedia({video: videoTrackConstraints})
+ navigator.mediaDevices
+ .getUserMedia({ video: videoTrackConstraints })
.then((stream: MediaStream) => {
this.mediaStream = stream;
_video.srcObject = stream;
_video.play();
this.activeVideoSettings = stream.getVideoTracks()[0].getSettings();
- const activeDeviceId: string = WebcamComponent.getDeviceIdFromMediaStreamTrack(stream.getVideoTracks()[0]);
+ const activeDeviceId: string = WebcamComponent.getDeviceIdFromMediaStreamTrack(
+ stream.getVideoTracks()[0]
+ );
this.cameraSwitched.next(activeDeviceId);
@@ -331,20 +410,31 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
// Run detect once again within getUserMedia callback, to make sure this time we have permissions and get deviceIds.
this.detectAvailableDevices()
.then(() => {
- this.activeVideoInputIndex = activeDeviceId ? this.availableVideoInputs
- .findIndex((mediaDeviceInfo: MediaDeviceInfo) => mediaDeviceInfo.deviceId === activeDeviceId) : -1;
+ this.activeVideoInputIndex = activeDeviceId
+ ? this.availableVideoInputs.findIndex(
+ (mediaDeviceInfo: MediaDeviceInfo) =>
+ mediaDeviceInfo.deviceId === activeDeviceId
+ )
+ : -1;
this.videoInitialized = true;
+ this.initSuccess.next(true);
})
.catch(() => {
this.activeVideoInputIndex = -1;
this.videoInitialized = true;
+ this.initSuccess.next(false);
});
})
.catch((err: MediaStreamError) => {
- this.initError.next({message: err.message, mediaStreamError: err});
+ this.initError.next({
+ message: err.message,
+ mediaStreamError: err,
+ });
});
} else {
- this.initError.next({message: 'Cannot read UserMedia from MediaDevices.'});
+ this.initError.next({
+ message: "Cannot read UserMedia from MediaDevices.",
+ });
}
}
@@ -359,9 +449,9 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
// check for explicit mirror override parameter
{
- let mirror: string = 'auto';
+ let mirror: string = "auto";
if (this.mirrorImage) {
- if (typeof this.mirrorImage === 'string') {
+ if (typeof this.mirrorImage === "string") {
mirror = String(this.mirrorImage).toLowerCase();
} else {
// WebcamMirrorProperties
@@ -372,9 +462,9 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
}
switch (mirror) {
- case 'always':
+ case "always":
return true;
- case 'never':
+ case "never":
return false;
}
}
@@ -391,7 +481,8 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
private stopMediaTracks() {
if (this.mediaStream && this.mediaStream.getTracks) {
// getTracks() returns all media tracks (video+audio)
- this.mediaStream.getTracks()
+ this.mediaStream
+ .getTracks()
.forEach((track: MediaStreamTrack) => track.stop());
}
}
@@ -418,11 +509,10 @@ export class WebcamComponent implements AfterViewInit, OnDestroy {
this.availableVideoInputs = devices;
resolve(devices);
})
- .catch(err => {
+ .catch((err) => {
this.availableVideoInputs = [];
reject(err);
});
});
}
-
}