void
nsDOMCameraControl::StartRecording(JSContext* aCx,
                                   JS::Handle<JS::Value> aOptions,
                                   nsDOMDeviceStorage& storageArea,
                                   const nsAString& filename,
                                   nsICameraStartRecordingCallback* onSuccess,
                                   const Optional<nsICameraErrorCallback*>& onError,
                                   ErrorResult& aRv)
{
  MOZ_ASSERT(onSuccess, "no onSuccess handler passed");
  mozilla::idl::CameraStartRecordingOptions options;

  // Default values, until the dictionary parser can handle them.
  options.rotation = 0;
  options.maxFileSizeBytes = 0;
  options.maxVideoLengthMs = 0;
  aRv = options.Init(aCx, aOptions.address());
  if (aRv.Failed()) {
    return;
  }

  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  if (!obs) {
    NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }

  obs->NotifyObservers(nullptr,
                       "recording-device-events",
                       NS_LITERAL_STRING("starting").get());
  // Forward recording events to parent process.
  // The events are gathered in chrome process and used for recording indicator
  if (XRE_GetProcessType() != GeckoProcessType_Default) {
    unused << ContentChild::GetSingleton()->SendRecordingDeviceEvents(NS_LITERAL_STRING("starting"));
  }

  #ifdef MOZ_B2G
  if (!mAudioChannelAgent) {
    mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
    if (mAudioChannelAgent) {
      // Camera app will stop recording when it falls to the background, so no callback is necessary.
      mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, nullptr);
      // Video recording doesn't output any sound, so it's not necessary to check canPlay.
      bool canPlay;
      mAudioChannelAgent->StartPlaying(&canPlay);
    }
  }
  #endif

  nsCOMPtr<nsIFile> folder;
  aRv = storageArea.GetRootDirectoryForFile(filename, getter_AddRefs(folder));
  if (aRv.Failed()) {
    return;
  }
  aRv = mCameraControl->StartRecording(&options, folder, filename, onSuccess,
                                       onError.WasPassed() ? onError.Value() : nullptr);
}
void
nsDOMCameraControl::SetThumbnailSize(JSContext* cx, JS::Handle<JS::Value> aSize, ErrorResult& aRv)
{
  CameraSize size;
  aRv = size.Init(cx, aSize.address());
  if (aRv.Failed()) {
    return;
  }

  aRv = mCameraControl->Set(CAMERA_PARAM_THUMBNAILSIZE, size);
}
void
nsDOMCameraControl::GetPreviewStreamVideoMode(JSContext* aCx,
                                              JS::Handle<JS::Value> aOptions,
                                              nsICameraPreviewStreamCallback* onSuccess,
                                              const Optional<nsICameraErrorCallback*>& onError,
                                              ErrorResult& aRv)
{
  mozilla::idl::CameraRecorderOptions options;
  aRv = options.Init(aCx, aOptions.address());
  if (aRv.Failed()) {
    return;
  }

  aRv = mCameraControl->GetPreviewStreamVideoMode(&options, onSuccess,
                                                  onError.WasPassed()
                                                  ? onError.Value() : nullptr);
}
void
nsDOMCameraControl::StartRecording(JSContext* aCx,
                                   JS::Handle<JS::Value> aOptions,
                                   nsDOMDeviceStorage& storageArea,
                                   const nsAString& filename,
                                   nsICameraStartRecordingCallback* onSuccess,
                                   const Optional<nsICameraErrorCallback*>& onError,
                                   ErrorResult& aRv)
{
  MOZ_ASSERT(onSuccess, "no onSuccess handler passed");
  mozilla::idl::CameraStartRecordingOptions options;

  // Default values, until the dictionary parser can handle them.
  options.rotation = 0;
  options.maxFileSizeBytes = 0;
  options.maxVideoLengthMs = 0;
  aRv = options.Init(aCx, aOptions.address());
  if (aRv.Failed()) {
    return;
  }

  aRv = NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));

  #ifdef MOZ_B2G
  if (!mAudioChannelAgent) {
    mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
    if (mAudioChannelAgent) {
      // Camera app will stop recording when it falls to the background, so no callback is necessary.
      mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, nullptr);
      // Video recording doesn't output any sound, so it's not necessary to check canPlay.
      int32_t canPlay;
      mAudioChannelAgent->StartPlaying(&canPlay);
    }
  }
  #endif

  nsCOMPtr<nsIFile> folder;
  aRv = storageArea.GetRootDirectoryForFile(filename, getter_AddRefs(folder));
  if (aRv.Failed()) {
    return;
  }
  aRv = mCameraControl->StartRecording(&options, folder, filename, onSuccess,
                                       onError.WasPassed() ? onError.Value() : nullptr);
}