diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 838ed837461e..ce7e03e71d92 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 9b53b32fadb4..8e137bbcbf02 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 84b724b4eedd..45c113073a6f 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 95e5fdd00a1a..fd303c22a2a6 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 18093c043ec0..1c97fcfbdf56 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 1bc6d389a8a0..d04772a2ebf8 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 84b724b4eedd..45c113073a6f 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 7b6222453958..e7a3ac516e4a 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 45806ee6435f..45c8bb08cd31 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "60489c1ff8c5d1633fc4837d4f8019623d4e1940", + "git_revision": "d9d99f32762975a370f1abd34a3512bd6fe29111", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "43de6ab8b9790809ac7b4d80bf060a2976a88417", + "revision": "a1b18f9a9e869b1ae261a064a7dd174d59169fb9", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index bd557964e9d9..49ceab543fa1 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 3b12142e64d0..319ad2a91a18 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/dom/camera/CameraControlImpl.cpp b/dom/camera/CameraControlImpl.cpp index b05eaf19e1da..811ab97178f6 100644 --- a/dom/camera/CameraControlImpl.cpp +++ b/dom/camera/CameraControlImpl.cpp @@ -298,6 +298,8 @@ CameraControlImpl::OnUserError(CameraControlListener::UserContext aContext, "TakePicture", "StartRecording", "StopRecording", + "PauseRecording", + "ResumeRecording", "SetConfiguration", "StartPreview", "StopPreview", @@ -602,6 +604,48 @@ CameraControlImpl::StopRecording() return Dispatch(new Message(this, CameraControlListener::kInStopRecording)); } +nsresult +CameraControlImpl::PauseRecording() +{ + class Message : public ControlMessage + { + public: + Message(CameraControlImpl* aCameraControl, + CameraControlListener::UserContext aContext) + : ControlMessage(aCameraControl, aContext) + { } + + nsresult + RunImpl() override + { + return mCameraControl->PauseRecordingImpl(); + } + }; + + return Dispatch(new Message(this, CameraControlListener::kInPauseRecording)); +} + +nsresult +CameraControlImpl::ResumeRecording() +{ + class Message : public ControlMessage + { + public: + Message(CameraControlImpl* aCameraControl, + CameraControlListener::UserContext aContext) + : ControlMessage(aCameraControl, aContext) + { } + + nsresult + RunImpl() override + { + return mCameraControl->ResumeRecordingImpl(); + } + }; + + return Dispatch(new Message(this, CameraControlListener::kInResumeRecording)); +} + nsresult CameraControlImpl::StartPreview() { diff --git a/dom/camera/CameraControlImpl.h b/dom/camera/CameraControlImpl.h index 5d6035c9c790..d5da52906743 100644 --- a/dom/camera/CameraControlImpl.h +++ b/dom/camera/CameraControlImpl.h @@ -48,6 +48,8 @@ public: virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor, const StartRecordingOptions* aOptions) override; virtual nsresult StopRecording() override; + virtual nsresult PauseRecording() override; + virtual nsresult ResumeRecording() override; virtual nsresult ResumeContinuousFocus() override; // Event handlers called directly from outside this class. @@ -121,6 +123,8 @@ protected: virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor, const StartRecordingOptions* aOptions) = 0; virtual nsresult StopRecordingImpl() = 0; + virtual nsresult PauseRecordingImpl() = 0; + virtual nsresult ResumeRecordingImpl() = 0; virtual nsresult ResumeContinuousFocusImpl() = 0; virtual nsresult PushParametersImpl() = 0; virtual nsresult PullParametersImpl() = 0; diff --git a/dom/camera/CameraControlListener.h b/dom/camera/CameraControlListener.h index c3092302e89e..f0cfc9c5ddd8 100644 --- a/dom/camera/CameraControlListener.h +++ b/dom/camera/CameraControlListener.h @@ -64,6 +64,8 @@ public: { kRecorderStopped, kRecorderStarted, + kRecorderPaused, + kRecorderResumed, kPosterCreated, kPosterFailed, #ifdef MOZ_B2G_CAMERA @@ -109,6 +111,8 @@ public: kInTakePicture, kInStartRecording, kInStopRecording, + kInPauseRecording, + kInResumeRecording, kInSetConfiguration, kInStartPreview, kInStopPreview, diff --git a/dom/camera/DOMCameraControl.cpp b/dom/camera/DOMCameraControl.cpp index 98dbe1655db5..396305034e12 100755 --- a/dom/camera/DOMCameraControl.cpp +++ b/dom/camera/DOMCameraControl.cpp @@ -890,6 +890,24 @@ nsDOMCameraControl::StopRecording(ErrorResult& aRv) aRv = mCameraControl->StopRecording(); } +void +nsDOMCameraControl::PauseRecording(ErrorResult& aRv) +{ + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); + THROW_IF_NO_CAMERACONTROL(); + + aRv = mCameraControl->PauseRecording(); +} + +void +nsDOMCameraControl::ResumeRecording(ErrorResult& aRv) +{ + DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this); + THROW_IF_NO_CAMERACONTROL(); + + aRv = mCameraControl->ResumeRecording(); +} + void nsDOMCameraControl::ResumePreview(ErrorResult& aRv) { @@ -1400,6 +1418,14 @@ nsDOMCameraControl::OnRecorderStateChange(CameraControlListener::RecorderState a mOptions.mPosterStorageArea = nullptr; break; + case CameraControlListener::kRecorderPaused: + state = NS_LITERAL_STRING("Paused"); + break; + + case CameraControlListener::kRecorderResumed: + state = NS_LITERAL_STRING("Resumed"); + break; + #ifdef MOZ_B2G_CAMERA case CameraControlListener::kFileSizeLimitReached: state = NS_LITERAL_STRING("FileSizeLimitReached"); @@ -1656,6 +1682,18 @@ nsDOMCameraControl::OnUserError(CameraControlListener::UserContext aContext, nsr NS_WARNING("Failed to stop recording"); return; + case CameraControlListener::kInPauseRecording: + // This method doesn't have any callbacks, so all we can do is log the + // failure. This only happens after the hardware has been released. + NS_WARNING("Failed to pause recording"); + return; + + case CameraControlListener::kInResumeRecording: + // This method doesn't have any callbacks, so all we can do is log the + // failure. This only happens after the hardware has been released. + NS_WARNING("Failed to resume recording"); + return; + case CameraControlListener::kInStartPreview: // This method doesn't have any callbacks, so all we can do is log the // failure. This only happens after the hardware has been released. diff --git a/dom/camera/DOMCameraControl.h b/dom/camera/DOMCameraControl.h index ad20ef0c6471..ffbfbc6b3448 100644 --- a/dom/camera/DOMCameraControl.h +++ b/dom/camera/DOMCameraControl.h @@ -120,6 +120,8 @@ public: const nsAString& filename, ErrorResult& aRv); void StopRecording(ErrorResult& aRv); + void PauseRecording(ErrorResult& aRv); + void ResumeRecording(ErrorResult& aRv); void ResumePreview(ErrorResult& aRv); already_AddRefed ReleaseHardware(ErrorResult& aRv); void ResumeContinuousFocus(ErrorResult& aRv); diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 0d6fd365237b..e1eae093614b 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -1323,6 +1323,48 @@ nsGonkCameraControl::StopRecordingImpl() return NS_DispatchToMainThread(new RecordingComplete(mVideoFile.forget())); } +nsresult +nsGonkCameraControl::PauseRecordingImpl() +{ + ReentrantMonitorAutoEnter mon(mRecorderMonitor); + +#ifdef MOZ_WIDGET_GONK + if (!mRecorder) { + return NS_ERROR_NOT_AVAILABLE; + } + + int err = mRecorder->pause(); + switch (err) { + case OK: + break; + case INVALID_OPERATION: + return NS_ERROR_NOT_IMPLEMENTED; + default: + return NS_ERROR_FAILURE; + } +#endif + OnRecorderStateChange(CameraControlListener::kRecorderPaused); + return NS_OK; +} + +nsresult +nsGonkCameraControl::ResumeRecordingImpl() +{ + ReentrantMonitorAutoEnter mon(mRecorderMonitor); + +#ifdef MOZ_WIDGET_GONK + if (!mRecorder) { + return NS_ERROR_NOT_AVAILABLE; + } + + if (mRecorder->resume() != OK) { + return NS_ERROR_FAILURE; + } +#endif + OnRecorderStateChange(CameraControlListener::kRecorderResumed); + return NS_OK; +} + nsresult nsGonkCameraControl::ResumeContinuousFocusImpl() { diff --git a/dom/camera/GonkCameraControl.h b/dom/camera/GonkCameraControl.h index 2715bfcf09a4..aa6358fefbc4 100644 --- a/dom/camera/GonkCameraControl.h +++ b/dom/camera/GonkCameraControl.h @@ -138,6 +138,8 @@ protected: virtual nsresult StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescriptor, const StartRecordingOptions* aOptions = nullptr) override; virtual nsresult StopRecordingImpl() override; + virtual nsresult PauseRecordingImpl() override; + virtual nsresult ResumeRecordingImpl() override; virtual nsresult ResumeContinuousFocusImpl() override; virtual nsresult PushParametersImpl() override; virtual nsresult PullParametersImpl() override; diff --git a/dom/camera/GonkRecorder.cpp b/dom/camera/GonkRecorder.cpp index 46d52e88869f..89bcb861352f 100644 --- a/dom/camera/GonkRecorder.cpp +++ b/dom/camera/GonkRecorder.cpp @@ -20,6 +20,7 @@ #include "CameraCommon.h" #include "GonkCameraSource.h" #include "GonkRecorder.h" +#include "mozilla/CondVar.h" #define RE_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) #define RE_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) @@ -58,6 +59,132 @@ #define RES_720P (720 * 1280) namespace android { +struct GonkRecorder::WrappedMediaSource : MediaSource { +public: + WrappedMediaSource(const sp &encoder); + status_t start(MetaData *params = NULL) override; + status_t stop() override; + sp getFormat() override; + status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL) override; + void block(); + status_t resume(); + +protected: + virtual ~WrappedMediaSource() {}; + +private: + WrappedMediaSource(const WrappedMediaSource &); + WrappedMediaSource &operator=(const WrappedMediaSource &); + + sp mEncoder; + mozilla::Mutex mMutex; + mozilla::CondVar mCondVar; + bool mWait; + bool mResume; + status_t mResumeStatus; +}; + +GonkRecorder::WrappedMediaSource::WrappedMediaSource(const sp &encoder) + : mEncoder(encoder) + , mMutex("GonkRecorder::WrappedMediaSource::mMutex") + , mCondVar(mMutex, "GonkRecorder::WrappedMediaSource::mCondVar") + , mWait(false) + , mResume(false) + , mResumeStatus(UNKNOWN_ERROR) +{ +} + +status_t +GonkRecorder::WrappedMediaSource::start(MetaData *params) +{ + return mEncoder->start(params); +} + +status_t +GonkRecorder::WrappedMediaSource::stop() +{ + { + // Ensure the writer thread is not blocked first. + MutexAutoLock lock(mMutex); + mWait = false; + mCondVar.Notify(); + } + return mEncoder->stop(); +} + +sp +GonkRecorder::WrappedMediaSource::getFormat() +{ + return mEncoder->getFormat(); +} + +status_t +GonkRecorder::WrappedMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) +{ + MutexAutoLock lock(mMutex); + while (mWait) { + mCondVar.Wait(); + } + + status_t rv = UNKNOWN_ERROR; + MediaBuffer *buf = NULL; + + do { + rv = mEncoder->read(&buf, options); + if (!mResume) { + break; + } + + if (rv != OK || !buf) { + mResume = false; + mResumeStatus = UNKNOWN_ERROR; + mCondVar.Notify(); + break; + } + + int32_t isSync = 0; + buf->meta_data()->findInt32(kKeyIsSyncFrame, &isSync); + if (isSync) { + mResume = false; + mResumeStatus = OK; + mCondVar.Notify(); + break; + } + + buf->release(); + buf = NULL; + } while(true); + + *buffer = buf; + return rv; +} + +void +GonkRecorder::WrappedMediaSource::block() +{ + MutexAutoLock lock(mMutex); + mWait = true; +} + +status_t +GonkRecorder::WrappedMediaSource::resume() +{ + MutexAutoLock lock(mMutex); + if (!mWait) { + return UNKNOWN_ERROR; + } + + mWait = false; + mResume = true; + mCondVar.Notify(); + + do { + mCondVar.Wait(); + } while(mResume); + + return mResumeStatus; +} + GonkRecorder::GonkRecorder() : mWriter(NULL), mOutputFd(-1), @@ -1500,11 +1627,13 @@ status_t GonkRecorder::setupMPEG4Recording( int32_t videoWidth, int32_t videoHeight, int32_t videoBitRate, int32_t *totalBitRate, - sp *mediaWriter) { + sp *mediaWriter, + sp *mediaSource) { mediaWriter->clear(); *totalBitRate = 0; status_t err = OK; sp writer = new MPEG4Writer(outputFd); + sp writerSource; if (mVideoSource < VIDEO_SOURCE_LIST_END) { @@ -1520,7 +1649,10 @@ status_t GonkRecorder::setupMPEG4Recording( return err; } - writer->addSource(encoder); + sp cameraSource = reinterpret_cast(mediaSource.get()); + writerSource = new WrappedMediaSource(encoder); + + writer->addSource(writerSource); *totalBitRate += videoBitRate; } @@ -1556,6 +1688,7 @@ status_t GonkRecorder::setupMPEG4Recording( writer->setListener(mListener); *mediaWriter = writer; + *mediaSource = writerSource; return OK; } @@ -1587,7 +1720,8 @@ status_t GonkRecorder::startMPEG4Recording() { int32_t totalBitRate; status_t err = setupMPEG4Recording( mOutputFd, mVideoWidth, mVideoHeight, - mVideoBitRate, &totalBitRate, &mWriter); + mVideoBitRate, &totalBitRate, &mWriter, + &mWriterSource); if (err != OK) { return err; } @@ -1616,20 +1750,56 @@ status_t GonkRecorder::pause() { if (mWriter == NULL) { return UNKNOWN_ERROR; } - mWriter->pause(); - - if (mStarted) { + if (!mStarted) { + return OK; + } + // Pause is not properly supported by all writers although + // for B2G we only currently use 3GPP/MPEG4 + int err = INVALID_OPERATION; + switch (mOutputFormat) { + case OUTPUT_FORMAT_DEFAULT: + case OUTPUT_FORMAT_THREE_GPP: + case OUTPUT_FORMAT_MPEG_4: + err = mWriter->pause(); + break; + default: + break; + } + if (err == OK) { mStarted = false; } + return err; +} - - return OK; +status_t GonkRecorder::resume() { + RE_LOGV("resume"); + if (mWriter == NULL) { + return UNKNOWN_ERROR; + } + if (mStarted) { + return OK; + } + /* While the writer is paused, it will continue to pull frames + from the encoder. This ensures continuity on the timestamps of + the encoded frames, etc. When we want to resume however, we must + ensure that the first read frame is a key frame. */ + mWriterSource->block(); + int err = mWriter->start(NULL); + if (err != OK) { + return err; + } + err = mWriterSource->resume(); + if (err == OK) { + mStarted = true; + } + return err; } status_t GonkRecorder::stop() { RE_LOGV("stop"); status_t err = OK; + mWriterSource.clear(); if (mWriter != NULL) { err = mWriter->stop(); mWriter.clear(); diff --git a/dom/camera/GonkRecorder.h b/dom/camera/GonkRecorder.h index ddaa5ff57951..27b61967fb81 100644 --- a/dom/camera/GonkRecorder.h +++ b/dom/camera/GonkRecorder.h @@ -63,6 +63,7 @@ struct GonkRecorder { virtual status_t prepare(); virtual status_t start(); virtual status_t pause(); + virtual status_t resume(); virtual status_t stop(); virtual status_t close(); virtual status_t reset(); @@ -74,10 +75,13 @@ protected: virtual ~GonkRecorder(); private: + struct WrappedMediaSource; + sp mListener; String16 mClientName; uid_t mClientUid; sp mWriter; + sp mWriterSource; int mOutputFd; sp mAudioSourceNode; @@ -127,7 +131,8 @@ private: int32_t videoWidth, int32_t videoHeight, int32_t videoBitRate, int32_t *totalBitRate, - sp *mediaWriter); + sp *mediaWriter, + sp *mediaSource); void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, sp *meta); status_t startMPEG4Recording(); diff --git a/dom/camera/ICameraControl.h b/dom/camera/ICameraControl.h index 1b8d70b28e49..41be6694140a 100644 --- a/dom/camera/ICameraControl.h +++ b/dom/camera/ICameraControl.h @@ -256,6 +256,8 @@ public: virtual nsresult StartRecording(DeviceStorageFileDescriptor* aFileDescriptor, const StartRecordingOptions* aOptions = nullptr) = 0; virtual nsresult StopRecording() = 0; + virtual nsresult PauseRecording() = 0; + virtual nsresult ResumeRecording() = 0; virtual nsresult StartFaceDetection() = 0; virtual nsresult StopFaceDetection() = 0; virtual nsresult ResumeContinuousFocus() = 0; diff --git a/dom/camera/test/camera_common.js b/dom/camera/test/camera_common.js index edd7c6f62ec2..f67f1e5faaf0 100644 --- a/dom/camera/test/camera_common.js +++ b/dom/camera/test/camera_common.js @@ -80,6 +80,8 @@ function CameraTestSuite() { this.rejectTakePicture = this._rejectTakePicture.bind(this); this.rejectStartRecording = this._rejectStartRecording.bind(this); this.rejectStopRecording = this._rejectStopRecording.bind(this); + this.rejectPauseRecording = this._rejectPauseRecording.bind(this); + this.rejectResumeRecording = this._rejectResumeRecording.bind(this); this.rejectPreviewStarted = this._rejectPreviewStarted.bind(this); var self = this; @@ -409,6 +411,14 @@ CameraTestSuite.prototype = { return this.logError('stop recording failed', e); }, + _rejectPauseRecording: function(e) { + return this.logError('pause recording failed', e); + }, + + _rejectResumeRecording: function(e) { + return this.logError('resume recording failed', e); + }, + _rejectPreviewStarted: function(e) { return this.logError('preview start failed', e); }, diff --git a/dom/camera/test/test_camera_record.html b/dom/camera/test/test_camera_record.html index b012669bf7d1..a2b801ee0635 100644 --- a/dom/camera/test/test_camera_record.html +++ b/dom/camera/test/test_camera_record.html @@ -45,6 +45,50 @@ suite.test('recording', function() { return Promise.all([domPromise, eventPromise]); } + function pauseRecording(p) { + var eventPromise = new Promise(function(resolve, reject) { + function onEvent(evt) { + ok(evt.newState === 'Paused', 'recorder state change event = ' + evt.newState); + suite.camera.removeEventListener('recorderstatechange', onEvent); + resolve(); + } + suite.camera.addEventListener('recorderstatechange', onEvent); + }); + + var domPromise = new Promise(function(resolve, reject) { + try { + suite.camera.pauseRecording(); + resolve(); + } catch(e) { + reject(e); + } + }); + + return Promise.all([domPromise, eventPromise]); + } + + function resumeRecording(p) { + var eventPromise = new Promise(function(resolve, reject) { + function onEvent(evt) { + ok(evt.newState === 'Resumed', 'recorder state change event = ' + evt.newState); + suite.camera.removeEventListener('recorderstatechange', onEvent); + resolve(); + } + suite.camera.addEventListener('recorderstatechange', onEvent); + }); + + var domPromise = new Promise(function(resolve, reject) { + try { + suite.camera.resumeRecording(); + resolve(); + } catch(e) { + reject(e); + } + }); + + return Promise.all([domPromise, eventPromise]); + } + function stopRecording(p) { var eventPromise = new Promise(function(resolve, reject) { function onEvent(evt) { @@ -70,7 +114,9 @@ suite.test('recording', function() { return suite.getCamera(undefined, baseConfig) .then(cleanup, suite.rejectGetCamera) .then(startRecording) - .then(stopRecording, suite.rejectStartRecording) + .then(pauseRecording, suite.rejectStartRecording) + .then(resumeRecording, suite.rejectPauseRecording) + .then(stopRecording, suite.rejectResumeRecording) .catch(suite.rejectStopRecording); }); diff --git a/dom/webidl/CameraControl.webidl b/dom/webidl/CameraControl.webidl index b06591770c1e..ba57cac72a8b 100644 --- a/dom/webidl/CameraControl.webidl +++ b/dom/webidl/CameraControl.webidl @@ -249,7 +249,19 @@ interface CameraControl : MediaStream recording limits (see CameraStartRecordingOptions) was reached. event type is CameraStateChangeEvent where: - 'newState' is the new recorder state */ + 'newState' is one of the following states: + 'Started' if the recording has begun capturing data + 'Stopped' when the recording has completed (success and failure) + 'Paused' if the recording is paused + 'Resumed' if the recording is resumed after pausing + 'PosterCreated' if a poster was requested and created + 'PosterFailed' if a poster was requested and failed to create + 'FileSizeLimitReached' if stopped due to file size limit + 'VideoLengthLimitReached' if stopped due to a time limit + 'TrackCompleted' if audio or video track complete when stopping + 'TrackFailed' if audio or video track incomplete when stopping + 'MediaRecorderFailed' if failed due to local error + 'MediaServerFailed' if failed due to media server attribute EventHandler onrecorderstatechange; /* the event dispatched when the viewfinder stops or starts, @@ -346,10 +358,21 @@ interface CameraControl : MediaStream DeviceStorage storageArea, DOMString filename); - /* stop precording video. */ + /* stop recording video. */ [Throws] void stopRecording(); + /* pause recording video. The camera remains active but audio and video + frames are no longer saved in the output file. If called when not + recording or already paused, it fails silently. */ + [Throws] + void pauseRecording(); + + /* resume recording video while paused. If called when not recording or + not paused, it fails silently. */ + [Throws] + void resumeRecording(); + /* call in or after the takePicture() onSuccess callback to resume the camera preview stream. */ [Throws] diff --git a/testing/docker/builder/Dockerfile b/testing/docker/builder/Dockerfile index 653a3c1ea29f..a808b942c6a7 100644 --- a/testing/docker/builder/Dockerfile +++ b/testing/docker/builder/Dockerfile @@ -21,7 +21,7 @@ RUN git config --global user.email "mozilla@example.com" && \ git config --global user.name "mozilla" # VCS Tools -RUN npm install -g taskcluster-vcs@2.3.6 +RUN npm install -g taskcluster-vcs@2.3.8 # TODO enable worker # TODO volume mount permissions will be an issue diff --git a/testing/docker/builder/VERSION b/testing/docker/builder/VERSION index b49b25336d47..d3532a107eeb 100644 --- a/testing/docker/builder/VERSION +++ b/testing/docker/builder/VERSION @@ -1 +1 @@ -0.5.6 +0.5.7 diff --git a/testing/docker/desktop-build/Dockerfile b/testing/docker/desktop-build/Dockerfile index ad3ad765fbc1..327878d74cd6 100644 --- a/testing/docker/desktop-build/Dockerfile +++ b/testing/docker/desktop-build/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/djmitche/ubuntu-build:0.0.4 +FROM taskcluster/ubuntu-build:0.0.5 MAINTAINER Morgan Reece Phillips # Add build scripts; these are the entry points from the taskcluster worker, and diff --git a/testing/docker/desktop-build/REGISTRY b/testing/docker/desktop-build/REGISTRY index 8d8449526f96..cb1e1bb482a2 100644 --- a/testing/docker/desktop-build/REGISTRY +++ b/testing/docker/desktop-build/REGISTRY @@ -1 +1 @@ -quay.io/djmitche +taskcluster diff --git a/testing/docker/desktop-build/VERSION b/testing/docker/desktop-build/VERSION index 818944f5b824..df5db66fed35 100644 --- a/testing/docker/desktop-build/VERSION +++ b/testing/docker/desktop-build/VERSION @@ -1 +1 @@ -0.0.22 +0.0.23 diff --git a/testing/docker/desktop32-build/Dockerfile b/testing/docker/desktop32-build/Dockerfile index de6762e3beb9..e4f6ef1bb736 100644 --- a/testing/docker/desktop32-build/Dockerfile +++ b/testing/docker/desktop32-build/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/djmitche/ubuntu32-build:0.0.4 +FROM taskcluster/ubuntu32-build:0.0.5 MAINTAINER Morgan Reece Phillips # Add build scripts; these are the entry points from the taskcluster worker, and diff --git a/testing/docker/desktop32-build/REGISTRY b/testing/docker/desktop32-build/REGISTRY index 8d8449526f96..cb1e1bb482a2 100644 --- a/testing/docker/desktop32-build/REGISTRY +++ b/testing/docker/desktop32-build/REGISTRY @@ -1 +1 @@ -quay.io/djmitche +taskcluster diff --git a/testing/docker/desktop32-build/VERSION b/testing/docker/desktop32-build/VERSION index 4e379d2bfeab..bcab45af15a0 100644 --- a/testing/docker/desktop32-build/VERSION +++ b/testing/docker/desktop32-build/VERSION @@ -1 +1 @@ -0.0.2 +0.0.3 diff --git a/testing/docker/tester-device/Dockerfile b/testing/docker/tester-device/Dockerfile index 847b80783b17..cc153ee61e4b 100644 --- a/testing/docker/tester-device/Dockerfile +++ b/testing/docker/tester-device/Dockerfile @@ -31,7 +31,7 @@ RUN git config --global user.email "mozilla@example.com" && \ # Get node packages -RUN npm install -g taskcluster-vcs@2.3.1 +RUN npm install -g taskcluster-vcs@2.3.8 WORKDIR /home/worker diff --git a/testing/docker/tester-device/VERSION b/testing/docker/tester-device/VERSION index 81340c7e72d5..bbdeab6222cb 100644 --- a/testing/docker/tester-device/VERSION +++ b/testing/docker/tester-device/VERSION @@ -1 +1 @@ -0.0.4 +0.0.5 diff --git a/testing/docker/tester/Dockerfile b/testing/docker/tester/Dockerfile index 8aecdb8f677c..18a21db211fd 100644 --- a/testing/docker/tester/Dockerfile +++ b/testing/docker/tester/Dockerfile @@ -18,7 +18,7 @@ RUN chmod u+x /usr/local/bin/linux64-minidump_stackwalk RUN apt-get install -y python-pip && pip install virtualenv; RUN mkdir Documents; mkdir Pictures; mkdir Music; mkdir Videos; mkdir artifacts RUN npm install -g npm@^2.0.0 -RUN npm install -g taskcluster-vcs@2.3.4 +RUN npm install -g taskcluster-vcs@2.3.8 RUN npm install -g taskcluster-npm-cache@1.1.14 RUN rm -Rf .cache && mkdir -p .cache ENV PATH $PATH:/home/worker/bin diff --git a/testing/docker/tester/VERSION b/testing/docker/tester/VERSION index c2c0004f0e2a..449d7e73a966 100644 --- a/testing/docker/tester/VERSION +++ b/testing/docker/tester/VERSION @@ -1 +1 @@ -0.3.5 +0.3.6 diff --git a/testing/docker/ubuntu-build/Dockerfile b/testing/docker/ubuntu-build/Dockerfile index 50d56f2260d2..1e37ffc067f1 100644 --- a/testing/docker/ubuntu-build/Dockerfile +++ b/testing/docker/ubuntu-build/Dockerfile @@ -11,7 +11,7 @@ RUN bash /tmp/system-setup.sh # configure git and install tc-vcs RUN git config --global user.email "nobody@mozilla.com" && \ git config --global user.name "mozilla" -RUN npm install -g taskcluster-vcs@2.3.6 +RUN npm install -g taskcluster-vcs@2.3.8 # Ensure that build specific dependencies live in a single layer ADD build-setup.sh /tmp/build-setup.sh diff --git a/testing/docker/ubuntu-build/REGISTRY b/testing/docker/ubuntu-build/REGISTRY index 8d8449526f96..cb1e1bb482a2 100644 --- a/testing/docker/ubuntu-build/REGISTRY +++ b/testing/docker/ubuntu-build/REGISTRY @@ -1 +1 @@ -quay.io/djmitche +taskcluster diff --git a/testing/docker/ubuntu-build/VERSION b/testing/docker/ubuntu-build/VERSION index 81340c7e72d5..bbdeab6222cb 100644 --- a/testing/docker/ubuntu-build/VERSION +++ b/testing/docker/ubuntu-build/VERSION @@ -1 +1 @@ -0.0.4 +0.0.5 diff --git a/testing/docker/ubuntu32-build/Dockerfile b/testing/docker/ubuntu32-build/Dockerfile index d30243bf4e1f..6332157093b4 100644 --- a/testing/docker/ubuntu32-build/Dockerfile +++ b/testing/docker/ubuntu32-build/Dockerfile @@ -11,7 +11,7 @@ RUN bash /tmp/system-setup.sh # configure git and install tc-vcs RUN git config --global user.email "nobody@mozilla.com" && \ git config --global user.name "mozilla" -RUN npm install -g taskcluster-vcs@2.3.6 +RUN npm install -g taskcluster-vcs@2.3.8 # Ensure that build specific dependencies live in a single layer ADD build-setup.sh /tmp/build-setup.sh diff --git a/testing/docker/ubuntu32-build/REGISTRY b/testing/docker/ubuntu32-build/REGISTRY index 8d8449526f96..cb1e1bb482a2 100644 --- a/testing/docker/ubuntu32-build/REGISTRY +++ b/testing/docker/ubuntu32-build/REGISTRY @@ -1 +1 @@ -quay.io/djmitche +taskcluster diff --git a/testing/docker/ubuntu32-build/VERSION b/testing/docker/ubuntu32-build/VERSION index 81340c7e72d5..bbdeab6222cb 100644 --- a/testing/docker/ubuntu32-build/VERSION +++ b/testing/docker/ubuntu32-build/VERSION @@ -1 +1 @@ -0.0.4 +0.0.5