Commit dc85603d authored by Wei Lee's avatar Wei Lee Committed by Commit Bot

CCA: Add photo-capture-shutter perf event and put facing into event name

When taking photo, there are two stages:
1. Click shutter button -> Shutter is done
2. Shutter is done -> Captured image is returned and save

We already have 'photo-taking' event to measure (1) + (2) and
'photo-capture-post-processing' for (2). It will be helpful to have a
'photo-capture-shutter' for (1) as well.

In addition, to measure performance for front camera and back camera
respectively, we can add events with facing information in their names.
Therefore, the ones without facing information are the average metrics
and the ones with facing information are results for specific facing.

Bug: b/149454553
Test: tast run [DUT] camera.CCAUIPerf
Change-Id: I5889ddde4df7c1b3ca4a71ba1c1c0f1628af2fff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2087501Reviewed-by: default avatarShik Chen <shik@chromium.org>
Reviewed-by: default avatarKuo Jen Wei <inker@chromium.org>
Commit-Queue: Wei Lee <wtlee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749134}
parent eb931527
......@@ -5,6 +5,8 @@
import {browserProxy} from './browser_proxy/browser_proxy.js';
// eslint-disable-next-line no-unused-vars
import {Intent} from './intent.js';
// eslint-disable-next-line no-unused-vars
import {PerfEvent} from './perf.js';
import * as state from './state.js';
// eslint-disable-next-line no-unused-vars
import {Facing} from './type.js';
......@@ -141,15 +143,16 @@ function captureType(facingMode, length, resolution, intentResult) {
/**
* Returns event builder for the metrics type: perf.
* @param {string} event The target event type.
* @param {PerfEvent} event The target event type.
* @param {number} duration The duration of the event in ms.
* @param {Object=} extras Optional information for the event.
* @return {!analytics.EventBuilder}
*/
function perfType(event, duration, extras = {}) {
const {resolution = ''} = extras;
const {resolution = '', facing = ''} = extras;
return base.category('perf')
.action(event)
.label(facing)
// Round the duration here since GA expects that the value is an integer.
// Reference: https://support.google.com/analytics/answer/1033068
.value(Math.round(duration))
......
......@@ -12,6 +12,7 @@ import {PerfInformation} from './type.js';
*/
export const PerfEvent = {
PHOTO_TAKING: 'photo-taking',
PHOTO_CAPTURE_SHUTTER: 'photo-capture-shutter',
PHOTO_CAPTURE_POST_PROCESSING: 'photo-capture-post-processing',
VIDEO_CAPTURE_POST_PROCESSING: 'video-capture-post-processing',
PORTRAIT_MODE_CAPTURE_POST_PROCESSING:
......
......@@ -263,7 +263,8 @@ export class Camera extends View {
console.error(e);
} finally {
this.take_ = null;
state.set(state.State.TAKING, false, {hasError});
state.set(
state.State.TAKING, false, {hasError, facing: this.facingMode_});
this.focus(); // Refocus the visible shutter button for ChromeVox.
}
})();
......@@ -406,7 +407,8 @@ export class Camera extends View {
await this.preview_.start(stream);
this.facingMode_ = await this.options_.updateValues(stream);
await this.modes_.updateModeSelectionUI(deviceId);
await this.modes_.updateMode(mode, stream, deviceId, captureR);
await this.modes_.updateMode(
mode, stream, this.facingMode_, deviceId, captureR);
nav.close(ViewName.WARNING, 'no-camera');
return true;
} catch (e) {
......
......@@ -3,10 +3,11 @@
// found in the LICENSE file.
import {assert, assertInstanceof} from '../../chrome_util.js';
import {CaptureCandidate, // eslint-disable-line no-unused-vars
ConstraintsPreferrer, // eslint-disable-line no-unused-vars
PhotoConstraintsPreferrer, // eslint-disable-line no-unused-vars
VideoConstraintsPreferrer, // eslint-disable-line no-unused-vars
import {
CaptureCandidate, // eslint-disable-line no-unused-vars
ConstraintsPreferrer, // eslint-disable-line no-unused-vars
PhotoConstraintsPreferrer, // eslint-disable-line no-unused-vars
VideoConstraintsPreferrer, // eslint-disable-line no-unused-vars
} from '../../device/constraints_preferrer.js';
import {Filenamer} from '../../models/filenamer.js';
import * as filesystem from '../../models/filesystem.js';
......@@ -18,10 +19,14 @@ import {PerfEvent} from '../../perf.js';
import * as sound from '../../sound.js';
import * as state from '../../state.js';
import * as toast from '../../toast.js';
import {Resolution,
ResolutionList, // eslint-disable-line no-unused-vars
import {
Resolution,
ResolutionList, // eslint-disable-line no-unused-vars
} from '../../type.js';
import {
Facing, // eslint-disable-line no-unused-vars
Mode,
} from '../../type.js';
import {Mode} from '../../type.js';
import * as util from '../../util.js';
import {RecordTime} from './recordtime.js';
......@@ -175,6 +180,13 @@ export class Modes {
*/
this.stream_ = null;
/**
* Camera facing of current mode.
* @type {!Facing}
* @private
*/
this.facing_ = Facing.UNKNOWN;
/**
* @type {!HTMLElement}
* @private
......@@ -231,8 +243,8 @@ export class Modes {
this.allModes_ = {
[Mode.VIDEO]: {
captureFactory: () => new Video(
assertInstanceof(this.stream_, MediaStream), createVideoSaver,
doSaveVideo),
assertInstanceof(this.stream_, MediaStream), this.facing_,
createVideoSaver, doSaveVideo),
isSupported: async () => true,
constraintsPreferrer: videoPreferrer,
getV1Constraints: getV1Constraints.bind(this, true),
......@@ -241,8 +253,8 @@ export class Modes {
},
[Mode.PHOTO]: {
captureFactory: () => new Photo(
assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect),
assertInstanceof(this.stream_, MediaStream), this.facing_,
doSavePhoto, this.captureResolution_, playShutterEffect),
isSupported: async () => true,
constraintsPreferrer: photoPreferrer,
getV1Constraints: getV1Constraints.bind(this, false),
......@@ -251,8 +263,8 @@ export class Modes {
},
[Mode.SQUARE]: {
captureFactory: () => new Square(
assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect),
assertInstanceof(this.stream_, MediaStream), this.facing_,
doSavePhoto, this.captureResolution_, playShutterEffect),
isSupported: async () => true,
constraintsPreferrer: photoPreferrer,
getV1Constraints: getV1Constraints.bind(this, false),
......@@ -261,8 +273,8 @@ export class Modes {
},
[Mode.PORTRAIT]: {
captureFactory: () => new Portrait(
assertInstanceof(this.stream_, MediaStream), doSavePhoto,
this.captureResolution_, playShutterEffect),
assertInstanceof(this.stream_, MediaStream), this.facing_,
doSavePhoto, this.captureResolution_, playShutterEffect),
isSupported: async (deviceId) => {
if (deviceId === null) {
return false;
......@@ -430,17 +442,19 @@ export class Modes {
* Creates and updates new current mode object.
* @param {!Mode} mode Classname of mode to be updated.
* @param {!MediaStream} stream Stream of the new switching mode.
* @param {!Facing} facing Camera facing of the current mode.
* @param {?string} deviceId Device id of currently working video device.
* @param {?Resolution} captureResolution Capturing resolution width and
* height.
* @return {!Promise}
*/
async updateMode(mode, stream, deviceId, captureResolution) {
async updateMode(mode, stream, facing, deviceId, captureResolution) {
if (this.current !== null) {
await this.current.stopCapture();
}
this.updateModeUI_(mode);
this.stream_ = stream;
this.facing_ = facing;
this.captureResolution_ = captureResolution;
this.current = this.allModes_[mode].captureFactory();
if (deviceId && this.captureResolution_) {
......@@ -493,10 +507,11 @@ export class Modes {
class ModeBase {
/**
* @param {!MediaStream} stream
* @param {!Facing} facing
* @param {?Resolution} captureResolution Capturing resolution width and
* height.
*/
constructor(stream, captureResolution) {
constructor(stream, facing, captureResolution) {
/**
* Stream of current mode.
* @type {!MediaStream}
......@@ -504,6 +519,13 @@ class ModeBase {
*/
this.stream_ = stream;
/**
* Camera facing of current mode.
* @type {!Facing}
* @protected
*/
this.facing_ = facing;
/**
* Capture resolution. May be null on device not support of setting
* resolution.
......@@ -579,11 +601,12 @@ const VIDEO_MIMETYPE = 'video/x-matroska;codecs=avc1';
class Video extends ModeBase {
/**
* @param {!MediaStream} stream
* @param {!Facing} facing
* @param {!CreateVideoSaver} createVideoSaver
* @param {!DoSaveVideo} doSaveVideo
*/
constructor(stream, createVideoSaver, doSaveVideo) {
super(stream, null);
constructor(stream, facing, createVideoSaver, doSaveVideo) {
super(stream, facing, null);
/**
* @type {!CreateVideoSaver}
......@@ -662,7 +685,9 @@ class Video extends ModeBase {
try {
await this.doSaveVideo_(
{resolution, duration, videoSaver}, (new Filenamer()).newVideoName());
state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {resolution});
state.set(
PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false,
{resolution, facing: this.facing_});
} catch (e) {
state.set(
PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {hasError: true});
......@@ -725,12 +750,14 @@ class Video extends ModeBase {
class Photo extends ModeBase {
/**
* @param {!MediaStream} stream
* @param {!Facing} facing
* @param {!DoSavePhoto} doSavePhoto
* @param {?Resolution} captureResolution
* @param {!PlayShutterEffect} playShutterEffect
*/
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, captureResolution);
constructor(
stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, facing, captureResolution);
/**
* Callback for saving picture.
......@@ -805,8 +832,11 @@ class Photo extends ModeBase {
});
}
state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, true);
try {
const results = await this.crosImageCapture_.takePhoto(photoSettings);
state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {facing: this.facing_});
this.playShutterEffect_();
state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true);
......@@ -814,8 +844,11 @@ class Photo extends ModeBase {
const image = await util.blobToImage(blob);
const resolution = new Resolution(image.width, image.height);
await this.doSavePhoto_({resolution, blob}, imageName);
state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {resolution});
state.set(
PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false,
{resolution, facing: this.facing_});
} catch (e) {
state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {hasError: true});
state.set(
PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {hasError: true});
toast.show('error_msg_take_photo_failed');
......@@ -901,12 +934,14 @@ class Photo extends ModeBase {
class Square extends Photo {
/**
* @param {!MediaStream} stream
* @param {!Facing} facing
* @param {!DoSavePhoto} doSavePhoto
* @param {?Resolution} captureResolution
* @param {!PlayShutterEffect} playShutterEffect
*/
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, doSavePhoto, captureResolution, playShutterEffect);
constructor(
stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, facing, doSavePhoto, captureResolution, playShutterEffect);
this.doSavePhoto_ = async (result, ...args) => {
// Since the image blob after square cut will lose its EXIF including
......@@ -948,12 +983,14 @@ class Square extends Photo {
class Portrait extends Photo {
/**
* @param {!MediaStream} stream
* @param {!Facing} facing
* @param {!DoSavePhoto} doSavePhoto
* @param {?Resolution} captureResolution
* @param {!PlayShutterEffect} playShutterEffect
*/
constructor(stream, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, doSavePhoto, captureResolution, playShutterEffect);
constructor(
stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
super(stream, facing, doSavePhoto, captureResolution, playShutterEffect);
}
/**
......@@ -1036,6 +1073,7 @@ class Portrait extends Photo {
}
await refSave;
state.set(
PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false, {hasError});
PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false,
{hasError, facing: this.facing_});
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment