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