[Tizen.Multimedia] Fix XML Doc warnings
[platform/core/csapi/tizenfx.git] / src / Tizen.Multimedia.Camera / Camera / Camera.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Diagnostics;
20 using System.Linq;
21 using System.Runtime.InteropServices;
22 using System.Threading;
23 using static Interop;
24 using Native = Interop.Camera;
25
26 namespace Tizen.Multimedia
27 {
28     static internal class CameraLog
29     {
30         internal const string Tag = "Tizen.Multimedia.Camera";
31         internal const string Enter = "[Enter]";
32         internal const string Leave = "[Leave]";
33     }
34
35     /// <summary>
36     /// This camera class provides methods to capture photos and supports setting up notifications
37     /// for state changes of capturing, previewing, focusing, and informing about the resolution and the binary format,
38     /// and functions for picture manipulations like sepia, negative, and many more.
39     /// It also notifies you when a significant picture parameter changes, (For example, focus).
40     /// </summary>
41     public class Camera : IDisposable, IDisplayable<CameraError>
42     {
43         private IntPtr _handle = IntPtr.Zero;
44         private bool _disposed = false;
45         private CameraState _state = CameraState.None;
46
47         /// <summary>
48         /// Initializes a new instance of the <see cref="Camera"/> class.
49         /// </summary>
50         /// <since_tizen> 3 </since_tizen>
51         /// <param name="device">The camera device to access.</param>
52         public Camera(CameraDevice device)
53         {
54             CameraErrorFactory.ThrowIfError(Native.Create(device, out _handle),
55                 "Failed to create camera instance");
56
57             Capabilities = new CameraCapabilities(this);
58             Settings = new CameraSettings(this);
59             DisplaySettings = new CameraDisplaySettings(this);
60
61             RegisterCallbacks();
62
63             SetState(CameraState.Created);
64         }
65
66         /// <summary>
67         /// Finalizes an instance of the Camera class.
68         /// </summary>
69         ~Camera()
70         {
71             Dispose(false);
72         }
73
74         /// <summary>
75         /// Gets the native handle of the camera.
76         /// </summary>
77         public IntPtr Handle => GetHandle();
78
79         internal IntPtr GetHandle()
80         {
81             ValidateNotDisposed();
82             return _handle;
83         }
84
85         #region Dispose support
86         /// <summary>
87         /// Releases the unmanaged resources used by the camera.
88         /// </summary>
89         /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
90         protected virtual void Dispose(bool disposing)
91         {
92             if (!_disposed)
93             {
94                 if (disposing)
95                 {
96                     // to be used if there are any other disposable objects
97                 }
98
99                 if (_handle != IntPtr.Zero)
100                 {
101                     Native.Destroy(_handle);
102                     _handle = IntPtr.Zero;
103                 }
104
105                 _disposed = true;
106             }
107         }
108
109         /// <summary>
110         /// Releases all resources used by the camera.
111         /// </summary>
112         /// <since_tizen> 3 </since_tizen>
113         public void Dispose()
114         {
115             ReplaceDisplay(null);
116             Dispose(true);
117             GC.SuppressFinalize(this);
118         }
119
120         internal void ValidateNotDisposed()
121         {
122             if (_disposed)
123             {
124                 Log.Error(CameraLog.Tag, "Camera handle is disposed.");
125                 throw new ObjectDisposedException(nameof(Camera));
126             }
127         }
128         #endregion Dispose support
129
130         #region Check camera state
131         internal void ValidateState(params CameraState[] required)
132         {
133             ValidateNotDisposed();
134
135             Debug.Assert(required.Length > 0);
136
137             var curState = _state;
138             if (!required.Contains(curState))
139             {
140                 throw new InvalidOperationException($"The camera is not in a valid state. " +
141                     $"Current State : { curState }, Valid State : { string.Join(", ", required) }.");
142             }
143         }
144
145         internal void SetState(CameraState state)
146         {
147             _state = state;
148         }
149         #endregion Check camera state
150
151         #region EventHandlers
152         /// <summary>
153         /// An event that occurs when the camera interrupt is started by the policy.
154         /// </summary>
155         public event EventHandler<CameraInterruptStartedEventArgs> InterruptStarted;
156         private Native.InterruptStartedCallback _interruptStartedCallback;
157
158         /// <summary>
159         /// An event that occurs when an camera is interrupted by the policy.
160         /// </summary>
161         /// <since_tizen> 3 </since_tizen>
162         public event EventHandler<CameraInterruptedEventArgs> Interrupted;
163         private Native.InterruptedCallback _interruptedCallback;
164
165         /// <summary>
166         /// An event that occurs when there is an asynchronous error.
167         /// </summary>
168         /// <since_tizen> 3 </since_tizen>
169         public event EventHandler<CameraErrorOccurredEventArgs> ErrorOccurred;
170         private Native.ErrorCallback _errorCallback;
171
172         /// <summary>
173         /// An event that occurs when the auto focus state is changed.
174         /// </summary>
175         /// <since_tizen> 3 </since_tizen>
176         public event EventHandler<CameraFocusStateChangedEventArgs> FocusStateChanged;
177         private Native.FocusStateChangedCallback _focusStateChangedCallback;
178
179         /// <summary>
180         /// An event that occurs when a face is detected in the preview frame.
181         /// </summary>
182         /// <since_tizen> 3 </since_tizen>
183         public event EventHandler<FaceDetectedEventArgs> FaceDetected;
184         private Native.FaceDetectedCallback _faceDetectedCallback;
185
186         /// <summary>
187         /// An event that occurs during capture of an image.
188         /// </summary>
189         /// <since_tizen> 3 </since_tizen>
190         public event EventHandler<CameraCapturingEventArgs> Capturing;
191         private Native.CapturingCallback _capturingCallback;
192
193         /// <summary>
194         /// An event that occurs after the capture of the image.
195         /// </summary>
196         /// <since_tizen> 3 </since_tizen>
197         public event EventHandler<EventArgs> CaptureCompleted;
198         private Native.CaptureCompletedCallback _captureCompletedCallback;
199
200         private Native.HdrCaptureProgressCallback _hdrCaptureProgressCallback;
201         private event EventHandler<HdrCaptureProgressEventArgs> _hdrCaptureProgress;
202         private object _hdrCaptureProgressEventLock = new object();
203
204         /// <summary>
205         /// An event that occurs when there is a change in the HDR capture progress.
206         /// Checks whether the <see cref="CameraCapabilities.IsHdrCaptureSupported"/> is supported or not before adding this EventHandler.
207         /// </summary>
208         /// <since_tizen> 3 </since_tizen>
209         /// <exception cref="NotSupportedException">In case of HDR feature is not supported.</exception>
210         public event EventHandler<HdrCaptureProgressEventArgs> HdrCaptureProgress
211         {
212             add
213             {
214                 lock (_hdrCaptureProgressEventLock)
215                 {
216                     if (_hdrCaptureProgress == null)
217                     {
218                         RegisterHdrCaptureProgress();
219                     }
220
221                     _hdrCaptureProgress += value;
222                 }
223             }
224
225             remove
226             {
227                 lock (_hdrCaptureProgressEventLock)
228                 {
229                     _hdrCaptureProgress -= value;
230
231                     if (_hdrCaptureProgress == null)
232                     {
233                         UnregisterHdrCaptureProgress();
234                     }
235                 }
236             }
237         }
238
239         /// <summary>
240         /// An event that occurs when the camera state is changed.
241         /// </summary>
242         /// <since_tizen> 3 </since_tizen>
243         public event EventHandler<CameraStateChangedEventArgs> StateChanged;
244         private Native.StateChangedCallback _stateChangedCallback;
245
246         private static Native.DeviceStateChangedCallback _deviceStateChangedCallback;
247         private static event EventHandler<CameraDeviceStateChangedEventArgs> _deviceStateChanged;
248         private static object _deviceStateChangedEventLock = new object();
249         private static int _deviceStateCallbackId;
250
251         /// <summary>
252         /// An event that occurs after the <see cref="CameraDeviceState"/> is changed.
253         /// </summary>
254         /// <since_tizen> 3 </since_tizen>
255         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
256         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
257         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
258         public static event EventHandler<CameraDeviceStateChangedEventArgs> DeviceStateChanged
259         {
260             add
261             {
262                 lock (_deviceStateChangedEventLock)
263                 {
264                     if (_deviceStateChanged == null)
265                     {
266                         RegisterDeviceStateChangedCallback();
267                     }
268
269                     _deviceStateChanged += value;
270                 }
271             }
272
273             remove
274             {
275                 lock (_deviceStateChangedEventLock)
276                 {
277                     _deviceStateChanged -= value;
278
279                     if (_deviceStateChanged == null)
280                     {
281                         UnregisterDeviceStateChangedCallback();
282                     }
283                 }
284             }
285         }
286
287         private Native.PreviewCallback _previewCallback;
288         private event EventHandler<PreviewEventArgs> _preview;
289         private object _previewEventLock = new object();
290         /// <summary>
291         /// An event that occurs once per frame when previewing.
292         /// Preview callback is registered when an user adds a callback explicitly to avoid useless P/Invoke.
293         /// </summary>
294         /// <since_tizen> 3 </since_tizen>
295         public event EventHandler<PreviewEventArgs> Preview
296         {
297             add
298             {
299                 lock (_previewEventLock)
300                 {
301                     if (_preview == null)
302                     {
303                         RegisterPreviewCallback();
304                     }
305
306                     _preview += value;
307                 }
308             }
309
310             remove
311             {
312                 lock (_previewEventLock)
313                 {
314                     _preview -= value;
315
316                     if (_preview == null)
317                     {
318                         UnregisterPreviewCallback();
319                     }
320                 }
321             }
322         }
323
324         private Native.MediaPacketPreviewCallback _mediaPacketPreviewCallback;
325         private EventHandler<MediaPacketPreviewEventArgs> _mediaPacketPreview;
326         private object _mediaPacketPreviewEventLock = new object();
327
328         /// <summary>
329         /// An event that occurs once per frame when previewing.
330         /// Preview callback is registered when an user adds a callback explicitly to avoid useless P/Invoke.
331         /// </summary>
332         /// <since_tizen> 3 </since_tizen>
333         public event EventHandler<MediaPacketPreviewEventArgs> MediaPacketPreview
334         {
335             add
336             {
337                 lock (_mediaPacketPreviewEventLock)
338                 {
339                     if (_mediaPacketPreview == null)
340                     {
341                         RegisterMediaPacketPreviewCallback();
342                     }
343
344                     _mediaPacketPreview += value;
345                 }
346             }
347
348             remove
349             {
350                 lock (_mediaPacketPreviewEventLock)
351                 {
352                     _mediaPacketPreview -= value;
353
354                     if (_mediaPacketPreview == null)
355                     {
356                         UnregisterMediaPacketPreviewCallback();
357                     }
358                 }
359             }
360         }
361         #endregion EventHandlers
362
363         #region Properties
364         /// <summary>
365         /// Gets or sets the various camera settings.
366         /// </summary>
367         /// <since_tizen> 3 </since_tizen>
368         public CameraSettings Settings { get; }
369
370         /// <summary>
371         /// Gets the various camera capabilities.
372         /// </summary>
373         /// <since_tizen> 3 </since_tizen>
374         public CameraCapabilities Capabilities { get; }
375
376         /// <summary>
377         /// Get/set various camera display properties.
378         /// </summary>
379         /// <since_tizen> 3 </since_tizen>
380         public CameraDisplaySettings DisplaySettings { get; }
381
382         private Display _display;
383
384         private CameraError SetDisplay(Display display)
385         {
386             if (display == null)
387             {
388                 return CameraDisplay.SetTarget(GetHandle(), DisplayType.None, IntPtr.Zero);
389             }
390
391             return display.ApplyTo(this);
392         }
393
394         private void ReplaceDisplay(Display newDisplay)
395         {
396             _display?.SetOwner(null);
397             _display = newDisplay;
398             _display?.SetOwner(this);
399         }
400
401         /// <summary>
402         /// Sets or gets the display type and handle to show preview images.
403         /// The camera must be in the <see cref="CameraState.Created"/> state.
404         /// </summary>
405         /// <since_tizen> 3 </since_tizen>
406         /// <remarks>
407         /// This must be set before the StartPreview() method.
408         /// In custom ROI display mode, DisplayRoiArea property must be set before calling this method.
409         /// </remarks>
410         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
411         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
412         /// <exception cref="ObjectDisposedException" > The camera already has been disposed of.</exception>
413         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
414         public Display Display
415         {
416             get
417             {
418                 return _display;
419             }
420
421             set
422             {
423                 ValidateState(CameraState.Created);
424
425                 if (value?.Owner != null)
426                 {
427                     if (ReferenceEquals(this, value.Owner))
428                     {
429                         return;
430                     }
431
432                     throw new ArgumentException("The display has already been assigned to another.");
433                 }
434
435                 CameraErrorFactory.ThrowIfError(SetDisplay(value), "Failed to set the camera display");
436
437                 ReplaceDisplay(value);
438             }
439         }
440
441         CameraError IDisplayable<CameraError>.ApplyEvasDisplay(DisplayType type, ElmSharp.EvasObject evasObject)
442         {
443             Debug.Assert(_disposed == false);
444             ValidationUtil.ValidateEnum(typeof(DisplayType), type, nameof(type));
445
446             return CameraDisplay.SetTarget(GetHandle(), type, evasObject);
447         }
448
449         CameraError IDisplayable<CameraError>.ApplyEcoreWindow(IntPtr windowHandle)
450         {
451             throw new NotSupportedException("Camera does not support NUI.Window display.");
452         }
453
454         /// <summary>
455         /// Gets the state of the camera.
456         /// </summary>
457         /// <since_tizen> 3 </since_tizen>
458         /// <value> None, Created, Preview, Capturing, Captured.</value>
459         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
460         public CameraState State
461         {
462             get
463             {
464                 ValidateNotDisposed();
465
466                 CameraState val = CameraState.None;
467                 CameraErrorFactory.ThrowIfError(Native.GetState(_handle, out val),
468                     "Failed to get camera state");
469
470                 return val;
471             }
472         }
473
474         /// <summary>
475         /// The hint for the display reuse.
476         /// If the hint is set to true, the display will be reused when the camera device is changed with
477         /// the ChangeDevice method.
478         /// </summary>
479         /// <since_tizen> 3 </since_tizen>
480         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
481         /// <exception cref="InvalidOperationException">An invalid state.</exception>
482         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
483         public bool DisplayReuseHint
484         {
485             get
486             {
487                 ValidateNotDisposed();
488
489                 CameraErrorFactory.ThrowIfError(Native.GetDisplayReuseHint(_handle, out bool val),
490                     "Failed to get camera display reuse hint");
491
492                 return val;
493             }
494
495             set
496             {
497                 ValidateState(CameraState.Preview);
498
499                 CameraErrorFactory.ThrowIfError(Native.SetDisplayReuseHint(_handle, value),
500                     "Failed to set display reuse hint.");
501             }
502         }
503
504         /// <summary>
505         /// Gets the facing direction of the camera module.
506         /// </summary>
507         /// <since_tizen> 3 </since_tizen>
508         /// <value>A <see cref="CameraFacingDirection"/> that specifies the facing direction of the camera device.</value>
509         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
510         public CameraFacingDirection Direction
511         {
512             get
513             {
514                 ValidateNotDisposed();
515
516                 CameraErrorFactory.ThrowIfError(Native.GetFacingDirection(_handle, out var val),
517                     "Failed to get camera direction");
518
519                 return val;
520             }
521         }
522
523         /// <summary>
524         /// Gets the camera device count.
525         /// </summary>
526         /// <since_tizen> 3 </since_tizen>
527         /// <value>This returns 2, if the device supports primary and secondary cameras.
528         /// Otherwise 1, if the device only supports primary camera.</value>
529         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
530         public int CameraCount
531         {
532             get
533             {
534                 ValidateNotDisposed();
535
536                 CameraErrorFactory.ThrowIfError(Native.GetDeviceCount(_handle, out int val),
537                     "Failed to get camera device count");
538
539                 return val;
540             }
541         }
542         #endregion Properties
543
544         #region Methods
545         /// <summary>
546         /// Changes the camera device.
547         /// </summary>
548         /// <since_tizen> 3 </since_tizen>
549         /// <param name="device">The hardware camera to access.</param>
550         /// <remarks>
551         /// If display reuse is set using <see cref="DisplayReuseHint"/>
552         /// before stopping the preview, the display will be reused and last frame on the display
553         /// can be kept even though camera device is changed.
554         /// The camera must be in the <see cref="CameraState.Created"/>.
555         /// </remarks>
556         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
557         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
558         /// <exception cref="NotSupportedException">In case of the ChangeDevice feature is not supported.</exception>
559         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
560         public void ChangeDevice(CameraDevice device)
561         {
562             ValidateState(CameraState.Created);
563             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
564
565             CameraErrorFactory.ThrowIfError(Native.ChangeDevice(_handle, device),
566                 "Failed to change the camera device");
567         }
568
569         /// <summary>
570         /// Gets the device state.
571         /// </summary>
572         /// <since_tizen> 3 </since_tizen>
573         /// <param name="device">The device to get the state.</param>
574         /// <returns>Returns the state of the camera device.</returns>
575         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
576         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
577         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
578         public static CameraDeviceState GetDeviceState(CameraDevice device)
579         {
580             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
581
582             CameraErrorFactory.ThrowIfError(Native.GetDeviceState(device, out var val),
583                 "Failed to get the camera device state.");
584
585             return val;
586         }
587
588         /// <summary>
589         /// Gets the flash state.
590         /// </summary>
591         /// <since_tizen> 3 </since_tizen>
592         /// <param name="device">The device to get the state.</param>
593         /// <returns>Returns the flash state of the camera device.</returns>
594         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
595         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
596         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
597         public static CameraFlashState GetFlashState(CameraDevice device)
598         {
599             ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));
600
601             CameraErrorFactory.ThrowIfError(Native.GetFlashState(device, out var val),
602                 "Failed to get camera flash state");
603
604             return val;
605         }
606
607         /// <summary>
608         /// Starts capturing and drawing preview frames on the screen.
609         /// The display property must be set using <see cref="Display"/> before using this method.
610         /// If needed set fps <see cref="CameraSettings.PreviewFps"/>, preview resolution
611         /// <see cref="CameraSettings.PreviewResolution"/>, or preview format <see cref="CameraSettings.PreviewPixelFormat"/>
612         /// before using this method.
613         /// The camera must be in the <see cref="CameraState.Created"/> or the <see cref="CameraState.Captured"/> state.
614         /// </summary>
615         /// <since_tizen> 3 </since_tizen>
616         /// <privilege>
617         /// http://tizen.org/privilege/camera
618         /// </privilege>
619         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
620         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
621         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
622         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
623         public void StartPreview()
624         {
625             ValidateState(CameraState.Created, CameraState.Captured);
626
627             CameraErrorFactory.ThrowIfError(Native.StartPreview(_handle),
628                 "Failed to start the camera preview.");
629
630             // Update by StateChangedCallback can be delayed for dozens of milliseconds.
631             SetState(CameraState.Preview);
632         }
633
634         /// <summary>
635         /// Stops capturing and drawing preview frames on the screen.
636         /// The camera must be in the <see cref="CameraState.Preview"/> state.
637         /// </summary>
638         /// <since_tizen> 3 </since_tizen>
639         /// <privilege>
640         /// http://tizen.org/privilege/camera
641         /// </privilege>
642         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
643         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
644         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
645         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
646         public void StopPreview()
647         {
648             ValidateState(CameraState.Preview);
649
650             CameraErrorFactory.ThrowIfError(Native.StopPreview(_handle),
651                 "Failed to stop the camera preview.");
652
653             SetState(CameraState.Created);
654         }
655
656         /// <summary>
657         /// Starts capturing of still images.
658         /// EventHandler must be set for capturing using <see cref="Capturing"/>
659         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
660         /// The camera must be in the <see cref="CameraState.Preview"/> state.
661         /// </summary>
662         /// <since_tizen> 3 </since_tizen>
663         /// <privilege>
664         /// http://tizen.org/privilege/camera
665         /// </privilege>
666         /// <remarks>
667         /// This function causes the transition of the camera state from capturing to captured
668         /// automatically and the corresponding EventHandlers will be invoked.
669         /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
670         /// </remarks>
671         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
672         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
673         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
674         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
675         public void StartCapture()
676         {
677             ValidateState(CameraState.Preview);
678
679             CameraErrorFactory.ThrowIfError(Native.StartCapture(_handle, _capturingCallback, _captureCompletedCallback, IntPtr.Zero),
680                 "Failed to start the camera capture.");
681
682             SetState(CameraState.Capturing);
683         }
684
685         /// <summary>
686         /// Starts continuously capturing still images.
687         /// EventHandler must be set for capturing using <see cref="Capturing"/>
688         /// and for completed using <see cref="CaptureCompleted"/> before calling this method.
689         /// The camera must be in the <see cref="CameraState.Preview"/> state.
690         /// </summary>
691         /// <since_tizen> 3 </since_tizen>
692         /// <privilege>
693         /// http://tizen.org/privilege/camera
694         /// </privilege>
695         /// <param name="count">The number of still images.</param>
696         /// <param name="interval">The interval of the capture(milliseconds).</param>
697         /// <param name="cancellationToken">The cancellation token to cancel capturing.</param>
698         /// <seealso cref="CancellationToken"/>
699         /// <remarks>
700         /// If this is not supported, zero shutter lag occurs. The capture resolution could be
701         /// changed to the preview resolution. This function causes the transition of the camera state
702         /// from capturing to captured automatically and the corresponding Eventhandlers will be invoked.
703         /// Each captured image will be delivered through Eventhandler set using the <see cref="Capturing"/> event.
704         /// The preview should be restarted by calling the <see cref="StartPreview"/> method after capture is completed.
705         /// </remarks>
706         /// <exception cref="ArgumentOutOfRangeException">In case of invalid parameters.</exception>
707         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
708         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
709         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
710         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
711         public void StartCapture(int count, int interval, CancellationToken cancellationToken)
712         {
713             ValidateState(CameraState.Preview);
714
715             if (count < 2)
716             {
717                 throw new ArgumentOutOfRangeException(nameof(count), count, $"{nameof(count)} should be greater than one.");
718             }
719
720             if (interval < 0)
721             {
722                 throw new ArgumentOutOfRangeException(nameof(interval), interval, $"{nameof(interval)} should be greater than or equal to zero.");
723             }
724
725             //Handle CancellationToken
726             if (cancellationToken != CancellationToken.None)
727             {
728                 cancellationToken.Register(() =>
729                 {
730                     CameraErrorFactory.ThrowIfError(Native.StopContinuousCapture(_handle),
731                         "Failed to cancel the continuous capture");
732                     SetState(CameraState.Captured);
733                 });
734             }
735
736             CameraErrorFactory.ThrowIfError(Native.StartContinuousCapture(_handle, count, interval,
737                 _capturingCallback, _captureCompletedCallback, IntPtr.Zero), "Failed to start the continuous capture.");
738
739             SetState(CameraState.Capturing);
740         }
741
742         /// <summary>
743         /// Starts camera auto-focusing, asynchronously.
744         /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
745         /// </summary>
746         /// <since_tizen> 3 </since_tizen>
747         /// <param name="continuous">Continuous auto focus.</param>
748         /// <privilege>
749         /// http://tizen.org/privilege/camera
750         /// </privilege>
751         /// <remarks>
752         /// If continuous status is true, the camera continuously tries to focus.
753         /// </remarks>
754         /// <exception cref="ArgumentException">In case of invalid parameters.</exception>
755         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
756         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
757         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
758         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
759         public void StartFocusing(bool continuous)
760         {
761             ValidateState(CameraState.Preview, CameraState.Captured);
762
763             CameraErrorFactory.ThrowIfError(Native.StartFocusing(_handle, continuous),
764                 "Failed to cancel the camera focus.");
765         }
766
767         /// <summary>
768         /// Stops camera auto focusing.
769         /// The camera must be in the <see cref="CameraState.Preview"/> or the <see cref="CameraState.Captured"/> state.
770         /// </summary>
771         /// <since_tizen> 3 </since_tizen>
772         /// <privilege>
773         /// http://tizen.org/privilege/camera
774         /// </privilege>
775         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
776         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
777         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
778         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
779         public void StopFocusing()
780         {
781             ValidateState(CameraState.Preview, CameraState.Captured);
782
783             CameraErrorFactory.ThrowIfError(Native.CancelFocusing(_handle),
784                 "Failed to cancel the camera focus.");
785         }
786
787         /// <summary>
788         /// Starts face detection.
789         /// The camera must be in the <see cref="CameraState.Preview"/> state.
790         /// </summary>
791         /// <since_tizen> 3 </since_tizen>
792         /// <privilege>
793         /// http://tizen.org/privilege/camera
794         /// </privilege>
795         /// <remarks>
796         /// This should be called after <see cref="StartPreview"/> is started.
797         /// The Eventhandler set using <see cref="FaceDetected"/> is invoked when the face is detected in the preview frame.
798         /// Internally, it starts continuously focus and focusing on the detected face.
799         /// </remarks>
800         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
801         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
802         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
803         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
804         public void StartFaceDetection()
805         {
806             ValidateState(CameraState.Preview);
807
808             _faceDetectedCallback = (IntPtr faces, int count, IntPtr userData) =>
809             {
810                 var result = new List<FaceDetectionData>();
811                 IntPtr current = faces;
812
813                 for (int i = 0; i < count; i++)
814                 {
815                     result.Add(new FaceDetectionData(current));
816                     current = IntPtr.Add(current, Marshal.SizeOf<Native.DetectedFaceStruct>());
817                 }
818
819                 FaceDetected?.Invoke(this, new FaceDetectedEventArgs(result));
820             };
821             CameraErrorFactory.ThrowIfError(Native.StartFaceDetection(_handle, _faceDetectedCallback, IntPtr.Zero),
822                 "Failed to start face detection");
823         }
824
825         /// <summary>
826         /// Stops face detection.
827         /// </summary>
828         /// <since_tizen> 3 </since_tizen>
829         /// <privilege>
830         /// http://tizen.org/privilege/camera
831         /// </privilege>
832         /// <exception cref="InvalidOperationException">In case of any invalid operations.</exception>
833         /// <exception cref="NotSupportedException">In case of this feature is not supported.</exception>
834         /// <exception cref="ObjectDisposedException">The camera already has been disposed of.</exception>
835         /// <exception cref="UnauthorizedAccessException">In case of access to the resources cannot be granted.</exception>
836         public void StopFaceDetection()
837         {
838             if (_faceDetectedCallback == null)
839             {
840                 throw new InvalidOperationException("The face detection is not started.");
841             }
842
843             CameraErrorFactory.ThrowIfError(Native.StopFaceDetection(_handle),
844                 "Failed to stop the face detection.");
845
846             _faceDetectedCallback = null;
847         }
848         #endregion Methods
849
850         #region Callback registrations
851         private void RegisterCallbacks()
852         {
853             RegisterErrorCallback();
854             RegisterFocusStateChanged();
855             RegisterInterruptStartedCallback();
856             RegisterInterruptedCallback();
857             RegisterStateChangedCallback();
858
859             //Define capturing callback
860             _capturingCallback = (IntPtr main, IntPtr postview, IntPtr thumbnail, IntPtr userData) =>
861             {
862                 Capturing?.Invoke(this, new CameraCapturingEventArgs(new StillImage(main),
863                     postview == IntPtr.Zero ? null : new StillImage(postview),
864                     thumbnail == IntPtr.Zero ? null : new StillImage(thumbnail)));
865             };
866
867             //Define captureCompleted callback
868             _captureCompletedCallback = _ =>
869             {
870                 SetState(CameraState.Captured);
871                 CaptureCompleted?.Invoke(this, EventArgs.Empty);
872             };
873         }
874
875         private void RegisterInterruptStartedCallback()
876         {
877             _interruptStartedCallback = (CameraPolicy policy, CameraState state, IntPtr userData) =>
878             {
879                 InterruptStarted?.Invoke(this, new CameraInterruptStartedEventArgs(policy, state));
880             };
881             CameraErrorFactory.ThrowIfError(Native.SetInterruptStartedCallback(_handle, _interruptStartedCallback, IntPtr.Zero),
882                 "Failed to set interrupt callback");
883         }
884
885         private void RegisterInterruptedCallback()
886         {
887             _interruptedCallback = (CameraPolicy policy, CameraState previous, CameraState current, IntPtr userData) =>
888             {
889                 Interrupted?.Invoke(this, new CameraInterruptedEventArgs(policy, previous, current));
890             };
891             CameraErrorFactory.ThrowIfError(Native.SetInterruptedCallback(_handle, _interruptedCallback, IntPtr.Zero),
892                 "Failed to set interrupt callback");
893         }
894
895         private void RegisterErrorCallback()
896         {
897             _errorCallback = (CameraErrorCode error, CameraState current, IntPtr userData) =>
898             {
899                 ErrorOccurred?.Invoke(this, new CameraErrorOccurredEventArgs(error, current));
900             };
901             CameraErrorFactory.ThrowIfError(Native.SetErrorCallback(_handle, _errorCallback, IntPtr.Zero),
902                 "Setting error callback failed");
903         }
904
905         private void RegisterStateChangedCallback()
906         {
907             _stateChangedCallback = (CameraState previous, CameraState current, bool byPolicy, IntPtr _) =>
908             {
909                 SetState(current);
910                 Log.Info(CameraLog.Tag, "Camera state changed " + previous.ToString() + " -> " + current.ToString());
911                 StateChanged?.Invoke(this, new CameraStateChangedEventArgs(previous, current, byPolicy));
912             };
913             CameraErrorFactory.ThrowIfError(Native.SetStateChangedCallback(_handle, _stateChangedCallback, IntPtr.Zero),
914                 "Setting state changed callback failed");
915         }
916
917         private static void RegisterDeviceStateChangedCallback()
918         {
919             _deviceStateChangedCallback = (CameraDevice device, CameraDeviceState state, IntPtr userData) =>
920             {
921                 _deviceStateChanged?.Invoke(null, new CameraDeviceStateChangedEventArgs(device, state));
922             };
923
924             CameraErrorFactory.ThrowIfError(Native.SetDeviceStateChangedCallback(_deviceStateChangedCallback, IntPtr.Zero, out _deviceStateCallbackId),
925                 "Failed to set device state changed callback");
926
927             Log.Info(CameraLog.Tag, "add callbackId " + _deviceStateCallbackId.ToString());
928         }
929
930         private static void UnregisterDeviceStateChangedCallback()
931         {
932             CameraErrorFactory.ThrowIfError(Native.UnsetDeviceStateChangedCallback(_deviceStateCallbackId),
933                 "Unsetting device state changed callback failed");
934             _deviceStateChangedCallback = null;
935             _deviceStateCallbackId = 0;
936         }
937
938         private void RegisterFocusStateChanged()
939         {
940             _focusStateChangedCallback = (CameraFocusState state, IntPtr userData) =>
941             {
942                 FocusStateChanged?.Invoke(this, new CameraFocusStateChangedEventArgs(state));
943             };
944             CameraErrorFactory.ThrowIfError(Native.SetFocusStateChangedCallback(_handle, _focusStateChangedCallback, IntPtr.Zero),
945                 "Setting focus changed callback failed");
946         }
947
948         private void RegisterHdrCaptureProgress()
949         {
950             _hdrCaptureProgressCallback = (int percent, IntPtr userData) =>
951             {
952                 _hdrCaptureProgress?.Invoke(this, new HdrCaptureProgressEventArgs(percent));
953             };
954             CameraErrorFactory.ThrowIfError(Native.SetHdrCaptureProgressCallback(_handle, _hdrCaptureProgressCallback, IntPtr.Zero),
955                 "Setting Hdr capture progress callback failed");
956         }
957
958         private void UnregisterHdrCaptureProgress()
959         {
960             CameraErrorFactory.ThrowIfError(Native.UnsetHdrCaptureProgressCallback(_handle),
961                 "Unsetting hdr capture progress is failed");
962             _hdrCaptureProgressCallback = null;
963         }
964
965         private void RegisterPreviewCallback()
966         {
967             _previewCallback = (IntPtr frame, IntPtr userData) =>
968             {
969                 _preview?.Invoke(this, new PreviewEventArgs(new PreviewFrame(frame)));
970             };
971             CameraErrorFactory.ThrowIfError(Native.SetPreviewCallback(_handle, _previewCallback, IntPtr.Zero),
972                 "Setting preview callback failed");
973         }
974
975         private void UnregisterPreviewCallback()
976         {
977             CameraErrorFactory.ThrowIfError(Native.UnsetPreviewCallback(_handle),
978                 "Unsetting preview callback failed");
979             _previewCallback = null;
980         }
981
982         private void RegisterMediaPacketPreviewCallback()
983         {
984             _mediaPacketPreviewCallback = (IntPtr mediaPacket, IntPtr userData) =>
985             {
986                 MediaPacket packet = MediaPacket.From(mediaPacket);
987                 var eventHandler = _mediaPacketPreview;
988
989                 if (eventHandler != null)
990                 {
991                     eventHandler.Invoke(this, new MediaPacketPreviewEventArgs(packet));
992                 }
993                 else
994                 {
995                     packet.Dispose();
996                 }
997             };
998             CameraErrorFactory.ThrowIfError(Native.SetMediaPacketPreviewCallback(_handle, _mediaPacketPreviewCallback, IntPtr.Zero),
999                 "Setting media packet preview callback failed");
1000         }
1001
1002         private void UnregisterMediaPacketPreviewCallback()
1003         {
1004             CameraErrorFactory.ThrowIfError(Native.UnsetMediaPacketPreviewCallback(_handle),
1005                 "Unsetting media packet preview callback failed");
1006             _mediaPacketPreviewCallback = null;
1007         }
1008         #endregion Callback registrations
1009     }
1010 }