Commit fb6d0dcd authored by Wei Lee's avatar Wei Lee Committed by Chromium LUCI CQ

[CCA] Remove timeout mechanism for playing sound

We can use 'ended' event instead of timeout.

Bug: b/172341904
Test: Manually
Change-Id: I9f2704aa5edc41ba5a04c9d02e0824778d3d59e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2640515
Commit-Queue: Wei Lee <wtlee@chromium.org>
Reviewed-by: default avatarShik Chen <shik@chromium.org>
Auto-Submit: Wei Lee <wtlee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845998}
parent 5fafea43
......@@ -2,29 +2,61 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as dom from './dom.js';
import {AsyncJobQueue} from './async_job_queue.js';
import {WaitableEvent} from './waitable_event.js';
/**
* @type {!Map<!HTMLAudioElement, !AsyncJobQueue>}
*/
const jobQueueMap = new Map();
/**
* Gets the audio job queue for the element.
* @param {!HTMLAudioElement} el
* @return {!AsyncJobQueue}
*/
function getQueueFor(el) {
if (!jobQueueMap.has(el)) {
jobQueueMap.set(el, new AsyncJobQueue());
}
return jobQueueMap.get(el);
}
/**
* Plays a sound.
* @param {string} selector Selector of the sound.
* @return {{promise: !Promise, cancel: function()}} Promise for waiting
* finishing playing and function for canceling wait.
* @param {!HTMLAudioElement} el Audio element to play.
* @return {!Promise} Promise which will be resolved once the sound is ended or
* paused.
*/
export function play(selector) {
// Use a timeout to wait for sound finishing playing instead of end-event
// as it might not be played at all (crbug.com/135780).
// TODO(yuli): Don't play sounds if the speaker settings is muted.
let cancel;
const promise = new Promise((resolve, reject) => {
const element = dom.get(selector, HTMLAudioElement);
const timeout =
setTimeout(resolve, Number(element.dataset['timeout'] || 0));
cancel = () => {
clearTimeout(timeout);
reject(new Error('cancel'));
export function play(el) {
cancel(el);
const queue = getQueueFor(el);
const job = async () => {
el.currentTime = 0;
await el.play();
const audioEnded = new WaitableEvent();
const events = ['ended', 'pause'];
const onAudioStopped = () => {
audioEnded.signal();
for (const event of events) {
el.removeEventListener(event, onAudioStopped);
}
};
element.currentTime = 0;
element.play();
});
return {promise, cancel};
for (const event of events) {
el.addEventListener(event, onAudioStopped);
}
return audioEnded.wait();
};
return queue.push(job);
}
/**
* Cancel a sound from playing.
* @param {!HTMLAudioElement} el Audio element to cancel.
* @return {!Promise}
*/
export async function cancel(el) {
el.pause();
await getQueueFor(el).flush();
}
......@@ -449,7 +449,7 @@ export class Camera extends View {
* @override
*/
playShutterEffect() {
sound.play('#sound-shutter');
sound.play(dom.get('#sound-shutter', HTMLAudioElement));
animate.play(this.preview_.video);
}
......
......@@ -5,6 +5,7 @@
import {AsyncJobQueue} from '../../../async_job_queue.js';
import {browserProxy} from '../../../browser_proxy/browser_proxy.js';
import {assert, assertString} from '../../../chrome_util.js';
import * as dom from '../../../dom.js';
import {Filenamer} from '../../../models/file_namer.js';
import {
VideoSaver, // eslint-disable-line no-unused-vars
......@@ -131,13 +132,6 @@ export class Video extends ModeBase {
*/
this.handler_ = handler;
/**
* Promise for play start sound delay.
* @type {?{promise: !Promise, cancel: function()}}
* @private
*/
this.startSound_ = null;
/**
* MediaRecorder object to record motion pictures.
* @type {?MediaRecorder}
......@@ -221,7 +215,9 @@ export class Video extends ModeBase {
};
const playEffect = async () => {
state.set(state.State.RECORDING_UI_PAUSED, toBePaused);
await sound.play(toBePaused ? '#sound-rec-pause' : '#sound-rec-start');
await sound.play(dom.get(
toBePaused ? '#sound-rec-pause' : '#sound-rec-start',
HTMLAudioElement));
};
this.mediaRecorder_.addEventListener(toggledEvent, onToggled);
......@@ -244,13 +240,8 @@ export class Video extends ModeBase {
async start_() {
this.snapshots_ = new AsyncJobQueue();
this.togglePaused_ = null;
this.startSound_ = sound.play('#sound-rec-start');
this.everPaused_ = false;
try {
await this.startSound_.promise;
} finally {
this.startSound_ = null;
}
await sound.play(dom.get('#sound-rec-start', HTMLAudioElement));
if (this.mediaRecorder_ === null) {
try {
......@@ -276,7 +267,7 @@ export class Video extends ModeBase {
} finally {
duration = this.recordTime_.stop({pause: false});
}
sound.play('#sound-rec-end');
sound.play(dom.get('#sound-rec-end', HTMLAudioElement));
const settings = this.stream_.getVideoTracks()[0].getSettings();
const resolution = new Resolution(settings.width, settings.height);
......@@ -300,9 +291,8 @@ export class Video extends ModeBase {
* @override
*/
stop_() {
if (this.startSound_ !== null) {
this.startSound_.cancel();
}
sound.cancel(dom.get('#sound-rec-start', HTMLAudioElement));
if (this.mediaRecorder_ &&
(this.mediaRecorder_.state === 'recording' ||
this.mediaRecorder_.state === 'paused')) {
......
......@@ -46,7 +46,7 @@ export function start() {
resolve();
} else {
if (sounds[tickCounter] !== undefined) {
play(sounds[tickCounter]);
play(dom.get(sounds[tickCounter], HTMLAudioElement));
}
tickMsg.textContent = tickCounter + '';
animate.play(tickMsg);
......
......@@ -433,17 +433,13 @@
</div>
<div id="toast" class="centered-overlay" aria-live="polite"></div>
<div id="tooltip" aria-hidden="true"></div>
<audio id="sound-tick-final" src="/sounds/tick_final.ogg"
data-timeout="1000">
<audio id="sound-tick-inc" src="/sounds/tick_inc.ogg" data-timeout="1000">
<audio id="sound-tick-start" src="/sounds/tick_start.ogg"
data-timeout="1000">
<audio id="sound-shutter" src="/sounds/shutter.ogg" data-timeout="350">
<audio id="sound-rec-start" src="/sounds/record_start.ogg"
data-timeout="300">
<audio id="sound-rec-end" src="/sounds/record_end.ogg" data-timeout="450">
<audio id="sound-rec-pause" src="/sounds/record_pause.ogg"
data-timeout="500">
<audio id="sound-tick-final" src="/sounds/tick_final.ogg">
<audio id="sound-tick-inc" src="/sounds/tick_inc.ogg">
<audio id="sound-tick-start" src="/sounds/tick_start.ogg">
<audio id="sound-shutter" src="/sounds/shutter.ogg">
<audio id="sound-rec-start" src="/sounds/record_start.ogg">
<audio id="sound-rec-end" src="/sounds/record_end.ogg">
<audio id="sound-rec-pause" src="/sounds/record_pause.ogg">
<template id="preview-video-template">
<video id="preview-video" class="preview-content" aria-hidden="true"
muted></video>
......
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