diff --git a/.eslintrc.js b/.eslintrc.js index 3e7673ef..05f3f636 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { root: true, parserOptions: { - ecmaVersion: 6, + ecmaVersion: 8, sourceType: 'module', ecmaFeatures: { 'impliedStrict': true @@ -18,7 +18,8 @@ module.exports = { 'moment': false, 'jsPDF': false, 'Ajv': false, - 'PipeSDK': false + 'RecordRTCPromisesHandler': false + //'PipeSDK': false }, rules: { // 'warn', 'error', or 'off' 'no-console': 'off', // allow console.log diff --git a/app/components/exp-lookit-calibration/component.js b/app/components/exp-lookit-calibration/component.js index 0725b3e6..88159e8d 100644 --- a/app/components/exp-lookit-calibration/component.js +++ b/app/components/exp-lookit-calibration/component.js @@ -115,18 +115,22 @@ export default ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, ExpandAss // already been destroyed at that point. window.clearInterval(this.get('calTimer')); this.disablePausing(); - var _this = this; - if (this.get('doRecording')) { + if (this.get('doRecording') && (!this.get('stoppedRecording')) && !(this.get('stopping'))) { + this.set('stopping', true); + var _this = this; this.stopRecorder().then(() => { _this.set('stoppedRecording', true); + _this.destroyRecorder(); _this.send('next'); - return; }, () => { + _this.destroyRecorder(); _this.send('next'); - return; }); + } else if (this.get('doRecording') && this.get('stoppedRecording') && !(this.get('stopping'))) { + this.destroyRecorder(); + this.send('next'); } else { - _this.send('next'); + this.send('next'); } }, diff --git a/app/components/exp-lookit-change-detection/component.js b/app/components/exp-lookit-change-detection/component.js index a1eb099d..f0f77a26 100644 --- a/app/components/exp-lookit-change-detection/component.js +++ b/app/components/exp-lookit-change-detection/component.js @@ -360,15 +360,25 @@ export default ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, ExpandAss * @event stoppingCapture */ this.disablePausing(); - var _this = this; - this.stopRecorder().then(() => { - _this.set('stoppedRecording', true); - _this.send('next'); - return; - }, () => { - _this.send('next'); - return; - }); + if (this.get('doRecording')) { + if (!this.get('stoppedRecording') && (!this.get('stopping'))) { + var _this = this; + this.stopRecorder().then(() => { + _this.set('stoppedRecording', true); + _this.destroyRecorder(); + _this.send('next'); + }, () => { + _this.destroyRecorder(); + _this.send('next'); + }); + } else if (this.get('stoppedRecording') && (!this.get('stopping'))) { + this.destroyRecorder(); + this.send('next'); + } + // if the recorder is still stopping/uploading, then wait + } else { + this.send('next'); + } this._super(...arguments); } @@ -442,9 +452,9 @@ export default ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, ExpandAss // When triangles have been shown for time indicated: play end-audio if // present, or just move on. endTrial() { - this.stopRecorder(); + if (this.get('endAudioSources').length) { - $('#player-endaudio')[0].play(); + $('#player-endaudio')[0].play(); // onended calls finish } else { this.send('finish'); } @@ -607,8 +617,9 @@ export default ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, ExpandAss this.pause(); }); - if (this.get('doRecording')) { - let _this = this; + if (this.get('doRecording') && !this.get('stoppedRecording') && !this.get('stopping')) { + var _this = this; + this.set('stopping', true); return this.stopRecorder().finally(() => { _this.set('stoppedRecording', true); _this.destroyRecorder(); diff --git a/app/components/exp-lookit-observation/component.js b/app/components/exp-lookit-observation/component.js index c994304d..9c213a44 100644 --- a/app/components/exp-lookit-observation/component.js +++ b/app/components/exp-lookit-observation/component.js @@ -64,11 +64,15 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { okayToProceedTimer: null, timerStart: null, - hasStartedRecording: false, + // Flag to prevent recorder from continuing to automatically start when 'startRecordingAutomatically' + // We can't use the recorder's hasCreatedRecording property to track this because a new recorder is created after each recording ends. + hasMadeRecording: false, recordingStarted: false, toggling: false, hidden: false, recorderElement: '#recorder', + // Flag to track that user requests to move on via a next button click while upload is still in progress + proceedClicked: false, frameSchemaProperties: { /** @@ -209,10 +213,10 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { }, // Override to deal with whether or not recording is starting automatically - whenPossibleToRecord: observer('recorder.hasCamAccess', 'recorderReady', function() { - - if (this.get('recorder.hasCamAccess') && this.get('recorderReady')) { - if (this.get('startRecordingAutomatically')) { + whenPossibleToRecordObserver: observer('recorder.hasCamAccess', 'recorderReady', function() { + if (this.get('recorder.hasCamAccess') && this.get('recorderReady') && !(this.get('recorder.recording')) && !(this.get('starting'))) { + if (this.get('startRecordingAutomatically') && !(this.get('hasMadeRecording'))) { + this.set('starting', true); this.send('record'); } else { $('#recordButton').show(); @@ -222,7 +226,7 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { if (this.get('hideWebcam')) { $('#webcamToggleButton').html(this._translate('exp-lookit-observation.Show')); $('#hiddenWebcamMessage').show(); - $(this.get('recorderElement') + ' div').addClass('exp-lookit-observation-hidevideo'); + $('video').parent('div.lookit-video-recorder').parent().addClass('exp-lookit-observation-hidevideo'); this.set('hidden', true); /** * Webcam display hidden from participant @@ -233,9 +237,13 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { } } - }), + // Override to set startedRecording flag when starting automatically or via the record action + onRecordingStarted() { + this.set('recordingStarted', true); + }, + didInsertElement() { // initial state of all buttons/text $('#hiddenWebcamMessage').hide(); $('#recordButton').hide(); @@ -255,52 +263,90 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { $('#nextbutton').text(this.get('nextButtonText')); }, + onDestroyed() { + // reset any states here, since the recorder variable and states are not actually overwritten/reset + // by the recorder's destroy event + this.set('starting', false); + this.set('stopping', false); + this.set('recordingStarted', false); + this.set('stoppedRecording', false); + }, + actions: { record() { - this.startRecorder(); // TODO: use then - var _this = this; - if (this.get('recordSegmentLength')) { // no timer if 0 - window.clearTimeout(this.get('recordingTimer')); // as a precaution in case still running - window.clearInterval(this.get('progressTimer')); - window.clearTimeout(this.get('okayToProceedTimer')); - this.set('timerStart', new Date().getTime()); - this.set('recordingTimer', window.setTimeout(function() { - /** - * Video recording automatically paused upon reaching time limit - * - * @event recorderTimeout - */ - _this.send('setTimeEvent', 'recorderTimeout'); - _this.send('pause'); - }, _this.get('recordSegmentLength') * 1000)); - this.set('progressTimer', window.setInterval(function() { - var prctDone = (_this.get('recordSegmentLength') * 1000 - (new Date().getTime() - _this.get('timerStart'))) / (_this.get('recordSegmentLength') * 10); - $('.progress-bar').css('width', prctDone + '%'); - }, 100)); - if (this.get('recordingRequired')) { - this.set('okayToProceedTimer', window.setTimeout(function() { - _this.enableNext(); - }, 1000 * this.get('recordingRequired'))); + this.startRecorder().then(() => { + _this.set('starting', false); + + // set up timer and progress bar if necessary + if (this.get('recordSegmentLength')) { // no timer if 0 + window.clearTimeout(this.get('recordingTimer')); // as a precaution in case still running + window.clearInterval(this.get('progressTimer')); + window.clearTimeout(this.get('okayToProceedTimer')); + this.set('timerStart', new Date().getTime()); + this.set('recordingTimer', window.setTimeout(function() { + /** + * Video recording automatically paused upon reaching time limit + * @event recorderTimeout + */ + _this.send('setTimeEvent', 'recorderTimeout'); + _this.send('pause'); + }, _this.get('recordSegmentLength') * 1000)); + this.set('progressTimer', window.setInterval(function() { + var prctDone = (_this.get('recordSegmentLength') * 1000 - (new Date().getTime() - _this.get('timerStart'))) / (_this.get('recordSegmentLength') * 10); + $('.progress-bar').css('width', prctDone + '%'); + }, 100)); + if (this.get('recordingRequired')) { + this.set('okayToProceedTimer', window.setTimeout(function() { + _this.enableNext(); + }, 1000 * this.get('recordingRequired'))); + } } - } - $('#pauseButton').show(); - $('#recordButton').hide(); - $('#recordingIndicator').show(); - $('#recordingText').text(`${this._translate('exp-lookit-observation.Recording')}...`); - $('#recordButtonText').text(this._translate('exp-lookit-observation.Record')); + + $('#pauseButton').show(); + $('#recordButton').hide(); + $('#recordingIndicator').show(); + $('#recordingText').text(`${this._translate('exp-lookit-observation.Recording')}...`); + $('#recordButtonText').text(this._translate('exp-lookit-observation.Record')); + + }); + }, proceed() { // make sure 'next' fires while still on this frame window.clearTimeout(this.get('recordingTimer')); // no need for current timer window.clearTimeout(this.get('okayToProceedTimer')); window.clearInterval(this.get('progressTimer')); - this.stopRecorder().finally(() => { - this.destroyRecorder(); + let rec = this.get('recorder'); + this.set('proceedClicked', true); + if (rec && !(rec._recorderIsDestroyed)) { + var _this = this; + rec.get('recorder').getState().then((state) => { + if (state == 'recording') { + _this.set('stopping', true); + _this.stopRecorder().finally(() => { + _this.set('stoppedRecording', true); + _this.destroyRecorder(); + _this.onDestroyed(); + _this.send('next'); + }); + } else if ((_this.recordingStarted && _this.stoppedRecording && rec.isUploaded) || !(_this.recordingStarted)) { + // recorder is paused/stopped/inactive, and either it never started recording or has but upload has finished + _this.destroyRecorder(); + _this.onDestroyed(); + _this.send('next'); + } + // Do not do anything if is currently stopping/uploading - the destroy and next actions will be handled via the existing stop promise and proceedClicked flag + }, () => { + _this.send('next'); + }); + } else { + // recorder does not exist or exists but has been destroyed this.send('next'); - }); + } }, + pause() { var _this = this; $('#recordingText').text(`${this._translate('exp-lookit-observation.stopping-and-uploading')}...`); @@ -310,13 +356,34 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { window.clearInterval(_this.get('progressTimer')); $('.progress-bar').css('width', '100%'); $('#recordingIndicator').hide(); - this.stopRecorder().finally(() => { + this.set('stopping', true); + this.stopRecorder().then(() => { + _this.set('hasMadeRecording', true); + _this.set('stoppedRecording', true); + $('#recordButton').show(); + $('#recordingText').text(_this._translate('exp-lookit-observation.Paused')); + _this.destroyRecorder(); + _this.onDestroyed(); + if (_this.get('proceedClicked')) { + _this.send('proceed'); + } else { + _this.setupRecorder(_this.$(_this.get('recorderElement'))); + } + }, () => { + _this.set('hasMadeRecording', true); + _this.set('stoppedRecording', true); $('#recordButton').show(); $('#recordingText').text(_this._translate('exp-lookit-observation.Paused')); _this.destroyRecorder(); - _this.setupRecorder(_this.$(_this.get('recorderElement'))); + _this.onDestroyed(); + if (_this.get('proceedClicked')) { + _this.send('proceed'); + } else { + _this.setupRecorder(_this.$(_this.get('recorderElement'))); + } }); }, + toggleWebcamButton() { if (!this.toggling) { this.set('toggling', true); diff --git a/app/components/exp-lookit-stimuli-preview/component.js b/app/components/exp-lookit-stimuli-preview/component.js index 84ae34d9..6600b57b 100644 --- a/app/components/exp-lookit-stimuli-preview/component.js +++ b/app/components/exp-lookit-stimuli-preview/component.js @@ -17,7 +17,6 @@ export default ExpFrameBaseComponent.extend(VideoRecord, ExpandAssets, { videoIndex: 0, - recordingStopped: false, recordingStarted: false, noNext: computed('videoIndex', function() { @@ -192,17 +191,23 @@ export default ExpFrameBaseComponent.extend(VideoRecord, ExpandAssets, { this.send('setTimeEvent', 'previousStimulus'); this.set('videoIndex', this.get('videoIndex') - 1); }, - finish() { + finish() { // continue button press if (this.get('doRecording')) { - if (!this.get('recordingStopped')) { - this.set('recordingStopped', true); + if (!this.get('stoppedRecording') && !this.get('stopping')) { + this.set('stopping', true); var _this = this; this.stopRecorder().then(() => { + _this.set('stoppedRecording', true); + _this.destroyRecorder(); _this.send('next'); }, () => { + _this.destroyRecorder(); _this.send('next'); }); - } else { + } else if (this.get('stoppedRecording') && !this.get('stopping')) { + // if recorder has finished stopping/uploading then we can destroy it and move on + // (if recorder is already stopping, then do nothing - need to wait for it to finish) + this.destroyRecorder(); this.send('next'); } } else { diff --git a/app/components/exp-lookit-stop-recording/component.js b/app/components/exp-lookit-stop-recording/component.js index 17b8ae7f..49e62f30 100644 --- a/app/components/exp-lookit-stop-recording/component.js +++ b/app/components/exp-lookit-stop-recording/component.js @@ -129,38 +129,40 @@ export default ExpFrameBaseComponent.extend(ExpandAssets, { }); this.set('progressTimer', window.setInterval(function() { - let msg = $('.pipeMsgOverlay').html(); - let match = msg.match(/\d*%/); - if (match) { - $('#progress').html(`Uploading video... ${match[0]}`); - $('.progress-bar').css('width', match); - _this.set('hasStartedUpload', true); - } else if (msg) { - $('#progress').html(msg); - } else { - $('#progress').html('Uploading video...') + $('#progress').html('Uploading video...     '); + if (!_this.get('_recording') && _this.get('sessionRecorder').s3.hasStartedCompletingUpload) { + const percComplete = _this.get('sessionRecorder').s3.percentUploadComplete; + if (percComplete > 0) { + _this.set('hasStartedUpload', true); + window.clearInterval(_this.get('allowProceedTimer')); + } + let progressPercStr = percComplete.toString()+'%'; + $('#progress').html(`Uploading video... ${progressPercStr}`); + $('.progress-bar').css('width', progressPercStr); } }, 100)); this.set('allowProceedTimer', window.setTimeout(function() { if (!_this.get('hasStartedUpload')) { /** - * If no progress update about upload is available within 10s, and - * frame proceeds automatically. Otherwise if the upload has started - * (e.g. we know it is 10% done) it will continue waiting. + * Note: this timer waits a long time (5 minutes) before checking if at least one part of the multi-part * upload has completed, and if not, allowing the participant to proceed. + * This is a longer wait time (vs the old Pipe system) because we don't have as fine-grained upload + * progress info with RecordRTC/S3 as we used to have with Pipe. We might want to reconsider the way + * this timer works and its duration in the future, if we get reports about participants getting 'stuck' + * while waiting for uploads. * * @event warningUploadTimeoutError */ _this.send('setTimeEvent', 'warningUploadTimeoutError'); _this.send('next'); } - }, 5000)); + }, 300000)); }, willDestroyElement() { window.clearInterval(this.get('progressTimer')); - window.clearInterval(this.get('allowProceedTimer')); + window.clearTimeout(this.get('allowProceedTimer')); this._super(...arguments); } diff --git a/app/components/exp-lookit-video-assent/component.js b/app/components/exp-lookit-video-assent/component.js index 78437834..3e34a469 100644 --- a/app/components/exp-lookit-video-assent/component.js +++ b/app/components/exp-lookit-video-assent/component.js @@ -32,6 +32,9 @@ export default ExpFrameBaseComponent.extend(VideoRecord, ExpandAssets, { disableRecord: Em.computed('recorder.recording', 'recorder.hasCamAccess', function () { return !this.get('recorder.hasCamAccess') || this.get('recorder.recording'); }), + // keep track of whether a recorder has already started, + // in case of recording last page and moving forward/backward through pages, + // and to prevent race conditions when recorder is still installing startedRecording: false, pageIndex: null, @@ -132,7 +135,8 @@ export default ExpFrameBaseComponent.extend(VideoRecord, ExpandAssets, { }, updatePage() { - if (this.get('recordLastPage') && !this.get('recordWholeProcedure') && (this.get('pageIndex') === this.get('pages').length - 1)) { + if (this.get('recordLastPage') && !this.get('recordWholeProcedure') && !(this.get('startedRecording')) && (this.get('pageIndex') === this.get('pages').length - 1)) { + this.set('startedRecording', true); this.startRecorder(); } if (this.get('pageHasAudio')) { @@ -195,15 +199,30 @@ export default ExpFrameBaseComponent.extend(VideoRecord, ExpandAssets, { this.send('setTimeEvent', 'assentQuestionSubmit', {childResponse: this.get('childResponse')}); - var _this = this; - if (_this.get('childResponse') === 'Yes') { - this.stopRecorder().then(() => { - _this.send('next'); - }, () => { - _this.send('next'); - }); + if (this.get('childResponse') === 'Yes') { + if (this.get('sessionRecorder') && this.get('sessionRecordingInProgress')) { + this.send('next'); + } else { + if (!this.get('stoppedRecording') && (!this.get('stopping'))) { + this.set('stopping', true); + var _this = this; + this.stopRecorder().then(() => { + _this.set('stoppedRecording', true); + _this.destroyRecorder(); + _this.send('next'); + }, () => { + _this.destroyRecorder(); + _this.send('next'); + }); + } else if (this.get('stoppedRecording') && (!this.get('stopping'))) { + // if recorder has finished stopping/uploading then we can destroy it and move on + // (if recorder is already stopping but hasn't finished, then do nothing - need to wait for it to finish) + this.destroyRecorder(); + this.send('next'); + } + } } else { - _this.send('exit'); + this.send('exit'); } }, diff --git a/app/components/exp-lookit-video-consent/component.js b/app/components/exp-lookit-video-consent/component.js index 8d094aa9..ece04c4a 100644 --- a/app/components/exp-lookit-video-consent/component.js +++ b/app/components/exp-lookit-video-consent/component.js @@ -51,25 +51,27 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { startRecorderAndUpdateDisplay() { this.set('startedRecording', true); // keep track of if ANY recorder has been set up yet let _this = this; - this.startRecorder().then(() => { - // Require at least 2 s recording - setTimeout(function() { - $('#stopbutton').prop('disabled', false); - }, 2000); - $('#recordingIndicator').show(); - $('#recordingText').text(_this._translate('exp-lookit-video-consent.Recording')); - }, () => { - $('#recordingText').text(_this._translate('exp-lookit-video-consent.Error-starting-recorder')); - $('#recordbutton').prop('disabled', false); - }); + this.startRecorder() + .then(() => { + // Require at least 2 s recording + setTimeout(function() { + $('#stopbutton').prop('disabled', false); + }, 2000); + $('#recordingIndicator').show(); + $('#recordingText').text(_this._translate('exp-lookit-video-consent.Recording')); + }) + .catch((err) => { + $('#recordingText').text(_this._translate('exp-lookit-video-consent.Error-starting-recorder')); + $('#recordbutton').prop('disabled', false); + console.error(`Error starting recorder: ${err.name}: ${err.message}`); + console.trace(); + }); }, actions: { record() { - $('#recordingStatus').show(); $('#recordingText').text(`${this._translate('exp-lookit-video-consent.Starting-recorder')}...`); - $('[id^=pipeMenu]').hide(); $('#recordbutton').prop('disabled', true); $('#playbutton').prop('disabled', true); this.set('showWarning', false); @@ -77,18 +79,22 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { this.set('hasMadeVideo', false); if (this.get('startedRecording')) { - if (this.get('recorder') && this.get('recorder').get('recorder')) { - this.get('recorder').get('recorder').pause(); + if (this.get('recorder')) { + this.get('recorder').pause(); } this.destroyRecorder(); // Need to destroy between recordings or else the same video ID is sent as payload. // Don't destroy after stopRecorder call because then can't replay. var _this = this; - this.setupRecorder(_this.$(_this.get('recorderElement'))).then(() => { - _this.startRecorderAndUpdateDisplay(); - }, () => { - $('#recordingText').text(_this._translate('exp-lookit-video-consent.Error-starting-recorder')); - $('#recordbutton').prop('disabled', false); - }); + this.setupRecorder(_this.$(_this.get('recorderElement'))) + .then(() => { + _this.startRecorderAndUpdateDisplay(); + }) + .catch((err) => { + $('#recordingText').text(_this._translate('exp-lookit-video-consent.Error-starting-recorder')); + $('#recordbutton').prop('disabled', false); + console.error(`Error restarting recorder: ${err.name}: ${err.message}`); + console.trace(); + }); } else { this.startRecorderAndUpdateDisplay(); // First time - can use current recorder } @@ -100,24 +106,23 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { $('#stopbutton').prop('disabled', true); var _this = this; - this.stopRecorder().finally(() => { - _this.set('stoppedRecording', true); - _this.set('hasMadeVideo', true); - $('#recordingText').text(_this._translate('exp-lookit-video-consent.Not-recording')); - $('#playbutton').prop('disabled', false); - $('#recordbutton').prop('disabled', false); - }); + this.stopRecorder() + .finally(() => { + _this.set('stoppedRecording', true); + _this.set('hasMadeVideo', true); + $('#recordingText').text(_this._translate('exp-lookit-video-consent.Not-recording')); + $('#playbutton').prop('disabled', false); + $('#recordbutton').prop('disabled', false); + }); }, playvideo() { $('#recordingText').text(''); $('#recordingStatus').hide(); - this.get('recorder').get('recorder').playVideo(); - $('[id^=pipeMenu]').show(); + this.setUpPlayback(); this.set('hasCheckedVideo', true); }, finish() { - if (!this.get('hasMadeVideo') || !this.get('hasCheckedVideo')) { this.set('showWarning', true); } else { @@ -636,7 +641,6 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { this.set('consentFormText', $('#consent-form-text').text()); $('#recordingIndicator').hide(); $('#recordingText').text(this._translate('exp-lookit-video-consent.Not-recording-yet')); - $('[id^=pipeMenu]').hide(); $('#recordbutton').prop('disabled', false); $('#stopbutton').prop('disabled', true); $('#playbutton').prop('disabled', true); diff --git a/app/components/exp-lookit-video-infant-control/component.js b/app/components/exp-lookit-video-infant-control/component.js index 480dee6d..4e559686 100644 --- a/app/components/exp-lookit-video-infant-control/component.js +++ b/app/components/exp-lookit-video-infant-control/component.js @@ -35,7 +35,7 @@ export default ExpLookitVideo.extend(InfantControlledTiming, { actions: { videoStarted() { - if (this.get('testVideoTimesPlayed') === 0) { + if ((this.get('testVideoTimesPlayed') === 0) && !this.get('_finishing')) { this.startParentControl(); } this._super(...arguments); diff --git a/app/components/exp-lookit-video/component.js b/app/components/exp-lookit-video/component.js index bf2c7e61..6344ff1f 100644 --- a/app/components/exp-lookit-video/component.js +++ b/app/components/exp-lookit-video/component.js @@ -48,7 +48,6 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp skip: false, hasParentText: true, - /** comment some text */ maximizeVideoArea: false, _finishing: false, @@ -202,7 +201,7 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp * * @event videoStarted */ - if (this.get('isDestroying') || this.get('isDestroyed')) { + if (this.get('isDestroying') || this.get('isDestroyed') || this.get('_finishing')) { return; } @@ -229,7 +228,7 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp }, videoStopped() { - if (this.get('isDestroying') || this.get('isDestroyed')) { + if (this.get('isDestroying') || this.get('isDestroyed') || (this.get('_finishing'))) { return; } this.set('testVideoTimesPlayed', this.get('testVideoTimesPlayed') + 1); @@ -281,10 +280,6 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp // to call next AFTER recording is stopped and we don't want this to have // already been destroyed at that point. - // Pause audio/video so we don't trigger started/stopped handlers while destroying - $('audio, video').each(function() { - this.pause(); - }); /** * When trial is complete and begins cleanup (may then wait for video upload) * @@ -296,19 +291,31 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp this.set('testVideoTimesPlayed', 0); this.set('testAudioTimesPlayed', 0); this.set('satisfiedDuration', false); - var _this = this; if (!this.get('_finishing')) { this.set('_finishing', true); + // Pause audio/video so we don't trigger started/stopped handlers while destroying + $('audio, video').each(function() { + this.pause(); + }); if (this.get('doRecording')) { - this.set('doingTest', false); - this.stopRecorder().then(() => { - _this.set('stoppedRecording', true); - _this.send('next'); - }, () => { - _this.send('next'); - }); + if (!this.get('stopping') && !this.get('stoppedRecording')) { + this.set('stopping', true); + this.set('doingTest', false); + var _this = this; + this.stopRecorder().then(() => { + _this.set('stoppedRecording', true); + _this.destroyRecorder(); + _this.send('next'); + }, () => { + _this.destroyRecorder(); + _this.send('next'); + }); + } else if (!this.get('stopping') && this.get('stoppedRecording')) { + this.destroyRecorder(); + this.send('next'); + } } else { - _this.send('next'); + this.send('next'); } } } @@ -356,8 +363,9 @@ let ExpLookitVideo = ExpFrameBaseComponent.extend(VideoRecord, PauseUnpause, Exp this.set('satisfiedDuration', false); $('.exp-lookit-video').hide(); $('#nextbutton').prop('disabled', true); // disable Next while paused - if (this.get('doRecording')) { + if (this.get('doRecording') && (!this.get('stoppedRecording')) && (!this.get('stopping'))) { let _this = this; + this.set('stopping', true); return this.stopRecorder().finally(() => { _this.set('stoppedRecording', true); _this.destroyRecorder(); diff --git a/app/components/exp-video-config-quality/component.js b/app/components/exp-video-config-quality/component.js index f5294e5c..f77a1544 100644 --- a/app/components/exp-video-config-quality/component.js +++ b/app/components/exp-video-config-quality/component.js @@ -320,12 +320,17 @@ export default ExpFrameBaseComponent.extend(VideoRecord, { if (!this.get('showRecordMenu')) { this.set('requireTestVideo', false); + $('#recordingStatus').hide(); + $('#recordingIndicator').hide(); $('.exp-video-config-quality').append($('