private void MoveToNextShot()
        {
            // (2) Move to the next shot
            string message;

            if (!ValidateShot(out message))
            {
                this.ClearFrames();

                var ea2 = new Smithers.Sessions.SessionManagerEventArgs <TShot, TShotDefinition, TSavedItem>(_capturingShot, message);

                _capturingShot = null;

                if (ShotCompletedError != null)
                {
                    ShotCompletedError(this, ea2);
                }

                return;
            }

            var outEvent = new Smithers.Sessions.SessionManagerEventArgs <TShot, TShotDefinition, TSavedItem>(_capturingShot, message);

            _writingShot   = _capturingShot;
            _capturingShot = null;

            if (ShotCompletedSuccess != null)
            {
                ShotCompletedSuccess(this, outEvent);
            }

            FinishShot();
        }
        private async void FinishShot()
        {
            try
            {
                await Task.Run(() => SaveFrameData());
            }
            catch (Exception e)
            {
                this.ClearFrames();

                var ea = new Smithers.Sessions.SessionManagerEventArgs <TShot, TShotDefinition, TSavedItem>(_writingShot, "An error occurred while saving", e);

                _writingShot = null;

                if (ShotSavedError != null)
                {
                    ShotSavedError(this, ea);
                }

                return;
            }

            _writingShot.Completed = true;

            string metadataPath = Path.Combine(_session.SessionPath, DS4Session.METADATA_FILE);

            //Write device config
#if !DSAPI
            _reader.Device.WriteDeviceConfig <TMetadata>(_session.Metadata as TMetadata, _mode);
#else
            _reader.DSAPI.WriteDeviceConfig <TMetadata>(_session.Metadata, _mode);
#endif

            await Task.Run(() => Smithers.Sessions.JSONHelper.Instance.Serialize(_session.Metadata, metadataPath));


            //// Perform calibration if we haven't already
            if (!_wroteCalibrationRecord)
            {
                DS4CalibrationRecord record = await _calibration;

                string calibrationPath = Path.Combine(_session.SessionPath, CALIBRATION_FILE);
                JSONHelper.Instance.Serialize(record, calibrationPath);

                //copy calibration and metadata to record folder

                _wroteCalibrationRecord = true;
            }

            // Clear the frames to make sure we don't use them again
            this.ClearFrames();

            var ea2 = new Smithers.Sessions.SessionManagerEventArgs <TShot, TShotDefinition, TSavedItem>(_writingShot);

            _writingShot = null;

            if (ShotSavedSuccess != null)
            {
                ShotSavedSuccess(this, ea2);
            }

            if (_mode == CaptureMode.Stream || (_mode == CaptureMode.Sweeping))
            {
                ShotDefinition videoShot = new DS4VideoShotDefintion();

                _session.AddShot((TShotDefinition)videoShot);
            }

            PrepareForNextShot();

            if (_nextShot == null)
            {
                if (LastShotFinished != null)
                {
                    LastShotFinished(this, ea2);
                }
            }

            if (_mode == CaptureMode.Stream || _mode == CaptureMode.Sweeping)
            {
                //keep going
                _capturingShot = _nextShot;
            }
        }
        public virtual void FrameArrived(object sender, FrameArrivedEventArgs ea)
        {
            // When the first frame arrive, start the calibration operation. This won't work
            // if we try to do it right after calling _sensor.Open().
            if (_calibration == null)
            {
                _calibration = Calibrator.CalibrateAsync(_reader);
                // set device config once
                //_reader.Device.SetDeviceConfig();
            }

            if (_capturingShot == null)
            {
                return;
            }

            if (_mode == CaptureMode.Sweeping && !_sweeping)
            {
                return;
            }

            if (!_cameraConfigLocked)
            {
                LockCameraExposureAndGain();
                _cameraConfigLocked = true;
            }

            if (!_lastShotTaken.HasValue)
            {
                _lastShotTaken = DateTime.Now;
            }

            DateTime currentFrame = DateTime.Now;

            double durationFromLastShot = (currentFrame - _lastShotTaken.Value).TotalMilliseconds;


            if (durationFromLastShot != 0 && durationFromLastShot < _capturingShot.ShotDefinition.ShotDuration)
            {
                return;
            }
            // (1) Serialize frame data

            if (_frameCount >= _session.MaximumFrameCount)
            {
                Console.WriteLine(string.Format("Too many frames! Got {0} but we only have room for {1}", _frameCount + 1, _session.MaximumFrameCount));
            }

            _frameHandles.Add(ea.FrameHandle.Clone());

            // Increment whether we saved the data or not (this allows an improved error message)
            _frameCount += 1;

            if (FrameCaptured != null)
            {
                var outEvent = new Smithers.Sessions.SessionManagerEventArgs <TShot, TShotDefinition, TSavedItem>(_capturingShot, null, null);
                FrameCaptured(this, outEvent);
            }


            if (_mode == CaptureMode.Sweeping)
            {
                if (_capturingShot != null && _frameCount < _capturingShot.ShotDefinition.MaximumFrameCount)
                {
                    _lastShotTaken = DateTime.Now;
                    return;
                }
            }
            else if ((_mode != CaptureMode.Sweeping) && _frameCount < _capturingShot.ShotDefinition.MaximumFrameCount)
            {
                return;
            }

            if (_capturingShot != null)
            {
                MoveToNextShot();
            }
        }